VFS messaging/interfacing work stage 9/99: VFS 'NEW' API WORK.
authorMatthew Dillon <dillon@dragonflybsd.org>
Fri, 12 Nov 2004 00:09:56 +0000 (00:09 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Fri, 12 Nov 2004 00:09:56 +0000 (00:09 +0000)
NOTE: unionfs and nullfs are temporarily broken by this commit.

* Remove the old namecache API.  Remove vfs_cache_lookup(), cache_lookup(),
  cache_enter(), namei() and lookup() are all gone.  VOP_LOOKUP() and
  VOP_CACHEDLOOKUP() have been collapsed into a single non-caching
  VOP_LOOKUP().

* Complete the new VFS CACHE (namecache) API.  The new API is able to
  supply topological guarentees and is able to reserve namespaces,
  including negative cache spaces (whether the target name exists or not),
  which the new API uses to reserve namespace for things like NRENAME
  and NCREATE (and others).

* Complete the new namecache API.  VOP_NRESOLVE, NLOOKUPDOTDOT, NCREATE,
  NMKDIR, NMKNOD, NLINK, NSYMLINK, NWHITEOUT, NRENAME, NRMDIR, NREMOVE.
  These new calls take (typicaly locked) namecache pointers rather then
  combinations of directory vnodes, file vnodes, and name components.  The
  new calls are *MUCH* simpler in concept and implementation.  For example,
  VOP_RENAME() has 8 arguments while VOP_NRENAME() has only 3 arguments.

  The new namecache API uses the namecache to lock namespaces without having
  to lock the underlying vnodes.  For example, this allows the kernel
  to reserve the target name of a create function trivially.  Namecache
  records are maintained BY THE KERNEL for both positive and negative hits.

  Generally speaking, the kernel layer is now responsible for resolving
  path elements.  NRESOLVE is called when an unresolved namecache record
  needs to be resolved.  Unlike the old VOP_LOOKUP, NRESOLVE is simply
  responsible for associating a vnode to a namecache record (positive hit)
  or telling the system that it's a negative hit, and not responsible for
  handling symlinks or other special cases or doing any of the other
  path lookup work, much unlike the old VOP_LOOKUP.

  It should be particularly noted that the new namecache topology does not
  allow disconnected namecache records.  In rare cases where a vnode must
  be converted to a namecache pointer for new API operation via a file handle
  (i.e. NFS), the cache_fromdvp() function is provided and a new API VOP,
  VOP_NLOOKUPDOTDOT() is provided to allow the namecache to resolve the
  topology leading up to the requested vnode.  These and other topological
  guarentees greatly reduce the complexity of the new namecache API.

  The new namei() is called nlookup().  This function uses a combination
  of cache_n*() calls, VOP_NRESOLVE(), and standard VOP calls resolve the
  supplied path, deal with symlinks, and so forth, in a nice small compact
  compartmentalized procedure.

* The old VFS code is no longer responsible for maintaining namecache records,
  a function which was mostly adhoc cache_purge()s occuring before the VFS
  actually knows whether an operation will succeed or not.

  The new VFS code is typically responsible for adjusting the state of
  locked namecache records passed into it.  For example, if NCREATE succeeds
  it must call cache_setvp() to associate the passed namecache record with
  the vnode representing the successfully created file.  The new requirements
  are much less complex then the old requirements.

* Most VFSs still implement the old API calls, albeit somewhat modified
  and in particular the VOP_LOOKUP function is now *MUCH* simpler.  However,
  the kernel now uses the new API calls almost exclusively and relies on
  compatibility code installed in the default ops (vop_compat_*()) to
  convert the new calls to the old calls.

* All kernel system calls and related support functions which used to do
  complex and confusing namei() operations now do far less complex and
  far less confusing nlookup() operations.

* SPECOPS shortcutting has been implemented.  User reads and writes now go
  directly to supporting functions which talk to the device via fileops
  rather then having to be routed through VOP_READ or VOP_WRITE, saving
  significant overhead.  Note, however, that these only really effect
  /dev/null and /dev/zero.

  Implementing this was fairly easy, we now simply pass an optional
  struct file pointer to VOP_OPEN() and let spec_open() handle the
  override.

SPECIAL NOTES: It should be noted that we must still lock a directory vnode
LK_EXCLUSIVE before issuing a VOP_LOOKUP(), even for simple lookups, because
a number of VFS's (including UFS) store active directory scanning information
in the directory vnode.  The legacy NAMEI_LOOKUP cases can be changed to
use LK_SHARED once these VFS cases are fixed.  In particular, we are now
organized well enough to actually be able to do record locking within a
directory for handling NCREATE, NDELETE, and NRENAME situations, but it hasn't
been done yet.

Many thanks to all of the testers and in particular David Rhodus for
finding a large number of panics and other issues.

104 files changed:
sys/checkpt/checkpt.c
sys/dev/disk/ccd/ccd.c
sys/dev/disk/vn/vn.c
sys/dev/misc/streams/streams.c
sys/emulation/43bsd/43bsd_file.c
sys/emulation/ibcs2/coff/imgact_coff.c
sys/emulation/ibcs2/i386/ibcs2_stat.c
sys/emulation/ibcs2/i386/ibcs2_util.c
sys/emulation/ibcs2/i386/ibcs2_xenix.c
sys/emulation/linux/i386/linux_machdep.c
sys/emulation/linux/linux_file.c
sys/emulation/linux/linux_getcwd.c
sys/emulation/linux/linux_misc.c
sys/emulation/linux/linux_stats.c
sys/emulation/linux/linux_uid16.c
sys/emulation/linux/linux_util.c
sys/emulation/ndis/subr_ndis.c
sys/emulation/svr4/svr4_misc.c
sys/emulation/svr4/svr4_sysvec.c
sys/kern/imgact_elf.c
sys/kern/kern_acct.c
sys/kern/kern_acl.c
sys/kern/kern_clock.c
sys/kern/kern_descrip.c
sys/kern/kern_event.c
sys/kern/kern_exec.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/sys_pipe.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_lookup.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_subr.c
sys/kern/vfs_syscalls.c
sys/kern/vfs_vnops.c
sys/kern/vfs_vopops.c
sys/opencrypto/cryptodev.c
sys/sys/buf2.h
sys/sys/file.h
sys/sys/filedesc.h
sys/sys/kern_syscall.h
sys/sys/mount.h
sys/sys/namecache.h
sys/sys/namei.h
sys/sys/nlookup.h
sys/sys/vfsops.h
sys/sys/vnode.h
sys/vfs/coda/coda_fbsd.c
sys/vfs/coda/coda_vfsops.c
sys/vfs/coda/coda_vnops.c
sys/vfs/gnu/ext2fs/ext2_extern.h
sys/vfs/gnu/ext2fs/ext2_lookup.c
sys/vfs/gnu/ext2fs/ext2_vfsops.c
sys/vfs/gnu/ext2fs/ext2_vnops.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.h
sys/vfs/isofs/cd9660/cd9660_vfsops.c
sys/vfs/isofs/cd9660/cd9660_vnops.c
sys/vfs/msdosfs/denode.h
sys/vfs/msdosfs/msdosfs_lookup.c
sys/vfs/msdosfs/msdosfs_vfsops.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/nfs/nfs.h
sys/vfs/nfs/nfs_nqlease.c
sys/vfs/nfs/nfs_serv.c
sys/vfs/nfs/nfs_socket.c
sys/vfs/nfs/nfs_subs.c
sys/vfs/nfs/nfs_syscalls.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/ntfs/ntfs_vfsops.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/nullfs/null_vfsops.c
sys/vfs/nullfs/null_vnops.c
sys/vfs/nwfs/nwfs_io.c
sys/vfs/nwfs/nwfs_vnops.c
sys/vfs/procfs/procfs_vnops.c
sys/vfs/smbfs/smbfs_io.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_vfsops.c
sys/vfs/ufs/ufs_extern.h
sys/vfs/ufs/ufs_lookup.c
sys/vfs/ufs/ufs_quota.c
sys/vfs/ufs/ufs_vnops.c
sys/vfs/ufs/ufsmount.h
sys/vfs/umapfs/umap_vfsops.c
sys/vfs/union/union_subr.c
sys/vfs/union/union_vfsops.c
sys/vfs/union/union_vnops.c
sys/vm/device_pager.c
sys/vm/vm_object.c
sys/vm/vm_swap.c

index 9ea6397..1a1cd83 100644 (file)
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/checkpt/Attic/checkpt.c,v 1.5 2004/06/03 10:00:06 eirikn Exp $
+ * $DragonFly: src/sys/checkpt/Attic/checkpt.c,v 1.6 2004/11/12 00:09:00 dillon Exp $
  */
 
 #include <sys/types.h>
@@ -450,7 +450,9 @@ elf_getsigs(struct proc *p, struct file *fp)
        return error;
 }
 
-
+/*
+ * Returns a locked, refd vnode
+ */
 static int
 ckpt_fhtovp(fhandle_t *fh, struct vnode **vpp) 
 {
@@ -480,22 +482,23 @@ ckpt_fhtovp(fhandle_t *fh, struct vnode **vpp)
 static int
 mmap_vp(struct vn_hdr *vnh) 
 {
-       struct vnode **vpp, *vp;
+       struct vnode *vp;
        Elf_Phdr *phdr;
        struct file *fp;
        int error;
        TRACE_ENTER;
-       vpp = &vp;
 
        phdr = &vnh->vnh_phdr;
 
-       if ((error = ckpt_fhtovp(&vnh->vnh_fh, vpp)) != 0)
+       if ((error = ckpt_fhtovp(&vnh->vnh_fh, &vp)) != 0)
                return error;
        /*
         * XXX O_RDONLY -> or O_RDWR if file is PROT_WRITE, MAP_SHARED
         */
-       if ((error = fp_vpopen(*vpp, O_RDONLY, &fp)) != 0)
+       if ((error = fp_vpopen(vp, O_RDONLY, &fp)) != 0) {
+               vput(vp);
                return error;
+       }
        error = mmap_phdr(fp, phdr);
        fp_close(fp);
        TRACE_EXIT;
@@ -585,8 +588,10 @@ elf_getfiles(struct proc *p, struct file *fp)
                }
                if ((error = ckpt_fhtovp(&cfi->cfi_fh, &vp)) != 0)
                        break;
-               if ((error = fp_vpopen(vp, OFLAGS(cfi->cfi_flags), &tempfp)) != 0)
+               if ((error = fp_vpopen(vp, OFLAGS(cfi->cfi_flags), &tempfp)) != 0) {
+                       vput(vp);
                        break;
+               }
                tempfp->f_offset = cfi->cfi_offset;
                /*  XXX bail for now if we the index is 
                 *  larger than the current file table 
index 7ae15a4..f392e29 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.17 2004/10/12 19:20:30 dillon Exp $ */
+/* $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.18 2004/11/12 00:09:03 dillon Exp $ */
 
 /*     $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */
 
@@ -97,7 +97,7 @@
 #include <sys/proc.h>
 #include <sys/buf.h>
 #include <sys/malloc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/conf.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
@@ -1536,31 +1536,34 @@ ccddump(dev_t dev, u_int count, u_int blkno, u_int secsize)
 static int
 ccdlookup(char *path, struct thread *td, struct vnode **vpp)
 {
-       struct nameidata nd;
+       struct nlookupdata nd;
+       struct ucred *cred;
        struct vnode *vp;
        int error;
-       struct ucred *cred;
 
        KKASSERT(td->td_proc);
        cred = td->td_proc->p_ucred;
+       *vpp = NULL;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, path, td);
-       if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
+       error = nlookup_init(&nd, path, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
+       if (error)
+               return (error);
+       if ((error = vn_open(&nd, NULL, FREAD|FWRITE, 0)) != 0) {
 #ifdef DEBUG
                if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
                        printf("ccdlookup: vn_open error = %d\n", error);
 #endif
-               return (error);
+               goto done;
        }
-       vp = nd.ni_vp;
+       vp = nd.nl_open_vp;
 
        if (vp->v_usecount > 1) {
                error = EBUSY;
-               goto bad;
+               goto done;
        }
 
        if (!vn_isdisk(vp, &error)) 
-               goto bad;
+               goto done;
 
 #ifdef DEBUG
        if (ccddebug & CCDB_VNODE)
@@ -1568,14 +1571,12 @@ ccdlookup(char *path, struct thread *td, struct vnode **vpp)
 #endif
 
        VOP_UNLOCK(vp, 0, td);
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       *vpp = vp;
+       nd.nl_open_vp = NULL;
+       nlookup_done(&nd);
+       *vpp = vp;                              /* leave ref intact  */
        return (0);
-bad:
-       VOP_UNLOCK(vp, 0, td);
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       /* vn_close does vrele() for vp */
-       (void)vn_close(vp, FREAD|FWRITE, td);
+done:
+       nlookup_done(&nd);
        return (error);
 }
 
index f40b444..dba56bd 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.12 2004/10/12 19:20:32 dillon Exp $
+ * $DragonFly: src/sys/dev/disk/vn/vn.c,v 1.13 2004/11/12 00:09:04 dillon Exp $
  */
 
 /*
@@ -65,7 +65,7 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/buf.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
@@ -541,35 +541,40 @@ vniocattach_file(vn, vio, dev, flag, td)
        struct thread *td;
 {
        struct vattr vattr;
-       struct nameidata nd;
+       struct nlookupdata nd;
        int error, flags;
+       struct vnode *vp;
        struct proc *p = td->td_proc;
 
        KKASSERT(p != NULL);
 
        flags = FREAD|FWRITE;
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, vio->vn_file, td);
-       error = vn_open(&nd, flags, 0);
-       if (error) {
+       error = nlookup_init(&nd, vio->vn_file, 
+                               UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
+       if (error)
+               return (error);
+       if ((error = vn_open(&nd, NULL, flags, 0)) != 0) {
                if (error != EACCES && error != EPERM && error != EROFS)
-                       return (error);
+                       goto done;
                flags &= ~FWRITE;
-               NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW,
-                       UIO_USERSPACE, vio->vn_file, td);
-               error = vn_open(&nd, flags, 0);
+               nlookup_done(&nd);
+               error = nlookup_init(&nd, vio->vn_file, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
                if (error)
                        return (error);
+               if ((error = vn_open(&nd, NULL, flags, 0)) != 0)
+                       goto done;
        }
-       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, 0, td);
-               (void) vn_close(nd.ni_vp, flags, td);
-               return (error ? error : EINVAL);
+       vp = nd.nl_open_vp;
+       if (vp->v_type != VREG ||
+           (error = VOP_GETATTR(vp, &vattr, td))) {
+               if (error == 0)
+                       error = EINVAL;
+               goto done;
        }
-       VOP_UNLOCK(nd.ni_vp, 0, td);
+       VOP_UNLOCK(vp, 0, td);
        vn->sc_secsize = DEV_BSIZE;
-       vn->sc_vp = nd.ni_vp;
+       vn->sc_vp = vp;
+       nd.nl_open_vp = NULL;
 
        /*
         * If the size is specified, override the file attributes.  Note that
@@ -581,8 +586,9 @@ vniocattach_file(vn, vio, dev, flag, td)
                vn->sc_size = vattr.va_size / vn->sc_secsize;
        error = vnsetcred(vn, p->p_ucred);
        if (error) {
-               (void) vn_close(nd.ni_vp, flags, td);
-               return(error);
+               vn->sc_vp = NULL;
+               vn_close(vp, flags, td);
+               goto done;
        }
        vn->sc_flags |= VNF_INITED;
        if (flags == FREAD)
@@ -602,7 +608,9 @@ vniocattach_file(vn, vio, dev, flag, td)
        IFOPT(vn, VN_FOLLOW)
                printf("vnioctl: SET vp %p size %x blks\n",
                       vn->sc_vp, vn->sc_size);
-       return(0);
+done:
+       nlookup_done(&nd);
+       return(error);
 }
 
 /*
@@ -737,7 +745,7 @@ vnclear(struct vn_softc *vn)
                dsgone(&vn->sc_slices);
        vn->sc_flags &= ~VNF_INITED;
        if (vn->sc_vp != NULL) {
-               (void)vn_close(vn->sc_vp, vn->sc_flags & VNF_READONLY ?
+               vn_close(vn->sc_vp, vn->sc_flags & VNF_READONLY ?
                    FREAD : (FREAD|FWRITE), td);
                vn->sc_vp = NULL;
        }
index 1407b1f..1f5f94c 100644 (file)
@@ -31,7 +31,7 @@
  * in 3.0-980524-SNAP then hacked a bit (but probably not enough :-).
  *
  * $FreeBSD: src/sys/dev/streams/streams.c,v 1.16.2.1 2001/02/26 04:23:07 jlemon Exp $
- * $DragonFly: src/sys/dev/misc/streams/Attic/streams.c,v 1.13 2004/08/02 13:22:32 joerg Exp $
+ * $DragonFly: src/sys/dev/misc/streams/Attic/streams.c,v 1.14 2004/11/12 00:09:07 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -242,8 +242,11 @@ streamsopen(dev_t dev, int oflags, int devtype, d_thread_t *td)
          return error;
 
        if ((error = socreate(family, &so, type, protocol, td)) != 0) {
-         p->p_fd->fd_ofiles[fd] = 0;
-         ffree(fp);
+         if (p->p_fd->fd_ofiles[fd] == fp) {
+             p->p_fd->fd_ofiles[fd] = NULL;
+             fdrop(fp, td);
+         }
+         fdrop(fp, td);
          return error;
        }
 
@@ -251,8 +254,8 @@ streamsopen(dev_t dev, int oflags, int devtype, d_thread_t *td)
        fp->f_flag = FREAD|FWRITE;
        fp->f_ops = &svr4_netops;
        fp->f_type = DTYPE_SOCKET;
-
        (void)svr4_stream_get(fp);
+       fdrop(fp, td);
        p->p_dupfd = fd;
        return ENXIO;
 }
index 7a82c9a..c621a88 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.6 2004/10/12 19:20:33 dillon Exp $
+ * $DragonFly: src/sys/emulation/43bsd/43bsd_file.c,v 1.7 2004/11/12 00:09:10 dillon Exp $
  *     from: DragonFly kern/vfs_syscalls.c,v 1.20
  *
  * These syscalls used to live in kern/vfs_syscalls.c.  They are modified
@@ -58,8 +58,9 @@
 #include <sys/kern_syscall.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
-#include <sys/namei.h>
 #include <sys/uio.h>
+#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/vnode.h>
 
 #include <vfs/union/union.h>
 int
 ocreat(struct ocreat_args *uap)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        int error;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
-
-       error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, uap->mode,
-           &uap->sysmsg_result);
-
+       error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, 
+                                   uap->mode, &uap->sysmsg_result);
+       }
        return (error);
 }
 
@@ -103,14 +103,13 @@ olseek(struct olseek_args *uap)
 int
 otruncate(struct otruncate_args *uap)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        int error;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
-
-       error = kern_truncate(&nd, uap->length);
-
+       error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_truncate(&nd, uap->length);
+       nlookup_done(&nd);
        return (error);
 }
 
index aac6ba6..4490701 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.12 2004/10/12 19:20:34 dillon Exp $
+ * $DragonFly: src/sys/emulation/ibcs2/coff/Attic/imgact_coff.c,v 1.13 2004/11/12 00:09:12 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -39,7 +39,7 @@
 #include <sys/malloc.h>
 #include <sys/mount.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/vnode.h>
 
 #include <vm/vm.h>
@@ -154,7 +154,7 @@ coff_load_file(struct thread *td, char *name)
 {
        struct vmspace *vmspace;
        int error;
-       struct nameidata nd;
+       struct nlookupdata nd;
        struct vnode *vp;
        struct vattr attr;
        struct filehdr *fhdr;
@@ -173,15 +173,16 @@ coff_load_file(struct thread *td, char *name)
        vmspace = td->td_proc->p_vmspace;
 
        /* XXX use of 'curthread' should be 'td'?*/
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME, UIO_SYSSPACE, name, curthread);
-
-       error = namei(&nd);
+       error = nlookup_init(&nd, name, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0) {
+               error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp);
+               if (error)
+                       error = ENOEXEC;
+       }
        if (error)
-               return error;
-
-       vp = nd.ni_vp;
-       if (vp == NULL)
-               return ENOEXEC;
+               goto done;
 
        if (vp->v_writecount) {
                error = ETXTBSY;
@@ -204,7 +205,7 @@ coff_load_file(struct thread *td, char *name)
        if ((error = VOP_ACCESS(vp, VEXEC, cred, td)) != 0)
                goto fail;
 
-       if ((error = VOP_OPEN(vp, FREAD, cred, td)) != 0)
+       if ((error = VOP_OPEN(vp, FREAD, cred, NULL, td)) != 0)
                goto fail;
 
        /*
@@ -286,8 +287,9 @@ coff_load_file(struct thread *td, char *name)
  fail:
        VOP_UNLOCK(vp, 0, td);
  unlocked_fail:
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       vrele(nd.ni_vp);
+       vrele(vp);
+done:
+       nlookup_done(&nd);
        return error;
 }
 
index 322513e..9c87fd4 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/ibcs2/ibcs2_stat.c,v 1.10 1999/12/15 23:01:45 eivind Exp $
- * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_stat.c,v 1.9 2003/09/23 05:03:50 dillon Exp $
+ * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_stat.c,v 1.10 2004/11/12 00:09:16 dillon Exp $
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/file.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/stat.h>
 #include <sys/filedesc.h>
 #include <sys/kernel.h>
@@ -108,21 +108,24 @@ ibcs2_statfs(struct ibcs2_statfs_args *uap)
        struct mount *mp;
        struct statfs *sp;
        int error;
-       struct nameidata nd;
+       struct nlookupdata nd;
        caddr_t sg = stackgap_init();
 
        CHECKALTEXIST(&sg, SCARG(uap, path));
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
-       if ((error = namei(&nd)) != 0)
-               return (error);
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       mp = nd.ni_vp->v_mount;
-       sp = &mp->mnt_stat;
-       vrele(nd.ni_vp);
-       if ((error = VFS_STATFS(mp, sp, td)) != 0)
-               return (error);
-       sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-       return cvt_statfs(sp, (caddr_t)SCARG(uap, buf), SCARG(uap, len));
+       error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0) {
+               mp = nd.nl_ncp->nc_mount;
+               sp = &mp->mnt_stat;
+               error = VFS_STATFS(mp, sp, td);
+               if (error == 0) {
+                       sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+                       error = cvt_statfs(sp, (caddr_t)SCARG(uap, buf),
+                                           SCARG(uap, len));
+               }
+       }
+       nlookup_done(&nd);
 }
 
 int
index b428775..84d9c0c 100644 (file)
  *
  *     from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp
  * $FreeBSD: src/sys/i386/ibcs2/ibcs2_util.c,v 1.7 1999/12/15 23:01:45 eivind Exp $
- * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_util.c,v 1.8 2004/01/08 18:39:18 asmodai Exp $
+ * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_util.c,v 1.9 2004/11/12 00:09:16 dillon Exp $
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/malloc.h>
 #include <sys/vnode.h>
 
@@ -60,19 +60,15 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag)
        char            **pbuf;
        int               cflag;
 {
-       struct thread    *td = curthread;       /* XXX */
-       struct ucred    *cred;
-       struct nameidata         nd;
-       struct nameidata         ndroot;
+       struct nlookupdata       nd;
+       struct nlookupdata       ndroot;
        struct vattr             vat;
        struct vattr             vatroot;
+       struct vnode            *vp;
        int                      error;
        char                    *ptr, *buf, *cp;
        size_t                   sz, len;
 
-       KKASSERT(td->td_proc);
-       cred = td->td_proc->p_ucred;
-
        buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
        *pbuf = path;
 
@@ -111,21 +107,22 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag)
                for (cp = &ptr[len] - 1; *cp != '/'; cp--);
                *cp = '\0';
 
-               NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td);
-
-               if ((error = namei(&nd)) != 0) {
-                       free(buf, M_TEMP);
-                       return error;
+               error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&nd);
+               if (error) {
+                       nlookup_done(&nd);
+                       return (error);
                }
-
                *cp = '/';
-       }
-       else {
-               NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td);
-
-               if ((error = namei(&nd)) != 0) {
-                       free(buf, M_TEMP);
-                       return error;
+       } else {
+
+               error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&nd);
+               if (error) {
+                       nlookup_done(&nd);
+                       return (error);
                }
 
                /*
@@ -136,25 +133,24 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag)
                 * root directory and never finding it, because "/" resolves
                 * to the emulation root directory. This is expensive :-(
                 */
-               NDINIT(&ndroot, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE,
-                       ibcs2_emul_path, td);
-
-               if ((error = namei(&ndroot)) != 0) {
-                       /* Cannot happen! */
-                       free(buf, M_TEMP);
-                       NDFREE(&nd, NDF_ONLY_PNBUF);
-                       vrele(nd.ni_vp);
-                       return error;
-               }
-
-               if ((error = VOP_GETATTR(nd.ni_vp, &vat, td)) != 0) {
+               error = nlookup_init(&ndroot, ibcs2_emul_path, UIO_SYSSPACE,
+                                       NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&ndroot);
+               if (error == 0)
+                       error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp);
+               if (error) 
                        goto done;
-               }
-
-               if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, td))
-                   != 0) {
+               error = VOP_GETATTR(vp, &vat, nd.nl_td);
+               vrele(vp);
+               if (error == 0)
+                       error = cache_vref(ndroot.nl_ncp, nd.nl_cred, &vp);
+               if (error)
+                       goto done;
+               error = VOP_GETATTR(vp, &vatroot, nd.nl_td);
+               vrele(vp);
+               if (error)
                        goto done;
-               }
 
                if (vat.va_fsid == vatroot.va_fsid &&
                    vat.va_fileid == vatroot.va_fileid) {
@@ -163,22 +159,17 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag)
                }
 
        }
-       if (sgp == NULL)
+       if (sgp == NULL) {
                *pbuf = buf;
-       else {
+       else {
                sz = &ptr[len] - buf;
                *pbuf = stackgap_alloc(sgp, sz + 1);
                error = copyout(buf, *pbuf, sz);
                free(buf, M_TEMP);
        }
-
-
 done:
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       vrele(nd.ni_vp);
-       if (!cflag) {
-               NDFREE(&ndroot, NDF_ONLY_PNBUF);
-               vrele(ndroot.ni_vp);
-       }
-       return error;
+       nlookup_done(&nd);
+       if (!cflag)
+               nlookup_done(&ndroot);
+       return (error);
 }
index ce8a63c..a9ee9d5 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/ibcs2/ibcs2_xenix.c,v 1.20 1999/12/15 23:01:46 eivind Exp $
- * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_xenix.c,v 1.9 2003/09/23 05:03:50 dillon Exp $
+ * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_xenix.c,v 1.10 2004/11/12 00:09:16 dillon Exp $
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
-#include <sys/namei.h> 
+#include <sys/nlookup.h> 
 #include <sys/sysproto.h>
 #include <sys/kernel.h>
 #include <sys/filio.h>
@@ -196,17 +196,19 @@ xenix_eaccess(struct xenix_eaccess_args *uap)
        struct proc *p = curproc;
        struct ucred *cred = p->p_ucred;
        struct vnode *vp;
-        struct nameidata nd;
+        struct nlookupdata nd;
         int error, flags;
        caddr_t sg = stackgap_init();
 
        CHECKALTEXIST(&sg, SCARG(uap, path));
 
-        NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE,
-            SCARG(uap, path), td);
-        if ((error = namei(&nd)) != 0)
-                return error;
-        vp = nd.ni_vp;
+       error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0)
+               error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp);
+       if (error)
+               goto done;
 
         /* Flags == 0 means only check for existence. */
         if (SCARG(uap, flags)) {
@@ -220,7 +222,8 @@ xenix_eaccess(struct xenix_eaccess_args *uap)
                 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
                         error = VOP_ACCESS(vp, flags, cred, td);
         }
