VFS messaging/interfacing work stage 5/99. Start work on the new
authorMatthew Dillon <dillon@dragonflybsd.org>
Sun, 26 Sep 2004 01:25:52 +0000 (01:25 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sun, 26 Sep 2004 01:25:52 +0000 (01:25 +0000)
namecache/lookup API.  The core of this API will be the concept of a
'locked namespace' rather then a 'locked vnode' for namespace centric
operations like CREATE, DELETE, and RENAME.   The namecache will no longer
be optional for a VFS but instead will become centric to all kernel
namespace operations.

This commit is mostly non-functional.  It removes an extension I had made
to VOP_LOOKUP/VOP_CACHEDLOOKUP and starts adding support functions for the
new cache_nclookup() API.  The work being backed out was originally intended
to shepard the new work, but the new interface is now so different (and far
more simplified) then the original that it's actually better to create a
new VOP for it instead of augmenting existing VOPs.

sys/kern/vfs_cache.c
sys/kern/vfs_vopops.c
sys/sys/namecache.h
sys/sys/vfsops.h
sys/vfs/nfs/nfs_vnops.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/nwfs/nwfs_vnops.c
sys/vfs/smbfs/smbfs_vnops.c

index 373fcf4..252b224 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.25 2004/07/16 05:51:10 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_cache.c,v 1.26 2004/09/26 01:24:52 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -220,6 +220,74 @@ cache_drop(struct namecache *ncp)
        _cache_drop(ncp);
 }
 
