libafs: Avoid duplicate afs_Analyze in bulk stat
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index 9c75730..c3c9ad0 100644 (file)
@@ -57,7 +57,7 @@ EvalMountData(char type, char *data, afs_uint32 states, afs_uint32 cellnum,
     struct volume *tvp = 0;
     struct VenusFid tfid;
     struct cell *tcell;
-    char *cpos, *volnamep;
+    char *cpos, *volnamep = NULL;
     char *buf, *endptr;
     afs_int32 prefetch;                /* 1=>None  2=>RO  3=>BK */
     afs_int32 mtptCell, assocCell = 0, hac = 0;
@@ -528,19 +528,19 @@ afs_getsysname(struct vrequest *areq, struct vcache *adp,
     if (!afs_nfsexporter)
        strcpy(bufp, (*sysnamelist)[0]);
     else {
-       au = afs_GetUser(areq->uid, adp->f.fid.Cell, 0);
+       au = afs_GetUser(areq->uid, adp->f.fid.Cell, READ_LOCK);
        if (au->exporter) {
            error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num, 0);
            if (error) {
                strcpy(bufp, "@sys");
-               afs_PutUser(au, 0);
+               afs_PutUser(au, READ_LOCK);
                return -1;
            } else {
                strcpy(bufp, (*sysnamelist)[0]);
            }
        } else
            strcpy(bufp, afs_sysname);
-       afs_PutUser(au, 0);
+       afs_PutUser(au, READ_LOCK);
     }
     return 0;
 }
@@ -604,16 +604,16 @@ Next_AtSys(struct vcache *avc, struct vrequest *areq,
        *sysnamelist = afs_sysnamelist;
 
        if (afs_nfsexporter) {
-           au = afs_GetUser(areq->uid, avc->f.fid.Cell, 0);
+           au = afs_GetUser(areq->uid, avc->f.fid.Cell, READ_LOCK);
            if (au->exporter) {
                error =
                    EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, &num, 0);
                if (error) {
-                   afs_PutUser(au, 0);
+                   afs_PutUser(au, READ_LOCK);
                    return 0;
                }
            }
-           afs_PutUser(au, 0);
+           afs_PutUser(au, READ_LOCK);
        }
        if (++(state->index) >= num || !(*sysnamelist)[(unsigned int)state->index])
            return 0;           /* end of list */
@@ -670,9 +670,11 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
     long startTime;            /* time we started the call,
                                 * for callback expiration base
                                 */
+    int ftype[4] = {VNON, VREG, VDIR, VLNK}; /* verify type is as expected */
     afs_size_t statSeqNo = 0;  /* Valued of file size to detect races */
     int code;                  /* error code */
     long newIndex;             /* new index in the dir */
+    struct DirBuffer entry;    /* Buffer for dir manipulation */
     struct DirEntry *dirEntryp;        /* dir entry we are examining */
     int i;
     struct VenusFid afid;      /* file ID we are using now */
@@ -682,7 +684,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
     struct volume *volp = 0;   /* volume ptr */
     struct VenusFid dotdot = {0, {0, 0, 0}};
     int flagIndex = 0;         /* First file with bulk fetch flag set */
-    int inlinebulk = 0;                /* Did we use InlineBulk RPC or not? */
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
     dotdot.Cell = 0;
     dotdot.Fid.Unique = 0;
@@ -790,14 +792,14 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        dirCookie = newIndex << 5;
 
        /* get a ptr to the dir entry */
-       dirEntryp =
-           (struct DirEntry *)afs_dir_GetBlob(dcp, newIndex);
-       if (!dirEntryp)
+       code = afs_dir_GetBlob(dcp, newIndex, &entry);
+       if (code)
            break;
+       dirEntryp = (struct DirEntry *)entry.data;
 
        /* dont copy more than we have room for */
        if (fidIndex >= nentries) {
-           DRelease(dirEntryp, 0);
+           DRelease(&entry, 0);
            break;
        }
 