-       NDFREE(&nd, NDF_ONLY_PNBUF);
         vput(vp);
-        return error;
+done:
+       nlookup_done(&nd);
+        return (error);
 }
index 87e1e20..d4a82ea 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/linux/linux_machdep.c,v 1.6.2.4 2001/11/05 19:08:23 marcel Exp $
- * $DragonFly: src/sys/emulation/linux/i386/linux_machdep.c,v 1.14 2003/12/20 05:52:21 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/i386/linux_machdep.c,v 1.15 2004/11/12 00:09:19 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -35,7 +35,7 @@
 #include <sys/kern_syscall.h>
 #include <sys/lock.h>
 #include <sys/mman.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/proc.h>
 #include <sys/resource.h>
 #include <sys/resourcevar.h>
@@ -104,8 +104,7 @@ bsd_to_linux_sigaltstack(int bsa)
 int
 linux_execve(struct linux_execve_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        struct image_args exec_args;
        char *path;
        int error;
@@ -117,12 +116,14 @@ linux_execve(struct linux_execve_args *args)
        if (ldebug(execve))
                printf(ARGS(execve, "%s"), path);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME,
-           UIO_SYSSPACE, path, td);
-       error = exec_copyin_args(&exec_args, path, PATH_SYSSPACE,
-                               args->argp, args->envp);
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = exec_copyin_args(&exec_args, path, PATH_SYSSPACE,
+                                       args->argp, args->envp);
+       }
        if (error == 0)
                error = kern_execve(&nd, &exec_args);
+       nlookup_done(&nd);
 
        /*
         * The syscall result is returned in registers to the new program.
index 29469ff..1547bb2 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.18 2004/10/12 19:20:37 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.19 2004/11/12 00:09:18 dillon Exp $
  */
 
 #include "opt_compat.h"
 #include <sys/dirent.h>
 #include <sys/fcntl.h>
 #include <sys/file.h>
+#include <sys/stat.h>
 #include <sys/filedesc.h>
 #include <sys/kern_syscall.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
-#include <sys/namei.h>
 #include <sys/nlookup.h>
 #include <sys/proc.h>
 #include <sys/sysproto.h>
@@ -62,8 +62,7 @@
 int
 linux_creat(struct linux_creat_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -74,11 +73,11 @@ linux_creat(struct linux_creat_args *args)
        if (ldebug(creat))
                printf(ARGS(creat, "%s, %d"), path, args->mode);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, args->mode,
-           &args->sysmsg_result);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC,
+                                   args->mode, &args->sysmsg_result);
+       }
        linux_free_path(&path);
        return(error);
 }
@@ -89,7 +88,7 @@ linux_open(struct linux_open_args *args)
 {
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error, flags;
 
@@ -135,9 +134,11 @@ linux_open(struct linux_open_args *args)
                flags |= O_EXCL;
        if (args->flags & LINUX_O_NOCTTY)
                flags |= O_NOCTTY;
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_open(&nd, flags, args->mode, &args->sysmsg_result);
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = kern_open(&nd, flags,
+                                   args->mode, &args->sysmsg_result);
+       }
 
        if (error == 0 && !(flags & O_NOCTTY) && 
                SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
@@ -462,8 +463,7 @@ linux_getdents64(struct linux_getdents64_args *args)
 int
 linux_access(struct linux_access_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -474,11 +474,10 @@ linux_access(struct linux_access_args *args)
        if (ldebug(access))
                printf(ARGS(access, "%s, %d"), path, args->flags);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ,
-           UIO_SYSSPACE, path, td);
-
-       error = kern_access(&nd, args->flags);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_access(&nd, args->flags);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -486,8 +485,7 @@ linux_access(struct linux_access_args *args)
 int
 linux_unlink(struct linux_unlink_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -498,10 +496,10 @@ linux_unlink(struct linux_unlink_args *args)
        if (ldebug(unlink))
                printf(ARGS(unlink, "%s"), path);
 #endif
-       NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td);
-
-       error = kern_unlink(&nd);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0)
+               error = kern_unlink(&nd);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -532,8 +530,7 @@ linux_chdir(struct linux_chdir_args *args)
 int
 linux_chmod(struct linux_chmod_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -544,10 +541,10 @@ linux_chmod(struct linux_chmod_args *args)
        if (ldebug(chmod))
                printf(ARGS(chmod, "%s, %d"), path, args->mode);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_chmod(&nd, args->mode);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_chmod(&nd, args->mode);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -555,8 +552,7 @@ linux_chmod(struct linux_chmod_args *args)
 int
 linux_mkdir(struct linux_mkdir_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -567,9 +563,10 @@ linux_mkdir(struct linux_mkdir_args *args)
        if (ldebug(mkdir))
                printf(ARGS(mkdir, "%s, %d"), path, args->mode);
 #endif
-       NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td);
-
-       error = kern_mkdir(&nd, args->mode);
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0)
+               error = kern_mkdir(&nd, args->mode);
+       nlookup_done(&nd);
 
        linux_free_path(&path);
        return(error);
@@ -578,8 +575,7 @@ linux_mkdir(struct linux_mkdir_args *args)
 int
 linux_rmdir(struct linux_rmdir_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -590,11 +586,10 @@ linux_rmdir(struct linux_rmdir_args *args)
        if (ldebug(rmdir))
                printf(ARGS(rmdir, "%s"), path);
 #endif
-       NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT | CNP_LOCKLEAF,
-           UIO_SYSSPACE, path, td);
-
-       error = kern_rmdir(&nd);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0)
+               error = kern_rmdir(&nd);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -602,8 +597,7 @@ linux_rmdir(struct linux_rmdir_args *args)
 int
 linux_rename(struct linux_rename_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata fromnd, tond;
+       struct nlookupdata fromnd, tond;
        char *from, *to;
        int error;
 
@@ -619,15 +613,14 @@ linux_rename(struct linux_rename_args *args)
        if (ldebug(rename))
                printf(ARGS(rename, "%s, %s"), from, to);
 #endif
-       NDINIT(&fromnd, NAMEI_DELETE, CNP_WANTPARENT | CNP_SAVESTART,
-           UIO_SYSSPACE, from, td);
-       NDINIT(&tond, NAMEI_RENAME,
-           CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_NOCACHE |
-           CNP_SAVESTART | CNP_NOOBJ,
-           UIO_SYSSPACE, to, td);
-
-       error = kern_rename(&fromnd, &tond);
-
+       error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
+               if (error == 0)
+                       error = kern_rename(&fromnd, &tond);
+               nlookup_done(&tond);
+       }
+       nlookup_done(&fromnd);
        linux_free_path(&from);
        linux_free_path(&to);
        return(error);
@@ -637,9 +630,10 @@ int
 linux_symlink(struct linux_symlink_args *args)
 {
        struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path, *link;
        int error;
+       int mode;
 
        error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
        if (error)
@@ -653,11 +647,12 @@ linux_symlink(struct linux_symlink_args *args)
        if (ldebug(symlink))
                printf(ARGS(symlink, "%s, %s"), path, link);
 #endif
-       NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ, UIO_SYSSPACE,
-           link, td);
-
-       error = kern_symlink(path, &nd);
-
+       error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
+               error = kern_symlink(&nd, path, mode);
+       }
+       nlookup_done(&nd);
        linux_free_path(&path);
        linux_free_path(&link);
        return(error);
@@ -666,8 +661,7 @@ linux_symlink(struct linux_symlink_args *args)
 int
 linux_readlink(struct linux_readlink_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -679,12 +673,12 @@ linux_readlink(struct linux_readlink_args *args)
                printf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
                    args->count);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_NOOBJ, UIO_SYSSPACE,
-          path, td);
-
-       error = kern_readlink(&nd, args->buf, args->count,
-           &args->sysmsg_result);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               error = kern_readlink(&nd, args->buf, args->count,
+                                       &args->sysmsg_result);
+       }
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -692,8 +686,7 @@ linux_readlink(struct linux_readlink_args *args)
 int
 linux_truncate(struct linux_truncate_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -705,10 +698,10 @@ linux_truncate(struct linux_truncate_args *args)
                printf(ARGS(truncate, "%s, %ld"), path,
                    (long)args->length);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_truncate(&nd, args->length);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_truncate(&nd, args->length);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -716,8 +709,7 @@ linux_truncate(struct linux_truncate_args *args)
 int
 linux_truncate64(struct linux_truncate64_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -729,10 +721,10 @@ linux_truncate64(struct linux_truncate64_args *args)
                printf(ARGS(truncate64, "%s, %lld"), path,
                    (off_t)args->length);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_truncate(&nd, args->length);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_truncate(&nd, args->length);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return error;
 }
@@ -770,8 +762,7 @@ linux_ftruncate64(struct linux_ftruncate64_args *args)
 int
 linux_link(struct linux_link_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd, linknd;
+       struct nlookupdata nd, linknd;
        char *path, *link;
        int error;
 
@@ -787,13 +778,14 @@ linux_link(struct linux_link_args *args)
        if (ldebug(link))
                printf(ARGS(link, "%s, %s"), path, link);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_NOOBJ, UIO_SYSSPACE,
-           path, td);
-       NDINIT(&linknd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ,
-           UIO_SYSSPACE, link, td);
-
-       error = kern_link(&nd, &linknd);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
+               if (error == 0)
+                       error = kern_link(&nd, &linknd);
+               nlookup_done(&linknd);
+       }
+       nlookup_done(&nd);
        linux_free_path(&path);
        linux_free_path(&link);
        return(error);
@@ -1189,8 +1181,7 @@ linux_fcntl64(struct linux_fcntl64_args *args)
 int
 linux_chown(struct linux_chown_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -1201,10 +1192,10 @@ linux_chown(struct linux_chown_args *args)
        if (ldebug(chown))
                printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_chown(&nd, args->uid, args->gid);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_chown(&nd, args->uid, args->gid);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -1212,8 +1203,7 @@ linux_chown(struct linux_chown_args *args)
 int
 linux_lchown(struct linux_lchown_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -1224,10 +1214,10 @@ linux_lchown(struct linux_lchown_args *args)
        if (ldebug(lchown))
                printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td);
-
-       error = kern_chown(&nd, args->uid, args->gid);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0)
+               error = kern_chown(&nd, args->uid, args->gid);
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
index f6f2db7..77bbb27 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.17 2004/10/12 19:20:37 dillon Exp $ */
+/* $DragonFly: src/sys/emulation/linux/linux_getcwd.c,v 1.18 2004/11/12 00:09:18 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 $ */
 
 #include <sys/uio.h>
 #include <sys/malloc.h>
 #include <sys/dirent.h>
+#include <sys/kern_syscall.h>
 #include <vfs/ufs/dir.h>       /* XXX only for DIRBLKSIZ */
 
 #include <arch_linux/linux.h>
 #include <arch_linux/linux_proto.h>
 #include "linux_util.h"
 
-static int
-linux_getcwd_scandir (struct vnode **, struct vnode **,
-    char **, char *, struct thread *);
-static int
-linux_getcwd_common (struct vnode *, struct vnode *,
-                  char **, char *, int, int, struct thread *);
-
 #define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4)
 
-/*
- * Vnode variable naming conventions in this file:
- *
- * rvp: the current root we're aiming towards.
- * lvp, *lvpp: the "lower" vnode
- * uvp, *uvpp: the "upper" vnode.
- *
- * Since all the vnodes we're dealing with are directories, and the
- * lookups are going *up* in the filesystem rather than *down*, the
- * usual "pvp" (parent) or "dvp" (directory) naming conventions are
- * too confusing.
- */
-
-/*
- * XXX Will infinite loop in certain cases if a directory read reliably
- *     returns EINVAL on last block.
- * XXX is EINVAL the right thing to return if a directory is malformed?
- */
-
-/*
- * XXX Untested vs. mount -o union; probably does the wrong thing.
- */
-
-/*
- * Find parent vnode of *lvpp, return in *uvpp
- *
- * If we care about the name, scan it looking for name of directory
- * entry pointing at lvp.
- *
- * Place the name in the buffer which starts at bufp, immediately
- * before *bpp, and move bpp backwards to point at the start of it.
- *
- * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed
- * On exit, *uvpp is either NULL or is a locked vnode reference.
- */
-static int
-linux_getcwd_scandir(lvpp, uvpp, bpp, bufp, td)
-       struct vnode **lvpp;
-       struct vnode **uvpp;
-       char **bpp;
-       char *bufp;
-       struct thread *td;
-{
-       struct proc *p = td->td_proc;
-       int     error = 0;
-       int     eofflag;
-       off_t   off;
-       int     tries;
-       struct uio uio;
-       struct iovec iov;
-       char   *dirbuf = NULL;
-       int     dirbuflen;
-       ino_t   fileno;
-       struct vattr va;
-       struct vnode *uvp = NULL;
-       struct vnode *lvp = *lvpp;      
-       struct componentname cn;
-       int len, reclen;
-       tries = 0;
-
-       KKASSERT(p);
-
-       /*
-        * If we want the filename, get some info we need while the
-        * current directory is still locked.
-        */
-       if (bufp != NULL) {
-               error = VOP_GETATTR(lvp, &va, td);
-               if (error) {
-                       vput(lvp);
-                       *lvpp = NULL;
-                       *uvpp = NULL;
-                       return error;
-               }
-       }
-
-       /*
-        * Ok, we have to do it the hard way..
-        * Next, get parent vnode using lookup of ..
-        */
-       cn.cn_nameiop = NAMEI_LOOKUP;
-       cn.cn_flags = CNP_ISLASTCN | CNP_ISDOTDOT | CNP_RDONLY;
-       cn.cn_td = td;
-       cn.cn_cred = p->p_ucred;
-       cn.cn_pnbuf = NULL;
-       cn.cn_nameptr = "..";
-       cn.cn_namelen = 2;
-       cn.cn_consume = 0;
-       
-       /*
-        * At this point, lvp is locked and will be unlocked by the lookup.
-        * On successful return, *uvpp will be locked
-        */
-       error = VOP_LOOKUP(lvp, uvpp, &cn);
-       if (error) {
-               vput(lvp);
-               *lvpp = NULL;
-               *uvpp = NULL;
-               return error;
-       }
-       uvp = *uvpp;
-
-       /* If we don't care about the pathname, we're done */
-       if (bufp == NULL) {
-               vrele(lvp);
-               *lvpp = NULL;
-               return 0;
-       }
-       
-       fileno = va.va_fileid;
-
-       dirbuflen = DIRBLKSIZ;
-       if (dirbuflen < va.va_blocksize)
-               dirbuflen = va.va_blocksize;
-       dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK);
-
-#if 0
-unionread:
-#endif
-       off = 0;
-       do {
-               /* call VOP_READDIR of parent */
-               iov.iov_base = dirbuf;
-               iov.iov_len = dirbuflen;
-
-               uio.uio_iov = &iov;
-               uio.uio_iovcnt = 1;
-               uio.uio_offset = off;
-               uio.uio_resid = dirbuflen;
-               uio.uio_segflg = UIO_SYSSPACE;
-               uio.uio_rw = UIO_READ;
-               uio.uio_td = td;
-
-               eofflag = 0;
-
-               error = VOP_READDIR(uvp, &uio, p->p_ucred, &eofflag, 0, 0);
-
-               off = uio.uio_offset;
-
-               /*
-                * Try again if NFS tosses its cookies.
-                * XXX this can still loop forever if the directory is busted
-                * such that the second or subsequent page of it always
-                * returns EINVAL
-                */
-               if ((error == EINVAL) && (tries < 3)) {
-                       off = 0;
-                       tries++;
-                       continue;       /* once more, with feeling */
-               }
-
-               if (!error) {
-                       char   *cpos;
-                       struct dirent *dp;
-                       
-                       cpos = dirbuf;
-                       tries = 0;
-                               
-                       /* scan directory page looking for matching vnode */ 
-                       for (len = (dirbuflen - uio.uio_resid); len > 0; len -= reclen) {
-                               dp = (struct dirent *) cpos;
-                               reclen = dp->d_reclen;
-
-                               /* check for malformed directory.. */
-                               if (reclen < DIRENT_MINSIZE) {
-                                       error = EINVAL;
-                                       goto out;
-                               }
-                               /*
-                                * XXX should perhaps do VOP_LOOKUP to
-                                * check that we got back to the right place,
-                                * but getting the locking games for that
-                                * right would be heinous.
-                                */
-                               if ((dp->d_type != DT_WHT) &&
-                                   (dp->d_fileno == fileno)) {
-                                       char *bp = *bpp;
-                                       bp -= dp->d_namlen;
-                                       
-                                       if (bp <= bufp) {
-                                               error = ERANGE;
-                                               goto out;
-                                       }
-                                       bcopy(dp->d_name, bp, dp->d_namlen);
-                                       error = 0;
-                                       *bpp = bp;
-                                       goto out;
-                               }
-                               cpos += reclen;
-                       }
-               }
-       } while (!eofflag);
-       error = ENOENT;
-               
-out:
-       vrele(lvp);
-       *lvpp = NULL;
-       free(dirbuf, M_TEMP);
-       return error;
-}
-
-
-/*
- * common routine shared by sys___getcwd() and linux_vn_isunder()
- */
-
-#define GETCWD_CHECK_ACCESS 0x0001
-
-static int
-linux_getcwd_common (lvp, rvp, bpp, bufp, limit, flags, td)
-       struct vnode *lvp;
-       struct vnode *rvp;
-       char **bpp;
-       char *bufp;
-       int limit;
-       int flags;
-       struct thread *td;
-{
-       struct proc *p = td->td_proc;
-       struct filedesc *fdp;
-       struct vnode *uvp = NULL;
-       char *bp = NULL;
-       int error;
-       int perms = VEXEC;
-
-       KKASSERT(p);
-       fdp = p->p_fd;
-
-       if (rvp == NULL) {
-               rvp = fdp->fd_rdir;
-               if (rvp == NULL)
-                       rvp = rootvnode;
-       }
-       
-       vref(rvp);
-       vref(lvp);
-
-       /*
-        * Error handling invariant:
-        * Before a `goto out':
-        *      lvp is either NULL, or locked and held.
-        *      uvp is either NULL, or locked and held.
-        */
-
-       error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, td);
-       if (error) {
-               vrele(lvp);
-               lvp = NULL;
-               goto out;
-       }
-       if (bufp)
-               bp = *bpp;
-       /*
-        * this loop will terminate when one of the following happens:
-        *      - we hit the root
-        *      - getdirentries or lookup fails
-        *      - we run out of space in the buffer.
-        */
-       if (lvp == rvp) {
-               if (bp)
-                       *(--bp) = '/';
-               goto out;
-       }
-       do {
-               if (lvp->v_type != VDIR) {
-                       error = ENOTDIR;
-                       goto out;
-               }
-               
-               /*
-                * access check here is optional, depending on
-                * whether or not caller cares.
-                */
-               if (flags & GETCWD_CHECK_ACCESS) {
-                       error = VOP_ACCESS(lvp, perms, p->p_ucred, td);
-                       if (error)
-                               goto out;
-                       perms = VEXEC|VREAD;
-               }
-               
-               /*
-                * step up if we're a covered vnode..
-                */
-               while (lvp->v_flag & VROOT) {
-                       struct vnode *tvp;
-
-                       if (lvp == rvp)
-                               goto out;
-                       
-                       tvp = lvp;
-                       lvp = lvp->v_mount->mnt_vnodecovered;
-                       vput(tvp);
-                       /*
-                        * hodie natus est radici frater
-                        */
-                       if (lvp == NULL) {
-                               error = ENOENT;
-                               goto out;
-                       }
-                       vref(lvp);
-                       error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, td);
-                       if (error != 0) {
-                               vrele(lvp);
-                               lvp = NULL;
-                               goto out;
-                       }
-               }
-               error = linux_getcwd_scandir(&lvp, &uvp, &bp, bufp, td);
-               if (error)
-                       goto out;
-#if DIAGNOSTIC         
-               if (lvp != NULL)
-                       panic("getcwd: oops, forgot to null lvp");
-               if (bufp && (bp <= bufp)) {
-                       panic("getcwd: oops, went back too far");
-               }
-#endif         
-               if (bp) 
-                       *(--bp) = '/';
-               lvp = uvp;
-               uvp = NULL;
-               limit--;
-       } while ((lvp != rvp) && (limit > 0)); 
-
-out:
-       if (bpp)
-               *bpp = bp;
-       if (uvp)
-               vput(uvp);
-       if (lvp)
-               vput(lvp);
-       vrele(rvp);
-       return error;
-}
-
-
 /*
  * Find pathname of process's current directory.
  *
@@ -415,66 +73,29 @@ out:
 int
 linux_getcwd(struct linux_getcwd_args *args)
 {
-       struct thread *td = curthread;
-       struct proc *p = td->td_proc;
-       struct __getcwd_args bsd;
-       caddr_t sg, bp, bend, path;
-       int error, len, lenused;
-
-       KKASSERT(p);
+       int buflen;
+       int error;
+       char *buf;
+       char *bp;
 
 #ifdef DEBUG
        printf("Linux-emul(%ld): getcwd(%p, %d)\n", (long)p->p_pid,
               args->buf, args->bufsize);
 #endif
-
-       sg = stackgap_init();
-       bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
-       bsd.buflen = SPARE_USRSPACE;
-       bsd.sysmsg_result = 0;
-       error = __getcwd(&bsd);
-       args->sysmsg_result = bsd.sysmsg_result;
-       if (!error) {
-               lenused = strlen(bsd.buf) + 1;
-               if (lenused <= args->bufsize) {
-                       args->sysmsg_result = lenused;
-                       error = copyout(bsd.buf, args->buf, lenused);
-               }
-               else
-                       error = ERANGE;
-       } else {
-               len = args->bufsize;
-
-               if (len > MAXPATHLEN*4)
-                       len = MAXPATHLEN*4;
-               else if (len < 2)
-                       return ERANGE;
-
-               path = (char *)malloc(len, M_TEMP, M_WAITOK);
-
-               bp = &path[len];
-               bend = bp;
-               *(--bp) = '\0';
-
-               /*
-                * 5th argument here is "max number of vnodes to traverse".
-                * Since each entry takes up at least 2 bytes in the output buffer,
-                * limit it to N/2 vnodes for an N byte buffer.
-                */
-
-               error = linux_getcwd_common (p->p_fd->fd_cdir, NULL,
-                   &bp, path, len/2, GETCWD_CHECK_ACCESS, td);
-
-               if (error)
-                       goto out;
-               lenused = bend - bp;
-               args->sysmsg_result = lenused;
-               /* put the result into user buffer */
-               error = copyout(bp, args->buf, lenused);
-
-out:
-               free(path, M_TEMP);     
+       buflen = args->bufsize;
+       if (buflen < 2)
+               return (EINVAL);
+       if (buflen > MAXPATHLEN)
+               buflen = MAXPATHLEN;
+
+       buf = malloc(buflen, M_TEMP, M_WAITOK);
+       bp = kern_getcwd(buf, buflen, &error);
+       if (error == 0) {
+               buflen = strlen(bp) + 1;
+               error = copyout(bp, args->buf, buflen);
+               args->sysmsg_result = buflen;
        }
+       free(buf, M_TEMP);
        return (error);
 }
 
index 006dd50..21f8434 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.21 2004/10/12 19:20:37 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.22 2004/11/12 00:09:18 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -42,7 +42,7 @@
 #include <sys/mount.h>
 #include <sys/poll.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/blist.h>
 #include <sys/reboot.h>
 #include <sys/resourcevar.h>
@@ -242,7 +242,7 @@ linux_uselib(struct linux_uselib_args *args)
 {
        struct thread *td = curthread;
        struct proc *p;
-       struct nameidata ni;
+       struct nlookupdata nd;
        struct vnode *vp;
        struct exec *a_out;
        struct vattr attr;
@@ -269,27 +269,17 @@ linux_uselib(struct linux_uselib_args *args)
        locked = 0;
        vp = NULL;
 
-       NDINIT(&ni, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF,
-               UIO_SYSSPACE, path, td);
-       error = namei(&ni);
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0)
+               error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp);
        if (error)
                goto cleanup;
-
-       vp = ni.ni_vp;
-       /*
-        * XXX - This looks like a bogus check. A LOCKLEAF namei should not
-        * succeed without returning a vnode.
-        */
-       if (vp == NULL) {
-               error = ENOEXEC;        /* ?? */
-               goto cleanup;
-       }
-       NDFREE(&ni, NDF_ONLY_PNBUF);
-
        /*
         * From here on down, we have a locked vnode that must be unlocked.
         */
-       locked++;
+       locked = 1;
 
        /* Writable? */
        if (vp->v_writecount) {
@@ -319,7 +309,7 @@ linux_uselib(struct linux_uselib_args *args)
        if (error)
                goto cleanup;
 
-       error = VOP_OPEN(vp, FREAD, p->p_ucred, td);
+       error = VOP_OPEN(vp, FREAD, p->p_ucred, NULL, td);
        if (error)
                goto cleanup;
 
@@ -462,17 +452,20 @@ linux_uselib(struct linux_uselib_args *args)
        }
 
 cleanup:
-       /* Unlock vnode if needed */
-       if (locked)
-               VOP_UNLOCK(vp, 0, td);
-
+       /* Unlock/release vnode */
+       if (vp) {
+               if (locked)
+                       VOP_UNLOCK(vp, 0, td);
+               vrele(vp);
+       }
        /* Release the kernel mapping. */
-       if (a_out)
+       if (a_out) {
                vm_map_remove(kernel_map, (vm_offset_t)a_out,
                    (vm_offset_t)a_out + PAGE_SIZE);
-
+       }
+       nlookup_done(&nd);
        linux_free_path(&path);
-       return error;
+       return (error);
 }
 
 int
