windows-afscache-validate-20050806
[openafs.git] / src / WINNT / afsd / cm_aclent.c
index 89902dc..e34470a 100644 (file)
 #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 */
-cm_aclent_t *cm_aclLRUp;                /* LRUQ for dudes in vnode's lists */
-cm_aclent_t *cm_aclLRUEndp;             /* ditto */
+
+/* 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.
@@ -40,25 +74,30 @@ long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp)
     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_aclLRUEndp == aclp)
-                    cm_aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
+                if (cm_data.aclLRUEndp == aclp)
+                    cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
 
                 /* move to the head of the LRU queue */
-                osi_QRemove((osi_queue_t **) &cm_aclLRUp, &aclp->q);
-                osi_QAddH((osi_queue_t **) &cm_aclLRUp,
-                           (osi_queue_t **) &cm_aclLRUEndp,
+                osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
+                osi_QAddH((osi_queue_t **) &cm_data.aclLRUp,
+                           (osi_queue_t **) &cm_data.aclLRUEndp,
                            &aclp->q);
                 retval = 0;     /* success */
             }               
@@ -70,44 +109,32 @@ long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp)
     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;
-
-    if (cm_aclLRUp == NULL)
+    cm_scache_t *ascp = 0;
+       
+    if (cm_data.aclLRUp == NULL)
         osi_panic("empty aclent LRU", __FILE__, __LINE__);
 
-    aclp = cm_aclLRUEndp;
-    if (aclp == cm_aclLRUEndp)
-        cm_aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
-    osi_QRemove((osi_queue_t **) &cm_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;
-    }
+    aclp = cm_data.aclLRUEndp;
+    cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
+    osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
 
-    /* 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);
     }
+    CleanupACLEnt(aclp);
+
+    if (ascp)
+        lock_ReleaseMutex(&ascp->mx);
     return aclp;
 }
 
@@ -138,8 +165,8 @@ long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights)
      * and  reuse. But first try the free list and see if there's already 
      * someone there.
      */
-    aclp = GetFreeACLEnt();             /* can't fail, panics instead */
-    osi_QAddH((osi_queue_t **) &cm_aclLRUp, (osi_queue_t **) &cm_aclLRUEndp, &aclp->q);
+    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;
     scp->randomACLp = aclp;
@@ -152,10 +179,80 @@ long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights)
     return 0;
 }
 
+long cm_ShutdownACLCache(void)
+{
+    return 0;
+}
+
+long cm_ValidateACLCache(void)
+{
+    long size = cm_data.stats * 2;
+    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) {
+            afsi_log("cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC");
+            fprintf(stderr, "cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC\n");
+            return -1;
+        }
+        if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) {
+            afsi_log("cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC");
+            fprintf(stderr,"cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC\n");
+            return -2;
+        }
+        if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) {
+            afsi_log("cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC");
+            fprintf(stderr,"cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC\n");
+            return -3;
+        }
+        if (count != 0 && aclp == cm_data.aclLRUp || count > size) {
+            afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUp list");
+            fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUp list\n");
+            return -4;
+        }
+    }
+
+    for ( aclp = cm_data.aclLRUEndp, count = 0; aclp;
+          aclp = (cm_aclent_t *) osi_QPrev(&aclp->q), count++ ) {
+        if (aclp->magic != CM_ACLENT_MAGIC) {
+            afsi_log("cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC");
+            fprintf(stderr, "cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC\n");
+            return -5;
+        }
+        if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) {
+            afsi_log("cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC");
+            fprintf(stderr, "cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC\n");
+            return -6;
+        }
+        if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) {
+            afsi_log("cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC");
+            fprintf(stderr, "cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC\n");
+            return -7;
+        }
+
+        if (count != 0 && aclp == cm_data.aclLRUEndp || count > size) {
+            afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list");
+            fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list\n");
+            return -8;
+        }
+    }
+
+    return 0;
+}
+
 /* 
  * Initialize the cache to have an entries.  Called during system startup.
  */
-long cm_InitACLCache(long size)
+long cm_InitACLCache(int newFile, long size)
 {
     cm_aclent_t *aclp;
     long i;
@@ -167,16 +264,26 @@ long cm_InitACLCache(long size)
     }
 
     lock_ObtainWrite(&cm_aclLock);
-    cm_aclLRUp = cm_aclLRUEndp = NULL;
-    aclp = (cm_aclent_t *) malloc(size * sizeof(cm_aclent_t));
-    memset(aclp, 0, size * sizeof(cm_aclent_t));
+    if ( newFile ) {
+        cm_data.aclLRUp = cm_data.aclLRUEndp = NULL;
+        aclp = (cm_aclent_t *) cm_data.aclBaseAddress;
+        memset(aclp, 0, size * sizeof(cm_aclent_t));
 
-    /* 
-     * Put all of these guys on the LRU queue 
-     */
-    for (i = 0; i < size; i++) {
-        osi_QAddH((osi_queue_t **) &cm_aclLRUp, (osi_queue_t **) &cm_aclLRUEndp, &aclp->q);
-        aclp++;
+        /* 
+         * Put all of these guys on the LRU queue 
+         */
+        for (i = 0; i < size; i++) {
+            aclp->magic = CM_ACLENT_MAGIC;
+            osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
+            aclp++;
+        }
+    } else {
+        aclp = (cm_aclent_t *) cm_data.aclBaseAddress;
+        for (i = 0; i < size; i++) {
+            aclp->userp = NULL;
+            aclp->tgtLifetime = 0;
+            aclp++;
+        }
     }
     lock_ReleaseWrite(&cm_aclLock);
     return 0;