afs: only reset access caches for the matching cell
[openafs.git] / src / afs / afs_user.c
index d22f2ab..7f7468c 100644 (file)
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs/afs_stats.h"     /* afs statistics */
 
-#if    defined(AFS_SUN56_ENV)
+#if    defined(AFS_SUN5_ENV)
 #include <inet/led.h>
 #include <inet/common.h>
-#if   defined(AFS_SUN58_ENV)
 #include <netinet/ip6.h>
-#endif
 #include <inet/ip.h>
 #endif
 
+#include "afs/afs_axscache.h"
 
 /* Exported variables */
 afs_rwlock_t afs_xuser;
@@ -51,40 +50,7 @@ struct unixuser *afs_users[NUSERS];
 
 #ifndef AFS_PAG_MANAGER
 /* Forward declarations */
-void afs_ResetAccessCache(afs_int32 uid, int alock);
-
-/*
- * Called with afs_xuser, afs_xserver and afs_xconn locks held, to delete
- * appropriate conn structures for au
- */
-static void
-RemoveUserConns(struct unixuser *au)
-{
-    int i;
-    struct server *ts;
-    struct srvAddr *sa;
-    struct afs_conn *tc, **lc;
-
-    AFS_STATCNT(RemoveUserConns);
-    for (i = 0; i < NSERVERS; i++) {
-       for (ts = afs_servers[i]; ts; ts = ts->next) {
-           for (sa = ts->addr; sa; sa = sa->next_sa) {
-               lc = &sa->conns;
-               for (tc = *lc; tc; lc = &tc->next, tc = *lc) {
-                   if (tc->user == au && tc->refCount == 0) {
-                       *lc = tc->next;
-                       AFS_GUNLOCK();
-                       rx_DestroyConnection(tc->id);
-                       AFS_GLOCK();
-                       afs_osi_Free(tc, sizeof(struct afs_conn));
-                       break;  /* at most one instance per server */
-                   }           /*Found unreferenced connection for user */
-               }               /*For each connection on the server */
-           }
-       }                       /*For each server on chain */
-    }                          /*For each chain */
-
-}                              /*RemoveUserConns */
+void afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock);
 #endif /* !AFS_PAG_MANAGER */
 
 
@@ -130,7 +96,7 @@ afs_GCUserData(int aforce)
            if (delFlag) {
                *lu = tu->next;
 #ifndef AFS_PAG_MANAGER
-               RemoveUserConns(tu);
+                afs_ReleaseConnsUser(tu);
 #endif
                afs_FreeTokens(&tu->tokens);
 
@@ -152,6 +118,23 @@ afs_GCUserData(int aforce)
 
 }                              /*afs_GCUserData */
 
+static struct unixuser *
+afs_FindUserNoLock(afs_int32 auid, afs_int32 acell)
+{
+    struct unixuser *tu;
+    afs_int32 i;
+
+    AFS_STATCNT(afs_FindUser);
+    i = UHash(auid);
+    for (tu = afs_users[i]; tu; tu = tu->next) {
+       if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
+           tu->refCount++;
+           return tu;
+       }
+    }
+    return NULL;
+
+}
 
 #ifndef AFS_PAG_MANAGER
 /*
@@ -165,6 +148,9 @@ afs_CheckTokenCache(void)
     int i;
     struct unixuser *tu;
     afs_int32 now;
+    struct vcache *tvc;
+    struct axscache *tofreelist;
+    int do_scan = 0;
 
     AFS_STATCNT(afs_CheckCacheResets);
     ObtainReadLock(&afs_xvcache);
@@ -172,8 +158,6 @@ afs_CheckTokenCache(void)
     now = osi_Time();
     for (i = 0; i < NUSERS; i++) {
        for (tu = afs_users[i]; tu; tu = tu->next) {
-           afs_int32 uid;
-
            /*
             * If tokens are still good and user has Kerberos tickets,
             * check expiration
@@ -187,20 +171,60 @@ afs_CheckTokenCache(void)
                    tu->states |= (UTokensBad | UNeedsReset);
                }
            }
-           if (tu->states & UNeedsReset) {
-               tu->states &= ~UNeedsReset;
-               uid = tu->uid;
-               afs_ResetAccessCache(uid, 0);
+           if (tu->states & UNeedsReset)
+               do_scan = 1;
+       }
+    }
+    /* Skip the potentially expensive scan if nothing to do */
+    if (!do_scan)
+       goto done;
+
+    tofreelist = NULL;
+    for (i = 0; i < VCSIZE; i++) {
+       for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
+           /* really should do this under cache write lock, but that.
+            * is hard to under locking hierarchy */
+           if (tvc->Access) {
+               struct axscache **ac, **nac;
+
+               for ( ac = &tvc->Access; *ac;)  {
+                   nac = &(*ac)->next;
+                   tu = afs_FindUserNoLock((*ac)->uid, tvc->f.fid.Cell);
+                   if (tu == NULL || (tu->states & UNeedsReset)) {
+                       struct axscache *tmp;
+                       tmp = *ac;
+                       *ac = *nac;
+                       tmp->next = tofreelist;
+                       tofreelist = tmp;
+                   } else
+                       ac = nac;
+                   if (tu != NULL)
+                       tu->refCount--;
+               }
            }
        }
     }
+    afs_FreeAllAxs(&tofreelist);
+    for (i = 0; i < NUSERS; i++) {
+       for (tu = afs_users[i]; tu; tu = tu->next) {
+           if (tu->states & UNeedsReset)
+               tu->states &= ~UNeedsReset;
+       }
+    }
+
+done:
     ReleaseReadLock(&afs_xuser);
     ReleaseReadLock(&afs_xvcache);
 }                              /*afs_CheckTokenCache */
 
 
