linux-dcache-create-negative-dentries-22-needs-while-still-avoiding-vlru-cycle-20020328
[openafs.git] / src / afs / afs_vcache.c
index 136e14f..13e91ab 100644 (file)
@@ -70,7 +70,7 @@ extern struct vcache *afs_globalVp;
 #ifdef AFS_OSF_ENV
 extern struct mount *afs_globalVFS;
 extern struct vnodeops Afs_vnodeops;
-#elif defined(AFS_DARWIN_ENV)
+#elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
 extern struct mount *afs_globalVFS;
 #else
 extern struct vfs *afs_globalVFS;
@@ -132,7 +132,7 @@ int afs_FlushVCache(struct vcache *avc, int *slept)
               ICL_TYPE_INT32, avc->states);
 #ifdef  AFS_OSF_ENV
     AFS_GUNLOCK();
-    VN_LOCK((struct vnode *)avc);
+    VN_LOCK(AFSTOV(avc));
     AFS_GLOCK();
 #endif
 
@@ -213,16 +213,16 @@ int afs_FlushVCache(struct vcache *avc, int *slept)
     /* This should put it back on the vnode free list since usecount is 1 */
     afs_vcount--;
     vSetType(avc, VREG);
-    if (avc->vrefCount > 0) {
-        VN_UNLOCK((struct vnode *)avc);
-        AFS_RELE((struct vnode *)avc);
+    if (VREFCOUNT(avc) > 0) {
+        VN_UNLOCK(AFSTOV(avc));
+        AFS_RELE(AFSTOV(avc));
     } else {
        if (afs_norefpanic) {
          printf ("flush vc refcnt < 1");
          afs_norefpanic++;
          (void) vgone(avc, VX_NOSLEEP, (struct vnodeops *) 0);
          AFS_GLOCK();
-         VN_UNLOCK((struct vnode *)avc);
+         VN_UNLOCK(AFSTOV(avc));
        }
        else osi_Panic ("flush vc refcnt < 1");
     }
@@ -232,7 +232,7 @@ int afs_FlushVCache(struct vcache *avc, int *slept)
 
 bad:
 #ifdef AFS_OSF_ENV
-    VN_UNLOCK((struct vnode *)avc);
+    VN_UNLOCK(AFSTOV(avc));
 #endif
     return code;
 
@@ -251,7 +251,7 @@ void afs_InactiveVCache(struct vcache *avc, struct AFS_UCRED *acred)
     AFS_STATCNT(afs_inactive);
     if (avc->states & CDirty) {
       /* we can't keep trying to push back dirty data forever.  Give up. */
-      afs_InvalidateAllSegments(avc, 1/*set lock*/);  /* turns off dirty bit */
+      afs_InvalidateAllSegments(avc);  /* turns off dirty bit */
     }
     avc->states        &= ~CMAPPED;    /* mainly used by SunOS 4.0.x */
     avc->states        &= ~CDirty;     /* Turn it off */
@@ -378,14 +378,10 @@ afs_int32 afs_FlushVCBs (afs_int32 lockit)
                                            SHARED_LOCK);
                        if (tc) {
                          XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
-#ifdef RX_ENABLE_LOCKS
-                         AFS_GUNLOCK();
-#endif /* RX_ENABLE_LOCKS */
+                         RX_AFS_GUNLOCK();
                          code = RXAFS_GiveUpCallBacks(tc->id, &fidArray,
                                                       &cbArray);
-#ifdef RX_ENABLE_LOCKS
-                         AFS_GLOCK();
-#endif /* RX_ENABLE_LOCKS */
+                         RX_AFS_GLOCK();
                          XSTATS_END_TIME;
                        }
                        else code = -1;
@@ -466,6 +462,59 @@ static afs_int32 afs_QueueVCB(struct vcache *avc)
     return 0;
 }
 
