afs: Clarify vcache->mvid accesses
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index 5bddf76..9d59564 100644 (file)
@@ -39,7 +39,7 @@ int afs_fakestat_enable = 0;  /* 1: fakestat-all, 2: fakestat-crosscell */
  * what "@sys" is in binary... */
 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
 
-/* call under write lock, evaluate mvid field from a mt pt.
+/* call under write lock, evaluate mvid.target_root field from a mt pt.
  * avc is the vnode of the mount point object; must be write-locked.
  * advc is the vnode of the containing directory (optional; if NULL and
  *   EvalMountPoint succeeds, caller must initialize *avolpp->dotdot)
@@ -279,7 +279,7 @@ EvalMountPoint(struct vcache *avc, struct vcache *advc,
 
     AFS_STATCNT(EvalMountPoint);
 #ifdef notdef
-    if (avc->mvid && (avc->f.states & CMValid))
+    if (avc->mvid.target_root && (avc->f.states & CMValid))
        return 0;               /* done while racing */
 #endif
     *avolpp = NULL;
@@ -299,12 +299,12 @@ EvalMountPoint(struct vcache *avc, struct vcache *advc,
     if (!auniq)
        auniq = 1;
 
-    if (avc->mvid == 0)
-       avc->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
-    avc->mvid->Cell = (*avolpp)->cell;
-    avc->mvid->Fid.Volume = (*avolpp)->volume;
-    avc->mvid->Fid.Vnode = avnoid;
-    avc->mvid->Fid.Unique = auniq;
+    if (avc->mvid.target_root == NULL)
+       avc->mvid.target_root = osi_AllocSmallSpace(sizeof(struct VenusFid));
+    avc->mvid.target_root->Cell = (*avolpp)->cell;
+    avc->mvid.target_root->Fid.Volume = (*avolpp)->volume;
+    avc->mvid.target_root->Fid.Vnode = avnoid;
+    avc->mvid.target_root->Fid.Unique = auniq;
     avc->f.states |= CMValid;
 
     /* Used to: if the mount point is stored within a backup volume,
@@ -373,7 +373,7 @@ afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
     state->did_eval = 1;
 
     tvc = *avcp;
-    if (tvc->mvstat != 1)
+    if (tvc->mvstat != AFS_MVSTAT_MTPT)
        return 0;
 
     if (canblock) {
@@ -393,14 +393,14 @@ afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
            tvolp->dotdot.Fid.Unique = tvc->f.parent.unique;
        }
     }
-    if (tvc->mvid && (tvc->f.states & CMValid)) {
+    if (tvc->mvid.target_root && (tvc->f.states & CMValid)) {
        if (!canblock) {
            afs_int32 retry;
 
            do {
                retry = 0;
                ObtainWriteLock(&afs_xvcache, 597);
-               root_vp = afs_FindVCache(tvc->mvid, &retry, IS_WLOCK);
+               root_vp = afs_FindVCache(tvc->mvid.target_root, &retry, IS_WLOCK);
                if (root_vp && retry) {
                    ReleaseWriteLock(&afs_xvcache);
                    afs_PutVCache(root_vp);
@@ -408,7 +408,7 @@ afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
            } while (root_vp && retry);
            ReleaseWriteLock(&afs_xvcache);
        } else {
-           root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL);
+           root_vp = afs_GetVCache(tvc->mvid.target_root, areq, NULL, NULL);
        }
        if (!root_vp) {
            code = canblock ? ENOENT : 0;
@@ -427,9 +427,9 @@ afs_EvalFakeStat_int(struct vcache **avcp, struct afs_fakestat_state *state,
             * NBObtainWriteLock to avoid potential deadlock.
             */
            ObtainWriteLock(&root_vp->lock, 598);
-           if (!root_vp->mvid)
-               root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
-           *root_vp->mvid = tvolp->dotdot;
+           if (!root_vp->mvid.parent)
+               root_vp->mvid.parent = osi_AllocSmallSpace(sizeof(struct VenusFid));
+           *root_vp->mvid.parent = tvolp->dotdot;
            ReleaseWriteLock(&root_vp->lock);
        }
        state->need_release = 1;