@@ -826,19 +828,31 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
                tvcp = afs_NewBulkVCache(&tfid, hostp, statSeqNo);
                if (tvcp)
                {
-                       ObtainWriteLock(&tvcp->lock, 505);
-                       ReleaseWriteLock(&afs_xvcache);
-                       afs_RemoveVCB(&tfid);
-                       ReleaseWriteLock(&tvcp->lock);
+                   ObtainWriteLock(&tvcp->lock, 505);
+#ifdef AFS_DARWIN80_ENV
+                   /* use even/odd hack to guess file versus dir.
+                      let links be reaped. oh well. */
+                   if (dirEntryp->fid.vnode & 1)
+                       tvcp->f.m.Type = VDIR;
+                   else
+                       tvcp->f.m.Type = VREG;
+                   /* finalize to a best guess */
+                   afs_darwin_finalizevnode(tvcp, VTOAFS(adp), NULL, 0, 1);
+                   /* re-acquire usecount that finalizevnode disposed of */
+                   vnode_ref(AFSTOV(tvcp));
+#endif
+                   ReleaseWriteLock(&afs_xvcache);
+                   afs_RemoveVCB(&tfid);
+                   ReleaseWriteLock(&tvcp->lock);
                } else {
-                       ReleaseWriteLock(&afs_xvcache);
+                   ReleaseWriteLock(&afs_xvcache);
                }
            } else {
                ReleaseWriteLock(&afs_xvcache);
            }
            if (!tvcp)
            {
-               DRelease(dirEntryp, 0);
+               DRelease(&entry, 0);
                ReleaseReadLock(&dcp->lock);
                ReleaseReadLock(&adp->lock);
                afs_PutDCache(dcp);
@@ -897,7 +911,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
         * used by this dir entry.
         */
        temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
-       DRelease(dirEntryp, 0);
+       DRelease(&entry, 0);
        if (temp <= 0)
            break;
        dirCookie += temp;
@@ -926,7 +940,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        /* start the timer; callback expirations are relative to this */
        startTime = osi_Time();
 
-       tcp = afs_Conn(&adp->f.fid, areqp, SHARED_LOCK);
+       tcp = afs_Conn(&adp->f.fid, areqp, SHARED_LOCK, &rxconn);
        if (tcp) {
            hostp = tcp->parent->srvr->server;
 
@@ -962,40 +976,28 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
 
            if (!(tcp->parent->srvr->server->flags & SNO_INLINEBULK)) {
-           retryonce:
                RX_AFS_GUNLOCK();
                code =
-                   RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
+                   RXAFS_InlineBulkStatus(rxconn, &fidParm, &statParm,
                                           &cbParm, &volSync);
                RX_AFS_GLOCK();
                if (code == RXGEN_OPCODE) {
                    tcp->parent->srvr->server->flags |= SNO_INLINEBULK;
-                   inlinebulk = 0;
                    RX_AFS_GUNLOCK();
                    code =
-                       RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
+                       RXAFS_BulkStatus(rxconn, &fidParm, &statParm,
                                         &cbParm, &volSync);
                    RX_AFS_GLOCK();
-               } else {
-                   inlinebulk = 1;
-                   if (!code && ((&statsp[0])->errorCode)) {
-                       /*
-                        * If this is an error needing retry, do so.
-                        * Retryable errors are all whole-volume or
-                        * whole-server.
-                        */
-                       if (afs_Analyze(tcp, (&statsp[0])->errorCode,
-                                       &adp->f.fid, areqp,
-                                       AFS_STATS_FS_RPCIDX_BULKSTATUS,
-                                       SHARED_LOCK, NULL) != 0)
-                           goto retryonce;
-                   }
+               } else if (!code) {
+                   /* The InlineBulkStatus call itself succeeded, but we
+                    * may have failed to stat the first entry. Use the error
+                    * from the first entry for processing. */
+                   code = (&statsp[0])->errorCode;
                }
            } else {
-               inlinebulk = 0;
                RX_AFS_GUNLOCK();
                code =
-                   RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
+                   RXAFS_BulkStatus(rxconn, &fidParm, &statParm, &cbParm,
                                     &volSync);
                RX_AFS_GLOCK();
            }
@@ -1003,7 +1005,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        } else
            code = -1;
     } while (afs_Analyze
-            (tcp, code, &adp->f.fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
+            (tcp, rxconn, code, &adp->f.fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
              SHARED_LOCK, NULL));
 
     /* now, if we didnt get the info, bail out. */
@@ -1109,7 +1111,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        do {
            retry = 0;
            ObtainReadLock(&afs_xvcache);
-           tvcp = afs_FindVCache(&afid, &retry, FIND_CDEAD /* !stats&!lru */);
+           tvcp = afs_FindVCache(&afid, &retry, 0/* !stats&!lru */);
            ReleaseReadLock(&afs_xvcache);
        } while (tvcp && retry);
 
@@ -1125,9 +1127,12 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
         * matches the value we placed there when we set the CBulkFetching
         * flag, then someone else has done something with this node,
         * and we may not have the latest status information for this
-        * file.  Leave the entry alone.
+        * file.  Leave the entry alone. There's also a file type
+        * change here, for OSX bulkstat support.
         */
-       if (!(tvcp->f.states & CBulkFetching) || (tvcp->f.m.Length != statSeqNo)) {
+       if (!(tvcp->f.states & CBulkFetching)
+           || (tvcp->f.m.Length != statSeqNo)
+           || (ftype[(&statsp[i])->FileType] != vType(tvcp))) {
            flagIndex++;
            ReleaseWriteLock(&tvcp->lock);
            afs_PutVCache(tvcp);
@@ -1253,10 +1258,9 @@ 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 {
+           } else
                /* re-acquire the usecount that finalizevnode disposed of */
                vnode_ref(AFSTOV(tvcp));
-           }
        } else
 #endif
        ReleaseWriteLock(&afs_xcbhash);
@@ -1288,7 +1292,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        do {
            retry = 0;
            ObtainReadLock(&afs_xvcache);
-           tvcp = afs_FindVCache(&afid, &retry, FIND_CDEAD /* !stats&!lru */);
+           tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */);
            ReleaseReadLock(&afs_xvcache);
        } while (tvcp && retry);
        if (tvcp != NULL) {
@@ -1302,16 +1306,6 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
     if (volp)
        afs_PutVolume(volp, READ_LOCK);
 
-    /* If we did the InlineBulk RPC pull out the return code */
-    if (inlinebulk && code == 0) {
-       if ((&statsp[0])->errorCode) {
-           afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->f.fid, areqp,
-                       AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, NULL);
-           code = (&statsp[0])->errorCode;
-       }
-    } else {
-       code = 0;
-    }
   done2:
     osi_FreeLargeSpace((char *)fidsp);
     osi_Free((char *)statsp, AFSCBMAX * sizeof(AFSFetchStatus));
@@ -1320,7 +1314,11 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
 }
 
 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
+#ifdef AFS_DARWIN80_ENV
+int AFSDOBULK = 1;
+#else
 static int AFSDOBULK = 1;
+#endif
 
 static_inline int
 osi_lookup_isdot(const char *aname)