]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Windows: Add per object per user EACCES caching
authorJeffrey Altman <jaltman@your-file-system.com>
Sun, 1 Apr 2012 05:17:21 +0000 (01:17 -0400)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Fri, 6 Apr 2012 15:03:06 +0000 (08:03 -0700)
If a cache manager is told by a file server that the user does
not have permission to fetch status for an object, the cache
manager must avoid requesting a fetch status a second time for
that object for the same user.  Doing so risks triggering the
rx call abort throttling which can have a significant impact on
end user usability of the Explorer Shell and other applications.

The cache manager cannot make a decision on whether or not to
issue an RXAFS_FetchStatus RPC based upon the type of the object
because the type is unknown to the cache manager.  A file server
will succeed a FetchStatus request when the parent directory ACL
grants lookup permission if the object in question is the directory
or is a symlink/mountpoint.  Only file objects require read/write
permissions to obtain status information.

The rx call abort throttling is broken is many ways and must be
avoided.  Call aborts are tracked by call channel and occur whenever
ten call aborts are issued on the same call channel in a row
regardless of the amount of time that has elapsed.

The EACCES cache works by storing EACCES events by the FID and User
for which the event occurred, when it occurred and the FID of the
parent directory.  By definition, the parent FID of a volume root
directory is itself.

Entries are removed from the cache under the following circumstances:

 1. When the parent FID's callback expires or is replaced.

 2. When the parent FID's cm_scache object is recycled.

 3. When the user's tokens expire or are replaced.

Entries are not removed when the FID's cm_scache object is recycled.

This patchset also implements correct behavior if the VLF_DFSFILESET
flag is set on a volume.

Change-Id: I69507601f9872c9544e52a1d5e01064fa42efb81
Reviewed-on: http://gerrit.openafs.org/6996
Reviewed-by: Jeffrey Altman <jaltman@secure-endpoints.com>
Tested-by: Jeffrey Altman <jaltman@secure-endpoints.com>
19 files changed:
src/WINNT/afsd/NTMakefile
src/WINNT/afsd/afsd.h
src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/cm.h
src/WINNT/afsd/cm_access.c
src/WINNT/afsd/cm_aclent.c
src/WINNT/afsd/cm_btree.c
src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_daemon.c
src/WINNT/afsd/cm_eacces.c [new file with mode: 0644]
src/WINNT/afsd/cm_eacces.h [new file with mode: 0644]
src/WINNT/afsd/cm_scache.c
src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_user.c
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_vnodeops.h
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c
src/WINNT/afsrdr/user/RDRFunction.c

index 6d6646c12fbfd0b82236421bb3b43220203cd481..b9e4442d9f8fd6c9d1c3be0bf7cc238bfb7095ee 100644 (file)
@@ -60,6 +60,7 @@ INCFILES =\
         $(INCFILEDIR)\cm_volstat.h \
        $(INCFILEDIR)\cm_dcache.h \
        $(INCFILEDIR)\cm_access.h \
+       $(INCFILEDIR)\cm_eacces.h \
        $(INCFILEDIR)\cm_vnodeops.h \
        $(INCFILEDIR)\cm_dir.h \
        $(INCFILEDIR)\cm_utils.h \
@@ -129,6 +130,7 @@ AFSDOBJS=\
        $(OUT)\cm_scache.obj \
        $(OUT)\cm_dcache.obj \
        $(OUT)\cm_access.obj \
+       $(OUT)\cm_eacces.obj \
        $(OUT)\cm_callback.obj \
        $(OUT)\cm_vnodeops.obj \
        $(OUT)\cm_dir.obj \
index 65f2d18117de5b7b3a455fc4060c51c051707d7f..feabae28e48d763d65596f9fec5ba3756872f8fe 100644 (file)
@@ -48,6 +48,7 @@ BOOL APIENTRY About(HWND, unsigned int, unsigned int, long);
 #include "cm_volume.h"
 #include "cm_dcache.h"
 #include "cm_access.h"
+#include "cm_eacces.h"
 #include "cm_dir.h"
 #include "cm_utils.h"
 #include "cm_vnodeops.h"
index 72bf229d566f7391e5bed245fa777f83b0a42ae3..ba25a408afb15cc579cc1940a8748f32ad38d6ec 100644 (file)
@@ -1407,6 +1407,9 @@ afsd_InitCM(char **reasonP)
         return -1;
     }
 
+    /* Must be called after cm_InitMappedMemory. */
+    cm_EAccesInitCache();
+
 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
     if (cm_InitDNS(cm_dnsEnabled) == -1)
         cm_dnsEnabled = 0;  /* init failed, so deactivate */
index 5d9f29387d4f613db26356d9b78aaf348b35929b..e1711ad8a492d333d2e849014de5223d60251e88 100644 (file)
@@ -82,6 +82,7 @@
 #define LOCK_HIERARCHY_OTHER_GLOBAL            720
 #define LOCK_HIERARCHY_ACL_GLOBAL              730
 #define LOCK_HIERARCHY_USER_GLOBAL             740