@@ -740,10 +733,9 @@ struct l_utimbuf {
 int
 linux_utime(struct linux_utime_args *args)
 {
-       struct thread *td = curthread;
        struct timeval tv[2];
        struct l_utimbuf lut;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -764,10 +756,10 @@ linux_utime(struct linux_utime_args *args)
                tv[1].tv_sec = lut.l_modtime;
                tv[1].tv_usec = 0;
        }
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_utimes(&nd, args->times ? tv : NULL);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_utimes(&nd, args->times ? tv : NULL);
+       nlookup_done(&nd);
 cleanup:
        linux_free_path(&path);
        return (error);
@@ -856,8 +848,7 @@ linux_wait4(struct linux_wait4_args *args)
 int
 linux_mknod(struct linux_mknod_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -869,13 +860,15 @@ linux_mknod(struct linux_mknod_args *args)
                printf(ARGS(mknod, "%s, %d, %d"),
                    path, args->mode, args->dev);
 #endif
-       NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td);
-
-       if (args->mode & S_IFIFO) {
-               error = kern_mkfifo(&nd, args->mode);
-       } else {
-               error = kern_mknod(&nd, args->mode, args->dev);
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               if (args->mode & S_IFIFO) {
+                       error = kern_mkfifo(&nd, args->mode);
+               } else {
+                       error = kern_mknod(&nd, args->mode, args->dev);
+               }
        }
+       nlookup_done(&nd);
 
        linux_free_path(&path);
        return(error);
index 1c45433..c01dc53 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/compat/linux/linux_stats.c,v 1.22.2.3 2001/11/05 19:08:23 marcel Exp $
- * $DragonFly: src/sys/emulation/linux/linux_stats.c,v 1.14 2004/10/05 07:57:41 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/linux_stats.c,v 1.15 2004/11/12 00:09:18 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -37,7 +37,6 @@
 #include <sys/filedesc.h>
 #include <sys/proc.h>
 #include <sys/mount.h>
-#include <sys/namei.h>
 #include <sys/nlookup.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
@@ -234,9 +233,8 @@ statfs_copyout(struct statfs *statfs, struct l_statfs_buf *buf)
 int
 linux_statfs(struct linux_statfs_args *args)
 {
-       struct thread *td = curthread;
        struct statfs statfs;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -247,10 +245,10 @@ linux_statfs(struct linux_statfs_args *args)
        if (ldebug(statfs))
                printf(ARGS(statfs, "%s, *"), path);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_statfs(&nd, &statfs);
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = kern_statfs(&nd, &statfs);
+       nlookup_done(&nd);
        if (error == 0)
                error = statfs_copyout(&statfs, args->buf);
        linux_free_path(&path);
index f49e645..bc53800 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/compat/linux/linux_uid16.c,v 1.4.2.1 2001/10/21 03:57:35 marcel Exp $
- * $DragonFly: src/sys/emulation/linux/linux_uid16.c,v 1.9 2003/11/13 04:04:42 daver Exp $
+ * $DragonFly: src/sys/emulation/linux/linux_uid16.c,v 1.10 2004/11/12 00:09:18 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -32,7 +32,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kern_syscall.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/proc.h>
 #include <sys/sysproto.h>
 #include <sys/thread.h>
@@ -51,8 +51,7 @@ DUMMY(getresgid16);
 int
 linux_chown16(struct linux_chown16_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -64,10 +63,12 @@ linux_chown16(struct linux_chown16_args *args)
                printf(ARGS(chown16, "%s, %d, %d"), path, args->uid,
                    args->gid);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
-
-       error = kern_chown(&nd, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid));
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = kern_chown(&nd, CAST_NOCHG(args->uid),
+                                   CAST_NOCHG(args->gid));
+       }
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
@@ -75,8 +76,7 @@ linux_chown16(struct linux_chown16_args *args)
 int
 linux_lchown16(struct linux_lchown16_args *args)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *path;
        int error;
 
@@ -88,10 +88,12 @@ linux_lchown16(struct linux_lchown16_args *args)
                printf(ARGS(lchown16, "%s, %d, %d"), path, args->uid,
                    args->gid);
 #endif
-       NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td);
-
-       error = kern_chown(&nd, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid));
-
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               error = kern_chown(&nd, CAST_NOCHG(args->uid),
+                                   CAST_NOCHG(args->gid));
+       }
+       nlookup_done(&nd);
        linux_free_path(&path);
        return(error);
 }
index 4c49835..5ce6fdb 100644 (file)
  *
  *     from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp
  * $FreeBSD: src/sys/compat/linux/linux_util.c,v 1.12.2.2 2001/11/05 19:08:23 marcel Exp $
- * $DragonFly: src/sys/emulation/linux/linux_util.c,v 1.9 2004/09/09 20:52:19 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/linux_util.c,v 1.10 2004/11/12 00:09:18 dillon Exp $
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/malloc.h>
 #include <sys/vnode.h>
 
@@ -53,8 +53,9 @@ int
 linux_copyin_path(char *uname, char **kname, int flags)
 {
        struct thread *td = curthread;
-       struct nameidata nd, ndroot;
+       struct nlookupdata nd, ndroot;
        struct vattr vat, vatroot;
+       struct vnode *vp, *vproot;
        char *buf, *cp;
        int error, length, dummy;
 
@@ -93,17 +94,22 @@ linux_copyin_path(char *uname, char **kname, int flags)
                        goto dont_translate;
                *cp = 0;
 
-               NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td);
-               error = namei(&nd);
+               error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&nd);
+               nlookup_done(&nd);
                if (error)
                        goto dont_translate;
-               NDFREE(&nd, NDF_ONLY_PNBUF);
-               vrele(nd.ni_vp);
                *cp = '/';
                return (0);
        case LINUX_PATH_EXISTS:
-               NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td);
-               error = namei(&nd);
+               error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&nd);
+               vp = NULL;
+               if (error == 0)
+                       error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp);
+               nlookup_done(&nd);
                if (error)
                        goto dont_translate;
 
@@ -120,28 +126,32 @@ linux_copyin_path(char *uname, char **kname, int flags)
                 * emulation subtree does not exist.  Cross our fingers
                 * and return the untranslated path if something happens.
                 */
-               NDINIT(&ndroot, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE,
-                   linux_emul_path, td);
-               error = namei(&ndroot);
+               error = nlookup_init(&ndroot, linux_emul_path, UIO_SYSSPACE,
+                                       NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&ndroot);
+               vproot = NULL;
+               if (error == 0) {
+                       error = cache_vref(ndroot.nl_ncp, ndroot.nl_cred,
+                                               &vproot);
+               }
+               nlookup_done(&ndroot);
                if (error) {
-                       NDFREE(&nd, NDF_ONLY_PNBUF);
-                       vrele(nd.ni_vp);
+                       vrele(vp);
                        goto dont_translate;
                }
                
-               error = VOP_GETATTR(nd.ni_vp, &vat, td);
+               error = VOP_GETATTR(vp, &vat, td);
                if (error == 0) {
-                       error = VOP_GETATTR(ndroot.ni_vp, &vatroot, td);
+                       error = VOP_GETATTR(vproot, &vatroot, td);
                        if (error == 0) {
                                if (vat.va_fsid == vatroot.va_fsid &&
                                    vat.va_fileid == vatroot.va_fileid)
                                        error = ENOENT;
                        }
                }
-               NDFREE(&nd, NDF_ONLY_PNBUF);
-               vrele(nd.ni_vp);
-               NDFREE(&ndroot, NDF_ONLY_PNBUF);
-               vrele(ndroot.ni_vp);
+               vrele(vp);
+               vrele(vproot);
                if (error)
                        goto dont_translate;
                return (0);
@@ -165,8 +175,7 @@ done:
 int
 linux_translate_path(char *path, int size)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char *buf;
        int error, length, dummy;
 
@@ -178,16 +187,16 @@ linux_translate_path(char *path, int size)
                goto cleanup;
        
        /*
-        * If this errors, then the path probably doesn't exists.
+        * If this errors, then the path probably doesn't exist.
         */
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td);
-       error = namei(&nd);
+       error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       nlookup_done(&nd);
        if (error) {
                error = 0;
                goto cleanup;
        }
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       vrele(nd.ni_vp);
 
        /*
         * The alternate path does exist.  Return it in the buffer if
index 323a607..ad4ae4b 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.5 2004/10/12 19:20:40 dillon Exp $
+ * $DragonFly: src/sys/emulation/ndis/subr_ndis.c,v 1.6 2004/11/12 00:09:20 dillon Exp $
  */
 
 /*
@@ -64,7 +64,7 @@
 #include <sys/queue.h>
 #include <sys/proc.h>
 #include <sys/filedesc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/fcntl.h>
 #include <sys/vnode.h>
 #include <sys/kthread.h>
@@ -2543,11 +2543,12 @@ ndis_open_file(status, filehandle, filelength, filename, highestaddr)
 {
        char                    *afilename = NULL;
        struct thread           *td = curthread;
-       struct nameidata        nd;
+       struct nlookupdata      nd;
        int                     error;
        struct vattr            vat;
        struct vattr            *vap = &vat;
        ndis_fh                 *fh;
+       struct vnode            *vp;
        char                    path[MAXPATHLEN];
 
        ndis_unicode_to_ascii(filename->nus_buf,
@@ -2562,29 +2563,31 @@ ndis_open_file(status, filehandle, filelength, filename, highestaddr)
                return;
        }
 
-       NDINIT2(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, 
-               td, proc0.p_ucred);
-
-       error = vn_open(&nd, FREAD, 0);
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
+       if (error == 0)
+               error = vn_open(&nd, NULL, FREAD, 0);
        if (error) {
                *status = NDIS_STATUS_FILE_NOT_FOUND;
                free(fh, M_TEMP);
                printf("NDIS: open file %s failed: %d\n", path, error);
-               return;
+               goto done;
        }
 
-       NDFREE(&nd, NDF_ONLY_PNBUF);
+       vp = nd.nl_open_vp;
+       nd.nl_open_vp = NULL;
 
        /* Get the file size. */
-       VOP_GETATTR(nd.ni_vp, vap, td);
-       VOP_UNLOCK(nd.ni_vp, 0, td);
+       VOP_GETATTR(vp, vap, td);
+       VOP_UNLOCK(vp, 0, td);
 
-       fh->nf_vp = nd.ni_vp;
+       fh->nf_vp = vp;
        fh->nf_map = NULL;
        *filehandle = fh;
        *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
        *status = NDIS_STATUS_SUCCESS;
 
+done:
+       nlookup_done(&nd);
        return;
 }
 
index a53102e..f8b8063 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.25 2004/10/12 19:20:42 dillon Exp $
+ * $DragonFly: src/sys/emulation/svr4/Attic/svr4_misc.c,v 1.26 2004/11/12 00:09:22 dillon Exp $
  */
 
 /*
@@ -41,7 +41,7 @@
 #include <sys/dirent.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -1651,27 +1651,26 @@ svr4_sys_nice(struct svr4_sys_nice_args *uap)
 int
 svr4_sys_resolvepath(struct svr4_sys_resolvepath_args *uap)
 {
-       struct thread *td = curthread;  /* XXX */
-       struct nameidata nd;
+       struct nlookupdata nd;
        int error;
        int *retval;
 
        retval = &uap->sysmsg_result;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_SAVENAME, UIO_USERSPACE,
-           SCARG(uap, path), td);
-
-       if ((error = namei(&nd)) != 0)
-               return error;
+       error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, 0);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error)
+               goto bad;
 
-       if ((error = copyout(nd.ni_cnd.cn_pnbuf, SCARG(uap, buf),
-           SCARG(uap, bufsiz))) != 0)
+       if ((error = copyout(nd.nl_path, SCARG(uap, buf),
+                               SCARG(uap, bufsiz))) != 0) {
                goto bad;
+       }
 
-       *retval = strlen(nd.ni_cnd.cn_pnbuf) < SCARG(uap, bufsiz) ? 
-         strlen(nd.ni_cnd.cn_pnbuf) + 1 : SCARG(uap, bufsiz);
+       *retval = strlen(nd.nl_path) < SCARG(uap, bufsiz) ? 
+                 strlen(nd.nl_path) + 1 : SCARG(uap, bufsiz);
 bad:
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       vput(nd.ni_vp);
-       return error;
+       nlookup_done(&nd);
+       return (error);
 }
index 4c25497..c03819b 100644 (file)
@@ -28,7 +28,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * 
  * $FreeBSD: src/sys/svr4/svr4_sysvec.c,v 1.10.2.2 2002/07/09 14:12:43 robert Exp $
- * $DragonFly: src/sys/emulation/svr4/Attic/svr4_sysvec.c,v 1.10 2004/01/08 18:39:18 asmodai Exp $
+ * $DragonFly: src/sys/emulation/svr4/Attic/svr4_sysvec.c,v 1.11 2004/11/12 00:09:22 dillon Exp $
  */
 
 /* XXX we use functions that might not exist. */
@@ -47,7 +47,7 @@
 #include <sys/imgact_elf.h>
 #include <sys/socket.h>
 #include <sys/malloc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/vnode.h>
 #include <sys/module.h>
 #include <vm/vm.h>
@@ -251,10 +251,11 @@ svr4_emul_find(sgp, prefix, path, pbuf, cflag)
        int               cflag;
 {
        struct thread *td = curthread;  /* XXX */
-       struct nameidata         nd;
-       struct nameidata         ndroot;
+       struct nlookupdata       nd;
+       struct nlookupdata       ndroot;
        struct vattr             vat;
        struct vattr             vatroot;
+       struct vnode            *vp;
        int                      error;
        char                    *ptr, *buf, *cp;
        size_t                   sz, len;
@@ -301,24 +302,31 @@ svr4_emul_find(sgp, prefix, path, pbuf, cflag)
                for (cp = &ptr[len] - 1; *cp != '/'; cp--);
                *cp = '\0';
 
-               NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td);
-
-               if ((error = namei(&nd)) != 0) {
+               error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&nd);
+               nlookup_done(&nd);
+               if (error) {
                        free(buf, M_TEMP);
-                       return error;
+                       return (error);
                }
-               NDFREE(&nd, NDF_ONLY_PNBUF);
-
                *cp = '/';
-       }
-       else {
-               NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td);
-
-               if ((error = namei(&nd)) != 0) {
+       } else {
+               error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&nd);
+               vp = NULL;
+               if (error == 0)
+                       error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp);
+               nlookup_done(&nd);
+               if (error) {
                        free(buf, M_TEMP);
-                       return error;
+                       return (error);
                }
-               NDFREE(&nd, NDF_ONLY_PNBUF);
+               error = VOP_GETATTR(vp, &vat, td);
+               vrele(vp);
+               if (error)
+                       goto done;
 
                /*
                 * We now compare the vnode of the svr4_root to the one
@@ -328,47 +336,38 @@ svr4_emul_find(sgp, prefix, path, pbuf, cflag)
                 * root directory and never finding it, because "/" resolves
                 * to the emulation root directory. This is expensive :-(
                 */
-               NDINIT(&ndroot, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE,
-                   svr4_emul_path, td);
-
-               if ((error = namei(&ndroot)) != 0) {
-                       /* Cannot happen! */
+               error = nlookup_init(&ndroot, svr4_emul_path, UIO_SYSSPACE,
+                                       NLC_FOLLOW);
+               if (error == 0)
+                       error = nlookup(&ndroot);
+               vp = NULL;
+               if (error == 0)
+                       error = cache_vref(ndroot.nl_ncp, ndroot.nl_cred, &vp);
+               nlookup_done(&ndroot);
+               if (error) {
                        free(buf, M_TEMP);
-                       vrele(nd.ni_vp);
-                       return error;
+                       return (error);
                }
-               NDFREE(&ndroot, NDF_ONLY_PNBUF);
-
-               if ((error = VOP_GETATTR(nd.ni_vp, &vat, td)) != 0) {
-                       goto done;
-               }
-
-               if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, td))
-                   != 0) {
+               error = VOP_GETATTR(vp, &vatroot, td);
+               vrele(vp);
+               if (error)
                        goto done;
-               }
 
                if (vat.va_fsid == vatroot.va_fsid &&
                    vat.va_fileid == vatroot.va_fileid) {
                        error = ENOENT;
                        goto done;
                }
-
        }
-       if (sgp == NULL)
+       if (sgp == NULL) {
                *pbuf = buf;
-       else {
+       else {
                sz = &ptr[len] - buf;
                *pbuf = stackgap_alloc(sgp, sz + 1);
                error = copyout(buf, *pbuf, sz);
                free(buf, M_TEMP);
        }
-
-
 done:
-       vrele(nd.ni_vp);
-       if (!cflag)
-               vrele(ndroot.ni_vp);
        return error;
 }
 
index 8cc245a..4a4e531 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.22 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/imgact_elf.c,v 1.23 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -41,7 +41,7 @@
 #include <sys/mman.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/pioctl.h>
 #include <sys/procfs.h>
 #include <sys/resourcevar.h>
@@ -337,13 +337,13 @@ static int
 elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
 {
        struct {
-               struct nameidata nd;
+               struct nlookupdata nd;
                struct vattr attr;
                struct image_params image_params;
        } *tempdata;
        const Elf_Ehdr *hdr = NULL;
        const Elf_Phdr *phdr = NULL;
-       struct nameidata *nd;
+       struct nlookupdata *nd;
        struct vmspace *vmspace = p->p_vmspace;
        struct vattr *attr;
        struct image_params *imgp;
@@ -365,23 +365,23 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
        imgp->attr = attr;
        imgp->firstpage = NULL;
        imgp->image_header = NULL;
+       imgp->vp = NULL;
 
-        NDINIT(nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW,
-           UIO_SYSSPACE, file, td);
-                        
-       if ((error = namei(nd)) != 0) {
-               nd->ni_vp = NULL;
+       error = nlookup_init(nd, file, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(nd);
+       if (error == 0)
+               error = cache_vget(nd->nl_ncp, nd->nl_cred, LK_EXCLUSIVE, &imgp->vp);
+       nlookup_done(nd);
+       if (error)
                goto fail;
-       }
-       NDFREE(nd, NDF_ONLY_PNBUF);
-       imgp->vp = nd->ni_vp;
 
        /*
         * Check permissions, modes, uid, etc on the file, and "open" it.
         */
        error = exec_check_permissions(imgp);
        if (error) {
-               VOP_UNLOCK(nd->ni_vp, 0, td);
+               VOP_UNLOCK(imgp->vp, 0, td);
                goto fail;
        }
 
@@ -391,8 +391,8 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
         * its VTEXT flag, too.
         */
        if (error == 0)
-               nd->ni_vp->v_flag |= VTEXT;
-       VOP_UNLOCK(nd->ni_vp, 0, td);
+               imgp->vp->v_flag |= VTEXT;
+       VOP_UNLOCK(imgp->vp, 0, td);
        if (error)
                 goto fail;
 
@@ -429,7 +429,7 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
                                prot |= VM_PROT_READ;
 
                        error = elf_load_section(
-                                   p, vmspace, nd->ni_vp,
+                                   p, vmspace, imgp->vp,
                                    phdr[i].p_offset,
                                    (caddr_t)phdr[i].p_vaddr +
                                    rbase,
@@ -452,9 +452,10 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
 fail:
        if (imgp->firstpage)
                exec_unmap_first_page(imgp);
-       if (nd->ni_vp)
-               vrele(nd->ni_vp);
-
+       if (imgp->vp) {
+               vrele(imgp->vp);
+               imgp->vp = NULL;
+       }
        free(tempdata, M_TEMP);
 
        return error;
@@ -801,9 +802,12 @@ elf_coredump(struct proc *p, struct vnode *vp, off_t limit)
                return (error);
        fsetcred(fp, p->p_ucred);
 
+       /*
+        * XXX fixme.
+        */
        fp->f_data = (caddr_t)vp;
        fp->f_flag = O_CREAT|O_WRONLY|O_NOFOLLOW;
-       fp->f_ops = &vnops;
+       fp->f_ops = &vnode_fileops;
        fp->f_type = DTYPE_VNODE;
        VOP_UNLOCK(vp, 0, p->p_thread);
        
index 1103338..a6c9c59 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.15 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_acct.c,v 1.16 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -52,7 +52,7 @@
 #include <sys/kernel.h>
 #include <sys/sysent.h>
 #include <sys/sysctl.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/acct.h>
 #include <sys/resourcevar.h>
 #include <sys/tty.h>
@@ -123,7 +123,8 @@ acct(uap)
        } */ *uap;
 {
        struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
+       struct vnode *vp;
        int error;
 
        /* Make sure that the caller is root. */
@@ -136,29 +137,40 @@ acct(uap)
         * appending and make sure it's a 'normal'.
         */
        if (SCARG(uap, path) != NULL) {
-               NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE,
-                       SCARG(uap, path), td);
-               error = vn_open(&nd, FWRITE | O_APPEND, 0);
-               if (error)
+               error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE,
+                                       NLC_LOCKVP);
+               if (error == 0)
+                       error = vn_open(&nd, NULL, FWRITE | O_APPEND, 0);
+               if (error == 0 && nd.nl_open_vp->v_type != VREG) 
+                       error = EACCES;
+               if (error) {
+                       nlookup_done(&nd);
                        return (error);
-               NDFREE(&nd, NDF_ONLY_PNBUF);
-               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);
                }
+               vp = nd.nl_open_vp;
+               nd.nl_open_vp = NULL;
+               nlookup_done(&nd);
+
+               VOP_UNLOCK(vp, 0, td);
+       } else {
+               vp = NULL;
        }
 
        /*
         * If accounting was previously enabled, kill the old space-watcher,
-        * close the file, and (if no new file was specified, leave).
+        * close the file.
         */
        if (acctp != NULLVP || savacctp != NULLVP) {
                callout_stop(&acctwatch_handle);
                error = vn_close((acctp != NULLVP ? acctp : savacctp),
-                   FWRITE | O_APPEND, td);
+                               FWRITE | O_APPEND, td);
                acctp = savacctp = NULLVP;
        }
+
+       /*
+        * If no new file opened then leave.  We never did an nlookup so
+        * don't try cleaning it up.
+        */
        if (SCARG(uap, path) == NULL)
                return (error);
 
@@ -166,7 +178,7 @@ acct(uap)
         * Save the new accounting file vnode, and schedule the new
         * free space watcher.
         */
-       acctp = nd.ni_vp;
+       acctp = vp;
        acctwatch(NULL);
        return (error);
 }
index 4e7dc33..8bd441a 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.7 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_acl.c,v 1.8 2004/11/12 00:09:23 dillon Exp $
  */
 
 /*
@@ -40,7 +40,7 @@
 #include <sys/vnode.h>
 #include <sys/lock.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/file.h>
 #include <sys/sysent.h>
 #include <sys/errno.h>
@@ -156,18 +156,21 @@ vacl_aclcheck(struct vnode *vp, acl_type_t type, struct acl *aclp)
 int
 __acl_get_file(struct __acl_get_file_args *uap)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
+       struct vnode *vp;
        int error;
 
-       /* what flags are required here -- possible not LOCKLEAF? */
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW,
-           UIO_USERSPACE, SCARG(uap, path), td);
-       error = namei(&nd);
-       if (error)
-               return(error);
-       error = vacl_get_acl(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
-       NDFREE(&nd, 0);
+       vp = NULL;
+       error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0)
+               error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp);
+       nlookup_done(&nd);
+       if (error == 0) {
+               error = vacl_get_acl(vp, SCARG(uap, type), SCARG(uap, aclp));
+               vrele(vp);
+       }
        return (error);
 }
 
@@ -177,17 +180,21 @@ __acl_get_file(struct __acl_get_file_args *uap)
 int
 __acl_set_file(struct __acl_set_file_args *uap)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
+       struct vnode *vp;
        int error;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, 
-           UIO_USERSPACE, SCARG(uap, path), td);
-       error = namei(&nd);
-       if (error)
-               return(error);
-       error = vacl_set_acl(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
-       NDFREE(&nd, 0);
+       vp = NULL;
+       error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0)
+               error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp);
+       nlookup_done(&nd);
+       if (error == 0) {
+               error = vacl_set_acl(vp, SCARG(uap, type), SCARG(uap, aclp));
+               vrele(vp);
+       }
        return (error);
 }
 
@@ -233,17 +240,22 @@ __acl_set_fd(struct __acl_set_fd_args *uap)
 int
 __acl_delete_file(struct __acl_delete_file_args *uap)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
+       struct vnode *vp;
        int error;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW,
-           UIO_USERSPACE, SCARG(uap, path), td);
-       error = namei(&nd);
-       if (error)
-               return(error);
-       error = vacl_delete(nd.ni_vp, SCARG(uap, type));
-       NDFREE(&nd, 0);
+       vp = NULL;
+       error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0)
+               error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp);
+       nlookup_done(&nd);
+
+       if (error == 0) {
+               error = vacl_delete(vp, SCARG(uap, type));
+               vrele(vp);
+       }
        return (error);
 }
 
@@ -271,17 +283,22 @@ __acl_delete_fd(struct __acl_delete_fd_args *uap)
 int
 __acl_aclcheck_file(struct __acl_aclcheck_file_args *uap)
 {
-       struct thread *td = curthread;
-       struct nameidata        nd;
-       int     error;
+       struct nlookupdata nd;
+       struct vnode *vp;
+       int error;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW,
-           UIO_USERSPACE, SCARG(uap, path), td);
-       error = namei(&nd);
-       if (error)
-               return(error);
-       error = vacl_aclcheck(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
-       NDFREE(&nd, 0);
+       vp = NULL;
+       error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0)
+               error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp);
+       nlookup_done(&nd);
+
+       if (error == 0) {
+               error = vacl_aclcheck(vp, SCARG(uap, type), SCARG(uap, aclp));
+               vrele(vp);
+       }
        return (error);
 }
 
index d64e348..56c8be6 100644 (file)
@@ -70,7 +70,7 @@
  *
  *     @(#)kern_clock.c        8.5 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/kern_clock.c,v 1.105.2.10 2002/10/17 13:19:40 maxim Exp $
- * $DragonFly: src/sys/kern/kern_clock.c,v 1.24 2004/09/17 00:18:09 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_clock.c,v 1.25 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include "opt_ntp.h"
@@ -279,10 +279,14 @@ hardclock(systimer_t info, struct intrframe *frame)
         * stay in synch.
         *
         * Note that we never allow info->time (aka gd->gd_hardclock.time)
-        * to reverse index gd_cpuclock_base.
+        * to reverse index gd_cpuclock_base, but that it is possible for
+        * it to temporarily get behind in the seconds if something in the
+        * system locks interrupts for a long period of time.  Since periodic
+        * timers count events, though everything should resynch again
+        * immediately.
         */
        cputicks = info->time - gd->gd_cpuclock_base;
-       if (cputicks > cputimer_freq) {
+       if (cputicks >= cputimer_freq) {
                ++gd->gd_time_seconds;
                gd->gd_cpuclock_base += cputimer_freq;
        }
@@ -676,6 +680,12 @@ SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD,
  * Each cpu independantly maintains the current time of day, so all
  * we need to do to protect ourselves from changes is to do a loop
  * check on the seconds field changing out from under us.
+ *
+ * The system timer maintains a 32 bit count and due to various issues
+ * it is possible for the calculated delta to occassionally exceed
+ * cputimer_freq.  If this occurs the cputimer_freq64_nsec multiplication
+ * can easily overflow, so we deal with the case.  For uniformity we deal
+ * with the case in the usec case too.
  */
 void
 getmicrouptime(struct timeval *tvp)
@@ -687,6 +697,11 @@ getmicrouptime(struct timeval *tvp)
                tvp->tv_sec = gd->gd_time_seconds;
                delta = gd->gd_hardclock.time - gd->gd_cpuclock_base;
        } while (tvp->tv_sec != gd->gd_time_seconds);
+
+       if (delta >= cputimer_freq) {
+               tvp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
+       }
        tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32;
        if (tvp->tv_usec >= 1000000) {
                tvp->tv_usec -= 1000000;
@@ -704,11 +719,12 @@ getnanouptime(struct timespec *tsp)
                tsp->tv_sec = gd->gd_time_seconds;
                delta = gd->gd_hardclock.time - gd->gd_cpuclock_base;
        } while (tsp->tv_sec != gd->gd_time_seconds);
-       tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32;
-       if (tsp->tv_nsec >= 1000000000) {
-               tsp->tv_nsec -= 1000000000;
-               ++tsp->tv_sec;
+
+       if (delta >= cputimer_freq) {
+               tsp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
        }
+       tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32;
 }
 
 void
@@ -721,11 +737,12 @@ microuptime(struct timeval *tvp)
                tvp->tv_sec = gd->gd_time_seconds;
                delta = cputimer_count() - gd->gd_cpuclock_base;
        } while (tvp->tv_sec != gd->gd_time_seconds);
