afs-dont-mask-rights-granted-by-lookup-20020328
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index 0346dc0..726a95d 100644 (file)
@@ -19,8 +19,8 @@
  * afs_index
  */
 
-#include "../afs/param.h"      /* Should be always first */
 #include <afsconfig.h>
+#include "../afs/param.h"
 
 RCSID("$Header$");
 
@@ -133,7 +133,7 @@ EvalMountPoint(avc, advc, avolpp, areq)
        volnamep = &avc->linkData[1];
        tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
     }
-    if (!tcell) return ENOENT;
+    if (!tcell) return ENODEV;
 
     mtptCell = tcell->cell;               /* The cell for the mountpoint */
     if (tcell->lcellp) {
@@ -353,7 +353,7 @@ extern int BlobScan(afs_int32 *afile, afs_int32 ablob);
  * CForeign bit set.
  */
 struct vcache * BStvc = (struct vcache *) 0;
-void afs_DoBulkStat(adp, dirCookie, areqp)
+int afs_DoBulkStat(adp, dirCookie, areqp)
   struct vcache *adp;
   long dirCookie;
   struct vrequest *areqp;
@@ -364,7 +364,7 @@ void afs_DoBulkStat(adp, dirCookie, areqp)
     struct dcache *dcp;                /* chunk containing the dir block */
     char *statMemp;            /* status memory block */
     char *cbfMemp;             /* callback and fid memory block */
-    long temp;                 /* temp for holding chunk length, &c. */
+    afs_size_t temp;           /* temp for holding chunk length, &c. */
     struct AFSFid *fidsp;      /* file IDs were collecting */
     struct AFSCallBack *cbsp;  /* call back pointers */
     struct AFSCallBack *tcbp;  /* temp callback ptr */
@@ -385,7 +385,7 @@ void afs_DoBulkStat(adp, dirCookie, areqp)
     long startTime;            /* time we started the call,
                                 * for callback expiration base
                                 */
-    int statSeqNo;             /* Valued of file size to detect races */
+    afs_size_t statSeqNo;      /* Valued of file size to detect races */
     int code;                  /* error code */
     long newIndex;             /* new index in the dir */
     struct DirEntry *dirEntryp;        /* dir entry we are examining */
@@ -397,6 +397,7 @@ void afs_DoBulkStat(adp, dirCookie, areqp)
     struct volume *volp=0;     /* volume ptr */
     struct VenusFid dotdot;
     int        flagIndex;              /* First file with bulk fetch flag set */
+    int inlinebulk=0;           /* Did we use InlineBulk RPC or not? */
     XSTATS_DECLS
 
     /* first compute some basic parameters.  We dont want to prefetch more
@@ -436,7 +437,7 @@ tagain:
     code = afs_VerifyVCache(adp, areqp);
     if (code) goto done;
 
-    dcp = afs_GetDCache(adp, 0, areqp, &temp, &temp, 1);
+    dcp = afs_GetDCache(adp, (afs_size_t) 0, areqp, &temp, &temp, 1);
     if (!dcp) {
        code = ENOENT;
        goto done;
@@ -444,6 +445,7 @@ tagain:
 
     /* lock the directory cache entry */
     ObtainReadLock(&adp->lock);
+    ObtainReadLock(&dcp->lock);
 
     /*
      * Make sure that the data in the cache is current. There are two
@@ -452,15 +454,22 @@ tagain:
      * 2. The cache data is no longer valid
      */
     while ((adp->states & CStatd)
-          && (dcp->flags & DFFetching)
+          && (dcp->dflags & DFFetching)
           && hsame(adp->m.DataVersion, dcp->f.versionNo)) {
-       dcp->flags |= DFWaiting;
+       afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
+                       ICL_TYPE_STRING, __FILE__,
+                       ICL_TYPE_INT32, __LINE__,
+                       ICL_TYPE_POINTER, dcp,
+                       ICL_TYPE_INT32, dcp->dflags);
+       ReleaseReadLock(&dcp->lock);
        ReleaseReadLock(&adp->lock);
        afs_osi_Sleep(&dcp->validPos);
        ObtainReadLock(&adp->lock);
+       ObtainReadLock(&dcp->lock);
     }
     if (!(adp->states & CStatd)
        || !hsame(adp->m.DataVersion, dcp->f.versionNo)) {
+       ReleaseReadLock(&dcp->lock);
        ReleaseReadLock(&adp->lock);
        afs_PutDCache(dcp);
        goto tagain;
@@ -516,7 +525,7 @@ tagain:
              tvcp = afs_FindVCache(&tfid, 0, 0, &retry, 0 /* no stats | LRU */);
              if (tvcp && retry) {
                ReleaseWriteLock(&afs_xvcache);
-               afs_PutVCache(tvcp);
+               afs_PutVCache(tvcp, 0);
              }
            } while (tvcp && retry);
            if (!tvcp) {          /* otherwise, create manually */
@@ -562,13 +571,12 @@ tagain:
                 * preserve the value of the file size. We could
                 * flush the pages, but it wouldn't be worthwhile.
                 */
-               bcopy((char *) &tfid.Fid, (char *)(fidsp+fidIndex),
-                     sizeof(*fidsp));
+               memcpy((char *)(fidsp+fidIndex), (char *) &tfid.Fid, sizeof(*fidsp));
                tvcp->states |= CBulkFetching;
                tvcp->m.Length = statSeqNo;
                fidIndex++;
            }
