Fix a HAMMER assertion which turned out to be a bug in VOP_N*(). Sometimes
authorMatthew Dillon <dillon@dragonflybsd.org>
Fri, 9 May 2008 17:52:18 +0000 (17:52 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Fri, 9 May 2008 17:52:18 +0000 (17:52 +0000)
the dvp passed to these functions can be reclaimed.  The locked leaf
namecache node is not sufficient to prevent its parent directory from
being reclaimed under heavy loads.

Instead of trying to play cute tricks, actually do a formal reference of
the dvp.  We don't have to lock it, though.

sys/kern/uipc_usrreq.c
sys/kern/vfs_cache.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_syscalls.c
sys/kern/vfs_vnops.c
sys/kern/vfs_vopops.c
sys/sys/namecache.h
sys/sys/nlookup.h

index 3f5bc1a..a39e34c 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.38 2008/05/08 01:41:05 dillon Exp $
+ * $DragonFly: src/sys/kern/uipc_usrreq.c,v 1.39 2008/05/09 17:52:17 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -609,7 +609,6 @@ unp_bind(struct unpcb *unp, struct sockaddr *nam, struct thread *td)
 {
        struct proc *p = td->td_proc;
        struct sockaddr_un *soun = (struct sockaddr_un *)nam;
-       struct vnode *dvp;
        struct vnode *vp;
        struct vattr vattr;
        int error, namelen;
@@ -623,21 +622,19 @@ unp_bind(struct unpcb *unp, struct sockaddr *nam, struct thread *td)
                return (EINVAL);
        strncpy(buf, soun->sun_path, namelen);
        buf[namelen] = 0;       /* null-terminate the string */
-       error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_LOCKVP|NLC_CREATE);
+       error = nlookup_init(&nd, buf, UIO_SYSSPACE,
+                            NLC_LOCKVP | NLC_CREATE | NLC_REFDVP);
        if (error == 0)
                error = nlookup(&nd);
        if (error == 0 && nd.nl_nch.ncp->nc_vp != NULL)
                error = EADDRINUSE;
-       if (error == 0 && (dvp = cache_dvpref(nd.nl_nch.ncp)) == NULL)
-               error = EPERM;
        if (error)
                goto done;
 
        VATTR_NULL(&vattr);
        vattr.va_type = VSOCK;
        vattr.va_mode = (ACCESSPERMS & ~p->p_fd->fd_cmask);
-       error = VOP_NCREATE(&nd.nl_nch, dvp, &vp, nd.nl_cred, &vattr);
-       cache_dvprel(dvp);
+       error = VOP_NCREATE(&nd.nl_nch, nd.nl_dvp, &vp, nd.nl_cred, &vattr);
        if (error == 0) {
                vp->v_socket = unp->unp_socket;
                unp->unp_vnode = vp;
index 33240e3..89f4fdb 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.89 2008/05/08 01:41:05 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_cache.c,v 1.90 2008/05/09 17:52:17 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -152,6 +152,7 @@ SYSCTL_INT(_debug, OID_AUTO, vnsize, CTLFLAG_RD, 0, sizeof(struct vnode), "");
 SYSCTL_INT(_debug, OID_AUTO, ncsize, CTLFLAG_RD, 0, sizeof(struct namecache), "");
 
 static int cache_resolve_mp(struct mount *mp);
+static struct vnode *cache_dvpref(struct namecache *ncp);
 static void _cache_rehash(struct namecache *ncp);
 static void _cache_lock(struct namecache *ncp);
 static void _cache_setunresolved(struct namecache *ncp);
@@ -1127,41 +1128,31 @@ again:
 /*
  * Return a referenced vnode representing the parent directory of
  * ncp.  Because the caller has locked the ncp it should not be possible for
- * the parent to go away.
+ * the parent ncp to go away.
+ *
+ * However, we might race against the parent dvp and not be able to
+ * reference it.  If we race, return NULL.
  */
-struct vnode *
+static struct vnode *
 cache_dvpref(struct namecache *ncp)
 {
+       struct namecache *par;
        struct vnode *dvp;
-#if 0
-       int error;
-#endif
 
-       if (ncp->nc_parent == NULL)
-               return(NULL);
-       if ((dvp = ncp->nc_parent->nc_vp) == NULL)
-               return(NULL);
-       KKASSERT((dvp->v_flag & VRECLAIMED) == 0);
-       vhold(dvp);
-       return(dvp);
-#if 0
-       if (vget(dvp, LK_SHARED) == 0) {
-               vn_unlock(dvp);
-               return(dvp);
-       } else {
-               panic("cache_dvpref: vget(%p) failed", dvp);
-               return(NULL);   /* NOT REACHED */
+       dvp = NULL;
+       if ((par = ncp->nc_parent) != NULL) {
+               if ((par->nc_flag & NCF_UNRESOLVED) == 0) {
+                       if ((dvp = par->nc_vp) != NULL) {
+                               if (vget(dvp, LK_SHARED) == 0) {
+                                       vn_unlock(dvp);
+                                       /* return referenced, unlocked dvp */
+                               } else {
+                                       dvp = NULL;
+                               }
+                       }
+               }
        }
-#endif
-}
-
-void
-cache_dvprel(struct vnode *dvp)
-{
-       vdrop(dvp);
-#if 0
-       vrele(dvp);
-#endif
+       return(dvp);
 }
 
 /*
@@ -2035,7 +2026,7 @@ restart:
         * not occur all that often, or if it does not have to go back too
         * many nodes to resolve the ncp.
         */
-       while (ncp->nc_parent->nc_vp == NULL) {
+       while ((dvp = cache_dvpref(ncp)) == NULL) {
                /*
                 * This case can occur if a process is CD'd into a
                 * directory which is then rmdir'd.  If the parent is marked
@@ -2074,7 +2065,7 @@ restart:
                                nctmp.ncp = par;
                                par->nc_error = VOP_NRESOLVE(&nctmp, dvp, cred);
                        }
-                       cache_dvprel(dvp);
+                       vrele(dvp);
                }
                if ((error = par->nc_error) != 0) {
                        if (par->nc_error != EAGAIN) {
@@ -2099,11 +2090,11 @@ restart:
         * NOTE: in order to call VOP_NRESOLVE(), the parent of the passed
         * ncp must already be resolved.
         */
-       if ((dvp = cache_dvpref(ncp)) != NULL) {
+       if (dvp) {
                nctmp.mount = mp;
                nctmp.ncp = ncp;
                ncp->nc_error = VOP_NRESOLVE(&nctmp, dvp, cred);
-               cache_dvprel(dvp);
+               vrele(dvp);
        } else {
                ncp->nc_error = EPERM;
        }
index 5f04719..5c15320 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/vfs_nlookup.c,v 1.23 2008/04/14 12:01:50 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_nlookup.c,v 1.24 2008/05/09 17:52:17 dillon Exp $
  */
 /*
  * nlookup() is the 'new' namei interface.  Rather then return directory and
@@ -225,6 +225,10 @@ nlookup_done(struct nlookupdata *nd)
        vn_close(nd->nl_open_vp, nd->nl_vp_fmode);
        nd->nl_open_vp = NULL;
     }
+    if (nd->nl_dvp) {
+       vrele(nd->nl_dvp);
+       nd->nl_dvp = NULL;
+    }
     nd->nl_flags = 0;  /* clear remaining flags (just clear everything) */
 }
 
@@ -277,6 +281,10 @@ nlookup_simple(const char *str, enum uio_seg seg,
  * creation (VCREATE/VDELETE), and an error code of 0 will be returned for
  * a non-existant target.  Otherwise a non-existant target will cause
  * ENOENT to be returned.
+ *
+ * If NLC_REFDVP is set nd->nl_dvp will be set to the directory vnode
+ * of the returned entry.  The vnode will be referenced, but not locked,
+ * and will be released by nlookup_done() along with everything else.
  */
 int
 nlookup(struct nlookupdata *nd)
@@ -307,6 +315,10 @@ nlookup(struct nlookupdata *nd)
        nd->nl_flags &= ~NLC_NCPISLOCKED;
        cache_unlock(&nd->nl_nch);
     }
+    if (nd->nl_dvp ) {
+       vrele(nd->nl_dvp);
+       nd->nl_dvp = NULL;
+    }
     ptr = nd->nl_path;
 
     /*
@@ -327,10 +339,21 @@ nlookup(struct nlookupdata *nd)
            cache_copy(&nd->nl_rootnch, &nch);
            cache_drop(&nd->nl_nch);
            nd->nl_nch = nch;
+
+           /*
+            * Fast-track termination.  There is no parent directory of
+            * the root in the same mount from the point of view of
+            * the caller so return EPERM if NLC_REFDVP is specified.
+            * e.g. 'rmdir /' is not allowed.
+            */
            if (*ptr == 0) {
-               cache_lock(&nd->nl_nch);
-               nd->nl_flags |= NLC_NCPISLOCKED;
-               error = 0;
+               if (nd->nl_flags & NLC_REFDVP) {
+                       error = EPERM;
+               } else {
+                       cache_lock(&nd->nl_nch);
+                       nd->nl_flags |= NLC_NCPISLOCKED;
+                       error = 0;
+               }
                break;
            }
            continue;
@@ -427,7 +450,7 @@ nlookup(struct nlookupdata *nd)
         *
         * Also handle invalid '.' or '..' components terminating a path
         * during removal.  The standard requires this and pax pretty
-         *stupidly depends on it.
+        stupidly depends on it.
         */
        for (xptr = ptr; *xptr == '/'; ++xptr)
                ;
@@ -573,7 +596,17 @@ nlookup(struct nlookupdata *nd)
         * Termination: no more elements.  If NLC_CREATE was set the
         * ncp may represent a negative hit (ncp->nc_error will be ENOENT),
         * but we still return an error code of 0.
+        *
+        * If NLC_REFDVP is set acquire a referenced parent dvp.
         */
+       if (nd->nl_flags & NLC_REFDVP) {
+               error = cache_vref(&nd->nl_nch, nd->nl_cred, &nd->nl_dvp);
+               if (error) {
+                       kprintf("NLC_REFDVP: Cannot ref dvp of %p\n", nch.ncp);
+                       cache_put(&nch);
+                       break;
+               }
+       }
        cache_drop(&nd->nl_nch);
        nd->nl_nch = nch;
        nd->nl_flags |= NLC_NCPISLOCKED;
index 98583c7..62e6301 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_syscalls.c      8.13 (Berkeley) 4/15/94
  * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $
- * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.125 2008/05/08 01:41:05 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.126 2008/05/09 17:52:17 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -1626,7 +1626,6 @@ kern_mknod(struct nlookupdata *nd, int mode, int rmajor, int rminor)
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
        struct vnode *vp;
-       struct vnode *dvp;
        struct vattr vattr;
        int error;
        int whiteout = 0;
@@ -1646,15 +1645,13 @@ kern_mknod(struct nlookupdata *nd, int mode, int rmajor, int rminor)
                return (error);
 
        bwillwrite();
-       nd->nl_flags |= NLC_CREATE;
+       nd->nl_flags |= NLC_CREATE | NLC_REFDVP;
        if ((error = nlookup(nd)) != 0)
                return (error);
        if (nd->nl_nch.ncp->nc_vp)
                return (EEXIST);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
                return (error);
-       if ((dvp = cache_dvpref(nd->nl_nch.ncp)) == NULL)
-               return (EPERM);
 
        VATTR_NULL(&vattr);
        vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
@@ -1681,15 +1678,16 @@ kern_mknod(struct nlookupdata *nd, int mode, int rmajor, int rminor)
        }
        if (error == 0) {
                if (whiteout) {
-                       error = VOP_NWHITEOUT(&nd->nl_nch, dvp, nd->nl_cred, NAMEI_CREATE);
+                       error = VOP_NWHITEOUT(&nd->nl_nch, nd->nl_dvp,
+                                             nd->nl_cred, NAMEI_CREATE);
                } else {
                        vp = NULL;
-                       error = VOP_NMKNOD(&nd->nl_nch, dvp, &vp, nd->nl_cred, &vattr);
+                       error = VOP_NMKNOD(&nd->nl_nch, nd->nl_dvp,
+                                          &vp, nd->nl_cred, &vattr);
                        if (error == 0)
                                vput(vp);
                }
        }
-       cache_dvprel(dvp);
        return (error);
 }
 
@@ -1720,27 +1718,23 @@ kern_mkfifo(struct nlookupdata *nd, int mode)
        struct proc *p = td->td_proc;
        struct vattr vattr;
        struct vnode *vp;
-       struct vnode *dvp;
        int error;
 
        bwillwrite();
 
-       nd->nl_flags |= NLC_CREATE;
+       nd->nl_flags |= NLC_CREATE | NLC_REFDVP;
        if ((error = nlookup(nd)) != 0)
                return (error);
        if (nd->nl_nch.ncp->nc_vp)
                return (EEXIST);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
                return (error);
-       if ((dvp = cache_dvpref(nd->nl_nch.ncp)) == NULL)
-               return (EPERM);
 
        VATTR_NULL(&vattr);
        vattr.va_type = VFIFO;
        vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
        vp = NULL;
-       error = VOP_NMKNOD(&nd->nl_nch, dvp, &vp, nd->nl_cred, &vattr);
-       cache_dvprel(dvp);
+       error = VOP_NMKNOD(&nd->nl_nch, nd->nl_dvp, &vp, nd->nl_cred, &vattr);
        if (error == 0)
                vput(vp);
        return (error);
@@ -1820,7 +1814,6 @@ kern_link(struct nlookupdata *nd, struct nlookupdata *linknd)
 {
        struct thread *td = curthread;
        struct vnode *vp;
-       struct vnode *dvp;
        int error;
 
        /*
@@ -1849,7 +1842,7 @@ kern_link(struct nlookupdata *nd, struct nlookupdata *linknd)
        nd->nl_flags &= ~NLC_NCPISLOCKED;
        cache_unlock(&nd->nl_nch);
 
-       linknd->nl_flags |= NLC_CREATE;
+       linknd->nl_flags |= NLC_CREATE | NLC_REFDVP;
        if ((error = nlookup(linknd)) != 0) {
                vput(vp);
                return (error);
@@ -1858,18 +1851,15 @@ kern_link(struct nlookupdata *nd, struct nlookupdata *linknd)
                vput(vp);
                return (EEXIST);
        }
-       if ((dvp = cache_dvpref(linknd->nl_nch.ncp)) == NULL) {
-               vput(vp);
-               return (EPERM);
-       }
 
        /*
         * Finally run the new API VOP.
         */
        error = can_hardlink(vp, td, td->td_proc->p_ucred);
-       if (error == 0)
-               error = VOP_NLINK(&linknd->nl_nch, dvp, vp, linknd->nl_cred);
-       cache_dvprel(dvp);
+       if (error == 0) {
+               error = VOP_NLINK(&linknd->nl_nch, linknd->nl_dvp,
+                                 vp, linknd->nl_cred);
+       }
        vput(vp);
        return (error);
 }
@@ -1905,19 +1895,17 @@ kern_symlink(struct nlookupdata *nd, char *path, int mode)
        int error;
 
        bwillwrite();
-       nd->nl_flags |= NLC_CREATE;
+       nd->nl_flags |= NLC_CREATE | NLC_REFDVP;
        if ((error = nlookup(nd)) != 0)
                return (error);
        if (nd->nl_nch.ncp->nc_vp)
                return (EEXIST);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
                return (error);
-       if ((dvp = cache_dvpref(nd->nl_nch.ncp)) == NULL)
-               return (EPERM);
+       dvp = nd->nl_dvp;
        VATTR_NULL(&vattr);
        vattr.va_mode = mode;
        error = VOP_NSYMLINK(&nd->nl_nch, dvp, &vp, nd->nl_cred, &vattr, path);
-       cache_dvprel(dvp);
        if (error == 0)
                vput(vp);
        return (error);
@@ -1961,25 +1949,18 @@ int
 sys_undelete(struct undelete_args *uap)
 {
        struct nlookupdata nd;
-       struct vnode *dvp;
        int error;
 
        error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0);
        bwillwrite();
-       nd.nl_flags |= NLC_DELETE;
+       nd.nl_flags |= NLC_DELETE | NLC_REFDVP;
        if (error == 0)
                error = nlookup(&nd);
        if (error == 0)
                error = ncp_writechk(&nd.nl_nch);
-       dvp = NULL;
        if (error == 0) {
-               if ((dvp = cache_dvpref(nd.nl_nch.ncp)) != NULL) {
-                       error = VOP_NWHITEOUT(&nd.nl_nch, dvp,
-                                             nd.nl_cred, NAMEI_DELETE);
-                       cache_dvprel(dvp);
-               } else {
-                       error = EPERM;
-               }
+               error = VOP_NWHITEOUT(&nd.nl_nch, nd.nl_dvp, nd.nl_cred,
+                                     NAMEI_DELETE);
        }
        nlookup_done(&nd);
        return (error);
@@ -1988,19 +1969,15 @@ sys_undelete(struct undelete_args *uap)
 int
 kern_unlink(struct nlookupdata *nd)
 {
-       struct vnode *dvp;
        int error;
 
        bwillwrite();
-       nd->nl_flags |= NLC_DELETE;
+       nd->nl_flags |= NLC_DELETE | NLC_REFDVP;
        if ((error = nlookup(nd)) != 0)
                return (error);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
                return (error);
-       if ((dvp = cache_dvpref(nd->nl_nch.ncp)) == NULL)
-               return (EPERM);
-       error = VOP_NREMOVE(&nd->nl_nch, dvp, nd->nl_cred);
-       cache_dvprel(dvp);
+       error = VOP_NREMOVE(&nd->nl_nch, nd->nl_dvp, nd->nl_cred);
        return (error);
 }
 
@@ -2887,6 +2864,7 @@ kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond)
        int error;
 
        bwillwrite();
+       fromnd->nl_flags |= NLC_REFDVP;
        if ((error = nlookup(fromnd)) != 0)
                return (error);
        if ((fnchd.ncp = fromnd->nl_nch.ncp->nc_parent) == NULL)
@@ -2907,7 +2885,7 @@ kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond)
        fromnd->nl_flags &= ~NLC_NCPISLOCKED;
        cache_unlock(&fromnd->nl_nch);
 
-       tond->nl_flags |= NLC_CREATE;
+       tond->nl_flags |= NLC_CREATE | NLC_REFDVP;
        if ((error = nlookup(tond)) != 0) {
                cache_drop(&fnchd);
                return (error);
@@ -3034,8 +3012,8 @@ kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond)
         * when we detect the situation.
         */
        if (error == 0) {
-               fdvp = cache_dvpref(fromnd->nl_nch.ncp);
-               tdvp = cache_dvpref(tond->nl_nch.ncp);
+               fdvp = fromnd->nl_dvp;
+               tdvp = tond->nl_dvp;
                if (fdvp == NULL || tdvp == NULL) {
                        error = EPERM;
                } else if (fromnd->nl_nch.ncp->nc_vp == tond->nl_nch.ncp->nc_vp) {
@@ -3045,10 +3023,6 @@ kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond)
                        error = VOP_NRENAME(&fromnd->nl_nch, &tond->nl_nch, 
                                            fdvp, tdvp, tond->nl_cred);
                }
-               if (fdvp)
-                       cache_dvprel(fdvp);
-               if (tdvp)
-                       cache_dvprel(tdvp);
        }
        return (error);
 }
