#include <malloc.h>
#include "afsd.h"
+#include <osisleep.h>
/*
* This next lock controls access to all cm_aclent structures in the system,
* in either the free list or in the LRU queue. A read lock prevents someone
* from modifying the list(s), and a write lock is required for modifying
* the list. The actual data stored in the randomUid and randomAccess fields
- * is actually maintained as up-to-date or not via the scache llock.
+ * is actually maintained as up-to-date or not via the scache lock.
* An aclent structure is free if it has no back vnode pointer.
*/
osi_rwlock_t cm_aclLock; /* lock for system's aclents */
+/* This must be called with cm_aclLock and the aclp->back->mx held */
+static void CleanupACLEnt(cm_aclent_t * aclp)
+{
+ cm_aclent_t *taclp;
+ cm_aclent_t **laclpp;
+
+ if (aclp->backp) {
+ if (aclp->backp->randomACLp) {
+ /*
+ * Remove the entry from the vnode's list
+ */
+ lock_AssertMutex(&aclp->backp->mx);
+ laclpp = &aclp->backp->randomACLp;
+ for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) {
+ if (taclp == aclp)
+ break;
+ }
+ if (!taclp)
+ osi_panic("CleanupACLEnt race", __FILE__, __LINE__);
+ *laclpp = aclp->nextp; /* remove from vnode list */
+ }
+ aclp->backp = NULL;
+ }
+
+ /* release the old user */
+ if (aclp->userp) {
+ cm_ReleaseUser(aclp->userp);
+ aclp->userp = NULL;
+ }
+
+ aclp->randomAccess = 0;
+ aclp->tgtLifetime = 0;
+}
+
/*
* Get an acl cache entry for a particular user and file, or return that it doesn't exist.
* Called with the scp locked.
long retval = -1;
lock_ObtainWrite(&cm_aclLock);
+ *rightsp = 0; /* get a new acl from server if we don't find a
+ * current entry
+ */
+
for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
if (aclp->userp == userp) {
- if (aclp->tgtLifetime && aclp->tgtLifetime <= (long) osi_Time()) {
+ if (aclp->tgtLifetime && aclp->tgtLifetime <= osi_Time()) {
/* ticket expired */
- aclp->tgtLifetime = 0;
- *rightsp = 0; /* get a new acl from server */
+ osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
+ CleanupACLEnt(aclp);
- /* Shouldn't we remove this entry from the scp?
- * 2005-01-25 - jaltman@secure-endpoints.com
- */
+ /* move to the tail of the LRU queue */
+ osi_QAddT((osi_queue_t **) &cm_data.aclLRUp,
+ (osi_queue_t **) &cm_data.aclLRUEndp,
+ &aclp->q);
} else {
*rightsp = aclp->randomAccess;
if (cm_data.aclLRUEndp == aclp)
return retval;
}
-
/*
* This function returns a free (not in the LRU queue) acl cache entry.
- * It must be called with the cm_aclLock lock held.
+ * It must be called with the cm_aclLock lock held
*/
-static cm_aclent_t *GetFreeACLEnt(void)
+static cm_aclent_t *GetFreeACLEnt(cm_scache_t * scp)
{
cm_aclent_t *aclp;
- cm_aclent_t *taclp;
- cm_aclent_t **laclpp;
-
+ cm_scache_t *ascp = 0;
+
if (cm_data.aclLRUp == NULL)
osi_panic("empty aclent LRU", __FILE__, __LINE__);
- lock_ObtainWrite(&cm_aclLock);
aclp = cm_data.aclLRUEndp;
- if (aclp == cm_data.aclLRUEndp)
- cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
+ cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
- if (aclp->backp) {
- /*
- * Remove the entry from the vnode's list
- */
- laclpp = &aclp->backp->randomACLp;
- for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) {
- if (taclp == aclp)
- break;
- }
- if (!taclp)
- osi_panic("GetFreeACLEnt race", __FILE__, __LINE__);
- *laclpp = aclp->nextp; /* remove from vnode list */
- aclp->backp = NULL;
- }
- /* release the old user */
- if (aclp->userp) {
- cm_ReleaseUser(aclp->userp);
- aclp->userp = NULL;
+ if (aclp->backp && scp != aclp->backp) {
+ ascp = aclp->backp;
+ lock_ReleaseWrite(&cm_aclLock);
+ lock_ObtainMutex(&ascp->mx);
+ lock_ObtainWrite(&cm_aclLock);
}
- lock_ReleaseWrite(&cm_aclLock);
+ CleanupACLEnt(aclp);
+
+ if (ascp)
+ lock_ReleaseMutex(&ascp->mx);
return aclp;
}
* and reuse. But first try the free list and see if there's already
* someone there.
*/
- aclp = GetFreeACLEnt(); /* can't fail, panics instead */
+ aclp = GetFreeACLEnt(scp); /* can't fail, panics instead */
osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
aclp->backp = scp;
aclp->nextp = scp->randomACLp;
long count;
cm_aclent_t * aclp;
+ if ( cm_data.aclLRUp == NULL && cm_data.aclLRUEndp != NULL ||
+ cm_data.aclLRUp != NULL && cm_data.aclLRUEndp == NULL) {
+ afsi_log("cm_ValidateACLCache failure: inconsistent LRU pointers");
+ fprintf(stderr, "cm_ValidateACLCache failure: inconsistent LRU pointers\n");
+ return -9;
+ }
+
for ( aclp = cm_data.aclLRUp, count = 0; aclp;
aclp = (cm_aclent_t *) osi_QNext(&aclp->q), count++ ) {
if (aclp->magic != CM_ACLENT_MAGIC) {