+#define LOCK_HIERARCHY_EACCES_GLOBAL           750
 #define LOCK_HIERARCHY_AFSDBSBMT_GLOBAL       1000
 #define LOCK_HIERARCHY_TOKEN_EVENT_GLOBAL     2000
 #define LOCK_HIERARCHY_SYSCFG_GLOBAL          3000
index 79692b1e2fc362fa907ee275bb51a7c1c2399655..17c6c7c8067f3ef0fe1d4767aa44df6c2b9c5add 100644 (file)
@@ -38,37 +38,41 @@ int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, cm_req_t *
                         afs_uint32 *outRightsp)
 {
     cm_scache_t *aclScp;
-    long code;
+    long code = 0;
     cm_fid_t tfid;
     int didLock;
     long trights;
     int release = 0;    /* Used to avoid a call to cm_HoldSCache in the directory case */
+    cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
 
     didLock = 0;
-    if (scp->fileType == CM_SCACHETYPE_DIRECTORY || cm_accessPerFileCheck) {
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+        cm_accessPerFileCheck ||
+        !volp || (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME)) {
         aclScp = scp;   /* not held, not released */
     } else {
         cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
         aclScp = cm_FindSCache(&tfid);
-        if (!aclScp)
-            return 0;
+        if (!aclScp) {
+            code = 0;
+            goto done;
+        }
+        release = 1;
         if (aclScp != scp) {
             if (aclScp->fid.vnode < scp->fid.vnode)
                 lock_ReleaseWrite(&scp->rw);
             lock_ObtainRead(&aclScp->rw);
+           didLock = 1;
             if (aclScp->fid.vnode < scp->fid.vnode)
                 lock_ObtainWrite(&scp->rw);
 
-           /* check that we have a callback, too */
+            /* check that we have a callback, too */
             if (!cm_HaveCallback(aclScp)) {
                 /* can't use it */
-                lock_ReleaseRead(&aclScp->rw);
-                cm_ReleaseSCache(aclScp);
-                return 0;
+                code = 0;
+                goto done;
             }
-            didLock = 1;
         }
-        release = 1;
     }
 
     lock_AssertAny(&aclScp->rw);
@@ -133,6 +137,8 @@ int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, cm_req_t *
     /* fall through */
 
   done:
+    if (volp)
+        cm_PutVolume(volp);
     if (didLock)
         lock_ReleaseRead(&aclScp->rw);
     if (release)
@@ -154,6 +160,7 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
     cm_fid_t tfid;
     cm_scache_t *aclScp = NULL;
     int got_cb = 0;
+    cm_volume_t * volp = cm_GetVolumeByFID(&scp->fid);
 
     /* pretty easy: just force a pass through the fetch status code */
 
@@ -162,13 +169,16 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
     /* first, start by finding out whether we have a directory or something
      * else, so we can find what object's ACL we need.
      */
-    if (scp->fileType == CM_SCACHETYPE_DIRECTORY || cm_accessPerFileCheck) {
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+        cm_accessPerFileCheck ||
+        !volp || (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME))
+    {
        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
        if (!code)
            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    else
-        osi_Log3(afsd_logp, "GetAccessRights syncop failure scp %x user %x code %x", scp, userp, code);
+        else
+            osi_Log3(afsd_logp, "GetAccessRights syncop failure scp %x user %x code %x", scp, userp, code);
     } else {
         /* not a dir, use parent dir's acl */
         cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
@@ -194,5 +204,7 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
     }
 
   _done:
+    if (volp)
+        cm_PutVolume(volp);
     return code;
 }
index b9f06fc183d7db1b9ee27cec69815da68c52798e..3c01da5cd3d70eab67dcd2ef91402b9d86d9d735 100644 (file)
@@ -404,6 +404,8 @@ cm_ResetACLCache(cm_cell_t *cellp, cm_user_t *userp)
     }
     lock_ReleaseRead(&cm_scacheLock);
 
