afs: Avoid non-dir ENOENT errors in afs_lookup
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index 08ad2af..2ca0969 100644 (file)
@@ -773,7 +773,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
      */
     while ((adp->f.states & CStatd)
           && (dcp->dflags & DFFetching)
-          && hsame(adp->f.m.DataVersion, dcp->f.versionNo)) {
+          && afs_IsDCacheFresh(dcp, adp)) {
        afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT, ICL_TYPE_STRING,
                   __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER, dcp,
                   ICL_TYPE_INT32, dcp->dflags);
@@ -784,7 +784,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        ObtainReadLock(&dcp->lock);
     }
     if (!(adp->f.states & CStatd)
-       || !hsame(adp->f.m.DataVersion, dcp->f.versionNo)) {
+       || !afs_IsDCacheFresh(dcp, adp)) {
        ReleaseReadLock(&dcp->lock);
        ReleaseReadLock(&adp->lock);
        afs_PutDCache(dcp);
@@ -1388,6 +1388,11 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
     int dynrootRetry = 1;
     struct afs_fakestat_state fakestate;
     int tryEvalOnly = 0;
+
+    /* Don't allow ENOENT errors, except for a specific code path where
+     * 'enoent_prohibited' is cleared below. */
+    int enoent_prohibited = 1;
+
     OSI_VC_CONVERT(adp);
 
     AFS_STATCNT(afs_lookup);
@@ -1643,7 +1648,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
        if (!afs_InReadDir(adp)) {
            while ((adp->f.states & CStatd)
                   && (tdc->dflags & DFFetching)
-                  && hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
+                  && afs_IsDCacheFresh(tdc, adp)) {
                ReleaseReadLock(&tdc->lock);
                ReleaseReadLock(&adp->lock);
                afs_osi_Sleep(&tdc->validPos);
@@ -1651,7 +1656,7 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
                ObtainReadLock(&tdc->lock);
            }
            if (!(adp->f.states & CStatd)
-               || !hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
+               || !afs_IsDCacheFresh(tdc, adp)) {
                ReleaseReadLock(&tdc->lock);
                ReleaseReadLock(&adp->lock);
                afs_PutDCache(tdc);
@@ -1727,8 +1732,10 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
                   ICL_TYPE_INT32, code);
 
        if (code) {
-           if (code != ENOENT) {
-               /*printf("LOOKUP dirLookupOff -> %d\n", code);*/
+           if (code == ENOENT) {
+               /* The target name really doesn't exist (according to
+                * afs_dir_LookupOffset, anyway). */
+               enoent_prohibited = 0;
            }
            goto done;
        }
@@ -1948,6 +1955,16 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr
         */
        *avcp = NULL;
     }
+    if (code == ENOENT && enoent_prohibited) {
+       /*
+        * We got an ENOENT error, but we didn't get it while looking up the
+        * dir entry in the relevant dir blob. That means we likely hit some
+        * other internal error; don't allow us to return ENOENT in this case,
+        * since some platforms cache ENOENT errors, and the target path name
+        * may actually exist.
+        */
+       code = EIO;
+    }
 
     afs_PutFakeStat(&fakestate);
     afs_DestroyReq(treq);