VFS messaging/interfacing work stage 8/99: Major reworking of the vnode
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 12 Oct 2004 19:21:16 +0000 (19:21 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 12 Oct 2004 19:21:16 +0000 (19:21 +0000)
interlock and other miscellanious things.  This patch also fixes FS
corruption due to prior vfs work in head.  In particular, prior to this
patch the namecache locking could introduce blocking conditions that
confuse the old vnode deactivation and reclamation code paths.  With
this patch there appear to be no serious problems even after two days
of continuous testing.

* VX lock all VOP_CLOSE operations.
* Fix two NFS issues.  There was an incorrect assertion (found by
  David Rhodus), and the nfs_rename() code was not properly
  purging the target file from the cache, resulting in Stale file
  handle errors during, e.g. a buildworld with an NFS-mounted /usr/obj.
* Fix a TTY session issue.  Programs which open("/dev/tty" ,...) and
  then run the TIOCNOTTY ioctl were causing the system to lose track
  of the open count, preventing the tty from properly detaching.
  This is actually a very old BSD bug, but it came out of the woodwork
  in DragonFly because I am now attempting to track device opens
  explicitly.
* Gets rid of the vnode interlock.  The lockmgr interlock remains.
* Introduced VX locks, which are mandatory vp->v_lock based locks.
* Rewrites the locking semantics for deactivation and reclamation.
  (A ref'd VX lock'd vnode is now required for vgone(), VOP_INACTIVE,
  and VOP_RECLAIM).  New guarentees emplaced with regard to vnode
  ripouts.
* Recodes the mountlist scanning routines to close timing races.
* Recodes getnewvnode to close timing races (it now returns a
  VX locked and refd vnode rather then a refd but unlocked vnode).
* Recodes VOP_REVOKE- a locked vnode is now mandatory.
* Recodes all VFS inode hash routines to close timing holes.
* Removes cache_leaf_test() - vnodes representing intermediate
  directories are now held so the leaf test should no longer be
  necessary.
* Splits the over-large vfs_subr.c into three additional source
  files, broken down by major function (locking, mount related,
  filesystem syncer).

* Changes splvm() protection to a critical-section in a number of
  places (bleedover from another patch set which is also about to be
  committed).

Known issues not yet resolved:

* Possible vnode/namecache deadlocks.
* While most filesystems now use vp->v_lock, I haven't done a final
  pass to make vp->v_lock mandatory and to clean up the few remaining
  inode based locks (nwfs I think and other obscure filesystems).
* NullFS gets confused when you hit a mount point in the underlying
  filesystem.
* Only UFS and NFS have been well tested
* NFS is not properly timing out namecache entries, causing changes made
  on the server to not be properly detected on the client if the client
  already has a negative-cache hit for the filename in question.

Testing-by: David Rhodus <sdrhodus@gmail.com>,
    Peter Kadau <peter.kadau@tuebingen.mpg.de>,
    walt <wa1ter@myrealbox.com>,
    others

121 files changed:
sys/conf/files
sys/dev/disk/ccd/ccd.c
sys/dev/disk/vn/vn.c
sys/emulation/43bsd/43bsd_file.c
sys/emulation/ibcs2/coff/imgact_coff.c
sys/emulation/ibcs2/i386/ibcs2_misc.c
sys/emulation/linux/i386/linprocfs/linprocfs_subr.c
sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c
sys/emulation/linux/linux_file.c
sys/emulation/linux/linux_getcwd.c
sys/emulation/linux/linux_misc.c
sys/emulation/ndis/subr_ndis.c
sys/emulation/svr4/svr4_fcntl.c
sys/emulation/svr4/svr4_misc.c
sys/kern/imgact_elf.c
sys/kern/imgact_resident.c
sys/kern/init_main.c
sys/kern/kern_acct.c
sys/kern/kern_acl.c
sys/kern/kern_descrip.c
sys/kern/kern_exec.c
sys/kern/kern_exit.c
sys/kern/kern_fork.c
sys/kern/kern_fp.c
sys/kern/kern_ktrace.c
sys/kern/kern_linker.c
sys/kern/kern_sig.c
sys/kern/link_aout.c
sys/kern/link_elf.c
sys/kern/tty.c
sys/kern/tty_tty.c
sys/kern/uipc_syscalls.c
sys/kern/uipc_usrreq.c
sys/kern/vfs_cache.c
sys/kern/vfs_default.c
sys/kern/vfs_init.c
sys/kern/vfs_lock.c [new file with mode: 0644]
sys/kern/vfs_lookup.c
sys/kern/vfs_mount.c [new file with mode: 0644]
sys/kern/vfs_subr.c
sys/kern/vfs_sync.c [new file with mode: 0644]
sys/kern/vfs_syscalls.c
sys/kern/vfs_vnops.c
sys/kern/vfs_vopops.c
sys/sys/namecache.h
sys/sys/systm.h
sys/sys/tty.h
sys/sys/vfsops.h
sys/sys/vnode.h
sys/vfs/coda/coda_vfsops.c
sys/vfs/coda/coda_vnops.c
sys/vfs/deadfs/dead_vnops.c
sys/vfs/fdesc/fdesc_vfsops.c
sys/vfs/fdesc/fdesc_vnops.c
sys/vfs/fifofs/fifo_vnops.c
sys/vfs/gnu/ext2fs/ext2_lookup.c
sys/vfs/gnu/ext2fs/ext2_vfsops.c
sys/vfs/gnu/ext2fs/ext2_vnops.c
sys/vfs/gnu/ext2fs/fs.h
sys/vfs/hpfs/hpfs.h
sys/vfs/hpfs/hpfs_hash.c
sys/vfs/hpfs/hpfs_vfsops.c
sys/vfs/hpfs/hpfs_vnops.c
sys/vfs/isofs/cd9660/cd9660_lookup.c
sys/vfs/isofs/cd9660/cd9660_node.c
sys/vfs/isofs/cd9660/cd9660_vfsops.c
sys/vfs/mfs/mfs_vfsops.c
sys/vfs/mfs/mfs_vnops.c
sys/vfs/msdosfs/msdosfs_denode.c
sys/vfs/msdosfs/msdosfs_lookup.c
sys/vfs/msdosfs/msdosfs_vfsops.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/nfs/nfs_bio.c
sys/vfs/nfs/nfs_node.c
sys/vfs/nfs/nfs_nqlease.c
sys/vfs/nfs/nfs_serv.c
sys/vfs/nfs/nfs_subs.c
sys/vfs/nfs/nfs_vfsops.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/ntfs/ntfs.h
sys/vfs/ntfs/ntfs_vfsops.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/nullfs/null_subr.c
sys/vfs/nullfs/null_vfsops.c
sys/vfs/nullfs/null_vnops.c
sys/vfs/nwfs/nwfs_io.c
sys/vfs/nwfs/nwfs_node.c
sys/vfs/nwfs/nwfs_vfsops.c
sys/vfs/nwfs/nwfs_vnops.c
sys/vfs/portal/portal_vfsops.c
sys/vfs/portal/portal_vnops.c
sys/vfs/procfs/procfs_subr.c
sys/vfs/procfs/procfs_vnops.c
sys/vfs/smbfs/smbfs_io.c
sys/vfs/smbfs/smbfs_node.c
sys/vfs/smbfs/smbfs_vfsops.c
sys/vfs/smbfs/smbfs_vnops.c
sys/vfs/specfs/spec_vnops.c
sys/vfs/udf/udf_vfsops.c
sys/vfs/udf/udf_vnops.c
sys/vfs/ufs/ffs_rawread.c
sys/vfs/ufs/ffs_softdep.c
sys/vfs/ufs/ffs_vfsops.c
sys/vfs/ufs/ufs_ihash.c
sys/vfs/ufs/ufs_inode.c
sys/vfs/ufs/ufs_lookup.c
sys/vfs/ufs/ufs_quota.c
sys/vfs/ufs/ufs_vnops.c
sys/vfs/umapfs/umap_subr.c
sys/vfs/umapfs/umap_vfsops.c
sys/vfs/umapfs/umap_vnops.c
sys/vfs/union/union.h
sys/vfs/union/union_subr.c
sys/vfs/union/union_vfsops.c
sys/vfs/union/union_vnops.c
sys/vm/vm_contig.c
sys/vm/vm_map.c
sys/vm/vm_object.c
sys/vm/vm_pageout.c
sys/vm/vm_swap.c
sys/vm/vnode_pager.c

index 0468751..fd3a460 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/sys/conf/files,v 1.76 2004/09/28 00:25:25 dillon Exp $
+# $DragonFly: src/sys/conf/files,v 1.77 2004/10/12 19:20:26 dillon Exp $
 #
 # The long compile-with and dependency lines are required because of
 # limitations in config: backslash-newline doesn't work in strings, and
@@ -725,6 +725,9 @@ kern/vfs_init.c             standard
 kern/vfs_lookup.c      standard
 kern/vfs_nlookup.c     standard
 kern/vfs_subr.c                standard
+kern/vfs_lock.c                standard
+kern/vfs_mount.c       standard
+kern/vfs_sync.c                standard
 kern/vfs_syscalls.c    standard
 kern/vfs_vnops.c       standard
 kern/vfs_vopops.c      standard
index 2fe2102..7ae15a4 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/dev/ccd/ccd.c,v 1.73.2.1 2001/09/11 09:49:52 kris Exp $ */
-/* $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.16 2004/05/19 22:52:41 dillon Exp $ */
+/* $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.17 2004/10/12 19:20:30 dillon Exp $ */
 
 /*     $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */
 
@@ -1567,12 +1567,12 @@ ccdlookup(char *path, struct thread *td, struct vnode **vpp)
                vprint("ccdlookup: vnode info", vp);
 #endif
 
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        NDFREE(&nd, NDF_ONLY_PNBUF);
        *vpp = vp;
        return (0);
 bad:
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        NDFREE(&nd, NDF_ONLY_PNBUF);
        /* vn_close does vrele() for vp */
        (void)vn_close(vp, FREAD|FWRITE, td);
index 4ddd919..f40b444 100644 (file)
@@ -39,7 +39,7 @@
  *
  *     from: @(#)vn.c  8.6 (Berkeley) 4/1/94
  * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $
- * $DragonFly: src/sys/dev/disk/vn/vn.c,v 1.11 2004/05/26 01:14:36 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/vn/vn.c,v 1.12 2004/10/12 19:20:32 dillon Exp $
  */
 
 /*
@@ -390,12 +390,12 @@ vnstrategy(struct buf *bp)
                        auio.uio_rw = UIO_WRITE;
                auio.uio_resid = bp->b_bcount;
                auio.uio_td = curthread;
-               vn_lock(vn->sc_vp, NULL, LK_EXCLUSIVE | LK_RETRY, curthread);
+               vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curthread);
                if (bp->b_flags & B_READ)
                        error = VOP_READ(vn->sc_vp, &auio, IO_DIRECT, vn->sc_cred);
                else
                        error = VOP_WRITE(vn->sc_vp, &auio, IO_NOWDRAIN, vn->sc_cred);
-               VOP_UNLOCK(vn->sc_vp, NULL, 0, curthread);
+               VOP_UNLOCK(vn->sc_vp, 0, curthread);
                bp->b_resid = auio.uio_resid;
 
                if (error) {
@@ -563,11 +563,11 @@ vniocattach_file(vn, vio, dev, flag, td)
        NDFREE(&nd, NDF_ONLY_PNBUF);
        if (nd.ni_vp->v_type != VREG ||
            (error = VOP_GETATTR(nd.ni_vp, &vattr, td))) {
-               VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+               VOP_UNLOCK(nd.ni_vp, 0, td);
                (void) vn_close(nd.ni_vp, flags, td);
                return (error ? error : EINVAL);
        }
-       VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+       VOP_UNLOCK(nd.ni_vp, 0, td);
        vn->sc_secsize = DEV_BSIZE;
        vn->sc_vp = nd.ni_vp;
 
@@ -718,9 +718,9 @@ vnsetcred(struct vn_softc *vn, struct ucred *cred)
                auio.uio_rw = UIO_READ;
                auio.uio_segflg = UIO_SYSSPACE;
                auio.uio_resid = aiov.iov_len;
-               vn_lock(vn->sc_vp, NULL, LK_EXCLUSIVE | LK_RETRY, curthread);
+               vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curthread);
                error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred);
-               VOP_UNLOCK(vn->sc_vp, NULL, 0, curthread);
+               VOP_UNLOCK(vn->sc_vp, 0, curthread);
                free(tmpbuf, M_TEMP);
        }
        return (error);
index 747d963..7a82c9a 100644 (file)
@@ -37,7 +37,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/emulation/43bsd/43bsd_file.c,v 1.5 2004/04/24 04:32:02 drhodus Exp $
+ * $DragonFly: src/sys/emulation/43bsd/43bsd_file.c,v 1.6 2004/10/12 19:20:33 dillon Exp $
  *     from: DragonFly kern/vfs_syscalls.c,v 1.20
  *
  * These syscalls used to live in kern/vfs_syscalls.c.  They are modified
@@ -147,7 +147,7 @@ unionread:
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_td = td;
        auio.uio_resid = uap->count;
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        loff = auio.uio_offset = fp->f_offset;
 #      if (BYTE_ORDER != LITTLE_ENDIAN)
                if (vp->v_mount->mnt_maxsymlinklen <= 0) {
@@ -200,7 +200,7 @@ unionread:
                }
                FREE(dirbuf, M_TEMP);
        }
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        if (error)
                return (error);
        if (uap->count == auio.uio_resid) {
index e46cac2..aac6ba6 100644 (file)
@@ -27,7 +27,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/ibcs2/imgact_coff.c,v 1.40 1999/12/15 23:01:47 eivind Exp $
- * $DragonFly: src/sys/emulation/ibcs2/coff/Attic/imgact_coff.c,v 1.11 2004/06/21 05:58:01 dillon Exp $
+ * $DragonFly: src/sys/emulation/ibcs2/coff/Attic/imgact_coff.c,v 1.12 2004/10/12 19:20:34 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -211,7 +211,7 @@ coff_load_file(struct thread *td, char *name)
         * Lose the lock on the vnode. It's no longer needed, and must not
         * exist for the pagefault paging to work below.
         */
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
 
        if ((error = vm_mmap(kernel_map,
                            (vm_offset_t *) &ptr,
@@ -284,7 +284,7 @@ coff_load_file(struct thread *td, char *name)
                panic("%s: vm_map_remove failed", __FUNCTION__);
 
  fail:
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
  unlocked_fail:
        NDFREE(&nd, NDF_ONLY_PNBUF);
        vrele(nd.ni_vp);
index 1b9cb59..72d8c35 100644 (file)
@@ -46,7 +46,7 @@
  *     @(#)sun_misc.c  8.1 (Berkeley) 6/18/93
  *
  * $FreeBSD: src/sys/i386/ibcs2/ibcs2_misc.c,v 1.34 1999/09/29 15:12:09 marcel Exp $
- * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_misc.c,v 1.9 2004/03/01 06:33:15 dillon Exp $
+ * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_misc.c,v 1.10 2004/10/12 19:20:36 dillon Exp $
  */
 
 /*
@@ -330,7 +330,7 @@ ibcs2_getdents(struct ibcs2_getdents_args *uap)
        buflen = max(DIRBLKSIZ, SCARG(uap, nbytes));
        buflen = min(buflen, MAXBSIZE);
        buf = malloc(buflen, M_TEMP, M_WAITOK);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 again:
        aiov.iov_base = buf;
        aiov.iov_len = buflen;
@@ -432,7 +432,7 @@ eof:
 out:
        if (cookies)
                free(cookies, M_TEMP);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        free(buf, M_TEMP);
        return (error);
 }
@@ -479,7 +479,7 @@ ibcs2_read(struct ibcs2_read_args *uap)
        buflen = max(DIRBLKSIZ, SCARG(uap, nbytes));
        buflen = min(buflen, MAXBSIZE);
        buf = malloc(buflen, M_TEMP, M_WAITOK);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 again:
        aiov.iov_base = buf;
        aiov.iov_len = buflen;
@@ -585,7 +585,7 @@ eof:
 out:
        if (cookies)
                free(cookies, M_TEMP);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        free(buf, M_TEMP);
        return (error);
 }
index e1cb325..609229b 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.12 2004/08/28 19:02:04 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_subr.c,v 1.13 2004/10/12 19:20:38 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -100,7 +100,7 @@ loop:
                if (pfs->pfs_pid == pid &&
                    pfs->pfs_type == pfs_type &&
                    vp->v_mount == mp) {
-                       if (vget(vp, NULL, 0, td))
+                       if (vget(vp, LK_EXCLUSIVE|LK_SLEEPFAIL, td))
                                goto loop;
                        *vpp = vp;
                        return (0);
@@ -203,6 +203,8 @@ loop:
                continue;
        *pp = pfs;
 
+       vx_unlock(vp);  /* vnode ready to roll! */
+
 out:
        pfsvplock &= ~PROCFS_LOCKED;
 
index 180b377..9905f5a 100644 (file)
@@ -39,7 +39,7 @@
  *     @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
  *
  * $FreeBSD: src/sys/i386/linux/linprocfs/linprocfs_vnops.c,v 1.3.2.5 2001/08/12 14:29:19 rwatson Exp $
- * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c,v 1.17 2004/09/09 20:52:21 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c,v 1.18 2004/10/12 19:20:38 dillon Exp $
  */
 
 /*
@@ -323,12 +323,13 @@ linprocfs_bmap(ap)
 
 /*
  * linprocfs_inactive is called when the pfsnode
- * is vrele'd and the reference count goes
- * to zero.  (vp) will be on the vnode free
+ * is vrele'd and the reference count is about
+ * to go to zero.  (vp) will be on the vnode free
  * list, so to get it back vget() must be
  * used.
  *
- * (vp) is locked on entry, but must be unlocked on exit.
+ * (vp) is locked on entry and must remain locked
+ *      on exit.
  */
 static int
 linprocfs_inactive(ap)
@@ -336,9 +337,7 @@ linprocfs_inactive(ap)
                struct vnode *a_vp;
        } */ *ap;
 {
-       struct vnode *vp = ap->a_vp;
-
-       VOP_UNLOCK(vp, NULL, 0, ap->a_td);
+       /*struct vnode *vp = ap->a_vp;*/
 
        return (0);
 }
@@ -356,7 +355,6 @@ linprocfs_reclaim(ap)
                struct vnode *a_vp;
        } */ *ap;
 {
-
        return (linprocfs_freevp(ap->a_vp));
 }
 
@@ -758,7 +756,7 @@ 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);
+                       VOP_UNLOCK(dvp, 0, cnp->cn_td);
                }
        }
        return (error);
index 776ea65..29469ff 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/compat/linux/linux_file.c,v 1.41.2.6 2003/01/06 09:19:43 fjoe Exp $
- * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.17 2004/09/30 18:59:38 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.18 2004/10/12 19:20:37 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -291,7 +291,7 @@ getdents_common(struct linux_getdents64_args *args, int is64bit)
        buflen = max(LINUX_DIRBLKSIZ, nbytes);
        buflen = min(buflen, MAXBSIZE);
        buf = malloc(buflen, M_TEMP, M_WAITOK);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 
 again:
        aiov.iov_base = buf;
@@ -430,7 +430,7 @@ out:
        if (cookies)
                free(cookies, M_TEMP);
 
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        free(buf, M_TEMP);
        return (error);
 }
index 1873866..f6f2db7 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/compat/linux/linux_getcwd.c,v 1.2.2.3 2001/11/05 19:08:22 marcel Exp $ */
-/* $DragonFly: src/sys/emulation/linux/linux_getcwd.c,v 1.16 2004/09/26 06:00:07 dillon Exp $ */
+/* $DragonFly: src/sys/emulation/linux/linux_getcwd.c,v 1.17 2004/10/12 19:20:37 dillon Exp $ */
 /* $OpenBSD: linux_getcwd.c,v 1.2 2001/05/16 12:50:21 ho Exp $ */
 /* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */
 
@@ -313,7 +313,7 @@ linux_getcwd_common (lvp, rvp, bpp, bufp, limit, flags, td)
         *      uvp is either NULL, or locked and held.
         */
 
-       error = vn_lock(lvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, td);
        if (error) {
                vrele(lvp);
                lvp = NULL;
@@ -369,7 +369,7 @@ linux_getcwd_common (lvp, rvp, bpp, bufp, limit, flags, td)
                                goto out;
                        }
                        vref(lvp);
-                       error = vn_lock(lvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+                       error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, td);
                        if (error != 0) {
                                vrele(lvp);
                                lvp = NULL;
index ea3bf96..006dd50 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/compat/linux/linux_misc.c,v 1.85.2.9 2002/09/24 08:11:41 mdodd Exp $
- * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.20 2004/09/17 01:29:45 joerg Exp $
+ * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.21 2004/10/12 19:20:37 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -326,7 +326,7 @@ linux_uselib(struct linux_uselib_args *args)
        /*
         * Lock no longer needed
         */
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        locked = 0;
 
        /* Pull in executable header into kernel_map */
@@ -464,7 +464,7 @@ linux_uselib(struct linux_uselib_args *args)
 cleanup:
        /* Unlock vnode if needed */
        if (locked)
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
 
        /* Release the kernel mapping. */
        if (a_out)
index 66aaeb7..323a607 100644 (file)
@@ -30,7 +30,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.62 2004/07/11 00:19:30 wpaul Exp $
- * $DragonFly: src/sys/emulation/ndis/subr_ndis.c,v 1.4 2004/09/20 06:32:41 dillon Exp $
+ * $DragonFly: src/sys/emulation/ndis/subr_ndis.c,v 1.5 2004/10/12 19:20:40 dillon Exp $
  */
 
 /*
@@ -2577,7 +2577,7 @@ ndis_open_file(status, filehandle, filelength, filename, highestaddr)
 
        /* Get the file size. */
        VOP_GETATTR(nd.ni_vp, vap, td);
-       VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+       VOP_UNLOCK(nd.ni_vp, 0, td);
 
        fh->nf_vp = nd.ni_vp;
        fh->nf_map = NULL;
index 2e3799a..4ff1640 100644 (file)
@@ -29,7 +29,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * 
  * $FreeBSD: src/sys/svr4/svr4_fcntl.c,v 1.7 1999/12/12 10:27:04 newton Exp $
- * $DragonFly: src/sys/emulation/svr4/Attic/svr4_fcntl.c,v 1.14 2003/08/27 06:07:10 rob Exp $
+ * $DragonFly: src/sys/emulation/svr4/Attic/svr4_fcntl.c,v 1.15 2004/10/12 19:20:42 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -263,6 +263,9 @@ fd_revoke(struct thread *td, int fd)
 
        vp = (struct vnode *) fp->f_data;
 
+       if ((error = vx_get(vp)) != 0)
+               return (error);
+
        if (vp->v_type != VCHR && vp->v_type != VBLK) {
                error = EINVAL;
                goto out;
@@ -278,7 +281,7 @@ fd_revoke(struct thread *td, int fd)
        if (vcount(vp) > 1)
                VOP_REVOKE(vp, REVOKEALL);
 out:
-       vrele(vp);
+       vx_put(vp);
        return error;
 }
 
index 683046c..a53102e 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * 
  * $FreeBSD: src/sys/svr4/svr4_misc.c,v 1.13.2.7 2003/01/14 21:33:58 dillon Exp $
- * $DragonFly: src/sys/emulation/svr4/Attic/svr4_misc.c,v 1.24 2004/09/30 18:59:43 dillon Exp $
+ * $DragonFly: src/sys/emulation/svr4/Attic/svr4_misc.c,v 1.25 2004/10/12 19:20:42 dillon Exp $
  */
 
 /*
@@ -286,7 +286,7 @@ svr4_sys_getdents64(struct svr4_sys_getdents64_args *uap)
        buflen = max(DIRBLKSIZ, nbytes);
        buflen = min(buflen, MAXBSIZE);
        buf = malloc(buflen, M_TEMP, M_WAITOK);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 again:
        aiov.iov_base = buf;
        aiov.iov_len = buflen;
@@ -400,7 +400,7 @@ eof:
 out:
        if (cookies)
                free(cookies, M_TEMP);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        free(buf, M_TEMP);
        return error;
 }
@@ -440,7 +440,7 @@ svr4_sys_getdents(struct svr4_sys_getdents_args *uap)
 
        buflen = min(MAXBSIZE, SCARG(uap, nbytes));
        buf = malloc(buflen, M_TEMP, M_WAITOK);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        off = fp->f_offset;
 again:
        aiov.iov_base = buf;
@@ -514,7 +514,7 @@ again:
 eof:
        *retval = SCARG(uap, nbytes) - resid;
 out:
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        if (cookiebuf)
                free(cookiebuf, M_TEMP);
        free(buf, M_TEMP);
@@ -609,12 +609,12 @@ svr4_sys_fchroot(struct svr4_sys_fchroot_args *uap)
        if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
                return error;
        vp = (struct vnode *) fp->f_data;
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        if (vp->v_type != VDIR || fp->f_ncp == NULL)
                error = ENOTDIR;
        else
                error = VOP_ACCESS(vp, VEXEC, cred, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        if (error)
                return error;
        vref(vp);
index 206a9eb..8cc245a 100644 (file)
@@ -27,7 +27,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/imgact_elf.c,v 1.73.2.13 2002/12/28 19:49:41 dillon Exp $
- * $DragonFly: src/sys/kern/imgact_elf.c,v 1.21 2004/07/24 20:21:35 dillon Exp $
+ * $DragonFly: src/sys/kern/imgact_elf.c,v 1.22 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -381,7 +381,7 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
         */
        error = exec_check_permissions(imgp);
        if (error) {
-               VOP_UNLOCK(nd->ni_vp, NULL, 0, td);
+               VOP_UNLOCK(nd->ni_vp, 0, td);
                goto fail;
        }
 
@@ -392,7 +392,7 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
         */
        if (error == 0)
                nd->ni_vp->v_flag |= VTEXT;
-       VOP_UNLOCK(nd->ni_vp, NULL, 0, td);
+       VOP_UNLOCK(nd->ni_vp, 0, td);
        if (error)
                 goto fail;
 
@@ -484,7 +484,6 @@ exec_elf_imgact(struct image_params *imgp)
        const char *interp = NULL;
        Elf_Brandinfo *brand_info;
        char *path;
-       lwkt_tokref ilock;
 
        error = 0;
 
@@ -518,9 +517,7 @@ exec_elf_imgact(struct image_params *imgp)
         * a context switch.  Better safe than sorry; I really don't want
         * the file to change while it's being loaded.
         */
-       lwkt_gettoken(&ilock, imgp->vp->v_interlock);
-       imgp->vp->v_flag |= VTEXT;
-       lwkt_reltoken(&ilock);
+       vsetflags(imgp->vp, VTEXT);
 
        vmspace = imgp->proc->p_vmspace;
 
@@ -808,7 +805,7 @@ elf_coredump(struct proc *p, struct vnode *vp, off_t limit)
        fp->f_flag = O_CREAT|O_WRONLY|O_NOFOLLOW;
        fp->f_ops = &vnops;
        fp->f_type = DTYPE_VNODE;
-       VOP_UNLOCK(vp, NULL, 0, p->p_thread);
+       VOP_UNLOCK(vp, 0, p->p_thread);
        
        error = generic_elf_coredump(p, fp, limit);
 
index 2bef4a3..ff2892e 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/imgact_resident.c,v 1.5 2004/07/16 05:51:09 dillon Exp $
+ * $DragonFly: src/sys/kern/imgact_resident.c,v 1.6 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -101,7 +101,7 @@ fill_xresident(struct vmresident *vr, struct xresident *in, struct thread *td)
                }
 
                /* indicate that we are using the vnode */
-               error = vget(vrtmp, NULL, LK_EXCLUSIVE, td);
+               error = vget(vrtmp, LK_EXCLUSIVE, td);
                if (error)
                        goto done;
        