@@ -3082,12 +3056,11 @@ kern_mkdir(struct nlookupdata *nd, int mode)
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
        struct vnode *vp;
-       struct vnode *dvp;
        struct vattr vattr;
        int error;
 
        bwillwrite();
-       nd->nl_flags |= NLC_WILLBEDIR | NLC_CREATE;
+       nd->nl_flags |= NLC_WILLBEDIR | NLC_CREATE | NLC_REFDVP;
        if ((error = nlookup(nd)) != 0)
                return (error);
 
@@ -3095,15 +3068,12 @@ kern_mkdir(struct nlookupdata *nd, int mode)
                return (EEXIST);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
                return (error);
-       if ((dvp = cache_dvpref(nd->nl_nch.ncp)) == NULL)
-               return (EPERM);
        VATTR_NULL(&vattr);
        vattr.va_type = VDIR;
        vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
 
        vp = NULL;
-       error = VOP_NMKDIR(&nd->nl_nch, dvp, &vp, p->p_ucred, &vattr);
-       cache_dvprel(dvp);
+       error = VOP_NMKDIR(&nd->nl_nch, nd->nl_dvp, &vp, p->p_ucred, &vattr);
        if (error == 0)
                vput(vp);
        return (error);
@@ -3131,11 +3101,10 @@ sys_mkdir(struct mkdir_args *uap)
 int
 kern_rmdir(struct nlookupdata *nd)
 {
-       struct vnode *dvp;
        int error;
 
        bwillwrite();
-       nd->nl_flags |= NLC_DELETE;
+       nd->nl_flags |= NLC_DELETE | NLC_REFDVP;
        if ((error = nlookup(nd)) != 0)
                return (error);
 
@@ -3148,10 +3117,7 @@ kern_rmdir(struct nlookupdata *nd)
                return (EINVAL);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
                return (error);
-       if ((dvp = cache_dvpref(nd->nl_nch.ncp)) == NULL)
-               return (EPERM);
-       error = VOP_NRMDIR(&nd->nl_nch, dvp, nd->nl_cred);
-       cache_dvprel(dvp);
+       error = VOP_NRMDIR(&nd->nl_nch, nd->nl_dvp, nd->nl_cred);
        return (error);
 }
 
