Windows: Implement cm_TGTLifeTime()
[openafs.git] / src / WINNT / afsd / cm_aclent.c
index 0a1779f..ebec61b 100644 (file)
@@ -1,26 +1,26 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include <afsconfig.h>
 #include <afs/param.h>
+#include <roken.h>
+
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
-#endif
 #include <stdlib.h>
 #include <string.h>
-#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
@@ -35,19 +35,19 @@ 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 
+            /*
+             * Remove the entry from the vnode's list
              */
-            lock_AssertMutex(&aclp->backp->mx);
+            lock_AssertWrite(&aclp->backp->rw);
             laclpp = &aclp->backp->randomACLp;
             for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) {
-                if (taclp == aclp) 
+                if (taclp == aclp)
                     break;
             }
-            if (!taclp) 
+            if (!taclp)
                 osi_panic("CleanupACLEnt race", __FILE__, __LINE__);
             *laclpp = aclp->nextp;                     /* remove from vnode list */
         }
@@ -64,25 +64,25 @@ static void CleanupACLEnt(cm_aclent_t * aclp)
     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 cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp)
+long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 *rightsp)
 {
     cm_aclent_t *aclp;
     long retval = -1;
 
     lock_ObtainWrite(&cm_aclLock);
     *rightsp = 0;   /* get a new acl from server if we don't find a
-                     * current entry 
+                     * current entry
                      */
 
     for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
         if (aclp->userp == userp) {
-            if (aclp->tgtLifetime && aclp->tgtLifetime <= osi_Time()) {
+            if (aclp->tgtLifetime && aclp->tgtLifetime <= time(NULL)) {
                 /* ticket expired */
-                osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
+                osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
                 CleanupACLEnt(aclp);
 
                 /* move to the tail of the LRU queue */
@@ -92,26 +92,23 @@ long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp)
             } else {
                 *rightsp = aclp->randomAccess;
                if (cm_data.aclLRUp != aclp) {
-                   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_data.aclLRUp, &aclp->q);
+                   osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
                    osi_QAddH((osi_queue_t **) &cm_data.aclLRUp,
                               (osi_queue_t **) &cm_data.aclLRUEndp,
                               &aclp->q);
                }
                 retval = 0;     /* success */
-            }               
+            }
             break;
         }
     }
 
     lock_ReleaseWrite(&cm_aclLock);
     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
  */
@@ -119,52 +116,77 @@ static cm_aclent_t *GetFreeACLEnt(cm_scache_t * scp)
 {
     cm_aclent_t *aclp;
     cm_scache_t *ascp = 0;
-       
+
     if (cm_data.aclLRUp == NULL)
         osi_panic("empty aclent LRU", __FILE__, __LINE__);
 
+    if (cm_data.aclLRUEndp == NULL)
+        osi_panic("inconsistent aclent LRUEndp == NULL", __FILE__, __LINE__);
+
     aclp = cm_data.aclLRUEndp;
-    cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
-    osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
+    osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
 
     if (aclp->backp && scp != aclp->backp) {
         ascp = aclp->backp;
         lock_ReleaseWrite(&cm_aclLock);
-        lock_ObtainMutex(&ascp->mx);
+        lock_ObtainWrite(&ascp->rw);
         lock_ObtainWrite(&cm_aclLock);
     }
     CleanupACLEnt(aclp);
 
     if (ascp)
-        lock_ReleaseMutex(&ascp->mx);
+        lock_ReleaseWrite(&ascp->rw);
     return aclp;
 }
 
+time_t cm_TGTLifeTime(cm_user_t *userp, afs_uint32 cellID)
+{
+    cm_cell_t *cellp = NULL;
+    cm_ucell_t * ucp = NULL;
+    time_t      expirationTime = 0;
+
+    cellp = cm_FindCellByID(cellID, CM_FLAG_NOPROBE);
+    lock_ObtainMutex(&userp->mx);
+    ucp = cm_GetUCell(userp, cellp);
+    if (ucp->ticketp)
+        expirationTime = ucp->expirationTime;
+    lock_ReleaseMutex(&userp->mx);
+
+    return expirationTime;
+}
 