-           afs_PutVCache(tvcp);
+           afs_PutVCache(tvcp, 0);
        }       /* if dir vnode has non-zero entry */
 
        /* move to the next dir entry by adding in the # of entries
@@ -581,6 +589,7 @@ tagain:
     }  /* while loop over all dir entries */
 
     /* now release the dir lock and prepare to make the bulk RPC */
+    ReleaseReadLock(&dcp->lock);
     ReleaseReadLock(&adp->lock);
 
     /* release the chunk */
@@ -608,8 +617,22 @@ tagain:
 #ifdef RX_ENABLE_LOCKS
            AFS_GUNLOCK();
 #endif /* RX_ENABLE_LOCKS */
-           code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
-                                   &volSync);
+
+           if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
+               code = RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
+                                             &cbParm, &volSync);
+               if (code == RXGEN_OPCODE) {
+                   tcp->srvr->server->flags |= SNO_INLINEBULK;
+                   inlinebulk = 0;
+                   code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, 
+                                           &cbParm, &volSync);
+               } else
+                   inlinebulk=1;
+           } else {
+               inlinebulk=0;
+               code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
+                                       &volSync);
+           }
 #ifdef RX_ENABLE_LOCKS
            AFS_GLOCK();
 #endif /* RX_ENABLE_LOCKS */
@@ -681,6 +704,8 @@ tagain:
      * We also have to take into account racing token revocations.
      */
     for(i=0; i<fidIndex; i++) {
+       if ((&statsp[i])->errorCode) 
+           continue;
        afid.Cell = adp->fid.Cell;
        afid.Fid.Volume = adp->fid.Fid.Volume;
        afid.Fid.Vnode = fidsp[i].Vnode;
@@ -709,7 +734,7 @@ tagain:
        if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
            flagIndex++;
            ReleaseWriteLock(&tvcp->lock);
-           afs_PutVCache(tvcp);
+           afs_PutVCache(tvcp, 0);
            continue;
        }
 
@@ -756,7 +781,7 @@ tagain:
            flagIndex++;
            ReleaseWriteLock(&tvcp->lock);
            ReleaseWriteLock(&afs_xcbhash);
-           afs_PutVCache(tvcp);
+           afs_PutVCache(tvcp, 0);
            continue;
        }
 
@@ -816,11 +841,11 @@ tagain:
 
        ReleaseWriteLock(&tvcp->lock);
        /* finally, we're done with the entry */