index 10f511e..240ccc8 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/vfs_vnops.c,v 1.87.2.13 2002/12/29 18:19:53 dillon Exp $
- * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.56 2008/05/08 01:41:06 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.57 2008/05/09 17:52:17 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -127,7 +127,6 @@ int
 vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
 {
        struct vnode *vp;
-       struct vnode *dvp;
        struct ucred *cred = nd->nl_cred;
        struct vattr vat;
        struct vattr *vap = &vat;
@@ -156,6 +155,7 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
                if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
                        nd->nl_flags |= NLC_FOLLOW;
                nd->nl_flags |= NLC_CREATE;
+               nd->nl_flags |= NLC_REFDVP;
                bwillwrite();
                error = nlookup(nd);
        } else {
@@ -177,16 +177,13 @@ again:
                if (nd->nl_nch.ncp->nc_vp == NULL) {
                        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
                                return (error);
-                       if ((dvp = cache_dvpref(nd->nl_nch.ncp)) == NULL)
-                               return (EPERM);
                        VATTR_NULL(vap);
                        vap->va_type = VREG;
                        vap->va_mode = cmode;
                        if (fmode & O_EXCL)
                                vap->va_vaflags |= VA_EXCLUSIVE;
-                       error = VOP_NCREATE(&nd->nl_nch, dvp, &vp,
+                       error = VOP_NCREATE(&nd->nl_nch, nd->nl_dvp, &vp,
                                            nd->nl_cred, vap);
-                       cache_dvprel(dvp);
                        if (error)
                                return (error);
                        fmode &= ~O_TRUNC;
index 5fe0ea3..3df0873 100644 (file)
@@ -32,7 +32,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.37 2008/02/06 00:27:27 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.38 2008/05/09 17:52:17 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -923,8 +923,8 @@ vop_mountctl(struct vop_ops *ops, int op, struct file *fp,
 /*
  * NEW API FUNCTIONS
  *
- * nresolve takes a locked ncp and a cred and resolves the ncp into a 
- * positive or negative hit.
+ * nresolve takes a locked ncp, a referenced but unlocked dvp, and a cred,
+ * and resolves the ncp into a positive or negative hit.
  *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
@@ -947,8 +947,9 @@ vop_nresolve(struct vop_ops *ops, struct nchandle *nch,
 }
 
 /*
- * nlookupdotdot takes an unlocked directory, dvp, and looks up "..", returning
- * a locked parent directory in *vpp.  If an error occurs *vpp will be NULL.
+ * nlookupdotdot takes an unlocked directory, referenced dvp, and looks
+ * up "..", returning a locked parent directory in *vpp.  If an error
+ * occurs *vpp will be NULL.
  */
 int
 vop_nlookupdotdot(struct vop_ops *ops, struct vnode *dvp,
@@ -973,6 +974,8 @@ vop_nlookupdotdot(struct vop_ops *ops, struct vnode *dvp,
  * cache hit and creates the file or node specified by the ncp, cred, and
  * vattr.  If no error occurs a locked vnode is returned in *vpp.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1002,6 +1005,8 @@ vop_ncreate(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * cache hit and creates the directory specified by the ncp, cred, and
  * vattr.  If no error occurs a locked vnode is returned in *vpp.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1031,6 +1036,8 @@ vop_nmkdir(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * cache hit and creates the node specified by the ncp, cred, and
  * vattr.  If no error occurs a locked vnode is returned in *vpp.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1061,6 +1068,8 @@ vop_nmknod(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * existing vnode.  The passed vp must be locked and will remain locked
  * on return, as does the ncp, whether an error occurs or not.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1090,6 +1099,8 @@ vop_nlink(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * contents of the link).  If no error occurs a locked vnode is returned in
  * *vpp.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1120,6 +1131,8 @@ vop_nsymlink(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * nwhiteout takes a locked, resolved ncp that can represent a positive or
  * negative hit and executes the whiteout function specified in flags.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1147,6 +1160,8 @@ vop_nwhiteout(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * nremove takes a locked, resolved ncp that generally represents a
  * positive hit and removes the file.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1173,6 +1188,8 @@ vop_nremove(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * nrmdir takes a locked, resolved ncp that generally represents a
  * directory and removes the directory.
  *
+ * The dvp passed in is referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.
  */
@@ -1200,6 +1217,8 @@ vop_nrmdir(struct vop_ops *ops, struct nchandle *nch, struct vnode *dvp,
  * and renames the source ncp to the target ncp.  The target ncp may 
  * represent a positive or negative hit.
  *
+ * The fdvp and tdvp passed in are referenced but unlocked.
+ *
  * The namecache is automatically adjusted by this function.  The ncp
  * is left locked on return.  The source ncp is typically changed to
  * a negative cache hit and the target ncp typically takes on the
index e5f4119..0cf7ef1 100644 (file)
@@ -62,7 +62,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/sys/namecache.h,v 1.30 2008/05/08 01:41:07 dillon Exp $
+ * $DragonFly: src/sys/sys/namecache.h,v 1.31 2008/05/09 17:52:18 dillon Exp $
  */
 
 #ifndef _SYS_NAMECACHE_H_
@@ -194,8 +194,6 @@ int cache_vget(struct nchandle *, struct ucred *, int, struct vnode **);
 int    cache_vref(struct nchandle *, struct ucred *, struct vnode **);
 int    cache_fromdvp(struct vnode *, struct ucred *, int, struct nchandle *);
 int    cache_fullpath(struct proc *, struct nchandle *, char **, char **);
-struct vnode *cache_dvpref(struct namecache *);
-void   cache_dvprel(struct vnode *);
 void   cache_update_fsmid(struct nchandle *);
 void   cache_update_fsmid_vp(struct vnode *);
 int64_t cache_sync_fsmid_vp(struct vnode *);
index 6990824..9def8fb 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/sys/nlookup.h,v 1.5 2006/10/27 04:56:33 dillon Exp $
+ * $DragonFly: src/sys/sys/nlookup.h,v 1.6 2008/05/09 17:52:18 dillon Exp $
  */
 
 #ifndef _SYS_NLOOKUP_H_
@@ -80,6 +80,7 @@ struct nlookupdata {
        char            *nl_path;       /* path buffer */
        struct thread   *nl_td;         /* thread requesting the nlookup */
        struct ucred    *nl_cred;       /* credentials for nlookup */
+       struct vnode    *nl_dvp;        /* NLC_REFDVP */
 
        int             nl_flags;       /* operations flags */
        int             nl_loopcnt;     /* symlinks encountered */
@@ -104,6 +105,7 @@ struct nlookupdata {
 #define NLC_DELETE             0x00000100
 #define NLC_NFS_RDONLY         0x00010000      /* set by nfs_namei() only */
 #define NLC_NFS_NOSOFTLINKTRAV 0x00020000      /* do not traverse softlnks */
+#define NLC_REFDVP             0x00040000      /* set ref'd/unlocked nl_dvp */
 
 #ifdef _KERNEL