+/* Remove any access caches associated with this uid+cell
+ * by scanning the entire vcache table.  Specify cell=-1
+ * to remove all access caches associated with this uid
+ * regardless of cell.
+ */
 void
-afs_ResetAccessCache(afs_int32 uid, int alock)
+afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock)
 {
     int i;
     struct vcache *tvc;
@@ -213,8 +237,11 @@ afs_ResetAccessCache(afs_int32 uid, int alock)
        for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
            /* really should do this under cache write lock, but that.
             * is hard to under locking hierarchy */
-           if (tvc->Access && (ac = afs_FindAxs(tvc->Access, uid))) {
-               afs_RemoveAxs(&tvc->Access, ac);
+           if (tvc->Access && (cell == -1 || tvc->f.fid.Cell == cell)) {
+               ac = afs_FindAxs(tvc->Access, uid);
+               if (ac) {
+                   afs_RemoveAxs(&tvc->Access, ac);
+               }
            }
        }
     }
@@ -231,9 +258,9 @@ afs_ResetAccessCache(afs_int32 uid, int alock)
 void
 afs_ResetUserConns(struct unixuser *auser)
 {
-    int i;
+    int i, j;
     struct srvAddr *sa;
-    struct afs_conn *tc;
+    struct sa_conn_vector *tcv;
 
     AFS_STATCNT(afs_ResetUserConns);
     ObtainReadLock(&afs_xsrvAddr);
@@ -241,9 +268,11 @@ afs_ResetUserConns(struct unixuser *auser)
 
     for (i = 0; i < NSERVERS; i++) {
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
-           for (tc = sa->conns; tc; tc = tc->next) {
-               if (tc->user == auser) {
-                   tc->forceConnectFS = 1;
+           for (tcv = sa->conns; tcv; tcv = tcv->next) {
+               if (tcv->user == auser) {
+                   for(j = 0; j < CVEC_LEN; ++j) {
+                       (tcv->cvec[j]).forceConnectFS = 1;
+                   }
                }
            }
        }
@@ -251,7 +280,7 @@ afs_ResetUserConns(struct unixuser *auser)
 
     ReleaseWriteLock(&afs_xconn);
     ReleaseReadLock(&afs_xsrvAddr);
-    afs_ResetAccessCache(auser->uid, 1);
+    afs_ResetAccessCache(auser->uid, auser->cell, 1);
     auser->states &= ~UNeedsReset;
 }                              /*afs_ResetUserConns */
 #endif /* !AFS_PAG_MANAGER */
@@ -261,21 +290,13 @@ struct unixuser *
 afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
 {
     struct unixuser *tu;
-    afs_int32 i;
 
-    AFS_STATCNT(afs_FindUser);
-    i = UHash(auid);
     ObtainWriteLock(&afs_xuser, 99);
-    for (tu = afs_users[i]; tu; tu = tu->next) {
-       if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
-           tu->refCount++;
-           ReleaseWriteLock(&afs_xuser);
-           return tu;
-       }
-    }
+    tu = afs_FindUserNoLock(auid, acell);
     ReleaseWriteLock(&afs_xuser);
-    return NULL;
-
+    if (tu)
+       afs_LockUser(tu, locktype, 365);
+    return tu;
 }                              /*afs_FindUser */
 
 
@@ -458,12 +479,10 @@ afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
                /* Here we setup the real cell for the client */
                tu->cell = acell;
                tu->refCount++;
-               ReleaseWriteLock(&afs_xuser);
-               return tu;
+               goto done;
            } else if (tu->cell == acell || acell == -1) {
                tu->refCount++;
-               ReleaseWriteLock(&afs_xuser);
-               return tu;
+               goto done;
            }
        }
     }
@@ -473,6 +492,7 @@ afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
     afs_stats_cmfullperf.authent.PAGCreations++;
 #endif /* AFS_NOSTATS */
     memset(tu, 0, sizeof(struct unixuser));
+    AFS_RWLOCK_INIT(&tu->lock, "unixuser lock");
     tu->next = afs_users[i];
     afs_users[i] = tu;
     if (RmtUser) {
@@ -492,16 +512,54 @@ afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
     tu->viceId = UNDEFVID;
     tu->refCount = 1;
     tu->tokenTime = osi_Time();
+
+ done:
     ReleaseWriteLock(&afs_xuser);
+    afs_LockUser(tu, locktype, 364);
     return tu;
 
 }                              /*afs_GetUser */
 
+void
+afs_LockUser(struct unixuser *au, afs_int32 locktype,
+             unsigned int src_indicator)
+{
+    switch (locktype) {
+    case READ_LOCK:
+       ObtainReadLock(&au->lock);
+       break;
+    case WRITE_LOCK:
+       ObtainWriteLock(&au->lock, src_indicator);
+       break;
+    case SHARED_LOCK:
+       ObtainSharedLock(&au->lock, src_indicator);
+       break;
+    default:
+       /* noop */
+       break;
+    }
+}
 
 void
 afs_PutUser(struct unixuser *au, afs_int32 locktype)
 {
     AFS_STATCNT(afs_PutUser);
+
+    switch (locktype) {
+    case READ_LOCK:
+       ReleaseReadLock(&au->lock);
+       break;
+    case WRITE_LOCK:
+       ReleaseWriteLock(&au->lock);
+       break;
+    case SHARED_LOCK:
+       ReleaseSharedLock(&au->lock);
+       break;
+    default:
+       /* noop */
+       break;
+    }
+
     --au->refCount;
 }                              /*afs_PutUser */