-       afs_PutVCache(tvcp);
+       afs_PutVCache(tvcp, 0);
     }  /* for all files we got back */
 
     /* finally return the pointer into the LRU queue */
-    afs_PutVCache(lruvcp);
+    afs_PutVCache(lruvcp, 0);
 
   done:
     /* Be sure to turn off the CBulkFetching flags */
@@ -841,14 +866,26 @@ tagain:
          tvcp->states &= ~CBulkFetching;
        }
        if (tvcp != NULL) {
-         afs_PutVCache(tvcp);
+         afs_PutVCache(tvcp, 0);
        }
     }
     if ( volp )
        afs_PutVolume(volp, READ_LOCK);
     
+    /* If we did the InlineBulk RPC pull out the return code */
+    if (inlinebulk) {
+       if ((&statsp[0])->errorCode) {
+           afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->fid, areqp, 
+                       AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, 
+                       (struct cell *)0);
+           code = (&statsp[0])->errorCode;
+       }
+    } else {
+       code = 0;
+    }
     osi_FreeLargeSpace(statMemp);
     osi_FreeLargeSpace(cbfMemp);
+    return code;
 }
 
 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
@@ -886,6 +923,7 @@ afs_lookup(adp, aname, avcp, acred)
     char *tname = (char *)0;
     register struct vcache *tvc=0;
     register afs_int32 code;
+    register afs_int32 bulkcode = 0;
     int pass = 0, hit = 0;
     long dirCookie;
     extern afs_int32 afs_mariner;                      /*Writing activity to log?*/
@@ -893,18 +931,19 @@ afs_lookup(adp, aname, avcp, acred)
     afs_hyper_t versionNo;
     int no_read_access = 0;
     struct sysname_info sysState;   /* used only for @sys checking */
+    int dynrootRetry = 1;
 
     AFS_STATCNT(afs_lookup);
 #ifdef AFS_OSF_ENV
-    ndp->ni_dvp = (struct vnode *)adp;
-    bcopy(ndp->ni_ptr, aname, ndp->ni_namelen);
+    ndp->ni_dvp = AFSTOV(adp);
+    memcpy(aname, ndp->ni_ptr, ndp->ni_namelen);
     aname[ndp->ni_namelen] = '\0';
 #endif /* AFS_OSF_ENV */
 
     *avcp = (struct vcache *) 0;   /* Since some callers don't initialize it */
 
     if (code = afs_InitReq(&treq, acred)) { 
-      goto done;
+       goto done;
     }
 
     /* come back to here if we encounter a non-existent object in a read-only
@@ -912,10 +951,12 @@ afs_lookup(adp, aname, avcp, acred)
 
   redo:
     *avcp = (struct vcache *) 0;   /* Since some callers don't initialize it */
+    bulkcode = 0;
 
     if (!(adp->states & CStatd)) {
-       if (code = afs_VerifyVCache2(adp, &treq))
-         goto done;
+       if (code = afs_VerifyVCache2(adp, &treq)) {
+           goto done;
+       }
     }
     else code = 0;
 