index 8ce23aa..627261a 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     @(#)init_main.c 8.9 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/init_main.c,v 1.134.2.8 2003/06/06 20:21:32 tegge Exp $
- * $DragonFly: src/sys/kern/init_main.c,v 1.39 2004/10/04 09:20:40 dillon Exp $
+ * $DragonFly: src/sys/kern/init_main.c,v 1.40 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_init_path.h"
@@ -464,7 +464,7 @@ start_init(void *dummy)
        if (VFS_ROOT(mp, &vp))
                panic("cannot find root vnode");
        if (mp->mnt_ncp == NULL) {
-               mp->mnt_ncp = cache_allocroot(vp);
+               mp->mnt_ncp = cache_allocroot(mp, vp);
                cache_unlock(mp->mnt_ncp);      /* leave ref intact */
        }
        p->p_fd->fd_cdir = vp;
@@ -472,7 +472,7 @@ start_init(void *dummy)
        p->p_fd->fd_rdir = vp;
        vref(p->p_fd->fd_rdir);
        vfs_cache_setroot(vp, cache_hold(mp->mnt_ncp));
-       VOP_UNLOCK(vp, NULL, 0, curthread); /* leave ref intact */
+       VOP_UNLOCK(vp, 0, curthread); /* leave ref intact */
        p->p_fd->fd_ncdir = cache_hold(mp->mnt_ncp);
        p->p_fd->fd_nrdir = cache_hold(mp->mnt_ncp);
 
index 1d7d682..1103338 100644 (file)
@@ -38,7 +38,7 @@
  *
  *     @(#)kern_acct.c 8.1 (Berkeley) 6/14/93
  * $FreeBSD: src/sys/kern/kern_acct.c,v 1.23.2.1 2002/07/24 18:33:55 johan Exp $
- * $DragonFly: src/sys/kern/kern_acct.c,v 1.14 2004/09/17 17:06:59 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_acct.c,v 1.15 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -142,7 +142,7 @@ acct(uap)
                if (error)
                        return (error);
                NDFREE(&nd, NDF_ONLY_PNBUF);
-               VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+               VOP_UNLOCK(nd.ni_vp, 0, td);
                if (nd.ni_vp->v_type != VREG) {
                        vn_close(nd.ni_vp, FWRITE | O_APPEND, td);
                        return (EACCES);
index 9a73fd1..4e7dc33 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_acl.c,v 1.2.2.1 2000/07/28 18:48:16 rwatson Exp $
- * $DragonFly: src/sys/kern/kern_acl.c,v 1.6 2004/03/01 06:33:17 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_acl.c,v 1.7 2004/10/12 19:20:46 dillon Exp $
  */
 
 /*
@@ -80,9 +80,9 @@ vacl_set_acl(struct vnode *vp, acl_type_t type, struct acl *aclp)
        ucred = td->td_proc->p_ucred;
 
        VOP_LEASE(vp, td, ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        error = VOP_SETACL(vp, type, &inkernacl, ucred, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return(error);
 }
 
@@ -118,9 +118,9 @@ vacl_delete(struct vnode *vp, acl_type_t type)
        KKASSERT(td->td_proc);
        ucred = td->td_proc->p_ucred;
        VOP_LEASE(vp, td, ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, ucred, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return (error);
 }
 
index afd79cd..098616d 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_descrip.c      8.6 (Berkeley) 4/19/94
  * $FreeBSD: src/sys/kern/kern_descrip.c,v 1.81.2.19 2004/02/28 00:43:31 tegge Exp $
- * $DragonFly: src/sys/kern/kern_descrip.c,v 1.29 2004/09/30 18:59:48 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_descrip.c,v 1.30 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -1366,7 +1366,7 @@ fdcheckstd(struct proc *p)
                        fp->f_flag = flags;
                        fp->f_ops = &vnops;
                        fp->f_type = DTYPE_VNODE;
-                       VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+                       VOP_UNLOCK(nd.ni_vp, 0, td);
                        devnull = fd;
                } else {
                        error = kern_dup(DUP_FIXED, devnull, i, &retval);
index d4bd73c..4ffc0e3 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_exec.c,v 1.107.2.15 2002/07/30 15:40:46 nectar Exp $
- * $DragonFly: src/sys/kern/kern_exec.c,v 1.27 2004/05/13 17:40:15 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_exec.c,v 1.28 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -67,6 +67,8 @@
 #include <sys/user.h>
 #include <machine/reg.h>
 
+#include <sys/thread2.h>
+
 MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments");
 
 static register_t *exec_copyout_strings (struct image_params *);
@@ -175,12 +177,12 @@ interpret:
         */
        error = exec_check_permissions(imgp);
        if (error) {
-               VOP_UNLOCK(imgp->vp, NULL, 0, td);
+               VOP_UNLOCK(imgp->vp, 0, td);
                goto exec_fail_dealloc;
        }
 
        error = exec_map_first_page(imgp);
-       VOP_UNLOCK(imgp->vp, NULL, 0, td);
+       VOP_UNLOCK(imgp->vp, 0, td);
        if (error)
                goto exec_fail_dealloc;
 
@@ -490,7 +492,7 @@ execve(struct execve_args *uap)
 int
 exec_map_first_page(struct image_params *imgp)
 {
-       int s, rv, i;
+       int rv, i;
        int initial_pagein;
        vm_page_t ma[VM_INITIAL_PAGEIN];
        vm_page_t m;
@@ -506,7 +508,7 @@ exec_map_first_page(struct image_params *imgp)
         * need it for the lookup loop below (lookup/busy race), since
         * an interrupt can unbusy and free the page before our busy check.
         */
-       s = splvm();
+       crit_enter();
        m = vm_page_grab(object, 0, VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
 
        if ((m->valid & VM_PAGE_BITS_ALL) != VM_PAGE_BITS_ALL) {
@@ -542,13 +544,13 @@ exec_map_first_page(struct image_params *imgp)
                                vm_page_protect(m, VM_PROT_NONE);
                                vm_page_free(m);
                        }
-                       splx(s);
+                       crit_exit();
                        return EIO;
                }
        }
        vm_page_hold(m);
        vm_page_wakeup(m);      /* unbusy the page */
-       splx(s);
+       crit_exit();
 
        imgp->firstpage = sf_buf_alloc(m, SFBA_QUICK);
        imgp->image_header = (void *)sf_buf_kva(imgp->firstpage);
@@ -561,9 +563,8 @@ exec_unmap_first_page(imgp)
        struct image_params *imgp;
 {
        vm_page_t m;
-       int s;
 
-       s = splvm();
+       crit_enter();
        if (imgp->firstpage != NULL) {
                m = sf_buf_page(imgp->firstpage);
                sf_buf_free(imgp->firstpage);
@@ -571,7 +572,7 @@ exec_unmap_first_page(imgp)
                imgp->image_header = NULL;
                vm_page_unhold(m);
        }
-       splx(s);
+       crit_exit();
 }
 
 /*
index 5533048..5eeed44 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_exit.c 8.7 (Berkeley) 2/12/94
  * $FreeBSD: src/sys/kern/kern_exit.c,v 1.92.2.11 2003/01/13 22:51:16 dillon Exp $
- * $DragonFly: src/sys/kern/kern_exit.c,v 1.38 2004/09/17 01:29:45 joerg Exp $
+ * $DragonFly: src/sys/kern/kern_exit.c,v 1.39 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -260,15 +260,21 @@ exit1(int rv)
                                 * if we blocked.
                                 */
                                if ((vp = sp->s_ttyvp) != NULL) {
-                                       sp->s_ttyvp = NULL;
-                                       VOP_REVOKE(vp, REVOKEALL);
-                                       vrele(vp);
+                                       ttyclosesession(sp, 0);
+                                       if (vx_lock(vp) == 0) {
+                                               VOP_REVOKE(vp, REVOKEALL);
+                                               vx_unlock(vp);
+                                       }
+                                       vrele(vp);      /* s_ttyvp ref */
                                }
                        }
-                       if ((vp = sp->s_ttyvp) != NULL) {
-                               sp->s_ttyvp = NULL;
-                               vrele(vp);
-                       }
+                       /*
+                        * Release the tty.  If someone has it open via
+                        * /dev/tty then close it (since they no longer can
+                        * once we've NULL'd it out).
+                        */
+                       if (sp->s_ttyvp)
+                               ttyclosesession(sp, 1);
                        /*
                         * s_ttyp is not zero'd; we use this to indicate
                         * that the session once had a controlling terminal.
index 0877dd7..396e76b 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_fork.c 8.6 (Berkeley) 4/8/94
  * $FreeBSD: src/sys/kern/kern_fork.c,v 1.72.2.14 2003/06/26 04:15:10 silby Exp $
- * $DragonFly: src/sys/kern/kern_fork.c,v 1.29 2004/09/17 01:29:45 joerg Exp $
+ * $DragonFly: src/sys/kern/kern_fork.c,v 1.30 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -473,6 +473,11 @@ again:
        if (flags & RFPPWAIT)
                p2->p_flag |= P_PPWAIT;
 
+       /*
+        * Once we are on a pglist we may receive signals.  XXX we might
+        * race a ^C being sent to the process group by not receiving it
+        * at all prior to this line.
+        */
        LIST_INSERT_AFTER(p1, p2, p_pglist);
 
        /*
index 1c56d99..79856b3 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/kern_fp.c,v 1.7 2004/07/29 20:32:59 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_fp.c,v 1.8 2004/10/12 19:20:46 dillon Exp $
  */
 
 /*
@@ -119,7 +119,7 @@ fp_open(const char *path, int flags, int mode, file_t *fpp)
        fp->f_flag = flags;
        fp->f_ops = &vnops;
        fp->f_type = DTYPE_VNODE;
-       VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+       VOP_UNLOCK(nd.ni_vp, 0, td);
     } else {
        fdrop(fp, td);
        *fpp = NULL;
@@ -205,7 +205,7 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp)
     if (flags & FWRITE)
        vp->v_writecount++;
 done:
-    VOP_UNLOCK(vp, NULL, 0, td);
+    VOP_UNLOCK(vp, 0, td);
     return (error);
 }
 
index 172c6ff..b83585e 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)kern_ktrace.c       8.2 (Berkeley) 9/23/93
  * $FreeBSD: src/sys/kern/kern_ktrace.c,v 1.35.2.6 2002/07/05 22:36:38 darrenr Exp $
- * $DragonFly: src/sys/kern/kern_ktrace.c,v 1.15 2004/05/21 15:41:23 drhodus Exp $
+ * $DragonFly: src/sys/kern/kern_ktrace.c,v 1.16 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -268,7 +268,7 @@ ktrace(struct ktrace_args *uap)
                }
                NDFREE(&nd, NDF_ONLY_PNBUF);
                vp = nd.ni_vp;
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
                if (vp->v_type != VREG) {
                        (void) vn_close(vp, FREAD|FWRITE, td);
                        curp->p_traceflag &= ~KTRFAC_ACTIVE;
@@ -488,13 +488,13 @@ ktrwrite(struct vnode *vp, struct ktr_header *kth, struct uio *uio)
                        kth->ktr_len += uio->uio_resid;
        }
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred);
        if (error == 0 && uio != NULL) {
                VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
                error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred);
        }
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        if (!error)
                return;
        /*
index 25b2d0b..de28449 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_linker.c,v 1.41.2.3 2001/11/21 17:50:35 luigi Exp $
- * $DragonFly: src/sys/kern/kern_linker.c,v 1.18 2004/03/01 06:33:17 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_linker.c,v 1.19 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_ddb.h"
@@ -1129,7 +1129,7 @@ linker_search_path(const char *name)
        if (error == 0) {
            NDFREE(&nd, NDF_ONLY_PNBUF);
            type = nd.ni_vp->v_type;
-           VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+           VOP_UNLOCK(nd.ni_vp, 0, td);
            vn_close(nd.ni_vp, FREAD, td);
            if (type == VREG)
                return(result);
index 89efe8d..ea0a838 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_sig.c  8.7 (Berkeley) 4/18/94
  * $FreeBSD: src/sys/kern/kern_sig.c,v 1.72.2.17 2003/05/16 16:34:34 obrien Exp $
- * $DragonFly: src/sys/kern/kern_sig.c,v 1.30 2004/04/15 00:51:32 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_sig.c,v 1.31 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -959,6 +959,9 @@ psignal(struct proc *p, int sig)
                 * other than kicking ourselves if we are running.
                 * It will either never be noticed, or noticed very soon.
                 *
+                * Note that p_thread may be NULL or may not be completely
+                * initialized if the process is in the SIDL or SZOMB state.
+                *
                 * For SMP we may have to forward the request to another cpu.
                 * YYY the MP lock prevents the target process from moving
                 * to another cpu, see kern/kern_switch.c
@@ -970,9 +973,13 @@ psignal(struct proc *p, int sig)
 #ifdef SMP
                if (p == lwkt_preempted_proc()) {
                        signotify();
-               } else {
+               } else if (p->p_stat == SRUN) {
                        struct thread *td = p->p_thread;
 
+                       KASSERT(td != NULL, 
+                           ("pid %d NULL p_thread stat %d flags %08x",
+                           p->p_pid, p->p_stat, p->p_flag));
+
                        if (td->td_gd != mycpu)
                                lwkt_send_ipiq(td->td_gd, signotify_remote, p);
                        else if (td->td_msgport.mp_flags & MSGPORTF_WAITING)
@@ -981,8 +988,13 @@ psignal(struct proc *p, int sig)
 #else
                if (p == lwkt_preempted_proc()) {
                        signotify();
-               } else {
+               } else if (p->p_stat == SRUN) {
                        struct thread *td = p->p_thread;
+
+                       KASSERT(td != NULL, 
+                           ("pid %d NULL p_thread stat %d flags %08x",
+                           p->p_pid, p->p_stat, p->p_flag));
+
                        if (td->td_msgport.mp_flags & MSGPORTF_WAITING)
                                lwkt_schedule(td);
                }
@@ -1473,7 +1485,7 @@ coredump(struct proc *p)
        NDFREE(&nd, NDF_ONLY_PNBUF);
        vp = nd.ni_vp;
 
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        lf.l_whence = SEEK_SET;
        lf.l_start = 0;
        lf.l_len = 0;
@@ -1490,12 +1502,12 @@ coredump(struct proc *p)
        }
 
        VATTR_NULL(&vattr);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        vattr.va_size = 0;
        VOP_LEASE(vp, td, cred, LEASE_WRITE);
        VOP_SETATTR(vp, &vattr, cred, td);
        p->p_acflag |= ACORE;
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
 
        error = p->p_sysent->sv_coredump ?
          p->p_sysent->sv_coredump(p, vp, limit) :
index 7f9bfa8..af5e824 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/link_aout.c,v 1.26 1999/12/24 15:33:36 bde Exp $
- * $DragonFly: src/sys/kern/link_aout.c,v 1.11 2004/05/21 15:41:23 drhodus Exp $
+ * $DragonFly: src/sys/kern/link_aout.c,v 1.12 2004/10/12 19:20:46 dillon Exp $
  */
 
 #ifndef __alpha__
@@ -286,7 +286,7 @@ link_aout_load_file(const char* filename, linker_file_t* result)
     *result = lf;
 
 out:
-    VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+    VOP_UNLOCK(nd.ni_vp, 0, td);
     vn_close(nd.ni_vp, FREAD, td);
 
     return error;
index 58cfbe4..4169675 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/link_elf.c,v 1.24 1999/12/24 15:33:36 bde Exp $
- * $DragonFly: src/sys/kern/link_elf.c,v 1.13 2004/03/20 16:27:41 drhodus Exp $
+ * $DragonFly: src/sys/kern/link_elf.c,v 1.14 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -696,7 +696,7 @@ out:
        free(shdr, M_LINKER);
     if (firstpage)
        free(firstpage, M_LINKER);
-    VOP_UNLOCK(nd.ni_vp, NULL, 0, td);
+    VOP_UNLOCK(nd.ni_vp, 0, td);
     vn_close(nd.ni_vp, FREAD, td);
 
     return error;
index baeda44..2bd19d8 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)tty.c       8.8 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/tty.c,v 1.129.2.5 2002/03/11 01:32:31 dd Exp $
- * $DragonFly: src/sys/kern/tty.c,v 1.13 2004/10/07 01:32:03 dillon Exp $
+ * $DragonFly: src/sys/kern/tty.c,v 1.14 2004/10/12 19:20:46 dillon Exp $
  */
 
 /*-
@@ -289,6 +289,31 @@ ttyclearsession(struct tty *tp)
        }
 }
 
+/*
+ * Terminate the tty vnode association for a session.  This is the 
+ * 'other half' of the close.
+ */
+void
+ttyclosesession(struct session *sp, int dorele)
+{
+       struct vnode *vp;
+       struct thread *td = curthread;
+
+       if ((vp = sp->s_ttyvp) == NULL)
+               return;
+       sp->s_ttyvp = NULL;
+       if (vp->v_flag & VCTTYISOPEN) {
+               if (vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, td) == 0) {
+                       vclrflags(vp, VCTTYISOPEN);
+                       VOP_CLOSE(vp, 0, td);
+                       VOP_UNLOCK(vp, 0, td);
+               }
+       }
+       if (dorele)
+               vrele(vp);
+}
+
+
 #define        FLUSHQ(q) {                                                     \
        if ((q)->c_cc)                                                  \
                ndflush(q, (q)->c_cc);                                  \
index 15eacbe..9070030 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)tty_tty.c   8.2 (Berkeley) 9/23/93
  * $FreeBSD: src/sys/kern/tty_tty.c,v 1.30 1999/09/25 18:24:24 phk Exp $
- * $DragonFly: src/sys/kern/tty_tty.c,v 1.9 2004/05/19 22:52:58 dillon Exp $
+ * $DragonFly: src/sys/kern/tty_tty.c,v 1.10 2004/10/12 19:20:46 dillon Exp $
  */
 
 /*
@@ -89,9 +89,14 @@ cttyopen(dev_t dev, int flag, int mode, struct thread *td)
        KKASSERT(p);
        ttyvp = cttyvp(p);
        if (ttyvp) {
-               vn_lock(ttyvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
-               error = VOP_OPEN(ttyvp, flag, NOCRED, td);
-               VOP_UNLOCK(ttyvp, NULL, 0, td);
+               if (ttyvp->v_flag & VCTTYISOPEN) {
+                       error = 0;
+               } else {
+                       vsetflags(ttyvp, VCTTYISOPEN);
+                       vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
+                       error = VOP_OPEN(ttyvp, flag, NOCRED, td);
+                       VOP_UNLOCK(ttyvp, 0, td);
+               }
        } else {
                error = ENXIO;
        }
@@ -107,10 +112,23 @@ cttyclose(dev_t dev, int fflag, int devtype, struct thread *td)
 
        KKASSERT(p);
        ttyvp = cttyvp(p);
-       if (ttyvp == NULL)
-               error = EIO;
-       else
-               error = VOP_CLOSE(ttyvp, fflag, td);
+       if (ttyvp == NULL) {
+               /*
+                * The tty may have been TIOCNOTTY'd, don't return an
+                * error on close.  We just have nothing to do.
+                */
+               /* error = EIO; */
+               error = 0;
+       } else if (ttyvp->v_flag & VCTTYISOPEN) {
+               vclrflags(ttyvp, VCTTYISOPEN);
+               error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
+               if (error == 0) {
+                       error = VOP_CLOSE(ttyvp, fflag, td);
+                       VOP_UNLOCK(ttyvp, 0, td);
+               }
+       } else {
+               error = 0;
+       }
        return(error);
 }
 
@@ -130,9 +148,9 @@ cttyread(dev, uio, flag)
        ttyvp = cttyvp(p);
        if (ttyvp == NULL)
                return (EIO);
-       vn_lock(ttyvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
        error = VOP_READ(ttyvp, uio, flag, NOCRED);
-       VOP_UNLOCK(ttyvp, NULL, 0, td);
+       VOP_UNLOCK(ttyvp, 0, td);
        return (error);
 }
 
@@ -152,9 +170,9 @@ cttywrite(dev, uio, flag)
        ttyvp = cttyvp(p);
        if (ttyvp == NULL)
                return (EIO);
-       vn_lock(ttyvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
        error = VOP_WRITE(ttyvp, uio, flag, NOCRED);
-       VOP_UNLOCK(ttyvp, NULL, 0, td);
+       VOP_UNLOCK(ttyvp, 0, td);
        return (error);
 }
 
index 85a68f8..ca7da9e 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)uipc_syscalls.c     8.4 (Berkeley) 2/21/94
  * $FreeBSD: src/sys/kern/uipc_syscalls.c,v 1.65.2.17 2003/04/04 17:11:16 tegge Exp $
- * $DragonFly: src/sys/kern/uipc_syscalls.c,v 1.41 2004/08/24 21:53:38 dillon Exp $
+ * $DragonFly: src/sys/kern/uipc_syscalls.c,v 1.42 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -1299,17 +1299,16 @@ sf_buf_mfree(void *arg)
 {
        struct sfbuf_mref *sfm = arg;
        vm_page_t m;
-       int s;
 
        KKASSERT(sfm->mref_count > 0);
        if (--sfm->mref_count == 0) {
                m = sf_buf_page(sfm->sf);
                sf_buf_free(sfm->sf);
-               s = splvm();
+               crit_enter();
                vm_page_unwire(m, 0);
                if (m->wire_count == 0 && m->object == NULL)
                        vm_page_free(m);
-               splx(s);
+               crit_exit();
                free(sfm, M_SENDFILE);
        }
 }
@@ -1449,7 +1448,6 @@ kern_sendfile(struct vnode *vp, int sfd, off_t offset, size_t nbytes,
        off_t off, xfsize;
        off_t hbytes = 0;
        int error = 0;
-       int s;
 
        if (vp->v_type != VREG || VOP_GETVOBJECT(vp, &obj) != 0) {
                error = EINVAL;
@@ -1520,26 +1518,27 @@ retry_lookup:
                 * Attempt to look up the page.  
                 *
                 *      Allocate if not found, wait and loop if busy, then
-                *      wire the page.  splvm() protection is required to
-                *      maintain the object association (an interrupt can
-                *      free the page) through to the vm_page_wire() call.
+                *      wire the page.  critical section protection is
+                *      required to maintain the object association (an
+                *      interrupt can free the page) through to the
+                *      vm_page_wire() call.
                 */
-               s = splvm();
+               crit_enter();
                pg = vm_page_lookup(obj, pindex);
                if (pg == NULL) {
                        pg = vm_page_alloc(obj, pindex, VM_ALLOC_NORMAL);
                        if (pg == NULL) {
                                vm_wait();
-                               splx(s);
+                               crit_exit();
                                goto retry_lookup;
                        }
                        vm_page_wakeup(pg);
                } else if (vm_page_sleep_busy(pg, TRUE, "sfpbsy")) {
-                       splx(s);
+                       crit_exit();
                        goto retry_lookup;
                }
                vm_page_wire(pg);
-               splx(s);
+               crit_exit();
 
                /*
                 * If page is not valid for what we need, initiate I/O
@@ -1569,11 +1568,11 @@ retry_lookup:
                        auio.uio_segflg = UIO_NOCOPY;
                        auio.uio_rw = UIO_READ;
                        auio.uio_td = td;
-                       vn_lock(vp, NULL, LK_SHARED | LK_NOPAUSE | LK_RETRY, td);
+                       vn_lock(vp, LK_SHARED | LK_NOPAUSE | LK_RETRY, td);
                        error = VOP_READ(vp, &auio, 
                                    IO_VMIO | ((MAXBSIZE / bsize) << 16),
                                    p->p_ucred);
-                       VOP_UNLOCK(vp, NULL, 0, td);
+                       VOP_UNLOCK(vp, 0, td);
                        vm_page_flag_clear(pg, PG_ZERO);
                        vm_page_io_finish(pg);
                        if (error) {
@@ -1599,11 +1598,11 @@ retry_lookup:
                 * but this wait can be interrupted.
                 */
                if ((sf = sf_buf_alloc(pg, SFBA_PCATCH)) == NULL) {
-                       s = splvm();
+                       crit_enter();
                        vm_page_unwire(pg, 0);
                        if (pg->wire_count == 0 && pg->object == NULL)
                                vm_page_free(pg);
-                       splx(s);
+                       crit_exit();
                        sbunlock(&so->so_snd);
                        error = EINTR;
                        goto done;
@@ -1649,7 +1648,7 @@ retry_lookup:
                /*
                 * Add the buffer to the socket buffer chain.
                 */
-               s = splnet();
+               crit_enter();
 retry_space:
                /*
                 * Make sure that the socket is still able to take more data.
@@ -1671,7 +1670,7 @@ retry_space:
                        }
                        m_freem(m);
                        sbunlock(&so->so_snd);
-                       splx(s);
+                       crit_exit();
                        goto done;
                }
                /*
@@ -1683,7 +1682,7 @@ retry_space:
                        if (so->so_state & SS_NBIO) {
                                m_freem(m);
                                sbunlock(&so->so_snd);
-                               splx(s);
+                               crit_exit();
                                error = EAGAIN;
                                goto done;
                        }
@@ -1696,13 +1695,13 @@ retry_space:
                        if (error) {
                                m_freem(m);
                                sbunlock(&so->so_snd);
-                               splx(s);
+                               crit_exit();
                                goto done;
                        }
                        goto retry_space;
                }
                error = so_pru_send(so, 0, m, NULL, NULL, td);
-               splx(s);
+               crit_exit();
                if (error) {
                        sbunlock(&so->so_snd);
                        goto done;
index 30f0ce5..3d12d11 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/kern/uipc_usrreq.c,v 1.54.2.10 2003/03/04 17:28:09 nectar Exp $
- * $DragonFly: src/sys/kern/uipc_usrreq.c,v 1.15 2004/06/06 19:16:06 dillon Exp $
+ * $DragonFly: src/sys/kern/uipc_usrreq.c,v 1.16 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -626,7 +626,7 @@ unp_bind(struct unpcb *unp, struct sockaddr *nam, struct thread *td)
        vp->v_socket = unp->unp_socket;
        unp->unp_vnode = vp;
        unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return (0);
 }
 
index 2496bf6..1208393 100644 (file)
@@ -67,7 +67,7 @@
  *
  *     @(#)vfs_cache.c 8.5 (Berkeley) 3/22/95
  * $FreeBSD: src/sys/kern/vfs_cache.c,v 1.42.2.6 2001/10/05 20:07:03 dillon Exp $
- * $DragonFly: src/sys/kern/vfs_cache.c,v 1.37 2004/10/07 20:18:33 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_cache.c,v 1.38 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -356,12 +356,16 @@ cache_lock(struct namecache *ncp)
                }
                ncp->nc_flag |= NCF_LOCKREQ;
                if (tsleep(ncp, 0, "clock", hz) == EWOULDBLOCK) {
-                       if (didwarn == 0) {
-                               didwarn = 1;
-                               printf("[diagnostic] cache_lock: blocked on %*.*s\n",
-                                       ncp->nc_nlen, ncp->nc_nlen,
-                                       ncp->nc_name);
-                       }
+                       if (didwarn)
+                               continue;
+                       didwarn = 1;
+                       printf("[diagnostic] cache_lock: blocked on %p", ncp);
+                       if ((ncp->nc_flag & NCF_MOUNTPT) && ncp->nc_mount)
+                           printf(" [MOUNTPT %s]\n", ncp->nc_mount->mnt_stat.f_mntonname);
+                       else
+                           printf(" \"%*.*s\"\n",
+                               ncp->nc_nlen, ncp->nc_nlen,
+                               ncp->nc_name);
                }
        }
 
@@ -638,7 +642,7 @@ again:
                error = 0;
        }
        if (error == 0 && (vp = ncp->nc_vp) != NULL) {
-               error = vget(vp, NULL, lk_type, curthread);
+               error = vget(vp, lk_type, curthread);
                if (error) {
                        if (vp != ncp->nc_vp)   /* handle cache_zap race */
                                goto again;
@@ -1438,11 +1442,12 @@ nchinit(void)
  * a referenced, unlocked namecache record.
  */
 struct namecache *
-cache_allocroot(struct vnode *vp)
+cache_allocroot(struct mount *mp, struct vnode *vp)
 {
        struct namecache *ncp = cache_alloc(0);
 
        ncp->nc_flag |= NCF_MOUNTPT | NCF_ROOT;
+       ncp->nc_mount = mp;
        cache_setvp(ncp, vp);
        return(ncp);
 }
@@ -1546,29 +1551,6 @@ cache_purgevfs(struct mount *mp)
        }
 }
 
-/*
- * cache_leaf_test()
- *
- *     Test whether the vnode is at a leaf in the nameicache tree.
- *
- *     Returns 0 if it is a leaf, -1 if it isn't.
- */
-int
-cache_leaf_test(struct vnode *vp)
-{
-       struct namecache *scan;
-       struct namecache *ncp;
-
-       TAILQ_FOREACH(scan, &vp->v_namecache, nc_vnode) {
-               TAILQ_FOREACH(ncp, &scan->nc_list, nc_entry) {
-                       /* YYY && ncp->nc_vp->v_type == VDIR ? */
-                       if (ncp->nc_vp != NULL)
-                               return(-1);
-               }
-       }
-       return(0);
-}
-
 /*
  * Perform canonical checks and cache lookup and pass on to filesystem
  * through the vop_cachedlookup only if needed.
@@ -1627,19 +1609,19 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
                /* already ref'd from cache_lookup() */
                error = 0;
        } else if (flags & CNP_ISDOTDOT) {
-               VOP_UNLOCK(dvp, NULL, 0, td);
+               VOP_UNLOCK(dvp, 0, td);
                cnp->cn_flags |= CNP_PDIRUNLOCK;
-               error = vget(vp, NULL, LK_EXCLUSIVE, td);
+               error = vget(vp, LK_EXCLUSIVE, td);
                vrele(vp);
                if (!error && lockparent && (flags & CNP_ISLASTCN)) {
-                       if ((error = vn_lock(dvp, NULL, LK_EXCLUSIVE, td)) == 0)
+                       if ((error = vn_lock(dvp, LK_EXCLUSIVE, td)) == 0)
                                cnp->cn_flags &= ~CNP_PDIRUNLOCK;
                }
        } else {
-               error = vget(vp, NULL, LK_EXCLUSIVE, td);
+               error = vget(vp, LK_EXCLUSIVE, td);
                vrele(vp);
                if (!lockparent || error || !(flags & CNP_ISLASTCN)) {
-                       VOP_UNLOCK(dvp, NULL, 0, td);
+                       VOP_UNLOCK(dvp, 0, td);
                        cnp->cn_flags |= CNP_PDIRUNLOCK;
                }
        }