+/*
+ * Namespace locking.  The caller must already hold a reference to the
+ * namecache structure in order to lock/unlock it.  
+ *
+ * Note that holding a locked namecache structure does not prevent the
+ * underlying vnode from being destroyed and the namecache state moving
+ * to an unresolved state.  XXX MP
+ */
+void
+cache_lock(struct namecache *ncp)
+{
+       thread_t td = curthread;
+       int didwarn = 0;
+
+       KKASSERT(ncp->nc_refs != 0);
+       for (;;) {
+               if (ncp->nc_exlocks == 0) {
+                       ncp->nc_exlocks = 1;
+                       ncp->nc_locktd = td;
+                       break;
+               }
+               if (ncp->nc_locktd == td) {
+                       ++ncp->nc_exlocks;
+                       break;
+               }
+               ncp->nc_flag |= NCF_LOCKREQ;
+               if (tsleep(ncp, 0, "clock", hz) == EWOULDBLOCK) {
+                       if (didwarn == 0) {
+                               didwarn = 1;
+                               printf("cache_lock: blocked on %*.*s\n",
+                                       ncp->nc_nlen, ncp->nc_nlen,
+                                       ncp->nc_name);
+                       }
+               }
+       }
+       if (didwarn == 1) {
+               printf("cache_lock: unblocked %*.*s\n",
+                       ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
+       }
+}
+
+void
+cache_unlock(struct namecache *ncp)
+{
+       thread_t td = curthread;
+
+       KKASSERT(ncp->nc_refs > 0);
+       KKASSERT(ncp->nc_exlocks > 0);
+       KKASSERT(ncp->nc_locktd == td);
+       if (--ncp->nc_exlocks == 0) {
+               ncp->nc_locktd = NULL;
+               if (ncp->nc_flag & NCF_LOCKREQ) {
+                       ncp->nc_flag &= ~NCF_LOCKREQ;
+                       wakeup_one(ncp);
+               }
+       }
+}
+
+/*
+ * Unlock and release a namecache entry.
+ */
+void
+cache_put(struct namecache *ncp)
+{
+       cache_unlock(ncp);
+       _cache_drop(ncp);
+}
+
 static void
 cache_link_parent(struct namecache *ncp, struct namecache *par)
 {
@@ -265,6 +333,19 @@ cache_alloc(struct vnode *vp)
        return(ncp);
 }
 
+#if 0
+static struct namecache *
+cache_alloc_unresolved(struct vnode *vp)
+{
+       struct namecache *ncp;
+
+       ncp = malloc(sizeof(*ncp), M_VFSCACHE, M_WAITOK|M_ZERO);
+       TAILQ_INIT(&ncp->nc_list);
+       ncp->nc_flag = NCF_UNRESOLVED;
+       return(ncp);
+}
+#endif
+
 /*
  * Try to destroy a namecache entry.  The entry is disassociated from its
  * vnode or ncneglist and reverted to an UNRESOLVED state.
@@ -362,6 +443,44 @@ done:
        --ncp->nc_refs;
 }
 
+/*
+ * NEW NAMECACHE LOOKUP API
+ *
+ * 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
+ * cache_put() or cache_unlock() + cache_drop().
+ *
+ * namecache locks are recursive but care must be taken to avoid lock order
+ * reversals.
+ *
+ * Nobody else will be able to manipulate the associated namespace (e.g.
+ * create, delete, rename, rename-target) until the caller unlocks the
+ * entry.
+ *
+ * The returned entry will be in one of three states:  positive hit (non-null
+ * vnode), negative hit (null vnode), or unresolved (NCF_UNRESOLVED is set).
+ * Unresolved entries must be resolved through the filesystem to associate the
+ * vnode and/or determine whether a positive or negative hit has occured.
+ *
+ * It is not necessary to lock a directory in order to lock namespace under
+ * that directory.  In fact, it is explicitly not allowed to do that.  A
+ * directory is typically only locked when being created, renamed, or
+ * destroyed.
+ *
+ * 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 
+ * specifically allows whole chains to be created in an unresolved state.
+ */
+struct namecache *
+cache_nclookup(struct namecache *par, struct componentname *cnp)
+{
+       KKASSERT(0);
+       return(NULL);
+}
+
 /*
  * Lookup an entry in the cache
  *
@@ -380,10 +499,10 @@ done:
  * entries.
  */
 int
-cache_lookup(struct vnode *dvp, struct namecache *par, struct vnode **vpp,
-               struct namecache **ncpp, struct componentname *cnp)
+cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
 {
        struct namecache *ncp;
+       struct namecache *par;
        u_int32_t hash;
        globaldata_t gd = mycpu;
 
@@ -398,10 +517,8 @@ cache_lookup(struct vnode *dvp, struct namecache *par, struct vnode **vpp,
         * NOTE: in this stage of development, the passed 'par' is
         * almost always NULL.
         */
-       if (par == NULL) {
-               if ((par = TAILQ_FIRST(&dvp->v_namecache)) == NULL)
-                       par = cache_alloc(dvp);
-       }
+       if ((par = TAILQ_FIRST(&dvp->v_namecache)) == NULL)
+               par = cache_alloc(dvp);
 
        /*
         * Deal with "." and "..".  In this stage of code development we leave
@@ -893,9 +1010,7 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
        struct vnode *dvp, *vp;
        int lockparent;
        int error;
-       struct namecache *par = ap->a_par;
        struct vnode **vpp = ap->a_vpp;
-       struct namecache **ncpp = ap->a_ncpp;
        struct componentname *cnp = ap->a_cnp;
        struct ucred *cred = cnp->cn_cred;
        int flags = cnp->cn_flags;
@@ -903,8 +1018,6 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
        u_long vpid;    /* capability number of vnode */
 
        *vpp = NULL;
-       if (ncpp)
-               *ncpp = NULL;
        dvp = ap->a_dvp;
        lockparent = flags & CNP_LOCKPARENT;
 
@@ -921,10 +1034,10 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
        if (error)
                return (error);
 
-       error = cache_lookup(dvp, par, vpp, ncpp, cnp);
+       error = cache_lookup(dvp, vpp, cnp);
 
        if (!error) 
-               return (VOP_CACHEDLOOKUP(dvp, par, vpp, ncpp, cnp));
+               return (VOP_CACHEDLOOKUP(dvp, vpp, cnp));
 
        if (error == ENOENT)
                return (error);
@@ -969,7 +1082,7 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
                        return (error);
                cnp->cn_flags &= ~CNP_PDIRUNLOCK;
        }
-       return (VOP_CACHEDLOOKUP(dvp, par, vpp, ncpp, cnp));
+       return (VOP_CACHEDLOOKUP(dvp, vpp, cnp));
 }
 
 static int disablecwd;
index 1d49359..4df8cb1 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.4 2004/08/28 19:02:05 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.5 2004/09/26 01:25:52 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -297,8 +297,7 @@ vop_lookup(struct vop_ops *ops, struct vnode *dvp,
 
 int
 vop_cachedlookup(struct vop_ops *ops, struct vnode *dvp,
-       struct namecache *par, struct vnode **vpp,
-       struct namecache **ncpp, struct componentname *cnp)
+       struct vnode **vpp, struct componentname *cnp)
 {
        struct vop_cachedlookup_args ap;
        int error;
@@ -306,9 +305,7 @@ vop_cachedlookup(struct vop_ops *ops, struct vnode *dvp,
        ap.a_head.a_desc = &vop_cachedlookup_desc;
        ap.a_head.a_ops = ops;
        ap.a_dvp = dvp;
-       ap.a_par = par;
        ap.a_vpp = vpp;
-       ap.a_ncpp = ncpp;
        ap.a_cnp = cnp;
 
        DO_OPS(ops, error, &ap, vop_cachedlookup);
index f30bb40..0069523 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.7 2004/08/28 19:02:07 dillon Exp $
+ * $DragonFly: src/sys/sys/namecache.h,v 1.8 2004/09/26 01:24:54 dillon Exp $
  */
 
 #ifndef _SYS_NAMECACHE_H_
@@ -106,9 +106,8 @@ struct namecache {
     u_char     nc_unused;
     char       *nc_name;               /* Separately allocated seg name */
     int                nc_timeout;             /* compared against ticks, or 0 */
-#if 0
-    struct lockmgr nc_lock;            /* namespace lock */
-#endif
+    int                nc_exlocks;             /* namespace locking */
+    struct thread *nc_locktd;          /* namespace locking */
 };
 
 typedef struct namecache *namecache_t;
@@ -116,12 +115,13 @@ typedef struct namecache *namecache_t;
 /*
  * Flags in namecache.nc_flag (u_char)
  */
-#define NCF_NEGATIVE   0x0001  /* negative entry */
+#define NCF_LOCKED     0x0001  /* locked namespace */
 #define NCF_WHITEOUT   0x0002  /* negative entry corresponds to whiteout */
 #define NCF_UNRESOLVED 0x0004  /* invalid or unresolved entry */
 #define NCF_MOUNTPT    0x0008  /* mount point */
 #define NCF_ROOT       0x0010  /* namecache root (static) */
 #define NCF_HASHED     0x0020  /* namecache entry in hash table */
+#define NCF_LOCKREQ    0x0040
 
 #define CINV_SELF      0x0001  /* invalidate a specific (dvp,vp) entry */
 #define CINV_CHILDREN  0x0002  /* invalidate all children of vp */
@@ -135,8 +135,13 @@ struct vop_lookup_args;
 struct componentname;
 struct mount;
 
-int    cache_lookup(struct vnode *dvp, struct namecache *par,
-                       struct vnode **vpp, struct namecache **ncpp,
+void   cache_lock(struct namecache *ncp);
+void   cache_unlock(struct namecache *ncp);
+void   cache_put(struct namecache *ncp);
+struct namecache *cache_nclookup(struct namecache *par,
+                       struct componentname *cnp);
+
+int    cache_lookup(struct vnode *dvp, struct vnode **vpp,
                        struct componentname *cnp);
 void   cache_mount(struct vnode *dvp, struct vnode *tvp);
 void   cache_enter(struct vnode *dvp, struct namecache *par,
index 8939c1a..f7c294b 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/sys/vfsops.h,v 1.3 2004/08/25 19:14:40 dillon Exp $
+ * $DragonFly: src/sys/sys/vfsops.h,v 1.4 2004/09/26 01:24:54 dillon Exp $
  */
 
 /*
@@ -105,9 +105,7 @@ struct vop_lookup_args {
 struct vop_cachedlookup_args {
        struct vop_generic_args a_head;
        struct vnode *a_dvp;
-       struct namecache *a_par;
        struct vnode **a_vpp;
-       struct namecache **a_ncpp;
        struct componentname *a_cnp;
 };
 
@@ -672,8 +670,7 @@ int vop_lookup(struct vop_ops *ops, struct vnode *dvp, struct namecache *par,
                struct vnode **vpp, struct namecache **ncpp,
                struct componentname *cnp);
 int vop_cachedlookup(struct vop_ops *ops, struct vnode *dvp, 
-               struct namecache *par, struct vnode **vpp,
-               struct namecache **ncpp, struct componentname *cnp);
+               struct vnode **vpp, struct componentname *cnp);
 int vop_create(struct vop_ops *ops, struct vnode *dvp, struct namecache *par,
                struct vnode **vpp, struct componentname *cnp,
                struct vattr *vap);
@@ -906,8 +903,8 @@ extern struct vnodeop_desc vop_vfsset_desc;
        vop_islocked((vp)->v_ops, vp, td)
 #define VOP_LOOKUP(dvp, par, vpp, ncpp, cnp)           \
        vop_lookup((dvp)->v_ops, dvp, par, vpp, ncpp, cnp)
-#define VOP_CACHEDLOOKUP(dvp, par, vpp, ncpp, cnp)     \
-       vop_cachedlookup((dvp)->v_ops, dvp, par, vpp, ncpp, cnp)
+#define VOP_CACHEDLOOKUP(dvp, vpp, cnp)        \
+       vop_cachedlookup((dvp)->v_ops, dvp, vpp, cnp)
 #define VOP_CREATE(dvp, par, vpp, cnp, vap)            \
        vop_create((dvp)->v_ops, dvp, par, vpp, cnp, vap)
 #define VOP_WHITEOUT(dvp, par, cnp, flags)             \
index f414a19..28ac6a1 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.29 2004/08/28 23:04:23 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.30 2004/09/26 01:24:56 dillon Exp $
  */
 
 
@@ -857,7 +857,7 @@ nfs_lookup(struct vop_lookup_args *ap)
        wantparent = flags & (CNP_LOCKPARENT|CNP_WANTPARENT);
        nmp = VFSTONFS(dvp->v_mount);
        np = VTONFS(dvp);
-       error = cache_lookup(dvp, NCPNULL, vpp, NCPPNULL, cnp);
+       error = cache_lookup(dvp, vpp, cnp);
        if (error != 0) {
                struct vattr vattr;
                int vpid;
index 078554c..fa67c8d 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.14 2004/08/17 18:57:34 dillon Exp $
+ * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.15 2004/09/26 01:24:57 dillon Exp $
  *
  */
 
@@ -739,7 +739,7 @@ ntfs_lookup(struct vop_lookup_args *ap)
         * check the name cache to see if the directory/name pair
         * we are looking for is known already.
         */
-       if ((error = cache_lookup(ap->a_dvp, NCPNULL, ap->a_vpp, NCPPNULL, cnp)) >= 0)
+       if ((error = cache_lookup(ap->a_dvp, ap->a_vpp, cnp)) >= 0)
                return (error);
 #endif
 
index 4e35ecd..6190c4e 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/nwfs/nwfs_vnops.c,v 1.6.2.3 2001/03/14 11:26:59 bp Exp $
- * $DragonFly: src/sys/vfs/nwfs/nwfs_vnops.c,v 1.14 2004/08/17 18:57:35 dillon Exp $
+ * $DragonFly: src/sys/vfs/nwfs/nwfs_vnops.c,v 1.15 2004/09/26 01:24:59 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -886,7 +886,7 @@ printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISD
        if (error) 
            return ENOENT;
 
-       error = cache_lookup(dvp, NCPNULL, vpp, NCPPNULL, cnp);
+       error = cache_lookup(dvp, vpp, cnp);
        NCPVNDEBUG("cache_lookup returned %d\n",error);
        if (error > 0)
                return error;
index 667e758..bd48b3b 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/smbfs/smbfs_vnops.c,v 1.2.2.8 2003/04/04 08:57:23 tjr Exp $
- * $DragonFly: src/sys/vfs/smbfs/smbfs_vnops.c,v 1.16 2004/08/28 19:02:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/smbfs/smbfs_vnops.c,v 1.17 2004/09/26 01:25:00 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1102,7 +1102,7 @@ smbfs_lookup(struct vop_lookup_args *ap)
        if (error) 
                return ENOENT;
 
-       error = cache_lookup(dvp, NCPNULL, vpp, NCPPNULL, cnp);
+       error = cache_lookup(dvp, vpp, cnp);
        SMBVDEBUG("cache_lookup returned %d\n", error);
        if (error > 0)
                return error;