-       tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32;
-       if (tvp->tv_usec >= 1000000) {
-               tvp->tv_usec -= 1000000;
-               ++tvp->tv_sec;
+
+       if (delta >= cputimer_freq) {
+               tvp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
        }
+       tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32;
 }
 
 void
@@ -738,11 +755,12 @@ nanouptime(struct timespec *tsp)
                tsp->tv_sec = gd->gd_time_seconds;
                delta = cputimer_count() - gd->gd_cpuclock_base;
        } while (tsp->tv_sec != gd->gd_time_seconds);
-       tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32;
-       if (tsp->tv_nsec >= 1000000000) {
-               tsp->tv_nsec -= 1000000000;
-               ++tsp->tv_sec;
+
+       if (delta >= cputimer_freq) {
+               tsp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
        }
+       tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32;
 }
 
 /*
@@ -759,6 +777,11 @@ getmicrotime(struct timeval *tvp)
                tvp->tv_sec = gd->gd_time_seconds;
                delta = gd->gd_hardclock.time - gd->gd_cpuclock_base;
        } while (tvp->tv_sec != gd->gd_time_seconds);
+
+       if (delta >= cputimer_freq) {
+               tvp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
+       }
        tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32;
 
        tvp->tv_sec += basetime.tv_sec;
@@ -779,6 +802,11 @@ getnanotime(struct timespec *tsp)
                tsp->tv_sec = gd->gd_time_seconds;
                delta = gd->gd_hardclock.time - gd->gd_cpuclock_base;
        } while (tsp->tv_sec != gd->gd_time_seconds);
+
+       if (delta >= cputimer_freq) {
+               tsp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
+       }
        tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32;
 
        tsp->tv_sec += basetime.tv_sec;
@@ -799,6 +827,11 @@ microtime(struct timeval *tvp)
                tvp->tv_sec = gd->gd_time_seconds;
                delta = cputimer_count() - gd->gd_cpuclock_base;
        } while (tvp->tv_sec != gd->gd_time_seconds);
+
+       if (delta >= cputimer_freq) {
+               tvp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
+       }
        tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32;
 
        tvp->tv_sec += basetime.tv_sec;
@@ -819,6 +852,11 @@ nanotime(struct timespec *tsp)
                tsp->tv_sec = gd->gd_time_seconds;
                delta = cputimer_count() - gd->gd_cpuclock_base;
        } while (tsp->tv_sec != gd->gd_time_seconds);
+
+       if (delta >= cputimer_freq) {
+               tsp->tv_sec += delta / cputimer_freq;
+               delta %= cputimer_freq;
+       }
        tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32;
 
        tsp->tv_sec += basetime.tv_sec;
@@ -941,7 +979,8 @@ pps_event(struct pps_state *pps, sysclock_t count, int event)
                ts.tv_sec = gd->gd_time_seconds;
                delta = count - gd->gd_cpuclock_base;
        } while (ts.tv_sec != gd->gd_time_seconds);
-       if (delta > cputimer_freq) {
+
+       if (delta >= cputimer_freq) {
                ts.tv_sec += delta / cputimer_freq;
                delta %= cputimer_freq;
        }
@@ -968,7 +1007,13 @@ pps_event(struct pps_state *pps, sysclock_t count, int event)
                /* magic, at its best... */
                tcount = count - pps->ppscount[2];
                pps->ppscount[2] = count;
-               delta = (cputimer_freq64_nsec * tcount) >> 32;
+               if (tcount >= cputimer_freq) {
+                       delta = 1000000000 * (tcount / cputimer_freq) +
+                               (cputimer_freq64_nsec * 
+                                (tcount % cputimer_freq)) >> 32;
+               } else {
+                       delta = (cputimer_freq64_nsec * tcount) >> 32;
+               }
                hardpps(tsp, delta);
        }
 #endif
index 098616d..2967202 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.30 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_descrip.c,v 1.31 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -51,7 +51,7 @@
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/filio.h>
@@ -876,62 +876,78 @@ fdavail(struct proc *p, int n)
  *     is allocated and the file pointer is returned unassociated with
  *     any process.  resultfd is only used if p is not NULL and may
  *     separately be NULL indicating that you don't need the returned fd.
+ *
+ *     A held file pointer is returned.  If a descriptor has been allocated
+ *     an additional hold on the fp will be made due to the fd_ofiles[]
+ *     reference.
  */
 int
 falloc(struct proc *p, struct file **resultfp, int *resultfd)
 {
-       struct file *fp, *fq;
-       int error, i;
        static struct timeval lastfail;
        static int curfail;
+       struct file *fp;
+       int error;
 
+       fp = NULL;
+
+       /*
+        * Handle filetable full issues and root overfill.
+        */
        if (nfiles >= maxfiles - maxfilesrootres &&
            ((p && p->p_ucred->cr_ruid != 0) || nfiles >= maxfiles)) {
                if (ppsratecheck(&lastfail, &curfail, 1)) {
                        printf("kern.maxfiles limit exceeded by uid %d, please see tuning(7).\n",
                                (p ? p->p_ucred->cr_ruid : -1));
                }
-               return (ENFILE);
+               error = ENFILE;
+               goto done;
        }
+
        /*
         * Allocate a new file descriptor.
-        * If the process has file descriptor zero open, add to the list
-        * of open files at that point, otherwise put it at the front of
-        * the list of open files.
         */
        nfiles++;
        fp = malloc(sizeof(struct file), M_FILE, M_WAITOK | M_ZERO);
-
-       /*
-        * wait until after malloc (which may have blocked) returns before
-        * allocating the slot, else a race might have shrunk it if we had
-        * allocated it before the malloc.
-        */
-       i = -1;
-       if (p && (error = fdalloc(p, 0, &i))) {
-               nfiles--;
-               free(fp, M_FILE);
-               return (error);
-       }
        fp->f_count = 1;
        fp->f_ops = &badfileops;
        fp->f_seqcount = 1;
-       if (p) {
+       if (p)
                fp->f_cred = crhold(p->p_ucred);
-               if ((fq = p->p_fd->fd_ofiles[0]) != NULL) {
-                       LIST_INSERT_AFTER(fq, fp, f_list);
-               } else {
-                       LIST_INSERT_HEAD(&filehead, fp, f_list);
+       else
+               fp->f_cred = crhold(proc0.p_ucred);
+       LIST_INSERT_HEAD(&filehead, fp, f_list);
+       if (resultfd) {
+               if ((error = fsetfd(p, fp, resultfd)) != 0) {
+                       fdrop(fp, p->p_thread);
+                       fp = NULL;
                }
-               p->p_fd->fd_ofiles[i] = fp;
        } else {
-               fp->f_cred = crhold(proc0.p_ucred);
-               LIST_INSERT_HEAD(&filehead, fp, f_list);
+               error = 0;
        }
-       if (resultfp)
-               *resultfp = fp;
-       if (resultfd)
-               *resultfd = i;
+done:
+       *resultfp = fp;
+       return (0);
+}
+
+/*
+ * Associate a file pointer with a file descriptor.  On success the fp
+ * will have an additional ref representing the fd_ofiles[] association.
+ */
+int
+fsetfd(struct proc *p, struct file *fp, int *resultfd)
+{
+       int i;
+       int error;
+
+       KKASSERT(p);
+
+       i = -1;
+       if ((error = fdalloc(p, 0, &i)) == 0) {
+               fhold(fp);
+               p->p_fd->fd_ofiles[i] = fp;
+       }
+       *resultfd = i;
        return (0);
 }
 
@@ -1334,7 +1350,7 @@ int
 fdcheckstd(struct proc *p)
 {
        struct thread *td = p->p_thread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        struct filedesc *fdp;
        struct file *fp;
        register_t retval;
@@ -1346,33 +1362,30 @@ fdcheckstd(struct proc *p)
        devnull = -1;
        error = 0;
        for (i = 0; i < 3; i++) {
-               if (fdp->fd_ofiles[i] != NULL)
-                       continue;
-               if (devnull < 0) {
-                       error = falloc(p, &fp, &fd);
-                       if (error != 0)
-                               break;
-                       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, 
-                          "/dev/null", td);
-                       flags = FREAD | FWRITE;
-                       error = vn_open(&nd, flags, 0);
-                       if (error != 0) {
-                               fdp->fd_ofiles[i] = NULL;
-                               fdrop(fp, td);
-                               break;
-                       }
-                       NDFREE(&nd, NDF_ONLY_PNBUF);
-                       fp->f_data = (caddr_t)nd.ni_vp;
-                       fp->f_flag = flags;
-                       fp->f_ops = &vnops;
-                       fp->f_type = DTYPE_VNODE;
-                       VOP_UNLOCK(nd.ni_vp, 0, td);
-                       devnull = fd;
-               } else {
-                       error = kern_dup(DUP_FIXED, devnull, i, &retval);
-                       if (error != 0)
-                               break;
-               }
+               if (fdp->fd_ofiles[i] != NULL)
+                       continue;
+               if (devnull < 0) {
+                       if ((error = falloc(p, &fp, NULL)) != 0)
+                               break;
+
+                       error = nlookup_init(&nd, "/dev/null", UIO_SYSSPACE,
+                                               NLC_FOLLOW|NLC_LOCKVP);
+                       flags = FREAD | FWRITE;
+                       if (error == 0)
+                               error = vn_open(&nd, fp, flags, 0);
+                       if (error == 0)
+                               error = fsetfd(p, fp, &fd);
+                       fdrop(fp, td);
+                       nlookup_done(&nd);
+                       if (error)
+                               break;
+                       KKASSERT(i == fd);
+                       devnull = fd;
+               } else {
+                       error = kern_dup(DUP_FIXED, devnull, i, &retval);
+                       if (error != 0)
+                               break;
+               }
        }
        return (error);
 }
index 6559400..c75c329 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_event.c,v 1.2.2.10 2004/04/04 07:03:14 cperciva Exp $
- * $DragonFly: src/sys/kern/kern_event.c,v 1.12 2004/05/13 23:49:23 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_event.c,v 1.13 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -377,6 +377,7 @@ kqueue(struct kqueue_args *uap)
        TAILQ_INIT(&kq->kq_head);
        fp->f_data = (caddr_t)kq;
        uap->sysmsg_result = fd;
+       fdrop(fp, curthread);
        if (fdp->fd_knlistsize < 0)
                fdp->fd_knlistsize = 0;         /* this process has a kq */
        kq->kq_fdp = fdp;
index 4ffc0e3..5ff14ee 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.28 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_exec.c,v 1.29 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -44,7 +44,7 @@
 #include <sys/proc.h>
 #include <sys/signalvar.h>
 #include <sys/pioctl.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/sfbuf.h>
 #include <sys/sysent.h>
 #include <sys/shm.h>
@@ -117,7 +117,7 @@ print_execve_args(struct image_args *args)
 static const struct execsw **execsw;
 
 int
-kern_execve(struct nameidata *ndp, struct image_args *args)
+kern_execve(struct nlookupdata *nd, struct image_args *args)
 {
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
@@ -164,13 +164,17 @@ kern_execve(struct nameidata *ndp, struct image_args *args)
 interpret:
 
        /*
-        * Translate the file name. namei() returns a vnode pointer
-        *      in ni_vp amoung other things.
+        * Translate the file name to a vnode.  Unlock the cache entry to
+        * improve parallelism for programs exec'd in parallel.
         */
-       if ((error = namei(ndp)) != 0)
+       if ((error = nlookup(nd)) != 0)
+               goto exec_fail;
+       error = cache_vget(nd->nl_ncp, nd->nl_cred, LK_EXCLUSIVE, &imgp->vp);
+       KKASSERT(nd->nl_flags & NLC_NCPISLOCKED);
+       nd->nl_flags &= ~NLC_NCPISLOCKED;
+       cache_unlock(nd->nl_ncp);
+       if (error)
                goto exec_fail;
-
-       imgp->vp = ndp->ni_vp;
 
        /*
         * Check file permissions (also 'opens' file)
@@ -233,13 +237,13 @@ interpret:
         */
        if (imgp->interpreted) {
                exec_unmap_first_page(imgp);
-               /* free name buffer and old vnode */
-               NDFREE(ndp, NDF_ONLY_PNBUF);
-               vrele(ndp->ni_vp);
-               /* set new name to that of the interpreter */
-               NDINIT(ndp, NAMEI_LOOKUP, 
-                   CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME,
-                   UIO_SYSSPACE, imgp->interpreter_name, td);
+               nlookup_done(nd);
+               vrele(imgp->vp);
+               imgp->vp = NULL;
+               error = nlookup_init(nd, imgp->interpreter_name, UIO_SYSSPACE,
+                                       NLC_FOLLOW);
+               if (error)
+                       goto exec_fail;
                goto interpret;
        }
 
@@ -306,8 +310,8 @@ interpret:
        execsigs(p);
 
        /* name this process - nameiexec(p, ndp) */
-       len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN);
-       bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len);
+       len = min(nd->nl_ncp->nc_nlen, MAXCOMLEN);
+       bcopy(nd->nl_ncp->nc_name, p->p_comm, len);
        p->p_comm[len] = 0;
 
        /*
@@ -385,8 +389,8 @@ interpret:
         */
        if (p->p_textvp)                /* release old reference */
                vrele(p->p_textvp);
-       vref(ndp->ni_vp);
-       p->p_textvp = ndp->ni_vp;
+       p->p_textvp = imgp->vp;
+       vref(p->p_textvp);
 
         /*
          * Notify others that we exec'd, and clear the P_INEXEC flag
@@ -435,8 +439,8 @@ exec_fail_dealloc:
                exec_unmap_first_page(imgp);
 
        if (imgp->vp) {
-               NDFREE(ndp, NDF_ONLY_PNBUF);
                vrele(imgp->vp);
+               imgp->vp = NULL;
        }
 
        if (error == 0) {
@@ -463,19 +467,18 @@ exec_fail:
 int
 execve(struct execve_args *uap)
 {
-       struct thread *td = curthread;
-       struct nameidata nd;
+       struct nlookupdata nd;
        struct image_args args;
        int error;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME,
-           UIO_USERSPACE, uap->fname, td);
-
-       error = exec_copyin_args(&args, uap->fname, PATH_USERSPACE,
-                               uap->argv, uap->envv);
+       error = nlookup_init(&nd, uap->fname, UIO_USERSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = exec_copyin_args(&args, uap->fname, PATH_USERSPACE,
+                                       uap->argv, uap->envv);
+       }
        if (error == 0)
                error = kern_execve(&nd, &args);
-
+       nlookup_done(&nd);
        exec_free_args(&args);
 
        /*
@@ -497,11 +500,24 @@ exec_map_first_page(struct image_params *imgp)
        vm_page_t ma[VM_INITIAL_PAGEIN];
        vm_page_t m;
        vm_object_t object;
+       int error;
 
        if (imgp->firstpage)
                exec_unmap_first_page(imgp);
 
-       VOP_GETVOBJECT(imgp->vp, &object);
+       /*
+        * XXX the callers should really use vn_open so we don't have to
+        * do this junk.
+        */
+       if ((error = VOP_GETVOBJECT(imgp->vp, &object)) != 0) {
+               if (vn_canvmio(imgp->vp) == TRUE) {
+                       error = vfs_object_create(imgp->vp, curthread);
+                       if (error == 0)
+                               error = VOP_GETVOBJECT(imgp->vp, &object);
+               }
+       }
+       if (error)
+               return (EIO);
 
        /*
         * We shouldn't need protection for vm_page_grab() but we certainly
@@ -906,7 +922,7 @@ exec_check_permissions(imgp)
         * Call filesystem specific open routine (which does nothing in the
         * general case).
         */
-       error = VOP_OPEN(vp, FREAD, p->p_ucred, td);
+       error = VOP_OPEN(vp, FREAD, p->p_ucred, NULL, td);
        if (error)
                return (error);
 
index 79856b3..8eda3c7 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.8 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_fp.c,v 1.9 2004/11/12 00:09:23 dillon Exp $
  */
 
 /*
@@ -54,7 +54,7 @@
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/filio.h>
@@ -96,7 +96,7 @@ typedef struct file *file_t;
 int
 fp_open(const char *path, int flags, int mode, file_t *fpp)
 {
-    struct nameidata nd;
+    struct nlookupdata nd;
     struct thread *td;
     struct file *fp;
     int error;
@@ -106,21 +106,15 @@ fp_open(const char *path, int flags, int mode, file_t *fpp)
     fp = *fpp;
     td = curthread;
     if (td->td_proc) {
-       if ((flags & O_ROOTCRED) == 0 && td->td_proc)
+       if ((flags & O_ROOTCRED) == 0)
            fsetcred(fp, td->td_proc->p_ucred);
-       NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td);
-    } else {
-       NDINIT2(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td, proc0.p_ucred);
     }
+    error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_LOCKVP);
     flags = FFLAGS(flags);
-    if ((error = vn_open(&nd, flags, mode)) == 0) {
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       fp->f_data = (caddr_t)nd.ni_vp;
-       fp->f_flag = flags;
-       fp->f_ops = &vnops;
-       fp->f_type = DTYPE_VNODE;
-       VOP_UNLOCK(nd.ni_vp, 0, td);
-    } else {
+    if (error == 0)
+       error = vn_open(&nd, fp, flags, mode);
+    nlookup_done(&nd);
+    if (error) {
        fdrop(fp, td);
        *fpp = NULL;
     }
@@ -129,8 +123,14 @@ fp_open(const char *path, int flags, int mode, file_t *fpp)
 
 
 /*
- * fp_vpopen():        open a file pointer given a vnode.  The vnode must be locked.
- * The vnode will be returned unlocked whether an error occurs or not.
+ * fp_vpopen():        convert a vnode to a file pointer, call VOP_OPEN() on the
+ * the vnode.  The vnode must be refd and locked.
+ *
+ * On success the vnode's ref is inherited by the file pointer and the caller
+ * should not vrele() it, and the vnode is unlocked.
+ *
+ * On failure the vnode remains locked and refd and the caller is responsible
+ * for vput()ing it.
  */
 int
 fp_vpopen(struct vnode *vp, int flags, file_t *fpp)
@@ -140,7 +140,6 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp)
     int vmode;
     int error;
 
-    *fpp = NULL;
     td = curthread;
 
     /*
@@ -148,22 +147,22 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp)
      */
     if (vp->v_type == VLNK) {
        error = EMLINK;
-       goto done;
+       goto bad2;
     }
     if (vp->v_type == VSOCK) {
        error = EOPNOTSUPP;
-       goto done;
+       goto bad2;
     }
     flags = FFLAGS(flags);
     vmode = 0;
     if (flags & (FWRITE | O_TRUNC)) {
        if (vp->v_type == VDIR) {
            error = EISDIR;
-           goto done;
+           goto bad2;
        }
        error = vn_writechk(vp);
        if (error)
-           goto done;
+           goto bad2;
        vmode |= VWRITE;
     }
     if (flags & FREAD)
@@ -171,41 +170,50 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp)
     if (vmode) {
        error = VOP_ACCESS(vp, vmode, td->td_proc->p_ucred, td);
        if (error)
-           goto done;
-    }
-    error = VOP_OPEN(vp, flags, td->td_proc->p_ucred, td);
-    if (error)
-       goto done;
-    /*
-     * Make sure that a VM object is created for VMIO support.
-     */
-    if (vn_canvmio(vp) == TRUE) {
-       if ((error = vfs_object_create(vp, td)) != 0)
-           goto done;
+           goto bad2;
     }
 
     /*
      * File pointer setup
      */
     if ((error = falloc(NULL, fpp, NULL)) != 0)
-       goto done;
+       goto bad2;
     fp = *fpp;
     if ((flags & O_ROOTCRED) == 0 && td->td_proc)
        fsetcred(fp, td->td_proc->p_ucred);
     fp->f_data = (caddr_t)vp;
     fp->f_flag = flags;
-    fp->f_ops = &vnops;
+    fp->f_ops = &vnode_fileops;
     fp->f_type = DTYPE_VNODE;
 
+    error = VOP_OPEN(vp, flags, td->td_proc->p_ucred, fp, td);
+    if (error)
+       goto bad1;
+
     /*
-     * All done, set return value and update v_writecount now that no more
-     * errors can occur.
+     * Make sure that a VM object is created for VMIO support.
+     */
+    if (vn_canvmio(vp) == TRUE) {
+       if ((error = vfs_object_create(vp, td)) != 0) {
+           VOP_CLOSE(vp, flags, td);
+           goto bad1;
+       }
+    }
+
+    /*
+     * All done, update v_writecount now that no more errors can occur.
      */
-    *fpp = fp;
     if (flags & FWRITE)
        vp->v_writecount++;
-done:
     VOP_UNLOCK(vp, 0, td);
+    return (0);
+bad1:
+    fp->f_ops = &badfileops;   /* open failed, don't close */
+    fp->f_data = NULL;
+    fdrop(fp, td);
+    /* leave the vnode intact, but fall through and unlock it anyway */
+bad2:
+    *fpp = NULL;
     return (error);
 }
 
index b83585e..ffb563d 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.16 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_ktrace.c,v 1.17 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -44,7 +44,7 @@
 #include <sys/proc.h>
 #include <sys/fcntl.h>
 #include <sys/lock.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/vnode.h>
 #include <sys/ktrace.h>
 #include <sys/malloc.h>
@@ -253,27 +253,28 @@ ktrace(struct ktrace_args *uap)
        int descend = uap->ops & KTRFLAG_DESCEND;
        int ret = 0;
        int error = 0;
-       struct nameidata nd;
+       struct nlookupdata nd;
 
        curp->p_traceflag |= KTRFAC_ACTIVE;
        if (ops != KTROP_CLEAR) {
                /*
                 * an operation which requires a file argument.
                 */
-               NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, uap->fname, td);
-               error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0);
+               error = nlookup_init(&nd, uap->fname, 
+                                       UIO_USERSPACE, NLC_LOCKVP);
+               if (error == 0)
+                       error = vn_open(&nd, NULL, FREAD|FWRITE|O_NOFOLLOW, 0);
+               if (error == 0 && nd.nl_open_vp->v_type != VREG)
+                       error = EACCES;
                if (error) {
                        curp->p_traceflag &= ~KTRFAC_ACTIVE;
+                       nlookup_done(&nd);
                        return (error);
                }
-               NDFREE(&nd, NDF_ONLY_PNBUF);
-               vp = nd.ni_vp;
+               vp = nd.nl_open_vp;
+               nd.nl_open_vp = NULL;
+               nlookup_done(&nd);
                VOP_UNLOCK(vp, 0, td);
-               if (vp->v_type != VREG) {
-                       (void) vn_close(vp, FREAD|FWRITE, td);
-                       curp->p_traceflag &= ~KTRFAC_ACTIVE;
-                       return (EACCES);
-               }
        }
        /*
         * Clear all uses of the tracefile.  XXX umm, what happens to the
@@ -285,7 +286,7 @@ ktrace(struct ktrace_args *uap)
                                if (ktrcanset(curp, p) && p->p_tracep == vp) {
                                        p->p_tracep = NULL;
                                        p->p_traceflag = 0;
-                                       (void) vn_close(vp, FREAD|FWRITE, td);
+                                       vn_close(vp, FREAD|FWRITE, td);
                                } else {
                                        error = EPERM;
                                }
@@ -312,12 +313,12 @@ ktrace(struct ktrace_args *uap)
                        error = ESRCH;
                        goto done;
                }
-               LIST_FOREACH(p, &pg->pg_members, p_pglist)
+               LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                        if (descend)
                                ret |= ktrsetchildren(curp, p, ops, facs, vp);
                        else
                                ret |= ktrops(curp, p, ops, facs, vp);
-
+               }
        } else {
                /*
                 * by pid
@@ -336,7 +337,7 @@ ktrace(struct ktrace_args *uap)
                error = EPERM;
 done:
        if (vp != NULL)
-               (void) vn_close(vp, FWRITE, td);
+               vn_close(vp, FWRITE, td);
        curp->p_traceflag &= ~KTRFAC_ACTIVE;
        return (error);
 #else
index de28449..e9579b4 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.19 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_linker.c,v 1.20 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include "opt_ddb.h"
@@ -41,7 +41,7 @@
 #include <sys/linker.h>
 #include <sys/fcntl.h>
 #include <sys/libkern.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/vnode.h>
 #include <sys/sysctl.h>
 
@@ -1096,8 +1096,7 @@ linker_strdup(const char *str)
 char *
 linker_search_path(const char *name)
 {
-    struct nameidata   nd;
-    struct thread      *td = curthread;
+    struct nlookupdata nd;
     char               *cp, *ep, *result;
     int                        error;
     enum vtype         type;
@@ -1124,16 +1123,17 @@ linker_search_path(const char *name)
         * Attempt to open the file, and return the path if we succeed and it's
         * a regular file.
         */
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, result, td);
-       error = vn_open(&nd, FREAD, 0);
+       error = nlookup_init(&nd, result, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
+       if (error == 0)
+           error = vn_open(&nd, NULL, FREAD, 0);
        if (error == 0) {
-           NDFREE(&nd, NDF_ONLY_PNBUF);
-           type = nd.ni_vp->v_type;
-           VOP_UNLOCK(nd.ni_vp, 0, td);
-           vn_close(nd.ni_vp, FREAD, td);
-           if (type == VREG)
-               return(result);
+           type = nd.nl_open_vp->v_type;
+           if (type == VREG) {
+               nlookup_done(&nd);
+               return (result);
+           }
        }
+       nlookup_done(&nd);
        free(result, M_LINKER);
 
        if (*ep == 0)
index ea0a838..8e5ef2d 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.31 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_sig.c,v 1.32 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -51,7 +51,7 @@
 #include <sys/vnode.h>
 #include <sys/event.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/pioctl.h>
 #include <sys/systm.h>
 #include <sys/acct.h>
@@ -1451,7 +1451,7 @@ coredump(struct proc *p)
        struct ucred *cred = p->p_ucred;
        struct thread *td = p->p_thread;
        struct flock lf;
-       struct nameidata nd;
+       struct nlookupdata nd;
        struct vattr vattr;
        int error, error1;
        char *name;                     /* name of corefile */
@@ -1477,13 +1477,17 @@ coredump(struct proc *p)
        name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid);
        if (name == NULL)
                return (EINVAL);
-       NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, name, td);
-       error = vn_open(&nd, O_CREAT | FWRITE | O_NOFOLLOW, S_IRUSR | S_IWUSR);
+       error = nlookup_init(&nd, name, UIO_SYSSPACE, NLC_LOCKVP);
+       if (error == 0)
+               error = vn_open(&nd, NULL, O_CREAT | FWRITE | O_NOFOLLOW, S_IRUSR | S_IWUSR);
        free(name, M_TEMP);