@@ -1652,12 +1634,12 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
                        return (0);
                vput(vp);
                if (lockparent && dvp != vp && (flags & CNP_ISLASTCN)) {
-                       VOP_UNLOCK(dvp, NULL, 0, td);
+                       VOP_UNLOCK(dvp, 0, td);
                        cnp->cn_flags |= CNP_PDIRUNLOCK;
                }
        }
        if (cnp->cn_flags & CNP_PDIRUNLOCK) {
-               error = vn_lock(dvp, NULL, LK_EXCLUSIVE, td);
+               error = vn_lock(dvp, LK_EXCLUSIVE, td);
                if (error)
                        return (error);
                cnp->cn_flags &= ~CNP_PDIRUNLOCK;
index b9fafbc..20ac585 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.20 2004/10/07 10:03:02 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_default.c,v 1.21 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -191,7 +191,7 @@ vop_noresolve(struct vop_resolve_args *ap)
        if ((dvp = ncp->nc_parent->nc_vp) == NULL)
                return(EPERM);
 
-       if ((error = vget(dvp, NULL, LK_EXCLUSIVE, curthread)) != 0) {
+       if ((error = vget(dvp, LK_EXCLUSIVE, curthread)) != 0) {
                printf("[diagnostic] vop_noresolve: EAGAIN on ncp %p %*.*s\n",
                        ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
                return(EAGAIN);
@@ -211,9 +211,9 @@ vop_noresolve(struct vop_resolve_args *ap)
         */
        error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
        if (error == 0)
-               VOP_UNLOCK(vp, NULL, 0, curthread);
+               VOP_UNLOCK(vp, 0, curthread);
        if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
-               VOP_UNLOCK(dvp, NULL, 0, curthread);
+               VOP_UNLOCK(dvp, 0, curthread);
        if ((ncp->nc_flag & NCF_UNRESOLVED) == 0) {
                /* was resolved by another process while we were unlocked */
                if (error == 0)
@@ -373,7 +373,6 @@ int
 vop_stdlock(ap)
        struct vop_lock_args /* {
                struct vnode *a_vp;
-               lwkt_tokref_t a_vlock;
                int a_flags;
                struct proc *a_p;
        } */ *ap;
@@ -381,11 +380,10 @@ vop_stdlock(ap)
        int error;
 
 #ifndef        DEBUG_LOCKS
-       error = lockmgr(&ap->a_vp->v_lock, ap->a_flags,
-                       ap->a_vlock, ap->a_td);
+       error = lockmgr(&ap->a_vp->v_lock, ap->a_flags, NULL, ap->a_td);
 #else
        error = debuglockmgr(&ap->a_vp->v_lock, ap->a_flags,
-                       ap->a_vlock, ap->a_td,
+                       NULL, ap->a_td,
                        "vop_stdlock", ap->a_vp->filename, ap->a_vp->line);
 #endif
        return(error);
@@ -395,7 +393,6 @@ int
 vop_stdunlock(ap)
        struct vop_unlock_args /* {
                struct vnode *a_vp;
-               lwkt_tokref_t a_vlock;
                int a_flags;
                struct thread *a_td;
        } */ *ap;
@@ -403,7 +400,7 @@ vop_stdunlock(ap)
        int error;
 
        error = lockmgr(&ap->a_vp->v_lock, ap->a_flags | LK_RELEASE,
-                       ap->a_vlock, ap->a_td);
+                       NULL, ap->a_td);
        return(error);
 }
 
@@ -508,9 +505,9 @@ retry:
                vp->v_usecount--;
        } else {
                if (object->flags & OBJ_DEAD) {
-                       VOP_UNLOCK(vp, NULL, 0, td);
+                       VOP_UNLOCK(vp, 0, td);
                        tsleep(object, 0, "vodead", 0);
-                       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+                       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
                        goto retry;
                }
        }
index 0e760a7..f89f47c 100644 (file)
@@ -70,7 +70,7 @@
  *
  *     @(#)vfs_init.c  8.3 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/kern/vfs_init.c,v 1.59 2002/04/30 18:44:32 dillon Exp $
- * $DragonFly: src/sys/kern/vfs_init.c,v 1.6 2004/08/17 18:57:32 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_init.c,v 1.7 2004/10/12 19:20:46 dillon Exp $
  */
 /*
  * Manage vnode VOP operations vectors
@@ -84,7 +84,7 @@
 #include <sys/malloc.h>
 #include <vm/vm_zone.h>
 
-MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
+static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
 
 /*
  * Zone for namei
@@ -129,9 +129,10 @@ vfs_add_vnodeops(struct vop_ops **vops_pp, struct vnodeopv_entry_desc *descs)
        struct vnodeopv_node *node;
        struct vop_ops *ops;
 
-       node = malloc(sizeof(*node), M_VNODE, M_ZERO|M_WAITOK);
+       node = malloc(sizeof(*node), M_VNODEOP, M_ZERO|M_WAITOK);
        if ((ops = *vops_pp) == NULL) {
-               ops = malloc(sizeof(struct vop_ops), M_VNODE, M_ZERO|M_WAITOK);
+               ops = malloc(sizeof(struct vop_ops),
+                               M_VNODEOP, M_ZERO|M_WAITOK);
                *vops_pp = ops;
        }
        node->ops = ops;
@@ -159,11 +160,11 @@ vfs_rm_vnodeops(struct vop_ops **vops_pp)
                return;
        }
        TAILQ_REMOVE(&vnodeopv_list, node, entry);
-       free(node, M_VNODE);
+       free(node, M_VNODEOP);
        KKASSERT(ops != NULL && ops->vv_refs > 0);
        if (--ops->vv_refs == 0) {
                *vops_pp = NULL;
-               free(ops, M_VNODE);
+               free(ops, M_VNODEOP);
        }
        vfs_recalc_vnodeops();
 }
@@ -191,7 +192,7 @@ vfs_recalc_vnodeops(void)
                ops = node->ops;
                if ((vnew = ops->vv_new) == NULL) {
                        vnew = malloc(sizeof(struct vop_ops),
-                                       M_VNODE, M_ZERO|M_WAITOK);
+                                       M_VNODEOP, M_ZERO|M_WAITOK);
                        ops->vv_new = vnew;
                        vnew->vop_default = vop_eopnotsupp;
                }
@@ -224,7 +225,7 @@ vfs_recalc_vnodeops(void)
                                *(void **)((char *)vnew + off);
                }
                ops->vv_new = NULL;
-               free(vnew, M_VNODE);
+               free(vnew, M_VNODEOP);
        }
 }
 
@@ -246,7 +247,10 @@ vfsinit(void *dummy)
        /*
         * Initialize the vnode table
         */
-       vntblinit();
+       vfs_subr_init();
+       vfs_mount_init();
+       vfs_lock_init();
+       vfs_sync_init();
        /*
         * Initialize the vnode name cache
         */
diff --git a/sys/kern/vfs_lock.c b/sys/kern/vfs_lock.c
new file mode 100644 (file)
index 0000000..7946ba2
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
+ * 
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/kern/vfs_lock.c,v 1.1 2004/10/12 19:20:46 dillon Exp $
+ */
+
+/*
+ * External virtual filesystem routines
+ */
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/buf.h>
+#include <sys/sysctl.h>
+
+#include <machine/limits.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+
+#include <sys/buf2.h>
+#include <sys/thread2.h>
+
+
+static MALLOC_DEFINE(M_VNODE, "vnodes", "vnode structures");
+
+static TAILQ_HEAD(freelst, vnode) vnode_free_list;     /* vnode free list */
+
+int  freevnodes = 0;
+SYSCTL_INT(_debug, OID_AUTO, freevnodes, CTLFLAG_RD,
+               &freevnodes, 0, "");
+static int wantfreevnodes = 25;
+SYSCTL_INT(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW,
+               &wantfreevnodes, 0, "");
+static int minvnodes;
+SYSCTL_INT(_kern, OID_AUTO, minvnodes, CTLFLAG_RW,
+               &minvnodes, 0, "Minimum number of vnodes");
+
+/*
+ * Called from vfsinit()
+ */
+void
+vfs_lock_init(void)
+{
+       minvnodes = desiredvnodes / 4;
+
+       TAILQ_INIT(&vnode_free_list);
+}
+
+/*
+ * Inline helper functions.  vbusy() and vfree() must be called while in a
+ * critical section.
+ */
+static __inline 
+void
+__vbusy(struct vnode *vp)
+{
+       KKASSERT(vp->v_flag & VFREE);
+       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
+       freevnodes--;
+       vp->v_flag &= ~(VFREE|VAGE);
+}
+
+static __inline
+void
+__vfree(struct vnode *vp)
+{
+       KKASSERT((vp->v_flag & VFREE) == 0);
+       if (vp->v_flag & (VAGE|VRECLAIMED))
+               TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
+       else
+               TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
+       freevnodes++;
+       vp->v_flag &= ~VAGE;
+       vp->v_flag |= VFREE;
+}
+
+/*
+ * Return 1 if we can immediately place the vnode on the freelist.
+ */
+static __inline int
+vshouldfree(struct vnode *vp, int usecount)
+{
+       if (vp->v_holdcnt != 0 || vp->v_usecount != usecount)
+               return (0);             /* other holderse */
+       if (vp->v_object &&
+           (vp->v_object->ref_count || vp->v_object->resident_page_count)) {
+               return (0);
+       }
+       return (1);
+}
+
+/*
+ * Reference a vnode or release the reference on a vnode.  The vnode will
+ * be taken off the freelist if it is on it and cannot be recycled or 
+ * deactivated while refd.  The last release of a vnode will deactivate the
+ * vnode via VOP_INACTIVE().
+ *
+ * Special cases: refing a vnode does not clear VINACTIVE, you have to vget()
+ * the vnode shared or exclusive to do that.
+ */
+static __inline
+void
+__vref(struct vnode *vp)
+{
+       ++vp->v_usecount;
+       if (vp->v_flag & VFREE)
+               __vbusy(vp);
+}
+
+void
+vref(struct vnode *vp)
+{
+       crit_enter();
+       __vref(vp);
+       crit_exit();
+}
+
+void
+vrele(struct vnode *vp)
+{
+       thread_t td = curthread;
+
+       crit_enter();
+       if (vp->v_usecount == 1) {
+               KKASSERT(lockcount(&vp->v_lock) == 0);
+
+               /*
+                * Deactivation requires an exclusive v_lock (vx_lock()), and
+                * only occurs if the usecount is still 1 after locking.
+                */
+               if ((vp->v_flag & VINACTIVE) == 0) {
+                       if (vx_lock(vp) == 0) {
+                               if ((vp->v_flag & VINACTIVE) == 0 &&
+                                   vp->v_usecount == 1) {
+                                       vp->v_flag |= VINACTIVE;
+                                       VOP_INACTIVE(vp, td);
+                               }
+                               vx_unlock(vp);
+                       }
+               }
+               if (vshouldfree(vp, 1))
+                       __vfree(vp);
+       } else {
+               KKASSERT(vp->v_usecount > 0);
+       }
+       --vp->v_usecount;
+       crit_exit();
+}
+
+/*
+ * Hold a vnode or drop the hold on a vnode.  The vnode will be taken off
+ * the freelist if it is on it and cannot be recycled.  However, the
+ * vnode can be deactivated and reactivated while held.
+ *
+ * Special cases: The last drop of a vnode does nothing special, allowing it
+ * to be called from an interrupt.  vrele() on the otherhand cannot be called
+ * from an interrupt.
+ */
+void
+vhold(struct vnode *vp)
+{
+       crit_enter();
+       ++vp->v_holdcnt;
+       if (vp->v_flag & VFREE)
+               __vbusy(vp);
+       crit_exit();
+}
+
+void
+vdrop(struct vnode *vp)
+{
+       crit_enter();
+       if (vp->v_holdcnt == 1) {
+               --vp->v_holdcnt;
+               if (vshouldfree(vp, 0))
+                       __vfree(vp);
+       } else {
+               --vp->v_holdcnt;
+               KKASSERT(vp->v_holdcnt > 0);
+       }
+       crit_exit();
+}
+
+/****************************************************************
+ *                     VX LOCKING FUNCTIONS                    *
+ ****************************************************************
+ *
+ * These functions lock vnodes for reclamation and deactivation ops.
+ * Only vp->v_lock, the top layer of the VFS, is locked.  You must be
+ * holding a normal reference in order to be able to safely call vx_lock()
+ * and vx_unlock().  vx_get() and vx_put() are combination functions which
+ * vref+vx_lock and vrele+vx_unlock.
+ */
+
+#define VXLOCKFLAGS    (LK_EXCLUSIVE|LK_RETRY)
+#define VXLOCKFLAGS_NB (LK_EXCLUSIVE|LK_NOWAIT)
+
+static int
+__vxlock(struct vnode *vp, int flags)
+{
+       return(lockmgr(&vp->v_lock, flags, NULL, curthread));
+}
+
+static void
+__vxunlock(struct vnode *vp)
+{
+       lockmgr(&vp->v_lock, LK_RELEASE, NULL, curthread);
+}
+
+int
+vx_lock(struct vnode *vp)
+{
+       return(__vxlock(vp, VXLOCKFLAGS));
+}
+
+void
+vx_unlock(struct vnode *vp)
+{
+       __vxunlock(vp);
+}
+
+int
+vx_get(struct vnode *vp)
+{
+       int error;
+
+       vref(vp);
+       if ((error = __vxlock(vp, VXLOCKFLAGS)) != 0)
+               vrele(vp);
+       return(error);
+}
+
+int
+vx_get_nonblock(struct vnode *vp)
+{
+       int error;
+
+       vref(vp);
+       if ((error = __vxlock(vp, VXLOCKFLAGS_NB)) != 0)
+               vrele(vp);
+       return(error);
+}
+
+void
+vx_put(struct vnode *vp)
+{
+       __vxunlock(vp);
+       vrele(vp);
+}
+
+/****************************************************************
+ *                     VNODE ACQUISITION FUNCTIONS             *
+ ****************************************************************
+ *
+ * vget() and vput() access a vnode for the intent of executing an
+ * operation other then a reclamation or deactivation.  vget() will ref
+ * and lock the vnode, vput() will unlock and deref the vnode.  
+ * The VOP_*() locking functions are used.
+ *
+ * Special cases: If vget()'s locking operation fails the vrele() call may
+ * cause the vnode to be deactivated (VOP_INACTIVE called).  However, this
+ * never occurs if the vnode is in a reclaimed state.  Vnodes in reclaimed
+ * states always return an error code of ENOENT.
+ *
+ * Special cases: vput() will unlock and, if it is the last reference, 
+ * deactivate the vnode.  The deactivation uses a separate non-layered
+ * VX lock after the normal unlock.  XXX make it more efficient.
+ */
+int
+vget(struct vnode *vp, int flags, thread_t td)
+{
+       int error;
+
+       crit_enter();
+       __vref(vp);
+       if (flags & LK_TYPE_MASK) {
+               if ((error = vn_lock(vp, flags, td)) != 0) {
+                       vrele(vp);
+               } else if (vp->v_flag & VRECLAIMED) {
+                       VOP_UNLOCK(vp, 0, td);
+                       vrele(vp);
+                       error = ENOENT;
+               } else {
+                       vp->v_flag &= ~VINACTIVE;
+                       error = 0;
+               }
+       } else {
+               panic("vget() called with no lock specified!");
+               error = ENOENT; /* not reached, compiler opt */
+       }
+       crit_exit();
+       return(error);
+}
+
+void
+vput(struct vnode *vp)
+{
+       VOP_UNLOCK(vp, 0, curthread);
+       vrele(vp);
+}
+
+void
+vsetflags(struct vnode *vp, int flags)
+{
+       crit_enter();
+       vp->v_flag |= flags;
+       crit_exit();
+}
+
+void
+vclrflags(struct vnode *vp, int flags)
+{
+       crit_enter();
+       vp->v_flag &= ~flags;
+       crit_exit();
+}
+
+/*
+ * Obtain a new vnode from the freelist, allocating more if necessary.
+ * The returned vnode is VX locked & refd.
+ */
+struct vnode *
+allocvnode(int lktimeout, int lkflags)
+{
+       struct thread *td;
+       struct vnode *vp;
+
+       /*
+        * Try to reuse vnodes if we hit the max.  This situation only
+        * occurs in certain large-memory (2G+) situations.  We cannot
+        * attempt to directly reclaim vnodes due to nasty recursion
+        * problems.
+        */
+       while (numvnodes - freevnodes > desiredvnodes)
+               vnlru_proc_wait();
+
+       td = curthread;
+       vp = NULL;
+
+       /*
+        * Attempt to reuse a vnode already on the free list, allocating
+        * a new vnode if we can't find one or if we have not reached a
+        * good minimum for good LRU performance.
+        */
+       if (freevnodes >= wantfreevnodes && numvnodes >= minvnodes) {
+               int count;
+
+               for (count = 0; count < freevnodes; count++) {
+                       /*
+                        * __VNODESCAN__
+                        *
+                        * Pull the next vnode off the free list and do some
+                        * sanity checks.  Note that regardless of how we
+                        * block, if freevnodes is non-zero there had better
+                        * be something on the list.
+                        */
+                       vp = TAILQ_FIRST(&vnode_free_list);
+                       if (vp == NULL)
+                               panic("getnewvnode: free vnode isn't");
+
+                       /*
+                        * Note the lack of a critical section.  We vx_get()
+                        * the vnode before we check it for validity, reducing
+                        * the number of checks we have to make.  The vx_get()
+                        * will pull it off the freelist.
+                        */
+                       if (vx_get(vp)) {
+                               vp = NULL;
+                               continue;
+                       }
+
+                       /*
+                        * Can this vnode be recycled?  It must be in a
+                        * VINACTIVE state with only our reference to it.
+                        * (vx_get(), unlike vget(), does not reactivate
+                        * the vnode).  vx_put() will recycle it onto the
+                        * end of the freelist.
+                        */
+                       if ((vp->v_flag & VINACTIVE) == 0 ||
+                           vp->v_holdcnt || vp->v_usecount != 1) {
+                               vx_put(vp);
+                               vp = NULL;
+                               continue;
+                       }
+
+                       /*
+                        * Ok, we can reclaim the vnode if it isn't already
+                        * in a reclaimed state.  If the reclamation fails,
+                        * or if someone else is referencing the vnode after
+                        * we have vgone()'d it, we recycle the vnode on the
+                        * freelist or hold it (by calling vx_put()).
+                        */
+                       if ((vp->v_flag & VRECLAIMED) == 0) {
+                               vgone(vp);
+                               if ((vp->v_flag & VRECLAIMED) == 0 ||
+                                   vp->v_holdcnt || vp->v_usecount != 1) {
+                                       vx_put(vp);
+                                       vp = NULL;
+                                       continue;
+                               }
+                       }
+                       KKASSERT(vp->v_flag & VINACTIVE);
+
+                       /*
+                        * We have a vnode!
+                        */
+                       break;
+               }
+       }
+
+       /*
+        * If we have a vp it will be refd and VX locked.
+        */
+       if (vp) {
+               vp->v_lease = NULL;
+
+#ifdef INVARIANTS
+               if (vp->v_data)
+                       panic("cleaned vnode isn't");
+               if (vp->v_numoutput)
+                       panic("Clean vnode has pending I/O's");
+               KKASSERT(vp->v_mount == NULL);
+#endif
+               vp->v_flag = 0;
+               vp->v_lastw = 0;
+               vp->v_lasta = 0;
+               vp->v_cstart = 0;
+               vp->v_clen = 0;
+               vp->v_socket = 0;
+               vp->v_writecount = 0;   /* XXX */
+               lockreinit(&vp->v_lock, 0, "vnode", lktimeout, lkflags);
+               KKASSERT(TAILQ_FIRST(&vp->v_namecache) == NULL);
+       } else {
+               /*
+                * A brand-new vnode (we could use malloc() here I think) XXX
+                */
+               vp = malloc(sizeof(struct vnode), M_VNODE, M_WAITOK|M_ZERO);
+               lwkt_token_init(&vp->v_pollinfo.vpi_token);
+               lockinit(&vp->v_lock, 0, "vnode", lktimeout, lkflags);
+               TAILQ_INIT(&vp->v_namecache);
+
+               /*
+                * short cut around vfreeing it and looping, just set it up
+                * as if we had pulled a reclaimed vnode off the freelist
+                * and reinitialized it.
+                */
+               vp->v_usecount = 1;
+               if (__vxlock(vp, VXLOCKFLAGS))
+                       panic("getnewvnode: __vxlock failed");
+               numvnodes++;
+       }
+
+       TAILQ_INIT(&vp->v_cleanblkhd);
+       TAILQ_INIT(&vp->v_dirtyblkhd);
+       vp->v_type = VNON;
+       vp->v_tag = 0;
+       vp->v_ops = NULL;
+       vp->v_data = NULL;
+       KKASSERT(vp->v_mount == NULL);
+       return (vp);
+}
+
+struct vnode *
+allocvnode_placemarker(void)
+{
+       struct vnode *pvp;
+
+       pvp = malloc(sizeof(struct vnode), 
+                       M_VNODE, M_WAITOK|M_USE_RESERVE|M_ZERO);
+       pvp->v_flag |= VPLACEMARKER;
+       return(pvp);
+}
+
+void
+freevnode_placemarker(struct vnode *pvp)
+{
+       KKASSERT(pvp->v_flag & VPLACEMARKER);
+       free(pvp, M_VNODE);
+}
+
index 9508b4c..6155b21 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_lookup.c        8.4 (Berkeley) 2/16/94
  * $FreeBSD: src/sys/kern/vfs_lookup.c,v 1.38.2.3 2001/08/31 19:36:49 dillon Exp $
- * $DragonFly: src/sys/kern/vfs_lookup.c,v 1.18 2004/10/07 04:20:26 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_lookup.c,v 1.19 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -196,7 +196,7 @@ namei(struct nameidata *ndp)
                        return (0);
                }
                if ((cnp->cn_flags & CNP_LOCKPARENT) && ndp->ni_pathlen == 1)
-                       VOP_UNLOCK(ndp->ni_dvp, NULL, 0, cnp->cn_td);
+                       VOP_UNLOCK(ndp->ni_dvp, 0, cnp->cn_td);
                if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
                        error = ELOOP;
                        break;
@@ -328,7 +328,7 @@ lookup(struct nameidata *ndp)
        cnp->cn_flags &= ~CNP_ISSYMLINK;
        dp = ndp->ni_startdir;
        ndp->ni_startdir = NULLVP;
-       vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
 
 dirloop:
        /*
@@ -408,7 +408,7 @@ dirloop:
                }
                ndp->ni_vp = dp;
                if (!(cnp->cn_flags & (CNP_LOCKPARENT | CNP_LOCKLEAF)))
-                       VOP_UNLOCK(dp, NULL, 0, cnp->cn_td);
+                       VOP_UNLOCK(dp, 0, cnp->cn_td);
                /* XXX This should probably move to the top of function. */
                if (cnp->cn_flags & CNP_SAVESTART)
                        panic("lookup: CNP_SAVESTART");
@@ -448,7 +448,7 @@ dirloop:
                        dp = dp->v_mount->mnt_vnodecovered;
                        vput(tdp);
                        vref(dp);
-                       vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+                       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
                }
        }
 
@@ -475,7 +475,7 @@ unionlookup:
                        else
                                vput(tdp);
                        vref(dp);
-                       vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+                       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
                        goto unionlookup;
                }
 
