$(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 \
$(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 \
#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"
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 */
#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
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);
/* fall through */
done:
+ if (volp)
+ cm_PutVolume(volp);
if (didLock)
lock_ReleaseRead(&aclScp->rw);
if (release)
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 */
/* 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);
}
_done:
+ if (volp)
+ cm_PutVolume(volp);
return code;
}
}
lock_ReleaseRead(&cm_scacheLock);
+ cm_EAccesClearUserEntries(userp, cellp->cellID);
+
if (RDR_Initialized) {
lock_ObtainRead(&cm_volumeLock);
for (hash = 0; hash < cm_data.volumeHashTableSize; hash++) {
goto done;
}
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
if (!bs_errorCodep) {
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.
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
goto done;
}
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
if (!bs_errorCodep) {
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.
goto done;
}
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
bs_errorCodep = malloc(sizeof(DWORD *) * AFSCBMAX);
if (!bs_errorCodep) {
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.
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);
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 */
time_t lastServerRankCheck;
time_t lastRDRShakeExtents;
time_t lastAfsdHookReload;
+ time_t lastEAccesCheck;
char thostName[200];
unsigned long code;
struct hostent *thp;
lastRDRShakeExtents = now - cm_daemonRDRShakeExtentsInterval/2 * (rand() % cm_daemonRDRShakeExtentsInterval);
if (cm_daemonAfsdHookReloadInterval)
lastAfsdHookReload = now;
+ lastEAccesCheck = now;
hHookDll = cm_LoadAfsdHookLib();
if (hHookDll)
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 &&
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
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
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;
| 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;
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);
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);
if (RDR_Initialized)
rdr_invalidate = 1;
- } else {
- _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_EACCESS);
}
dataVersion = statusp->dataVersionHigh;
}
}
+ /* 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);
#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 */
}
_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);
#include <roken.h>
#include <afs/stds.h>
+#include <afs/unified_afs.h>
#include <windows.h>
#include <winsock2.h>
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.
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)
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,
bbp = malloc(sizeof(cm_bulkStat_t));
memset(bbp, 0, sizeof(cm_bulkStat_t));
+ bbp->userp = userp;
bbp->bufOffset = *offsetp;
lock_ReleaseWrite(&dscp->rw);
/* 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 */
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;
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.
if (bsp->counter == AFSCBMAX) {
code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
}
}
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 */
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;
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.
if (bsp->counter == AFSCBMAX) {
code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
memset(bsp, 0, sizeof(cm_bulkStat_t));
+ bsp->userp = userp;
}
}
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'
* 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);
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);