-       if (error)
+       if (error) {
+               nlookup_done(&nd);
                return (error);
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       vp = nd.ni_vp;
+       }
+       vp = nd.nl_open_vp;
+       nd.nl_open_vp = NULL;
+       nlookup_done(&nd);
 
        VOP_UNLOCK(vp, 0, td);
        lf.l_whence = SEEK_SET;
@@ -1510,8 +1514,7 @@ coredump(struct proc *p)
        VOP_UNLOCK(vp, 0, td);
 
        error = p->p_sysent->sv_coredump ?
-         p->p_sysent->sv_coredump(p, vp, limit) :
-         ENOSYS;
+                 p->p_sysent->sv_coredump(p, vp, limit) : ENOSYS;
 
 out1:
        lf.l_type = F_UNLCK;
index af5e824..97d75a8 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.12 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/link_aout.c,v 1.13 2004/11/12 00:09:23 dillon Exp $
  */
 
 #ifndef __alpha__
@@ -37,7 +37,7 @@
 #include <sys/types.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/fcntl.h>
 #include <sys/vnode.h>
 #include <sys/linker.h>
@@ -196,9 +196,10 @@ link_aout_load_module(const char* filename, linker_file_t* result)
 static int
 link_aout_load_file(const char* filename, linker_file_t* result)
 {
-    struct nameidata nd;
+    struct nlookupdata nd;
     struct thread *td = curthread;
     struct proc *p = td->td_proc;
+    struct vnode *vp;
     int error = 0;
     int resid;
     struct exec header;
@@ -217,17 +218,22 @@ link_aout_load_file(const char* filename, linker_file_t* result)
     pathname = linker_search_path(filename);
     if (pathname == NULL)
        return ENOENT;
-    NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, pathname, td);
-    error = vn_open(&nd, FREAD, 0);
+    error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
+    if (error == 0)
+       error = vn_open(&nd, NULL, FREAD, 0);
     free(pathname, M_LINKER);
-    if (error)
+    if (error) {
+       nlookup_done(&nd);
        return error;
-    NDFREE(&nd, NDF_ONLY_PNBUF);
+    }
+    vp = nd.nl_open_vp;
+    nd.nl_open_vp = NULL;
+    nlookup_done(&nd);
 
     /*
      * Read the a.out header from the file.
      */
-    error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0,
+    error = vn_rdwr(UIO_READ, vp, (void*) &header, sizeof header, 0,
                    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
     if (error)
        goto out;
@@ -246,8 +252,8 @@ link_aout_load_file(const char* filename, linker_file_t* result)
     /*
      * Read the text and data sections and zero the bss.
      */
-    VOP_LEASE(nd.ni_vp, td, p->p_ucred, LEASE_READ);
-    error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) af->address,
+    VOP_LEASE(vp, td, p->p_ucred, LEASE_READ);
+    error = vn_rdwr(UIO_READ, vp, (void*) af->address,
                    header.a_text + header.a_data, 0,
                    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
     if (error)
@@ -286,8 +292,8 @@ link_aout_load_file(const char* filename, linker_file_t* result)
     *result = lf;
 
 out:
-    VOP_UNLOCK(nd.ni_vp, 0, td);
-    vn_close(nd.ni_vp, FREAD, td);
+    VOP_UNLOCK(vp, 0, td);
+    vn_close(vp, FREAD, td);
 
     return error;
 }
index 4169675..69d9451 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.14 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/link_elf.c,v 1.15 2004/11/12 00:09:23 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -32,7 +32,7 @@
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/fcntl.h>
 #include <sys/vnode.h>
 #include <sys/linker.h>
@@ -394,9 +394,10 @@ link_elf_load_module(const char *filename, linker_file_t *result)
 static int
 link_elf_load_file(const char* filename, linker_file_t* result)
 {
-    struct nameidata nd;
+    struct nlookupdata nd;
     struct thread *td = curthread;     /* XXX */
     struct proc *p = td->td_proc;
+    struct vnode *vp;
     Elf_Ehdr *hdr;
     caddr_t firstpage;
     int nbytes, i;
@@ -434,12 +435,17 @@ link_elf_load_file(const char* filename, linker_file_t* result)
     if (pathname == NULL)
        return ENOENT;
 
-    NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, pathname, td);
-    error = vn_open(&nd, FREAD, 0);
+    error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
+    if (error == 0)
+       error = vn_open(&nd, NULL, FREAD, 0);
     free(pathname, M_LINKER);
-    if (error)
+    if (error) {
+       nlookup_done(&nd);
        return error;
-    NDFREE(&nd, NDF_ONLY_PNBUF);
+    }
+    vp = nd.nl_open_vp;
+    nd.nl_open_vp = NULL;
+    nlookup_done(&nd);
 
     /*
      * Read the elf header from the file.
@@ -450,7 +456,7 @@ link_elf_load_file(const char* filename, linker_file_t* result)
        goto out;
     }
     hdr = (Elf_Ehdr *)firstpage;
-    error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0,
+    error = vn_rdwr(UIO_READ, vp, firstpage, PAGE_SIZE, 0,
                    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
     nbytes = PAGE_SIZE - resid;
     if (error)
@@ -574,7 +580,7 @@ link_elf_load_file(const char* filename, linker_file_t* result)
      */
     for (i = 0; i < 2; i++) {
        caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
-       error = vn_rdwr(UIO_READ, nd.ni_vp,
+       error = vn_rdwr(UIO_READ, vp,
                        segbase, segs[i]->p_filesz, segs[i]->p_offset,
                        UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
        if (error) {
@@ -642,7 +648,7 @@ link_elf_load_file(const char* filename, linker_file_t* result)
        goto out;
     }
     bzero(shdr, nbytes);
-    error = vn_rdwr(UIO_READ, nd.ni_vp,
+    error = vn_rdwr(UIO_READ, vp,
                    (caddr_t)shdr, nbytes, hdr->e_shoff,
                    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
     if (error)
@@ -667,12 +673,12 @@ link_elf_load_file(const char* filename, linker_file_t* result)
        error = ENOMEM;
        goto out;
     }
-    error = vn_rdwr(UIO_READ, nd.ni_vp,
+    error = vn_rdwr(UIO_READ, vp,
                    ef->symbase, symcnt, shdr[symtabindex].sh_offset,
                    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
     if (error)
        goto out;
-    error = vn_rdwr(UIO_READ, nd.ni_vp,
+    error = vn_rdwr(UIO_READ, vp,
                    ef->strbase, strcnt, shdr[symstrindex].sh_offset,
                    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
     if (error)
@@ -696,8 +702,8 @@ out:
        free(shdr, M_LINKER);
     if (firstpage)
        free(firstpage, M_LINKER);
-    VOP_UNLOCK(nd.ni_vp, 0, td);
-    vn_close(nd.ni_vp, FREAD, td);
+    VOP_UNLOCK(vp, 0, td);
+    vn_close(vp, FREAD, td);
 
     return error;
 }
index 4aca992..e5971f8 100644 (file)
@@ -17,7 +17,7 @@
  *    are met.
  *
  * $FreeBSD: src/sys/kern/sys_pipe.c,v 1.60.2.13 2002/08/05 15:05:15 des Exp $
- * $DragonFly: src/sys/kern/sys_pipe.c,v 1.24 2004/07/24 20:30:00 dillon Exp $
+ * $DragonFly: src/sys/kern/sys_pipe.c,v 1.25 2004/11/12 00:09:24 dillon Exp $
  */
 
 /*
@@ -251,7 +251,6 @@ pipe(struct pipe_args *uap)
                pipeclose(wpipe);
                return (error);
        }
-       fhold(rf);
        uap->sysmsg_fds[0] = fd1;
 
        /*
@@ -284,6 +283,7 @@ pipe(struct pipe_args *uap)
        rpipe->pipe_peer = wpipe;
        wpipe->pipe_peer = rpipe;
        fdrop(rf, td);
+       fdrop(wf, td);
 
        return (0);
 }
index 9070030..ece68de 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.10 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/tty_tty.c,v 1.11 2004/11/12 00:09:24 dillon Exp $
  */
 
 /*
@@ -94,7 +94,7 @@ cttyopen(dev_t dev, int flag, int mode, struct thread *td)
                } else {
                        vsetflags(ttyvp, VCTTYISOPEN);
                        vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
-                       error = VOP_OPEN(ttyvp, flag, NOCRED, td);
+                       error = VOP_OPEN(ttyvp, flag, NOCRED, NULL, td);
                        VOP_UNLOCK(ttyvp, 0, td);
                }
        } else {
index ca31070..c555b38 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.43 2004/10/22 13:42:14 hsu Exp $
+ * $DragonFly: src/sys/kern/uipc_syscalls.c,v 1.44 2004/11/12 00:09:24 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -109,7 +109,6 @@ kern_socket(int domain, int type, int protocol, int *res)
        error = falloc(p, &fp, &fd);
        if (error)
                return (error);
-       fhold(fp);
        error = socreate(domain, &so, type, protocol, td);
        if (error) {
                if (fdp->fd_ofiles[fd] == fp) {
@@ -271,7 +270,6 @@ kern_accept(int s, struct sockaddr **name, int *namelen, int *res)
                fdrop(lfp, td);
                return (error);
        }
-       fhold(nfp);
        *res = fd;
 
        head = (struct socket *)lfp->f_data;
@@ -355,7 +353,7 @@ done:
        /*
         * Release explicitly held references before returning.
         */
-       if (nfp != NULL)
+       if (nfp)
                fdrop(nfp, td);
        fdrop(lfp, td);
        return (error);
@@ -501,13 +499,11 @@ kern_socketpair(int domain, int type, int protocol, int *sv)
        error = falloc(p, &fp1, &fd);
        if (error)
                goto free2;
-       fhold(fp1);
        sv[0] = fd;
        fp1->f_data = (caddr_t)so1;
        error = falloc(p, &fp2, &fd);
        if (error)
                goto free3;
-       fhold(fp2);
        fp2->f_data = (caddr_t)so2;
        sv[1] = fd;
        error = soconnect2(so1, so2);
index 3d12d11..21bfbb1 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.16 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/uipc_usrreq.c,v 1.17 2004/11/12 00:09:24 dillon Exp $
  */
 
 #include <sys/param.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
 #include <sys/mbuf.h>
-#include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/protosw.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/resourcevar.h>
 #include <sys/stat.h>
+#include <sys/mount.h>
 #include <sys/sysctl.h>
 #include <sys/un.h>
 #include <sys/unpcb.h>
@@ -588,46 +589,37 @@ unp_bind(struct unpcb *unp, struct sockaddr *nam, struct thread *td)
        struct vnode *vp;
        struct vattr vattr;
        int error, namelen;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char buf[SOCK_MAXADDRLEN];
 
        if (unp->unp_vnode != NULL)
                return (EINVAL);
        namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path);
        if (namelen <= 0)
-               return EINVAL;
+               return (EINVAL);
        strncpy(buf, soun->sun_path, namelen);
        buf[namelen] = 0;       /* null-terminate the string */
-       NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_SYSSPACE, buf, td);
-/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
-       error = namei(&nd);
+       error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_LOCKVP|NLC_CREATE);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0 && nd.nl_ncp->nc_vp != NULL)
+               error = EADDRINUSE;
        if (error)
-               return (error);
-       vp = nd.ni_vp;
-       if (vp != NULL) {
-               NDFREE(&nd, NDF_ONLY_PNBUF);
-               if (nd.ni_dvp == vp)
-                       vrele(nd.ni_dvp);
-               else
-                       vput(nd.ni_dvp);
-               vrele(vp);
-               return (EADDRINUSE);
-       }
+               goto done;
+
        VATTR_NULL(&vattr);
        vattr.va_type = VSOCK;
        vattr.va_mode = (ACCESSPERMS & ~p->p_fd->fd_cmask);
-       VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
-       error = VOP_CREATE(nd.ni_dvp, NCPNULL, &nd.ni_vp, &nd.ni_cnd, &vattr);
-       NDFREE(&nd, NDF_ONLY_PNBUF);
-       vput(nd.ni_dvp);
-       if (error)
-               return (error);
-       vp = nd.ni_vp;
-       vp->v_socket = unp->unp_socket;
-       unp->unp_vnode = vp;
-       unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam);
-       VOP_UNLOCK(vp, 0, td);
-       return (0);
+       error = VOP_NCREATE(nd.nl_ncp, &vp, nd.nl_cred, &vattr);
+       if (error == 0) {
+               vp->v_socket = unp->unp_socket;
+               unp->unp_vnode = vp;
+               unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam);
+               VOP_UNLOCK(vp, 0, td);
+       }
+done:
+       nlookup_done(&nd);
+       return (error);
 }
 
 static int
@@ -639,7 +631,7 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
        struct socket *so2, *so3;
        struct unpcb *unp, *unp2, *unp3;
        int error, len;
-       struct nameidata nd;
+       struct nlookupdata nd;
        char buf[SOCK_MAXADDRLEN];
 
        KKASSERT(p);
@@ -650,13 +642,16 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
        strncpy(buf, soun->sun_path, len);
        buf[len] = 0;
 
-       NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF,
-           UIO_SYSSPACE, buf, td);
-       error = namei(&nd);
+       vp = NULL;
+       error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0)
+               error = nlookup(&nd);
+       if (error == 0)
+               error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp);
+       nlookup_done(&nd);
        if (error)
                return (error);
-       vp = nd.ni_vp;
-       NDFREE(&nd, NDF_ONLY_PNBUF);
+
        if (vp->v_type != VSOCK) {
                error = ENOTSOCK;
                goto bad;
index 8e3df92..844bdee 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.41 2004/10/28 18:56:52 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_cache.c,v 1.42 2004/11/12 00:09:24 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -85,6 +85,7 @@
 #include <sys/fnv_hash.h>
 #include <sys/globaldata.h>
 #include <sys/kern_syscall.h>
+#include <sys/dirent.h>
 #include <ddb/ddb.h>
 
 /*
@@ -112,6 +113,19 @@ MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
 static LIST_HEAD(nchashhead, namecache) *nchashtbl;    /* Hash Table */
 static struct namecache_list   ncneglist;              /* instead of vnode */
 
+/*
+ * ncvp_debug - debug cache_fromvp().  This is used by the NFS server
+ * to create the namecache infrastructure leading to a dangling vnode.
+ *
+ * 0   Only errors are reported
+ * 1   Successes are reported
+ * 2   Successes + the whole directory scan is reported
+ * 3   Force the directory scan code run as if the parent vnode did not
+ *     have a namecache record, even if it does have one.
+ */
+static int     ncvp_debug;
+SYSCTL_INT(_debug, OID_AUTO, ncvp_debug, CTLFLAG_RW, &ncvp_debug, 0, "");
+
 static u_long  nchash;                 /* size of hash table */
 SYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0, "");
 
@@ -262,7 +276,8 @@ cache_unlink_parent(struct namecache *ncp)
 }
 
 /*
- * Allocate a new namecache structure.
+ * Allocate a new namecache structure.  Most of the code does not require
+ * zero-termination of the string but it makes vop_compat_ncreate() easier.
  */
 static struct namecache *
 cache_alloc(int nlen)
@@ -271,7 +286,7 @@ cache_alloc(int nlen)
 
        ncp = malloc(sizeof(*ncp), M_VFSCACHE, M_WAITOK|M_ZERO);
        if (nlen)
-               ncp->nc_name = malloc(nlen, M_VFSCACHE, M_WAITOK);
+               ncp->nc_name = malloc(nlen + 1, M_VFSCACHE, M_WAITOK);
        ncp->nc_nlen = nlen;
        ncp->nc_flag = NCF_UNRESOLVED;
        ncp->nc_error = ENOTCONN;       /* needs to be resolved */
@@ -375,6 +390,31 @@ cache_lock(struct namecache *ncp)
        }
 }
 
+int
+cache_lock_nonblock(struct namecache *ncp)
+{
+       thread_t td;
+
+       KKASSERT(ncp->nc_refs != 0);
+       td = curthread;
+       if (ncp->nc_exlocks == 0) {
+               ncp->nc_exlocks = 1;
+               ncp->nc_locktd = td;
+               /* 
+                * The vp associated with a locked ncp must be held
+                * to prevent it from being recycled (which would
+                * cause the ncp to become unresolved).
+                *
+                * XXX loop on race for later MPSAFE work.
+                */
+               if (ncp->nc_vp)
+                       vhold(ncp->nc_vp);
+               return(0);
+       } else {
+               return(EWOULDBLOCK);
+       }
+}
+
 void
 cache_unlock(struct namecache *ncp)
 {
@@ -470,6 +510,13 @@ cache_setvp(struct namecache *ncp, struct vnode *vp)
        ncp->nc_flag &= ~NCF_UNRESOLVED;
 }
 
+void
+cache_settimeout(struct namecache *ncp, int nticks)
+{
+       if ((ncp->nc_timeout = ticks + nticks) == 0)
+               ncp->nc_timeout = 1;
+}
+
 /*
  * Disassociate the vnode or negative-cache association and mark a
  * namecache entry as unresolved again.  Note that the ncp is still
@@ -492,11 +539,12 @@ cache_setunresolved(struct namecache *ncp)
        if ((ncp->nc_flag & NCF_UNRESOLVED) == 0) {
                ncp->nc_flag |= NCF_UNRESOLVED;
                ncp->nc_flag &= ~(NCF_WHITEOUT|NCF_ISDIR|NCF_ISSYMLINK);
+               ncp->nc_timeout = 0;
                ncp->nc_error = ENOTCONN;
                ++numunres;
                if ((vp = ncp->nc_vp) != NULL) {
                        --numcache;
-                       ncp->nc_vp = NULL;      /* safety */
+                       ncp->nc_vp = NULL;
                        TAILQ_REMOVE(&vp->v_namecache, ncp, nc_vnode);
 
                        /*
@@ -513,13 +561,6 @@ cache_setunresolved(struct namecache *ncp)
                        TAILQ_REMOVE(&ncneglist, ncp, nc_vnode);
                        --numneg;
                }
-
-#if 0
-               if (TAILQ_FIRST(&ncp->nc_list)) {
-                       db_print_backtrace();
-                       printf("[diagnostic] cache_setunresolved() called on directory with children: %p %*.*s\n", ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
-               }
-#endif
        }
 }
 
@@ -540,23 +581,21 @@ cache_inval(struct namecache *ncp, int flags)
 
        if (flags & CINV_SELF)
                cache_setunresolved(ncp);
-       if (flags & CINV_PARENT) {
-               ncp->nc_flag |= NCF_REVALPARENT;
+       if (flags & CINV_PARENT)
                cache_unlink_parent(ncp);
-       }
 
        /*
-        * TEMPORARY XX old-api / rename handling.  Any unresolved or
-        * negative cache-hit children with a ref count of 0 must be
-        * recursively destroyed or this disconnection from our parent,
-        * or the childrens disconnection from us, may leave them dangling
-        * forever.
+        * Children are invalidated when the parent is destroyed.  This
+        * basically disconnects the children from the parent.  Anyone
+        * CD'd into a child will no longer be able to ".." back up.
         *
-        * In the new API it won't be possible to unlink in the middle of
-        * the topology and we will have a cache_rename() to physically
-        * move a subtree from one place to another.
+        * Any unresolved or negative cache-hit children with a ref count
+        * of 0 must be immediately and recursively destroyed or this
+        * disconnection may leave them dangling forever.  XXX this recursion
+        * could run the kernel out of stack, the children should be placed
+        * on a to-destroy list instead.
         */
-       if (flags & (CINV_PARENT|CINV_CHILDREN)) {
+       if (flags & CINV_CHILDREN) {
                if ((kid = TAILQ_FIRST(&ncp->nc_list)) != NULL)
                        cache_hold(kid);
                while (kid) {
@@ -568,20 +607,9 @@ cache_inval(struct namecache *ncp, int flags)
                        ) {
                                cache_inval(kid, CINV_PARENT);
                        }
-                       cache_drop(kid);
-                       kid = nextkid;
-               }
-       }
-
-       /*
-        * TEMPORARY XXX old-api / rename handling.
-        */
-       if (flags & CINV_CHILDREN) {
-               while ((kid = TAILQ_FIRST(&ncp->nc_list)) != NULL) {
-                       kid->nc_flag |= NCF_REVALPARENT;
-                       cache_hold(kid);
                        cache_unlink_parent(kid);
                        cache_drop(kid);
+                       kid = nextkid;
                }
        }
 }
@@ -607,6 +635,37 @@ cache_inval_vp(struct vnode *vp, int flags)
        }
 }
 
+/*
+ * The source ncp has been renamed to the target ncp.  Both fncp and tncp
+ * must be locked.  Both will be set to unresolved, any children of tncp
+ * will be disconnected (the prior contents of the target is assumed to be
+ * destroyed by the rename operation, e.g. renaming over an empty directory),
+ * and all children of fncp will be moved to tncp.
+ *
+ * After we return the caller has the option of calling cache_setvp() if
+ * the vnode of the new target ncp is known.
+ *
+ * Any process CD'd into any of the children will no longer be able to ".."
+ * back out.  An rm -rf can cause this situation to occur.
+ */
+void
+cache_rename(struct namecache *fncp, struct namecache *tncp)
+{
+       struct namecache *scan;
+
+       cache_setunresolved(fncp);
+       cache_setunresolved(tncp);
+       cache_inval(tncp, CINV_CHILDREN);
+       while ((scan = TAILQ_FIRST(&fncp->nc_list)) != NULL) {
+               cache_hold(scan);
+               cache_unlink_parent(scan);
+               cache_link_parent(scan, tncp);
+               if (scan->nc_flag & NCF_HASHED)
+                       cache_rehash(scan);
+               cache_drop(scan);
+       }
+}
+
 /*
  * vget the vnode associated with the namecache entry.  Resolve the namecache
  * entry if necessary and deal with namecache/vp races.  The passed ncp must
@@ -686,6 +745,259 @@ again:
        return(error);
 }
 
+/*
+ * Convert a directory vnode to a namecache record without any other 
+ * knowledge of the topology.  This ONLY works with directory vnodes and
+ * is ONLY used by the NFS server.  dvp must be refd but unlocked, and the
+ * returned ncp (if not NULL) will be held and unlocked.
+ *
+ * If 'makeit' is 0 and dvp has no existing namecache record, NULL is returned.
+ * If 'makeit' is 1 we attempt to track-down and create the namecache topology
+ * for dvp.  This will fail only if the directory has been deleted out from
+ * under the caller.  
+ *
+ * Callers must always check for a NULL return no matter the value of 'makeit'.
+ */
+
+static int cache_inefficient_scan(struct namecache *ncp, struct ucred *cred,
+                                 struct vnode *dvp);
+
+struct namecache *
+cache_fromdvp(struct vnode *dvp, struct ucred *cred, int makeit)
+{
+       struct namecache *ncp;
+       struct vnode *pvp;
+       int error;
+
+       /*
+        * Temporary debugging code to force the directory scanning code
+        * to be exercised.
+        */
+       ncp = NULL;
+       if (ncvp_debug >= 3 && makeit && TAILQ_FIRST(&dvp->v_namecache)) {
+               ncp = TAILQ_FIRST(&dvp->v_namecache);
+               printf("cache_fromdvp: forcing %s\n", ncp->nc_name);
+               goto force;
+       }
+
+       /*
+        * Loop until resolution, inside code will break out on error.
+        */
+       while ((ncp = TAILQ_FIRST(&dvp->v_namecache)) == NULL && makeit) {
+force:
+               /*
+                * If dvp is the root of its filesystem it should already
+                * have a namecache pointer associated with it as a side 
+                * effect of the mount, but it may have been disassociated.
+                */
+               if (dvp->v_flag & VROOT) {
+                       ncp = cache_get(dvp->v_mount->mnt_ncp);
+                       error = cache_resolve_mp(ncp);
+                       cache_put(ncp);
+                       if (ncvp_debug) {
+                               printf("cache_fromdvp: resolve root of mount %p error %d", 
+                                       dvp->v_mount, error);
+                       }
+                       if (error) {
+                               if (ncvp_debug)
+                                       printf(" failed\n");
+                               ncp = NULL;
+                               break;
+                       }
+                       if (ncvp_debug)
+                               printf(" succeeded\n");
+                       continue;
+               }
+
+               /*
+                * Get the parent directory and resolve its ncp.
+                */
+               error = vop_nlookupdotdot(dvp->v_ops, dvp, &pvp, cred);
+               if (error) {
+                       printf("lookupdotdot failed %d %p\n", error, pvp);
+                       break;
+               }
+               VOP_UNLOCK(pvp, 0, curthread);
+
+               /*
+                * XXX this recursion could run the kernel out of stack,
+                * change to a less efficient algorithm if we get too deep
+                * (use 'makeit' for a depth counter?)
+                */
+               ncp = cache_fromdvp(pvp, cred, makeit);
+               vrele(pvp);
+               if (ncp == NULL)
+                       break;
+
+               /*
+                * Do an inefficient scan of pvp (embodied by ncp) to look
+                * for dvp.  This will create a namecache record for dvp on
+                * success.  We loop up to recheck on success.
+                *
+                * ncp and dvp are both held but not locked.
+                */
+               error = cache_inefficient_scan(ncp, cred, dvp);
+               cache_drop(ncp);
+               if (error) {
+                       printf("cache_fromdvp: scan %p (%s) failed on dvp=%p\n",
+                               pvp, ncp->nc_name, dvp);
+                       ncp = NULL;
+                       break;
+               }
+               if (ncvp_debug) {
+                       printf("cache_fromdvp: scan %p (%s) succeeded\n",
+                               pvp, ncp->nc_name);
+               }
+       }
+       if (ncp)
+               cache_hold(ncp);
+       return (ncp);
+}
+
+/*
+ * Do an inefficient scan of the directory represented by ncp looking for
+ * the directory vnode dvp.  ncp must be held but not locked on entry and
+ * will be held on return.  dvp must be refd but not locked on entry and
+ * will remain refd on return.
+ *
+ * Why do this at all?  Well, due to its stateless nature the NFS server
+ * converts file handles directly to vnodes without necessarily going through
+ * the namecache ops that would otherwise create the namecache topology
+ * leading to the vnode.  We could either (1) Change the namecache algorithms
+ * to allow disconnect namecache records that are re-merged opportunistically,
+ * or (2) Make the NFS server backtrack and scan to recover a connected
+ * namecache topology in order to then be able to issue new API lookups.
+ *
+ * It turns out that (1) is a huge mess.  It takes a nice clean set of 
+ * namecache algorithms and introduces a lot of complication in every subsystem
+ * that calls into the namecache to deal with the re-merge case, especially
+ * since we are using the namecache to placehold negative lookups and the
+ * vnode might not be immediately assigned. (2) is certainly far less
+ * efficient then (1), but since we are only talking about directories here
+ * (which are likely to remain cached), the case does not actually run all
+ * that often and has the supreme advantage of not polluting the namecache
+ * algorithms.
+ */
+static int
+cache_inefficient_scan(struct namecache *ncp, struct ucred *cred, 
+                      struct vnode *dvp)
+{
+       struct nlcomponent nlc;
+       struct namecache *rncp;
+       struct dirent *den;
+       struct vnode *pvp;
+       struct vattr vat;
+       struct iovec iov;
+       struct uio uio;
+       u_long *cookies;
+       off_t baseoff;
+       int ncookies;
+       int blksize;
+       int eofflag;
+       char *rbuf;
+       int error;
+       int xoff;
+       int i;
+
+       vat.va_blocksize = 0;
+       if ((error = VOP_GETATTR(dvp, &vat, curthread)) != 0)
+               return (error);
+       if ((error = cache_vget(ncp, cred, LK_SHARED, &pvp)) != 0)
+               return (error);
+       if (ncvp_debug)
+               printf("inefficient_scan: directory iosize %ld vattr fileid = %ld\n", vat.va_blocksize, (long)vat.va_fileid);
+       if ((blksize = vat.va_blocksize) == 0)
+               blksize = DEV_BSIZE;
+       rbuf = malloc(blksize, M_TEMP, M_WAITOK);
+       rncp = NULL;
+
+       eofflag = 0;
+       uio.uio_offset = 0;
+       cookies = NULL;
+again:
+       baseoff = uio.uio_offset;
+       iov.iov_base = rbuf;
+       iov.iov_len = blksize;
+       uio.uio_iov = &iov;
+       uio.uio_iovcnt = 1;
+       uio.uio_resid = blksize;
+       uio.uio_segflg = UIO_SYSSPACE;
+       uio.uio_rw = UIO_READ;
+       uio.uio_td = curthread;
+
+       if (cookies) {
+               free(cookies, M_TEMP);
+               cookies = NULL;
+       }
+       if (ncvp_debug >= 2)
+               printf("cache_inefficient_scan: readdir @ %08x\n", (int)baseoff);
+       error = VOP_READDIR(pvp, &uio, cred, &eofflag, &ncookies, &cookies);
+       if (error == 0 && cookies == NULL)
+               error = EPERM;
+       if (error == 0) {
+               for (i = 0; i < ncookies; ++i) {
+                       xoff = (int)(cookies[i] - (u_long)baseoff);
+                       /*
+                        * UFS plays a little trick to skip the first entry
+                        * in a directory ("."), by assigning the cookie to
+                        * dpoff + dp->d_reclen in the loop.  This causes
+                        * the last cookie to be assigned to the data-end of
+                        * the directory.  XXX
+                        */
+                       if (xoff == blksize)
+                               break;
+                       KKASSERT(xoff >= 0 && xoff <= blksize);
+                       den = (struct dirent *)(rbuf + xoff);
+                       if (ncvp_debug >= 2)
+                               printf("cache_inefficient_scan: %*.*s\n",
+                                       den->d_namlen, den->d_namlen, den->d_name);
+                       if (den->d_type != DT_WHT &&
+                           den->d_fileno == vat.va_fileid) {
+                               if (ncvp_debug)
+                                       printf("cache_inefficient_scan: MATCHED inode %ld path %s/%*.*s\n", vat.va_fileid, ncp->nc_name, den->d_namlen, den->d_namlen, den->d_name);
+                               nlc.nlc_nameptr = den->d_name;
+                               nlc.nlc_namelen = den->d_namlen;
+                               VOP_UNLOCK(pvp, 0, curthread);
+                               rncp = cache_nlookup(ncp, &nlc);
+                               KKASSERT(rncp != NULL);
+                               break;
+                       }
+               }
+               if (rncp == NULL && eofflag == 0 && uio.uio_resid != blksize)
+                       goto again;
+       }
+       if (cookies) {
+               free(cookies, M_TEMP);
+               cookies = NULL;
+       }
+       if (rncp) {
+               vrele(pvp);
+               if (rncp->nc_flag & NCF_UNRESOLVED) {
+                       cache_setvp(rncp, dvp);
+                       if (ncvp_debug >= 2) {
+                               printf("cache_inefficient_scan: setvp %s/%s = %p\n",
+                                       ncp->nc_name, rncp->nc_name, dvp);
+                       }
+               } else {
+                       if (ncvp_debug >= 2) {
+                               printf("cache_inefficient_scan: setvp %s/%s already set %p/%p\n", 
+                                       ncp->nc_name, rncp->nc_name, dvp,
+                                       rncp->nc_vp);
+                       }
+               }
+               if (rncp->nc_vp == NULL)
+                       error = rncp->nc_error;
+               cache_put(rncp);
+       } else {
+               printf("cache_inefficient_scan: dvp %p NOT FOUND in %s\n",
+                       dvp, ncp->nc_name);
+               vput(pvp);
+               error = ENOENT;
+       }
+       free(rbuf, M_TEMP);
+       return (error);
+}
+
 /*
  * Zap a namecache entry.  The ncp is unconditionally set to an unresolved
  * state, which disassociates it from its vnode or ncneglist.
@@ -811,7 +1123,7 @@ cache_hysteresis(void)
  *
  * Lookup an entry in the cache.  A locked, referenced, non-NULL 
  * entry is *always* returned, even if the supplied component is illegal.
- * The returned namecache entry should be returned to the system with
+ * The resulting namecache entry should be returned to the system with
  * cache_put() or cache_unlock() + cache_drop().
  *
  * namecache locks are recursive but care must be taken to avoid lock order
@@ -833,8 +1145,8 @@ cache_hysteresis(void)
  *
  * The directory (par) may be unresolved, in which case any returned child
  * will likely also be marked unresolved.  Likely but not guarenteed.  Since
- * the filesystem VOP_NEWLOOKUP() requires a resolved directory vnode the
- * caller is responsible for resolving the namecache chain top-down.  This API 
+ * the filesystem lookup requires a resolved directory vnode the caller is
+ * responsible for resolving the namecache chain top-down.  This API 
  * specifically allows whole chains to be created in an unresolved state.
  */
 struct namecache *