@@ -532,7 +532,7 @@ unionlookup:
               (cnp->cn_flags & CNP_NOCROSSMOUNT) == 0) {
                if (vfs_busy(mp, 0, NULL, td))
                        continue;
-               VOP_UNLOCK(dp, NULL, 0, td);
+               VOP_UNLOCK(dp, 0, td);
                error = VFS_ROOT(mp, &tdp);
                vfs_unbusy(mp, td);
                if (error) {
@@ -603,13 +603,13 @@ nextname:
                vrele(ndp->ni_dvp);
 
        if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
-               VOP_UNLOCK(dp, NULL, 0, td);
+               VOP_UNLOCK(dp, 0, td);
        return (0);
 
 bad2:
        if ((cnp->cn_flags & (CNP_LOCKPARENT | CNP_PDIRUNLOCK)) == CNP_LOCKPARENT &&
            *ndp->ni_next == '\0')
-               VOP_UNLOCK(ndp->ni_dvp, NULL, 0, td);
+               VOP_UNLOCK(ndp->ni_dvp, 0, td);
        vrele(ndp->ni_dvp);
 bad:
        if (dpunlocked)
@@ -646,7 +646,7 @@ relookup(dvp, vpp, cnp)
        rdonly = cnp->cn_flags & CNP_RDONLY;
        cnp->cn_flags &= ~CNP_ISSYMLINK;
        dp = dvp;
-       vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
 
 /* dirloop: */
        /*
@@ -680,7 +680,7 @@ relookup(dvp, vpp, cnp)
                        goto bad;
                }
                if (!(cnp->cn_flags & CNP_LOCKLEAF))
-                       VOP_UNLOCK(dp, NULL, 0, td);
+                       VOP_UNLOCK(dp, 0, td);
                *vpp = dp;
                /* XXX This should probably move to the top of function. */
                if (cnp->cn_flags & CNP_SAVESTART)
@@ -744,12 +744,12 @@ relookup(dvp, vpp, cnp)
                vfs_object_create(dp, cnp->cn_td);
 
        if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
-               VOP_UNLOCK(dp, NULL, 0, td);
+               VOP_UNLOCK(dp, 0, td);
        return (0);
 
 bad2:
        if ((cnp->cn_flags & CNP_LOCKPARENT) && (cnp->cn_flags & CNP_ISLASTCN))
-               VOP_UNLOCK(dvp, NULL, 0, td);
+               VOP_UNLOCK(dvp, 0, td);
        vrele(dvp);
 bad:
        vput(dp);
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
new file mode 100644 (file)
index 0000000..08c83c7
--- /dev/null
@@ -0,0 +1,784 @@
+/*
+ * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
+ * 
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/kern/vfs_mount.c,v 1.1 2004/10/12 19:20:46 dillon Exp $
+ */
+
+/*
+ * External virtual filesystem routines
+ */
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/buf.h>
+#include <sys/eventhandler.h>
+#include <sys/kthread.h>
+#include <sys/sysctl.h>
+
+#include <machine/limits.h>
+
+#include <sys/buf2.h>
+#include <sys/thread2.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+
+static int vnlru_nowhere = 0;
+SYSCTL_INT(_debug, OID_AUTO, vnlru_nowhere, CTLFLAG_RW,
+           &vnlru_nowhere, 0,
+           "Number of times the vnlru process ran without success");
+
+
+static struct lwkt_token mntid_token;
+
+struct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist); /* mounted fs */
+struct lwkt_token mountlist_token;
+struct lwkt_token mntvnode_token;
+
+
+/*
+ * Called from vfsinit()
+ */
+void
+vfs_mount_init(void)
+{
+       lwkt_token_init(&mountlist_token);
+       lwkt_token_init(&mntvnode_token);
+       lwkt_token_init(&mntid_token);
+}
+
+/*
+ * Allocate a new vnode and associate it with a tag, mount point, and
+ * operations vector.
+ *
+ * A VX locked and refd vnode is returned.  The caller should setup the
+ * remaining fields and vx_put() or, if he wishes to leave a vref,
+ * vx_unlock() the vnode.
+ */
+int
+getnewvnode(enum vtagtype tag, struct mount *mp, struct vop_ops *ops,
+               struct vnode **vpp, int lktimeout, int lkflags)
+{
+       struct vnode *vp;
+
+       vp = allocvnode(lktimeout, lkflags);
+       vp->v_tag = tag;
+       vp->v_ops = ops;
+       vp->v_data = NULL;
+
+       /*
+        * Placing the vnode on the mount point's queue makes it visible.
+        * VNON prevents it from being messed with, however.
+        */
+       insmntque(vp, mp);
+       vfs_object_create(vp, curthread);
+
+       /*
+        * A VX locked & refd vnode is returned.
+        */
+       *vpp = vp;
+       return (0);
+}
+
+/*
+ * Mark a mount point as busy. Used to synchronize access and to delay
+ * unmounting. Interlock is not released on failure.
+ */
+int
+vfs_busy(struct mount *mp, int flags,
+       lwkt_tokref_t interlkp, struct thread *td)
+{
+       int lkflags;
+
+       if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
+               if (flags & LK_NOWAIT)
+                       return (ENOENT);
+               mp->mnt_kern_flag |= MNTK_MWAIT;
+               /*
+                * Since all busy locks are shared except the exclusive
+                * lock granted when unmounting, the only place that a
+                * wakeup needs to be done is at the release of the
+                * exclusive lock at the end of dounmount.
+                *
+                * note: interlkp is a serializer and thus can be safely
+                * held through any sleep
+                */
+               tsleep((caddr_t)mp, 0, "vfs_busy", 0);
+               return (ENOENT);
+       }
+       lkflags = LK_SHARED | LK_NOPAUSE;
+       if (interlkp)
+               lkflags |= LK_INTERLOCK;
+       if (lockmgr(&mp->mnt_lock, lkflags, interlkp, td))
+               panic("vfs_busy: unexpected lock failure");
+       return (0);
+}
+
+/*
+ * Free a busy filesystem.
+ */
+void
+vfs_unbusy(struct mount *mp, struct thread *td)
+{
+       lockmgr(&mp->mnt_lock, LK_RELEASE, NULL, td);
+}
+
+/*
+ * Lookup a filesystem type, and if found allocate and initialize
+ * a mount structure for it.
+ *
+ * Devname is usually updated by mount(8) after booting.
+ */
+int
+vfs_rootmountalloc(char *fstypename, char *devname, struct mount **mpp)
+{
+       struct thread *td = curthread;  /* XXX */
+       struct vfsconf *vfsp;
+       struct mount *mp;
+
+       if (fstypename == NULL)
+               return (ENODEV);
+       for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
+               if (!strcmp(vfsp->vfc_name, fstypename))
+                       break;
+       }
+       if (vfsp == NULL)
+               return (ENODEV);
+       mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
+       bzero((char *)mp, (u_long)sizeof(struct mount));
+       lockinit(&mp->mnt_lock, 0, "vfslock", VLKTIMEOUT, LK_NOPAUSE);
+       vfs_busy(mp, LK_NOWAIT, NULL, td);
+       TAILQ_INIT(&mp->mnt_nvnodelist);
+       TAILQ_INIT(&mp->mnt_reservedvnlist);
+       mp->mnt_nvnodelistsize = 0;
+       mp->mnt_vfc = vfsp;
+       mp->mnt_op = vfsp->vfc_vfsops;
+       mp->mnt_flag = MNT_RDONLY;
+       mp->mnt_vnodecovered = NULLVP;
+       vfsp->vfc_refcount++;
+       mp->mnt_iosize_max = DFLTPHYS;
+       mp->mnt_stat.f_type = vfsp->vfc_typenum;
+       mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
+       strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
+       mp->mnt_stat.f_mntonname[0] = '/';
+       mp->mnt_stat.f_mntonname[1] = 0;
+       (void) copystr(devname, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 0);
+       *mpp = mp;
+       return (0);
+}
+
+/*
+ * Lookup a mount point by filesystem identifier.
+ */
+struct mount *
+vfs_getvfs(fsid_t *fsid)
+{
+       struct mount *mp;
+       lwkt_tokref ilock;
+
+       lwkt_gettoken(&ilock, &mountlist_token);
+       TAILQ_FOREACH(mp, &mountlist, mnt_list) {
+               if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
+                   mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
+                       break;
+           }
+       }
+       lwkt_reltoken(&ilock);
+       return (mp);
+}
+
+/*
+ * Get a new unique fsid.  Try to make its val[0] unique, since this value
+ * will be used to create fake device numbers for stat().  Also try (but
+ * not so hard) make its val[0] unique mod 2^16, since some emulators only
+ * support 16-bit device numbers.  We end up with unique val[0]'s for the
+ * first 2^16 calls and unique val[0]'s mod 2^16 for the first 2^8 calls.
+ *
+ * Keep in mind that several mounts may be running in parallel.  Starting
+ * the search one past where the previous search terminated is both a
+ * micro-optimization and a defense against returning the same fsid to
+ * different mounts.
+ */
+void
+vfs_getnewfsid(struct mount *mp)
+{
+       static u_int16_t mntid_base;
+       lwkt_tokref ilock;
+       fsid_t tfsid;
+       int mtype;
+
+       lwkt_gettoken(&ilock, &mntid_token);
+       mtype = mp->mnt_vfc->vfc_typenum;
+       tfsid.val[1] = mtype;
+       mtype = (mtype & 0xFF) << 24;
+       for (;;) {
+               tfsid.val[0] = makeudev(255,
+                   mtype | ((mntid_base & 0xFF00) << 8) | (mntid_base & 0xFF));
+               mntid_base++;
+               if (vfs_getvfs(&tfsid) == NULL)
+                       break;
+       }
+       mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
+       mp->mnt_stat.f_fsid.val[1] = tfsid.val[1];
+       lwkt_reltoken(&ilock);
+}
+
+/*
+ * This routine is called when we have too many vnodes.  It attempts
+ * to free <count> vnodes and will potentially free vnodes that still
+ * have VM backing store (VM backing store is typically the cause
+ * of a vnode blowout so we want to do this).  Therefore, this operation
+ * is not considered cheap.
+ *
+ * A number of conditions may prevent a vnode from being reclaimed.
+ * the buffer cache may have references on the vnode, a directory
+ * vnode may still have references due to the namei cache representing
+ * underlying files, or the vnode may be in active use.   It is not
+ * desireable to reuse such vnodes.  These conditions may cause the
+ * number of vnodes to reach some minimum value regardless of what
+ * you set kern.maxvnodes to.  Do not set kern.maxvnodes too low.
+ */
+
+/*
+ * Return 0 if the vnode is not already on the free list, return 1 if the
+ * vnode, with some additional work could possibly be placed on the free list.
+ */
+static __inline int 
+vmightfree(struct vnode *vp, int use_count, int page_count)
+{
+       if (vp->v_flag & VFREE)
+               return (0);
+       if (vp->v_usecount != use_count || vp->v_holdcnt)
+               return (0);
+       if (vp->v_object && vp->v_object->resident_page_count >= page_count)
+               return (0);
+       return (1);
+}
+
+
+static int
+vlrureclaim(struct mount *mp)
+{
+       struct vnode *vp;
+       lwkt_tokref ilock;
+       int done;
+       int trigger;
+       int usevnodes;
+       int count;
+
+       /*
+        * Calculate the trigger point, don't allow user
+        * screwups to blow us up.   This prevents us from
+        * recycling vnodes with lots of resident pages.  We
+        * aren't trying to free memory, we are trying to
+        * free vnodes.
+        */
+       usevnodes = desiredvnodes;
+       if (usevnodes <= 0)
+               usevnodes = 1;
+       trigger = vmstats.v_page_count * 2 / usevnodes;
+
+       done = 0;
+       lwkt_gettoken(&ilock, &mntvnode_token);
+       count = mp->mnt_nvnodelistsize / 10 + 1;
+       while (count && (vp = TAILQ_FIRST(&mp->mnt_nvnodelist)) != NULL) {
+               /*
+                * __VNODESCAN__
+                *
+                * The VP will stick around while we hold mntvnode_token,
+                * at least until we block, so we can safely do an initial
+                * check, and then must check again after we lock the vnode.
+                */
+               if (vp->v_type == VNON ||       /* XXX */
+                   vp->v_type == VBAD ||       /* XXX */
+                   !vmightfree(vp, 0, trigger) /* critical path opt */
+               ) {
+                       TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
+                       TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist,vp, v_nmntvnodes);
+                       --count;
+                       continue;
+               }
+
+               /*
+                * VX get the candidate vnode.  If the VX get fails the 
+                * vnode might still be on the mountlist.  Our loop depends
+                * on us at least cycling the vnode to the end of the
+                * mountlist.
+                */
+               if (vx_get_nonblock(vp) != 0) {
+                       if (vp->v_mount == mp) {
+                               TAILQ_REMOVE(&mp->mnt_nvnodelist, 
+                                               vp, v_nmntvnodes);
+                               TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist,
+                                               vp, v_nmntvnodes);
+                       }
+                       --count;
+                       continue;
+               }
+
+               /*
+                * Since we blocked locking the vp, make sure it is still
+                * a candidate for reclamation.  That is, it has not already
+                * been reclaimed and only has our VX reference associated
+                * with it.
+                */
+               if (vp->v_type == VNON ||       /* XXX */
+                   vp->v_type == VBAD ||       /* XXX */
+                   (vp->v_flag & VRECLAIMED) ||
+                   vp->v_mount != mp ||
+                   !vmightfree(vp, 1, trigger) /* critical path opt */
+               ) {
+                       if (vp->v_mount == mp) {
+                               TAILQ_REMOVE(&mp->mnt_nvnodelist, 
+                                               vp, v_nmntvnodes);
+                               TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist,
+                                               vp, v_nmntvnodes);
+                       }
+                       --count;
+                       vx_put(vp);
+                       continue;
+               }
+
+               /*
+                * All right, we are good, move the vp to the end of the
+                * mountlist and clean it out.  The vget will have returned
+                * an error if the vnode was destroyed (VRECLAIMED set), so we
+                * do not have to check again.  The vput() will move the 
+                * vnode to the free list if the vgone() was successful.
+                */
+               KKASSERT(vp->v_mount == mp);
+               TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
+               TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist,vp, v_nmntvnodes);
+               vgone(vp);
+               vx_put(vp);
+               ++done;
+               --count;
+       }
+       lwkt_reltoken(&ilock);
+       return (done);
+}
+
+/*
+ * Attempt to recycle vnodes in a context that is always safe to block.
+ * Calling vlrurecycle() from the bowels of file system code has some
+ * interesting deadlock problems.
+ */
+static struct thread *vnlruthread;
+static int vnlruproc_sig;
+
+void
+vnlru_proc_wait(void)
+{
+       if (vnlruproc_sig == 0) {
+               vnlruproc_sig = 1;      /* avoid unnecessary wakeups */
+               wakeup(vnlruthread);
+       }
+       tsleep(&vnlruproc_sig, 0, "vlruwk", hz);
+}
+
+static void 
+vnlru_proc(void)
+{
+       struct mount *mp, *nmp;
+       lwkt_tokref ilock;
+       int s;
+       int done;
+       struct thread *td = curthread;
+
+       EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, td,
+           SHUTDOWN_PRI_FIRST);   
+
+       s = splbio();
+       for (;;) {
+               kproc_suspend_loop();
+               if (numvnodes - freevnodes <= desiredvnodes * 9 / 10) {
+                       vnlruproc_sig = 0;
+                       wakeup(&vnlruproc_sig);
+                       tsleep(td, 0, "vlruwt", hz);
+                       continue;
+               }
+               done = 0;
+               lwkt_gettoken(&ilock, &mountlist_token);
+               for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
+                       if (vfs_busy(mp, LK_NOWAIT, &ilock, td)) {
+                               nmp = TAILQ_NEXT(mp, mnt_list);
+                               continue;
+                       }
+                       done += vlrureclaim(mp);
+                       lwkt_gettokref(&ilock);
+                       nmp = TAILQ_NEXT(mp, mnt_list);
+                       vfs_unbusy(mp, td);
+               }
+               lwkt_reltoken(&ilock);
+               if (done == 0) {
+                       ++vnlru_nowhere;
+                       tsleep(td, 0, "vlrup", hz * 3);
+                       if (vnlru_nowhere % 10 == 0)
+                               printf("vnlru_proc: vnode recycler stopped working!\n");
+               } else {
+                       vnlru_nowhere = 0;
+               }
+       }
+       splx(s);
+}
+
+static struct kproc_desc vnlru_kp = {
+       "vnlru",
+       vnlru_proc,
+       &vnlruthread
+};
+SYSINIT(vnlru, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &vnlru_kp)
+
+/*
+ * Move a vnode from one mount queue to another.
+ */
+void
+insmntque(struct vnode *vp, struct mount *mp)
+{
+       lwkt_tokref ilock;
+
+       lwkt_gettoken(&ilock, &mntvnode_token);
+       /*
+        * Delete from old mount point vnode list, if on one.
+        */
+       if (vp->v_mount != NULL) {
+               KASSERT(vp->v_mount->mnt_nvnodelistsize > 0,
+                       ("bad mount point vnode list size"));
+               TAILQ_REMOVE(&vp->v_mount->mnt_nvnodelist, vp, v_nmntvnodes);
+               vp->v_mount->mnt_nvnodelistsize--;
+       }
+       /*
+        * Insert into list of vnodes for the new mount point, if available.
+        */
+       if ((vp->v_mount = mp) == NULL) {
+               lwkt_reltoken(&ilock);
+               return;
+       }
+       TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
+       mp->mnt_nvnodelistsize++;
+       lwkt_reltoken(&ilock);
+}
+
+
+/*
+ * Scan the vnodes under a mount point.  The first function is called
+ * with just the mountlist token held (no vnode lock).  The second
+ * function is called with the vnode VX locked.
+ */
+int
+vmntvnodescan(
+    struct mount *mp, 
+    int flags,
+    int (*fastfunc)(struct mount *mp, struct vnode *vp, void *data),
+    int (*slowfunc)(struct mount *mp, struct vnode *vp, void *data),
+    void *data
+) {
+       lwkt_tokref ilock;
+       struct vnode *pvp;
+       struct vnode *vp;
+       int r = 0;
+
+       /*
+        * Scan the vnodes on the mount's vnode list.  Use a placemarker
+        */
+       pvp = allocvnode_placemarker();
+
+       lwkt_gettoken(&ilock, &mntvnode_token);
+       TAILQ_INSERT_HEAD(&mp->mnt_nvnodelist, pvp, v_nmntvnodes);
+
+       while ((vp = TAILQ_NEXT(pvp, v_nmntvnodes)) != NULL) {
+               /*
+                * Move the placemarker and skip other placemarkers we
+                * encounter.  The nothing can get in our way so the
+                * mount point on the vp must be valid.
+                */
+               TAILQ_REMOVE(&mp->mnt_nvnodelist, pvp, v_nmntvnodes);
+               TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, pvp, v_nmntvnodes);
+               if (vp->v_flag & VPLACEMARKER)  /* another procs placemarker */
+                       continue;
+               if (vp->v_type == VNON)         /* visible but not ready */
+                       continue;
+               KKASSERT(vp->v_mount == mp);
+
+               /*
+                * Quick test.  A negative return continues the loop without
+                * calling the slow test.  0 continues onto the slow test.
+                * A positive number aborts the loop.
+                */
+               if (fastfunc) {
+                       if ((r = fastfunc(mp, vp, data)) < 0)
+                               continue;
+                       if (r)
+                               break;
+               }
+
+               /*
+                * Get a vxlock on the vnode, retry if it has moved or isn't
+                * in the mountlist where we expect it.
+                */
+               if (slowfunc) {
+                       int error;
+
+                       switch(flags) {
+                       case VMSC_GETVP:
+                               error = vget(vp, LK_EXCLUSIVE, curthread);
+                               break;
+                       case VMSC_GETVP|VMSC_NOWAIT:
+                               error = vget(vp, LK_EXCLUSIVE|LK_NOWAIT,
+                                               curthread);
+                               break;
+                       case VMSC_GETVX:
+                               error = vx_get(vp);
+                               break;
+                       case VMSC_REFVP:
+                               vref(vp);
+                               /* fall through */
+                       default:
+                               error = 0;
+                               break;
+                       }
+                       if (error)
+                               continue;
+                       if (TAILQ_PREV(pvp, vnodelst, v_nmntvnodes) != vp)
+                               goto skip;
+                       if (vp->v_type == VNON)
+                               goto skip;
+                       r = slowfunc(mp, vp, data);
+skip:
+                       switch(flags) {
+                       case VMSC_GETVP:
+                       case VMSC_GETVP|VMSC_NOWAIT:
+                               vput(vp);
+                               break;
+                       case VMSC_GETVX:
+                               vx_put(vp);
+                               break;
+                       case VMSC_REFVP:
+                               vrele(vp);
+                               /* fall through */
+                       default:
+                               break;
+                       }
+                       if (r != 0)
+                               break;
+               }
+       }
+       TAILQ_REMOVE(&mp->mnt_nvnodelist, pvp, v_nmntvnodes);
+       freevnode_placemarker(pvp);
+       lwkt_reltoken(&ilock);
+       return(r);
+}
+
+/*
+ * Remove any vnodes in the vnode table belonging to mount point mp.
+ *
+ * If FORCECLOSE is not specified, there should not be any active ones,
+ * return error if any are found (nb: this is a user error, not a
+ * system error). If FORCECLOSE is specified, detach any active vnodes
+ * that are found.
+ *
+ * If WRITECLOSE is set, only flush out regular file vnodes open for
+ * writing.
+ *
+ * SKIPSYSTEM causes any vnodes marked VSYSTEM to be skipped.
+ *
+ * `rootrefs' specifies the base reference count for the root vnode
+ * of this filesystem. The root vnode is considered busy if its
+ * v_usecount exceeds this value. On a successful return, vflush()
+ * will call vrele() on the root vnode exactly rootrefs times.
+ * If the SKIPSYSTEM or WRITECLOSE flags are specified, rootrefs must
+ * be zero.
+ */
+#ifdef DIAGNOSTIC
+static int busyprt = 0;                /* print out busy vnodes */
+SYSCTL_INT(_debug, OID_AUTO, busyprt, CTLFLAG_RW, &busyprt, 0, "");
+#endif
+
+static int vflush_scan(struct mount *mp, struct vnode *vp, void *data);
+
+struct vflush_info {
+       int flags;
+       int busy;
+       thread_t td;
+};
+
+int
+vflush(struct mount *mp, int rootrefs, int flags)
+{
+       struct thread *td = curthread;  /* XXX */
+       struct vnode *rootvp = NULL;
+       int error;
+       struct vflush_info vflush_info;
+
+       if (rootrefs > 0) {
+               KASSERT((flags & (SKIPSYSTEM | WRITECLOSE)) == 0,
+                   ("vflush: bad args"));
+               /*
+                * Get the filesystem root vnode. We can vput() it
+                * immediately, since with rootrefs > 0, it won't go away.
+                */
+               if ((error = VFS_ROOT(mp, &rootvp)) != 0)
+                       return (error);
+               vput(rootvp);
+       }
+
+       vflush_info.busy = 0;
+       vflush_info.flags = flags;
+       vflush_info.td = td;
+       vmntvnodescan(mp, VMSC_GETVX, NULL, vflush_scan, &vflush_info);
+
+       if (rootrefs > 0 && (flags & FORCECLOSE) == 0) {
+               /*
+                * If just the root vnode is busy, and if its refcount
+                * is equal to `rootrefs', then go ahead and kill it.
+                */
+               KASSERT(vflush_info.busy > 0, ("vflush: not busy"));
+               KASSERT(rootvp->v_usecount >= rootrefs, ("vflush: rootrefs"));
+               if (vflush_info.busy == 1 && rootvp->v_usecount == rootrefs) {
+                       if (vx_lock(rootvp) == 0) {
+                               vgone(rootvp);
+                               vx_unlock(rootvp);
+                               vflush_info.busy = 0;
+                       }
+               }
+       }
+       if (vflush_info.busy)
+               return (EBUSY);
+       for (; rootrefs > 0; rootrefs--)
+               vrele(rootvp);
+       return (0);
+}
+
+/*
+ * The scan callback is made with an VX locked vnode.
+ */
+static int
+vflush_scan(struct mount *mp, struct vnode *vp, void *data)
+{
+       struct vflush_info *info = data;
+       struct vattr vattr;
+
+       /*
+        * Skip over a vnodes marked VSYSTEM.
+        */
+       if ((info->flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) {
+               return(0);
+       }
+
+       /*
+        * If WRITECLOSE is set, flush out unlinked but still open
+        * files (even if open only for reading) and regular file
+        * vnodes open for writing. 
+        */
+       if ((info->flags & WRITECLOSE) &&
+           (vp->v_type == VNON ||
+           (VOP_GETATTR(vp, &vattr, info->td) == 0 &&
+           vattr.va_nlink > 0)) &&
+           (vp->v_writecount == 0 || vp->v_type != VREG)) {
+               return(0);
+       }
+
+       /*
+        * With v_usecount == 0, all we need to do is clear out the
+        * vnode data structures and we are done.
+        */
+       if (vp->v_usecount == 1) {
+               vgone(vp);
+               return(0);
+       }
+
+       /*
+        * If FORCECLOSE is set, forcibly close the vnode. For block
+        * or character devices, revert to an anonymous device. For
+        * all other files, just kill them.
+        */
+       if (info->flags & FORCECLOSE) {
+               if (vp->v_type != VBLK && vp->v_type != VCHR) {
+                       vgone(vp);
+               } else {
+                       vclean(vp, 0, info->td);
+                       vp->v_ops = spec_vnode_vops;
+                       insmntque(vp, NULL);
+               }
+               return(0);
+       }
+#ifdef DIAGNOSTIC
+       if (busyprt)
+               vprint("vflush: busy vnode", vp);
+#endif
+       ++info->busy;
+       return(0);
+}
+
index e9c34e0..93fc704 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.42 2004/10/05 03:24:09 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_subr.c,v 1.43 2004/10/12 19:20:46 dillon Exp $
  */
 
 /*
 
 static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
 
-static void    insmntque (struct vnode *vp, struct mount *mp);
-static void    vclean (struct vnode *vp, lwkt_tokref_t vlock, 
-                       int flags, struct thread *td);
-
-static unsigned long numvnodes;
+int numvnodes;
 SYSCTL_INT(_debug, OID_AUTO, numvnodes, CTLFLAG_RD, &numvnodes, 0, "");
 
 enum vtype iftovt_tab[16] = {
@@ -102,15 +98,6 @@ int vttoif_tab[9] = {
        S_IFSOCK, S_IFIFO, S_IFMT,
 };
 
-static TAILQ_HEAD(freelst, vnode) vnode_free_list;     /* vnode free list */
-
-static u_long wantfreevnodes = 25;
-SYSCTL_INT(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW,
-               &wantfreevnodes, 0, "");
-static u_long freevnodes = 0;
-SYSCTL_INT(_debug, OID_AUTO, freevnodes, CTLFLAG_RD,
-               &freevnodes, 0, "");
-
 static int reassignbufcalls;
 SYSCTL_INT(_vfs, OID_AUTO, reassignbufcalls, CTLFLAG_RW,
                &reassignbufcalls, 0, "");
@@ -132,95 +119,47 @@ int vfs_ioopt = 0;
 SYSCTL_INT(_vfs, OID_AUTO, ioopt, CTLFLAG_RW, &vfs_ioopt, 0, "");
 #endif
 
-struct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist); /* mounted fs */
-struct lwkt_token mountlist_token;
-struct lwkt_token mntvnode_token;
 int    nfs_mount_type = -1;
-static struct lwkt_token mntid_token;
-static struct lwkt_token vnode_free_list_token;
 static struct lwkt_token spechash_token;
 struct nfs_public nfs_pub;     /* publicly exported FS */
-static vm_zone_t vnode_zone;
-
-/*
- * The workitem queue.
- */
-#define SYNCER_MAXDELAY                32
-static int syncer_maxdelay = SYNCER_MAXDELAY;  /* maximum delay time */
-time_t syncdelay = 30;         /* max time to delay syncing data */
-SYSCTL_INT(_kern, OID_AUTO, syncdelay, CTLFLAG_RW,
-               &syncdelay, 0, "VFS data synchronization delay");
-time_t filedelay = 30;         /* time to delay syncing files */
-SYSCTL_INT(_kern, OID_AUTO, filedelay, CTLFLAG_RW,
-               &filedelay, 0, "File synchronization delay");
-time_t dirdelay = 29;          /* time to delay syncing directories */
-SYSCTL_INT(_kern, OID_AUTO, dirdelay, CTLFLAG_RW,
-               &dirdelay, 0, "Directory synchronization delay");
-time_t metadelay = 28;         /* time to delay syncing metadata */
-SYSCTL_INT(_kern, OID_AUTO, metadelay, CTLFLAG_RW,
-               &metadelay, 0, "VFS metadata synchronization delay");
-static int rushjob;                    /* number of slots to run ASAP */
-static int stat_rush_requests; /* number of times I/O speeded up */
-SYSCTL_INT(_debug, OID_AUTO, rush_requests, CTLFLAG_RW,
-               &stat_rush_requests, 0, "");
-
-static int syncer_delayno = 0;
-static long syncer_mask; 
-LIST_HEAD(synclist, vnode);
-static struct synclist *syncer_workitem_pending;
 
 int desiredvnodes;
 SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RW, 
                &desiredvnodes, 0, "Maximum number of vnodes");
-static int minvnodes;
-SYSCTL_INT(_kern, OID_AUTO, minvnodes, CTLFLAG_RW, 
-               &minvnodes, 0, "Minimum number of vnodes");
-static int vnlru_nowhere = 0;
-SYSCTL_INT(_debug, OID_AUTO, vnlru_nowhere, CTLFLAG_RW,
-               &vnlru_nowhere, 0,
-               "Number of times the vnlru process ran without success");
 
 static void    vfs_free_addrlist (struct netexport *nep);
 static int     vfs_free_netcred (struct radix_node *rn, void *w);
 static int     vfs_hang_addrlist (struct mount *mp, struct netexport *nep,
                                       struct export_args *argp);
 
-#define VSHOULDFREE(vp) \
-       (!((vp)->v_flag & (VFREE|VDOOMED)) && \
-        !(vp)->v_holdcnt && !(vp)->v_usecount && \
-        (!(vp)->v_object || \
-         !((vp)->v_object->ref_count || (vp)->v_object->resident_page_count)))
-#define VMIGHTFREE(vp) \
-       (((vp)->v_flag & (VFREE|VDOOMED|VXLOCK)) == 0 &&   \
-        cache_leaf_test(vp) == 0 && (vp)->v_usecount == 0)
-#define VSHOULDBUSY(vp) \
-       (((vp)->v_flag & VFREE) && \
-        ((vp)->v_holdcnt || (vp)->v_usecount))
-
-static void vbusy(struct vnode *vp);
-static void vfree(struct vnode *vp);
-static void vmaybefree(struct vnode *vp);
-
 extern int dev_ref_debug;
 extern struct vnodeopv_entry_desc spec_vnodeop_entries[];
 
 /*
- * NOTE: the vnode interlock must be held on call.
+ * Return 0 if the vnode is already on the free list or cannot be placed
+ * on the free list.  Return 1 if the vnode can be placed on the free list.
  */
-static __inline void
-vmaybefree(struct vnode *vp)
+static __inline int
+vshouldfree(struct vnode *vp, int usecount)
 {
-       if (VSHOULDFREE(vp))
-               vfree(vp);
+       if (vp->v_flag & VFREE)
+               return (0);             /* already free */
+       if (vp->v_holdcnt != 0 || vp->v_usecount != usecount)
+               return (0);             /* other holderse */
+       if (vp->v_object &&
+           (vp->v_object->ref_count || vp->v_object->resident_page_count)) {
+               return (0);
+       }
+       return (1);
 }
+
 /*
- * Initialize the vnode management data structures.
+ * Initialize the vnode management data structures. 
+ *
+ * Called from vfsinit()
  */
 void
