VFS messaging/interfacing work stage 7d/99: More firming up of stage 7.
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 5 Oct 2004 03:24:35 +0000 (03:24 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 5 Oct 2004 03:24:35 +0000 (03:24 +0000)
Additional work to deal with old-api/new-api issues.  Cut more stuff
out of the old-api's cache_enter() routine to deal with deadlocks, at
the cost of some performance loss (temporary until the VFS's start using
the new APIs).  Change UFS and NFS to not purge whole directories in
*_rename() and *_rmdir().

Add some minor breakage to the API which will not be fixed until the VFS's
get new rename implementations - renaming a directory in which a process
has chdir'd will create problems for that process.  This doesn't happen
normally anyway so this temporary breakage should not cause any significant
problems.

Bug-reports-by: walt, Sascha Wildner, others
17 files changed:
sys/kern/vfs_cache.c
sys/kern/vfs_default.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_subr.c
sys/kern/vfs_syscalls.c
sys/sys/namecache.h
sys/vfs/coda/coda_vnops.c
sys/vfs/hpfs/hpfs_vnops.c
sys/vfs/isofs/cd9660/cd9660_node.c
sys/vfs/msdosfs/msdosfs_denode.c
sys/vfs/nfs/nfs_node.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/nwfs/nwfs_node.c
sys/vfs/smbfs/smbfs_node.c
sys/vfs/ufs/ufs_inode.c
sys/vfs/ufs/ufs_vnops.c

index 736d642..86870a0 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.32 2004/10/04 09:20:40 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_cache.c,v 1.33 2004/10/05 03:24:09 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -131,6 +131,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 namecache *ncp);
+static void cache_rehash(struct namecache *ncp);
 
 /*
  * The new name cache statistics
@@ -391,6 +392,18 @@ cache_get(struct namecache *ncp)
        return(ncp);
 }
 
+int
+cache_get_nonblock(struct namecache *ncp)
+{
+       /* XXX MP */
+       if (ncp->nc_exlocks == 0 || ncp->nc_locktd == curthread) {
+               _cache_hold(ncp);
+               cache_lock(ncp);
+               return(0);
+       }
+       return(EWOULDBLOCK);
+}
+
 void
 cache_put(struct namecache *ncp)
 {
@@ -462,10 +475,6 @@ void
 cache_setunresolved(struct namecache *ncp)
 {
        struct vnode *vp;
-#if 0
-       struct namecache *kid;
-       struct namecache *nextkid;
-#endif
 
        if ((ncp->nc_flag & NCF_UNRESOLVED) == 0) {
                ncp->nc_flag |= NCF_UNRESOLVED;
@@ -498,35 +507,55 @@ cache_setunresolved(struct namecache *ncp)
                        printf("[diagnostic] cache_setunresolved() called on directory with children: %p %*.*s\n", ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
                }
 #endif
+       }
+}
 
-#if 0
-               /*
-                * OLDAPI COMPAT CODE, XXX can be removed when the old api is
-                * gone.
-                *
-                * Remove any negative hits from the list of children.  With
-                * the parent gone there is no namecache<->vnode linkage for
-                * the OLDAPI code to traverse, so the OLDAPI code would not
-                * be able to find the negative cache entry to invalidate it
-                * in cache_enter() if a new file is created.  This case
-                * only occurs because NFS calls cache_purge() on the
-                * target directory in nfs_rename().
-                *
-                * This is different from what cache_purge() does.
-                */
-               if ((nextkid = TAILQ_FIRST(&ncp->nc_list)) != NULL)
-                       cache_hold(nextkid);
-               while ((kid = nextkid) != NULL) {
-                       if ((nextkid = TAILQ_NEXT(kid, nc_entry)) != NULL)
-                               cache_hold(nextkid);
-                       if ((kid->nc_flag & NCF_UNRESOLVED) == 0 &&
-                           kid->nc_vp == NULL
-                       ) {
-                               cache_setunresolved(kid);
-                       }
-                       cache_drop(kid);
+/*
+ * Invalidate portions of a namecache entry.  The passed ncp should be
+ * referenced and locked but we might not adhere to that rule during the
+ * old api -> new api transition period.
+ *
+ * CINV_PARENT         - disconnect the ncp from its parent
+ * CINV_SELF           - same as cache_setunresolved(ncp)
+ * CINV_CHILDREN       - disconnect children of the ncp from the ncp
+ */
+void
+cache_inval(struct namecache *ncp, int flags)
+{
+       struct namecache *kid;
+
+       if (flags & CINV_SELF)
+               cache_setunresolved(ncp);
+       if (flags & CINV_PARENT) {
+               ncp->nc_flag |= NCF_REVALPARENT;
+               cache_unlink_parent(ncp);
+       }
+       if (flags & CINV_CHILDREN) {
+               while ((kid = TAILQ_FIRST(&ncp->nc_list)) != NULL) {
+                       kid->nc_flag |= NCF_REVALPARENT;
+                       cache_unlink_parent(kid);
+               }
+       }
+}
+
+void
+cache_inval_vp(struct vnode *vp, int flags)
+{
+       struct namecache *ncp;
+
+       if (flags & CINV_SELF) {
+               while ((ncp = TAILQ_FIRST(&vp->v_namecache)) != NULL) {
+                       cache_hold(ncp);
+                       KKASSERT((ncp->nc_flag & NCF_UNRESOLVED) == 0);
+                       cache_inval(ncp, flags);
+                       cache_drop(ncp);
+               }
+       } else {
+               TAILQ_FOREACH(ncp, &vp->v_namecache, nc_vnode) {
+                       cache_hold(ncp);
+                       cache_inval(ncp, flags);
+                       cache_drop(ncp);
                }
-#endif
        }
 }
 
@@ -805,14 +834,20 @@ int
 cache_resolve(struct namecache *ncp, struct ucred *cred)
 {
        struct namecache *par;
+       struct namecache *scan;
+
+       /*
+        * If the ncp is already resolved we have nothing to do.
+        */
+       if ((ncp->nc_flag & NCF_UNRESOLVED) == 0)
+               return (ncp->nc_error);
 
        /*
         * Mount points need special handling because the parent does not
         * belong to the same filesystem as the ncp.
         */
-       if (ncp->nc_flag & NCF_MOUNTPT) {
+       if (ncp->nc_flag & NCF_MOUNTPT)
                return (cache_resolve_mp(ncp));
-       }
 
        /*
         * We expect an unbroken chain of ncps to at least the mount point,
@@ -820,7 +855,7 @@ cache_resolve(struct namecache *ncp, struct ucred *cred)
         * past the mount point).
         */
        if (ncp->nc_parent == NULL) {
-               printf("EXDEV case 1 %*.*s\n",
+               printf("EXDEV case 1 %p %*.*s\n", ncp,
                        ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
                ncp->nc_error = EXDEV;
                return(ncp->nc_error);
@@ -862,6 +897,10 @@ cache_resolve(struct namecache *ncp, struct ucred *cred)
                cache_get(par);
                if (par->nc_flag & NCF_MOUNTPT) {
                        cache_resolve_mp(par);
+               } else if (par->nc_parent->nc_vp == NULL) {
+                       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);
@@ -874,11 +913,27 @@ cache_resolve(struct namecache *ncp, struct ucred *cred)
                        return(par->nc_error);
                }
        }
-       if (ncp->nc_flag & NCF_MOUNTPT) {
-               cache_resolve_mp(ncp);
-       } else {
-               ncp->nc_error = 
-                       vop_resolve(ncp->nc_parent->nc_vp->v_ops, ncp, cred);
+
+       /*
+        * Call vop_resolve() 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.
+        */
+       KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0);
+       ncp->nc_error = vop_resolve(ncp->nc_parent->nc_vp->v_ops, ncp, cred);
+       if (ncp->nc_error == 0) {
+               TAILQ_FOREACH(scan, &ncp->nc_vp->v_namecache, nc_vnode) {
+                       if (scan != ncp && (scan->nc_flag & NCF_REVALPARENT)) {
+                               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);
+                               break;
+                       }
+               }
        }
        return(ncp->nc_error);
 }
@@ -1002,10 +1057,13 @@ restart:
                numchecks++;
 
                /*
-                * Zap entries that have timed out.
+                * 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
+                   (int)(ncp->nc_timeout - ticks) < 0 &&
+                   !(ncp->nc_flag & NCF_UNRESOLVED) &&
+                   ncp->nc_exlocks == 0
                ) {
                        cache_zap(cache_hold(ncp));
                        goto restart;
@@ -1049,8 +1107,11 @@ restart:
 
        /*
         * If we found an entry, but we don't want to have one, we zap it.
+        * If we are deleting, we disconnect it as well.
         */
        if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) {
+               if (cnp->cn_nameiop == NAMEI_DELETE)
+                       cache_inval(ncp, CINV_PARENT|CINV_SELF|CINV_CHILDREN);
                numposzaps++;
                gd->gd_nchstats->ncs_badhits++;
                cache_zap(ncp);
@@ -1101,9 +1162,11 @@ restart:
  *
  * 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.
  */
-static void cache_rehash(struct namecache *ncp);
-
 void
 cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
 {
@@ -1139,33 +1202,6 @@ cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
        if (cnp->cn_namelen == 2 && cnp->cn_nameptr[0] == '.' &&
            cnp->cn_nameptr[1] == '.'
        ) {
-               /*
-                * ncp is associated with dvp
-                * par is not necessarily associated with any vp
-                * vp represents the new parent directory of dvp (..)
-                */
-               par = ncp->nc_parent;   /* old parent of ncp/dvp */
-               if (vp == NULL) {
-                       if (par) {
-                               cache_unlink_parent(ncp);
-                               printf("[diagnostic] cache_enter: disconnecting1 %*.*s\n", ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
-                       }
-               } else if (par == NULL || par->nc_vp != vp) {
-                       cache_unlink_parent(ncp);
-                       if ((par = TAILQ_FIRST(&vp->v_namecache)) == NULL) {
-                               printf("[diagnostic] cache_enter: disconnecting2 %*.*s\n", ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
-                       } else {
-                               /* 
-                                * par/vp is the new parent of ncp.
-                                */
-                               cache_hold(par);
-                               cache_link_parent(ncp, par);
-                               printf("[diagnostic] cache_enter: moving %*.*s\n", ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
-                               if (ncp->nc_flag & NCF_HASHED)
-                                       cache_rehash(ncp);
-                               cache_drop(par);
-                       }
-               }
                cache_drop(ncp);
                return;
        }
@@ -1211,13 +1247,20 @@ againagain:
                numchecks++;
 
                /*
-                * Break out if we find a matching entry.
+                * 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
                ) {
-                       cache_get(ncp);
+                       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;
                }
        }
@@ -1384,28 +1427,8 @@ void
 cache_purge(struct vnode *vp)
 {
        static u_long nextid;
-       struct namecache *ncp;
-       struct namecache *kid;
-       struct namecache *nextkid;
 
-       /*
-        * Disassociate the vnode from its namecache entries along with
-        * (to support NFS) any resolved direct children.
-        */
-       while ((ncp = TAILQ_FIRST(&vp->v_namecache)) != NULL) {
-               cache_hold(ncp);
-
-               if ((nextkid = TAILQ_FIRST(&ncp->nc_list)) != NULL)
-                       cache_hold(nextkid);
-               while ((kid = nextkid) != NULL) {
-                       if ((nextkid = TAILQ_NEXT(kid, nc_entry)) != NULL)
-                               cache_hold(nextkid);
-                       if ((kid->nc_flag & NCF_UNRESOLVED) == 0)
-                               cache_setunresolved(kid);
-                       cache_drop(kid);
-               }
-               cache_zap(ncp);
-       }
+       cache_inval_vp(vp, CINV_PARENT | CINV_SELF | CINV_CHILDREN);
 
        /*
         * Calculate a new unique id for ".." handling
index 78d77ea..2831cea 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.16 2004/10/04 09:20:40 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_default.c,v 1.17 2004/10/05 03:24:09 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -171,6 +171,9 @@ vop_panic(struct vop_generic_args *ap)
  * cache_setvp() is called with a NULL vnode to resolve the entry into a
  * negative cache entry.  No vnode locks are retained and the
  * ncp is left locked on return.
+ *
+ * There is a potential directory and vnode interlock.   The lock order
+ * requirement is: namecache, governing directory, resolved vnode.
  */
 static int
 vop_noresolve(struct vop_resolve_args *ap)
@@ -189,12 +192,6 @@ vop_noresolve(struct vop_resolve_args *ap)
        if ((dvp = ncp->nc_parent->nc_vp) == NULL)
                return(EPERM);
 
-       /*
-        * We can race against another thread holding a locked vnode
-        * trying to do a cache_enter().  We have to unlock the ncp
-        * for the duration of any code that locks vp's.
-        */
-       cache_unlock(ncp);
        vget(dvp, NULL, LK_EXCLUSIVE, curthread);
 
        bzero(&cnp, sizeof(cnp));
@@ -208,17 +205,12 @@ vop_noresolve(struct vop_resolve_args *ap)
        /*
         * vop_lookup() always returns vp locked.  dvp may or may not be
         * left locked depending on CNP_PDIRUNLOCK.
-        *
-        * We have to unlock all related vnodes before we can safely relock
-        * the ncp.  Fortunately this trash code goes away when the old
-        * API goes away.
         */
        error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
        if (error == 0)
                VOP_UNLOCK(vp, NULL, 0, curthread);
        if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
                VOP_UNLOCK(dvp, NULL, 0, curthread);
-       cache_lock(ncp);
        if ((ncp->nc_flag & NCF_UNRESOLVED) == 0) {
                /* was resolved by another process while we were unlocked */
                if (error == 0)
index d1c02c2..85ef2f4 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.2 2004/09/30 18:59:48 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_nlookup.c,v 1.3 2004/10/05 03:24:09 dillon Exp $
  */
 /*
  * nlookup() is the 'new' namei interface.  Rather then return directory and
@@ -287,23 +287,40 @@ nlookup(struct nlookupdata *nd)
                ncp = cache_get(ncp);
            } else {
                if (ncp->nc_flag & NCF_MOUNTPT) {
+                   /* ignore NCF_REVALPARENT on a mount point */
                    ncp = ncp->nc_parent;
                    KKASSERT(ncp != NULL && 1);
                }
+               if (ncp->nc_flag & NCF_REVALPARENT) {
+                   printf("[diagnostic] nlookup can't .. past a renamed directory: %*.*s\n", ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
+                   error = EINVAL;
+                   break;
+               }
                ncp = ncp->nc_parent;
                KKASSERT(ncp != NULL && 2);
                ncp = cache_get(ncp);
            }
        } else {
            ncp = cache_nlookup(nd->nl_ncp, &nlc);
+           while ((error = cache_resolve(ncp, nd->nl_cred)) == EAGAIN) {
+               printf("[diagnostic] nlookup: relookup %*.*s\n", 
+                       ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
+               cache_put(ncp);
+               ncp = cache_nlookup(nd->nl_ncp, &nlc);
+               error = cache_resolve(ncp, nd->nl_cred);
+           }
        }
 
        /*
         * Resolve the namespace if necessary.  The ncp returned by
         * cache_nlookup() is referenced and locked.
+        *
+        * XXX neither '.' nor '..' should return EAGAIN since they were
+        * previously resolved and thus cannot be newly created ncp's.
         */
        if (ncp->nc_flag & NCF_UNRESOLVED) {
            error = cache_resolve(ncp, nd->nl_cred);
+           KKASSERT(error != EAGAIN);
        } else {
            error = ncp->nc_error;
        }
@@ -574,10 +591,12 @@ naccess(struct namecache *ncp, int vmode, struct ucred *cred)
        if (((vmode & VCREATE) && ncp->nc_vp == NULL) ||
            ((vmode & VDELETE) && ncp->nc_vp != NULL)
        ) {
-           if (ncp->nc_parent == NULL)
-               error = EROFS;
-           else
+           if (ncp->nc_parent == NULL) {
+               if (error != EAGAIN)
+                       error = EROFS;
+           } else {
                error = naccess(ncp->nc_parent, VWRITE, cred);
+           }
        }
        if ((vmode & VEXCL) && ncp->nc_vp != NULL)
            error = EEXIST;
index 241abfa..e9c34e0 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_subr.c  8.31 (Berkeley) 5/26/95
  * $FreeBSD: src/sys/kern/vfs_subr.c,v 1.249.2.30 2003/04/04 20:35:57 tegge Exp $
- * $DragonFly: src/sys/kern/vfs_subr.c,v 1.41 2004/09/26 20:14:20 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_subr.c,v 1.42 2004/10/05 03:24:09 dillon Exp $
  */
 
 /*
@@ -759,7 +759,7 @@ getnewvnode(enum vtagtype tag, struct mount *mp, struct vop_ops *ops,
                vp->v_flag &= ~VFREE;
                freevnodes--;
                lwkt_reltoken(&ilock);
-               cache_purge(vp);        /* YYY may block */
+               cache_inval_vp(vp, CINV_SELF);  /* YYY may block */
                vp->v_lease = NULL;
                if (vp->v_type != VBAD) {
                        vgonel(vp, &vlock, td);
@@ -797,7 +797,7 @@ getnewvnode(enum vtagtype tag, struct mount *mp, struct vop_ops *ops,
                vp->v_interlock = lwkt_token_pool_get(vp);
                lwkt_token_init(&vp->v_pollinfo.vpi_token);
                lockinit(&vp->v_lock, 0, "vnode", lktimeout, lkflags);
-               cache_purge(vp);
+               cache_inval_vp(vp, CINV_SELF);
                TAILQ_INIT(&vp->v_namecache);
                numvnodes++;
        }
@@ -2117,7 +2117,7 @@ vclean(struct vnode *vp, lwkt_tokref_t vlock, int flags, struct thread *td)
                }
        }
 
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        vmaybefree(vp);
        
        /*
index 2b5282b..9e0e9f8 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.41 2004/10/02 03:18:26 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.42 2004/10/05 03:24:09 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -356,8 +356,11 @@ update:
         * vnode-under to the root of the new mount.  The lookup code
         * detects the mount point going forward and detects the special
         * mnt_ncp via NCP_MOUNTPT going backwards.
+        *
+        * It is not necessary to invalidate or purge the vnode underneath
+        * because elements under the mount will be given their own glue
+        * namecache record.
         */
-       cache_purge(vp);
        if (!error) {
                nlc.nlc_nameptr = "";
                nlc.nlc_namelen = 0;
index e905096..2759fc2 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.11 2004/10/02 03:18:28 dillon Exp $
+ * $DragonFly: src/sys/sys/namecache.h,v 1.12 2004/10/05 03:24:21 dillon Exp $
  */
 
 #ifndef _SYS_NAMECACHE_H_
@@ -127,9 +127,14 @@ typedef struct namecache *namecache_t;
 #define NCF_UNUSED080  0x0080
 #define NCF_ISSYMLINK  0x0100  /* represents a symlink */
 #define NCF_ISDIR      0x0200  /* represents a directory */
+#define NCF_REVALPARENT        0x0400  /* reevaluate the parent link */
 
-#define CINV_SELF      0x0001  /* invalidate a specific (dvp,vp) entry */
-#define CINV_CHILDREN  0x0002  /* invalidate all children of vp */
+/*
+ * cache_inval[_vp]() flags
+ */
+#define CINV_PARENT    0x0001  /* disconnect from parent in namecache */
+#define CINV_SELF      0x0002  /* disconnect vp from namecache */
+#define CINV_CHILDREN  0x0004  /* disconnect children in namecache */
 
 #define NCPNULL                ((struct namecache *)NULL)      /* placemarker */
 #define NCPPNULL       ((struct namecache **)NULL)     /* placemarker */
@@ -151,6 +156,8 @@ void        cache_enter(struct vnode *dvp, struct vnode *vp,
                        struct componentname *cnp);
 struct namecache *cache_nlookup(struct namecache *par, struct nlcomponent *nlc);
 struct namecache *cache_allocroot(struct vnode *vp);
+void   cache_inval(struct namecache *ncp, int flags);
+void   cache_inval_vp(struct vnode *vp, int flags);
 void   vfs_cache_setroot(struct vnode *vp, struct namecache *ncp);
 
 int    cache_resolve(struct namecache *ncp, struct ucred *cred);
index 21d843e..e2b469a 100644 (file)
@@ -28,7 +28,7 @@
  * 
  *     @(#) src/sys/coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
  * $FreeBSD: src/sys/coda/coda_vnops.c,v 1.22.2.1 2001/06/29 16:26:22 shafeeq Exp $
- * $DragonFly: src/sys/vfs/coda/Attic/coda_vnops.c,v 1.20 2004/09/26 06:00:08 dillon Exp $
+ * $DragonFly: src/sys/vfs/coda/Attic/coda_vnops.c,v 1.21 2004/10/05 03:24:23 dillon Exp $
  * 
  */
 
@@ -1721,7 +1721,7 @@ coda_reclaim(void *v)
     }
 #endif
     }  
-    cache_purge(vp);
+    cache_inval_vp(vp, CINV_SELF);
     coda_free(VTOC(vp));
     vp->v_data = NULL;
     return (0);
index f814332..1e10790 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/hpfs/hpfs_vnops.c,v 1.2.2.2 2002/01/15 18:35:09 semenu Exp $
- * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.18 2004/09/30 18:59:57 dillon Exp $
+ * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.19 2004/10/05 03:24:25 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -655,7 +655,7 @@ hpfs_reclaim(struct vop_reclaim_args *ap)
        hpfs_hphashrem(hp);
 
        /* Purge old data structures associated with the inode. */
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        if (hp->h_devvp) {
                vrele(hp->h_devvp);
                hp->h_devvp = NULL;
index 7e5c77f..c86006e 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)cd9660_node.c       8.2 (Berkeley) 1/23/94
  * $FreeBSD: src/sys/isofs/cd9660/cd9660_node.c,v 1.29.2.1 2000/07/08 14:35:56 bp Exp $
- * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.c,v 1.11 2004/08/28 19:02:15 dillon Exp $
+ * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.c,v 1.12 2004/10/05 03:24:28 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -226,7 +226,7 @@ cd9660_reclaim(struct vop_reclaim_args *ap)
         * Remove the inode from its hash chain and purge namecache
         * data associated with the vnode.
         */
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        vp->v_data = NULL;
        if (ip) {
                cd9660_ihashrem(ip);
index 6e727c4..ccdce48 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/msdosfs/msdosfs_denode.c,v 1.47.2.3 2002/08/22 16:20:15 trhodes Exp $ */
-/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_denode.c,v 1.15 2004/08/28 19:02:18 dillon Exp $ */
+/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_denode.c,v 1.16 2004/10/05 03:24:30 dillon Exp $ */
 /*     $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $  */
 
 /*-
@@ -671,7 +671,7 @@ msdosfs_reclaim(struct vop_reclaim_args *ap)
         * Remove the denode from its hash chain and purge namecache
         * data associated with the vnode.
         */
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        vp->v_data = NULL;
        if (dep) {
                msdosfs_hashrem(dep);
index dd51e0d..5db7af3 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_node.c  8.6 (Berkeley) 5/22/95
  * $FreeBSD: src/sys/nfs/nfs_node.c,v 1.36.2.3 2002/01/05 22:25:04 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_node.c,v 1.15 2004/09/05 00:06:43 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_node.c,v 1.16 2004/10/05 03:24:31 dillon Exp $
  */
 
 
@@ -285,7 +285,7 @@ nfs_reclaim(struct vop_reclaim_args *ap)
                np->n_wucred = NULL;
        }
 
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        vp->v_data = NULL;
        zfree(nfsnode_zone, np);
        return (0);
index 1bba95c..54afeff 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
  * $FreeBSD: src/sys/nfs/nfs_vnops.c,v 1.150.2.5 2001/12/20 19:56:28 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.32 2004/10/04 09:20:43 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.33 2004/10/05 03:24:31 dillon Exp $
  */
 
 
@@ -1705,6 +1705,7 @@ nfs_rename(struct vop_rename_args *ap)
         */
        if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
                tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
+               cache_purge(tvp);
                vput(tvp);
                tvp = NULL;
        }
@@ -1713,11 +1714,14 @@ nfs_rename(struct vop_rename_args *ap)
                tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
                tcnp->cn_td);
 
+       cache_purge(fvp);
+#if 0
        if (fvp->v_type == VDIR) {
                if (tvp != NULL && tvp->v_type == VDIR)
                        cache_purge(tdvp);
                cache_purge(fdvp);
        }
+#endif
 
 out:
        if (tdvp == tvp)
@@ -2058,7 +2062,9 @@ nfsmout:
        VTONFS(dvp)->n_flag |= NMODIFIED;
        if (!wccflag)
                VTONFS(dvp)->n_attrstamp = 0;
+#if 0
        cache_purge(dvp);
+#endif
        cache_purge(vp);
        /*
         * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
index 0bfd87d..cee84d9 100644 (file)
@@ -36,7 +36,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/ntfs/ntfs_vnops.c,v 1.9.2.4 2002/08/06 19:35:18 semenu Exp $
- * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.16 2004/09/30 19:00:11 dillon Exp $
+ * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.17 2004/10/05 03:24:32 dillon Exp $
  *
  */
 
@@ -300,7 +300,7 @@ ntfs_reclaim(struct vop_reclaim_args *ap)
                return (error);
        
        /* Purge old data structures associated with the inode. */
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
 
        ntfs_frele(fp);
        ntfs_ntput(ip);
index 270794d..7997151 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/nwfs/nwfs_node.c,v 1.3.2.8 2001/12/25 01:44:45 dillon Exp $
- * $DragonFly: src/sys/vfs/nwfs/nwfs_node.c,v 1.14 2004/08/28 19:02:24 dillon Exp $
+ * $DragonFly: src/sys/vfs/nwfs/nwfs_node.c,v 1.15 2004/10/05 03:24:33 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -235,7 +235,7 @@ nwfs_reclaim(struct vop_reclaim_args *ap)
                LIST_REMOVE(np, n_hash);
                lockmgr(&nwhashlock, LK_RELEASE, NULL, td);
        }
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        if (nmp->n_root == np)
                nmp->n_root = NULL;
        vp->v_data = NULL;
@@ -269,7 +269,7 @@ nwfs_inactive(struct vop_inactive_args *ap)
        }
        VOP_UNLOCK(vp, NULL, 0, td);
        if (np == NULL || (np->n_flag & NSHOULDFREE)) {
-               cache_purge(vp);
+               cache_inval_vp(vp, CINV_SELF);
                vgone(vp);
        }
        return (0);
index 05ef73f..d0e0090 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/smbfs/smbfs_node.c,v 1.2.2.3 2003/01/17 08:20:26 tjr Exp $
- * $DragonFly: src/sys/vfs/smbfs/smbfs_node.c,v 1.13 2004/08/28 19:02:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/smbfs/smbfs_node.c,v 1.14 2004/10/05 03:24:34 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -304,7 +304,7 @@ smbfs_reclaim(struct vop_reclaim_args *ap)
 
        if (np->n_hash.le_prev)
                LIST_REMOVE(np, n_hash);
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        if (smp->sm_root == np) {
                SMBVDEBUG("root vnode\n");
                smp->sm_root = NULL;
index 3dfb43b..3ced245 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)ufs_inode.c 8.9 (Berkeley) 5/14/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_inode.c,v 1.25.2.3 2002/07/05 22:42:31 dillon Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_inode.c,v 1.9 2004/08/28 19:02:30 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_inode.c,v 1.10 2004/10/05 03:24:35 dillon Exp $
  */
 
 #include "opt_quota.h"
@@ -130,7 +130,7 @@ ufs_reclaim(struct vop_reclaim_args *ap)
         * Remove the inode from its hash chain and purge namecache
         * data associated with the vnode.
         */
-       cache_purge(vp);
+       cache_inval_vp(vp, CINV_SELF);
        vp->v_data = NULL;
        if (ip) {
                ufs_ihashrem(ip);
index 10b69db..05da4de 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_vnops.c,v 1.131.2.8 2003/01/02 17:26:19 bde Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_vnops.c,v 1.20 2004/08/28 19:02:30 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_vnops.c,v 1.21 2004/10/05 03:24:35 dillon Exp $
  */
 
 #include "opt_quota.h"
@@ -1066,6 +1066,9 @@ abortit:
                 * Target must be empty if a directory and have no links
                 * to it. Also, ensure source and target are compatible
                 * (both directories, or both not directories).
+                *
+                * Purge the file or directory being replaced from the
+                * nameccache.
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
                        if ((xp->i_effnlink > 2) ||
@@ -1077,8 +1080,10 @@ abortit:
                                error = ENOTDIR;
                                goto bad;
                        }
-                       cache_purge(tdvp);
-               } else if (doingdirectory) {
+                       cache_purge(tvp);
+               } else if (doingdirectory == 0) {
+                       cache_purge(tvp);
+               } else {
                        error = EISDIR;
                        goto bad;
                }
@@ -1179,11 +1184,18 @@ abortit:
                if (doingdirectory && newparent) {
                        xp->i_offset = mastertemplate.dot_reclen;
                        ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0);
-                       cache_purge(fdvp);
+                       /*cache_purge(fdvp);*/
                }
                error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
                xp->i_flag &= ~IN_RENAME;
        }
+
+       /*
+        * The old API can only do a kitchen sink invalidation.  It will
+        * not be possible to '..' through the disconnected fvp (if a
+        * directory) until it is reconnected by a forward lookup.
+        */
+       cache_purge(fvp);
        VN_KNOTE(fvp, NOTE_RENAME);
        if (dp)
                vput(fdvp);
@@ -1482,7 +1494,7 @@ ufs_rmdir(struct vop_rmdir_args *ap)
                goto out;
        }
        VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
-       cache_purge(dvp);
+       cache_purge(vp);
        /*
         * Truncate inode. The only stuff left in the directory is "." and
         * "..". The "." reference is inconsequential since we are quashing