@@ -904,12 +1216,15 @@ restart:
 
        /*
         * Initialize as a new UNRESOLVED entry, lock (non-blocking),
-        * and link to the parent.  Only special mount points will have
-        * a namelen of 0.  Those will have their nc_mount assigned through
-        * other means.
+        * and link to the parent.  The mount point is usually inherited
+        * from the parent unless this is a special case such as a mount
+        * point where nlc_namelen is 0.  The caller is responsible for
+        * setting nc_mount in that case.  If nlc_namelen is 0 nc_name will
+        * be NULL.
         */
        if (nlc->nlc_namelen) {
                bcopy(nlc->nlc_nameptr, ncp->nc_name, nlc->nlc_namelen);
+               ncp->nc_name[nlc->nlc_namelen] = 0;
                ncp->nc_mount = par->nc_mount;
        }
        nchpp = NCHHASH(hash);
@@ -917,6 +1232,15 @@ restart:
        ncp->nc_flag |= NCF_HASHED;
        cache_link_parent(ncp, par);
 found:
+       /*
+        * stats and namecache size management
+        */
+       if (ncp->nc_flag & NCF_UNRESOLVED)
+               ++gd->gd_nchstats->ncs_miss;
+       else if (ncp->nc_vp)
+               ++gd->gd_nchstats->ncs_goodhits;
+       else
+               ++gd->gd_nchstats->ncs_neghits;
        cache_hysteresis();
        return(ncp);
 }
@@ -930,12 +1254,15 @@ found:
  * direct parent of the cache entry we are trying to resolve should
  * have a valid vnode.  If not then generate an error that we can 
  * determine is related to a resolver bug.
+ *
+ * Note that successful resolution does not necessarily return an error
+ * code of 0.  If the ncp resolves to a negative cache hit then ENOENT
+ * will be returned.
  */
 int
 cache_resolve(struct namecache *ncp, struct ucred *cred)
 {
        struct namecache *par;
-       struct namecache *scan;
        int error;
 
 restart:
@@ -1006,9 +1333,8 @@ restart:
                        printf("[diagnostic] cache_resolve: raced on %*.*s\n", par->nc_nlen, par->nc_nlen, par->nc_name);
                        cache_put(par);
                        continue;
-               } else {
-                       par->nc_error = 
-                           vop_resolve(par->nc_parent->nc_vp->v_ops, par, cred);
+               } else if (par->nc_flag & NCF_UNRESOLVED) {
+                       par->nc_error = VOP_NRESOLVE(par, cred);
                }
                if ((error = par->nc_error) != 0) {
                        if (par->nc_error != EAGAIN) {
@@ -1026,33 +1352,21 @@ restart:
        }
 
        /*
-        * Call vop_resolve() to get the vp, then scan for any disconnected
+        * Call VOP_NRESOLVE() to get the vp, then scan for any disconnected
         * ncp's and reattach them.  If this occurs the original ncp is marked
         * EAGAIN to force a relookup.
+        *
+        * NOTE: in order to call VOP_NRESOLVE(), the parent of the passed
+        * ncp must already be resolved.
         */
        KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0);
-       ncp->nc_error = vop_resolve(ncp->nc_parent->nc_vp->v_ops, ncp, cred);
+       ncp->nc_error = VOP_NRESOLVE(ncp, cred);
+       /*vop_nresolve(ncp->nc_parent->nc_vp->v_ops, ncp, cred);*/
        if (ncp->nc_error == EAGAIN) {
                printf("[diagnostic] cache_resolve: EAGAIN ncp %p %*.*s\n",
                        ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
                goto restart;
        }
-       if (ncp->nc_error == 0) {
-               TAILQ_FOREACH(scan, &ncp->nc_vp->v_namecache, nc_vnode) {
-                       if (scan != ncp && (scan->nc_flag & NCF_REVALPARENT)) {
-                               cache_hold(scan);
-                               cache_link_parent(scan, ncp->nc_parent);
-                               cache_unlink_parent(ncp);
-                               scan->nc_flag &= ~NCF_REVALPARENT;
-                               ncp->nc_error = EAGAIN;
-                               if (scan->nc_flag & NCF_HASHED)
-                                       cache_rehash(scan);
-                               printf("[diagnostic] cache_resolve: relinked %*.*s\n", scan->nc_nlen, scan->nc_nlen, scan->nc_name);
-                               cache_drop(scan);
-                               break;
-                       }
-               }
-       }
        return(ncp->nc_error);
 }
 
@@ -1087,346 +1401,6 @@ cache_resolve_mp(struct namecache *ncp)
        return(ncp->nc_error);
 }
 
-/*
- * Lookup an entry in the cache.
- *
- * XXX OLD API ROUTINE!  WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE
- * WILL BE REMOVED.  NOTE: even though this is an old api function it had
- * to be modified to vref() the returned vnode (whereas in 4.x an unreferenced
- * vnode was returned).  This is necessary because our namecache structure
- * manipulation can cause the vnode to be recycled if it isn't refd.
- *
- * Lookup is called with dvp pointing to the directory to search,
- * cnp pointing to the name of the entry being sought. 
- *
- * If the lookup succeeds, a REFd but unlocked vnode is returned in *vpp,
- * and a status of -1 is returned.
- *
- * If the lookup determines that the name does not exist (negative cacheing),
- * a status of ENOENT is returned. 
- *
- * If the lookup fails, a status of zero is returned.
- *
- * Matching UNRESOLVED entries are resolved.
- *
- * HACKS: we create dummy nodes for parents
- */
-int
-cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
-{
-       struct namecache *ncp;
-       struct namecache *par;
-       struct namecache *bpar;
-       u_int32_t hash;
-       globaldata_t gd = mycpu;
-
-       numcalls++;
-       *vpp = NULL;
-
-       /*
-        * Obtain the namecache entry associated with dvp.  If there is no
-        * entry then assume a miss.
-        */
-       if ((par = TAILQ_FIRST(&dvp->v_namecache)) == NULL) {
-               if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) {
-                       nummisszap++;
-               } else {
-                       nummiss++;
-               }
-               gd->gd_nchstats->ncs_miss++;
-               return (0);
-       }
-
-       /*
-        * Deal with "." and "..".   Note that if the namecache is disjoint,
-        * we won't find a vnode for ".." and we return a miss.
-        */
-       if (cnp->cn_nameptr[0] == '.') {
-               if (cnp->cn_namelen == 1) {
-                       *vpp = dvp;
-                       vref(*vpp);
-                       dothits++;
-                       numposhits++;   /* include in total statistics */
-                       return (-1);
-               }
-               if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
-                       if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) {
-                               dotdothits++;
-                               numposhits++;
-                               return (0);
-                       }
-                       if (par->nc_parent == NULL ||
-                           par->nc_parent->nc_vp == NULL) {
-                               nummiss++;
-                               gd->gd_nchstats->ncs_miss++;
-                               return (0);
-                       }
-                       *vpp = par->nc_parent->nc_vp;
-                       vref(*vpp);
-                       dotdothits++;
-                       numposhits++;   /* include in total statistics */
-                       return (-1);
-               }
-       }
-
-       /*
-        * Try to locate an existing entry
-        */
-       cache_hold(par);
-       hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT);
-       bpar = par;
-       hash = fnv_32_buf(&bpar, sizeof(bpar), hash);
-restart:
-       LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) {
-               numchecks++;
-
-               /*
-                * Zap entries that have timed out.  Don't do anything if
-                * the entry is in an unresolved state or is held locked.
-                */
-               if (ncp->nc_timeout && 
-                   (int)(ncp->nc_timeout - ticks) < 0 &&
-                   (ncp->nc_flag & NCF_UNRESOLVED) == 0 &&
-                   ncp->nc_exlocks == 0
-               ) {
-                       cache_zap(cache_get(ncp));
-                       goto restart;
-               }
-
-               /*
-                * Break out if we find a matching entry.
-                */
-               if (ncp->nc_parent == par &&
-                   ncp->nc_nlen == cnp->cn_namelen &&
-                   bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen) == 0
-               ) {
-                       if (cache_get_nonblock(ncp) == 0)
-                               break;
-                       cache_get(ncp);
-                       cache_put(ncp);
-                       goto restart;
-               }
-       }
-       cache_drop(par);
-
-       /*
-        * We found an entry but it is unresolved, act the same as if we
-        * failed to locate the entry.  cache_enter() will do the right
-        * thing.
-        */
-       if (ncp && (ncp->nc_flag & NCF_UNRESOLVED)) {
-               cache_put(ncp);
-               ncp = NULL;
-       }
-
-       /*
-        * If we failed to locate an entry, return 0 (indicates failure).
-        */
-       if (ncp == NULL) {
-               if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) {
-                       nummisszap++;
-               } else {
-                       nummiss++;
-               }
-               gd->gd_nchstats->ncs_miss++;
-               return (0);
-       }
-
-       /*
-        * If we found an entry, but we don't want to have one, we just
-        * return.  The old API tried to zap the entry in the vfs_lookup()
-        * phase but this is too early to know whether the operation
-        * will have succeeded or not.  The new API zaps it after the
-        * operation has succeeded, not here.
-        *
-        * At the same time, the old api's rename() function uses the
-        * old api lookup to clear out any negative cache hit on the
-        * target name.  We still have to do that.
-        */
-       if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) {
-               if (cnp->cn_nameiop == NAMEI_RENAME && ncp->nc_vp == NULL)
-                       cache_zap(ncp);
-               else
-                       cache_put(ncp);
-               return (0);
-       }
-
-       /*
-        * If the vnode is not NULL then return the positive match.
-        */
-       if (ncp->nc_vp) {
-               numposhits++;
-               gd->gd_nchstats->ncs_goodhits++;
-               *vpp = ncp->nc_vp;
-               vref(*vpp);
-               cache_put(ncp);
-               return (-1);
-       }
-
-       /*
-        * If the vnode is NULL we found a negative match.  If we want to
-        * create it, purge the negative match and return failure (as if
-        * we hadn't found a match in the first place).
-        */
-       if (cnp->cn_nameiop == NAMEI_CREATE) {
-               numnegzaps++;
-               gd->gd_nchstats->ncs_badhits++;
-               cache_zap(ncp);
-               return (0);
-       }
-
-       numneghits++;
-
-       /*
-        * We found a "negative" match, ENOENT notifies client of this match.
-        * The nc_flag field records whether this is a whiteout.  Since there
-        * is no vnode we can use the vnode tailq link field with ncneglist.
-        */
-       TAILQ_REMOVE(&ncneglist, ncp, nc_vnode);
-       TAILQ_INSERT_TAIL(&ncneglist, ncp, nc_vnode);
-       gd->gd_nchstats->ncs_neghits++;
-       if (ncp->nc_flag & NCF_WHITEOUT)
-               cnp->cn_flags |= CNP_ISWHITEOUT;
-       cache_put(ncp);
-       return (ENOENT);
-}
-
-/*
- * Add an entry to the cache.  (OLD API)
- *
- * XXX OLD API ROUTINE!  WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE
- * WILL BE REMOVED.
- *
- * Generally speaking this is 'optional'.  It's ok to do nothing at all.
- * The only reason I don't just return is to try to set nc_timeout if
- * requested.
- */
-void
-cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
-{
-       struct namecache *par;
-       struct namecache *ncp;
-       struct namecache *new_ncp;
-       struct namecache *bpar;
-       struct nchashhead *nchpp;
-       u_int32_t hash;
-
-       /*
-        * If the directory has no namecache entry we bail.  This will result
-        * in a lot of misses but frankly we don't have much of a choice if
-        * we want to be compatible with the new api's storage scheme.
-        */
-       if ((ncp = TAILQ_FIRST(&dvp->v_namecache)) == NULL)
-               return;
-       cache_hold(ncp);
-
-       /*
-        * This may be a bit confusing.  "." and ".." are 'virtual' entries.
-        * We do not actually create a namecache entry representing either.
-        * However, the ".." case is used to linkup a potentially disjoint
-        * directory with its parent, to disconnect a directory from its
-        * parent, or to change an existing linkage that may no longer be
-        * correct (as might occur when a subdirectory is renamed).
-        */
-
-       if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
-               cache_drop(ncp);
-               return;
-       }
-       if (cnp->cn_namelen == 2 && cnp->cn_nameptr[0] == '.' &&
-           cnp->cn_nameptr[1] == '.'
-       ) {
-               cache_drop(ncp);
-               return;
-       }
-
-       /*
-        * Ok, no special cases, ncp is actually the parent directory so
-        * assign it to par.  Note that it is held.
-        */
-       par = ncp;
-
-       /*
-        * Try to find a match in the hash table, allocate a new entry if
-        * we can't.  We have to retry the loop after any potential blocking
-        * situation.
-        */
-       bpar = par;
-       hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT);
-       hash = fnv_32_buf(&bpar, sizeof(bpar), hash);
-
-       new_ncp = NULL;
-againagain:
-       LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) {
-               numchecks++;
-
-               /*
-                * Break out if we find a matching entry.  Because cache_enter
-                * is called with one or more vnodes potentially locked, we
-                * cannot block trying to get the ncp lock (or we might 
-                * deadlock).
-                */
-               if (ncp->nc_parent == par &&
-                   ncp->nc_nlen == cnp->cn_namelen &&
-                   bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen) == 0
-               ) {
-                       if (cache_get_nonblock(ncp) != 0) {
-                               printf("[diagnostic] cache_enter: avoided race on %p %*.*s\n", ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
-                               cache_drop(par);
-                               return;
-                       }
-                       break;
-               }
-       }
-       if (ncp == NULL) {
-               if (new_ncp == NULL) {
-                       new_ncp = cache_alloc(cnp->cn_namelen);
-                       goto againagain;
-               }
-               ncp = new_ncp;
-               bcopy(cnp->cn_nameptr, ncp->nc_name, cnp->cn_namelen);
-               nchpp = NCHHASH(hash);
-               LIST_INSERT_HEAD(nchpp, ncp, nc_hash);
-               ncp->nc_flag |= NCF_HASHED;
-               ncp->nc_mount = dvp->v_mount;
-               cache_link_parent(ncp, par);
-       } else if (new_ncp) {
-               cache_free(new_ncp);
-       }
-       cache_drop(par);
-
-       /*
-        * Avoid side effects if we are simply re-entering the same
-        * information.
-        */
-       if ((ncp->nc_flag & NCF_UNRESOLVED) == 0 && ncp->nc_vp == vp) {
-               ncp->nc_error = vp ? 0 : ENOENT;
-       } else {
-               cache_setunresolved(ncp);
-               cache_setvp(ncp, vp);
-       }
-
-       /*
-        * Set a timeout
-        */
-       if (cnp->cn_flags & CNP_CACHETIMEOUT) {
-               if ((ncp->nc_timeout = ticks + cnp->cn_timeout) == 0)
-                       ncp->nc_timeout = 1;
-       }
-
-       /*
-        * If the target vnode is NULL if this is to be a negative cache
-        * entry.
-        */
-       if (vp == NULL) {
-               ncp->nc_flag &= ~NCF_WHITEOUT;
-               if (cnp->cn_flags & CNP_ISWHITEOUT)
-                       ncp->nc_flag |= NCF_WHITEOUT;
-       }
-       cache_put(ncp);
-       cache_hysteresis();
-}
-
 void
 cache_cleanneg(int count)
 {
@@ -1457,6 +1431,11 @@ cache_cleanneg(int count)
        }
 }
 
+/*
+ * Rehash a ncp.  Rehashing is typically required if the name changes (should
+ * not generally occur) or the parent link changes.  This function will
+ * unhash the ncp if the ncp is no longer hashable.
+ */
 static void
 cache_rehash(struct namecache *ncp)
 {
@@ -1467,14 +1446,16 @@ cache_rehash(struct namecache *ncp)
                ncp->nc_flag &= ~NCF_HASHED;
                LIST_REMOVE(ncp, nc_hash);
        }
-       hash = fnv_32_buf(ncp->nc_name, ncp->nc_nlen, FNV1_32_INIT);
-       hash = fnv_32_buf(&ncp->nc_parent, sizeof(ncp->nc_parent), hash);
-       nchpp = NCHHASH(hash);
-       LIST_INSERT_HEAD(nchpp, ncp, nc_hash);
-       ncp->nc_flag |= NCF_HASHED;
+       if (ncp->nc_nlen && ncp->nc_parent) {
+               hash = fnv_32_buf(ncp->nc_name, ncp->nc_nlen, FNV1_32_INIT);
+               hash = fnv_32_buf(&ncp->nc_parent, 
+                                       sizeof(ncp->nc_parent), hash);
+               nchpp = NCHHASH(hash);
+               LIST_INSERT_HEAD(nchpp, ncp, nc_hash);
+               ncp->nc_flag |= NCF_HASHED;
+       }
 }
 
-
 /*
  * Name cache initialization, from vfsinit() when we are booting
  */
@@ -1537,6 +1518,11 @@ vfs_cache_setroot(struct vnode *nvp, struct namecache *ncp)
 }
 
 /*
+ * XXX OLD API COMPAT FUNCTION.  This really messes up the new namecache
+ * topology and is being removed as quickly as possible.  The new VOP_N*()
+ * API calls are required to make specific adjustments using the supplied
+ * ncp pointers rather then just bogusly purging random vnodes.
+ *
  * Invalidate all namecache entries to a particular vnode as well as 
  * any direct children of that vnode in the namecache.  This is a 
  * 'catch all' purge used by filesystems that do not know any better.
@@ -1608,102 +1594,6 @@ cache_purgevfs(struct mount *mp)
        }
 }
 
-/*
- * Perform canonical checks and cache lookup and pass on to filesystem
- * through the vop_cachedlookup only if needed.
- *
- * vop_lookup_args {
- *     struct vnode a_dvp;
- *     struct vnode **a_vpp;
- *     struct componentname *a_cnp;
- * }
- */
-int
-vfs_cache_lookup(struct vop_lookup_args *ap)
-{
-       struct vnode *dvp, *vp;
-       int lockparent;
-       int error;
-       struct vnode **vpp = ap->a_vpp;
-       struct componentname *cnp = ap->a_cnp;
-       struct ucred *cred = cnp->cn_cred;
-       int flags = cnp->cn_flags;
-       struct thread *td = cnp->cn_td;
-       u_long vpid;    /* capability number of vnode */
-
-       *vpp = NULL;
-       dvp = ap->a_dvp;
-       lockparent = flags & CNP_LOCKPARENT;
-
-       if (dvp->v_type != VDIR)
-                return (ENOTDIR);
-
-       if ((flags & CNP_ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
-           (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) {
-               return (EROFS);
-       }
-
-       error = VOP_ACCESS(dvp, VEXEC, cred, td);
-
-       if (error)
-               return (error);
-
-       error = cache_lookup(dvp, vpp, cnp);
-
-       /*
-        * failure if error == 0, do a physical lookup
-        */
-       if (!error) 
-               return (VOP_CACHEDLOOKUP(dvp, vpp, cnp));
-
-       if (error == ENOENT)
-               return (error);
-
-       vp = *vpp;
-       vpid = vp->v_id;
-       cnp->cn_flags &= ~CNP_PDIRUNLOCK;
-       if (dvp == vp) {   /* lookup on "." */
-               /* already ref'd from cache_lookup() */
-               error = 0;
-       } else if (flags & CNP_ISDOTDOT) {
-               VOP_UNLOCK(dvp, 0, td);
-               cnp->cn_flags |= CNP_PDIRUNLOCK;
-               error = vget(vp, LK_EXCLUSIVE, td);
-               vrele(vp);
-               if (!error && lockparent && (flags & CNP_ISLASTCN)) {
-                       if ((error = vn_lock(dvp, LK_EXCLUSIVE, td)) == 0)
-                               cnp->cn_flags &= ~CNP_PDIRUNLOCK;
-               }
-       } else {
-               error = vget(vp, LK_EXCLUSIVE, td);
-               vrele(vp);
-               if (!lockparent || error || !(flags & CNP_ISLASTCN)) {
-                       VOP_UNLOCK(dvp, 0, td);
-                       cnp->cn_flags |= CNP_PDIRUNLOCK;
-               }
-       }
-       /*
-        * Check that the capability number did not change
-        * while we were waiting for the lock.
-        */
-       if (!error) {
-               if (vpid == vp->v_id)
-                       return (0);
-               vput(vp);
-               if (lockparent && dvp != vp && (flags & CNP_ISLASTCN)) {
-                       VOP_UNLOCK(dvp, 0, td);
-                       cnp->cn_flags |= CNP_PDIRUNLOCK;
-               }
-       }
-       if (cnp->cn_flags & CNP_PDIRUNLOCK) {
-               error = vn_lock(dvp, LK_EXCLUSIVE, td);
-               if (error)
-                       return (error);
-               cnp->cn_flags &= ~CNP_PDIRUNLOCK;
-       }
-       return (VOP_CACHEDLOOKUP(dvp, vpp, cnp));
-}
-
 static int disablecwd;
 SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, "");
 
@@ -1840,7 +1730,10 @@ vn_fullpath(struct proc *p, struct vnode *vn, char **retbuf, char **freebuf)
                if ((vn = p->p_textvp) == NULL)
                        return (EINVAL);
        }
-       ncp = TAILQ_FIRST(&vn->v_namecache);
+       TAILQ_FOREACH(ncp, &vn->v_namecache, nc_vnode) {
+               if (ncp->nc_nlen)
+                       break;
+       }
        if (ncp == NULL)
                return (EINVAL);
 
index 20ac585..98f677e 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.21 2004/10/12 19:20:46 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_default.c,v 1.22 2004/11/12 00:09:24 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -51,6 +51,7 @@
 #include <sys/unistd.h>
 #include <sys/vnode.h>
 #include <sys/namei.h>
+#include <sys/nlookup.h>
 #include <sys/poll.h>
 
 #include <machine/limits.h>