-vntblinit(void)
+vfs_subr_init(void)
 {
        /*
         * Desired vnodes is a result of the physical page count
@@ -234,163 +173,7 @@ vntblinit(void)
                    2 * (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) /
                    (5 * (sizeof(struct vm_object) + sizeof(struct vnode))));
 
-       minvnodes = desiredvnodes / 4;
-       lwkt_token_init(&mountlist_token);
-       lwkt_token_init(&mntvnode_token);
-       lwkt_token_init(&mntid_token);
        lwkt_token_init(&spechash_token);
-       TAILQ_INIT(&vnode_free_list);
-       lwkt_token_init(&vnode_free_list_token);
-       vnode_zone = zinit("VNODE", sizeof (struct vnode), 0, 0, 5);
-       /*
-        * Initialize the filesystem syncer.
-        */     
-       syncer_workitem_pending = hashinit(syncer_maxdelay, M_VNODE, 
-               &syncer_mask);
-       syncer_maxdelay = syncer_mask + 1;
-}
-
-/*
- * Mark a mount point as busy. Used to synchronize access and to delay
- * unmounting. Interlock is not released on failure.
- */
-int
-vfs_busy(struct mount *mp, int flags,
-       lwkt_tokref_t interlkp, struct thread *td)
-{
-       int lkflags;
-
-       if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
-               if (flags & LK_NOWAIT)
-                       return (ENOENT);
-               mp->mnt_kern_flag |= MNTK_MWAIT;
-               /*
-                * Since all busy locks are shared except the exclusive
-                * lock granted when unmounting, the only place that a
-                * wakeup needs to be done is at the release of the
-                * exclusive lock at the end of dounmount.
-                *
-                * note: interlkp is a serializer and thus can be safely
-                * held through any sleep
-                */
-               tsleep((caddr_t)mp, 0, "vfs_busy", 0);
-               return (ENOENT);
-       }
-       lkflags = LK_SHARED | LK_NOPAUSE;
-       if (interlkp)
-               lkflags |= LK_INTERLOCK;
-       if (lockmgr(&mp->mnt_lock, lkflags, interlkp, td))
-               panic("vfs_busy: unexpected lock failure");
-       return (0);
-}
-
-/*
- * Free a busy filesystem.
- */
-void
-vfs_unbusy(struct mount *mp, struct thread *td)
-{
-       lockmgr(&mp->mnt_lock, LK_RELEASE, NULL, td);
-}
-
-/*
- * Lookup a filesystem type, and if found allocate and initialize
- * a mount structure for it.
- *
- * Devname is usually updated by mount(8) after booting.
- */
-int
-vfs_rootmountalloc(char *fstypename, char *devname, struct mount **mpp)
-{
-       struct thread *td = curthread;  /* XXX */
-       struct vfsconf *vfsp;
-       struct mount *mp;
-
-       if (fstypename == NULL)
-               return (ENODEV);
-       for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
-               if (!strcmp(vfsp->vfc_name, fstypename))
-                       break;
-       }
-       if (vfsp == NULL)
-               return (ENODEV);
-       mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
-       bzero((char *)mp, (u_long)sizeof(struct mount));
-       lockinit(&mp->mnt_lock, 0, "vfslock", VLKTIMEOUT, LK_NOPAUSE);
-       vfs_busy(mp, LK_NOWAIT, NULL, td);
-       TAILQ_INIT(&mp->mnt_nvnodelist);
-       TAILQ_INIT(&mp->mnt_reservedvnlist);
-       mp->mnt_nvnodelistsize = 0;
-       mp->mnt_vfc = vfsp;
-       mp->mnt_op = vfsp->vfc_vfsops;
-       mp->mnt_flag = MNT_RDONLY;
-       mp->mnt_vnodecovered = NULLVP;
-       vfsp->vfc_refcount++;
-       mp->mnt_iosize_max = DFLTPHYS;
-       mp->mnt_stat.f_type = vfsp->vfc_typenum;
-       mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
-       strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
-       mp->mnt_stat.f_mntonname[0] = '/';
-       mp->mnt_stat.f_mntonname[1] = 0;
-       (void) copystr(devname, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 0);
-       *mpp = mp;
-       return (0);
-}
-
-/*
- * Lookup a mount point by filesystem identifier.
- */
-struct mount *
-vfs_getvfs(fsid_t *fsid)
-{
-       struct mount *mp;
-       lwkt_tokref ilock;
-
-       lwkt_gettoken(&ilock, &mountlist_token);
-       TAILQ_FOREACH(mp, &mountlist, mnt_list) {
-               if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
-                   mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
-                       break;
-           }
-       }
-       lwkt_reltoken(&ilock);
-       return (mp);
-}
-
-/*
- * Get a new unique fsid.  Try to make its val[0] unique, since this value
- * will be used to create fake device numbers for stat().  Also try (but
- * not so hard) make its val[0] unique mod 2^16, since some emulators only
- * support 16-bit device numbers.  We end up with unique val[0]'s for the
- * first 2^16 calls and unique val[0]'s mod 2^16 for the first 2^8 calls.
- *
- * Keep in mind that several mounts may be running in parallel.  Starting
- * the search one past where the previous search terminated is both a
- * micro-optimization and a defense against returning the same fsid to
- * different mounts.
- */
-void
-vfs_getnewfsid(struct mount *mp)
-{
-       static u_int16_t mntid_base;
-       lwkt_tokref ilock;
-       fsid_t tfsid;
-       int mtype;
-
-       lwkt_gettoken(&ilock, &mntid_token);
-       mtype = mp->mnt_vfc->vfc_typenum;
-       tfsid.val[1] = mtype;
-       mtype = (mtype & 0xFF) << 24;
-       for (;;) {
-               tfsid.val[0] = makeudev(255,
-                   mtype | ((mntid_base & 0xFF00) << 8) | (mntid_base & 0xFF));
-               mntid_base++;
-               if (vfs_getvfs(&tfsid) == NULL)
-                       break;
-       }
-       mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
-       mp->mnt_stat.f_fsid.val[1] = tfsid.val[1];
-       lwkt_reltoken(&ilock);
 }
 
 /*
@@ -462,396 +245,6 @@ vattr_null(struct vattr *vap)
        vap->va_vaflags = 0;
 }
 
-/*
- * This routine is called when we have too many vnodes.  It attempts
- * to free <count> vnodes and will potentially free vnodes that still
- * have VM backing store (VM backing store is typically the cause
- * of a vnode blowout so we want to do this).  Therefore, this operation
- * is not considered cheap.
- *
- * A number of conditions may prevent a vnode from being reclaimed.
- * the buffer cache may have references on the vnode, a directory
- * vnode may still have references due to the namei cache representing
- * underlying files, or the vnode may be in active use.   It is not
- * desireable to reuse such vnodes.  These conditions may cause the
- * number of vnodes to reach some minimum value regardless of what
- * you set kern.maxvnodes to.  Do not set kern.maxvnodes too low.
- */
-static int
-vlrureclaim(struct mount *mp)
-{
-       struct vnode *vp;
-       lwkt_tokref ilock;
-       lwkt_tokref vlock;
-       int done;
-       int trigger;
-       int usevnodes;
-       int count;
-
-       /*
-        * Calculate the trigger point, don't allow user
-        * screwups to blow us up.   This prevents us from
-        * recycling vnodes with lots of resident pages.  We
-        * aren't trying to free memory, we are trying to
-        * free vnodes.
-        */
-       usevnodes = desiredvnodes;
-       if (usevnodes <= 0)
-               usevnodes = 1;
-       trigger = vmstats.v_page_count * 2 / usevnodes;
-
-       done = 0;
-       lwkt_gettoken(&ilock, &mntvnode_token);
-       count = mp->mnt_nvnodelistsize / 10 + 1;
-       while (count && (vp = TAILQ_FIRST(&mp->mnt_nvnodelist)) != NULL) {
-               /*
-                * __VNODESCAN__
-                *
-                * The VP will stick around while we hold mntvnode_token,
-                * at least until we block, so we can safely do an initial
-                * check.  But we have to check again after obtaining
-                * the vnode interlock.  vp->v_interlock points to stable
-                * storage so it's ok if the vp gets ripped out from
-                * under us while we are blocked.
-                */
-               if (vp->v_type == VNON ||
-                   vp->v_type == VBAD ||
-                   !VMIGHTFREE(vp) ||          /* critical path opt */
-                   (vp->v_object &&
-                    vp->v_object->resident_page_count >= trigger)
-               ) {
-                       TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
-                       TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist,vp, v_nmntvnodes);
-                       --count;
-                       continue;
-               }
-
-               /*
-                * Get the interlock, delay moving the node to the tail so
-                * we don't race against new additions to the mountlist.
-                */
-               lwkt_gettoken(&vlock, vp->v_interlock);
-               if (TAILQ_FIRST(&mp->mnt_nvnodelist) != vp) {
-                       lwkt_reltoken(&vlock);
-                       continue;
-               }
-               TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
-               TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist,vp, v_nmntvnodes);
-
-               /*
-                * Must check again
-                */
-               if (vp->v_type == VNON ||
-                   vp->v_type == VBAD ||
-                   !VMIGHTFREE(vp) ||          /* critical path opt */
-                   (vp->v_object &&
-                    vp->v_object->resident_page_count >= trigger)
-               ) {
-                       lwkt_reltoken(&vlock);
-                       --count;
-                       continue;
-               }
-               vgonel(vp, &vlock, curthread);
-               ++done;
-               --count;
-       }
-       lwkt_reltoken(&ilock);
-       return done;
-}
-
-/*
- * Attempt to recycle vnodes in a context that is always safe to block.
- * Calling vlrurecycle() from the bowels of file system code has some
- * interesting deadlock problems.
- */
-static struct thread *vnlruthread;
-static int vnlruproc_sig;
-
-static void 
-vnlru_proc(void)
-{
-       struct mount *mp, *nmp;
-       lwkt_tokref ilock;
-       int s;
-       int done;
-       struct thread *td = curthread;
-
-       EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, td,
-           SHUTDOWN_PRI_FIRST);   
-
-       s = splbio();
-       for (;;) {
-               kproc_suspend_loop();
-               if (numvnodes - freevnodes <= desiredvnodes * 9 / 10) {
-                       vnlruproc_sig = 0;
-                       wakeup(&vnlruproc_sig);
-                       tsleep(td, 0, "vlruwt", hz);
-                       continue;
-               }
-               done = 0;
-               lwkt_gettoken(&ilock, &mountlist_token);
-               for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
-                       if (vfs_busy(mp, LK_NOWAIT, &ilock, td)) {
-                               nmp = TAILQ_NEXT(mp, mnt_list);
-                               continue;
-                       }
-                       done += vlrureclaim(mp);
-                       lwkt_gettokref(&ilock);
-                       nmp = TAILQ_NEXT(mp, mnt_list);
-                       vfs_unbusy(mp, td);
-               }
-               lwkt_reltoken(&ilock);
-               if (done == 0) {
-                       vnlru_nowhere++;
-                       tsleep(td, 0, "vlrup", hz * 3);
-               }
-       }
-       splx(s);
-}
-
-static struct kproc_desc vnlru_kp = {
-       "vnlru",
-       vnlru_proc,
-       &vnlruthread
-};
-SYSINIT(vnlru, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &vnlru_kp)
-
-/*
- * Routines having to do with the management of the vnode table.
- */
-
-/*
- * Return the next vnode from the free list.
- */
-int
-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 */
-       struct vnode *vp = NULL;
-       struct vnode *xvp;
-       vm_object_t object;
-       lwkt_tokref ilock;
-       lwkt_tokref vlock;
-
-       s = splbio();   /* YYY remove me */
-
-       /*
-        * Try to reuse vnodes if we hit the max.  This situation only
-        * occurs in certain large-memory (2G+) situations.  We cannot
-        * attempt to directly reclaim vnodes due to nasty recursion
-        * problems.
-        */
-       while (numvnodes - freevnodes > desiredvnodes) {
-               if (vnlruproc_sig == 0) {
-                       vnlruproc_sig = 1;      /* avoid unnecessary wakeups */
-                       wakeup(vnlruthread);
-               }
-               tsleep(&vnlruproc_sig, 0, "vlruwk", hz);
-       }
-
-
-       /*
-        * Attempt to reuse a vnode already on the free list, allocating
-        * a new vnode if we can't find one or if we have not reached a
-        * good minimum for good LRU performance.
-        */
-       lwkt_gettoken(&ilock, &vnode_free_list_token);
-       if (freevnodes >= wantfreevnodes && numvnodes >= minvnodes) {
-               int count;
-
-               for (count = 0; count < freevnodes; count++) {
-                       /*
-                        * __VNODESCAN__
-                        *
-                        * Pull the next vnode off the free list and do some
-                        * sanity checks.  Note that regardless of how we
-                        * block, if freevnodes is non-zero there had better
-                        * be something on the list.
-                        */
-                       vp = TAILQ_FIRST(&vnode_free_list);
-                       if (vp == NULL)
-                               panic("getnewvnode: free vnode isn't");
-
-                       /*
-                        * Move the vnode to the end of the list so other
-                        * processes do not double-block trying to recycle
-                        * the same vnode (as an optimization), then get
-                        * the interlock.
-                        */
-                       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-                       TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
-
-                       /*
-                        * Skip vnodes that are in the process of being
-                        * held or referenced.  Since the act of adding or
-                        * removing a vnode on the freelist requires a token
-                        * and may block, the ref count may be adjusted
-                        * prior to its addition or removal.
-                        */
-                       if (VSHOULDBUSY(vp)) {
-                               vp = NULL;
-                               continue;
-                       }
-
-
-                       /*
-                        * Obtain the vnode interlock and check that the
-                        * vnode is still on the free list.
-                        *
-                        * This normally devolves into a degenerate case so
-                        * it is optimal.   Loop up if it isn't.  Note that
-                        * the vnode could be in the middle of being moved
-                        * off the free list (the VSHOULDBUSY() check) and
-                        * must be skipped if so.
-                        */
-                       lwkt_gettoken(&vlock, vp->v_interlock);
-                       TAILQ_FOREACH_REVERSE(xvp, &vnode_free_list, 
-                           freelst, v_freelist) {
-                               if (vp == xvp)
-                                       break;
-                       }
-                       if (vp != xvp || VSHOULDBUSY(vp)) {
-                               vp = NULL;
-                               continue;
-                       }
-
-                       /*
-                        * We now safely own the vnode.  If the vnode has
-                        * an object do not recycle it if its VM object
-                        * has resident pages or references.
-                        */
-                       if ((VOP_GETVOBJECT(vp, &object) == 0 &&
-                           (object->resident_page_count || object->ref_count))
-                       ) {
-                               lwkt_reltoken(&vlock);
-                               vp = NULL;
-                               continue;
-                       }
-
-                       /*
-                        * We can almost reuse this vnode.  But we don't want
-                        * to recycle it if the vnode has children in the
-                        * namecache because that breaks the namecache's
-                        * path element chain.  (YYY use nc_refs for the
-                        * check?)
-                        */
-                       KKASSERT(vp->v_flag & VFREE);
-                       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-
-                       if (TAILQ_FIRST(&vp->v_namecache) == NULL ||
-                           cache_leaf_test(vp) >= 0) {
-                               /* ok, we can reuse this vnode */
-                               break;
-                       }
-                       lwkt_reltoken(&vlock);
-                       TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
-                       vp = NULL;
-               }
-       }
-
-       /*
-        * If vp is non-NULL we hold it's interlock.
-        */
-       if (vp) {
-               vp->v_flag |= VDOOMED;
-               vp->v_flag &= ~VFREE;
-               freevnodes--;
-               lwkt_reltoken(&ilock);
-               cache_inval_vp(vp, CINV_SELF);  /* YYY may block */
-               vp->v_lease = NULL;
-               if (vp->v_type != VBAD) {
-                       vgonel(vp, &vlock, td);
-               } else {
-                       lwkt_reltoken(&vlock);
-               }
-
-#ifdef INVARIANTS
-               {
-                       int s;
-
-                       if (vp->v_data)
-                               panic("cleaned vnode isn't");
-                       s = splbio();
-                       if (vp->v_numoutput)
-                               panic("Clean vnode has pending I/O's");
-                       splx(s);
-               }
-#endif
-               vp->v_flag = 0;
-               vp->v_lastw = 0;
-               vp->v_lasta = 0;
-               vp->v_cstart = 0;
-               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_inval_vp(vp, CINV_SELF);
-               TAILQ_INIT(&vp->v_namecache);
-               numvnodes++;
-       }
-
-       TAILQ_INIT(&vp->v_cleanblkhd);
-       TAILQ_INIT(&vp->v_dirtyblkhd);
-       vp->v_type = VNON;
-       vp->v_tag = tag;
-       vp->v_ops = ops;
-       *vpp = vp;
-       vp->v_usecount = 1;
-       vp->v_data = NULL;
-       splx(s);
-
-       /*
-        * Placing the vnode on the mount point's queue makes it visible.
-        * We had better already have a ref on it.
-        */
-       insmntque(vp, mp);
-
-       vfs_object_create(vp, td);
-       return (0);
-}
-
-/*
- * Move a vnode from one mount queue to another.
- */
-static void
-insmntque(struct vnode *vp, struct mount *mp)
-{
-       lwkt_tokref ilock;
-
-       lwkt_gettoken(&ilock, &mntvnode_token);
-       /*
-        * Delete from old mount point vnode list, if on one.
-        */
-       if (vp->v_mount != NULL) {
-               KASSERT(vp->v_mount->mnt_nvnodelistsize > 0,
-                       ("bad mount point vnode list size"));
-               TAILQ_REMOVE(&vp->v_mount->mnt_nvnodelist, vp, v_nmntvnodes);
-               vp->v_mount->mnt_nvnodelistsize--;
-       }
-       /*
-        * Insert into list of vnodes for the new mount point, if available.
-        */
-       if ((vp->v_mount = mp) == NULL) {
-               lwkt_reltoken(&ilock);
-               return;
-       }
-       TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
-       mp->mnt_nvnodelistsize++;
-       lwkt_reltoken(&ilock);
-}
-
 /*
  * Update outstanding I/O count and do wakeup if requested.
  */
@@ -874,7 +267,8 @@ vwakeup(struct buf *bp)
 
 /*
  * Flush out and invalidate all buffers associated with a vnode.
- * Called with the underlying object locked.
+ *
+ * vp must be locked.
  */
 int
 vinvalbuf(struct vnode *vp, int flags, struct thread *td,
@@ -884,7 +278,6 @@ vinvalbuf(struct vnode *vp, int flags, struct thread *td,
        struct buf *nbp, *blist;
        int s, error;
        vm_object_t object;
-       lwkt_tokref vlock;
 
        if (flags & V_SAVE) {
                s = splbio();
@@ -981,12 +374,10 @@ vinvalbuf(struct vnode *vp, int flags, struct thread *td,
        /*
         * Destroy the copy in the VM cache, too.
         */
-       lwkt_gettoken(&vlock, vp->v_interlock);
        if (VOP_GETVOBJECT(vp, &object) == 0) {
                vm_object_page_remove(object, 0, 0,
                        (flags & V_SAVE) ? TRUE : FALSE);
        }
-       lwkt_reltoken(&vlock);
 
        if (!TAILQ_EMPTY(&vp->v_dirtyblkhd) || !TAILQ_EMPTY(&vp->v_cleanblkhd))
                panic("vinvalbuf: flush failed");
@@ -997,6 +388,8 @@ vinvalbuf(struct vnode *vp, int flags, struct thread *td,
  * Truncate a file's buffer and pages to a specified length.  This
  * is in lieu of the old vinvalbuf mechanism, which performed unneeded
  * sync activity.
+ *
+ * The vnode must be locked.
  */
 int
 vtruncbuf(struct vnode *vp, struct thread *td, off_t length, int blksize)
@@ -1102,8 +495,6 @@ restartsync:
 void
 bgetvp(struct vnode *vp, struct buf *bp)
 {
-       int s;
-
        KASSERT(bp->b_vp == NULL, ("bgetvp: not free"));
 
        vhold(vp);
@@ -1112,11 +503,11 @@ bgetvp(struct vnode *vp, struct buf *bp)
        /*
         * Insert onto list for new vnode.
         */
-       s = splbio();
+       crit_enter();
        bp->b_xflags |= BX_VNCLEAN;
        bp->b_xflags &= ~BX_VNDIRTY;
        TAILQ_INSERT_TAIL(&vp->v_cleanblkhd, bp, b_vnbufs);
-       splx(s);
+       crit_exit();
 }
 
 /*
@@ -1127,7 +518,6 @@ brelvp(struct buf *bp)
 {
        struct vnode *vp;
        struct buflists *listheadp;
-       int s;
 
        KASSERT(bp->b_vp != NULL, ("brelvp: NULL"));
 
@@ -1135,7 +525,7 @@ brelvp(struct buf *bp)
         * Delete from old vnode list, if on one.
         */
        vp = bp->b_vp;
-       s = splbio();
+       crit_enter();
        if (bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) {
                if (bp->b_xflags & BX_VNDIRTY)
                        listheadp = &vp->v_dirtyblkhd;
@@ -1148,183 +538,9 @@ brelvp(struct buf *bp)
                vp->v_flag &= ~VONWORKLST;
                LIST_REMOVE(vp, v_synclist);
        }
-       splx(s);
-       bp->b_vp = (struct vnode *) 0;
-       vdrop(vp);
-}
-
-/*
- * The workitem queue.
- * 
- * It is useful to delay writes of file data and filesystem metadata
- * for tens of seconds so that quickly created and deleted files need
- * not waste disk bandwidth being created and removed. To realize this,
- * we append vnodes to a "workitem" queue. When running with a soft
- * updates implementation, most pending metadata dependencies should
- * not wait for more than a few seconds. Thus, mounted on block devices
- * are delayed only about a half the time that file data is delayed.
- * Similarly, directory updates are more critical, so are only delayed
- * about a third the time that file data is delayed. Thus, there are
- * SYNCER_MAXDELAY queues that are processed round-robin at a rate of
- * one each second (driven off the filesystem syncer process). The
- * syncer_delayno variable indicates the next queue that is to be processed.
- * Items that need to be processed soon are placed in this queue:
- *
- *     syncer_workitem_pending[syncer_delayno]
- *
- * A delay of fifteen seconds is done by placing the request fifteen
- * entries later in the queue:
- *
- *     syncer_workitem_pending[(syncer_delayno + 15) & syncer_mask]
- *
- */
-
-/*
- * Add an item to the syncer work queue.
- */
-static void
-vn_syncer_add_to_worklist(struct vnode *vp, int delay)
-{
-       int s, slot;
-
-       s = splbio();
-
-       if (vp->v_flag & VONWORKLST) {
-               LIST_REMOVE(vp, v_synclist);
-       }
-
-       if (delay > syncer_maxdelay - 2)
-               delay = syncer_maxdelay - 2;
-       slot = (syncer_delayno + delay) & syncer_mask;
-
-       LIST_INSERT_HEAD(&syncer_workitem_pending[slot], vp, v_synclist);
-       vp->v_flag |= VONWORKLST;
-       splx(s);
-}
-
-struct  thread *updatethread;
-static void sched_sync (void);
-static struct kproc_desc up_kp = {
-       "syncer",
-       sched_sync,
-       &updatethread
-};
-SYSINIT(syncer, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &up_kp)
-
-/*
- * System filesystem synchronizer daemon.
- */
-void 
-sched_sync(void)
-{
-       struct synclist *slp;
-       struct vnode *vp;
-       long starttime;
-       int s;
-       struct thread *td = curthread;
-
-       EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, td,
-           SHUTDOWN_PRI_LAST);   
-
-       for (;;) {
-               kproc_suspend_loop();
-
-               starttime = time_second;
-
-               /*
-                * Push files whose dirty time has expired.  Be careful
-                * of interrupt race on slp queue.
-                */
-               s = splbio();
-               slp = &syncer_workitem_pending[syncer_delayno];
-               syncer_delayno += 1;
-               if (syncer_delayno == syncer_maxdelay)
-                       syncer_delayno = 0;
-               splx(s);
-
-               while ((vp = LIST_FIRST(slp)) != NULL) {
-                       if (VOP_ISLOCKED(vp, NULL) == 0) {
-                               vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
-                               (void) VOP_FSYNC(vp, MNT_LAZY, td);
-                               VOP_UNLOCK(vp, NULL, 0, td);
-                       }
-                       s = splbio();
-                       if (LIST_FIRST(slp) == vp) {
-                               /*
-                                * Note: v_tag VT_VFS vps can remain on the
-                                * worklist too with no dirty blocks, but 
-                                * since sync_fsync() moves it to a different 
-                                * slot we are safe.
-                                */
-                               if (TAILQ_EMPTY(&vp->v_dirtyblkhd) &&
-                                   !vn_isdisk(vp, NULL))
-                                       panic("sched_sync: fsync failed vp %p tag %d", vp, vp->v_tag);
-                               /*
-                                * Put us back on the worklist.  The worklist
-                                * routine will remove us from our current
-                                * position and then add us back in at a later
-                                * position.
-                                */
-                               vn_syncer_add_to_worklist(vp, syncdelay);
-                       }
-                       splx(s);
-               }
-
-               /*
-                * Do soft update processing.
-                */
-               if (bioops.io_sync)
-                       (*bioops.io_sync)(NULL);
-
-               /*
-                * The variable rushjob allows the kernel to speed up the
-                * processing of the filesystem syncer process. A rushjob
-                * value of N tells the filesystem syncer to process the next
-                * N seconds worth of work on its queue ASAP. Currently rushjob
-                * is used by the soft update code to speed up the filesystem
-                * syncer process when the incore state is getting so far
-                * ahead of the disk that the kernel memory pool is being
-                * threatened with exhaustion.
-                */
-               if (rushjob > 0) {
-                       rushjob -= 1;
-                       continue;
-               }
-               /*
-                * If it has taken us less than a second to process the
-                * current work, then wait. Otherwise start right over
-                * again. We can still lose time if any single round
-                * takes more than two seconds, but it does not really
-                * matter as we are just trying to generally pace the
-                * filesystem activity.
-                */
-               if (time_second == starttime)
-                       tsleep(&lbolt, 0, "syncer", 0);
-       }
-}
-
-/*
- * Request the syncer daemon to speed up its work.
- * We never push it to speed up more than half of its
- * normal turn time, otherwise it could take over the cpu.
- *
- * YYY wchan field protected by the BGL.
- */
-int
-speedup_syncer(void)
-{
-       crit_enter();
-       if (updatethread->td_wchan == &lbolt) { /* YYY */
-               unsleep(updatethread);
-               lwkt_schedule(updatethread);
-       }
        crit_exit();
-       if (rushjob < syncdelay / 2) {
-               rushjob += 1;
-               stat_rush_requests += 1;
-               return (1);
-       }
-       return(0);
+       bp->b_vp = NULL;
+       vdrop(vp);
 }
 
 /*
@@ -1386,7 +602,6 @@ reassignbuf(struct buf *bp, struct vnode *newvp)
 {
        struct buflists *listheadp;
        int delay;
-       int s;
 
        if (newvp == NULL) {
                printf("reassignbuf: NULL");
@@ -1401,7 +616,7 @@ reassignbuf(struct buf *bp, struct vnode *newvp)
        if (bp->b_flags & B_PAGING)
                panic("cannot reassign paging buffer");
 
-       s = splbio();
+       crit_enter();
        /*
         * Delete from old vnode list, if on one.
         */
@@ -1508,7 +723,7 @@ reassignbuf(struct buf *bp, struct vnode *newvp)
                bp->b_vp = newvp;
                vhold(bp->b_vp);
        }
-       splx(s);
+       crit_exit();
 }
 
 /*
@@ -1534,611 +749,143 @@ bdevvp(dev_t dev, struct vnode **vpp)
        vp = nvp;
        vp->v_type = VCHR;
        vp->v_udev = dev->si_udev;
+       vx_unlock(vp);
        *vpp = vp;
        return (0);
-}
-
-int
-v_associate_rdev(struct vnode *vp, dev_t dev)
-{
-       lwkt_tokref ilock;
-
-       if (dev == NULL || dev == NODEV)
-               return(ENXIO);
-       if (dev_is_good(dev) == 0)
-               return(ENXIO);
-       KKASSERT(vp->v_rdev == NULL);
-       if (dev_ref_debug)
-               printf("Z1");
-       vp->v_rdev = reference_dev(dev);
-       lwkt_gettoken(&ilock, &spechash_token);
-       SLIST_INSERT_HEAD(&dev->si_hlist, vp, v_specnext);
-       lwkt_reltoken(&ilock);
-       return(0);
-}
-
-void
-v_release_rdev(struct vnode *vp)
-{
-       lwkt_tokref ilock;
-       dev_t dev;
-
-       if ((dev = vp->v_rdev) != NULL) {
-               lwkt_gettoken(&ilock, &spechash_token);
-               SLIST_REMOVE(&dev->si_hlist, vp, vnode, v_specnext);
-               if (dev_ref_debug && vp->v_opencount != 0) {
-                       printf("releasing rdev with non-0 "
-                               "v_opencount(%d) (revoked?)\n",
-                               vp->v_opencount);
-               }
-               vp->v_rdev = NULL;
-               vp->v_opencount = 0;
-               release_dev(dev);
-               lwkt_reltoken(&ilock);
-       }
-}
-
-/*
- * Add a vnode to the alias list hung off the dev_t.  We only associate
- * the device number with the vnode.  The actual device is not associated
- * until the vnode is opened (usually in spec_open()), and will be 
- * disassociated on last close.
- */
-void
-addaliasu(struct vnode *nvp, udev_t nvp_udev)
-{
-       if (nvp->v_type != VBLK && nvp->v_type != VCHR)
-               panic("addaliasu on non-special vnode");
-       nvp->v_udev = nvp_udev;
-}
-
-/*
- * Grab a particular vnode from the free list, increment its
- * reference count and lock it. The vnode lock bit is set if the
- * vnode is being eliminated in vgone. The process is awakened
- * when the transition is completed, and an error returned to
- * indicate that the vnode is no longer usable (possibly having
- * been changed to a new file system type).
- *
- * This code is very sensitive.  We are depending on the vnode interlock
- * to be maintained through to the vn_lock() call, which means that we
- * cannot block which means that we cannot call vbusy() until after vn_lock().
- * If the interlock is not maintained, the VXLOCK check will not properly
- * interlock against a vclean()'s LK_DRAIN operation on the lock.
- */
-int
-vget(struct vnode *vp, lwkt_tokref_t vlock, int flags, thread_t td)
-{
-       int error;
-       lwkt_tokref vvlock;
-
-       /*
-        * We need the interlock to safely modify the v_ fields.  ZZZ it is
-        * only legal to pass (1) the vnode's interlock and (2) only pass
-        * NULL w/o LK_INTERLOCK if the vnode is *ALREADY* referenced or
-        * held.
-        */
-       if ((flags & LK_INTERLOCK) == 0) {
-               lwkt_gettoken(&vvlock, vp->v_interlock);
-               vlock = &vvlock;
-       }
-
-       /*
-        * If the vnode is in the process of being cleaned out for
-        * another use, we wait for the cleaning to finish and then
-        * return failure. Cleaning is determined by checking that
-        * the VXLOCK flag is set.  It is possible for the vnode to be
-        * self-referenced during the cleaning operation.
-        */
-       if (vp->v_flag & VXLOCK) {
-               if (vp->v_vxthread == curthread) {
-#if 0
-                       /* this can now occur in normal operation */
-                       log(LOG_INFO, "VXLOCK interlock avoided\n");
-#endif
-               } else {
-                       vp->v_flag |= VXWANT;
-                       lwkt_reltoken(vlock);
-                       tsleep((caddr_t)vp, 0, "vget", 0);
-                       return (ENOENT);
-               }
-       }
-
-       /*
-        * Bump v_usecount to prevent the vnode from being recycled.  The
-        * usecount needs to be bumped before we successfully get our lock.
-        */
-       vp->v_usecount++;
-       if (flags & LK_TYPE_MASK) {
-               if ((error = vn_lock(vp, vlock, flags | LK_INTERLOCK, td)) != 0) {
-                       /*
-                        * must expand vrele here because we do not want
-                        * to call VOP_INACTIVE if the reference count
-                        * drops back to zero since it was never really
-                        * active. We must remove it from the free list
-                        * before sleeping so that multiple processes do
-                        * not try to recycle it.
-                        */
-                       lwkt_gettokref(vlock);
-                       vp->v_usecount--;
-                       vmaybefree(vp);
-                       lwkt_reltoken(vlock);
-               }
-               return (error);
-       }
-       if (VSHOULDBUSY(vp))
-               vbusy(vp);      /* interlock must be held on call */
-       lwkt_reltoken(vlock);
-       return (0);
-}
-
-void
-vref(struct vnode *vp)
-{
-       crit_enter();   /* YYY use crit section for moment / BGL protected */
-       vp->v_usecount++;
-       crit_exit();
-}
-
-/*
- * Release a usecount on a vnode.  This routine does not call unlock on the
- * vnode.
- *
- * If the usecount drops to zero, call the inactive routine and return the
- * vnode to the freelist.
- */
-void
-vrele(struct vnode *vp)
-{
-       struct thread *td = curthread;  /* XXX */
-       lwkt_tokref vlock;
-
-       KASSERT(vp != NULL && vp->v_usecount >= 0,
-           ("vrele: null vp or <=0 v_usecount"));
-
-       lwkt_gettoken(&vlock, vp->v_interlock);
-
-       if (vp->v_usecount > 1) {
-               vp->v_usecount--;
-               lwkt_reltoken(&vlock);
-               return;
-       }
-
-       if (vp->v_usecount == 1) {
-               vp->v_usecount--;
-               /*
-                * We must call VOP_INACTIVE with the node locked and the
-                * usecount 0.  If we are doing a vpu, the node is already
-                * locked, but, in the case of vrele, we must explicitly lock
-                * the vnode before calling VOP_INACTIVE.
-                */
-
-               if (vn_lock(vp, NULL, LK_EXCLUSIVE, td) == 0)
-                       VOP_INACTIVE(vp, td);
-               vmaybefree(vp);
-               lwkt_reltoken(&vlock);
-       } else {
-#ifdef DIAGNOSTIC
-               vprint("vrele: negative ref count", vp);
-#endif
-               lwkt_reltoken(&vlock);
-               panic("vrele: negative ref cnt");
-       }
-}
-
-/*
- * Release a usecount on a vnode.  This routine does not call unlock on the
- * vnode.   No action is taken if the usecount drops to zero.  This routine
- * is typically called only from within a *_inactive() procedure to avoid
- * recursing the procedure.
- */
-void
-vrele_noinactive(struct vnode *vp)
-{
-       lwkt_tokref vlock;
-
-       KASSERT(vp != NULL && vp->v_usecount >= 0,
-           ("vrele: null vp or <=0 v_usecount"));
-
-       lwkt_gettoken(&vlock, vp->v_interlock);
-       vp->v_usecount--;
-       lwkt_reltoken(&vlock);
-}
-
-/*
- * Unlock a vnode and release a usecount on it, inactivating the vnode if
- * the count drops to 0.
- */
-void
-vput(struct vnode *vp)
-{
-       struct thread *td = curthread;  /* XXX */
-       lwkt_tokref vlock;
-
-       KASSERT(vp != NULL, ("vput: null vp"));
-
-       lwkt_gettoken(&vlock, vp->v_interlock);
-
-       if (vp->v_usecount > 1) {
-               vp->v_usecount--;
-               VOP_UNLOCK(vp, &vlock, LK_INTERLOCK, td);
-               return;
-       }
-
-       if (vp->v_usecount == 1) {
-               vp->v_usecount--;
-               /*
-                * We must call VOP_INACTIVE with the node locked.
-                * If we are doing a vpu, the node is already locked,
-                * so we just need to release the vnode mutex.
-                */
-               VOP_INACTIVE(vp, td);
-               vmaybefree(vp);
-               lwkt_reltoken(&vlock);
-       } else {
-#ifdef DIAGNOSTIC
-               vprint("vput: negative ref count", vp);
-#endif
-               lwkt_reltoken(&vlock);
-               panic("vput: negative ref cnt");
-       }
-}
-
-/*
- * Somebody doesn't want the vnode recycled. ZZZ vnode interlock should
- * be held but isn't.
- */
-void
-vhold(struct vnode *vp)
-{
-       int s;
-
-       s = splbio();
-       vp->v_holdcnt++;
-       if (VSHOULDBUSY(vp))
-               vbusy(vp);      /* interlock must be held on call */
-       splx(s);
-}
-
-/*
- * One less who cares about this vnode.
- */
-void
-vdrop(struct vnode *vp)
-{
-       lwkt_tokref vlock;
-
-       lwkt_gettoken(&vlock, vp->v_interlock);
-       if (vp->v_holdcnt <= 0)
-               panic("vdrop: holdcnt");
-       vp->v_holdcnt--;
-       vmaybefree(vp);
-       lwkt_reltoken(&vlock);
-}
-
-int
-vmntvnodescan(
-    struct mount *mp, 
-    int (*fastfunc)(struct mount *mp, struct vnode *vp, void *data),
-    int (*slowfunc)(struct mount *mp, struct vnode *vp, 
-                   lwkt_tokref_t vlock, void *data),
-    void *data
-) {
-       lwkt_tokref ilock;
-       lwkt_tokref vlock;
-       struct vnode *pvp;
-       struct vnode *vp;
-       int r = 0;
-
-       /*
-        * Scan the vnodes on the mount's vnode list.  Use a placemarker
-        */
-       pvp = zalloc(vnode_zone);
-       pvp->v_flag |= VPLACEMARKER;
-
-       lwkt_gettoken(&ilock, &mntvnode_token);
-       TAILQ_INSERT_HEAD(&mp->mnt_nvnodelist, pvp, v_nmntvnodes);
-
-       while ((vp = TAILQ_NEXT(pvp, v_nmntvnodes)) != NULL) {
-               /*
-                * Move the placemarker and skip other placemarkers we
-                * encounter.  The nothing can get in our way so the
-                * mount point on the vp must be valid.
-                */
-               TAILQ_REMOVE(&mp->mnt_nvnodelist, pvp, v_nmntvnodes);
-               TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, pvp, v_nmntvnodes);
-               if (vp->v_flag & VPLACEMARKER)
-                       continue;
-               KKASSERT(vp->v_mount == mp);
-
-               /*
-                * Quick test
-                */
-               if (fastfunc) {
-                       if ((r = fastfunc(mp, vp, data)) < 0)
-                               continue;
-                       if (r)
-                               break;
-               }
-
-               /*
-                * Get the vnodes interlock and make sure it is still on the
-                * mount list.  Skip it if it has moved (we may encounter it
-                * later).  Then do the with-interlock test.  The callback
-                * is responsible for releasing the vnode interlock.
-                *
-                * The interlock is type-stable.
-                */
-               if (slowfunc) {
-                       lwkt_gettoken(&vlock, vp->v_interlock);
-                       if (vp != TAILQ_PREV(pvp, vnodelst, v_nmntvnodes)) {
-                               printf("vmntvnodescan (debug info only): f=%p vp=%p vnode ripped out from under us\n", slowfunc, vp);
-                               lwkt_reltoken(&vlock);
-                               continue;
-                       }
-                       if ((r = slowfunc(mp, vp, &vlock, data)) != 0) {
-                               KKASSERT(lwkt_havetokref(&vlock) == 0);
-                               break;
-                       }
-                       KKASSERT(lwkt_havetokref(&vlock) == 0);
-               }
-       }
-       TAILQ_REMOVE(&mp->mnt_nvnodelist, pvp, v_nmntvnodes);
-       zfree(vnode_zone, pvp);
-       lwkt_reltoken(&ilock);
-       return(r);
-}
-
-/*
- * Remove any vnodes in the vnode table belonging to mount point mp.
- *
- * If FORCECLOSE is not specified, there should not be any active ones,
- * return error if any are found (nb: this is a user error, not a
- * system error). If FORCECLOSE is specified, detach any active vnodes
- * that are found.
- *
- * If WRITECLOSE is set, only flush out regular file vnodes open for
- * writing.
- *
- * SKIPSYSTEM causes any vnodes marked VSYSTEM to be skipped.
- *
- * `rootrefs' specifies the base reference count for the root vnode
- * of this filesystem. The root vnode is considered busy if its
- * v_usecount exceeds this value. On a successful return, vflush()
- * will call vrele() on the root vnode exactly rootrefs times.
- * If the SKIPSYSTEM or WRITECLOSE flags are specified, rootrefs must
- * be zero.
- */
-#ifdef DIAGNOSTIC
-static int busyprt = 0;                /* print out busy vnodes */
-SYSCTL_INT(_debug, OID_AUTO, busyprt, CTLFLAG_RW, &busyprt, 0, "");
-#endif
-
-static int vflush_scan(struct mount *mp, struct vnode *vp,
-                       lwkt_tokref_t vlock, void *data);
-
-struct vflush_info {
-       int flags;
-       int busy;
-       thread_t td;
-};
+}
 
 int