+#ifdef AFS_LINUX22_ENV
+/* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by
+ *                               children of the dentry
+ *
+ * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires
+ *          AFS_GLOCK, so it can call dput, which may call iput, but
+ *          keeps afs_xvcache exclusively.
+ *
+ * Tree traversal algorithm from fs/dcache.c: select_parent()
+ */
+static void afs_TryFlushDcacheChildren(struct dentry *parent)
+{
+    struct dentry *this_parent = parent;
+    struct list_head *next;
+
+ repeat:
+    next = this_parent->d_subdirs.next;
+ resume:
+    DLOCK();
+    while (next != &this_parent->d_subdirs) {
+       struct list_head *tmp = next;
+       struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+
+       next = tmp->next;
+       if (!DCOUNT(dentry) && !dentry->d_inode) {
+           DGET(dentry);
+           AFS_GUNLOCK();
+           DUNLOCK();
+           d_drop(dentry);
+           dput(dentry);
+           AFS_GLOCK();
+           goto repeat;
+       }
+       /*
+        * Descend a level if the d_subdirs list is non-empty.
+         */
+       if (!list_empty(&dentry->d_subdirs)) {
+           this_parent = dentry;
+           goto repeat;
+       }
+    }
+    DUNLOCK();
+
+    /*
+     * All done at this level ... ascend and resume the search.
+     */
+    if (this_parent != parent) {
+       next = this_parent->d_child.next;
+       this_parent = this_parent->d_parent;
+       goto resume;
+    }
+}
+#endif /* AFS_LINUX22_ENV */
 
 /*
  * afs_RemoveVCB
@@ -525,7 +574,6 @@ afs_RemoveVCB(afid)
 } /*afs_RemoveVCB*/
 
 
-
 /*
  * afs_NewVCache
  *
@@ -563,27 +611,27 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
 #ifdef AFS_LINUX22_ENV
     if (!freeVCList) {
        /* Free some if possible. */