+    cm_EAccesClearUserEntries(userp, cellp->cellID);
+
     if (RDR_Initialized) {
         lock_ObtainRead(&cm_volumeLock);
         for (hash = 0; hash < cm_data.volumeHashTableSize; hash++) {
index eb5cbc50087b1f7d9894bb96034abc714cf75838..4f7048d3ae652b098dd66ab295968b189c2af070 100644 (file)
@@ -2362,6 +2362,7 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
         goto done;
     }
     memset(bsp, 0, sizeof(cm_bulkStat_t));
+    bsp->userp = userp;
 
     bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
     if (!bs_errorCodep) {
@@ -2390,7 +2391,7 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
         if (tscp) {
             if (lock_TryWrite(&tscp->rw)) {
                 /* we have an entry that we can look at */
-                if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
                     /* we have a callback on it.  Don't bother
                      * fetching this stat entry, since we're happy
                      * with the info we have.
@@ -2427,6 +2428,8 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
                 goto done;
             }
             memset(bsp, 0, sizeof(cm_bulkStat_t));
+            bsp->userp = userp;
+
             /*
              * In order to prevent the directory callback from expiring
              * on really large directories with many symlinks to mount
@@ -2497,6 +2500,7 @@ cm_BPlusDirEnumBulkStatOne(cm_direnum_t *enump, cm_scache_t *scp)
         goto done;
     }
     memset(bsp, 0, sizeof(cm_bulkStat_t));
+    bsp->userp = userp;
 
     bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
     if (!bs_errorCodep) {
@@ -2553,7 +2557,7 @@ cm_BPlusDirEnumBulkStatOne(cm_direnum_t *enump, cm_scache_t *scp)
 
             if (lock_TryWrite(&tscp->rw)) {
                 /* we have an entry that we can look at */
-                if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
                     /* we have a callback on it.  Don't bother
                      * fetching this stat entry, since we're happy
                      * with the info we have.
@@ -2629,6 +2633,7 @@ cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
         goto done;
     }
     memset(bsp, 0, sizeof(cm_bulkStat_t));
+    bsp->userp = userp;
 
     bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
     if (!bs_errorCodep) {
@@ -2657,7 +2662,7 @@ cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
         if (tscp) {
             if (lock_TryWrite(&tscp->rw)) {
                 /* we have an entry that we can look at */
-                if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
                     /* we have a callback on it.  Don't bother
                      * fetching this stat entry, since we're happy
                      * with the info we have.
index 5c326c427979bea21981935a6e5002c9c881edf1..9604ac1a127ed41c437f17e76ba690970eaf77c4 100644 (file)
@@ -2054,6 +2054,11 @@ void cm_CheckCBExpiration(void)
 
             cm_CallbackNotifyChange(scp);
 
+            if (scp->fileType == CM_SCACHETYPE_DIRECTORY &&
+                !(volp && (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME)) &&
+                !cm_accessPerFileCheck)
+                cm_EAccesClearParentEntries(&scp->fid);
+
           scp_complete:
             if (volp)
                 cm_PutVolume(volp);
index 2e5ef84f355e063aae421be72e38014f630b2ccc..597a266fac60b0350638b8e4d3e43ea0c9962001 100644 (file)
@@ -42,6 +42,7 @@ long cm_daemonPerformanceTuningInterval = 0;
 long cm_daemonRankServerInterval = 600;
 long cm_daemonRDRShakeExtentsInterval = 0;
 long cm_daemonAfsdHookReloadInterval = 0;
+long cm_daemonEAccesCheckInterval = 1800;
 
 osi_rwlock_t *cm_daemonLockp;
 afs_uint64 *cm_bkgQueueCountp;         /* # of queued requests */
@@ -505,6 +506,7 @@ void * cm_Daemon(void *vparm)
     time_t lastServerRankCheck;
     time_t lastRDRShakeExtents;
     time_t lastAfsdHookReload;
+    time_t lastEAccesCheck;
     char thostName[200];
     unsigned long code;
     struct hostent *thp;
@@ -564,6 +566,7 @@ void * cm_Daemon(void *vparm)
         lastRDRShakeExtents = now - cm_daemonRDRShakeExtentsInterval/2 * (rand() % cm_daemonRDRShakeExtentsInterval);
     if (cm_daemonAfsdHookReloadInterval)
         lastAfsdHookReload = now;
+    lastEAccesCheck = now;
 
     hHookDll = cm_LoadAfsdHookLib();
     if (hHookDll)
@@ -720,6 +723,16 @@ void * cm_Daemon(void *vparm)
            now = osi_Time();
         }
 
+        if (now > lastEAccesCheck + cm_daemonEAccesCheckInterval &&
+             daemon_ShutdownFlag == 0 &&
+             powerStateSuspended == 0) {
+            lastEAccesCheck = now;
+            cm_EAccesClearOutdatedEntries();
+            if (daemon_ShutdownFlag == 1)
+                break;
+           now = osi_Time();
+        }
+
         if (cm_daemonRDRShakeExtentsInterval &&
             now > lastRDRShakeExtents + cm_daemonRDRShakeExtentsInterval &&
             daemon_ShutdownFlag == 0 &&
diff --git a/src/WINNT/afsd/cm_eacces.c b/src/WINNT/afsd/cm_eacces.c
new file mode 100644 (file)
index 0000000..603a4c8
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2012 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <roken.h>
+
+#include "afsd.h"
+
+static osi_rwlock_t cm_eaccesLock;
+
+static struct osi_queue ** cm_eaccesFidHashTableH = NULL;
+static struct osi_queue ** cm_eaccesParentHashTableH = NULL;
+static struct osi_queue ** cm_eaccesUserHashTableH = NULL;
+
+static struct osi_queue ** cm_eaccesFidHashTableT = NULL;
+static struct osi_queue ** cm_eaccesParentHashTableT = NULL;
+static struct osi_queue ** cm_eaccesUserHashTableT = NULL;
+
+static afs_uint32 cm_eaccesFidHashTableSize = 0;
+static afs_uint32 cm_eaccesParentHashTableSize = 0;
+static afs_uint32 cm_eaccesUserHashTableSize = 0;
+
+static struct osi_queue * cm_eaccesFreeListH = NULL;
+
+void
+cm_EAccesInitCache(void)
+{
+    static osi_once_t once;
+
+    if (osi_Once(&once)) {
+        lock_InitializeRWLock(&cm_eaccesLock, "cm_eaccesLock", LOCK_HIERARCHY_EACCES_GLOBAL);
+        osi_EndOnce(&once);
+    }
+
+    lock_ObtainWrite(&cm_eaccesLock);
+    cm_eaccesFidHashTableSize = cm_data.stats * 2;
+    cm_eaccesParentHashTableSize = cm_data.stats * 2;
+    cm_eaccesUserHashTableSize = 32;
+
+    cm_eaccesFidHashTableH = malloc(cm_eaccesFidHashTableSize * sizeof(struct osi_queue *));
+    memset(cm_eaccesFidHashTableH, 0, cm_eaccesFidHashTableSize * sizeof(struct osi_queue *));
+    cm_eaccesFidHashTableT = malloc(cm_eaccesFidHashTableSize * sizeof(struct osi_queue *));
+    memset(cm_eaccesFidHashTableT, 0, cm_eaccesFidHashTableSize * sizeof(struct osi_queue *));
+
+    cm_eaccesParentHashTableH = malloc(cm_eaccesParentHashTableSize * sizeof(struct osi_queue *));
+    memset(cm_eaccesParentHashTableH, 0, cm_eaccesParentHashTableSize * sizeof(struct osi_queue *));
+    cm_eaccesParentHashTableT = malloc(cm_eaccesParentHashTableSize * sizeof(struct osi_queue *));
+    memset(cm_eaccesParentHashTableT, 0, cm_eaccesParentHashTableSize * sizeof(struct osi_queue *));
+
+    cm_eaccesUserHashTableH = malloc(cm_eaccesUserHashTableSize * sizeof(struct osi_queue *));
+    memset(cm_eaccesUserHashTableH, 0, cm_eaccesUserHashTableSize * sizeof(struct osi_queue *));
+    cm_eaccesUserHashTableT = malloc(cm_eaccesUserHashTableSize * sizeof(struct osi_queue *));
+    memset(cm_eaccesUserHashTableT, 0, cm_eaccesUserHashTableSize * sizeof(struct osi_queue *));
+
+    lock_ReleaseWrite(&cm_eaccesLock);
+}
+
+afs_uint32
+cm_EAccesAddEntry(cm_user_t* userp, cm_fid_t *fidp, cm_fid_t *parentFidp)
+{
+    cm_eacces_t *eaccesp = NULL;
+    afs_uint32   hash;
+    int          newEntry = 0;
+
+    hash = CM_EACCES_FID_HASH(fidp);
+
+    lock_ObtainWrite(&cm_eaccesLock);
+    for (eaccesp = (cm_eacces_t *)cm_eaccesFidHashTableH[hash];
+         eaccesp;
+         eaccesp = (cm_eacces_t *)osi_QNext(&eaccesp->q))
+    {
+        if (eaccesp->userp == userp &&
+            !cm_FidCmp(&eaccesp->fid, fidp))
+            break;
+    }
+
+    if (eaccesp == NULL) {
+        if (osi_QIsEmpty(&cm_eaccesFreeListH)) {
+            eaccesp = malloc(sizeof(cm_eacces_t));
+        } else {
+            eaccesp = (cm_eacces_t *)cm_eaccesFreeListH;
+            osi_QRemove(&cm_eaccesFreeListH, &eaccesp->q);
+        }
+
+        memset(eaccesp, 0, sizeof(cm_eacces_t));
+        eaccesp->magic = CM_EACCES_MAGIC;
+        eaccesp->fid = *fidp;
+        eaccesp->userp = userp;
+        cm_HoldUser(userp);
+
+        osi_QAddH( &cm_eaccesFidHashTableH[hash],
+                   &cm_eaccesFidHashTableT[hash],
+                   &eaccesp->q);
+
+        hash = CM_EACCES_USER_HASH(userp);
+        osi_QAddH( &cm_eaccesUserHashTableH[hash],
+                   &cm_eaccesUserHashTableT[hash],
+                   &eaccesp->userq);
+
+        newEntry = 1;
+    }
+
+    if (eaccesp) {
+        eaccesp->errorTime = time(NULL);
+
+        if (!newEntry &&
+            !cm_FidCmp(parentFidp, &eaccesp->parentFid))
+        {
+            hash = CM_EACCES_PARENT_HASH(&eaccesp->parentFid);
+            osi_QRemoveHT( &cm_eaccesParentHashTableH[hash],
+                           &cm_eaccesParentHashTableT[hash],
+                           &eaccesp->parentq);
+        }
+
+        eaccesp->parentFid = *parentFidp;
+        hash = CM_EACCES_PARENT_HASH(&eaccesp->parentFid);
+        osi_QAddH( &cm_eaccesParentHashTableH[hash],
+                  &cm_eaccesParentHashTableT[hash],
+                  &eaccesp->parentq);
+    }
+    lock_ReleaseWrite(&cm_eaccesLock);
+
+    return 0;
+}
+
+cm_eacces_t *
+cm_EAccesFindEntry(cm_user_t* userp, cm_fid_t *fidp)
+{
+    cm_eacces_t *eaccesp = NULL;
+    afs_uint32   hash;
+
+    hash = CM_EACCES_FID_HASH(fidp);
+
+    lock_ObtainRead(&cm_eaccesLock);
+    for (eaccesp = (cm_eacces_t *)cm_eaccesFidHashTableH[hash];
+         eaccesp;
+         eaccesp = (cm_eacces_t *)osi_QNext(&eaccesp->q))
+    {
+        if (eaccesp->userp == userp &&
+            !cm_FidCmp(&eaccesp->fid, fidp))
+            break;
+    }
+    lock_ReleaseRead(&cm_eaccesLock);
+
+    return eaccesp;
+}
+
+void
+cm_EAccesClearParentEntries(cm_fid_t *parentFidp)
+{
+    cm_eacces_t *eaccesp = NULL;
+    cm_eacces_t *nextp = NULL;
+    afs_uint32   hash, hash2;
+
+    hash = CM_EACCES_PARENT_HASH(parentFidp);
+
+    lock_ObtainRead(&cm_eaccesLock);
+    for (eaccesp = parentq_to_cm_eacces_t(cm_eaccesParentHashTableH[hash]);
+         eaccesp;
+         eaccesp = nextp)
+    {
+        nextp = parentq_to_cm_eacces_t(osi_QNext(&eaccesp->parentq));
+
+        if (!cm_FidCmp(&eaccesp->parentFid, parentFidp))
+        {
+            osi_QRemoveHT( &cm_eaccesParentHashTableH[hash],
+                           &cm_eaccesParentHashTableT[hash],
+                           &eaccesp->parentq);
+
+            hash2 = CM_EACCES_FID_HASH(&eaccesp->fid);
+            osi_QRemoveHT( &cm_eaccesFidHashTableH[hash2],
+                           &cm_eaccesFidHashTableT[hash2],
+                           &eaccesp->q);
+
+            hash2 = CM_EACCES_USER_HASH(eaccesp->userp);
+            osi_QRemoveHT( &cm_eaccesUserHashTableH[hash2],
+                           &cm_eaccesUserHashTableT[hash2],
+                           &eaccesp->userq);
+
+            cm_ReleaseUser(eaccesp->userp);
+            osi_QAdd( &cm_eaccesFreeListH, &eaccesp->q);
+        }
+    }
+    lock_ReleaseRead(&cm_eaccesLock);
+}
+
+void
+cm_EAccesClearUserEntries(cm_user_t *userp, afs_uint32 cellID)
+{
+    cm_eacces_t *eaccesp = NULL;
+    cm_eacces_t *nextp = NULL;
+    afs_uint32   hash, hash2;
+
+    hash = CM_EACCES_USER_HASH(userp);
+
+    lock_ObtainRead(&cm_eaccesLock);
+    for (eaccesp = userq_to_cm_eacces_t(cm_eaccesUserHashTableH[hash]);
+         eaccesp;
+         eaccesp = nextp)
+    {
+        nextp = userq_to_cm_eacces_t(osi_QNext(&eaccesp->userq));
+
+        if (eaccesp->userp == userp &&
+            (cellID == 0 || eaccesp->fid.cell == cellID))
+        {
+            cm_ReleaseUser(userp);
+            osi_QRemoveHT( &cm_eaccesUserHashTableH[hash],
+                           &cm_eaccesUserHashTableT[hash],
+                           &eaccesp->userq);
+
+            hash2 = CM_EACCES_FID_HASH(&eaccesp->fid);
+            osi_QRemoveHT( &cm_eaccesFidHashTableH[hash2],
+                           &cm_eaccesFidHashTableT[hash2],
+                           &eaccesp->q);
+
+            hash2 = CM_EACCES_PARENT_HASH(&eaccesp->parentFid);
+            osi_QRemoveHT( &cm_eaccesParentHashTableH[hash2],
+                           &cm_eaccesParentHashTableT[hash2],
+                           &eaccesp->parentq);
+
+            osi_QAdd( &cm_eaccesFreeListH, &eaccesp->q);
+        }
+    }
+    lock_ReleaseRead(&cm_eaccesLock);
+}
+
+void
+cm_EAccesClearOutdatedEntries(void)
+{
+    cm_eacces_t *eaccesp = NULL;
+    cm_eacces_t *nextp = NULL;
+    afs_uint32   hash, hash2;
+    time_t       now = time(NULL);
+
+    lock_ObtainRead(&cm_eaccesLock);
+    for (hash = 0; hash < cm_eaccesFidHashTableSize; hash++)
+    {
+        for (eaccesp = (cm_eacces_t *)(cm_eaccesFidHashTableH[hash]);
+              eaccesp;
+              eaccesp = nextp)
+        {
+            nextp = (cm_eacces_t *)(osi_QNext(&eaccesp->q));
+
+            if (eaccesp->errorTime + 4*60*60 < now)
+            {
+                osi_QRemoveHT( &cm_eaccesFidHashTableH[hash],
+                               &cm_eaccesFidHashTableT[hash],
+                               &eaccesp->q);
+
+                hash2 = CM_EACCES_USER_HASH(eaccesp->userp);
+                osi_QRemoveHT( &cm_eaccesUserHashTableH[hash2],
+                               &cm_eaccesUserHashTableT[hash2],
+                               &eaccesp->userq);
+                cm_ReleaseUser(eaccesp->userp);
+
+                hash2 = CM_EACCES_PARENT_HASH(&eaccesp->parentFid);
+                osi_QRemoveHT( &cm_eaccesParentHashTableH[hash2],
+                               &cm_eaccesParentHashTableT[hash2],
+                               &eaccesp->parentq);
+
+                osi_QAdd( &cm_eaccesFreeListH, &eaccesp->q);
+            }
+        }
+    }
+    lock_ReleaseRead(&cm_eaccesLock);
+}
diff --git a/src/WINNT/afsd/cm_eacces.h b/src/WINNT/afsd/cm_eacces.h
new file mode 100644 (file)
index 0000000..481b5b2
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012 Your File System, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software without
+ *   specific prior written permission from Secure Endpoints, Inc. and
+ *   Your File System, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CM_EACCES_H_
+#define _CM_EACCES_H_
+
+#include <osi.h>
+#include "cm_scache.h"
+
+#define CM_EACCES_MAGIC    ('E' | 'A' <<8 | 'C'<<16 | 'C'<<24)
+
+/*
+ * Structure to hold EACCES error info for FID,User pairs
+ */
+
+typedef struct cm_eacces {
+    struct osi_queue q;        /* fid hash table or free list */
+    afs_uint32  magic;
+    struct osi_queue parentq;
+    struct osi_queue userq;
+    cm_fid_t    fid;
+    cm_fid_t    parentFid;
+    cm_user_t  *userp;
+    time_t      errorTime;
+} cm_eacces_t;
+
+#define parentq_to_cm_eacces_t(q) ((q) ? (cm_eacces_t *)((char *) (q) - offsetof(cm_eacces_t, parentq)) : NULL)
+#define userq_to_cm_eacces_t(q) ((q) ? (cm_eacces_t *)((char *) (q) - offsetof(cm_eacces_t, userq)) : NULL)
+
+#define CM_EACCES_FID_HASH(fidp) (opr_jhash(&(fidp)->cell, 4, 0) & (cm_eaccesFidHashTableSize - 1))
+
+#define CM_EACCES_PARENT_HASH(fidp) (opr_jhash(&(fidp)->cell, 4, 0) & (cm_eaccesParentHashTableSize - 1))
+
+#define CM_EACCES_USER_HASH(userp) (opr_jhash((const uint32_t *)&userp, sizeof(cm_user_t *)/4, 0) & (cm_eaccesUserHashTableSize - 1))
+
+extern void cm_EAccesInitCache(void);
+
+extern cm_eacces_t * cm_EAccesFindEntry(cm_user_t* userp, cm_fid_t *fidp);
+
+extern afs_uint32 cm_EAccesAddEntry(cm_user_t* userp, cm_fid_t *fidp, cm_fid_t *parentFidp);
+
+extern void cm_EAccesClearParentEntries(cm_fid_t *parentFip);
+
+extern void cm_EAccesClearUserEntries(cm_user_t *userp, afs_uint32 CellID);
+
+extern void cm_EAccesClearOutdatedEntries(void);
+
+
+/*
+ * The EACCES cache works by storing EACCES events by the FID and User
+ * for which the event occurred, when it occurred and the FID of the parent
+ * directory.  By definition, the parent FID of a volume root directory
+ * is itself.
+ *
+ * Entries are removed from the cache under the following circumstances:
+ *  1. When the parent FID's callback expires or is replaced.
+ *  2. When the parent FID's cm_scache object is recycled.
+ *  3. When the user's tokens expire or are replaced.
+ *
+ * Entries are not removed when the FID's cm_scache object is recycled.
+ */
+#endif /* _CM_EACCES_H_ */
index b94f80f76cde8ee84ac81c64f6cd2f20a4fbe1d1..9b65daef3c224542813d518709046f7aeb180c21 100644 (file)
@@ -151,7 +151,6 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
        return -1;
     }
 
-
     if (scp->flags & CM_SCACHEFLAG_SMB_FID) {
        osi_Log1(afsd_logp,"cm_RecycleSCache CM_SCACHEFLAG_SMB_FID detected scp 0x%p", scp);
 #ifdef DEBUG
@@ -170,6 +169,15 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
 
     cm_RemoveSCacheFromHashTable(scp);
 
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY &&
+         !cm_accessPerFileCheck) {
+        cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
+
+        if (!(volp && (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME)))
+            cm_EAccesClearParentEntries(&fid);
+        cm_PutVolume(volp);
+    }
+
     /* invalidate so next merge works fine;
      * also initialize some flags */
     scp->fileType = 0;
@@ -179,8 +187,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
                     | CM_SCACHEFLAG_RO
                     | CM_SCACHEFLAG_PURERO
                     | CM_SCACHEFLAG_OVERQUOTA
-                    | CM_SCACHEFLAG_OUTOFSPACE
-                    | CM_SCACHEFLAG_EACCESS));
+                    | CM_SCACHEFLAG_OUTOFSPACE));
     scp->serverModTime = 0;
     scp->dataVersion = CM_SCACHE_VERSION_BAD;
     scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