-vflush(struct mount *mp, int rootrefs, int flags)
+v_associate_rdev(struct vnode *vp, dev_t dev)
 {
-       struct thread *td = curthread;  /* XXX */
-       struct vnode *rootvp = NULL;
-       int error;
-       lwkt_tokref vlock;
-       struct vflush_info vflush_info;
+       lwkt_tokref ilock;
 
-       if (rootrefs > 0) {
-               KASSERT((flags & (SKIPSYSTEM | WRITECLOSE)) == 0,
-                   ("vflush: bad args"));
-               /*
-                * Get the filesystem root vnode. We can vput() it
-                * immediately, since with rootrefs > 0, it won't go away.
-                */
-               if ((error = VFS_ROOT(mp, &rootvp)) != 0)
-                       return (error);
-               vput(rootvp);
-       }
+       if (dev == NULL || dev == NODEV)
+               return(ENXIO);
+       if (dev_is_good(dev) == 0)
+               return(ENXIO);
+       KKASSERT(vp->v_rdev == NULL);
+       if (dev_ref_debug)
+               printf("Z1");
+       vp->v_rdev = reference_dev(dev);
+       lwkt_gettoken(&ilock, &spechash_token);
+       SLIST_INSERT_HEAD(&dev->si_hlist, vp, v_specnext);
+       lwkt_reltoken(&ilock);
+       return(0);
+}
 
-       vflush_info.busy = 0;
-       vflush_info.flags = flags;
-       vflush_info.td = td;
-       vmntvnodescan(mp, NULL, vflush_scan, &vflush_info);
+void
+v_release_rdev(struct vnode *vp)
+{
+       lwkt_tokref ilock;
+       dev_t dev;
 
-       if (rootrefs > 0 && (flags & FORCECLOSE) == 0) {
-               /*
-                * If just the root vnode is busy, and if its refcount
-                * is equal to `rootrefs', then go ahead and kill it.
-                */
-               lwkt_gettoken(&vlock, rootvp->v_interlock);
-               KASSERT(vflush_info.busy > 0, ("vflush: not busy"));
-               KASSERT(rootvp->v_usecount >= rootrefs, ("vflush: rootrefs"));
-               if (vflush_info.busy == 1 && rootvp->v_usecount == rootrefs) {
-                       vgonel(rootvp, &vlock, td);
-                       vflush_info.busy = 0;
-               } else {
-                       lwkt_reltoken(&vlock);
+       if ((dev = vp->v_rdev) != NULL) {
+               lwkt_gettoken(&ilock, &spechash_token);
+               SLIST_REMOVE(&dev->si_hlist, vp, vnode, v_specnext);
+               if (dev_ref_debug && vp->v_opencount != 0) {
+                       printf("releasing rdev with non-0 "
+                               "v_opencount(%d) (revoked?)\n",
+                               vp->v_opencount);
                }
+               vp->v_rdev = NULL;
+               vp->v_opencount = 0;
+               release_dev(dev);
+               lwkt_reltoken(&ilock);
        }
-       if (vflush_info.busy)
-               return (EBUSY);
-       for (; rootrefs > 0; rootrefs--)
-               vrele(rootvp);
-       return (0);
 }
 
 /*
- * The scan callback is made with an interlocked vnode.
+ * Add a vnode to the alias list hung off the dev_t.  We only associate
+ * the device number with the vnode.  The actual device is not associated
+ * until the vnode is opened (usually in spec_open()), and will be 
+ * disassociated on last close.
  */
-static int
-vflush_scan(struct mount *mp, struct vnode *vp,
-           lwkt_tokref_t vlock, void *data)
+void
+addaliasu(struct vnode *nvp, udev_t nvp_udev)
 {
-       struct vflush_info *info = data;
-       struct vattr vattr;
-
-       /*
-        * Skip over a vnodes marked VSYSTEM.
-        */
-       if ((info->flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) {
-               lwkt_reltoken(vlock);
-               return(0);
-       }
-
-       /*
-        * If WRITECLOSE is set, flush out unlinked but still open
-        * files (even if open only for reading) and regular file
-        * vnodes open for writing. 
-        */
-       if ((info->flags & WRITECLOSE) &&
-           (vp->v_type == VNON ||
-           (VOP_GETATTR(vp, &vattr, info->td) == 0 &&
-           vattr.va_nlink > 0)) &&
-           (vp->v_writecount == 0 || vp->v_type != VREG)) {
-               lwkt_reltoken(vlock);
-               return(0);
-       }
-
-       /*
-        * With v_usecount == 0, all we need to do is clear out the
-        * vnode data structures and we are done.
-        */
-       if (vp->v_usecount == 0) {
-               vgonel(vp, vlock, info->td);
-               return(0);
-       }
-
-       /*
-        * If FORCECLOSE is set, forcibly close the vnode. For block
-        * or character devices, revert to an anonymous device. For
-        * all other files, just kill them.
-        */
-       if (info->flags & FORCECLOSE) {
-               if (vp->v_type != VBLK && vp->v_type != VCHR) {
-                       vgonel(vp, vlock, info->td);
-               } else {
-                       vclean(vp, vlock, 0, info->td);
-                       vp->v_ops = spec_vnode_vops;
-                       insmntque(vp, (struct mount *) 0);
-               }
-               return(0);
-       }
-#ifdef DIAGNOSTIC
-       if (busyprt)
-               vprint("vflush: busy vnode", vp);
-#endif
-       lwkt_reltoken(vlock);
-       ++info->busy;
-       return(0);
+       if (nvp->v_type != VBLK && nvp->v_type != VCHR)
+               panic("addaliasu on non-special vnode");
+       nvp->v_udev = nvp_udev;
 }
 
 /*
- * Disassociate the underlying file system from a vnode.
+ * Disassociate a vnode from its underlying filesystem. 
+ *
+ * The vnode must be VX locked and refd
+ *
+ * If there are v_usecount references to the vnode other then ours we have
+ * to VOP_CLOSE the vnode before we can deactivate and reclaim it.
  */
-static void
-vclean(struct vnode *vp, lwkt_tokref_t vlock, int flags, struct thread *td)
+void
+vclean(struct vnode *vp, int flags, struct thread *td)
 {
        int active;
 
        /*
-        * Check to see if the vnode is in use. If so we have to reference it
-        * before we clean it out so that its count cannot fall to zero and
-        * generate a race against ourselves to recycle it.
+        * If the vnode has already been reclaimed we have nothing to do.
         */
-       if ((active = vp->v_usecount))
-               vp->v_usecount++;
+       if (vp->v_flag & VRECLAIMED)
+               return;
+       vp->v_flag |= VRECLAIMED;
 
        /*
-        * Prevent the vnode from being recycled or brought into use while we
-        * clean it out.
+        * Scrap the vfs cache
         */
-       if (vp->v_flag & VXLOCK)
-               panic("vclean: deadlock");
-       vp->v_flag |= VXLOCK;
-       vp->v_vxthread = curthread;
+       cache_inval_vp(vp, CINV_SELF);
 
        /*
-        * Even if the count is zero, the VOP_INACTIVE routine may still
-        * have the object locked while it cleans it out. The VOP_LOCK
-        * ensures that the VOP_INACTIVE routine is done with its work.
-        * For active vnodes, it ensures that no other activity can
-        * occur while the underlying object is being cleaned out.
-        *
-        * NOTE: we continue to hold the vnode interlock through to the
-        * end of vclean().
+        * Check to see if the vnode is in use. If so we have to reference it
+        * before we clean it out so that its count cannot fall to zero and
+        * generate a race against ourselves to recycle it.
         */
-       VOP_LOCK(vp, NULL, LK_DRAIN, td);
+       active = (vp->v_usecount > 1);
 
        /*
-        * Clean out any buffers associated with the vnode.
+        * Clean out any buffers associated with the vnode and destroy its
+        * object, if it has one.
         */
        vinvalbuf(vp, V_SAVE, td, 0, 0);
        VOP_DESTROYVOBJECT(vp);
 
        /*
         * If purging an active vnode, it must be closed and
-        * deactivated before being reclaimed. Note that the
-        * VOP_INACTIVE will unlock the vnode.
+        * deactivated before being reclaimed.   XXX
+        *
+        * Note that neither of these routines unlocks the vnode.
         */
        if (active) {
                if (flags & DOCLOSE)
                        VOP_CLOSE(vp, FNONBLOCK, td);
+       }
+
+       /*
+        * If the vnode has not be deactivated, deactivated it.
+        */
+       if ((vp->v_flag & VINACTIVE) == 0) {
+               vp->v_flag |= VINACTIVE;
                VOP_INACTIVE(vp, td);
-       } else {
-               /*
-                * Any other processes trying to obtain this lock must first
-                * wait for VXLOCK to clear, then call the new lock operation.
-                */
-               VOP_UNLOCK(vp, NULL, 0, td);
        }
+
        /*
         * Reclaim the vnode.
         */
        if (VOP_RECLAIM(vp, td))
                panic("vclean: cannot reclaim");
 
-       if (active) {
-               /*
-                * Inline copy of vrele() since VOP_INACTIVE
-                * has already been called.
-                */
-               if (--vp->v_usecount <= 0) {
-#ifdef DIAGNOSTIC
-                       if (vp->v_usecount < 0 || vp->v_writecount != 0) {
-                               vprint("vclean: bad ref count", vp);
-                               panic("vclean: ref cnt");
-                       }
-#endif
-                       vfree(vp);
-               }
-       }
-
-       cache_inval_vp(vp, CINV_SELF);
-       vmaybefree(vp);
-       
        /*
         * Done with purge, notify sleepers of the grim news.
         */
        vp->v_ops = dead_vnode_vops;
        vn_pollgone(vp);
        vp->v_tag = VT_NON;
-       vp->v_flag &= ~VXLOCK;
-       vp->v_vxthread = NULL;
-       if (vp->v_flag & VXWANT) {
-               vp->v_flag &= ~VXWANT;
-               wakeup((caddr_t) vp);
-       }
-       lwkt_reltoken(vlock);
 }
 
 /*
  * Eliminate all activity associated with the requested vnode
  * and with all vnodes aliased to the requested vnode.
  *
+ * The vnode must be referenced and vx_lock()'d
+ *
  * revoke { struct vnode *a_vp, int a_flags }
  */
 int
@@ -2151,21 +898,20 @@ vop_stdrevoke(struct vop_revoke_args *ap)
        KASSERT((ap->a_flags & REVOKEALL) != 0, ("vop_revoke"));
 
        vp = ap->a_vp;
+
        /*
-        * If a vgone (or vclean) is already in progress,
-        * wait until it is done and return.
+        * If the vnode is already dead don't try to revoke it
         */
-       if (vp->v_flag & VXLOCK) {
-               vp->v_flag |= VXWANT;
-               /*lwkt_reltoken(vlock); ZZZ */
-               tsleep((caddr_t)vp, 0, "vop_revokeall", 0);
+       if (vp->v_flag & VRECLAIMED)
                return (0);
-       }
 
        /*
         * If the vnode has a device association, scrap all vnodes associated
         * with the device.  Don't let the device disappear on us while we
         * are scrapping the vnodes.
+        *
+        * The passed vp will probably show up in the list, do not VX lock
+        * it twice!
         */
        if (vp->v_type != VCHR && vp->v_type != VBLK)
                return(0);
@@ -2174,83 +920,72 @@ vop_stdrevoke(struct vop_revoke_args *ap)
                        return(0);
        }
        reference_dev(dev);
-       for (;;) {
-               lwkt_gettoken(&ilock, &spechash_token);
-               vq = SLIST_FIRST(&dev->si_hlist);
-               lwkt_reltoken(&ilock);
-               if (vq == NULL)
-                       break;
-               vgone(vq);
+       lwkt_gettoken(&ilock, &spechash_token);
+       while ((vq = SLIST_FIRST(&dev->si_hlist)) != NULL) {
+               if (vp == vq || vx_get(vq) == 0) {
+                       if (vq == SLIST_FIRST(&dev->si_hlist))
+                               vgone(vq);
+                       if (vp != vq)
+                               vx_put(vq);
+               }
        }
+       lwkt_reltoken(&ilock);
        release_dev(dev);
        return (0);
 }
 
 /*
  * Recycle an unused vnode to the front of the free list.
- * Release the passed interlock if the vnode will be recycled.
+ *
+ * Returns 1 if we were successfully able to recycle the vnode, 
+ * 0 otherwise.
  */
 int
-vrecycle(struct vnode *vp, lwkt_tokref_t inter_lkp, struct thread *td)
+vrecycle(struct vnode *vp, struct thread *td)
 {
-       lwkt_tokref vlock;
-
-       lwkt_gettoken(&vlock, vp->v_interlock);
-       if (vp->v_usecount == 0) {
-               if (inter_lkp)
-                       lwkt_reltoken(inter_lkp);
-               vgonel(vp, &vlock, td);
+       if (vp->v_usecount == 1) {
+               vgone(vp);
                return (1);
        }
-       lwkt_reltoken(&vlock);
        return (0);
 }
 
 /*
- * Eliminate all activity associated with a vnode
- * in preparation for reuse.
+ * Eliminate all activity associated with a vnode in preparation for reuse.
+ *
+ * The vnode must be VX locked and will remain VX locked on return.  This
+ * routine may be called with the vnode in any state, as long as it is
+ * VX locked.  The vnode will be cleaned out and marked VRECLAIMED but will
+ * not actually be reused until all existing refs and holds go away.
+ *
+ * NOTE: This routine may be called on a vnode which has not yet been
+ * already been deactivated (VOP_INACTIVE), or on a vnode which has
+ * already been reclaimed.
+ *
+ * This routine is not responsible for placing us back on the freelist. 
+ * Instead, it happens automatically when the caller releases the VX lock
+ * (assuming there aren't any other references).
  */
 void
 vgone(struct vnode *vp)
 {
-       struct thread *td = curthread;  /* XXX */
-       lwkt_tokref vlock;
-
-       lwkt_gettoken(&vlock, vp->v_interlock);
-       vgonel(vp, &vlock, td);
-}
-
-/*
- * vgone, with the vp interlock held.
- */
-void
-vgonel(struct vnode *vp, lwkt_tokref_t vlock, struct thread *td)
-{
-       lwkt_tokref ilock;
-       int s;
-
        /*
-        * If a vgone (or vclean) is already in progress,
-        * wait until it is done and return.
+        * assert that the VX lock is held.  This is an absolute requirement
+        * now for vgone() to be called.
         */
-       if (vp->v_flag & VXLOCK) {
-               vp->v_flag |= VXWANT;
-               lwkt_reltoken(vlock);
-               tsleep((caddr_t)vp, 0, "vgone", 0);
-               return;
-       }
+       KKASSERT(vp->v_lock.lk_exclusivecount == 1);
 
        /*
-        * Clean out the filesystem specific data.
+        * Clean out the filesystem specific data and set the VRECLAIMED
+        * bit.  Also deactivate the vnode if necessary.
         */
-       vclean(vp, vlock, DOCLOSE, td);
-       lwkt_gettokref(vlock);
+       vclean(vp, DOCLOSE, curthread);
 
        /*
         * Delete from old mount point vnode list, if on one.
         */
        if (vp->v_mount != NULL)
-               insmntque(vp, (struct mount *)0);
+               insmntque(vp, NULL);
 
        /*
         * If special device, remove it from special device alias list
@@ -2263,29 +998,9 @@ vgonel(struct vnode *vp, lwkt_tokref_t vlock, struct thread *td)
        }
 
        /*
-        * If it is on the freelist and not already at the head,
-        * move it to the head of the list. The test of the
-        * VDOOMED flag and the reference count of zero is because
-        * it will be removed from the free list by getnewvnode,
-        * but will not have its reference count incremented until
-        * after calling vgone. If the reference count were
-        * incremented first, vgone would (incorrectly) try to
-        * close the previous instance of the underlying object.
+        * Set us to VBAD
         */
-       if (vp->v_usecount == 0 && !(vp->v_flag & VDOOMED)) {
-               s = splbio();
-               lwkt_gettoken(&ilock, &vnode_free_list_token);
-               if (vp->v_flag & VFREE)
-                       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-               else
-                       freevnodes++;
-               vp->v_flag |= VFREE;
-               TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
-               lwkt_reltoken(&ilock);
-               splx(s);
-       }
        vp->v_type = VBAD;
-       lwkt_reltoken(vlock);
 }
 
 /*
@@ -2375,14 +1090,8 @@ vprint(char *label, struct vnode *vp)
                strcat(buf, "|VTEXT");
        if (vp->v_flag & VSYSTEM)
                strcat(buf, "|VSYSTEM");
-       if (vp->v_flag & VXLOCK)
-               strcat(buf, "|VXLOCK");
-       if (vp->v_flag & VXWANT)
-               strcat(buf, "|VXWANT");
        if (vp->v_flag & VBWAIT)
                strcat(buf, "|VBWAIT");
-       if (vp->v_flag & VDOOMED)
-               strcat(buf, "|VDOOMED");
        if (vp->v_flag & VFREE)
                strcat(buf, "|VFREE");
        if (vp->v_flag & VOBJBUF)
@@ -2881,13 +1590,13 @@ vfs_export_lookup(struct mount *mp, struct netexport *nep,
  * NOTE: MNT_WAIT still skips vnodes in the VXLOCK state.
  */
 static int vfs_msync_scan1(struct mount *mp, struct vnode *vp, void *data);
-static int vfs_msync_scan2(struct mount *mp, struct vnode *vp, 
-                           lwkt_tokref_t vlock, void *data);
+static int vfs_msync_scan2(struct mount *mp, struct vnode *vp, void *data);
 
 void
 vfs_msync(struct mount *mp, int flags) 
 {
-       vmntvnodescan(mp, vfs_msync_scan1, vfs_msync_scan2, (void *)flags);
+       vmntvnodescan(mp, VMSC_REFVP, vfs_msync_scan1, vfs_msync_scan2,
+                       (void *)flags);
 }
 
 /*
@@ -2901,45 +1610,40 @@ vfs_msync_scan1(struct mount *mp, struct vnode *vp, void *data)
 {
        int flags = (int)data;
 
-       if ((vp->v_flag & VXLOCK) == 0) {
-               if (VSHOULDFREE(vp))
-                       return(0);
+       if ((vp->v_flag & VRECLAIMED) == 0) {
+               if (vshouldfree(vp, 0))
+                       return(0);      /* call scan2 */
                if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
                    (vp->v_flag & VOBJDIRTY) &&
                    (flags == MNT_WAIT || VOP_ISLOCKED(vp, NULL) == 0)) {
-                       return(0);
+                       return(0);      /* call scan2 */
                }
        }
+
+       /*
+        * do not call scan2, continue the loop
+        */
        return(-1);
 }
 
 static
 int
-vfs_msync_scan2(struct mount *mp, struct vnode *vp, 
-               lwkt_tokref_t vlock, void *data)
+vfs_msync_scan2(struct mount *mp, struct vnode *vp, void *data)
 {
        vm_object_t obj;
-       int error;
        int flags = (int)data;
 
-       if (vp->v_flag & VXLOCK)
+       if (vp->v_flag & VRECLAIMED)
                return(0);
 
        if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
            (vp->v_flag & VOBJDIRTY) &&
            (flags == MNT_WAIT || VOP_ISLOCKED(vp, NULL) == 0)) {
-               error = vget(vp, vlock, LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ | LK_INTERLOCK, curthread);
-               if (error == 0) {
-                       if (VOP_GETVOBJECT(vp, &obj) == 0) {
-                               vm_object_page_clean(obj, 0, 0, 
-                                flags == MNT_WAIT ? OBJPC_SYNC : OBJPC_NOSYNC);
-                       }
-                       vput(vp);
+               if (VOP_GETVOBJECT(vp, &obj) == 0) {
+                       vm_object_page_clean(obj, 0, 0, 
+                        flags == MNT_WAIT ? OBJPC_SYNC : OBJPC_NOSYNC);
                }
-               return(0);
        }
-       vmaybefree(vp);
-       lwkt_reltoken(vlock);
        return(0);
 }
 
@@ -2957,56 +1661,6 @@ vfs_object_create(struct vnode *vp, struct thread *td)
        return (VOP_CREATEVOBJECT(vp, td));
 }
 