@@ -926,7 +967,7 @@ afs_lookup(adp, aname, avcp, acred)
 #ifdef AFS_OSF_ENV
            extern struct vcache *afs_globalVp;
            if (adp == afs_globalVp) {
-               struct vnode *rvp = (struct vnode *)adp;
+               struct vnode *rvp = AFSTOV(adp);
 /*
                ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
                ndp->ni_dvp = ndp->ni_vp;
@@ -948,7 +989,7 @@ afs_lookup(adp, aname, avcp, acred)
        *avcp = tvc;
        code = (tvc ? 0 : ENOENT);
        hit = 1;
-       if (tvc && !tvc->vrefCount) {
+       if (tvc && !VREFCOUNT(tvc)) {
            osi_Panic("TT1");
        }
        if (code) {
@@ -969,7 +1010,7 @@ afs_lookup(adp, aname, avcp, acred)
 
     /* Check for read access as well.  We need read access in order to
        stat files, but not to stat subdirectories. */
-    if (!afs_AccessOK(adp, PRSFS_READ, &treq, CHECK_MODE_BITS))
+    if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS))
        no_read_access = 1;
 
     /* special case lookup of ".".  Can we check for it sooner in this code,
@@ -981,13 +1022,13 @@ afs_lookup(adp, aname, avcp, acred)
        ObtainReadLock(&afs_xvcache);   
        osi_vnhold(adp, 0);
        ReleaseReadLock(&afs_xvcache);  
-      code = 0;
-      *avcp = tvc = adp;
-      hit = 1;
-       if (adp && !adp->vrefCount) {
+       code = 0;
+       *avcp = tvc = adp;
+       hit = 1;
+       if (adp && !VREFCOUNT(adp)) {
            osi_Panic("TT2");
        }
-      goto done;
+       goto done;
     }
 
     Check_AtSys(adp, aname, &sysState, &treq);
@@ -1003,8 +1044,8 @@ afs_lookup(adp, aname, avcp, acred)
     tvc = osi_dnlc_lookup (adp, tname, WRITE_LOCK);
     *avcp = tvc;  /* maybe wasn't initialized, but it is now */
     if (tvc) {
-       if (no_read_access && vType(tvc) != VDIR) {
-           /* need read access on dir to stat non-directory */
+       if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
+           /* need read access on dir to stat non-directory / non-link */
            afs_PutVCache(tvc, WRITE_LOCK);
            *avcp = (struct vcache *)0;
            code = EACCES;
@@ -1029,12 +1070,12 @@ afs_lookup(adp, aname, avcp, acred)
 
     {
     register struct dcache *tdc;
-    afs_int32 dirOffset, dirLen;
+    afs_size_t dirOffset, dirLen;
     ino_t theDir;
     struct VenusFid tfid;
 
     /* now we have to lookup the next fid */
-    tdc = afs_GetDCache(adp, 0, &treq, &dirOffset, &dirLen, 1);
+    tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1);
     if (!tdc) {
       *avcp = (struct vcache *)0;  /* redundant, but harmless */
       code = EIO;
@@ -1044,6 +1085,7 @@ afs_lookup(adp, aname, avcp, acred)
     /* now we will just call dir package with appropriate inode.
       Dirs are always fetched in their entirety for now */
     ObtainReadLock(&adp->lock);
+    ObtainReadLock(&tdc->lock);
 
     /*
      * Make sure that the data in the cache is current. There are two
@@ -1052,15 +1094,17 @@ afs_lookup(adp, aname, avcp, acred)
      * 2. The cache data is no longer valid
      */
     while ((adp->states & CStatd)
-          && (tdc->flags & DFFetching)
+          && (tdc->dflags & DFFetching)
           && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
-       tdc->flags |= DFWaiting;
+       ReleaseReadLock(&tdc->lock);
        ReleaseReadLock(&adp->lock);
        afs_osi_Sleep(&tdc->validPos);
        ObtainReadLock(&adp->lock);
+       ObtainReadLock(&tdc->lock);
     }
     if (!(adp->states & CStatd)
        || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
+       ReleaseReadLock(&tdc->lock);
        ReleaseReadLock(&adp->lock);
        afs_PutDCache(tdc);
        goto redo;
@@ -1091,9 +1135,28 @@ afs_lookup(adp, aname, avcp, acred)
     }
     tname = sysState.name;
 
-    ReleaseReadLock(&adp->lock);
+    ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);
 
+    if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
+       struct cell *tcell;
+
+       ReleaseReadLock(&adp->lock);
+       dynrootRetry = 0;
+       if (*tname == '.')
+           tcell = afs_GetCellByName(tname + 1, READ_LOCK);
+       else
+           tcell = afs_GetCellByName(tname, READ_LOCK);
+       if (tcell) {
+           afs_PutCell(tcell, READ_LOCK);
+           afs_RefreshDynroot();
+           if (tname != aname && tname) osi_FreeLargeSpace(tname);
+           goto redo;
+       }
+    } else {
+       ReleaseReadLock(&adp->lock);
+    }
+
     /* new fid has same cell and volume */
     tfid.Cell = adp->fid.Cell;
     tfid.Fid.Volume = adp->fid.Fid.Volume;
@@ -1111,7 +1174,7 @@ afs_lookup(adp, aname, avcp, acred)
     /* prefetch some entries, if the dir is currently open.  The variable
      * dirCookie tells us where to start prefetching from.
      */
-    if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign)) {
+    if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign) && !afs_IsDynroot(adp)) {
         afs_int32 retry;
        /* if the entry is not in the cache, or is in the cache,
         * but hasn't been statd, then do a bulk stat operation.
@@ -1123,23 +1186,26 @@ afs_lookup(adp, aname, avcp, acred)
           ReleaseReadLock(&afs_xvcache);       
         } while (tvc && retry);
 
-       if (!tvc || !(tvc->states & CStatd)) {
-           afs_DoBulkStat(adp, dirCookie, &treq);
-       }
+       if (!tvc || !(tvc->states & CStatd)) 
+           bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
+       else 
+           bulkcode = 0;
 
        /* if the vcache isn't usable, release it */
        if (tvc && !(tvc->states & CStatd)) {
-           afs_PutVCache(tvc);
+           afs_PutVCache(tvc, 0);
            tvc = (struct vcache *) 0;
        }
+    } else {
+       tvc = (struct vcache *) 0;
+       bulkcode = 0;
     }