@@ -1324,6 +1331,10 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
             if ((flags & CM_SCACHESYNC_FORCECB) || !cm_HaveCallback(scp)) {
                 osi_Log1(afsd_logp, "CM SyncOp getting callback on scp 0x%p",
                           scp);
+
+                if (cm_EAccesFindEntry(userp, &scp->fid))
+                    return CM_ERROR_NOACCESS;
+
                 if (bufLocked)
                    lock_ReleaseMutex(&bufp->mx);
                 code = cm_GetCallback(scp, userp, reqp, (flags & CM_SCACHESYNC_FORCECB)?1:0);
@@ -1655,7 +1666,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
         case UAEACCES:
         case EPERM:
         case UAEPERM:
-            _InterlockedOr(&scp->flags, CM_SCACHEFLAG_EACCESS);
+            cm_EAccesAddEntry(userp, &scp->fid, &dscp->fid);
         }
         osi_Log2(afsd_logp, "Merge, Failure scp 0x%p code 0x%x", scp, statusp->errorCode);
 
@@ -1689,8 +1700,6 @@ void cm_MergeStatus(cm_scache_t *dscp,
 
         if (RDR_Initialized)
             rdr_invalidate = 1;
-    } else {
-       _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_EACCESS);
     }
 
     dataVersion = statusp->dataVersionHigh;