@@ -861,7 +861,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
                    else
                        tvcp->f.m.Type = VREG;
                    /* finalize to a best guess */
-                   afs_darwin_finalizevnode(tvcp, VTOAFS(adp), NULL, 0, 1);
+                   afs_darwin_finalizevnode(tvcp, AFSTOV(adp), NULL, 0, 1);
                    /* re-acquire usecount that finalizevnode disposed of */
                    vnode_ref(AFSTOV(tvcp));
 #endif
@@ -1012,11 +1012,6 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
                        RXAFS_BulkStatus(rxconn, &fidParm, &statParm,
                                         &cbParm, &volSync);
                    RX_AFS_GLOCK();
-               } 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 {
                RX_AFS_GUNLOCK();
@@ -1032,8 +1027,13 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
            }
        } else
            code = -1;
+       /* make sure we give afs_Analyze a chance to retry,
+        * but if the RPC succeeded we may have entries to merge.
+        * if we wipe code with one entry's status we get bogus failures.
+        */
     } while (afs_Analyze
-            (tcp, rxconn, code, &adp->f.fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
+            (tcp, rxconn, code ? code : (&statsp[0])->errorCode,
+             &adp->f.fid, areqp, AFS_STATS_FS_RPCIDX_BULKSTATUS,
              SHARED_LOCK, NULL));
 
     /* now, if we didnt get the info, bail out. */
@@ -1168,10 +1168,10 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        }
 
        /* now copy ".." entry back out of volume structure, if necessary */
-       if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
-           if (!tvcp->mvid)
-               tvcp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
-           *tvcp->mvid = dotdot;
+       if (tvcp->mvstat == AFS_MVSTAT_ROOT && (dotdot.Fid.Volume != 0)) {
+           if (!tvcp->mvid.parent)
+               tvcp->mvid.parent = osi_AllocSmallSpace(sizeof(struct VenusFid));
+           *tvcp->mvid.parent = dotdot;
        }
 
 #ifdef AFS_DARWIN80_ENV