-/* 
- * Add rights to an acl cache entry.  Do the right thing if not present, 
+
+/*
+ * Add rights to an acl cache entry.  Do the right thing if not present,
  * including digging up an entry from the LRU queue.
  *
  * The scp must be locked when this function is called.
  */
-long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights)
+long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 rights)
 {
-    register struct cm_aclent *aclp;
+    struct cm_aclent *aclp;
 
     lock_ObtainWrite(&cm_aclLock);
     for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
         if (aclp->userp == userp) {
             aclp->randomAccess = rights;
-            if (aclp->tgtLifetime == 0) 
-                aclp->tgtLifetime = cm_TGTLifeTime(pag);
+            if (aclp->tgtLifetime == 0)
+                aclp->tgtLifetime = cm_TGTLifeTime(userp, scp->fid.cell);
+            if (cm_data.aclLRUp != aclp) {
+                /* move to the head of the LRU queue */
+                osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
+                osi_QAddH((osi_queue_t **) &cm_data.aclLRUp,
+                           (osi_queue_t **) &cm_data.aclLRUEndp,
+                           &aclp->q);
+            }
             lock_ReleaseWrite(&cm_aclLock);
             return 0;
         }
     }
 
-    /* 
-     * Didn't find the dude we're looking for, so take someone from the LRUQ 
-     * and  reuse. But first try the free list and see if there's already 
+    /*
+     * Didn't find the dude we're looking for, so take someone from the LRUQ
+     * and  reuse. But first try the free list and see if there's already
      * someone there.
      */
     aclp = GetFreeACLEnt(scp);          /* can't fail, panics instead */
@@ -175,7 +197,7 @@ long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights)
     cm_HoldUser(userp);
     aclp->userp = userp;
     aclp->randomAccess = rights;
-    aclp->tgtLifetime = cm_TGTLifeTime(userp);
+    aclp->tgtLifetime = cm_TGTLifeTime(userp, scp->fid.cell);
     lock_ReleaseWrite(&cm_aclLock);
 
     return 0;
@@ -251,7 +273,7 @@ long cm_ValidateACLCache(void)
     return 0;
 }
 
-/* 
+/*
  * Initialize the cache to have an entries.  Called during system startup.
  */
 long cm_InitACLCache(int newFile, long size)
@@ -261,7 +283,7 @@ long cm_InitACLCache(int newFile, long size)
     static osi_once_t once;
 
     if (osi_Once(&once)) {
-        lock_InitializeRWLock(&cm_aclLock, "cm_aclLock");
+        lock_InitializeRWLock(&cm_aclLock, "cm_aclLock", LOCK_HIERARCHY_ACL_GLOBAL);
         osi_EndOnce(&once);
     }
 
@@ -271,8 +293,8 @@ long cm_InitACLCache(int newFile, long size)
         aclp = (cm_aclent_t *) cm_data.aclBaseAddress;
         memset(aclp, 0, size * sizeof(cm_aclent_t));
 
-        /* 
-         * Put all of these guys on the LRU queue 
+        /*
+         * Put all of these guys on the LRU queue
          */
         for (i = 0; i < size; i++) {
             aclp->magic = CM_ACLENT_MAGIC;
@@ -292,7 +314,7 @@ long cm_InitACLCache(int newFile, long size)
 }
 
 
-/* 
+/*
  * Free all associated acl entries.  We actually just clear the back pointer
  * since the acl entries are already in the free list.  The scp must be locked
  * or completely unreferenced (such as when called while recycling the scp).
@@ -318,16 +340,19 @@ void cm_FreeAllACLEnts(cm_scache_t *scp)
 }
 
 
-/* 
+/*
  * Invalidate all ACL entries for particular user on this particular vnode.
  *
- * The scp must be locked.
+ * The scp must not be locked.
  */
 void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp)
 {
     cm_aclent_t *aclp;
     cm_aclent_t **laclpp;
+    int found = 0;
+    int callback = 0;
 
+    lock_ObtainWrite(&scp->rw);
     lock_ObtainWrite(&cm_aclLock);
     laclpp = &scp->randomACLp;
     for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) {
@@ -336,8 +361,79 @@ void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp)
             cm_ReleaseUser(aclp->userp);
             aclp->userp = NULL;
             aclp->backp = (struct cm_scache *) 0;