@@ -1953,6 +1962,14 @@ void cm_MergeStatus(cm_scache_t *dscp,
         }
     }
 
+    /* Remove cached EACCES / EPERM errors if the file is a directory */
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY &&
+        !(volp && (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME)) &&
+        !cm_accessPerFileCheck)
+    {
+        cm_EAccesClearParentEntries(&scp->fid);
+    }
+
   done:
     if (volp)
         cm_PutVolume(volp);
index 15b6d2d0e364e377b16b05d1a541e794856e73be..08c90ddadd5e1ac7c10df16e7905ffd4ba8b677b 100644 (file)
@@ -291,7 +291,6 @@ typedef struct cm_scache {
 #define CM_SCACHEFLAG_ANYWATCH \
                        (CM_SCACHEFLAG_WATCHED | CM_SCACHEFLAG_WATCHEDSUBTREE)
 
-#define CM_SCACHEFLAG_EACCESS           0x200000 /* Bulk Stat returned EACCES */
 #define CM_SCACHEFLAG_SMB_FID          0x400000
 #define CM_SCACHEFLAG_LOCAL             0x800000 /* Locally modified */
 #define CM_SCACHEFLAG_BULKREADING       0x1000000/* Bulk read in progress */
index d63ec12831b0a9bfd69538d0c1d78eeb685c083f..9f209078e3686355e4165ad53a8c1782c1083d4a 100644 (file)
@@ -188,15 +188,13 @@ void cm_CheckTokenCache(time_t now)
                         }
                         _InterlockedAnd(&ucellp->flags, ~CM_UCELLFLAG_RXKAD);
                         ucellp->gen++;