@@ -1373,7 +1373,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
 afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acred)
 #endif
 {
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     char *tname = NULL;
     struct vcache *tvc = 0;
     afs_int32 code;
@@ -1381,7 +1381,6 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
     int pass = 0, hit = 0;
     int force_eval = afs_fakestat_enable ? 0 : 1;
     long dirCookie;
-    extern afs_int32 afs_mariner;      /*Writing activity to log? */
     afs_hyper_t versionNo;
     int no_read_access = 0;
     struct sysname_info sysState;      /* used only for @sys checking */
@@ -1394,11 +1393,11 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
     afs_InitFakeStat(&fakestate);
 
     AFS_DISCON_LOCK();
-    
-    if ((code = afs_InitReq(&treq, acred)))
+
+    if ((code = afs_CreateReq(&treq, acred)))
        goto done;
 
-    if (afs_fakestat_enable && adp->mvstat == 1) {
+    if (afs_fakestat_enable && adp->mvstat == AFS_MVSTAT_MTPT) {
        if (strcmp(aname, ".directory") == 0)
            tryEvalOnly = 1;
     }
@@ -1407,57 +1406,54 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
     /* Workaround for MacOSX Finder, which tries to look for
      * .DS_Store and Contents under every directory.
      */
-    if (afs_fakestat_enable && adp->mvstat == 1) {
+    if (afs_fakestat_enable && adp->mvstat == AFS_MVSTAT_MTPT) {
        if (strcmp(aname, ".DS_Store") == 0)
            tryEvalOnly = 1;
        if (strcmp(aname, "Contents") == 0)
            tryEvalOnly = 1;
     }
-    if (afs_fakestat_enable && adp->mvstat == 2) {
+    if (afs_fakestat_enable && adp->mvstat == AFS_MVSTAT_ROOT) {
        if (strncmp(aname, "._", 2) == 0)
            tryEvalOnly = 1;
     }
 #endif
 
     if (tryEvalOnly)
-       code = afs_TryEvalFakeStat(&adp, &fakestate, &treq);
+       code = afs_TryEvalFakeStat(&adp, &fakestate, treq);
     else
-       code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+       code = afs_EvalFakeStat(&adp, &fakestate, treq);
 
     /*printf("Code is %d\n", code);*/
     
-    if (tryEvalOnly && adp->mvstat == 1)
+    if (tryEvalOnly && adp->mvstat == AFS_MVSTAT_MTPT)
        code = ENOENT;
     if (code)
        goto done;
 
-    *avcp = NULL;              /* Since some callers don't initialize it */
-
     /* come back to here if we encounter a non-existent object in a read-only
      * volume's directory */
-
   redo:
     *avcp = NULL;              /* Since some callers don't initialize it */
     bulkcode = 0;
 
     if (!(adp->f.states & CStatd) && !afs_InReadDir(adp)) {
-       if ((code = afs_VerifyVCache2(adp, &treq))) {
+       if ((code = afs_VerifyVCache2(adp, treq))) {
            goto done;
        }
     } else
        code = 0;
 
     /* watch for ".." in a volume root */
-    if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
+    if (adp->mvstat == AFS_MVSTAT_ROOT && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
        /* looking up ".." in root via special hacks */
-       if (adp->mvid == (struct VenusFid *)0 || adp->mvid->Fid.Volume == 0) {
+       if (adp->mvid.parent == (struct VenusFid *)0 || adp->mvid.parent->Fid.Volume == 0) {
            code = ENODEV;
            goto done;
        }
        /* otherwise we have the fid here, so we use it */
        /*printf("Getting vcache\n");*/
-       tvc = afs_GetVCache(adp->mvid, &treq, NULL, NULL);
-       afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT, ICL_TYPE_FID, adp->mvid,
+       tvc = afs_GetVCache(adp->mvid.parent, treq, NULL, NULL);
+       afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT, ICL_TYPE_FID, adp->mvid.parent,
                   ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, code);
        *avcp = tvc;
        code = (tvc ? 0 : ENOENT);
@@ -1472,18 +1468,18 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
     }
 
     /* now check the access */
-    if (treq.uid != adp->last_looker) {
-       if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
+    if (treq->uid != adp->last_looker) {
+       if (!afs_AccessOK(adp, PRSFS_LOOKUP, treq, CHECK_MODE_BITS)) {
            *avcp = NULL;
            code = EACCES;
            goto done;
        } else
-           adp->last_looker = treq.uid;
+           adp->last_looker = treq->uid;
     }
 
     /* 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_READ, treq, CHECK_MODE_BITS))
        no_read_access = 1;
 
     /* special case lookup of ".".  Can we check for it sooner in this code,
@@ -1536,7 +1532,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
        struct VenusFid tfid;
        afs_uint32 cellidx, volid, vnoid, uniq;
 
-       code = EvalMountData('%', aname, 0, 0, NULL, &treq, &cellidx, &volid, &vnoid, &uniq);
+       code = EvalMountData('%', aname, 0, 0, NULL, treq, &cellidx, &volid, &vnoid, &uniq);
        if (code)
            goto done;
        /* If a vnode was returned, it's not a real mount point */
@@ -1552,7 +1548,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
            tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
            tfid.Fid.Unique = volid;
        }
-       *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
+       *avcp = tvc = afs_GetVCache(&tfid, treq, NULL, NULL);
        code = (tvc ? 0 : ENOENT);
        hit = 1;
        goto done;
@@ -1568,14 +1564,14 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
        struct VenusFid tfid;
 
        afs_GetDynrootMountFid(&tfid);
-       *avcp = tvc = afs_GetVCache(&tfid, &treq, NULL, NULL);
+       *avcp = tvc = afs_GetVCache(&tfid, treq, NULL, NULL);
        code = 0;
        hit = 1;
        goto done;
     }
 #endif
 
-    Check_AtSys(adp, aname, &sysState, &treq);
+    Check_AtSys(adp, aname, &sysState, treq);
     tname = sysState.name;
 
     /* 1st Check_AtSys and lookup by tname is required here, for now,
@@ -1596,7 +1592,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
            goto done;
        }
 #ifdef AFS_LINUX22_ENV
-       if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
+       if (tvc->mvstat == AFS_MVSTAT_ROOT) {   /* we don't trust the dnlc for root vcaches */
            AFS_RELE(AFSTOV(tvc));
            *avcp = 0;
        } else {
@@ -1620,7 +1616,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
        if (afs_InReadDir(adp))
            tdc = adp->dcreaddir;
        else
-           tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq,
+           tdc = afs_GetDCache(adp, (afs_size_t) 0, treq,
                                &dirOffset, &dirLen, 1);
        if (!tdc) {
            *avcp = NULL;       /* redundant, but harmless */
@@ -1685,7 +1681,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
                                 &dirCookie);
 
        /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
-       while (code == ENOENT && Next_AtSys(adp, &treq, &sysState))
+       while (code == ENOENT && Next_AtSys(adp, treq, &sysState))
            code =
                afs_dir_LookupOffset(tdc, sysState.name, &tfid.Fid,
                                     &dirCookie);
@@ -1754,7 +1750,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
            } while (tvc && retry);
 
            if (!tvc || !(tvc->f.states & CStatd))
-               bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
+               bulkcode = afs_DoBulkStat(adp, dirCookie, treq);
            else
                bulkcode = 0;
 
@@ -1778,10 +1774,10 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
        if (!tvc) {
            afs_int32 cached = 0;
            if (!tfid.Fid.Unique && (adp->f.states & CForeign)) {
-               tvc = afs_LookupVCache(&tfid, &treq, &cached, adp, tname);
+               tvc = afs_LookupVCache(&tfid, treq, &cached, adp, tname);
            }
            if (!tvc && !bulkcode) {    /* lookup failed or wasn't called */
-               tvc = afs_GetVCache(&tfid, &treq, &cached, NULL);
+               tvc = afs_GetVCache(&tfid, treq, &cached, NULL);
            }
        }                       /* if !tvc */
     }                          /* sub-block just to reduce stack usage */
@@ -1793,11 +1789,11 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
        tvc->f.parent.unique = adp->f.fid.Fid.Unique;
        tvc->f.states &= ~CBulkStat;
 
-       if (afs_fakestat_enable == 2 && tvc->mvstat == 1) {
+       if (afs_fakestat_enable == 2 && tvc->mvstat == AFS_MVSTAT_MTPT) {
            ObtainSharedLock(&tvc->lock, 680);
            if (!tvc->linkData) {
                UpgradeSToWLock(&tvc->lock, 681);
-               code = afs_HandleLink(tvc, &treq);
+               code = afs_HandleLink(tvc, treq);
                ConvertWToRLock(&tvc->lock);
            } else {
                ConvertSToRLock(&tvc->lock);
@@ -1807,19 +1803,19 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
                force_eval = 1;
            ReleaseReadLock(&tvc->lock);
        }
-       if (tvc->mvstat == 1 && (tvc->f.states & CMValid) && tvc->mvid != NULL)
+       if (tvc->mvstat == AFS_MVSTAT_MTPT && (tvc->f.states & CMValid) && tvc->mvid.target_root != NULL)
          force_eval = 1; /* This is now almost for free, get it correct */
 
 #if defined(UKERNEL)
        if (!(flags & AFS_LOOKUP_NOEVAL))
            /* don't eval mount points */
 #endif /* UKERNEL */
-           if (tvc->mvstat == 1 && force_eval) {
+           if (tvc->mvstat == AFS_MVSTAT_MTPT && force_eval) {
                /* a mt point, possibly unevaluated */
                struct volume *tvolp;
 
                ObtainWriteLock(&tvc->lock, 133);
-               code = EvalMountPoint(tvc, adp, &tvolp, &treq);
+               code = EvalMountPoint(tvc, adp, &tvolp, treq);
                ReleaseWriteLock(&tvc->lock);
 
                if (code) {
@@ -1830,7 +1826,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
                }
 
                /* next, we want to continue using the target of the mt point */
-               if (tvc->mvid && (tvc->f.states & CMValid)) {
+               if (tvc->mvid.target_root && (tvc->f.states & CMValid)) {
                    struct vcache *uvc;
                    /* now lookup target, to set .. pointer */
                    afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
@@ -1841,9 +1837,9 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
                    if (tvolp && (tvolp->states & VForeign)) {
                        /* XXXX tvolp has ref cnt on but not locked! XXX */
                        tvc =
-                           afs_GetRootVCache(tvc->mvid, &treq, NULL, tvolp);
+                           afs_GetRootVCache(tvc->mvid.target_root, treq, NULL, tvolp);
                    } else {
-                       tvc = afs_GetVCache(tvc->mvid, &treq, NULL, NULL);
+                       tvc = afs_GetVCache(tvc->mvid.target_root, treq, NULL, NULL);
                    }
                    afs_PutVCache(uvc); /* we're done with it */
 
@@ -1860,12 +1856,12 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
                     * ptr to point back to the appropriate place */
                    if (tvolp) {
                        ObtainWriteLock(&tvc->lock, 134);
-                       if (tvc->mvid == NULL) {
-                           tvc->mvid =
+                       if (tvc->mvid.parent == NULL) {
+                           tvc->mvid.parent =
                                osi_AllocSmallSpace(sizeof(struct VenusFid));
                        }
                        /* setup backpointer */
-                       *tvc->mvid = tvolp->dotdot;
+                       *tvc->mvid.parent = tvolp->dotdot;
                        ReleaseWriteLock(&tvc->lock);
                        afs_PutVolume(tvolp, WRITE_LOCK);
                    }
@@ -1890,7 +1886,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
        if (!AFS_IS_DISCONNECTED) {
            if (pass == 0) {
                struct volume *tv;
-               tv = afs_GetVolume(&adp->f.fid, &treq, READ_LOCK);
+               tv = afs_GetVolume(&adp->f.fid, treq, READ_LOCK);
                if (tv) {
                    if (tv->states & VRO) {
                        pass = 1;       /* try this *once* */
@@ -1928,14 +1924,15 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
             * volume) rather than the vc of the mount point itself.  We can
             * still find the mount point's vc in the vcache by its fid. */
 #endif /* UKERNEL */
-           if (!hit && force_eval) {
+           if (!hit && (force_eval || tvc->mvstat != AFS_MVSTAT_MTPT)) {
                osi_dnlc_enter(adp, aname, tvc, &versionNo);
            } else {
 #ifdef AFS_LINUX20_ENV
                /* So Linux inode cache is up to date. */
-               code = afs_VerifyVCache(tvc, &treq);
+               code = afs_VerifyVCache(tvc, treq);
 #else
                afs_PutFakeStat(&fakestate);
+               afs_DestroyReq(treq);
                AFS_DISCON_UNLOCK();
                return 0;       /* can't have been any errors if hit and !code */
 #endif
@@ -1947,7 +1944,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
     if (bulkcode)
        code = bulkcode;
 
-    code = afs_CheckCode(code, &treq, 19);
+    code = afs_CheckCode(code, treq, 19);
     if (code) {
        /* If there is an error, make sure *avcp is null.
         * Alphas panic otherwise - defect 10719.
@@ -1956,6 +1953,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
     }
 
     afs_PutFakeStat(&fakestate);
+    afs_DestroyReq(treq);
     AFS_DISCON_UNLOCK();
     return code;
 }