-        struct afs_q *tq, *uq;
-        int i; char *panicstr;
-        int vmax = 2 * afs_cacheStats;
-        int vn = VCACHE_FREE;
-
-        i = 0;
-        for(tq = VLRU.prev; tq != &VLRU && vn > 0; tq = uq) {
+        struct afs_q *tq, *uq;
+        int i; char *panicstr;
+        int vmax = 2 * afs_cacheStats;
+        int vn = VCACHE_FREE;
+       
+        i = 0;
+        for(tq = VLRU.prev; tq != &VLRU && vn > 0; tq = uq) {
            tvc = QTOV(tq);
            uq = QPrev(tq);
            if (tvc->states & CVFlushed) 
-                refpanic ("CVFlushed on VLRU");
+                refpanic ("CVFlushed on VLRU");
            else if (i++ > vmax)
-                refpanic ("Exceeded pool of AFS vnodes(VLRU cycle?)");
+                refpanic ("Exceeded pool of AFS vnodes(VLRU cycle?)");
            else if (QNext(uq) != tq)
-                refpanic ("VLRU inconsistent");
-
+                refpanic ("VLRU inconsistent");
+           
            if (tvc == afs_globalVp)
                continue;
-
-           if ( tvc->vrefCount && tvc->opens == 0 ) {
-               struct inode *ip = (struct inode*)tvc;
+           
+           if ( VREFCOUNT(tvc) && tvc->opens == 0 ) {
+               struct inode *ip = AFSTOI(tvc);
                if (list_empty(&ip->i_dentry)) {
                    vn --;
                }
@@ -592,24 +640,18 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
                    struct list_head *head = &ip->i_dentry;
                    int all = 1;
                restart:
-#if defined(AFS_LINUX24_ENV)
-                   spin_lock(&dcache_lock);
-#endif
+                   DLOCK();
                    cur = head;
                    while ((cur = cur->next) != head) {
                        struct dentry *dentry = list_entry(cur, struct dentry, d_alias);
-#if defined(AFS_LINUX24_ENV)
-                       if (!atomic_read(&dentry->d_count)) {
-#else
-                       if (!dentry->d_count) {
-#endif
+                       if (DCOUNT(dentry)) {
+                           afs_TryFlushDcacheChildren(dentry);
+                       }
+
+                       if (!DCOUNT(dentry)) {
                            AFS_GUNLOCK();
-#if defined(AFS_LINUX24_ENV)
-                           dget_locked(dentry);
-                           spin_unlock(&dcache_lock);
-#else
-                           dget(dentry);
-#endif
+                           DGET(dentry);
+                           DUNLOCK();
                            d_drop(dentry);
                            dput(dentry);
                            AFS_GLOCK();
@@ -619,14 +661,12 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
                            all = 0;
                        }
                    }
-#if defined(AFS_LINUX24_ENV)
-                   spin_unlock(&dcache_lock);
-#endif
+                   DUNLOCK();
                    if (all) vn --;
                }
            }
            if (tq == uq) break;
-        }
+        }
     }
 #endif /* AFS_LINUX22_ENV */
 #ifdef AFS_OSF_ENV
@@ -656,10 +696,10 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
                 refpanic ("Exceeded pool of AFS vnodes(VLRU cycle?)");
            else if (QNext(uq) != tq)
                 refpanic ("VLRU inconsistent");
-           else if (tvc->vrefCount < 1) 
+           else if (VREFCOUNT(tvc) < 1) 
                 refpanic ("refcnt 0 on VLRU");
 
-           if ( tvc->vrefCount == 1   &&   tvc->opens == 0 
+           if ( VREFCOUNT(tvc) == 1   &&   tvc->opens == 0 
                && (tvc->states & CUnlinkedDel) == 0) {
                code = afs_FlushVCache(tvc, &fv_slept);
                if (code == 0) {
@@ -711,7 +751,7 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
 
 #ifdef AFS_DARWIN_ENV
           if (tvc->opens == 0 && ((tvc->states & CUnlinkedDel) == 0) &&
-                tvc->vrefCount == 1 && UBCINFOEXISTS(&tvc->v)) {
+                VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
                osi_VM_TryReclaim(tvc, &fv_slept);
                if (fv_slept) {
                   uq = VLRU.prev;
@@ -720,7 +760,23 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
                }
             }
 #endif
-          if (tvc->vrefCount == 0 && tvc->opens == 0
+#if defined(AFS_FBSD_ENV)
+          if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
+              && (tvc->states & CUnlinkedDel) == 0) {
+               if (!(VOP_LOCK(&tvc->v, LK_EXCLUSIVE, curproc))) {
+                 if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
+                     && (tvc->states & CUnlinkedDel) == 0) {
+                      VREFCOUNT_DEC(tvc);
+                      AFS_GUNLOCK(); /* perhaps inline inactive for locking */
+                      VOP_INACTIVE(&tvc->v, curproc);
+                      AFS_GLOCK();
+                  } else {
+                     VOP_UNLOCK(&tvc->v, 0, curproc);
+                  }
+               }
+           }
+#endif
+          if (VREFCOUNT(tvc) == 0 && tvc->opens == 0
               && (tvc->states & CUnlinkedDel) == 0) {
                code = afs_FlushVCache(tvc, &fv_slept);
                if (code == 0) {
@@ -752,7 +808,7 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
 #endif /* AFS_MACH_ENV */
 #if defined(AFS_SGI_ENV)
        { char name[METER_NAMSZ];
-       bzero(tvc, sizeof(struct vcache));
+       memset(tvc, 0, sizeof(struct vcache));
        tvc->v.v_number = ++afsvnumbers;
        tvc->vc_rwlockid = OSI_NO_LOCKID;
        initnsema(&tvc->vc_rwlock, 1, makesname(name, "vrw", tvc->v.v_number));
@@ -777,7 +833,7 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
 #endif /* AFS_MACH_ENV */
 
 #if !defined(AFS_SGI_ENV) && !defined(AFS_OSF_ENV)
-    bzero((char *)tvc, sizeof(struct vcache));
+    memset((char *)tvc, 0, sizeof(struct vcache));
 #else
     tvc->uncred = 0;
 #endif
@@ -813,9 +869,9 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
     hzero(tvc->m.DataVersion);         /* in case we copy it into flushDV */
 #ifdef AFS_OSF_ENV
     /* Hold it for the LRU (should make count 2) */
-    VN_HOLD((struct vnode *)tvc);
+    VN_HOLD(AFSTOV(tvc));
 #else  /* AFS_OSF_ENV */
-    tvc->vrefCount = 1;        /* us */
+    VREFCOUNT_SET(tvc, 1);     /* us */
 #endif /* AFS_OSF_ENV */
 #ifdef AFS_AIX32_ENV
     LOCK_INIT(&tvc->pvmlock, "vcache pvmlock");
@@ -851,10 +907,10 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
 #ifdef AFS_AIX_ENV
     /* Don't forget to free the gnode space */
     tvc->v.v_gnode = gnodepnt = (struct gnode *) osi_AllocSmallSpace(sizeof(struct gnode));
-    bzero((char *)gnodepnt, sizeof(struct gnode));
+    memset((char *)gnodepnt, 0, sizeof(struct gnode));
 #endif
 #ifdef AFS_SGI64_ENV
-    bzero((void*)&(tvc->vc_bhv_desc), sizeof(tvc->vc_bhv_desc));
+    memset((void*)&(tvc->vc_bhv_desc), 0, sizeof(tvc->vc_bhv_desc));
     bhv_desc_init(&(tvc->vc_bhv_desc), tvc, tvc, &Afs_vnodeops);
 #ifdef AFS_SGI65_ENV
     vn_bhv_head_init(&(tvc->v.v_bh), "afsvp");
@@ -882,12 +938,12 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
     AFS_VN_INIT_BUF_LOCK(&(tvc->v));
 #endif
 #else
-    SetAfsVnode((struct vnode *)tvc);
+    SetAfsVnode(AFSTOV(tvc));
 #endif /* AFS_SGI64_ENV */
 #ifdef AFS_DARWIN_ENV
     tvc->v.v_ubcinfo = UBC_INFO_NULL;
     lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
-    cache_purge((struct vnode *)tvc); 
+    cache_purge(AFSTOV(tvc)); 
     tvc->v.v_data=tvc;
     tvc->v.v_tag=VT_AFS;
     /* VLISTNONE(&tvc->v); */
@@ -895,6 +951,14 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
     tvc->v.v_freelist.tqe_prev=(struct vnode **)0xdeadb;
     /*tvc->vrefCount++;*/
 #endif 
+#ifdef AFS_FBSD_ENV
+    lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
+    cache_purge(AFSTOV(tvc)); 
+    tvc->v.v_data=tvc;
+    tvc->v.v_tag=VT_AFS;
+    tvc->v.v_usecount++; /* steal an extra ref for now so vfree never happens */
+                         /* This extra ref is dealt with above... */
+#endif
     /*
      * The proper value for mvstat (for root fids) is setup by the caller.
      */
@@ -945,7 +1009,7 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
 #endif /* AFS_SGI_ENV */
 #if defined(AFS_LINUX22_ENV)
     {
-       struct inode *ip = (struct inode*)tvc;
+       struct inode *ip = AFSTOI(tvc);
        sema_init(&ip->i_sem, 1);
 #if defined(AFS_LINUX24_ENV)
        sema_init(&ip->i_zombie, 1);
@@ -958,8 +1022,17 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
        INIT_LIST_HEAD(&ip->i_data.dirty_pages);
        INIT_LIST_HEAD(&ip->i_data.locked_pages);
        INIT_LIST_HEAD(&ip->i_dirty_buffers);
+#ifdef STRUCT_INODE_HAS_I_DIRTY_DATA_BUFFERS
+       INIT_LIST_HEAD(&ip->i_dirty_data_buffers);
+#endif
+#ifdef STRUCT_INODE_HAS_I_DEVICES
+       INIT_LIST_HEAD(&ip->i_devices);
+#endif
        ip->i_data.host = (void*) ip;
        ip->i_mapping = &ip->i_data;
+#ifdef STRUCT_INODE_HAS_I_TRUNCATE_SEM
+       init_rwsem(&ip->i_truncate_sem);
+#endif
 #else
        sema_init(&ip->i_atomic_write, 1);
        init_waitqueue(&ip->i_wait);
@@ -974,8 +1047,8 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
 #endif
     tvc->h1.dchint = 0;
     osi_dnlc_purgedp(tvc);  /* this may be overkill */
-    bzero((char *)&(tvc->quick),sizeof(struct vtodc));
-    bzero((char *)&(tvc->callsort),sizeof(struct afs_q));
+    memset((char *)&(tvc->quick), 0, sizeof(struct vtodc));
+    memset((char *)&(tvc->callsort), 0, sizeof(struct afs_q));
     tvc->slocks = (struct SimpleLocks *)0;
     i = VCHash(afid);
 
@@ -1043,16 +1116,12 @@ afs_FlushActiveVcaches(doflocks)
                    tc = afs_Conn(&tvc->fid, &treq, SHARED_LOCK);
                    if (tc) {
                      XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_EXTENDLOCK);
-#ifdef RX_ENABLE_LOCKS
-                     AFS_GUNLOCK();
-#endif /* RX_ENABLE_LOCKS */
+                     RX_AFS_GUNLOCK();
                      code =
                            RXAFS_ExtendLock(tc->id,
                                             (struct AFSFid *) &tvc->fid.Fid,
                                             &tsync);
-#ifdef RX_ENABLE_LOCKS
-                     AFS_GLOCK();
-#endif /* RX_ENABLE_LOCKS */
+                     RX_AFS_GLOCK();
                      XSTATS_END_TIME;
                    }
                    else code = -1;
@@ -1081,7 +1150,7 @@ afs_FlushActiveVcaches(doflocks)
                /*
                 * That's because if we come in via the CUnlinkedDel bit state path we'll be have 0 refcnt
                 */
-               osi_Assert(tvc->vrefCount > 0);
+               osi_Assert(VREFCOUNT(tvc) > 0);
                AFS_RWLOCK((vnode_t *)tvc, VRWLOCK_WRITE);
 #endif
                ObtainWriteLock(&tvc->lock,52);
@@ -1136,16 +1205,16 @@ afs_FlushActiveVcaches(doflocks)
                AFS_FAST_RELE(tvc);
                if (didCore) {
 #ifdef AFS_GFS_ENV
-                   tvc->vrefCount--;
+                   VREFCOUNT_DEC(tvc);
 #else
-                   AFS_RELE((struct vnode *)tvc);
+                   AFS_RELE(AFSTOV(tvc));
 #endif
                    /* Matches write code setting CCore flag */
                    crfree(cred);
                }
            }          
 #ifdef AFS_DARWIN_ENV
-            if (tvc->vrefCount == 1 && UBCINFOEXISTS(&tvc->v)) {
+            if (VREFCOUNT(tvc) == 1 && UBCINFOEXISTS(&tvc->v)) {
                if (tvc->opens) panic("flushactive open, hasubc, but refcnt 1");
                osi_VM_TryReclaim(tvc,0);
            }
@@ -1244,6 +1313,7 @@ afs_SimpleVStat(avc, astat, areq)
     struct vrequest *areq;
 { /*afs_SimpleVStat*/
 
+    afs_size_t length;
     AFS_STATCNT(afs_SimpleVStat);
 
 #ifdef AFS_SGI_ENV
@@ -1254,16 +1324,21 @@ afs_SimpleVStat(avc, astat, areq)
 #endif
 
        {
+#ifdef AFS_64BIT_ClIENT
+           FillInt64(length, astat->Length_hi, astat->Length);
+#else /* AFS_64BIT_CLIENT */
+           length = astat->Length;
+#endif /* AFS_64BIT_CLIENT */
 #if defined(AFS_SGI_ENV)
            osi_Assert((valusema(&avc->vc_rwlock) <= 0) &&
                   (OSI_GET_LOCKID() == avc->vc_rwlockid));
-           if (astat->Length < avc->m.Length) {
+           if (length < avc->m.Length) {
                vnode_t *vp = (vnode_t *)avc;
                
                osi_Assert(WriteLocked(&avc->lock));
                ReleaseWriteLock(&avc->lock);
                AFS_GUNLOCK();
-               PTOSSVP(vp, (off_t)astat->Length, (off_t)MAXLONG);
+               PTOSSVP(vp, (off_t)length, (off_t)MAXLONG);
                AFS_GLOCK();
                ObtainWriteLock(&avc->lock,67);
            }
@@ -1271,9 +1346,9 @@ afs_SimpleVStat(avc, astat, areq)
            /* if writing the file, don't fetch over this value */
            afs_Trace3(afs_iclSetp, CM_TRACE_SIMPLEVSTAT,
                       ICL_TYPE_POINTER, avc,
-                      ICL_TYPE_INT32, avc->m.Length,
-                      ICL_TYPE_INT32, astat->Length);
-           avc->m.Length = astat->Length;
+                      ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
+                      ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
+           avc->m.Length = length;
            avc->m.Date = astat->ClientModTime;
        }
     avc->m.Owner = astat->Owner;
@@ -1352,21 +1427,17 @@ afs_WriteVCache(avc, astatus, areq)
 
     AFS_STATCNT(afs_WriteVCache);
     afs_Trace2(afs_iclSetp, CM_TRACE_WVCACHE, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_INT32, avc->m.Length);
+              ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
 
     do {
        tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
        if (tc) {
          XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
-#ifdef RX_ENABLE_LOCKS
-         AFS_GUNLOCK();
-#endif /* RX_ENABLE_LOCKS */
+         RX_AFS_GUNLOCK();
          code = RXAFS_StoreStatus(tc->id,
                                   (struct AFSFid *) &avc->fid.Fid,
                                   astatus, &OutStatus, &tsync);
-#ifdef RX_ENABLE_LOCKS
-         AFS_GLOCK();
-#endif /* RX_ENABLE_LOCKS */
+         RX_AFS_GLOCK();
          XSTATS_END_TIME;
        }
        else code = -1;
@@ -1427,8 +1498,14 @@ afs_ProcessFS(avc, astat, areq)
 { /*afs_ProcessFS*/
 
     register int i;
+    afs_size_t length;
     AFS_STATCNT(afs_ProcessFS);
 
+#ifdef AFS_64BIT_CLIENT
+    FillInt64(length, astat->Length_hi, astat->Length);
+#else /* AFS_64BIT_CLIENT */
+    length = astat->Length;
+#endif /* AFS_64BIT_CLIENT */
     /* WARNING: afs_DoBulkStat uses the Length field to store a sequence
      * number for each bulk status request. Under no circumstances
      * should afs_DoBulkStat store a sequence number if the new
@@ -1446,9 +1523,9 @@ afs_ProcessFS(avc, astat, areq)
             *  values.
             */
            afs_Trace3(afs_iclSetp, CM_TRACE_PROCESSFS, ICL_TYPE_POINTER, avc,
-                      ICL_TYPE_INT32, avc->m.Length,
-                      ICL_TYPE_INT32, astat->Length);
-           avc->m.Length = astat->Length;
+                      ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
+                      ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(length));
+           avc->m.Length = length;
            avc->m.Date = astat->ClientModTime;
        }
     hset64(avc->m.DataVersion, astat->dataVersionHigh, astat->DataVersion);
@@ -1527,15 +1604,11 @@ afs_RemoteLookup(afid, areq, name, nfid, OutStatusp, CallBackp, serverp, tsyncp)
            if (serverp) *serverp = tc->srvr->server;
            start = osi_Time();
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_XLOOKUP);
-#ifdef RX_ENABLE_LOCKS
-           AFS_GUNLOCK();
-#endif /* RX_ENABLE_LOCKS */
+           RX_AFS_GUNLOCK();
            code = RXAFS_Lookup(tc->id, (struct AFSFid *) &afid->Fid, name,
                                (struct AFSFid *) &nfid->Fid, 
                                OutStatusp, &OutDirStatus, CallBackp, tsyncp);
-#ifdef RX_ENABLE_LOCKS
-           AFS_GLOCK();
-#endif /* RX_ENABLE_LOCKS */
+           RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else 
            code = -1;
@@ -1683,8 +1756,15 @@ loop:
     /* stat the file */
     afs_RemoveVCB(afid);
     {
-    struct AFSFetchStatus OutStatus;
-    code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
+       struct AFSFetchStatus OutStatus;
+
+       if (afs_DynrootNewVnode(tvc, &OutStatus)) {
+           afs_ProcessFS(tvc, &OutStatus, areq);
+           tvc->states |= CStatd | CUnique;
+           code = 0;
+       } else {
+           code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
+       }
     }
 
     if (code) {
@@ -1914,7 +1994,7 @@ struct vcache *afs_GetRootVCache(struct VenusFid *afid,
             * can be safely implemented */
            int vg;
            AFS_GUNLOCK();
-            vg = vget((struct vnode *)tvc);   /* this bumps ref count */
+            vg = vget(AFSTOV(tvc));   /* this bumps ref count */
            AFS_GLOCK();
            if (vg)
                 continue;
@@ -2088,15 +2168,11 @@ afs_int32 afs_FetchStatus(struct vcache *avc, struct VenusFid *afid,
            avc->callback = tc->srvr->server;
            start = osi_Time();
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
-#ifdef RX_ENABLE_LOCKS
-           AFS_GUNLOCK();
-#endif /* RX_ENABLE_LOCKS */
+           RX_AFS_GUNLOCK();
            code = RXAFS_FetchStatus(tc->id,
                                     (struct AFSFid *) &afid->Fid,
                                     Outsp, &CallBack, &tsync);
-#ifdef RX_ENABLE_LOCKS
-           AFS_GLOCK();
-#endif /* RX_ENABLE_LOCKS */
+           RX_AFS_GLOCK();
 
            XSTATS_END_TIME;
 
@@ -2365,7 +2441,7 @@ struct vcache *afs_FindVCache(struct VenusFid *afid, afs_int32 lockit,
             /* Grab this vnode, possibly reactivating from the free list */
            int vg;
            AFS_GUNLOCK();
-            vg = vget((struct vnode *)tvc);
+            vg = vget(AFSTOV(tvc));
            AFS_GLOCK();
            if (vg)
                 continue;
@@ -2487,7 +2563,7 @@ afs_int32 afs_NFSFindVCache(avcp, afid, lockit)
             /* Grab this vnode, possibly reactivating from the free list */
            int vg;
            AFS_GUNLOCK();
-            vg = vget((struct vnode *)tvc);
+            vg = vget(AFSTOV(tvc));
            AFS_GLOCK();
            if (vg) {
                /* This vnode no longer exists. */
@@ -2499,8 +2575,8 @@ afs_int32 afs_NFSFindVCache(avcp, afid, lockit)
                /* Duplicates */
 #ifdef AFS_OSF_ENV
                /* Drop our reference counts. */
-               vrele((struct vnode *)tvc);
-               vrele((struct vnode *)found_tvc);
+               vrele(AFSTOV(tvc));
+               vrele(AFSTOV(found_tvc));
 #endif
                afs_duplicate_nfs_fids++;
                ReleaseSharedLock(&afs_xvcache);
@@ -2602,7 +2678,7 @@ void afs_vcacheInit(int astatSize)
 #if    !defined(AFS_OSF_ENV)
     /* Allocate and thread the struct vcache entries */
     tvp = (struct vcache *) afs_osi_Alloc(astatSize * sizeof(struct vcache));
-    bzero((char *)tvp, sizeof(struct vcache)*astatSize);
+    memset((char *)tvp, 0, sizeof(struct vcache)*astatSize);
 
     Initial_freeVCList = tvp;
     freeVCList = &(tvp[0]);
@@ -2669,7 +2745,7 @@ void shutdown_vcache(void)
                tvc->mvid = (struct VenusFid*)0;
            }
 #ifdef AFS_AIX_ENV
-           aix_gnode_rele((struct vnode *)tvc);
+           aix_gnode_rele(AFSTOV(tvc));
 #endif
            if (tvc->linkData) {
                afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
@@ -2694,7 +2770,7 @@ void shutdown_vcache(void)
                    vms_delete(tvc->segid);
                    AFS_GLOCK();
                    tvc->segid = tvc->vmh = NULL;
-                   if (tvc->vrefCount) osi_Panic("flushVcache: vm race");
+                   if (VREFCOUNT(tvc)) osi_Panic("flushVcache: vm race");
                }
                if (tvc->credp) {
                    crfree(tvc->credp);