-                        bExpired=TRUE;
+                        lock_ReleaseMutex(&userp->mx);
+                        cm_ResetACLCache(ucellp->cellp, userp);
+                        lock_ObtainMutex(&userp->mx);
                     }
                 }
             }
             lock_ReleaseMutex(&userp->mx);
-            if (bExpired) {
-                bExpired=FALSE;
-                cm_ResetACLCache(NULL, userp);
-            }
         }
     }
     lock_ReleaseRead(&smb_rctLock);
index 0da77a692e9e13c9d89233b37fc79717029bfc83..411f53a4f71066a4242174b26c75f48d9fe2f888 100644 (file)
@@ -12,6 +12,7 @@
 #include <roken.h>
 
 #include <afs/stds.h>
+#include <afs/unified_afs.h>
 
 #include <windows.h>
 #include <winsock2.h>
@@ -2350,7 +2351,7 @@ long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
     if (tscp) {
         if (lock_TryWrite(&tscp->rw)) {
             /* we have an entry that we can look at */
-            if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+            if (!cm_EAccesFindEntry(bsp->userp, &tscp->fid) && cm_HaveCallback(tscp)) {
                 /* we have a callback on it.  Don't bother
                  * fetching this stat entry, since we're happy
                  * with the info we have.
@@ -2516,6 +2517,13 @@ cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_re
             if (inlinebulk && (&bbp->stats[j])->errorCode) {
                 cm_req_t treq = *reqp;
                 cm_Analyze(NULL, userp, &treq, &tfid, 0, &volSync, NULL, &cbReq, (&bbp->stats[j])->errorCode);
+                switch ((&bbp->stats[j])->errorCode) {
+                case EACCES:
+                case UAEACCES:
+                case EPERM:
+                case UAEPERM:
+                    cm_EAccesAddEntry(userp, &tfid, &dscp->fid);
+                }
             } else {
                 code = cm_GetSCache(&tfid, &dscp->fid, &scp, userp, reqp);
                 if (code != 0)
@@ -2547,7 +2555,7 @@ cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_re
                 if ((scp->cbServerp == NULL &&
                      !(scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING | CM_SCACHEFLAG_SIZESTORING))) ||
                      (scp->flags & CM_SCACHEFLAG_PURERO) ||
-                     (scp->flags & CM_SCACHEFLAG_EACCESS))
+                     cm_EAccesFindEntry(userp, &scp->fid))
                 {
                     lock_ConvertRToW(&scp->rw);
                     lostRace = cm_EndCallbackGrantingCall(scp, &cbReq,
@@ -2589,6 +2597,7 @@ cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
 
     bbp = malloc(sizeof(cm_bulkStat_t));
     memset(bbp, 0, sizeof(cm_bulkStat_t));
+    bbp->userp = userp;
     bbp->bufOffset = *offsetp;
 
     lock_ReleaseWrite(&dscp->rw);
index 47e4fd4463578e498e554da9a6f40a0506567f6e..07080d2854d0d4102d16fe7236aad9f78facb233 100644 (file)
@@ -254,6 +254,7 @@ extern int cm_IsSpaceAvailable(cm_fid_t * fidp, osi_hyper_t *sizep, cm_user_t *u
 
 /* rock for bulk stat calls */
 typedef struct cm_bulkStat {
+    cm_user_t *userp;
     osi_hyper_t bufOffset;     /* only do it for things in this buffer page */
 
     /* info for the actual call */
index 6836ff9072fa96f55c7fdb7238d0d72e84e1d850..21288b5f4e530955b3eff35c16bca27b1961d742 100644 (file)
@@ -4660,6 +4660,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
 
         memset(bsp, 0, sizeof(cm_bulkStat_t));
+        bsp->userp = userp;
 
         for (patchp = *dirPatchespp, count=0;
              patchp;
@@ -4670,7 +4671,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
             if (tscp) {
                 if (lock_TryWrite(&tscp->rw)) {
                     /* we have an entry that we can look at */
-                    if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                    if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
                         /* we have a callback on it.  Don't bother
                         * fetching this stat entry, since we're happy
                         * with the info we have.
@@ -4692,6 +4693,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
             if (bsp->counter == AFSCBMAX) {
                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
                 memset(bsp, 0, sizeof(cm_bulkStat_t));
+                bsp->userp = userp;
             }
         }
 
@@ -4720,7 +4722,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
             continue;
         }
         lock_ObtainWrite(&scp->rw);
-        if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
+        if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
             lock_ReleaseWrite(&scp->rw);
 
             /* set the attribute */
index e2eae0d89bba8cdefbf094c1ab48368cebc5b277..aea349ed6233e302c075b5a6d9698befc186fb64 100644 (file)
@@ -4577,6 +4577,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
 
         memset(bsp, 0, sizeof(cm_bulkStat_t));
+        bsp->userp = userp;
 
         for (patchp = *dirPatchespp, count=0;
              patchp;
@@ -4604,7 +4605,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
                         continue;
                     }
 #endif /* AFS_FREELANCE_CLIENT */
-                    if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                    if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
                         /* we have a callback on it.  Don't bother
                         * fetching this stat entry, since we're happy
                         * with the info we have.
@@ -4626,6 +4627,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
             if (bsp->counter == AFSCBMAX) {
                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
                 memset(bsp, 0, sizeof(cm_bulkStat_t));
+                bsp->userp = userp;
             }
         }
 
@@ -4679,7 +4681,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
             continue;
 
         lock_ObtainWrite(&scp->rw);
-        if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
+        if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
             lock_ReleaseWrite(&scp->rw);
 
             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
index 03475c7310e4d25e8376e636e1c2bde5db264c98..cc5a4c7c58c1abd58774048ff6cc8a31806329dc 100644 (file)
@@ -404,7 +404,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
              * status information.  If not, perform a bulk status lookup of multiple
              * entries in order to reduce the number of RPCs issued to the file server.
              */
-            if ((scp->flags & CM_SCACHEFLAG_EACCESS))
+            if (cm_EAccesFindEntry(userp, &scp->fid))
                 bMustFake = TRUE;
             else if (!cm_HaveCallback(scp)) {
                 lock_ReleaseWrite(&scp->rw);
@@ -1759,7 +1759,7 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     Fid.unique = FileId.Unique;
     Fid.hash   = FileId.Hash;
 
-    code = cm_GetSCache(&Fid, &dscp->fid, &scp, userp, &req);
+    code = cm_GetSCache(&Fid, dscp ? &dscp->fid : NULL, &scp, userp, &req);
     if (code) {
         osi_Log1(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache object FID failure code=0x%x",
                  code);