@@ -85,7 +86,6 @@ static struct vnodeopv_entry_desc default_vnodeop_entries[] = {
        { &vop_lease_desc,              vop_null },
        { &vop_lock_desc,               (void *) vop_stdlock },
        { &vop_mmap_desc,               vop_einval },
-       { &vop_resolve_desc,            (void *) vop_noresolve },
        { &vop_lookup_desc,             (void *) vop_nolookup },
        { &vop_open_desc,               vop_null },
        { &vop_pathconf_desc,           vop_einval },
@@ -100,6 +100,17 @@ static struct vnodeopv_entry_desc default_vnodeop_entries[] = {
        { &vop_aclcheck_desc,           vop_eopnotsupp },
        { &vop_getextattr_desc,         vop_eopnotsupp },
        { &vop_setextattr_desc,         vop_eopnotsupp },
+       { &vop_nresolve_desc,           (void *) vop_compat_nresolve },
+       { &vop_nlookupdotdot_desc,      (void *) vop_compat_nlookupdotdot },
+       { &vop_ncreate_desc,            (void *) vop_compat_ncreate },
+       { &vop_nmkdir_desc,             (void *) vop_compat_nmkdir },
+       { &vop_nmknod_desc,             (void *) vop_compat_nmknod },
+       { &vop_nlink_desc,              (void *) vop_compat_nlink },
+       { &vop_nsymlink_desc,           (void *) vop_compat_nsymlink },
+       { &vop_nwhiteout_desc,          (void *) vop_compat_nwhiteout },
+       { &vop_nremove_desc,            (void *) vop_compat_nremove },
+       { &vop_nrmdir_desc,             (void *) vop_compat_nrmdir },
+       { &vop_nrename_desc,            (void *) vop_compat_nrename },
        { NULL, NULL }
 };
 
@@ -152,16 +163,16 @@ vop_panic(struct vop_generic_args *ap)
 }
 
 /*
- * vop_noresolve { struct namecache *a_ncp }   XXX STOPGAP FUNCTION
+ * vop_compat_resolve { struct namecache *a_ncp }      XXX STOPGAP FUNCTION
  *
  * XXX OLD API ROUTINE!  WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE
  * WILL BE REMOVED.  This procedure exists for all VFSs which have not
- * yet implemented vop_resolve().  It converts vop_resolve() into a 
+ * yet implemented VOP_NRESOLVE().  It converts VOP_NRESOLVE() into a 
  * vop_lookup() and does appropriate translations.
  *
  * Resolve a ncp for VFSs which do not support the VOP.  Eventually all
  * VFSs will support this VOP and this routine can be removed, since
- * vop_resolve() is far less complex then the older LOOKUP/CACHEDLOOKUP
+ * VOP_NRESOLVE() is far less complex then the older LOOKUP/CACHEDLOOKUP
  * API.
  *
  * A locked ncp is passed in to be resolved.  The NCP is resolved by
@@ -171,11 +182,13 @@ vop_panic(struct vop_generic_args *ap)
  * negative cache entry.  No vnode locks are retained and the
  * ncp is left locked on return.
  *
+ * The ncp will NEVER represent "", "." or "..", or contain any slashes.
+ *
  * There is a potential directory and vnode interlock.   The lock order
  * requirement is: namecache, governing directory, resolved vnode.
  */
 int
-vop_noresolve(struct vop_resolve_args *ap)
+vop_compat_nresolve(struct vop_nresolve_args *ap)
 {
        int error;
        struct vnode *dvp;
@@ -191,15 +204,20 @@ vop_noresolve(struct vop_resolve_args *ap)
        if ((dvp = ncp->nc_parent->nc_vp) == NULL)
                return(EPERM);
 
+       /*
+        * UFS currently stores all sorts of side effects, including a loop
+        * variable, in the directory inode.  That needs to be fixed and the
+        * other VFS's audited before we can switch to LK_SHARED.
+        */
        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);
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
                return(EAGAIN);
        }
 
        bzero(&cnp, sizeof(cnp));
        cnp.cn_nameiop = NAMEI_LOOKUP;
-       cnp.cn_flags = CNP_ISLASTCN;
+       cnp.cn_flags = 0;
        cnp.cn_nameptr = ncp->nc_name;
        cnp.cn_namelen = ncp->nc_nlen;
        cnp.cn_cred = ap->a_cred;
@@ -232,67 +250,881 @@ vop_noresolve(struct vop_resolve_args *ap)
        return (error);
 }
 