-/*
- * NOTE: the vnode interlock must be held during the call.  We have to recheck
- * the VFREE flag since the vnode may have been removed from the free list
- * while we were blocked on vnode_free_list_token.  The use or hold count
- * must have already been bumped by the caller.
- */
-static void
-vbusy(struct vnode *vp)
-{
-       lwkt_tokref ilock;
-
-       lwkt_gettoken(&ilock, &vnode_free_list_token);
-       if ((vp->v_flag & VFREE) != 0) {
-           TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-           freevnodes--;
-           vp->v_flag &= ~(VFREE|VAGE);
-       }
-       lwkt_reltoken(&ilock);
-}
-
-/*
- * NOTE: the vnode interlock must be held during the call.  The use or hold
- * count must have already been bumped by the caller.  We use a VINFREE to
- * interlock against other calls to vfree() which might occur while we 
- * are blocked.  The vnode cannot be reused until it has actually been
- * placed on the free list, so there are no other races even though the
- * use and hold counts are 0.
- */
-static void
-vfree(struct vnode *vp)
-{
-       lwkt_tokref ilock;
-
-       if ((vp->v_flag & VINFREE) == 0) {
-               vp->v_flag |= VINFREE;
-               lwkt_gettoken(&ilock, &vnode_free_list_token); /* can block */
-               KASSERT((vp->v_flag & VFREE) == 0, ("vnode already free"));
-               if (vp->v_flag & VAGE) {
-                       TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
-               } else {
-                       TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
-               }
-               freevnodes++;
-               vp->v_flag &= ~(VAGE|VINFREE);
-               vp->v_flag |= VFREE;
-               lwkt_reltoken(&ilock);  /* can block */
-       }
-}
-
-
 /*
  * Record a process's interest in events which might happen to
  * a vnode.  Because poll uses the historic select-style interface
@@ -3090,187 +1744,6 @@ vn_pollgone(struct vnode *vp)
        lwkt_reltoken(&ilock);
 }
 
-
-
-/*
- * Routine to create and manage a filesystem syncer vnode.
- */
-#define sync_close ((int (*) (struct  vop_close_args *))nullop)
-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_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_stdislocked)
-
-static struct vop_ops *sync_vnode_vops;
-static struct vnodeopv_entry_desc sync_vnodeop_entries[] = {
-       { &vop_default_desc,    vop_eopnotsupp },
-       { &vop_close_desc,      (void *) sync_close },          /* close */
-       { &vop_fsync_desc,      (void *) sync_fsync },          /* fsync */
-       { &vop_inactive_desc,   (void *) sync_inactive },       /* inactive */
-       { &vop_reclaim_desc,    (void *) sync_reclaim },        /* reclaim */
-       { &vop_lock_desc,       (void *) sync_lock },           /* lock */
-       { &vop_unlock_desc,     (void *) sync_unlock },         /* unlock */
-       { &vop_print_desc,      (void *) sync_print },          /* print */
-       { &vop_islocked_desc,   (void *) sync_islocked },       /* islocked */
-       { NULL, NULL }
-};
-
-static struct vnodeopv_desc sync_vnodeop_opv_desc =
-       { &sync_vnode_vops, sync_vnodeop_entries };
-
-VNODEOP_SET(sync_vnodeop_opv_desc);
-
-/*
- * Create a new filesystem syncer vnode for the specified mount point.
- * This vnode is placed on the worklist and is responsible for sync'ing
- * the filesystem.
- *
- * NOTE: read-only mounts are also placed on the worklist.  The filesystem
- * sync code is also responsible for cleaning up vnodes.
- */
-int
-vfs_allocate_syncvnode(struct mount *mp)
-{
-       struct vnode *vp;
-       static long start, incr, next;
-       int error;
-
-       /* Allocate a new vnode */
-       error = getnewvnode(VT_VFS, mp, sync_vnode_vops, &vp, 0, 0);
-       if (error) {
-               mp->mnt_syncer = NULL;
-               return (error);
-       }
-       vp->v_type = VNON;
-       /*
-        * Place the vnode onto the syncer worklist. We attempt to
-        * scatter them about on the list so that they will go off
-        * at evenly distributed times even if all the filesystems
-        * are mounted at once.
-        */
-       next += incr;
-       if (next == 0 || next > syncer_maxdelay) {
-               start /= 2;
-               incr /= 2;
-               if (start == 0) {
-                       start = syncer_maxdelay / 2;
-                       incr = syncer_maxdelay;
-               }
-               next = start;
-       }
-       vn_syncer_add_to_worklist(vp, syncdelay > 0 ? next % syncdelay : 0);
-       mp->mnt_syncer = vp;
-       return (0);
-}
-
-/*
- * Do a lazy sync of the filesystem.
- *
- * sync_fsync { struct vnode *a_vp, struct ucred *a_cred, int a_waitfor,
- *             struct thread *a_td }
- */
-static int
-sync_fsync(struct vop_fsync_args *ap)
-{
-       struct vnode *syncvp = ap->a_vp;
-       struct mount *mp = syncvp->v_mount;
-       struct thread *td = ap->a_td;
-       lwkt_tokref ilock;
-       int asyncflag;
-
-       /*
-        * We only need to do something if this is a lazy evaluation.
-        */
-       if (ap->a_waitfor != MNT_LAZY)
-               return (0);
-
-       /*
-        * Move ourselves to the back of the sync list.
-        */
-       vn_syncer_add_to_worklist(syncvp, syncdelay);
-
-       /*
-        * Walk the list of vnodes pushing all that are dirty and
-        * not already on the sync list, and freeing vnodes which have
-        * no refs and whos VM objects are empty.  vfs_msync() handles
-        * the VM issues and must be called whether the mount is readonly
-        * or not.
-        */
-       lwkt_gettoken(&ilock, &mountlist_token);
-       if (vfs_busy(mp, LK_EXCLUSIVE | LK_NOWAIT, &ilock, td) != 0) {
-               lwkt_reltoken(&ilock);
-               return (0);
-       }
-       if (mp->mnt_flag & MNT_RDONLY) {
-               vfs_msync(mp, MNT_NOWAIT);
-       } else {
-               asyncflag = mp->mnt_flag & MNT_ASYNC;
-               mp->mnt_flag &= ~MNT_ASYNC;     /* ZZZ hack */
-               vfs_msync(mp, MNT_NOWAIT);
-               VFS_SYNC(mp, MNT_LAZY, td);
-               if (asyncflag)
-                       mp->mnt_flag |= MNT_ASYNC;
-       }
-       vfs_unbusy(mp, td);
-       return (0);
-}
-
-/*
- * The syncer vnode is no referenced.
- *
- * sync_inactive { struct vnode *a_vp, struct proc *a_p }
- */
-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);
-}
-
-/*
- * The syncer vnode is no longer needed and is being decommissioned.
- *
- * Modifications to the worklist must be protected at splbio().
- *
- *     sync_reclaim { struct vnode *a_vp }
- */
-static int
-sync_reclaim(struct vop_reclaim_args *ap)
-{
-       struct vnode *vp = ap->a_vp;
-       int s;
-
-       s = splbio();
-       vp->v_mount->mnt_syncer = NULL;
-       if (vp->v_flag & VONWORKLST) {
-               LIST_REMOVE(vp, v_synclist);
-               vp->v_flag &= ~VONWORKLST;
-       }
-       splx(s);
-
-       return (0);
-}
-
-/*
- * Print out a syncer vnode.
- *
- *     sync_print { struct vnode *a_vp }
- */
-static int
-sync_print(struct vop_print_args *ap)
-{
-       struct vnode *vp = ap->a_vp;
-
-       printf("syncer vnode");
-       lockmgr_printinfo(&vp->v_lock);
-       printf("\n");
-       return (0);
-}
-
 /*
  * extract the dev_t from a VBLK or VCHR.  The vnode must have been opened
  * (or v_rdev might be NULL).
@@ -3332,7 +1805,7 @@ NDFREE(struct nameidata *ndp, const uint flags)
        if (!(flags & NDF_NO_DVP_UNLOCK) &&
            (ndp->ni_cnd.cn_flags & CNP_LOCKPARENT) &&
            ndp->ni_dvp != ndp->ni_vp) {
-               VOP_UNLOCK(ndp->ni_dvp, NULL, 0, ndp->ni_cnd.cn_td);
+               VOP_UNLOCK(ndp->ni_dvp, 0, ndp->ni_cnd.cn_td);
        }
        if (!(flags & NDF_NO_DVP_RELE) &&
            (ndp->ni_cnd.cn_flags & (CNP_LOCKPARENT|CNP_WANTPARENT))) {
@@ -3341,7 +1814,7 @@ NDFREE(struct nameidata *ndp, const uint flags)
        }
        if (!(flags & NDF_NO_VP_UNLOCK) &&
            (ndp->ni_cnd.cn_flags & CNP_LOCKLEAF) && ndp->ni_vp) {
-               VOP_UNLOCK(ndp->ni_vp, NULL, 0, ndp->ni_cnd.cn_td);
+               VOP_UNLOCK(ndp->ni_vp, 0, ndp->ni_cnd.cn_td);
        }
        if (!(flags & NDF_NO_VP_RELE) &&
            ndp->ni_vp) {
diff --git a/sys/kern/vfs_sync.c b/sys/kern/vfs_sync.c
new file mode 100644 (file)
index 0000000..cae909b
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)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_sync.c,v 1.1 2004/10/12 19:20:46 dillon Exp $
+ */
+
+/*
+ * External virtual filesystem routines
+ */
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/dirent.h>
+#include <sys/domain.h>
+#include <sys/eventhandler.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/namei.h>
+#include <sys/reboot.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/vmmeter.h>
+#include <sys/vnode.h>
+
+#include <machine/limits.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+
+#include <sys/buf2.h>
+#include <sys/thread2.h>
+
+/*
+ * The workitem queue.
+ */
+#define SYNCER_MAXDELAY                32
+static int syncer_maxdelay = SYNCER_MAXDELAY;  /* maximum delay time */
+time_t syncdelay = 30;         /* max time to delay syncing data */
+SYSCTL_INT(_kern, OID_AUTO, syncdelay, CTLFLAG_RW,
+               &syncdelay, 0, "VFS data synchronization delay");
+time_t filedelay = 30;         /* time to delay syncing files */
+SYSCTL_INT(_kern, OID_AUTO, filedelay, CTLFLAG_RW,
+               &filedelay, 0, "File synchronization delay");
+time_t dirdelay = 29;          /* time to delay syncing directories */
+SYSCTL_INT(_kern, OID_AUTO, dirdelay, CTLFLAG_RW,
+               &dirdelay, 0, "Directory synchronization delay");
+time_t metadelay = 28;         /* time to delay syncing metadata */
+SYSCTL_INT(_kern, OID_AUTO, metadelay, CTLFLAG_RW,
+               &metadelay, 0, "VFS metadata synchronization delay");
+static int rushjob;                    /* number of slots to run ASAP */
+static int stat_rush_requests; /* number of times I/O speeded up */
+SYSCTL_INT(_debug, OID_AUTO, rush_requests, CTLFLAG_RW,
+               &stat_rush_requests, 0, "");
+
+static int syncer_delayno = 0;
+static long syncer_mask; 
+LIST_HEAD(synclist, vnode);
+static struct synclist *syncer_workitem_pending;
+
+/*
+ * Called from vfsinit()
+ */
+void
+vfs_sync_init(void)
+{
+       syncer_workitem_pending = hashinit(syncer_maxdelay, M_DEVBUF,
+                                           &syncer_mask);
+       syncer_maxdelay = syncer_mask + 1;
+}
+
+/*
+ * The workitem queue.
+ * 
+ * It is useful to delay writes of file data and filesystem metadata
+ * for tens of seconds so that quickly created and deleted files need
+ * not waste disk bandwidth being created and removed. To realize this,
+ * we append vnodes to a "workitem" queue. When running with a soft
+ * updates implementation, most pending metadata dependencies should
+ * not wait for more than a few seconds. Thus, mounted on block devices
+ * are delayed only about a half the time that file data is delayed.
+ * Similarly, directory updates are more critical, so are only delayed
+ * about a third the time that file data is delayed. Thus, there are
+ * SYNCER_MAXDELAY queues that are processed round-robin at a rate of
+ * one each second (driven off the filesystem syncer process). The
+ * syncer_delayno variable indicates the next queue that is to be processed.
+ * Items that need to be processed soon are placed in this queue:
+ *
+ *     syncer_workitem_pending[syncer_delayno]
+ *
+ * A delay of fifteen seconds is done by placing the request fifteen
+ * entries later in the queue:
+ *
+ *     syncer_workitem_pending[(syncer_delayno + 15) & syncer_mask]
+ *
+ */
+
+/*
+ * Add an item to the syncer work queue.
+ */
+void
+vn_syncer_add_to_worklist(struct vnode *vp, int delay)
+{
+       int slot;
+
+       crit_enter();
+
+       if (vp->v_flag & VONWORKLST) {
+               LIST_REMOVE(vp, v_synclist);
+       }
+
+       if (delay > syncer_maxdelay - 2)
+               delay = syncer_maxdelay - 2;
+       slot = (syncer_delayno + delay) & syncer_mask;
+
+       LIST_INSERT_HEAD(&syncer_workitem_pending[slot], vp, v_synclist);
+       vp->v_flag |= VONWORKLST;
+       crit_exit();
+}
+
+struct  thread *updatethread;
+static void sched_sync (void);
+static struct kproc_desc up_kp = {
+       "syncer",
+       sched_sync,
+       &updatethread
+};
+SYSINIT(syncer, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &up_kp)
+
+/*
+ * System filesystem synchronizer daemon.
+ */
+void 
+sched_sync(void)
+{
+       struct synclist *slp;
+       struct vnode *vp;
+       long starttime;
+       int s;
+       struct thread *td = curthread;
+
+       EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, td,
+           SHUTDOWN_PRI_LAST);   
+
+       for (;;) {
+               kproc_suspend_loop();
+
+               starttime = time_second;
+
+               /*
+                * Push files whose dirty time has expired.  Be careful
+                * of interrupt race on slp queue.
+                */
+               s = splbio();
+               slp = &syncer_workitem_pending[syncer_delayno];
+               syncer_delayno += 1;
+               if (syncer_delayno == syncer_maxdelay)
+                       syncer_delayno = 0;
+               splx(s);
+
+               while ((vp = LIST_FIRST(slp)) != NULL) {
+                       if (VOP_ISLOCKED(vp, NULL) == 0) {
+                               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+                               (void) VOP_FSYNC(vp, MNT_LAZY, td);
+                               VOP_UNLOCK(vp, 0, td);
+                       }
+                       s = splbio();
+                       if (LIST_FIRST(slp) == vp) {
+                               /*
+                                * Note: v_tag VT_VFS vps can remain on the
+                                * worklist too with no dirty blocks, but 
+                                * since sync_fsync() moves it to a different 
+                                * slot we are safe.
+                                */
+                               if (TAILQ_EMPTY(&vp->v_dirtyblkhd) &&
+                                   !vn_isdisk(vp, NULL))
+                                       panic("sched_sync: fsync failed vp %p tag %d", vp, vp->v_tag);
+                               /*
+                                * Put us back on the worklist.  The worklist
+                                * routine will remove us from our current
+                                * position and then add us back in at a later
+                                * position.
+                                */
+                               vn_syncer_add_to_worklist(vp, syncdelay);
+                       }
+                       splx(s);
+               }
+
+               /*
+                * Do soft update processing.
+                */
+               if (bioops.io_sync)
+                       (*bioops.io_sync)(NULL);
+
+               /*
+                * The variable rushjob allows the kernel to speed up the
+                * processing of the filesystem syncer process. A rushjob
+                * value of N tells the filesystem syncer to process the next
+                * N seconds worth of work on its queue ASAP. Currently rushjob
+                * is used by the soft update code to speed up the filesystem
+                * syncer process when the incore state is getting so far
+                * ahead of the disk that the kernel memory pool is being
+                * threatened with exhaustion.
+                */
+               if (rushjob > 0) {
+                       rushjob -= 1;
+                       continue;
+               }
+               /*
+                * If it has taken us less than a second to process the
+                * current work, then wait. Otherwise start right over
+                * again. We can still lose time if any single round
+                * takes more than two seconds, but it does not really
+                * matter as we are just trying to generally pace the
+                * filesystem activity.
+                */
+               if (time_second == starttime)
+                       tsleep(&lbolt, 0, "syncer", 0);
+       }
+}
+
+/*
+ * Request the syncer daemon to speed up its work.
+ * We never push it to speed up more than half of its
+ * normal turn time, otherwise it could take over the cpu.
+ *
+ * YYY wchan field protected by the BGL.
+ */
+int
+speedup_syncer(void)
+{
+       crit_enter();
+       if (updatethread->td_wchan == &lbolt) { /* YYY */
+               unsleep(updatethread);
+               lwkt_schedule(updatethread);
+       }
+       crit_exit();
+       if (rushjob < syncdelay / 2) {
+               rushjob += 1;
+               stat_rush_requests += 1;
+               return (1);
+       }
+       return(0);
+}
+
+/*
+ * Routine to create and manage a filesystem syncer vnode.
+ */
+#define sync_close ((int (*) (struct  vop_close_args *))nullop)
+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_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_stdislocked)
+
+static struct vop_ops *sync_vnode_vops;
+static struct vnodeopv_entry_desc sync_vnodeop_entries[] = {
+       { &vop_default_desc,    vop_eopnotsupp },
+       { &vop_close_desc,      (void *) sync_close },          /* close */
+       { &vop_fsync_desc,      (void *) sync_fsync },          /* fsync */
+       { &vop_inactive_desc,   (void *) sync_inactive },       /* inactive */
+       { &vop_reclaim_desc,    (void *) sync_reclaim },        /* reclaim */
+       { &vop_lock_desc,       (void *) sync_lock },           /* lock */
+       { &vop_unlock_desc,     (void *) sync_unlock },         /* unlock */
+       { &vop_print_desc,      (void *) sync_print },          /* print */
+       { &vop_islocked_desc,   (void *) sync_islocked },       /* islocked */
+       { NULL, NULL }
+};
+
+static struct vnodeopv_desc sync_vnodeop_opv_desc =
+       { &sync_vnode_vops, sync_vnodeop_entries };
+
+VNODEOP_SET(sync_vnodeop_opv_desc);
+
+/*
+ * Create a new filesystem syncer vnode for the specified mount point.
+ * This vnode is placed on the worklist and is responsible for sync'ing
+ * the filesystem.
+ *
+ * NOTE: read-only mounts are also placed on the worklist.  The filesystem
+ * sync code is also responsible for cleaning up vnodes.
+ */
+int
+vfs_allocate_syncvnode(struct mount *mp)
+{
+       struct vnode *vp;
+       static long start, incr, next;
+       int error;
+
+       /* Allocate a new vnode */
+       error = getnewvnode(VT_VFS, mp, sync_vnode_vops, &vp, 0, 0);
+       if (error) {
+               mp->mnt_syncer = NULL;
+               return (error);
+       }
+       vp->v_type = VNON;
+       /*
+        * Place the vnode onto the syncer worklist. We attempt to
+        * scatter them about on the list so that they will go off
+        * at evenly distributed times even if all the filesystems
+        * are mounted at once.
+        */
+       next += incr;
+       if (next == 0 || next > syncer_maxdelay) {
+               start /= 2;
+               incr /= 2;
+               if (start == 0) {
+                       start = syncer_maxdelay / 2;
+                       incr = syncer_maxdelay;
+               }
+               next = start;
+       }
+       vn_syncer_add_to_worklist(vp, syncdelay > 0 ? next % syncdelay : 0);
+       mp->mnt_syncer = vp;
+       vx_unlock(vp);
+       return (0);
+}
+
+/*
+ * Do a lazy sync of the filesystem.
+ *
+ * sync_fsync { struct vnode *a_vp, struct ucred *a_cred, int a_waitfor,
+ *             struct thread *a_td }
+ */
+static int
+sync_fsync(struct vop_fsync_args *ap)
+{
+       struct vnode *syncvp = ap->a_vp;
+       struct mount *mp = syncvp->v_mount;
+       struct thread *td = ap->a_td;
+       lwkt_tokref ilock;
+       int asyncflag;
+
+       /*
+        * We only need to do something if this is a lazy evaluation.
+        */
+       if (ap->a_waitfor != MNT_LAZY)
+               return (0);
+
+       /*
+        * Move ourselves to the back of the sync list.
+        */
+       vn_syncer_add_to_worklist(syncvp, syncdelay);
+
+       /*
+        * Walk the list of vnodes pushing all that are dirty and
+        * not already on the sync list, and freeing vnodes which have
+        * no refs and whos VM objects are empty.  vfs_msync() handles
+        * the VM issues and must be called whether the mount is readonly
+        * or not.
+        */
+       lwkt_gettoken(&ilock, &mountlist_token);
+       if (vfs_busy(mp, LK_EXCLUSIVE | LK_NOWAIT, &ilock, td) != 0) {
+               lwkt_reltoken(&ilock);
+               return (0);
+       }
+       if (mp->mnt_flag & MNT_RDONLY) {
+               vfs_msync(mp, MNT_NOWAIT);
+       } else {
+               asyncflag = mp->mnt_flag & MNT_ASYNC;
+               mp->mnt_flag &= ~MNT_ASYNC;     /* ZZZ hack */
+               vfs_msync(mp, MNT_NOWAIT);
+               VFS_SYNC(mp, MNT_LAZY, td);
+               if (asyncflag)
+                       mp->mnt_flag |= MNT_ASYNC;
+       }
+       vfs_unbusy(mp, td);
+       return (0);
+}
+
+/*
+ * The syncer vnode is no referenced.
+ *
+ * sync_inactive { struct vnode *a_vp, struct proc *a_p }
+ */
+static int
+sync_inactive(struct vop_inactive_args *ap)
+{
+       vgone(ap->a_vp);
+       return (0);
+}
+
+/*
+ * The syncer vnode is no longer needed and is being decommissioned.
+ *
+ * Modifications to the worklist must be protected at splbio().
+ *
+ *     sync_reclaim { struct vnode *a_vp }
+ */
+static int
+sync_reclaim(struct vop_reclaim_args *ap)
+{
+       struct vnode *vp = ap->a_vp;
+       int s;
+
+       s = splbio();
+       vp->v_mount->mnt_syncer = NULL;
+       if (vp->v_flag & VONWORKLST) {
+               LIST_REMOVE(vp, v_synclist);
+               vp->v_flag &= ~VONWORKLST;
+       }
+       splx(s);
+
+       return (0);
+}
+
+/*
+ * Print out a syncer vnode.
+ *
+ *     sync_print { struct vnode *a_vp }
+ */
+static int
+sync_print(struct vop_print_args *ap)
+{
+       struct vnode *vp = ap->a_vp;
+
+       printf("syncer vnode");
+       lockmgr_printinfo(&vp->v_lock);
+       printf("\n");
+       return (0);
+}
+
index 2712bc1..6737631 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_syscalls.c      8.13 (Berkeley) 4/15/94
  * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $
- * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.44 2004/10/07 04:20:26 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.45 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -111,7 +111,6 @@ mount(struct mount_args *uap)
        struct vattr va;
        struct nlookupdata nd;
        char fstypename[MFSNAMELEN];
-       lwkt_tokref vlock;
        lwkt_tokref ilock;
        struct nlcomponent nlc;
 
@@ -160,7 +159,7 @@ mount(struct mount_args *uap)
         * now we have the locked ref'd ncp and unreferenced vnode.
         */
        vp = ncp->nc_vp;
-       if ((error = vget(vp, NULL, LK_EXCLUSIVE, td)) != 0) {
+       if ((error = vget(vp, LK_EXCLUSIVE, td)) != 0) {
                cache_put(ncp);
                return (error);
        }
@@ -203,20 +202,17 @@ mount(struct mount_args *uap)
                        vput(vp);
                        return (EBUSY);
                }
-               lwkt_gettoken(&vlock, vp->v_interlock);
                if ((vp->v_flag & VMOUNT) != 0 ||
                    vp->v_mountedhere != NULL) {
                        cache_drop(ncp);
-                       lwkt_reltoken(&vlock);
                        vfs_unbusy(mp, td);
                        vput(vp);
                        return (EBUSY);
                }
                vp->v_flag |= VMOUNT;
-               lwkt_reltoken(&vlock);
                mp->mnt_flag |=
                    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
                goto update;
        }
        /*
@@ -280,16 +276,13 @@ mount(struct mount_args *uap)
                        return (ENODEV);
                }
        }
-       lwkt_gettoken(&vlock, vp->v_interlock);
        if ((vp->v_flag & VMOUNT) != 0 ||
            vp->v_mountedhere != NULL) {
-               lwkt_reltoken(&vlock);
                cache_drop(ncp);
                vput(vp);
                return (EBUSY);
        }
        vp->v_flag |= VMOUNT;
-       lwkt_reltoken(&vlock);
 
        /*
         * Allocate and initialize the filesystem.
@@ -309,7 +302,7 @@ mount(struct mount_args *uap)
        mp->mnt_vnodecovered = vp;
        mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
        mp->mnt_iosize_max = DFLTPHYS;
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
 update:
        /*
         * Set the mount level flags.
@@ -342,14 +335,12 @@ update:
                        mp->mnt_kern_flag = flag2;
                }
                vfs_unbusy(mp, td);
-               lwkt_gettoken(&vlock, vp->v_interlock);
                vp->v_flag &= ~VMOUNT;
-               lwkt_reltoken(&vlock);
                vrele(vp);
                cache_drop(ncp);
                return (error);
        }
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        /*
         * Put the new filesystem on the mount list after root.  The mount
         * point gets its own mnt_ncp which is a special ncp linking the
@@ -369,16 +360,14 @@ update:
                mp->mnt_ncp->nc_mount = mp;
                cache_drop(ncp);
                /* XXX get the root of the fs and cache_setvp(mnt_ncp...) */
-               lwkt_gettoken(&vlock, vp->v_interlock);
                vp->v_flag &= ~VMOUNT;
                vp->v_mountedhere = mp;
-               lwkt_reltoken(&vlock);
                lwkt_gettoken(&ilock, &mountlist_token);
                TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
                lwkt_reltoken(&ilock);
                checkdirs(vp, mp->mnt_ncp);
                cache_unlock(mp->mnt_ncp);      /* leave ref intact */
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
                error = vfs_allocate_syncvnode(mp);
                vfs_unbusy(mp, td);
                if ((error = VFS_START(mp, 0, td)) != 0)
@@ -387,9 +376,7 @@ update:
                vfs_rm_vnodeops(&mp->mnt_vn_ops);
                vfs_rm_vnodeops(&mp->mnt_vn_spec_ops);
                vfs_rm_vnodeops(&mp->mnt_vn_fifo_ops);
-               lwkt_gettoken(&vlock, vp->v_interlock);
                vp->v_flag &= ~VMOUNT;
-               lwkt_reltoken(&vlock);
                mp->mnt_vfc->vfc_refcount--;
                vfs_unbusy(mp, td);
                free(mp, M_MOUNT);
@@ -851,7 +838,7 @@ fchdir(struct fchdir_args *uap)
                return (error);
        vp = (struct vnode *)fp->f_data;
        vref(vp);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        if (vp->v_type != VDIR || fp->f_ncp == NULL)
                error = ENOTDIR;
        else
@@ -867,7 +854,7 @@ fchdir(struct fchdir_args *uap)
                        cache_unlock(nct);      /* leave ref intact */
                        vput(vp);
                        vp = nct->nc_vp;
-                       error = vget(vp, NULL, LK_SHARED, td);
+                       error = vget(vp, LK_SHARED, td);
                        KKASSERT(error == 0);
                        cache_drop(ncp);
                        ncp = nct;
@@ -876,7 +863,7 @@ fchdir(struct fchdir_args *uap)
        if (error == 0) {
                ovp = fdp->fd_cdir;
                oncp = fdp->fd_ncdir;
-               VOP_UNLOCK(vp, NULL, 0, td);    /* leave ref intact */
+               VOP_UNLOCK(vp, 0, td);  /* leave ref intact */
                fdp->fd_cdir = vp;
                fdp->fd_ncdir = ncp;
                cache_drop(oncp);
@@ -902,11 +889,11 @@ kern_chdir(struct nlookupdata *nd)
                return (error);
        if ((vp = nd->nl_ncp->nc_vp) == NULL)
                return (ENOENT);
-       if ((error = vget(vp, NULL, LK_SHARED, td)) != 0)
+       if ((error = vget(vp, LK_SHARED, td)) != 0)
                return (error);
 
        error = checkvp_chdir(vp, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        if (error == 0) {
                ovp = fdp->fd_cdir;
                oncp = fdp->fd_ncdir;
@@ -1015,7 +1002,7 @@ kern_chroot(struct nlookupdata *nd)
        if ((vp = ncp->nc_vp) == NULL)
                return (ENOENT);
 
-       if ((error = vget(vp, NULL, LK_SHARED, td)) != 0)
+       if ((error = vget(vp, LK_SHARED, td)) != 0)
                return (error);
 
        /*
@@ -1023,7 +1010,7 @@ kern_chroot(struct nlookupdata *nd)
         * associate it with rdir/jdir.
         */
        error = checkvp_chdir(vp, td);
-       VOP_UNLOCK(vp, NULL, 0, td);    /* leave reference intact */
+       VOP_UNLOCK(vp, 0, td);  /* leave reference intact */
        if (error == 0) {
                vrele(fdp->fd_rdir);
                fdp->fd_rdir = vp;      /* reference inherited by fd_rdir */
@@ -1165,7 +1152,7 @@ kern_open(struct nameidata *nd, int oflags, int mode, int *res)
        if (fp->f_count == 1) {
                KASSERT(fdp->fd_ofiles[indx] != fp,
                    ("Open file descriptor lost all refs"));
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
                vn_close(vp, flags & FMASK, td);
                fdrop(fp, td);
                *res = indx;
@@ -1188,7 +1175,7 @@ kern_open(struct nameidata *nd, int oflags, int mode, int *res)
                type = F_FLOCK;
                if ((flags & FNONBLOCK) == 0)
                        type |= F_WAIT;
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
                if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
                        /*
                         * lock request failed.  Normally close the descriptor
@@ -1204,13 +1191,13 @@ kern_open(struct nameidata *nd, int oflags, int mode, int *res)
                        nlookup_done(&ndx);
                        return (error);
                }
-               vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
                fp->f_flag |= FHASLOCK;
        }
        /* assert that vn_open created a backing object if one is needed */
        KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
                ("open: vmio vnode has no backing object after vn_open"));
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
 
        /*
         * If the vp is a directory locate the ncp to store with the file
@@ -1597,7 +1584,7 @@ kern_unlink(struct nameidata *nd)
                return (error);
        vp = nd->ni_vp;
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 
        if (vp->v_type == VDIR)
                error = EPERM;          /* POSIX */
@@ -1778,7 +1765,7 @@ kern_stat(struct nlookupdata *nd, struct stat *st)
                return (ENOENT);
 
        td = curthread;
-       if ((error = vget(vp, NULL, LK_SHARED, td)) != 0)
+       if ((error = vget(vp, LK_SHARED, td)) != 0)
                return (error);
        error = vn_stat(vp, st, td);
        vput(vp);
@@ -2013,11 +2000,11 @@ setfflags(struct vnode *vp, int flags)
                return (error);
 
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        VATTR_NULL(&vattr);
        vattr.va_flags = flags;
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return (error);
 }
 
@@ -2072,11 +2059,11 @@ setfmode(struct vnode *vp, int mode)
        struct vattr vattr;
 
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        VATTR_NULL(&vattr);
        vattr.va_mode = mode & ALLPERMS;
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return error;
 }
 
@@ -2164,12 +2151,12 @@ setfown(struct vnode *vp, uid_t uid, gid_t gid)
        struct vattr vattr;
 
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        VATTR_NULL(&vattr);
        vattr.va_uid = uid;
        vattr.va_gid = gid;
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return error;
 }
 
@@ -2270,14 +2257,14 @@ setutimes(struct vnode *vp, const struct timespec *ts, int nullflag)
        struct vattr vattr;
 
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        VATTR_NULL(&vattr);
        vattr.va_atime = ts[0];
        vattr.va_mtime = ts[1];
        if (nullflag)
                vattr.va_vaflags |= VA_UTIMES_NULL;
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return error;
 }
 
@@ -2406,7 +2393,7 @@ kern_truncate(struct nameidata* nd, off_t length)
        vp = nd->ni_vp;
        NDFREE(nd, NDF_ONLY_PNBUF);
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        if (vp->v_type == VDIR)
                error = EISDIR;
        else if ((error = vn_writechk(vp)) == 0 &&
@@ -2456,7 +2443,7 @@ kern_ftruncate(int fd, off_t length)
                return (EINVAL);
        vp = (struct vnode *)fp->f_data;
        VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        if (vp->v_type == VDIR)
                error = EISDIR;
        else if ((error = vn_writechk(vp)) == 0) {
@@ -2464,7 +2451,7 @@ kern_ftruncate(int fd, off_t length)
                vattr.va_size = length;
                error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
        }
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return (error);
 }
 
@@ -2502,14 +2489,14 @@ fsync(struct fsync_args *uap)
        if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
                return (error);
        vp = (struct vnode *)fp->f_data;
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        if (VOP_GETVOBJECT(vp, &obj) == 0)
                vm_object_page_clean(obj, 0, 0, 0);
        if ((error = VOP_FSYNC(vp, MNT_WAIT, td)) == 0 &&
            vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP) &&
            bioops.io_fsync)
                error = (*bioops.io_fsync)(vp);
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return (error);
 }
 
@@ -2782,12 +2769,12 @@ unionread:
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_td = td;
        auio.uio_resid = count;
-       /* vn_lock(vp, NULL, LK_SHARED | LK_RETRY, td); */
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        loff = auio.uio_offset = fp->f_offset;
        error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
        fp->f_offset = auio.uio_offset;
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        if (error)
                return (error);
        if (count == auio.uio_resid) {
@@ -2900,8 +2887,12 @@ revoke(struct revoke_args *uap)
        if (p->p_ucred->cr_uid != vattr.va_uid &&
            (error = suser_cred(p->p_ucred, PRISON_ROOT)))
                goto out;
-       if (count_udev(vp->v_udev) > 0)
-               VOP_REVOKE(vp, REVOKEALL);
+       if (count_udev(vp->v_udev) > 0) {
+               if ((error = vx_lock(vp)) == 0) {
+                       VOP_REVOKE(vp, REVOKEALL);
+                       vx_unlock(vp);
+               }
+       }
 out:
        vrele(vp);
        return (error);
@@ -3044,9 +3035,9 @@ fhopen(struct fhopen_args *uap)
                        goto bad;
        }
        if (fmode & O_TRUNC) {
-               VOP_UNLOCK(vp, NULL, 0, td);                    /* XXX */
+               VOP_UNLOCK(vp, 0, td);                  /* XXX */
                VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
-               vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
+               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);       /* XXX */
                VATTR_NULL(vap);
                vap->va_size = 0;
                error = VOP_SETATTR(vp, vap, p->p_ucred, td);