-    else tvc = (struct vcache *) 0;
-    
+
     /* now get the status info, if we don't already have it */
     /* This is kind of weird, but we might wind up accidentally calling
      * RXAFS_Lookup because we happened upon a file which legitimately
      * has a 0 uniquifier. That is the result of allowing unique to wrap
-     * to 0. This was fixed in AFS 3.4. For CForeigh, Unique == 0 means that
+     * to 0. This was fixed in AFS 3.4. For CForeign, Unique == 0 means that
      * the file has not yet been looked up.
      */
     if (!tvc) {
@@ -1148,10 +1214,10 @@ afs_lookup(adp, aname, avcp, acred)
            tvc = afs_LookupVCache(&tfid, &treq, &cached, WRITE_LOCK, 
                                   adp, tname);
        } 
-       if (!tvc) {  /* lookup failed or wasn't called */
-           tvc = afs_GetVCache(&tfid, &treq, &cached, (struct vcache*)0,
-                               WRITE_LOCK);
-       }
+       if (!tvc && !bulkcode) {  /* lookup failed or wasn't called */
+          tvc = afs_GetVCache(&tfid, &treq, &cached, (struct vcache*)0,
+                              WRITE_LOCK);
+       } 
     } /* if !tvc */
     } /* sub-block just to reduce stack usage */
 
@@ -1175,6 +1241,7 @@ afs_lookup(adp, aname, avcp, acred)
            ReleaseWriteLock(&tvc->lock);
 
            if (code) {
+               afs_PutVCache(tvc, WRITE_LOCK);
                if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
                goto done;
            }
@@ -1226,7 +1293,7 @@ afs_lookup(adp, aname, avcp, acred)
            }
        }
        *avcp = tvc;
-       if (tvc && !tvc->vrefCount) {
+       if (tvc && !VREFCOUNT(tvc)) {
            osi_Panic("TT3");
        }
        code = 0;
@@ -1294,6 +1361,7 @@ done:
 #endif
        }
     }
+    if (bulkcode) code = bulkcode; else 
     code = afs_CheckCode(code, &treq, 19);
     if (code) {
        /* If there is an error, make sure *avcp is null.