-#if 0
+/*
+ * vop_compat_nlookupdotdot { struct vnode *a_dvp,
+ *                     struct vnode **a_vpp,
+ *                     struct ucred *a_cred }
+ *
+ * Lookup the vnode representing the parent directory of the specified
+ * directory vnode.  a_dvp should not be locked.  If no error occurs *a_vpp
+ * will contained the parent vnode, locked and refd, else *a_vpp will be NULL.
+ *
+ * This function is designed to aid NFS server-side operations and is
+ * used by cache_fromdvp() to create a consistent, connected namecache
+ * topology.
+ *
+ * As part of the NEW API work, VFSs will first split their CNP_ISDOTDOT
+ * code out from their *_lookup() and create *_nlookupdotdot().  Then as time
+ * permits VFSs will implement the remaining *_n*() calls and finally get
+ * rid of their *_lookup() call.
+ */
+int
+vop_compat_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
+{
+       struct componentname cnp;
+       int error;
+
+       /*
+        * UFS currently stores all sorts of side effects, including a loop
+        * variable, in the directory inode.  That needs to be fixed and the
+        * other VFS's audited before we can switch to LK_SHARED.
+        */
+       *ap->a_vpp = NULL;
+       if ((error = vget(ap->a_dvp, LK_EXCLUSIVE, curthread)) != 0)
+               return (error);
+       if (ap->a_dvp->v_type != VDIR) {
+               vput(ap->a_dvp);
+               return (ENOTDIR);
+       }
+
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_LOOKUP;
+       cnp.cn_flags = CNP_ISDOTDOT;
+       cnp.cn_nameptr = "..";
+       cnp.cn_namelen = 2;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = curthread; /* XXX */
+
+       /*
+        * vop_lookup() always returns vp locked.  dvp may or may not be
+        * left locked depending on CNP_PDIRUNLOCK.
+        */
+       error = vop_lookup(ap->a_head.a_ops, ap->a_dvp, ap->a_vpp, &cnp);
+       if (error == 0)
+               VOP_UNLOCK(*ap->a_vpp, 0, curthread);
+       if (cnp.cn_flags & CNP_PDIRUNLOCK)
+               vrele(ap->a_dvp);
+       else
+               vput(ap->a_dvp);
+       return (error);
+}
 
 /*
- * vop_noremove { struct namecache *a_ncp }    XXX STOPGAP FUNCTION
+ * vop_compat_ncreate { struct namecache *a_ncp,       XXX STOPGAP FUNCTION
+ *                     struct vnode *a_vpp,
+ *                     struct ucred *a_cred,
+ *                     struct vattr *a_vap }
  *
- * Remove the file/dir represented by a_ncp.
+ * Create a file as specified by a_vap.  Compatibility requires us to issue
+ * the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_CREATE in order
+ * to setup the directory inode's i_offset and i_count (e.g. in UFS).
+ */
+int
+vop_compat_ncreate(struct vop_ncreate_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
+       int error;
+
+       /*
+        * Sanity checks, get a locked directory vnode.
+        */
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to create the entry in the
+        * directory inode.  We expect a return code of EJUSTRETURN for
+        * the CREATE case.  The cnp must simulated a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_CREATE;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+       *ap->a_vpp = NULL;
+
+       error = vop_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
+
+       /*
+        * EJUSTRETURN should be returned for this case, which means that
+        * the VFS has setup the directory inode for the create.  The dvp we
+        * passed in is expected to remain in a locked state.
+        *
+        * If the VOP_OLD_CREATE is successful we are responsible for updating
+        * the cache state of the locked ncp that was passed to us.
+        */
+       if (error == EJUSTRETURN) {
+               KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+               error = VOP_OLD_CREATE(dvp, ap->a_vpp, &cnp, ap->a_vap);
+               if (error == 0) {
+                       cache_setunresolved(ncp);
+                       cache_setvp(ncp, *ap->a_vpp);
+               }
+       } else {
+               if (error == 0) {
+                       vput(*ap->a_vpp);
+                       *ap->a_vpp = NULL;
+                       error = EEXIST;
+               }
+               KKASSERT(*ap->a_vpp == NULL);
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
+}
+
+/*
+ * vop_compat_nmkdir { struct namecache *a_ncp,        XXX STOPGAP FUNCTION
+ *                     struct vnode *a_vpp,
+ *                     struct ucred *a_cred,
+ *                     struct vattr *a_vap }
  *
- * XXX ultra difficult.  A number of existing filesystems, including UFS,
- *     assume that the directory will remain locked and the lookup will
- *     store the directory offset and other things in the directory inode
- *     for the later VOP_REMOVE to use.  We have to move all that
- *     functionality into e.g. UFS's VOP_REMOVE itself.
+ * Create a directory as specified by a_vap.  Compatibility requires us to
+ * issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKDIR in
+ * order to setup the directory inode's i_offset and i_count (e.g. in UFS).
  */
-static int
-vop_nonremove(struct vop_nremove_args *ap)
+int
+vop_compat_nmkdir(struct vop_nmkdir_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
+       int error;
+
+       /*
+        * Sanity checks, get a locked directory vnode.
+        */
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to create the entry in the
+        * directory inode.  We expect a return code of EJUSTRETURN for
+        * the CREATE case.  The cnp must simulated a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_CREATE;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+       *ap->a_vpp = NULL;
+
+       error = vop_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
+
+       /*
+        * EJUSTRETURN should be returned for this case, which means that
+        * the VFS has setup the directory inode for the create.  The dvp we
+        * passed in is expected to remain in a locked state.
+        *
+        * If the VOP_OLD_MKDIR is successful we are responsible for updating
+        * the cache state of the locked ncp that was passed to us.
+        */
+       if (error == EJUSTRETURN) {
+               KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+               error = VOP_OLD_MKDIR(dvp, ap->a_vpp, &cnp, ap->a_vap);
+               if (error == 0) {
+                       cache_setunresolved(ncp);
+                       cache_setvp(ncp, *ap->a_vpp);
+               }
+       } else {
+               if (error == 0) {
+                       vput(*ap->a_vpp);
+                       *ap->a_vpp = NULL;
+                       error = EEXIST;
+               }
+               KKASSERT(*ap->a_vpp == NULL);
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
+}
+
+/*
+ * vop_compat_nmknod { struct namecache *a_ncp,        XXX STOPGAP FUNCTION
+ *                     struct vnode *a_vpp,
+ *                     struct ucred *a_cred,
+ *                     struct vattr *a_vap }
+ *
+ * Create a device or fifo node as specified by a_vap.  Compatibility requires
+ * us to issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKNOD
+ * in order to setup the directory inode's i_offset and i_count (e.g. in UFS).
+ */
+int
+vop_compat_nmknod(struct vop_nmknod_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
+       int error;
+
+       /*
+        * Sanity checks, get a locked directory vnode.
+        */
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to create the entry in the
+        * directory inode.  We expect a return code of EJUSTRETURN for
+        * the CREATE case.  The cnp must simulated a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_CREATE;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+       *ap->a_vpp = NULL;
+
+       error = vop_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
+
+       /*
+        * EJUSTRETURN should be returned for this case, which means that
+        * the VFS has setup the directory inode for the create.  The dvp we
+        * passed in is expected to remain in a locked state.
+        *
+        * If the VOP_OLD_MKNOD is successful we are responsible for updating
+        * the cache state of the locked ncp that was passed to us.
+        */
+       if (error == EJUSTRETURN) {
+               KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+               error = VOP_OLD_MKNOD(dvp, ap->a_vpp, &cnp, ap->a_vap);
+               if (error == 0) {
+                       cache_setunresolved(ncp);
+                       cache_setvp(ncp, *ap->a_vpp);
+               }
+       } else {
+               if (error == 0) {
+                       vput(*ap->a_vpp);
+                       *ap->a_vpp = NULL;
+                       error = EEXIST;
+               }
+               KKASSERT(*ap->a_vpp == NULL);
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
+}
+
+/*
+ * vop_compat_nlink { struct namecache *a_ncp,         XXX STOPGAP FUNCTION
+ *                     struct vnode *a_vp,
+ *                     struct ucred *a_cred }
+ *
+ * The passed vp is locked and represents the source.  The passed ncp is
+ * locked and represents the target to create.
+ */
+int
+vop_compat_nlink(struct vop_nlink_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
+       struct vnode *tvp;
+       int error;
+
+       /*
+        * Sanity checks, get a locked directory vnode.
+        */
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to create the entry in the
+        * directory inode.  We expect a return code of EJUSTRETURN for
+        * the CREATE case.  The cnp must simulated a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_CREATE;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+
+       tvp = NULL;
+       error = vop_lookup(ap->a_head.a_ops, dvp, &tvp, &cnp);
+
+       /*
+        * EJUSTRETURN should be returned for this case, which means that
+        * the VFS has setup the directory inode for the create.  The dvp we
+        * passed in is expected to remain in a locked state.
+        *
+        * If the VOP_OLD_LINK is successful we are responsible for updating
+        * the cache state of the locked ncp that was passed to us.
+        */
+       if (error == EJUSTRETURN) {
+               KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+               VOP_LEASE(ap->a_vp, td, ap->a_cred, LEASE_WRITE);
+               error = VOP_OLD_LINK(dvp, ap->a_vp, &cnp);
+               if (error == 0) {
+                       cache_setunresolved(ncp);
+                       cache_setvp(ncp, ap->a_vp);
+               }
+       } else {
+               if (error == 0) {
+                       vput(tvp);
+                       error = EEXIST;
+               }
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
+}
+
+int
+vop_compat_nsymlink(struct vop_nsymlink_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
+       struct vnode *vp;
+       int error;
+
+       /*
+        * Sanity checks, get a locked directory vnode.
+        */
+       *ap->a_vpp = NULL;
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to create the entry in the
+        * directory inode.  We expect a return code of EJUSTRETURN for
+        * the CREATE case.  The cnp must simulated a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_CREATE;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+
+       vp = NULL;
+       error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
+
+       /*
+        * EJUSTRETURN should be returned for this case, which means that
+        * the VFS has setup the directory inode for the create.  The dvp we
+        * passed in is expected to remain in a locked state.
+        *
+        * If the VOP_OLD_SYMLINK is successful we are responsible for updating
+        * the cache state of the locked ncp that was passed to us.
+        */
+       if (error == EJUSTRETURN) {
+               KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+               error = VOP_OLD_SYMLINK(dvp, &vp, &cnp, ap->a_vap, ap->a_target);
+               if (error == 0) {
+                       cache_setunresolved(ncp);
+                       cache_setvp(ncp, vp);
+                       *ap->a_vpp = vp;
+               }
+       } else {
+               if (error == 0) {
+                       vput(vp);
+                       vp = NULL;
+                       error = EEXIST;
+               }
+               KKASSERT(vp == NULL);
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
+}
+
+/*
+ * vop_compat_nwhiteout { struct namecache *a_ncp,     XXX STOPGAP FUNCTION
+ *                       struct ucred *a_cred,
+ *                       int a_flags }
+ *
+ * Issie a whiteout operation (create, lookup, or delete).  Compatibility 
+ * requires us to issue the appropriate VOP_OLD_LOOKUP before we issue 
+ * VOP_OLD_WHITEOUT in order to setup the directory inode's i_offset and i_count
+ * (e.g. in UFS) for the NAMEI_CREATE and NAMEI_DELETE ops.  For NAMEI_LOOKUP
+ * no lookup is necessary.
+ */
+int
+vop_compat_nwhiteout(struct vop_nwhiteout_args *ap)
 {
-       struct namecache *ncfile;
-       struct namecache *ncdir;
-       struct componentname cnd;
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
        struct vnode *vp;
-       struct vnode *vpd;
-       thread_t td;
        int error;
 
-       td = curthread;
-       ncfile = ap->a_ncp;
-       ncdir = ncfile->nc_parent;
+       /*
+        * Sanity checks, get a locked directory vnode.
+        */
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
 
-       if ((error = cache_vget(ncdir, ap->a_cred, LK_EXCLUSIVE, &vpd)) != 0)
-               return (error);
-       if ((error = cache_vget(ncfile, ap->a_cred, LK_EXCLUSIVE, &vp)) != 0) {
-               vput(vpd);
-               return (error);
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
        }
-       bzero(&cnd, sizeof(cnd));
-       cnd.cn_nameiop = NAMEI_DELETE;
-       cnd.cn_td = td;
-       cnd.cn_cred = ap->a_cred;
-       cnd.cn_nameptr = ncfile->nc_name;
-       cnd.cn_namelen = ncfile->nc_nlen;
-       error = VOP_REMOVE(vpd, NCPNULL, vp, &cnd);
-       if (error == 0)
-               cache_purge(vp);
-       vput(vp);
-       vput(vpd);
 
        /*
-        * Re-resolve the ncp to match the fact that the file has been
-        * deleted from the namespace.  If an error occured leave the ncp
-        * unresolved (meaning that we have no idea what the correct state
-        * is).
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to create the entry in the
+        * directory inode.  We expect a return code of EJUSTRETURN for
+        * the CREATE case.  The cnp must simulated a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = ap->a_flags;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+
+       vp = NULL;
+
+       /*
+        * EJUSTRETURN should be returned for the CREATE or DELETE cases.
+        * The VFS has setup the directory inode for the create.  The dvp we
+        * passed in is expected to remain in a locked state.
+        *
+        * If the VOP_OLD_WHITEOUT is successful we are responsible for updating
+        * the cache state of the locked ncp that was passed to us.
+        */
+       switch(ap->a_flags) {
+       case NAMEI_DELETE:
+               cnp.cn_flags |= CNP_DOWHITEOUT;
+               /* fall through */
+       case NAMEI_CREATE:
+               error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
+               if (error == EJUSTRETURN) {
+                       KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+                       VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+                       error = VOP_OLD_WHITEOUT(dvp, &cnp, ap->a_flags);
+                       if (error == 0)
+                               cache_setunresolved(ncp);
+               } else {
+                       if (error == 0) {
+                               vput(vp);
+                               vp = NULL;
+                               error = EEXIST;
+                       }
+                       KKASSERT(vp == NULL);
+               }
+               break;
+       case NAMEI_LOOKUP:
+               error = VOP_OLD_WHITEOUT(dvp, NULL, ap->a_flags);
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
+}
+
+
+/*
+ * vop_compat_nremove { struct namecache *a_ncp,       XXX STOPGAP FUNCTION
+ *                       struct ucred *a_cred }
+ */
+int
+vop_compat_nremove(struct vop_nremove_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
+       struct vnode *vp;
+       int error;
+
+       /*
+        * Sanity checks, get a locked directory vnode.
         */
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to delete the entry in the
+        * directory inode.  We expect a return code of 0 for the DELETE
+        * case (meaning that a vp has been found).  The cnp must simulated
+        * a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_DELETE;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+
+       /*
+        * The vnode must be a directory and must not represent the
+        * current directory.
+        */
+       vp = NULL;
+       error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
+       if (error == 0 && vp->v_type == VDIR)
+               error = EPERM;
        if (error == 0) {
-               cache_setunresolved(ncfile);
-               cache_setvp(ncfile, NULL);
+               KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+               VOP_LEASE(vp, td, ap->a_cred, LEASE_WRITE);
+               error = VOP_OLD_REMOVE(dvp, vp, &cnp);
+               if (error == 0) {
+                       cache_setunresolved(ncp);
+                       cache_setvp(ncp, NULL);
+               }
        }
-        return (error);
+       if (vp) {
+               if (dvp == vp)
+                       vrele(vp);
+               else    
+                       vput(vp);
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
 }
 
-#endif
+/*
+ * vop_compat_nrmdir { struct namecache *a_ncp,        XXX STOPGAP FUNCTION
+ *                       struct ucred *a_cred }
+ */
+int
+vop_compat_nrmdir(struct vop_nrmdir_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname cnp;
+       struct namecache *ncp;
+       struct vnode *dvp;
+       struct vnode *vp;
+       int error;
+
+       /*
+        * Sanity checks, get a locked directory vnode.
+        */
+       ncp = ap->a_ncp;                /* locked namecache node */
+       if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (ncp->nc_parent == NULL)
+               return(EPERM);
+       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       ncp, ncp->nc_name);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to delete the entry in the
+        * directory inode.  We expect a return code of 0 for the DELETE
+        * case (meaning that a vp has been found).  The cnp must simulated
+        * a saved-name situation.
+        */
+       bzero(&cnp, sizeof(cnp));
+       cnp.cn_nameiop = NAMEI_DELETE;
+       cnp.cn_flags = CNP_LOCKPARENT;
+       cnp.cn_nameptr = ncp->nc_name;
+       cnp.cn_namelen = ncp->nc_nlen;
+       cnp.cn_cred = ap->a_cred;
+       cnp.cn_td = td;
+
+       /*
+        * The vnode must be a directory and must not represent the
+        * current directory.
+        */
+       vp = NULL;
+       error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
+       if (error == 0 && vp->v_type != VDIR)
+               error = ENOTDIR;
+       if (error == 0 && vp == dvp)
+               error = EINVAL;
+       if (error == 0 && (vp->v_flag & VROOT))
+               error = EBUSY;
+       if (error == 0) {
+               KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE);
+               VOP_LEASE(vp, td, ap->a_cred, LEASE_WRITE);
+               error = VOP_OLD_RMDIR(dvp, vp, &cnp);
+
+               /*
+                * Note that this invalidation will cause any process
+                * currently CD'd into the directory being removed to be
+                * disconnected from the topology and not be able to ".."
+                * back out.
+                */
+               if (error == 0)
+                       cache_inval(ncp, CINV_SELF|CINV_PARENT);
+       }
+       if (vp) {
+               if (dvp == vp)
+                       vrele(vp);
+               else    
+                       vput(vp);
+       }
+       if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
+               VOP_UNLOCK(dvp, 0, td);
+       vrele(dvp);
+       return (error);
+}
+
+/*
+ * vop_compat_nrename { struct namecache *a_fncp,      XXX STOPGAP FUNCTION
+ *                     struct namecache *a_tncp,
+ *                     struct ucred *a_cred }
+ *
+ * This is a fairly difficult procedure.  The old VOP_OLD_RENAME requires that
+ * the source directory and vnode be unlocked and the target directory and
+ * vnode (if it exists) be locked.  All arguments will be vrele'd and 
+ * the targets will also be unlocked regardless of the return code.
+ */
+int
+vop_compat_nrename(struct vop_nrename_args *ap)
+{
+       struct thread *td = curthread;
+       struct componentname fcnp;
+       struct componentname tcnp;
+       struct namecache *fncp;
+       struct namecache *tncp;
+       struct vnode *fdvp, *fvp;
+       struct vnode *tdvp, *tvp;
+       int error;
+
+       /*
+        * Sanity checks, get referenced vnodes representing the source.
+        */
+       fncp = ap->a_fncp;              /* locked namecache node */
+       if (fncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               return(EPERM);
+       if (fncp->nc_parent == NULL)
+               return(EPERM);
+       if ((fdvp = fncp->nc_parent->nc_vp) == NULL)
+               return(EPERM);
+
+       /*
+        * Temporarily lock the source directory and lookup in DELETE mode to
+        * check permissions.  XXX delete permissions should have been
+        * checked by nlookup(), we need to add NLC_DELETE for delete
+        * checking.  It is unclear whether VFS's require the directory setup
+        * info NAMEI_DELETE causes to be stored in the fdvp's inode, but
+        * since it isn't locked and since UFS always does a relookup of
+        * the source, it is believed that the only side effect that matters
+        * is the permissions check.
+        */
+       if ((error = vget(fdvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       fncp, fncp->nc_name);
+               return(EAGAIN);
+       }
+
+       bzero(&fcnp, sizeof(fcnp));
+       fcnp.cn_nameiop = NAMEI_DELETE;
+       fcnp.cn_flags = CNP_LOCKPARENT;
+       fcnp.cn_nameptr = fncp->nc_name;
+       fcnp.cn_namelen = fncp->nc_nlen;
+       fcnp.cn_cred = ap->a_cred;
+       fcnp.cn_td = td;
+
+       /*
+        * note: vop_lookup (i.e. VOP_OLD_LOOKUP) always returns a locked
+        * fvp.
+        */
+       fvp = NULL;
+       error = vop_lookup(ap->a_head.a_ops, fdvp, &fvp, &fcnp);
+       if (error == 0 && (fvp->v_flag & VROOT)) {
+               vput(fvp);      /* as if vop_lookup had failed */
+               error = EBUSY;
+       }
+       if ((fcnp.cn_flags & CNP_PDIRUNLOCK) == 0) {
+               fcnp.cn_flags |= CNP_PDIRUNLOCK;
+               VOP_UNLOCK(fdvp, 0, td);
+       }
+       if (error) {
+               vrele(fdvp);
+               return (error);
+       }
+       VOP_UNLOCK(fvp, 0, td);
 
+       /*
+        * fdvp and fvp are now referenced and unlocked.
+        *
+        * Get a locked directory vnode for the target and lookup the target
+        * in CREATE mode so it places the required information in the
+        * directory inode.
+        */
+       tncp = ap->a_tncp;              /* locked namecache node */
+       if (tncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
+               error = EPERM;
+       if (tncp->nc_parent == NULL)
+               error = EPERM;
+       if ((tdvp = tncp->nc_parent->nc_vp) == NULL)
+               error = EPERM;
+       if (error) {
+               vrele(fdvp);
+               vrele(fvp);
+               return (error);
+       }
+       if ((error = vget(tdvp, LK_EXCLUSIVE, td)) != 0) {
+               printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
+                       tncp, tncp->nc_name);
+               vrele(fdvp);
+               vrele(fvp);
+               return(EAGAIN);
+       }
+
+       /*
+        * Setup the cnp for a traditional vop_lookup() call.  The lookup
+        * caches all information required to create the entry in the
+        * target directory inode.
+        */
+       bzero(&tcnp, sizeof(tcnp));
+       tcnp.cn_nameiop = NAMEI_RENAME;
+       tcnp.cn_flags = CNP_LOCKPARENT;
+       tcnp.cn_nameptr = tncp->nc_name;
+       tcnp.cn_namelen = tncp->nc_nlen;
+       tcnp.cn_cred = ap->a_cred;
+       tcnp.cn_td = td;
+
+       tvp = NULL;
+       error = vop_lookup(ap->a_head.a_ops, tdvp, &tvp, &tcnp);
+
+       if (error == EJUSTRETURN) {
+               /*
+                * Target does not exist.  tvp should be NULL.
+                */
+               KKASSERT(tvp == NULL);
+               KKASSERT((tcnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               error = VOP_OLD_RENAME(fdvp, fvp, &fcnp, tdvp, tvp, &tcnp);
+               if (error == 0) {
+                       cache_rename(fncp, tncp);
+                       cache_setvp(tncp, fvp);
+               }
+       } else if (error == 0) {
+               /*
+                * Target exists.  VOP_OLD_RENAME should correctly delete the
+                * target.
+                */
+               KKASSERT((tcnp.cn_flags & CNP_PDIRUNLOCK) == 0);
+               error = VOP_OLD_RENAME(fdvp, fvp, &fcnp, tdvp, tvp, &tcnp);
+               if (error == 0) {
+                       cache_rename(fncp, tncp);
+                       cache_setvp(tncp, fvp);
+               }
+       } else {
+               vrele(fdvp);
+               vrele(fvp);
+               if (tcnp.cn_flags & CNP_PDIRUNLOCK)
+                       vrele(tdvp);
+               else
+                       vput(tdvp);
+       }
+       return (error);
+}
 
 static int
 vop_nolookup(ap)
@@ -580,7 +1412,7 @@ vop_stdgetvobject(ap)
  */
 int 
 vfs_stdmount(struct mount *mp, char *path, caddr_t data,
-       struct nameidata *ndp, struct thread *td)
+       struct nlookupdata *nd, struct thread *td)
 {
        return (0);
 }
index 2933160..9980dbf 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.20 2004/10/22 18:03:50 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_lookup.c,v 1.21 2004/11/12 00:09:24 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -63,639 +63,56 @@ SYSCTL_INT(_vfs, OID_AUTO, varsym_enable, CTLFLAG_RW, &varsym_enable, 0,
            "Enable Variant Symlinks");
 
 /*
- * Convert a pathname into a pointer to a locked inode.
+ * OLD API FUNCTION
  *
- * The CNP_FOLLOW flag is set when symbolic links are to be followed
- * when they occur at the end of the name translation process.
- * Symbolic links are always followed for all other pathname
- * components other than the last.
+ * Relookup a path name component.  This function is only used by the
+ * old API *_rename() code under very specific conditions.  CNP_LOCKPARENT
+ * must be set in the cnp.  dvp must be unlocked on entry and will be left
+ * unlocked if an error occurs.
  *
- * The segflg defines whether the name is to be copied from user
- * space or kernel space.
- *
- * Overall outline of namei:
- *
- *     copy in name
- *     get starting directory
- *     while (!done && !error) {
- *             call lookup to search path.
- *             if symbolic link, massage name in buffer and continue
- *     }
- *
- * NOTE: when namei() is called from a pure thread the system rootvnode
- * will be used as a basis for the search.
+ * The returned *vpp will be NULL if an error occurs.  Note that no error
+ * will occur (error == 0) for CREATE requests on a non-existant target, but
+ * *vpp will be NULL in that case.  Both dvp and *vpp (if not NULL) will be
+ * locked in the no-error case.   No additional references are made to dvp,
+ * only the locking state changes.
  */
 int
-namei(struct nameidata *ndp)
+relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
 {
-       struct filedesc *fdp;   /* pointer to file descriptor state */
-       char *cp;               /* pointer into pathname argument */
-       struct vnode *dp;       /* the directory we are searching */
-       struct iovec aiov;              /* uio for reading symbolic links */
-       struct uio auio;
-       int error, linklen;
-       struct componentname *cnp = &ndp->ni_cnd;
-       struct proc *p;
-
-       KKASSERT(ndp->ni_cnd.cn_td != NULL);
-       p = cnp->cn_td->td_proc;
-       if (p == NULL) {
-               KKASSERT(ndp->ni_segflg == UIO_SYSSPACE);
-               printf("namei() from non-process\n");
-               fdp = NULL;
-       } else {
-               KKASSERT(cnp->cn_cred == p->p_ucred); /* YYY */
-               fdp = p->p_fd;
-       }
-       KASSERT(cnp->cn_cred, ("namei: bad cred/proc"));
-       KASSERT((cnp->cn_nameiop & (~NAMEI_OPMASK)) == 0,
-           ("namei: nameiop contaminated with flags"));
-       KASSERT((cnp->cn_flags & NAMEI_OPMASK) == 0,
-           ("namei: flags contaminated with nameiops"));
-
-       /*
-        * Get a buffer for the name to be translated, and copy the
-        * name into the buffer.
-        */
-       if ((cnp->cn_flags & CNP_HASBUF) == 0)
-               cnp->cn_pnbuf = zalloc(namei_zone);
-       if (ndp->ni_segflg == UIO_SYSSPACE)
-               error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
-                           MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
-       else
-               error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
-                           MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
-
-       /*
-        * Don't allow empty pathnames.
-        * POSIX.1 requirement: "" is not a vaild file name.
-        */
-       if (!error && *cnp->cn_pnbuf == '\0')
-               error = ENOENT;
-
-       if (error) {
-               zfree(namei_zone, cnp->cn_pnbuf);
-               ndp->ni_vp = NULL;
-               return (error);
-       }
-       ndp->ni_loopcnt = 0;
-#ifdef KTRACE
-       if (KTRPOINT(cnp->cn_td, KTR_NAMEI))
-               ktrnamei(cnp->cn_td->td_proc->p_tracep, cnp->cn_pnbuf);
-#endif
-
-       /*
-        * Get starting point for the translation.
-        */
-       if (fdp) {
-               ndp->ni_rootdir = fdp->fd_rdir;
-               ndp->ni_topdir = fdp->fd_jdir;
-               dp = fdp->fd_cdir;
-       } else {
-               ndp->ni_rootdir = rootvnode;
-               ndp->ni_topdir = rootvnode;
-               dp = rootvnode;
-       }
-       vref(dp);
-       for (;;) {
-               /*
-                * Check if root directory should replace current directory.
-                * Done at start of translation and after symbolic link.
-                */
-               cnp->cn_nameptr = cnp->cn_pnbuf;
-               if (*(cnp->cn_nameptr) == '/') {
-                       vrele(dp);
-                       while (*(cnp->cn_nameptr) == '/') {
-                               cnp->cn_nameptr++;
-                               ndp->ni_pathlen--;
-                       }
-                       dp = ndp->ni_rootdir;
-                       vref(dp);
-               }
-               ndp->ni_startdir = dp;
-               error = lookup(ndp);
-               if (error) {
-                       zfree(namei_zone, cnp->cn_pnbuf);
-                       return (error);
-               }
-               /*
-                * Check for symbolic link
-                */
-               if ((cnp->cn_flags & CNP_ISSYMLINK) == 0) {
-                       if ((cnp->cn_flags & (CNP_SAVENAME | CNP_SAVESTART)) == 0)
-                               zfree(namei_zone, cnp->cn_pnbuf);
-                       else
-                               cnp->cn_flags |= CNP_HASBUF;
-
-                       if (vn_canvmio(ndp->ni_vp) == TRUE &&
-                               (cnp->cn_nameiop != NAMEI_DELETE) &&
-                               ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) ==
-                                CNP_LOCKLEAF))
-                               vfs_object_create(ndp->ni_vp, ndp->ni_cnd.cn_td);
-
-                       return (0);
-               }
-               if ((cnp->cn_flags & CNP_LOCKPARENT) && ndp->ni_pathlen == 1)
-                       VOP_UNLOCK(ndp->ni_dvp, 0, cnp->cn_td);
-               if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
-                       error = ELOOP;
-                       break;
-               }
-               if (ndp->ni_pathlen > 1)
-                       cp = zalloc(namei_zone);
-               else
-                       cp = cnp->cn_pnbuf;
-               aiov.iov_base = cp;
-               aiov.iov_len = MAXPATHLEN;
-               auio.uio_iov = &aiov;
-               auio.uio_iovcnt = 1;
-               auio.uio_offset = 0;
-               auio.uio_rw = UIO_READ;
-               auio.uio_segflg = UIO_SYSSPACE;
-               auio.uio_td = cnp->cn_td;
-               auio.uio_resid = MAXPATHLEN;
-               error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
-               if (error) {
-                       if (ndp->ni_pathlen > 1)
-                               zfree(namei_zone, cp);
-                       break;
-               }
-               linklen = MAXPATHLEN - auio.uio_resid;
-               if (linklen == 0) {
-                       if (ndp->ni_pathlen > 1)
-                               zfree(namei_zone, cp);
-                       error = ENOENT;
-                       break;
-               }
-               if (varsym_enable) {
-                       linklen = varsymreplace(cp, linklen, MAXPATHLEN);
-                       if (linklen < 0) {
-                               if (ndp->ni_pathlen > 1)
-                                       zfree(namei_zone, cp);
-                               error = ENAMETOOLONG;
-                               break;
-                       }
-               }
-               if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
-                       if (ndp->ni_pathlen > 1)
-                               zfree(namei_zone, cp);
-                       error = ENAMETOOLONG;
-                       break;
-               }
-               if (ndp->ni_pathlen > 1) {
-                       bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
-                       zfree(namei_zone, cnp->cn_pnbuf);
-                       cnp->cn_pnbuf = cp;
-               } else {
-                       cnp->cn_pnbuf[linklen] = '\0';
-               }
-               ndp->ni_pathlen += linklen;
-               vput(ndp->ni_vp);
-               dp = ndp->ni_dvp;
-       }
-       zfree(namei_zone, cnp->cn_pnbuf);
-       vrele(ndp->ni_dvp);
-       vput(ndp->ni_vp);
-       ndp->ni_vp = NULL;
-       return (error);
-}
-
-/*
- * Old API function, search a patchname.  This is an *EXTREMELY* complicated
- * function.
- *
- * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
- * The starting directory is taken from ni_startdir. The pathname is
- * descended until done, or a symbolic link is encountered. The variable
- * ni_more is clear if the path is completed; it is set to one if a
- * symbolic link needing interpretation is encountered.
- *
- * The flag argument is NAMEI_LOOKUP, CREATE, RENAME, or DELETE depending on
- * whether the name is to be looked up, created, renamed, or deleted.
- * When CREATE, RENAME, or DELETE is specified, information usable in
- * creating, renaming, or deleting a directory entry may be calculated.
- * If flag has LOCKPARENT or'ed into it, the parent directory is returned
- * locked. If flag has WANTPARENT or'ed into it, the parent directory is
- * returned unlocked. Otherwise the parent directory is not returned. If
- * the target of the pathname exists and LOCKLEAF is or'ed into the flag
- * the target is returned locked, otherwise it is returned unlocked.
- * When creating or renaming and LOCKPARENT is specified, the target may not
- * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
- *
- * SPECIAL CASE: When a symbolic link is encountered the parent
- * directory is always returned in ni_dvp regardless of WANTPARENT|LOCKPARENT
- * and the symbolic link is returned in ni_vp.  If the symbolic link was not
- * the last component ni_dvp will be returned UNLOCKED, regardless of
- * LOCKPARENT.  If the symbolic link is the last component then ni_dvp will
- * be returned locked or unlocked based on LOCKPARENT.
- *
- * SPECIAL CASE: If an error occurs ni_vp and/or ni_dvp may contain garbage
- * on return.
- *
- * VOP_LOOKUP EXPECTATIONS:  VOP_LOOKUP() takes a locked directory vnode
- * and returns a locked target vnode on success.  VOP_LOOKUP() may unlock the
- * directory vnode passed to it, in which case it will set CNP_PDIRUNLOCK.
- * However, this only occurs under very specific circumstances.  The
- * directory vnode will only be returned locked if (1) returned vnode ==
- * directory vnode, or (2) CNP_LOCKPARENT *AND* CNP_LASTCN are both set.
- */
-int
-lookup(struct nameidata *ndp)
-{
-       char *cp;                       /* pointer into pathname argument */
-       struct vnode *dp = NULL;        /* the directory we are searching */
-       struct vnode *tdp;              /* saved dp */
-       struct mount *mp;               /* mount table entry */
-       int docache;                    /* == 0 do not cache last component */
-       int wantparent;                 /* 1 => wantparent or lockparent flag */
+       struct thread *td = cnp->cn_td;
        int rdonly;                     /* lookup read-only flag bit */
-       int trailing_slash;
        int error = 0;
-       int dpunlocked = 0;             /* dp has already been unlocked */
-       struct componentname *cnp = &ndp->ni_cnd;
-       struct thread *td = cnp->cn_td;
 
        /*
         * Setup: break out flag bits into variables.
         */
-       wantparent = cnp->cn_flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
-       docache = (cnp->cn_flags & CNP_NOCACHE) ^ CNP_NOCACHE;
-       if (cnp->cn_nameiop == NAMEI_DELETE ||
-           (wantparent && cnp->cn_nameiop != NAMEI_CREATE &&
-            cnp->cn_nameiop != NAMEI_LOOKUP))
-               docache = 0;
-       rdonly = cnp->cn_flags & CNP_RDONLY;
-       ndp->ni_dvp = NULL;
-       cnp->cn_flags &= ~CNP_ISSYMLINK;
-       dp = ndp->ni_startdir;
-       ndp->ni_startdir = NULLVP;
-       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
-
-dirloop:
-       /*
-        * Search a new directory.
-        *
-        * The last component of the filename is left accessible via
-        * cnp->cn_nameptr for callers that need the name. Callers needing
-        * the name set the CNP_SAVENAME flag. When done, they assume
-        * responsibility for freeing the pathname buffer.
-        */
-       cnp->cn_consume = 0;
-       for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
-               continue;
-       cnp->cn_namelen = cp - cnp->cn_nameptr;
-       if (cnp->cn_namelen > NAME_MAX) {
-               error = ENAMETOOLONG;
-               goto bad;
-       }
-#ifdef NAMEI_DIAGNOSTIC
-       { char c = *cp;
-       *cp = '\0';
-       printf("{%s}: ", cnp->cn_nameptr);
-       *cp = c; }
-#endif
-       ndp->ni_pathlen -= cnp->cn_namelen;
-       ndp->ni_next = cp;
-
-       /*
-        * Replace multiple slashes by a single slash and trailing slashes
-        * by a null.  This must be done before VOP_LOOKUP() because some
-        * fs's don't know about trailing slashes.  Remember if there were
-        * trailing slashes to handle symlinks, existing non-directories
-        * and non-existing files that won't be directories specially later.
-        */
-       trailing_slash = 0;
-       while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
-               cp++;
-               ndp->ni_pathlen--;
-               if (*cp == '\0') {
-                       trailing_slash = 1;
-                       *ndp->ni_next = '\0';   /* XXX for direnter() ... */
-               }
-       }
-       ndp->ni_next = cp;
-
-       cnp->cn_flags |= CNP_MAKEENTRY;
-       if (*cp == '\0' && docache == 0)
-               cnp->cn_flags &= ~CNP_MAKEENTRY;
-       if (cnp->cn_namelen == 2 &&
-           cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
-               cnp->cn_flags |= CNP_ISDOTDOT;
-       else
-               cnp->cn_flags &= ~CNP_ISDOTDOT;
-       if (*ndp->ni_next == 0)
-               cnp->cn_flags |= CNP_ISLASTCN;
-       else
-               cnp->cn_flags &= ~CNP_ISLASTCN;
-
-
-       /*
-        * Check for degenerate name (e.g. / or "")
-        * which is a way of talking about a directory,
-        * e.g. like "/." or ".".
-        */
-       if (cnp->cn_nameptr[0] == '\0') {
-               if (dp->v_type != VDIR) {
-                       error = ENOTDIR;
-                       goto bad;
-               }
-               if (cnp->cn_nameiop != NAMEI_LOOKUP) {
-                       error = EISDIR;
-                       goto bad;
-               }
-               if (wantparent) {
-                       ndp->ni_dvp = dp;
-                       vref(dp);
-               }
-               ndp->ni_vp = dp;
-               if (!(cnp->cn_flags & (CNP_LOCKPARENT | CNP_LOCKLEAF)))
-                       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");
-               return (0);
-       }
-
-       /*
-        * Handle "..": two special cases.
-        * 1. If at root directory (e.g. after chroot)
-        *    or at absolute root directory
-        *    then ignore it so can't get out.
-        * 2. If this vnode is the root of a mounted
-        *    filesystem, then replace it with the
-        *    vnode which was mounted on so we take the
-        *    .. in the other file system.
-        * 3. If the vnode is the top directory of
-        *    the jail or chroot, don't let them out.
-        */
-       if (cnp->cn_flags & CNP_ISDOTDOT) {
-               for (;;) {
-                       if (dp == ndp->ni_rootdir || 
-                           dp == ndp->ni_topdir || 
-                           dp == rootvnode) {
-                               ndp->ni_dvp = dp;
-                               ndp->ni_vp = dp;
-                               vref(dp);
-                               goto nextname;
-                       }
-                       if ((dp->v_flag & VROOT) == 0 ||
-                           (cnp->cn_flags & CNP_NOCROSSMOUNT))
-                               break;
-                       if (dp->v_mount == NULL) {      /* forced unmount */
-                               error = EBADF;
-                               goto bad;
-                       }
-                       tdp = dp;
-                       dp = dp->v_mount->mnt_vnodecovered;
-                       vput(tdp);
-                       vref(dp);
-                       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
-               }
-       }
-
-       /*
-        * We now have a segment name to search for, and a directory to search.
-        */
-unionlookup:
-       ndp->ni_dvp = dp;
-       ndp->ni_vp = NULL;
+       KKASSERT(cnp->cn_flags & CNP_LOCKPARENT);
+       KKASSERT(cnp->cn_flags & CNP_PDIRUNLOCK);
+       vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
        cnp->cn_flags &= ~CNP_PDIRUNLOCK;
-       ASSERT_VOP_LOCKED(dp, "lookup");
-       if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
-               KASSERT(ndp->ni_vp == NULL, ("leaf should be empty"));
-#ifdef NAMEI_DIAGNOSTIC
-               printf("not found\n");
-#endif
-               if ((error == ENOENT) &&
-                   (dp->v_flag & VROOT) && (dp->v_mount != NULL) &&
-                   (dp->v_mount->mnt_flag & MNT_UNION)) {
-                       tdp = dp;
-                       dp = dp->v_mount->mnt_vnodecovered;
-                       if (cnp->cn_flags & CNP_PDIRUNLOCK)
-                               vrele(tdp);
-                       else
-                               vput(tdp);
-                       vref(dp);
-                       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
-                       goto unionlookup;
-               }
-
-               if (error != EJUSTRETURN)
-                       goto bad;
-               /*
-                * If creating and at end of pathname, then can consider
-                * allowing file to be created.
-                */
-               if (rdonly) {
-                       error = EROFS;
-                       goto bad;
-               }
-               if (*cp == '\0' && trailing_slash &&
-                    !(cnp->cn_flags & CNP_WILLBEDIR)) {
-                       error = ENOENT;
-                       goto bad;
-               }
-               /*
-                * We return with ni_vp NULL to indicate that the entry
-                * doesn't currently exist, leaving a pointer to the
-                * (possibly locked) directory inode in ndp->ni_dvp.
-                */
-               if (cnp->cn_flags & CNP_SAVESTART) {
-                       ndp->ni_startdir = ndp->ni_dvp;
-                       vref(ndp->ni_startdir);
-               }
-               return (0);
-       }
-#ifdef NAMEI_DIAGNOSTIC
-       printf("found\n");
-#endif
-
-       ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup");
 
-       /*
-        * Take into account any additional components consumed by
-        * the underlying filesystem.
-        */
-       if (cnp->cn_consume > 0) {
-               cnp->cn_nameptr += cnp->cn_consume;
-               ndp->ni_next += cnp->cn_consume;
-               ndp->ni_pathlen -= cnp->cn_consume;
-               cnp->cn_consume = 0;
-       }
-
-       dp = ndp->ni_vp;
-
-       /*
-        * Check to see if the vnode has been mounted on;
-        * if so find the root of the mounted file system.
-        */
-       while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
-              (cnp->cn_flags & CNP_NOCROSSMOUNT) == 0) {
-               if (vfs_busy(mp, 0, NULL, td))
-                       continue;
-               VOP_UNLOCK(dp, 0, td);
-               error = VFS_ROOT(mp, &tdp);
-               vfs_unbusy(mp, td);
-               if (error) {
-                       dpunlocked = 1;
-                       goto bad2;
-               }
-               vrele(dp);
-               ndp->ni_vp = dp = tdp;
-       }
-
-       /*
-        * Check for symbolic link
-        */
-       if ((dp->v_type == VLNK) &&
-           ((cnp->cn_flags & CNP_FOLLOW) || trailing_slash ||
-            *ndp->ni_next == '/')) {
-               cnp->cn_flags |= CNP_ISSYMLINK;
-               if (dp->v_mount == NULL) {
-                       /* We can't know whether the directory was mounted with
-                        * NOSYMFOLLOW, so we can't follow safely. */
-                       error = EBADF;
-                       goto bad2;
-               }
-               if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
-                       error = EACCES;
-                       goto bad2;
-               }
-               return (0);
-       }
-
-       /*
-        * Check for bogus trailing slashes.
-        */
-       if (trailing_slash && dp->v_type != VDIR) {
-               error = ENOTDIR;
-               goto bad2;
-       }
-
-nextname:
-       /*
-        * Not a symbolic link.  If more pathname,
-        * continue at next component, else return.
-        */
-       if (*ndp->ni_next == '/') {
-               cnp->cn_nameptr = ndp->ni_next;
-               while (*cnp->cn_nameptr == '/') {
-                       cnp->cn_nameptr++;
-                       ndp->ni_pathlen--;
-               }
-               if (ndp->ni_dvp != ndp->ni_vp)
-                       ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup");
-               vrele(ndp->ni_dvp);
-               goto dirloop;
-       }
-       /*
-        * Disallow directory write attempts on read-only file systems.
-        */
-       if (rdonly &&
-           (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) {
-               error = EROFS;
-               goto bad2;
-       }
-       if (cnp->cn_flags & CNP_SAVESTART) {
-               ndp->ni_startdir = ndp->ni_dvp;
-               vref(ndp->ni_startdir);
-       }
-       if (!wantparent)
-               vrele(ndp->ni_dvp);
-
-       if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
-               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, 0, td);
-       vrele(ndp->ni_dvp);
-bad:
-       if (dpunlocked)
-               vrele(dp);
-       else
-               vput(dp);
-       ndp->ni_vp = NULL;
-       return (error);
-}
-
-/*
- * relookup - lookup a path name component
- *    Used by lookup to re-aquire things.
- */
-int
-relookup(dvp, vpp, cnp)
-       struct vnode *dvp, **vpp;
-       struct componentname *cnp;
-{
-       struct thread *td = cnp->cn_td;
-       struct vnode *dp = 0;           /* the directory we are searching */
-       int wantparent;                 /* 1 => wantparent or lockparent flag */
-       int rdonly;                     /* lookup read-only flag bit */
-       int error = 0;
-#ifdef NAMEI_DIAGNOSTIC
-       int newhash;                    /* DEBUG: check name hash */
-       char *cp;                       /* DEBUG: check name ptr/len */
-#endif
-
-       /*
-        * Setup: break out flag bits into variables.
-        */
-       wantparent = cnp->cn_flags & (CNP_LOCKPARENT|CNP_WANTPARENT);
+       *vpp = NULL;
        rdonly = cnp->cn_flags & CNP_RDONLY;
-       cnp->cn_flags &= ~CNP_ISSYMLINK;
-       dp = dvp;
-       vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
 
-/* dirloop: */
        /*
         * Search a new directory.
-        *
-        * The last component of the filename is left accessible via
-        * cnp->cn_nameptr for callers that need the name. Callers needing
-        * the name set the CNP_SAVENAME flag. When done, they assume
-        * responsibility for freeing the pathname buffer.
         */
-#ifdef NAMEI_DIAGNOSTIC
-       if (cnp->cn_namelen != cp - cnp->cn_nameptr)
-               panic ("relookup: bad len");
-       if (*cp != 0)
-               panic("relookup: not last component");
-       printf("{%s}: ", cnp->cn_nameptr);
-#endif
 
        /*
-        * Check for degenerate name (e.g. / or "")
-        * which is a way of talking about a directory,
-        * e.g. like "/." or ".".
+        * Degenerate lookups (e.g. "/", "..", derived from "/.", etc)
+        * are not allowed.
         */
        if (cnp->cn_nameptr[0] == '\0') {
-               if (cnp->cn_nameiop != NAMEI_LOOKUP || wantparent) {
-                       error = EISDIR;
-                       goto bad;
-               }
-               if (dp->v_type != VDIR) {
-                       error = ENOTDIR;
-                       goto bad;
-               }
-               if (!(cnp->cn_flags & CNP_LOCKLEAF))
-                       VOP_UNLOCK(dp, 0, td);
-               *vpp = dp;
-               /* XXX This should probably move to the top of function. */
-               if (cnp->cn_flags & CNP_SAVESTART)
-                       panic("lookup: CNP_SAVESTART");
-               return (0);
+               error = EISDIR;
+               goto bad;
        }
-
        if (cnp->cn_flags & CNP_ISDOTDOT)
                panic ("relookup: lookup on dot-dot");
 
        /*
         * We now have a segment name to search for, and a directory to search.
         */
-       if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
+       if ((error = VOP_OLD_LOOKUP(dvp, vpp, cnp)) != 0) {
                KASSERT(*vpp == NULL, ("leaf should be empty"));
                if (error != EJUSTRETURN)
                        goto bad;
@@ -707,9 +124,6 @@ relookup(dvp, vpp, cnp)
                        error = EROFS;
                        goto bad;
                }
-               /* ASSERT(dvp == ndp->ni_startdir) */
-               if (cnp->cn_flags & CNP_SAVESTART)
-                       vref(dvp);
                /*
                 * We return with ni_vp NULL to indicate that the entry
                 * doesn't currently exist, leaving a pointer to the
@@ -717,43 +131,33 @@ relookup(dvp, vpp, cnp)
                 */
                return (0);
        }
-       dp = *vpp;
 
        /*
         * Check for symbolic link
         */
-       KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & CNP_FOLLOW),
+       KASSERT((*vpp)->v_type != VLNK || !(cnp->cn_flags & CNP_FOLLOW),
            ("relookup: symlink found.\n"));
 
        /*
         * Disallow directory write attempts on read-only file systems.
         */
-       if (rdonly &&
-           (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) {
+       if (rdonly && (cnp->cn_nameiop == NAMEI_DELETE || 
+                       cnp->cn_nameiop == NAMEI_RENAME)) {
                error = EROFS;
-               goto bad2;
+               goto bad;
        }
-       /* ASSERT(dvp == ndp->ni_startdir) */
-       if (cnp->cn_flags & CNP_SAVESTART)
-               vref(dvp);
-       
-       if (!wantparent)
-               vrele(dvp);
-
-       if (vn_canvmio(dp) == TRUE &&
-               ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) == CNP_LOCKLEAF))
-               vfs_object_create(dp, cnp->cn_td);
-
-       if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
-               VOP_UNLOCK(dp, 0, td);
+       KKASSERT((cnp->cn_flags & CNP_PDIRUNLOCK) == 0);
        return (0);
 
-bad2:
-       if ((cnp->cn_flags & CNP_LOCKPARENT) && (cnp->cn_flags & CNP_ISLASTCN))
-               VOP_UNLOCK(dvp, 0, td);
-       vrele(dvp);
 bad:
-       vput(dp);
-       *vpp = NULL;
+       if ((cnp->cn_flags & CNP_PDIRUNLOCK) == 0) {
+               cnp->cn_flags |= CNP_PDIRUNLOCK;
+               VOP_UNLOCK(dvp, 0, td);
+       }
+       if (*vpp) {
+               vput(*vpp);
+               *vpp = NULL;
+       }
        return (error);
 }
+