@@ -3097,7 +3088,7 @@ fhopen(struct fhopen_args *uap)
                type = F_FLOCK;
                if ((fmode & FNONBLOCK) == 0)
                        type |= F_WAIT;
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
                if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
                        /*
                         * lock request failed.  Normally close the descriptor
@@ -3115,13 +3106,13 @@ fhopen(struct fhopen_args *uap)
                        fdrop(fp, td);
                        return (error);
                }
-               vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
                fp->f_flag |= FHASLOCK;
        }
        if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
                vfs_object_create(vp, td);
 
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        fdrop(fp, td);
        uap->sysmsg_result = indx;
        return (0);
index f18d035..a6f76aa 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/vfs_vnops.c,v 1.87.2.13 2002/12/29 18:19:53 dillon Exp $
- * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.22 2004/06/15 00:30:53 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.23 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -174,9 +174,9 @@ vn_open(ndp, fmode, cmode)
                }
        }
        if (fmode & O_TRUNC) {
-               VOP_UNLOCK(vp, NULL, 0, td);                    /* XXX */
+               VOP_UNLOCK(vp, 0, td);                  /* XXX */
                VOP_LEASE(vp, td, cred, LEASE_WRITE);
-               vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
+               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);       /* XXX */
                VATTR_NULL(vap);
                vap->va_size = 0;
                error = VOP_SETATTR(vp, vap, cred, td);
@@ -232,7 +232,10 @@ vn_close(struct vnode *vp, int flags, struct thread *td)
 
        if (flags & FWRITE)
                vp->v_writecount--;
-       error = VOP_CLOSE(vp, flags, td);
+       if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td)) == 0) {
+               error = VOP_CLOSE(vp, flags, td);
+               VOP_UNLOCK(vp, 0, td);
+       }
        vrele(vp);
        return (error);
 }
@@ -294,7 +297,7 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, td)
        int error;
 
        if ((ioflg & IO_NODELOCKED) == 0)
-               vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        auio.uio_iov = &aiov;
        auio.uio_iovcnt = 1;
        aiov.iov_base = base;
@@ -315,7 +318,7 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, td)
                if (auio.uio_resid && error == 0)
                        error = EIO;
        if ((ioflg & IO_NODELOCKED) == 0)
-               VOP_UNLOCK(vp, NULL, 0, td);
+               VOP_UNLOCK(vp, 0, td);
        return (error);
 }
 
@@ -393,7 +396,7 @@ vn_read(fp, uio, cred, flags, td)
        if (fp->f_flag & O_DIRECT)
                ioflag |= IO_DIRECT;
        VOP_LEASE(vp, td, cred, LEASE_READ);
-       vn_lock(vp, NULL, LK_SHARED | LK_NOPAUSE | LK_RETRY, td);
+       vn_lock(vp, LK_SHARED | LK_NOPAUSE | LK_RETRY, td);
        if ((flags & FOF_OFFSET) == 0)
                uio->uio_offset = fp->f_offset;
 
@@ -403,7 +406,7 @@ vn_read(fp, uio, cred, flags, td)
        if ((flags & FOF_OFFSET) == 0)
                fp->f_offset = uio->uio_offset;
        fp->f_nextoff = uio->uio_offset;
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return (error);
 }
 
@@ -438,7 +441,7 @@ vn_write(fp, uio, cred, flags, td)
            (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
                ioflag |= IO_SYNC;
        VOP_LEASE(vp, td, cred, LEASE_WRITE);
-       vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
        if ((flags & FOF_OFFSET) == 0)
                uio->uio_offset = fp->f_offset;
        ioflag |= sequential_heuristic(uio, fp);
@@ -446,7 +449,7 @@ vn_write(fp, uio, cred, flags, td)
        if ((flags & FOF_OFFSET) == 0)
                fp->f_offset = uio->uio_offset;
        fp->f_nextoff = uio->uio_offset;
-       VOP_UNLOCK(vp, NULL, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        return (error);
 }
 
@@ -649,42 +652,33 @@ vn_poll(struct file *fp, int events, struct ucred *cred, struct thread *td)
  */
 int
 #ifndef        DEBUG_LOCKS
-vn_lock(struct vnode *vp, lwkt_tokref_t vlock, int flags, struct thread *td)
+vn_lock(struct vnode *vp, int flags, struct thread *td)
 #else
-debug_vn_lock(struct vnode *vp, lwkt_tokref_t vlock, int flags, 
-               struct thread *td, const char *filename, int line)
+debug_vn_lock(struct vnode *vp, int flags, struct thread *td,
+               const char *filename, int line)
 #endif
 {
        int error;
-       lwkt_tokref vvlock;
        
        do {
-               if ((flags & LK_INTERLOCK) == 0) {
-                       lwkt_gettoken(&vvlock, vp->v_interlock);
-                       vlock = &vvlock;
-               }
-               if ((vp->v_flag & VXLOCK) && vp->v_vxthread != curthread) {
-                       vp->v_flag |= VXWANT;
-                       lwkt_reltoken(vlock);
-                       tsleep((caddr_t)vp, 0, "vn_lock", 0);
-                       error = ENOENT;
-               } else {
-#if 0
-                       /* this can now occur in normal operation */
-                       if (vp->v_vxthread != NULL)
-                               log(LOG_INFO, "VXLOCK interlock avoided in vn_lock\n");
-#endif
 #ifdef DEBUG_LOCKS
-                       vp->filename = filename;
-                       vp->line = line;
+               vp->filename = filename;
+               vp->line = line;
 #endif
-                       error = VOP_LOCK(vp, vlock,
-                                   flags | LK_NOPAUSE | LK_INTERLOCK, td);
-                       if (error == 0)
-                               return (0);
-               }
-               flags &= ~LK_INTERLOCK;
+               error = VOP_LOCK(vp, flags | LK_NOPAUSE, td);
+               if (error == 0)
+                       break;
        } while (flags & LK_RETRY);
+
+       /*
+        * Because we (had better!) have a ref on the vnode, once it
+        * goes to VRECLAIMED state it will not be recycled until all
+        * refs go away.  So we can just check the flag.
+        */
+       if (error == 0 && (vp->v_flag & VRECLAIMED)) {
+               VOP_UNLOCK(vp, 0, td);
+               error = ENOENT;
+       }
        return (error);
 }
 
index 7070c85..d6b4d6f 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.8 2004/09/30 18:59:48 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.9 2004/10/12 19:20:46 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -841,8 +841,7 @@ vop_reclaim(struct vop_ops *ops, struct vnode *vp, struct thread *td)
 }
 
 int
-vop_lock(struct vop_ops *ops, struct vnode *vp, struct lwkt_tokref *vlock,
-       int flags, struct thread *td)
+vop_lock(struct vop_ops *ops, struct vnode *vp, int flags, struct thread *td)
 {
        struct vop_lock_args ap;
        int error;
@@ -850,7 +849,6 @@ vop_lock(struct vop_ops *ops, struct vnode *vp, struct lwkt_tokref *vlock,
        ap.a_head.a_desc = &vop_lock_desc;
        ap.a_head.a_ops = ops;
        ap.a_vp = vp;
-       ap.a_vlock = vlock;
        ap.a_flags = flags;
        ap.a_td = td;
 
@@ -859,8 +857,7 @@ vop_lock(struct vop_ops *ops, struct vnode *vp, struct lwkt_tokref *vlock,
 }
 
 int
-vop_unlock(struct vop_ops *ops, struct vnode *vp, struct lwkt_tokref *vlock,
-       int flags, struct thread *td)
+vop_unlock(struct vop_ops *ops, struct vnode *vp, int flags, struct thread *td)
 {
        struct vop_unlock_args ap;
        int error;
@@ -868,7 +865,6 @@ vop_unlock(struct vop_ops *ops, struct vnode *vp, struct lwkt_tokref *vlock,
        ap.a_head.a_desc = &vop_unlock_desc;
        ap.a_head.a_ops = ops;
        ap.a_vp = vp;
-       ap.a_vlock = vlock;
        ap.a_flags = flags;
        ap.a_td = td;
 
index 2759fc2..0f94fbb 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.12 2004/10/05 03:24:21 dillon Exp $
+ * $DragonFly: src/sys/sys/namecache.h,v 1.13 2004/10/12 19:20:48 dillon Exp $
  */
 
 #ifndef _SYS_NAMECACHE_H_
@@ -155,7 +155,7 @@ int cache_lookup(struct vnode *dvp, struct vnode **vpp,
 void   cache_enter(struct vnode *dvp, struct vnode *vp,
                        struct componentname *cnp);
 struct namecache *cache_nlookup(struct namecache *par, struct nlcomponent *nlc);
-struct namecache *cache_allocroot(struct vnode *vp);
+struct namecache *cache_allocroot(struct mount *mp, struct vnode *vp);
 void   cache_inval(struct namecache *ncp, int flags);
 void   cache_inval_vp(struct vnode *vp, int flags);
 void   vfs_cache_setroot(struct vnode *vp, struct namecache *ncp);
@@ -163,11 +163,11 @@ void      vfs_cache_setroot(struct vnode *vp, struct namecache *ncp);
 int    cache_resolve(struct namecache *ncp, struct ucred *cred);
 void   cache_purge(struct vnode *vp);
 void   cache_purgevfs (struct mount *mp);
+int    cache_get_nonblock(struct namecache *ncp);
 struct namecache *cache_get(struct namecache *ncp);
 struct namecache *cache_hold(struct namecache *ncp);
 void   cache_put(struct namecache *ncp);
 void   cache_drop(struct namecache *ncp);
-int    cache_leaf_test (struct vnode *vp);
 int    vfs_cache_lookup(struct vop_lookup_args *ap);
 int    cache_vget(struct namecache *, struct ucred *, int, struct vnode **);
 int    cache_vref(struct namecache *, struct ucred *, struct vnode **);
index 53fc719..9dcb8fb 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)systm.h     8.7 (Berkeley) 3/29/95
  * $FreeBSD: src/sys/sys/systm.h,v 1.111.2.18 2002/12/17 18:04:02 sam Exp $
- * $DragonFly: src/sys/sys/systm.h,v 1.23 2004/09/30 18:59:50 dillon Exp $
+ * $DragonFly: src/sys/sys/systm.h,v 1.24 2004/10/12 19:20:48 dillon Exp $
  */
 
 #ifndef _SYS_SYSTM_H_
@@ -217,7 +217,6 @@ void        consinit (void);
 void   cpu_initclocks (void);
 void   nchinit (void);
 void   usrinfoinit (void);
-void   vntblinit (void);
 
 /* Finalize the world. */
 void   shutdown_nice (int);
index c55c12e..1ff1c85 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)tty.h       8.6 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/sys/tty.h,v 1.53.2.1 2001/02/26 04:23:21 jlemon Exp $
- * $DragonFly: src/sys/sys/tty.h,v 1.6 2004/09/13 16:22:41 dillon Exp $
+ * $DragonFly: src/sys/sys/tty.h,v 1.7 2004/10/12 19:20:48 dillon Exp $
  */
 
 #ifndef _SYS_TTY_H_
@@ -253,6 +253,7 @@ void         ttychars (struct tty *tp);
 int     ttycheckoutq (struct tty *tp, int wait);
 int     ttyclose (struct tty *tp);
 void    ttyclearsession (struct tty *tp);
+void    ttyclosesession (struct session *, int);
 void    ttyflush (struct tty *tp, int rw);
 void    ttyfree (struct tty *tp);
 void    ttyinfo (struct tty *tp);
index 62243dd..1996b4d 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/sys/vfsops.h,v 1.7 2004/09/30 18:59:50 dillon Exp $
+ * $DragonFly: src/sys/sys/vfsops.h,v 1.8 2004/10/12 19:20:48 dillon Exp $
  */
 
 /*
@@ -339,7 +339,6 @@ struct vop_reclaim_args {
 struct vop_lock_args {
        struct vop_generic_args a_head;
        struct vnode *a_vp;
-       struct lwkt_tokref *a_vlock;
        int a_flags;
        struct thread *a_td;
 };
@@ -347,7 +346,6 @@ struct vop_lock_args {
 struct vop_unlock_args {
        struct vop_generic_args a_head;
        struct vnode *a_vp;
-       struct lwkt_tokref *a_vlock;
        int a_flags;
        struct thread *a_td;
 };
@@ -744,9 +742,9 @@ int vop_readlink(struct vop_ops *ops, struct vnode *vp, struct uio *uio,
 int vop_inactive(struct vop_ops *ops, struct vnode *vp, struct thread *td);
 int vop_reclaim(struct vop_ops *ops, struct vnode *vp, struct thread *td);
 int vop_lock(struct vop_ops *ops, struct vnode *vp,
-               struct lwkt_tokref *vlock, int flags, struct thread *td);
+               int flags, struct thread *td);
 int vop_unlock(struct vop_ops *ops, struct vnode *vp,
-               struct lwkt_tokref *vlock, int flags, struct thread *td);
+               int flags, struct thread *td);
 int vop_bmap(struct vop_ops *ops, struct vnode *vp, daddr_t bn,
                struct vnode **vpp, daddr_t *bnp, int *runp, int *runb);
 int vop_strategy(struct vop_ops *ops, struct vnode *vp, struct buf *bp);
@@ -979,10 +977,10 @@ extern struct vnodeop_desc vop_vfsset_desc;
        vop_inactive((vp)->v_ops, vp, td)
 #define VOP_RECLAIM(vp, td)                            \
        vop_reclaim((vp)->v_ops, vp, td)
-#define VOP_LOCK(vp, vlock, flags, td)                 \
-       vop_lock((vp)->v_ops, vp, vlock, flags, td)
-#define VOP_UNLOCK(vp, vlock, flags, td)               \
-       vop_unlock((vp)->v_ops, vp, vlock, flags, td)
+#define VOP_LOCK(vp, flags, td)                                \
+       vop_lock((vp)->v_ops, vp, flags, td)
+#define VOP_UNLOCK(vp, flags, td)                      \
+       vop_unlock((vp)->v_ops, vp, flags, td)
 #define VOP_BMAP(vp, bn, vpp, bnp, runp, runb)         \
        vop_bmap((vp)->v_ops, vp, bn, vpp, bnp, runp, runb)
 #define VOP_STRATEGY(vp, bp)                           \
index d5e6afc..7ab06a2 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.24 2004/10/07 01:13:20 dillon Exp $
+ * $DragonFly: src/sys/sys/vnode.h,v 1.25 2004/10/12 19:20:48 dillon Exp $
  */
 
 #ifndef _SYS_VNODE_H_
@@ -116,7 +116,6 @@ struct vnode {
        daddr_t v_lasta;                        /* last allocation */
        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_lock;                    /* file/dir ops lock */
        enum    vtagtype v_tag;                 /* type of underlying data */
        void    *v_data;                        /* private data for fs */
@@ -127,12 +126,12 @@ struct vnode {
                short   vpi_events;             /* what they are looking for */
                short   vpi_revents;            /* what has happened */
        } v_pollinfo;
-       struct thread   *v_vxthread;            /* thread owning VXLOCK */
        struct vmresident *v_resident;          /* optional vmresident */
 #ifdef DEBUG_LOCKS
        const char *filename;                   /* Source file doing locking */
        int line;                               /* Line number doing locking */
 #endif
+       void    *v_xaddr;
 };
 #define        v_mountedhere   v_un.vu_mountedhere
 #define        v_socket        v_un.vu_socket
@@ -154,24 +153,36 @@ struct vnode {
 #define        VTEXT           0x00002 /* vnode is a pure text prototype */
 #define        VSYSTEM         0x00004 /* vnode being used by kernel */
 #define        VISTTY          0x00008 /* vnode represents a tty */
-#define        VXLOCK          0x00100 /* vnode is locked to change underlying type */
-#define        VXWANT          0x00200 /* process is waiting for vnode */
+#define VCTTYISOPEN    0x00010 /* controlling terminal tty is open */
+/* open for business    0x00020 */
+/* open for business    0x00040 */
+/* open for business    0x00080 */
+/* open for business    0x00100 */
+/* open for business    0x00200 */
 #define        VBWAIT          0x00400 /* waiting for output to complete */
 /* open for business    0x00800 */
 /* open for business    0x01000 */
 #define        VOBJBUF         0x02000 /* Allocate buffers in VM object */
-/* open for business    0x04000 */
+#define        VINACTIVE       0x04000 /* The vnode is inactive */
 #define        VAGE            0x08000 /* Insert vnode at head of free list */
 #define        VOLOCK          0x10000 /* vnode is locked waiting for an object */
 #define        VOWANT          0x20000 /* a process is waiting for VOLOCK */
-#define        VDOOMED         0x40000 /* This vnode is being recycled */
+#define        VRECLAIMED      0x40000 /* This vnode has been destroyed */
 #define        VFREE           0x80000 /* This vnode is on the freelist */
-#define        VINFREE         0x100000 /* This vnode is in the midst of being freed */
+/* open for business    0x100000 */
 #define        VONWORKLST      0x200000 /* On syncer work-list */
 #define        VMOUNT          0x400000 /* Mount in progress */
 #define        VOBJDIRTY       0x800000 /* object might be dirty */
 #define        VPLACEMARKER    0x1000000 /* dummy vnode placemarker */
 
+/*
+ * vmntvnodescan() flags
+ */
+#define VMSC_GETVP     1
+#define VMSC_GETVX     2
+#define VMSC_REFVP     3
+#define VMSC_NOWAIT    0x10
+
 /*
  * Flags for ioflag. (high 16 bits used to ask for read-ahead and
  * help with write clustering)
@@ -220,10 +231,6 @@ struct vnode {
 
 #ifdef _KERNEL
 
-#ifdef MALLOC_DECLARE
-MALLOC_DECLARE(M_VNODE);
-#endif
-
 /*
  * Convert between vnode types and inode formats (since POSIX.1
  * defines mode word of stat structure in terms of inode formats).
@@ -270,6 +277,8 @@ extern      struct vm_zone *namei_zone;
 extern int prtactive;                  /* nonzero to call vprint() */
 extern struct vattr va_null;           /* predefined null vattr structure */
 extern int vfs_ioopt;
+extern int numvnodes;
+extern int freevnodes;
 
 /*
  * Macro/function to check for client cache inconsistency w.r.t. leasing.
@@ -280,9 +289,6 @@ extern      int vfs_ioopt;
 
 extern void    (*lease_updatetime) (int deltat);
 
-#define        VI_LOCK(vlock, vp)      lwkt_gettoken(vlock, (vp)->v_interlock)
-#define        VI_UNLOCK(vlock, vp)    lwkt_reltoken(vlock)
-
 #endif /* _KERNEL */
 
 /*
@@ -510,6 +516,9 @@ 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);
+struct vnode *allocvnode(int lktimeout, int lkflags);
+struct vnode *allocvnode_placemarker(void);
+void freevnode_placemarker(struct vnode *);
 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);
@@ -517,36 +526,33 @@ int       spec_vnoperate (struct vop_generic_args *);
 int    speedup_syncer (void);
 void   vattr_null (struct vattr *vap);
 int    vcount (struct vnode *vp);
-void   vdrop (struct vnode *);
 int    vfinddev (dev_t dev, enum vtype type, struct vnode **vpp);
 void   vfs_add_vnodeops_sysinit (const void *);
 void   vfs_rm_vnodeops_sysinit (const void *);
 void   vfs_add_vnodeops(struct vop_ops **, struct vnodeopv_entry_desc *);
 void   vfs_rm_vnodeops(struct vop_ops **);
 int    vflush (struct mount *mp, int rootrefs, int flags);
-int    vmntvnodescan(struct mount *mp, 
+int    vmntvnodescan(struct mount *mp, int flags,
            int (*fastfunc)(struct mount *mp, struct vnode *vp, void *data),
-           int (*slowfunc)(struct mount *mp, struct vnode *vp, lwkt_tokref_t vlock,
-           void *data), void *data);
+           int (*slowfunc)(struct mount *mp, struct vnode *vp, void *data),
+           void *data);
+void   insmntque(struct vnode *vp, struct mount *mp);
 
-int    vget (struct vnode *vp, lwkt_tokref_t vlock, int lockflag, struct thread *td);
+void   vclean (struct vnode *vp, int flags, struct thread *td);
 void   vgone (struct vnode *vp);
-void   vgonel (struct vnode *vp, lwkt_tokref_t vlock, struct thread *td);
-void   vhold (struct vnode *);
 int    vinvalbuf (struct vnode *vp, int save, 
            struct thread *td, int slpflag, int slptimeo);
 int    vtruncbuf (struct vnode *vp, struct thread *td,
                off_t length, int blksize);
 void   vprint (char *label, struct vnode *vp);
-int    vrecycle (struct vnode *vp, struct lwkt_tokref *inter_lkp,
-           struct thread *td);
+int    vrecycle (struct vnode *vp, struct thread *td);
 int    vn_close (struct vnode *vp, int flags, struct thread *td);
 int    vn_isdisk (struct vnode *vp, int *errp);
-int    vn_lock (struct vnode *vp, lwkt_tokref_t vlock, int flags, struct thread *td);
+int    vn_lock (struct vnode *vp, int flags, struct thread *td);
 #ifdef DEBUG_LOCKS
-int    debug_vn_lock (struct vnode *vp, lwkt_tokref_t vlock, int flags, struct thread *td,
+int    debug_vn_lock (struct vnode *vp, int flags, struct thread *td,
            const char *filename, int line);
-#define vn_lock(vp,vlock,flags,p) debug_vn_lock(vp,vlock,flags,p,__FILE__,__LINE__)
+#define vn_lock(vp,flags,p) debug_vn_lock(vp,flags,p,__FILE__,__LINE__)
 #endif
 
 int    vn_fullpath (struct proc *p, struct vnode *vn, char **retbuf, char **freebuf);
@@ -586,11 +592,28 @@ int       vop_stdcreatevobject (struct vop_createvobject_args *ap);
 int    vop_stddestroyvobject (struct vop_destroyvobject_args *ap);
 int    vop_stdgetvobject (struct vop_getvobject_args *ap);
 
-
+int    vx_lock (struct vnode *vp);
+void   vx_unlock (struct vnode *vp);
+int    vx_get (struct vnode *vp);
+int    vx_get_nonblock (struct vnode *vp);
+void   vx_put (struct vnode *vp);
+int    vget (struct vnode *vp, int lockflag, struct thread *td);
 void   vput (struct vnode *vp);
-void   vrele (struct vnode *vp);
-void   vrele_noinactive (struct vnode *vp);
+void   vhold (struct vnode *);
+void   vdrop (struct vnode *);
 void   vref (struct vnode *vp);
+void   vrele (struct vnode *vp);
+void   vsetflags (struct vnode *vp, int flags);
+void   vclrflags (struct vnode *vp, int flags);
+
+void   vfs_subr_init(void);
+void   vfs_mount_init(void);
+void   vfs_lock_init(void);
+void   vfs_sync_init(void);
+
+void   vn_syncer_add_to_worklist(struct vnode *, int);
+void   vnlru_proc_wait(void);
+
 
 extern struct vop_ops *default_vnode_vops;
 extern struct vop_ops *spec_vnode_vops;
index d180679..6c33998 100644 (file)
@@ -28,7 +28,7 @@
  * 
  *     @(#) src/sys/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
  * $FreeBSD: src/sys/coda/coda_vfsops.c,v 1.24.2.1 2001/07/26 20:36:45 iedowse Exp $
- * $DragonFly: src/sys/vfs/coda/Attic/coda_vfsops.c,v 1.16 2004/09/30 18:59:53 dillon Exp $
+ * $DragonFly: src/sys/vfs/coda/Attic/coda_vfsops.c,v 1.17 2004/10/12 19:20:50 dillon Exp $
  * 
  */
 
@@ -309,12 +309,7 @@ coda_root(struct mount *vfsp, struct vnode **vpp)
            { /* Found valid root. */
                *vpp = mi->mi_rootvp;
                /* On Mach, this is vref.  On NetBSD, VOP_LOCK */
-#if 1
-               vref(*vpp);
-               vn_lock(*vpp, NULL, LK_EXCLUSIVE, td);
-#else
-               vget(*vpp, NULL, LK_EXCLUSIVE, td);
-#endif
+               vget(*vpp, LK_EXCLUSIVE, td);
                MARK_INT_SAT(CODA_ROOT_STATS);
                return(0);
            }
@@ -332,12 +327,7 @@ coda_root(struct mount *vfsp, struct vnode **vpp)
        coda_save(VTOC(mi->mi_rootvp));
 
        *vpp = mi->mi_rootvp;
-#if    1
-       vref(*vpp);
-       vn_lock(*vpp, NULL, LK_EXCLUSIVE, td);
-#else
-       vget(*vpp, NULL, LK_EXCLUSIVE, td);
-#endif
+       vget(*vpp, LK_EXCLUSIVE, td);
 
        MARK_INT_SAT(CODA_ROOT_STATS);
        goto exit;
@@ -352,12 +342,7 @@ coda_root(struct mount *vfsp, struct vnode **vpp)
         * will fail.
         */
        *vpp = mi->mi_rootvp;
-#if    1
-       vref(*vpp);
-       vn_lock(*vpp, NULL, LK_EXCLUSIVE, td);
-#else
-       vget(*vpp, NULL, LK_EXCLUSIVE, td);
-#endif
+       vget(*vpp, LK_EXCLUSIVE, td);
 
        MARK_INT_FAIL(CODA_ROOT_STATS);
        error = 0;
index e2b469a..7909288 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.21 2004/10/05 03:24:23 dillon Exp $
+ * $DragonFly: src/sys/vfs/coda/Attic/coda_vnops.c,v 1.22 2004/10/12 19:20:50 dillon Exp $
  * 
  */
 
@@ -266,7 +266,7 @@ coda_open(void *v)
        return (error);
 
     /* We get the vnode back locked.  Needs unlocked */
-    VOP_UNLOCK(vp, NULL, 0, td);
+    VOP_UNLOCK(vp, 0, td);
     /* Keep a reference until the close comes in. */
     vref(*vpp);                
 
@@ -436,7 +436,7 @@ coda_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw rw, int ioflag,
             * We get the vnode back locked in both Mach and
             * NetBSD.  Needs unlocked 
             */
-           VOP_UNLOCK(cfvp, NULL, 0, td);
+           VOP_UNLOCK(cfvp, 0, td);
        }
        else {
            opened_internally = 1;
@@ -855,7 +855,7 @@ coda_inactive(void *v)
     struct vnode *vp = ap->a_vp;
     struct cnode *cp = VTOC(vp);
     struct ucred *cred __attribute__((unused)) = NULL;
-    struct thread *td = curthread;
+    /*struct thread *td = curthread;*/
 /* upcall decl */
 /* locals */
 
@@ -895,7 +895,6 @@ coda_inactive(void *v)
            printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n",
                   vp->v_usecount, vp, cp);
 #endif
-       lockmgr(&vp->v_lock, LK_RELEASE, NULL, td);
     } else {
 #ifdef OLD_DIAGNOSTIC
        if (CTOV(cp)->v_usecount) {
@@ -905,7 +904,6 @@ coda_inactive(void *v)
            panic("coda_inactive:  cp->ovp != NULL");
        }
 #endif
-       VOP_UNLOCK(vp, NULL, 0, td);
        vgone(vp);
     }
 
@@ -1050,7 +1048,7 @@ coda_lookup(void *v)
      */
     if (!error || (error == EJUSTRETURN)) {
        if (!(cnp->cn_flags & CNP_LOCKPARENT) || !(cnp->cn_flags & CNP_ISLASTCN)) {
-           if ((error = VOP_UNLOCK(dvp, NULL, 0, td))) {
+           if ((error = VOP_UNLOCK(dvp, 0, td))) {
                return error; 
            }       
            /* 
@@ -1058,7 +1056,7 @@ coda_lookup(void *v)
             * lock it without bothering to check anything else. 
             */
            if (*ap->a_vpp) {
-               if ((error = VOP_LOCK(*ap->a_vpp, NULL, LK_EXCLUSIVE, td))) {
+               if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) {
                    printf("coda_lookup: ");
                    panic("unlocked parent but couldn't lock child");
                }
@@ -1067,7 +1065,7 @@ coda_lookup(void *v)
            /* The parent is locked, and may be the same as the child */
            if (*ap->a_vpp && (*ap->a_vpp != dvp)) {
                /* Different, go ahead and lock it. */
-               if ((error = VOP_LOCK(*ap->a_vpp, NULL, LK_EXCLUSIVE, td))) {
+               if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) {
                    printf("coda_lookup: ");
                    panic("unlocked parent but couldn't lock child");
                }
@@ -1155,7 +1153,7 @@ coda_create(void *v)
 
     if (!error) {
        if (cnp->cn_flags & CNP_LOCKLEAF) {
-           if ((error = VOP_LOCK(*ap->a_vpp, NULL, LK_EXCLUSIVE, td))) {
+           if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) {
                printf("coda_create: ");
                panic("unlocked parent but couldn't lock child");
            }
@@ -1721,7 +1719,6 @@ coda_reclaim(void *v)
     }
 #endif
     }  
-    cache_inval_vp(vp, CINV_SELF);
     coda_free(VTOC(vp));
     vp->v_data = NULL;
     return (0);
@@ -1746,9 +1743,9 @@ coda_lock(void *v)
     }
 
 #ifndef        DEBUG_LOCKS
-    return (lockmgr(&vp->v_lock, ap->a_flags, ap->a_vlock, td));
+    return (lockmgr(&vp->v_lock, ap->a_flags, NULL, td));
 #else
-    return (debuglockmgr(&vp->v_lock, ap->a_flags, ap->a_vlock, td,
+    return (debuglockmgr(&vp->v_lock, ap->a_flags, NULL, td,
                         "coda_lock", vp->filename, vp->line));
 #endif
 }
@@ -1770,7 +1767,7 @@ coda_unlock(void *v)
                  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
     }
 
-    return (lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, ap->a_vlock, td));
+    return (lockmgr(&vp->v_lock, ap->a_flags | LK_