macos bulkstat don't double reget refs
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index 2086e17..6dbd070 100644 (file)
@@ -377,11 +377,12 @@ afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
     if (tvc->mvstat != 1)
        return 0;
 
-    /* Is the call to VerifyVCache really necessary? */
-    code = afs_VerifyVCache(tvc, areq);
-    if (code)
-       goto done;
     if (canblock) {
+       /* Is the call to VerifyVCache really necessary? */
+       code = afs_VerifyVCache(tvc, areq);
+       if (code)
+           goto done;
+
        ObtainWriteLock(&tvc->lock, 599);
        code = EvalMountPoint(tvc, NULL, &tvolp, areq);
        ReleaseWriteLock(&tvc->lock);
@@ -647,6 +648,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
     int nentries;              /* # of entries to prefetch */
     int nskip;                 /* # of slots in the LRU queue to skip */
 #ifdef AFS_DARWIN80_ENV
+    int npasses = 0;
     struct vnode *lruvp;
 #endif
     struct vcache *lruvcp;     /* vcache ptr of our goal pos in LRU queue */
@@ -872,12 +874,17 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
                 * CBulkFetching state bit and the value in the file size.
                 * It is safe to set the status only if the CBulkFetching
                 * flag is still set and the value in the file size does
-                * not change. NewBulkVCache sets us up.
+                * not change. NewBulkVCache sets us up for the new ones.
+                * Set up the rest here.
                 *
                 * Don't fetch status for dirty files. We need to
                 * preserve the value of the file size. We could
                 * flush the pages, but it wouldn't be worthwhile.
                 */
+               if (!(tvcp->f.states & CBulkFetching)) {
+                   tvcp->f.states |= CBulkFetching;
+                   tvcp->f.m.Length = statSeqNo;
+               }
                memcpy((char *)(fidsp + fidIndex), (char *)&tfid.Fid,
                       sizeof(*fidsp));
                fidIndex++;
@@ -973,6 +980,9 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
   reskip:
     nskip = afs_cacheStats / 2;        /* preserved fraction of the cache */
     ObtainReadLock(&afs_xvcache);
+#ifdef AFS_DARWIN80_ENV
+ reskip2:
+#endif
     if (QEmpty(&VLRU)) {
        /* actually a serious error, probably should panic. Probably will 
         * panic soon, oh well. */
@@ -986,7 +996,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
     for (tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
        if (--nskip <= 0) {
 #ifdef AFS_DARWIN80_ENV
-           if (!(QTOV(tq)->f.states & CDeadVnode))
+           if ((!(QTOV(tq)->f.states & CDeadVnode)&&!(QTOV(tq)->f.states & CVInit)))
 #endif
                break;
        }
@@ -1007,6 +1017,14 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
      */
     retry = 0;
 #ifdef AFS_DARWIN80_ENV
+    if (((lruvcp->f.states & CDeadVnode)||(lruvcp->f.states & CVInit))) {
+       if (npasses == 0) {
+           nskip = 1;
+           npasses++;
+           goto reskip2;
+       } else
+           panic("Can't find non-dead vnode in VLRU\n");
+    }
     lruvp = AFSTOV(lruvcp);
     if (vnode_get(lruvp))       /* this bumps ref count */
        retry = 1;
@@ -1063,14 +1081,17 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
         */
        if (!(tvcp->f.states & CBulkFetching) || (tvcp->f.m.Length != statSeqNo)) {
 #ifdef AFS_DARWIN80_ENV            
-           int isdead = (tvcp->f.states & CDeadVnode);
+           int isdead = ((tvcp->f.states & CDeadVnode) ||
+                         (tvcp->f.states & CVInit));
 #endif
            flagIndex++;
            ReleaseWriteLock(&tvcp->lock);
 #ifdef AFS_DARWIN80_ENV            
-           if (!isdead)
-               /* re-acquire the usecount that the other finalizevnode disposed of */
+           if (!isdead) {
+               /* re-acquire the io&usecount that the other finalizevnode disposed of */
+               vnode_get(AFSTOV(tvcp));
                vnode_ref(AFSTOV(tvcp));
+           }
 #endif
            afs_PutVCache(tvcp);
            continue;
@@ -1084,6 +1105,11 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
            *tvcp->mvid = dotdot;
        }
 
+#ifdef AFS_DARWIN80_ENV
+       if (((lruvcp->f.states & CDeadVnode)||(lruvcp->f.states & CVInit)))
+           panic("vlru control point went dead\n");
+#endif
+
        ObtainWriteLock(&afs_xvcache, 132);
        if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
            refpanic("Bulkstat VLRU inconsistent2");
@@ -1123,9 +1149,11 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        if (!(tvcp->f.states & CBulkFetching) || (tvcp->f.m.Length != statSeqNo)) {
            flagIndex++;
 #ifdef AFS_DARWIN80_ENV            
-           if ((tvcp->f.states & CDeadVnode) == 0)
-               /* re-acquire the usecount that the other finalizevnode disposed of */
+           if ((!(tvcp->f.states & CDeadVnode)&&!(tvcp->f.states & CVInit))) {
+               /* re-acquire the io&usecount that the other finalizevnode disposed of */
+               vnode_get(AFSTOV(tvcp));
                vnode_ref(AFSTOV(tvcp));
+           }
 #endif
            ReleaseWriteLock(&tvcp->lock);
            ReleaseWriteLock(&afs_xcbhash);
@@ -1185,7 +1213,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        ReleaseWriteLock(&afs_xcbhash);
 #ifdef AFS_DARWIN80_ENV
        /* reclaim->FlushVCache will need xcbhash */
-       if (tvcp->f.states & CDeadVnode) {
+       if (((tvcp->f.states & CDeadVnode)||(tvcp->f.states & CVInit))) {
            /* passing in a parent hangs getting the vnode lock */
            code = afs_darwin_finalizevnode(tvcp, NULL, NULL, 0, 1);
            if (code) {
@@ -1195,9 +1223,11 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
                afs_DequeueCallback(tvcp);
                if ((tvcp->f.states & CForeign) || (vType(tvcp) == VDIR))
                    osi_dnlc_purgedp(tvcp); /* if it (could be) a directory */
-           } else
-               /* re-acquire the usecount that finalizevnode disposed of */
+           } else {
+               /* re-acquire the io&usecount that finalizevnode disposed of */
+               vnode_get(AFSTOV(tvcp));
                vnode_ref(AFSTOV(tvcp));
+           }
        }
 #endif
 
@@ -1208,6 +1238,8 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
 
     /* finally return the pointer into the LRU queue */
 #ifdef AFS_DARWIN80_ENV
+    if (((lruvcp->f.states & CDeadVnode)||(lruvcp->f.states & CVInit)))
+       panic("vlru control point went dead before put\n");
     AFS_GUNLOCK();
     vnode_put(lruvp);
     vnode_rele(lruvp);
@@ -1229,18 +1261,27 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
            tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */ );
            ReleaseReadLock(&afs_xvcache);
        } while (tvcp && retry);
-       if (tvcp != NULL && (tvcp->f.states & CBulkFetching)
-           && (tvcp->f.m.Length == statSeqNo)) {
-           tvcp->f.states &= ~CBulkFetching;
-       }
        if (tvcp != NULL) {
-#ifdef AFS_DARWIN80_ENV            
-           if ((tvcp->f.states & CDeadVnode) == 0) 
-               /* re-acquire the usecount that the other finalizevnode disposed of */
-               vnode_ref(AFSTOV(tvcp));
+           if ((tvcp->f.states & CBulkFetching)
+               && (tvcp->f.m.Length == statSeqNo)) {
+               tvcp->f.states &= ~CBulkFetching;
+#ifdef AFS_DARWIN80_ENV
+               if ((!(tvcp->f.states & CDeadVnode)&&!(tvcp->f.states & CVInit))) {
+                   /* re-acquire the io&usecount that finalizevnode dropped */
+                   vnode_get(AFSTOV(tvcp));
+                   vnode_ref(AFSTOV(tvcp));
+               }
 #endif
+           }
            afs_PutVCache(tvcp);
        }
+#ifdef AFS_DARWIN80_ENV            
+       else {
+           if ((!(tvcp->f.states & CDeadVnode)&&!(tvcp->f.states & CVInit)))
+               osi_Panic("vnode finalized without clearing BulkFetching!");
+       }
+#endif
+
     }
     if (volp)
        afs_PutVolume(volp, READ_LOCK);