+            found = 1;
             break;
         }
     }
     lock_ReleaseWrite(&cm_aclLock);
+    if (found)
+        callback = cm_HaveCallback(scp);
+    lock_ReleaseWrite(&scp->rw);
+
+    if (found && callback && RDR_Initialized)
+        RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
+                             scp->fid.hash, scp->fileType, AFS_INVALIDATE_CREDS);
+}
+
+/*
+ * Invalidate ACL info for a user that has just        obtained or lost tokens.
+ */
+void
+cm_ResetACLCache(cm_cell_t *cellp, cm_user_t *userp)
+{
+    cm_volume_t *volp, *nextVolp;
+    cm_scache_t *scp, *nextScp;
+    afs_uint32 hash;
+
+    lock_ObtainRead(&cm_scacheLock);
+    for (hash=0; hash < cm_data.scacheHashTableSize; hash++) {
+        for (scp=cm_data.scacheHashTablep[hash]; scp; scp=nextScp) {
+            nextScp = scp->nextp;
+            if (cellp == NULL ||
+                scp->fid.cell == cellp->cellID) {
+                cm_HoldSCacheNoLock(scp);
+                lock_ReleaseRead(&cm_scacheLock);
+                cm_InvalidateACLUser(scp, userp);
+                lock_ObtainRead(&cm_scacheLock);
+                cm_ReleaseSCacheNoLock(scp);
+            }
+        }
+    }
+    lock_ReleaseRead(&cm_scacheLock);
+
+    if (RDR_Initialized) {
+        lock_ObtainRead(&cm_volumeLock);
+        for (hash = 0; hash < cm_data.volumeHashTableSize; hash++) {
+            for ( volp = cm_data.volumeRWIDHashTablep[hash]; volp; volp = nextVolp) {
+                nextVolp = volp->vol[RWVOL].nextp;
+                if ((cellp == NULL || cellp->cellID == volp->cellp->cellID) &&
+                    volp->vol[RWVOL].ID) {
+                    lock_ReleaseRead(&cm_volumeLock);
+                    RDR_InvalidateVolume(volp->cellp->cellID, volp->vol[RWVOL].ID, AFS_INVALIDATE_CREDS);
+                    lock_ObtainRead(&cm_volumeLock);
+                }
+            }
+            for ( volp = cm_data.volumeROIDHashTablep[hash]; volp; volp = nextVolp) {
+                nextVolp = volp->vol[ROVOL].nextp;
+                if ((cellp == NULL || cellp->cellID == volp->cellp->cellID) &&
+                    volp->vol[ROVOL].ID) {
+                    lock_ReleaseRead(&cm_volumeLock);
+                    RDR_InvalidateVolume(volp->cellp->cellID, volp->vol[ROVOL].ID, AFS_INVALIDATE_CREDS);
+                    lock_ObtainRead(&cm_volumeLock);
+                }
+            }
+            for ( volp = cm_data.volumeBKIDHashTablep[hash]; volp; volp = nextVolp) {
+                nextVolp = volp->vol[BACKVOL].nextp;
+                if ((cellp == NULL || cellp->cellID == volp->cellp->cellID) &&
+                    volp->vol[BACKVOL].ID) {
+                    lock_ReleaseRead(&cm_volumeLock);
+                    RDR_InvalidateVolume(volp->cellp->cellID, volp->vol[BACKVOL].ID, AFS_INVALIDATE_CREDS);
+                    lock_ObtainRead(&cm_volumeLock);
+                }
+            }
+        }
+        lock_ReleaseRead(&cm_volumeLock);
+    }
 }
+
+