unix cm rx-oblivious connection pooling
authorMatt Benjamin <matt@linuxbox.com>
Wed, 3 Nov 2010 21:02:19 +0000 (17:02 -0400)
committerDerrick Brashear <shadow@dementia.org>
Thu, 2 Dec 2010 18:18:04 +0000 (10:18 -0800)
Implements a connection pool for Rx client connections with the
same credentials.  The code trivially avoids the limit on Rx
call channels, without touching Rx directly.  The conn call limit
is known to be hit in cache-bypass, and probably other use cases,
so there is an incentive to address it potentially sooner than
larger Rx changes are ready to merge.

Upgrade to exclusive lock before calling find_preferred_connection.
Unset trace option.  Fix a warning around modular increment of
select_index, we'll go with the change suggested by Marc, I don't
see a real need to save the value mod CVEC_LEN.

Change-Id: I956aa22cd52b1c43187c7e03230e36820ba11c4d
Change-Id: Ie5f936ba912bcfe0544dbc1d035bb74e5ddc50f8
Reviewed-on: http://gerrit.openafs.org/2216
Reviewed-by: Marc Dionne <marc.c.dionne@gmail.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

17 files changed:
src/afs/VNOPS/afs_vnop_create.c
src/afs/VNOPS/afs_vnop_lookup.c
src/afs/VNOPS/afs_vnop_symlink.c
src/afs/afs.h
src/afs/afs_analyze.c
src/afs/afs_bypasscache.c
src/afs/afs_conn.c
src/afs/afs_dcache.c
src/afs/afs_disconnected.c
src/afs/afs_init.c
src/afs/afs_pioctl.c
src/afs/afs_prototypes.h
src/afs/afs_server.c
src/afs/afs_user.c
src/afs/afs_util.c
src/afs/afs_vcache.c
src/afs/afs_volume.c

index e598007..3e91a74 100644 (file)
@@ -299,7 +299,7 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
        do {
            tc = afs_Conn(&adp->f.fid, &treq, SHARED_LOCK);
            if (tc) {
-               hostp = tc->srvr->server;       /* remember for callback processing */
+               hostp = tc->parent->srvr->server; /* remember for callback processing */
                now = osi_Time();
                XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
                RX_AFS_GUNLOCK();
index 7bdbb2c..609403c 100644 (file)
@@ -928,10 +928,10 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
 
        tcp = afs_Conn(&adp->f.fid, areqp, SHARED_LOCK);
        if (tcp) {
-           hostp = tcp->srvr->server;
+           hostp = tcp->parent->srvr->server;
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
 
-           if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
+           if (!(tcp->parent->srvr->server->flags & SNO_INLINEBULK)) {
            retryonce:
                RX_AFS_GUNLOCK();
                code =
@@ -939,7 +939,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
                                           &cbParm, &volSync);
                RX_AFS_GLOCK();
                if (code == RXGEN_OPCODE) {
-                   tcp->srvr->server->flags |= SNO_INLINEBULK;
+                   tcp->parent->srvr->server->flags |= SNO_INLINEBULK;
                    inlinebulk = 0;
                    RX_AFS_GUNLOCK();
                    code =
index dbbf9c8..1ee329d 100644 (file)
@@ -158,7 +158,7 @@ afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
        do {
            tc = afs_Conn(&adp->f.fid, &treq, SHARED_LOCK);
            if (tc) {
-               hostp = tc->srvr->server;
+               hostp = tc->parent->srvr->server;
                XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SYMLINK);
                if (adp->f.states & CForeign) {
                    now = osi_Time();
index 037edf1..85064b7 100644 (file)
@@ -366,17 +366,41 @@ struct unixuser {
     void *cellinfo;             /* pointer to cell info (PAG manager only) */
 };
 
+#define CVEC_LEN 3 /* per-user connection pool */
+
+struct sa_conn_vector;
+typedef struct sa_conn_vector * p_sa_conn_vector; /* forward decl */
+
 struct afs_conn {
-    /* Per-connection block. */
-    struct afs_conn *next;             /* Next dude same server. */
+    int refCount;
+    int activated;
+    char forceConnectFS; /* Should we try again with these tokens? */
+    struct rx_connection *id; /* RPC connid */
+    struct sa_conn_vector *parent; /* the con_vector which contains us */
+};
+
+/* An sa_conn_vector replaces the erstwhile list of conn
+   structures maintained by the cache manager.  The sa_conn_vector
+   contains a C array of connections which, if non-zero, represent
+   connections to AFS servers.
+*/
+
+struct sa_conn_vector {
+    /* linked-list machinery */
+    struct sa_conn_vector *next;
+
+    /* AFS conn-identifying info */
     struct unixuser *user;     /* user validated with respect to. */
-    struct rx_connection *id;  /* RPC connid. */
     struct srvAddr *srvr;      /* server associated with this conn */
     short refCount;            /* reference count for allocation */
     unsigned short port;       /* port associated with this connection */
-    char forceConnectFS;       /* Should we try again with these tokens? */
-};
 
+    /* next connection to return when all in cvec are fully utilized */
+    int select_index; 
+    
+    /* connections vector */
+    struct afs_conn cvec[CVEC_LEN];
+};
 
 #define SQNULL -1
 
@@ -396,11 +420,12 @@ struct afs_conn {
 #define        SRVADDR_MH      1
 #define        SRVADDR_ISDOWN  0x20    /* same as SRVR_ISDOWN */
 #define  SRVADDR_NOUSE    0x40 /* Don't use this srvAddr */
+
 struct srvAddr {
     struct srvAddr *next_bkt;  /* next item in hash bucket */
     struct srvAddr *next_sa;   /* another interface on same host */
     struct server *server;     /* back to parent */
-    struct afs_conn *conns;            /* All user connections to this server */
+    struct sa_conn_vector *conns;   /* All user connections to this server */
     afs_int32 sa_ip;           /* Host addr in network byte order */
     u_short sa_iprank;         /* indiv ip address priority */
     u_short sa_portal;         /* port addr in network byte order */
@@ -427,8 +452,8 @@ struct srvAddr {
 #define SRV_CAPABILITIES(ts) \
 { if ( !(ts->flags & SCAPS_KNOWN)) afs_GetCapabilities(ts); ts->capabilities; }
 
-#define afs_serverSetNo64Bit(s) ((s)->srvr->server->flags |= SNO_64BIT)
-#define afs_serverHasNo64Bit(s) ((s)->srvr->server->flags & SNO_64BIT)
+#define afs_serverSetNo64Bit(s) (((struct sa_conn_vector*)(s)->parent)->srvr->server->flags |= SNO_64BIT)
+#define afs_serverHasNo64Bit(s) (((struct sa_conn_vector*)(s)->parent)->srvr->server->flags & SNO_64BIT)
 
 struct server {
     union {
index 8e7a883..a10ed87 100644 (file)
@@ -45,7 +45,6 @@
 #include <inet/ip.h>
 #endif
 
-
 /* shouldn't do it this way, but for now will do */
 #ifndef ERROR_TABLE_BASE_U
 #define ERROR_TABLE_BASE_U     (5376L)
@@ -119,12 +118,12 @@ VLDB_Same(struct VenusFid *afid, struct vrequest *areq)
            afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum,
                             &treq, SHARED_LOCK);
        if (tconn) {
-           if (tconn->srvr->server->flags & SNO_LHOSTS) {
+           if ( tconn->parent->srvr->server->flags & SNO_LHOSTS) {
                type = 0;
                RX_AFS_GUNLOCK();
                i = VL_GetEntryByNameO(tconn->id, bp, &v->tve);
                RX_AFS_GLOCK();
-           } else if (tconn->srvr->server->flags & SYES_LHOSTS) {
+           } else if (tconn->parent->srvr->server->flags & SYES_LHOSTS) {
                type = 1;
                RX_AFS_GUNLOCK();
                i = VL_GetEntryByNameN(tconn->id, bp, &v->ntve);
@@ -134,7 +133,7 @@ VLDB_Same(struct VenusFid *afid, struct vrequest *areq)
                RX_AFS_GUNLOCK();
                i = VL_GetEntryByNameU(tconn->id, bp, &v->utve);
                RX_AFS_GLOCK();
-               if (!(tconn->srvr->server->flags & SVLSRV_UUID)) {
+               if (!(tconn->parent->srvr->server->flags & SVLSRV_UUID)) {
                    if (i == RXGEN_OPCODE) {
                        type = 1;
                        RX_AFS_GUNLOCK();
@@ -142,14 +141,14 @@ VLDB_Same(struct VenusFid *afid, struct vrequest *areq)
                        RX_AFS_GLOCK();
                        if (i == RXGEN_OPCODE) {
                            type = 0;
-                           tconn->srvr->server->flags |= SNO_LHOSTS;
+                           tconn->parent->srvr->server->flags |= SNO_LHOSTS;
                            RX_AFS_GUNLOCK();
                            i = VL_GetEntryByNameO(tconn->id, bp, &v->tve);
                            RX_AFS_GLOCK();
                        } else if (!i)
-                           tconn->srvr->server->flags |= SYES_LHOSTS;
+                           tconn->parent->srvr->server->flags |= SYES_LHOSTS;
                    } else if (!i)
-                       tconn->srvr->server->flags |= SVLSRV_UUID;
+                       tconn->parent->srvr->server->flags |= SVLSRV_UUID;
                }
                lastcode = i;
            }
@@ -383,7 +382,7 @@ afs_Analyze(struct afs_conn *aconn, afs_int32 acode,
        return shouldRetry;     /* should retry */
     }
 
-    if (!aconn || !aconn->srvr) {
+    if (!aconn || !aconn->parent->srvr) {
        if (!areq->volumeError) {
            if (aerrP)
                (aerrP->err_Network)++;
@@ -425,7 +424,7 @@ afs_Analyze(struct afs_conn *aconn, afs_int32 acode,
     }
 
     /* Find server associated with this connection. */
-    sa = aconn->srvr;
+    sa = aconn->parent->srvr;
     tsp = sa->server;
     address = ntohl(sa->sa_ip);
 
@@ -542,11 +541,11 @@ afs_Analyze(struct afs_conn *aconn, afs_int32 acode,
                aconn->forceConnectFS = 1;
            } else if (acode == RXKADEXPIRED) {
                aconn->forceConnectFS = 0;      /* don't check until new tokens set */
-               aconn->user->states |= UTokensBad;
+               aconn->parent->user->states |= UTokensBad;
                afs_NotifyUser(tu, UTokensDropped);
                afs_warnuser
                    ("afs: Tokens for user of AFS id %d for cell %s have expired (server %d.%d.%d.%d)\n",
-                    tu->viceId, aconn->srvr->server->cell->cellName,
+                    tu->viceId, aconn->parent->srvr->server->cell->cellName,
                     (address >> 24), (address >> 16) & 0xff,
                     (address >> 8) & 0xff, (address) & 0xff);
            } else {
@@ -556,18 +555,18 @@ afs_Analyze(struct afs_conn *aconn, afs_int32 acode,
                if (serversleft) {
                    afs_warnuser
                        ("afs: Tokens for user of AFS id %d for cell %s: rxkad error=%d (server %d.%d.%d.%d)\n",
-                        tu->viceId, aconn->srvr->server->cell->cellName, acode,
+                        tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
                         (address >> 24), (address >> 16) & 0xff,
                         (address >> 8) & 0xff, (address) & 0xff);
                    shouldRetry = 1;
                } else {
                    areq->tokenError = 0;
                    aconn->forceConnectFS = 0;  /* don't check until new tokens set */
-                   aconn->user->states |= UTokensBad;
+                   aconn->parent->user->states |= UTokensBad;
                    afs_NotifyUser(tu, UTokensDropped);
                    afs_warnuser
                        ("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d, server %d.%d.%d.%d)\n",
-                        tu->viceId, aconn->srvr->server->cell->cellName, acode,
+                        tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
                         (address >> 24), (address >> 16) & 0xff,
                         (address >> 8) & 0xff, (address) & 0xff);
                }
@@ -579,20 +578,21 @@ afs_Analyze(struct afs_conn *aconn, afs_int32 acode,
                aconn->forceConnectFS = 1;
            } else if (acode == RXKADEXPIRED) {
                aconn->forceConnectFS = 0;      /* don't check until new tokens set */
-               aconn->user->states |= UTokensBad;
+               aconn->parent->user->states |= UTokensBad;
                afs_NotifyUser(tu, UTokensDropped);
                afs_warnuser
                    ("afs: Tokens for user %d for cell %s have expired (server %d.%d.%d.%d)\n",
-                    areq->uid, aconn->srvr->server->cell->cellName,
+                    areq->uid, aconn->parent->srvr->server->cell->cellName,
                     (address >> 24), (address >> 16) & 0xff,
                     (address >> 8) & 0xff, (address) & 0xff);
            } else {
                aconn->forceConnectFS = 0;      /* don't check until new tokens set */
-               aconn->user->states |= UTokensBad;
+               aconn->parent->user->states |= UTokensBad;
                afs_NotifyUser(tu, UTokensDropped);
                afs_warnuser
                    ("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d, server %d.%d.%d.%d)\n",
-                    areq->uid, aconn->srvr->server->cell->cellName, acode,
+                    areq->uid, aconn->parent->srvr->server->cell->cellName,
+                     acode,
                     (address >> 24), (address >> 16) & 0xff,
                     (address >> 8) & 0xff, (address) & 0xff);
 
index bb1baf4..3cab748 100644 (file)
@@ -535,7 +535,7 @@ afs_PrefetchNoCache(struct vcache *avc,
     do {
        tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK /* ignored */);
        if (tc) {
-           avc->callback = tc->srvr->server;
+           avc->callback = tc->parent->srvr->server;
            i = osi_Time();
            tcall = rx_NewCall(tc->id);
 #ifdef AFS_64BIT_CLIENT
index 91f56e7..fc4873c 100644 (file)
@@ -48,6 +48,145 @@ afs_rwlock_t afs_xconn;             /* allocation lock for new things */
 afs_rwlock_t afs_xinterface;   /* for multiple client address */
 afs_int32 cryptall = 0;                /* encrypt all communications */
 
+/* some connection macros */
+
+/* a constructor */
+#define new_conn_vector(xcv) \
+do { \
+       xcv = (struct sa_conn_vector *) \
+       afs_osi_Alloc(sizeof(struct sa_conn_vector)); \
+       if (xcv) { \
+               memset((char *)xcv, 0, sizeof(struct sa_conn_vector)); \
+       } \
+} while (0);
+
+/* select a connection to return (if no connection has lower utilization
+ * than any other) */
+#define conn_vec_select_conn(xcv, bix, conn) \
+do { \
+    (bix) = ((xcv)->select_index)++ % CVEC_LEN; \
+    (conn) = &((xcv)->cvec[bix]); \
+} while (0);
+
+#define struct_conn(s) ((struct afs_conn *)(s))
+
+#define REPORT_CONNECTIONS_ISSUED 0 /* enable to see utilization */
+
+/**
+ * Find a connection with call slots available, allocating one
+ * if nothing is available and we find an allocated slot
+ * @param xcv  A connection vector
+ * @param create  If set, a new connection may be created
+ */
+static struct afs_conn *
+find_preferred_connection(struct sa_conn_vector *xcv, int create)
+{
+    afs_int32 cix, bix;
+    struct afs_conn *tc = NULL;
+
+    bix = -1;
+    for(cix = 0; cix < CVEC_LEN; ++cix) {
+        tc = &(xcv->cvec[cix]);
+        if (!tc->id) {
+            if (create) {
+                tc->parent = xcv;
+                tc->forceConnectFS = 1;
+                tc->activated = 1;
+                bix = cix;
+                break;
+            } /* create */
+        } else {
+            if (tc->refCount < (RX_MAXCALLS-1)) {
+                bix = cix;
+                goto f_conn;
+            } else if (cix == (CVEC_LEN-1))
+                conn_vec_select_conn(xcv, bix, tc);
+        } /* tc->id */
+    } /* for cix < CVEC_LEN */
+
+    if (bix < 0) {
+        afs_warn("find_preferred_connection: no connection and !create\n");
+        tc = NULL;
+        goto out;
+    }
+
+f_conn:
+    tc->refCount++;
+    xcv->refCount++;
+
+#if REPORT_CONNECTIONS_ISSUED
+    afs_warn("Issuing conn %d refCount=%d parent refCount=%d\n", bix,
+             tc->refCount, xcv->refCount);
+#endif
+
+out:
+    return (tc);
+
+}        /* find_preferred_connection */
+
+
+/**
+ * Release all connections for unix user xu at server xs
+ * @param xu
+ * @param xs
+ */
+static void
+release_conns_user_server(struct unixuser *xu, struct server *xs)
+{
+    int cix, glocked;
+    struct srvAddr *sa;
+    struct afs_conn *tc;
+    struct sa_conn_vector *tcv, **lcv;
+    for (sa = (xs)->addr; sa; sa = sa->next_sa) {
+        lcv = &sa->conns;
+        for (tcv = *lcv; tcv; lcv = &tcv->next, tcv = *lcv) {
+            if (tcv->user == (xu) && tcv->refCount == 0) {
+                *lcv = tcv->next;
+                /* our old friend, the GLOCK */
+                glocked = ISAFS_GLOCK();
+                if (glocked)
+                    AFS_GUNLOCK();
+                for(cix = 0; cix < CVEC_LEN; ++cix) {
+                    tc = &(tcv->cvec[cix]);
+                    if (tc->activated)
+                        rx_DestroyConnection(tc->id);
+                }
+                if (glocked)
+                    AFS_GLOCK();
+                afs_osi_Free(tcv, sizeof(struct sa_conn_vector));
+                break;    /* at most one instance per server */
+            } /*Found unreferenced connection for user */
+        }
+    } /*For each connection on the server */
+
+}        /* release_conns_user_server */
+
+
+static void
+release_conns_vector(struct sa_conn_vector *xcv)
+{
+    int cix, glocked;
+    struct afs_conn *tc;
+    struct sa_conn_vector *tcv = NULL;
+    struct sa_conn_vector **lcv = NULL;
+    for (tcv = xcv; tcv; lcv = &tcv->next, tcv = *lcv) {
+        *lcv = tcv->next;
+        /* you know it, you love it, the GLOCK */
+        glocked = ISAFS_GLOCK();
+        if (glocked)
+            AFS_GUNLOCK(); \
+        for(cix = 0; cix < CVEC_LEN; ++cix) {
+            tc = &(tcv->cvec[cix]);
+            if (tc->activated)
+                rx_DestroyConnection( tc->id );
+        }
+        if (glocked)
+            AFS_GLOCK();
+        afs_osi_Free(tcv, sizeof(struct sa_conn_vector));
+    }
+
+}        /* release_conns_vector */
+
 
 unsigned int VNOSERVERS = 0;
 
@@ -72,8 +211,8 @@ afs_pickSecurityObject(struct afs_conn *conn, int *secLevel)
     union tokenUnion *token;
 
     /* Do we have tokens ? */
-    if (conn->user->states & UHasTokens) {
-       token = afs_FindToken(conn->user->tokens, RX_SECIDX_KAD);
+    if (conn->parent->user->states & UHasTokens) {
+       token = afs_FindToken(conn->parent->user->tokens, RX_SECIDX_KAD);
        if (token) {
            *secLevel = RX_SECIDX_KAD;
            /* kerberos tickets on channel 2 */
@@ -84,7 +223,7 @@ afs_pickSecurityObject(struct afs_conn *conn, int *secLevel)
                         token->rxkad.clearToken.AuthHandle,
                         token->rxkad.ticketLen, token->rxkad.ticket);
            /* We're going to use this token, so populate the viced */
-           conn->user->viceId = token->rxkad.clearToken.ViceId;
+           conn->parent->user->viceId = token->rxkad.clearToken.ViceId;
        }
      }
      if (secObj == NULL) {
@@ -205,28 +344,32 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
             struct unixuser *tu, int force_if_down, afs_int32 create,
             afs_int32 locktype)
 {
-    struct afs_conn *tc = 0;
-    struct rx_securityClass *csec;     /*Security class object */
-    int isec;                  /*Security index */
+    int glocked, foundvec;
+    struct afs_conn *tc = NULL;
+    struct sa_conn_vector *tcv = NULL;
+    struct rx_securityClass *csec; /*Security class object */
+    int isec; /*Security index */
     int service;
 
-    if (!sap || ((sap->sa_flags & SRVR_ISDOWN) && !force_if_down)) {
-       /* sa is known down, and we don't want to force it.  */
-       return NULL;
-    }
-
+    /* find cached connection */
     ObtainSharedLock(&afs_xconn, 15);
-    /* Get conn by port and user. */
-    for (tc = sap->conns; tc; tc = tc->next) {
-       if (tc->user == tu && tc->port == aport) {
-           break;
-       }
+    foundvec = 0;
+    for (tcv = sap->conns; tcv; tcv = tcv->next) {
+        if (tcv->user == tu && tcv->port == aport) {
+            /* return most eligible conn */
+            if (!foundvec)
+                foundvec = 1;
+            UpgradeSToWLock(&afs_xconn, 37);
+            tc = find_preferred_connection(tcv, create);
+            ConvertWToSLock(&afs_xconn);
+            break;
+        }
     }
 
     if (!tc && !create) {
-       /* Not found and can't create a new one. */
-       ReleaseSharedLock(&afs_xconn);
-       return NULL;
+        /* Not found and can't create a new one. */
+        ReleaseSharedLock(&afs_xconn);
+        return NULL;
     }
 
     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
@@ -235,31 +378,35 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
         return NULL;
     }
 
-    if (!tc) {
-       /* No such connection structure exists.  Create one and splice it in.
+    if (!foundvec && create) {
+       /* No such connection vector exists.  Create one and splice it in.
         * Make sure the server record has been marked as used (for the purposes
         * of calculating up & down times, it's now considered to be an
         * ``active'' server).  Also make sure the server's lastUpdateEvalTime
         * gets set, marking the time of its ``birth''.
         */
        UpgradeSToWLock(&afs_xconn, 37);
-       tc = afs_osi_Alloc(sizeof(struct afs_conn));
-       osi_Assert(tc != NULL);
-       memset(tc, 0, sizeof(struct afs_conn));
-
-       tc->user = tu;
-       tc->port = aport;
-       tc->srvr = sap;
-       tc->refCount = 0;       /* bumped below */
-       tc->forceConnectFS = 1;
-       tc->id = (struct rx_connection *)0;
-       tc->next = sap->conns;
-       sap->conns = tc;
+        new_conn_vector(tcv);
+
+        tcv->user = tu;
+        tcv->port = aport;
+        tcv->srvr = sap;
+        tcv->next = sap->conns;
+        sap->conns = tcv;
+
+        /* all struct afs_conn ptrs come from here */
+        tc = find_preferred_connection(tcv, create);
+
        afs_ActivateServer(sap);
 
        ConvertWToSLock(&afs_xconn);
-    } /* end of if (!tc) */
-    tc->refCount++;
+    } /* end of if (!tcv) */
+
+    if (!tc) {
+        /* Not found and no alternatives. */
+        ReleaseSharedLock(&afs_xconn);
+        return NULL;
+    }
 
     if (tu->states & UTokensBad) {
        /* we may still have an authenticated RPC connection here,
@@ -275,13 +422,16 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
        tu->states &= ~UHasTokens;      /* remove the authentication info */
     }
 
+    glocked = ISAFS_GLOCK();
     if (tc->forceConnectFS) {
        UpgradeSToWLock(&afs_xconn, 38);
        csec = (struct rx_securityClass *)0;
        if (tc->id) {
-           AFS_GUNLOCK();
+           if (glocked)
+                AFS_GUNLOCK();
            rx_DestroyConnection(tc->id);
-           AFS_GLOCK();
+           if (glocked)
+                AFS_GLOCK();
        }
        /*
         * Stupid hack to determine if using vldb service or file system
@@ -295,9 +445,11 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
 
        csec = afs_pickSecurityObject(tc, &isec);
 
-       AFS_GUNLOCK();
+       if (glocked)
+            AFS_GUNLOCK();
        tc->id = rx_NewConnection(sap->sa_ip, aport, service, csec, isec);
-       AFS_GLOCK();
+       if (glocked)
+            AFS_GLOCK();
        if (service == 52) {
            rx_SetConnHardDeadTime(tc->id, afs_rx_harddead);
        }
@@ -345,8 +497,8 @@ afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell,
               struct vrequest *areq, int aforce, afs_int32 locktype)
 {
     struct unixuser *tu;
-    struct afs_conn *tc = 0;
-    struct srvAddr *sa = 0;
+    struct afs_conn *tc = NULL;
+    struct srvAddr *sa = NULL;
 
     AFS_STATCNT(afs_ConnByHost);
 
@@ -433,10 +585,40 @@ afs_PutConn(struct afs_conn *ac, afs_int32 locktype)
 {
     AFS_STATCNT(afs_PutConn);
     ac->refCount--;
+    ac->parent->refCount--;
 }                              /*afs_PutConn */
 
 
 /**
+ * Free up a connection vector, allowing, eg, code in afs_user.c
+ * to ignore how connections are stored/pooled
+ * @param tcv
+ */
+void
+afs_ReleaseConns(struct sa_conn_vector *tcv) {
+    release_conns_vector(tcv);
+}
+
+
+/**
+ * Free connection vector(s) for a user
+ * @param au
+ */
+void
+afs_ReleaseConnsUser(struct unixuser *au) {
+
+    int i;
+    struct server *ts;
+
+    for (i = 0; i < NSERVERS; i++) {
+        for (ts = afs_servers[i]; ts; ts = ts->next) {
+            release_conns_user_server(au, ts);
+        }      /*For each server on chain */
+    } /*For each chain */
+}
+
+
+/**
  * For multi homed clients, a RPC may timeout because of a
  * client network interface going down. We need to reopen new
  * connections in this case.
@@ -446,13 +628,22 @@ afs_PutConn(struct afs_conn *ac, afs_int32 locktype)
 void
 ForceNewConnections(struct srvAddr *sap)
 {
-    struct afs_conn *tc = 0;
+    int cix;
+    struct afs_conn *tc = NULL;
+    struct sa_conn_vector *tcv = NULL;
 
     if (!sap)
-       return;                 /* defensive check */
+       return; /* defensive check */
 
     ObtainWriteLock(&afs_xconn, 413);
-    for (tc = sap->conns; tc; tc = tc->next)
-       tc->forceConnectFS = 1;
+    for (tcv = sap->conns; tcv; tcv = tcv->next) {
+        for(cix = 0; cix < CVEC_LEN; ++cix) {
+            tc = &(tcv->cvec[cix]);
+            if (tc->activated)
+                tc->forceConnectFS = 1;
+        }
+    }
     ReleaseWriteLock(&afs_xconn);
 }
+
+
index 7de98c1..fa569c9 100644 (file)
@@ -2216,9 +2216,9 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte,
 
 #endif /* AFS_NOSTATS */
                    if (!setLocks || slowPass) {
-                       avc->callback = tc->srvr->server;
+                       avc->callback = tc->parent->srvr->server;
                    } else {
-                       newCallback = tc->srvr->server;
+                       newCallback = tc->parent->srvr->server;
                        setNewCallback = 1;
                    }
                    i = osi_Time();
index 06d4d0c..7f76064 100644 (file)
@@ -1177,7 +1177,7 @@ afs_ResyncDisconFiles(struct vrequest *areq, afs_ucred_t *acred)
        do {
            tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
            if (tc) {
-               tvc->callback = tc->srvr->server;
+               tvc->callback = tc->parent->srvr->server;
                start = osi_Time();
                XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
                RX_AFS_GUNLOCK();
index a194cdb..a1a8562 100644 (file)
@@ -751,7 +751,6 @@ static void
 shutdown_server(void)
 {
     int i;
-    struct afs_conn *tc, *ntc;
     struct afs_cbr *tcbrp, *tbrp;
     struct srvAddr *sa;
 
@@ -763,22 +762,11 @@ shutdown_server(void)
            next = ts->next;
            for (sa = ts->addr; sa; sa = sa->next_sa) {
                if (sa->conns) {
-                   /*
-                    * Free all server's connection structs
-                    */
-                   tc = sa->conns;
-                   while (tc) {
-                       ntc = tc->next;
-#if 0
-                       /* we should destroy all connections
-                          when shutting down Rx, not here */
-                       AFS_GUNLOCK();
-                       rx_DestroyConnection(tc->id);
-                       AFS_GLOCK();
-#endif
-                       afs_osi_Free(tc, sizeof(struct afs_conn));
-                       tc = ntc;
-                   }
+                    /* afs_ReleaseConns has been updated to
+                     * defer rx_DestroyConnection to Rx
+                     * shutdown, as most recently was done
+                     * here */
+                    afs_ReleaseConns(sa->conns);
                }
            }
            for (tcbrp = ts->cbrs; tcbrp; tcbrp = tbrp) {
index 2cd5242..5bd07d8 100644 (file)
@@ -2626,7 +2626,7 @@ DECL_PIOCTL(PCheckAuth)
 {
     int i;
     struct srvAddr *sa;
-    struct afs_conn *tc;
+    struct sa_conn_vector *tcv;
     struct unixuser *tu;
     afs_int32 retValue;
 
@@ -2649,8 +2649,8 @@ DECL_PIOCTL(PCheckAuth)
        /* all connections in cell 1 working? */
        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 == tu && (tu->states & UTokensBad))
+               for (tcv = sa->conns; tcv; tcv = tcv->next) {
+                   if (tcv->user == tu && (tu->states & UTokensBad))
                        retValue = EACCES;
                }
            }
index 3857062..1327298 100644 (file)
@@ -190,6 +190,8 @@ extern struct afs_conn *afs_ConnByHost(struct server *aserver,
                                   struct vrequest *areq, int aforce,
                                   afs_int32 locktype);
 extern void afs_PutConn(struct afs_conn *ac, afs_int32 locktype);
+extern void afs_ReleaseConns(struct sa_conn_vector *tcv);
+extern void afs_ReleaseConnsUser(register struct unixuser *au);
 extern void ForceNewConnections(struct srvAddr *sap);
 
 
index 6043425..407c9cd 100644 (file)
@@ -313,7 +313,7 @@ CheckVLServer(struct srvAddr *sa, struct vrequest *areq)
      * with old vlsevers), then we treat this server as running again
      */
     if (code == 0 || (code <= -450 && code >= -470)) {
-       if (tc->srvr == sa) {
+       if (tc->parent->srvr == sa) {
            afs_MarkServerUpOrDown(sa, 0);
            print_internet_address("afs: volume location server ", sa,
                                   " is back up", 2);
@@ -635,7 +635,7 @@ afs_CheckServers(int adown, struct cell *acellp)
            continue;
 
        if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(sa->server)
-           || (tc->srvr->server == afs_setTimeHost)) {
+           || (tc->parent->srvr->server == afs_setTimeHost)) {
            conns[nconns]=tc;
            rxconns[nconns]=tc->id;
            if (sa->sa_flags & SRVADDR_ISDOWN) {
@@ -687,7 +687,7 @@ afs_CheckServers(int adown, struct cell *acellp)
                multi_RXAFS_GetTime(
                        (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
                tc = conns[multi_i];
-               sa = tc->srvr;
+               sa = tc->parent->srvr;
                if (conntimer[multi_i] == 1)
                  rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
                end = osi_Time();
@@ -699,9 +699,9 @@ afs_CheckServers(int adown, struct cell *acellp)
            }
        else {                  /* find and query setTimeHost only */
            for ( i = 0 ; i < j ; i++ ) {
-               if ( conns[i] == NULL || conns[i]->srvr == NULL )
+               if ( conns[i] == NULL || conns[i]->parent->srvr == NULL )
                    continue;
-               if ( conns[i]->srvr->server == afs_setTimeHost ) {
+               if ( conns[i]->parent->srvr->server == afs_setTimeHost ) {
                    tv.tv_sec = tv.tv_usec = 0;
                    results[i] = RXAFS_GetTime(rxconns[i],
                                (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
@@ -717,9 +717,9 @@ afs_CheckServers(int adown, struct cell *acellp)
 
     for(i=0;i<nconns;i++){
       tc = conns[i];
-      sa = tc->srvr;
+      sa = tc->parent->srvr;
 
-      if (( results[i] >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
+      if (( results[i] >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->parent->srvr == sa)) {
        /* server back up */
        print_internet_address("afs: file server ", sa, " is back up", 2);
 
@@ -751,9 +751,9 @@ afs_CheckServers(int adown, struct cell *acellp)
        for (i=0; i<nconns; i++) {
            delta = deltas[i];
            tc = conns[i];
-           sa = tc->srvr;
+           sa = tc->parent->srvr;
 
-           if ((tc->srvr->server == afs_setTimeHost ||
+           if ((tc->parent->srvr->server == afs_setTimeHost ||
                 /* Sync only to a server in the local cell */
                 (afs_setTimeHost == (struct server *)0 &&
                  afs_IsPrimaryCell(sa->server->cell)))) {
@@ -761,7 +761,7 @@ afs_CheckServers(int adown, struct cell *acellp)
                char msgbuf[90];  /* strlen("afs: setting clock...") + slop */
                delta = end - tv.tv_sec;   /* how many secs fast we are */
 
-               afs_setTimeHost = tc->srvr->server;
+               afs_setTimeHost = tc->parent->srvr->server;
                /* see if clock has changed enough to make it worthwhile */
                if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
                    end = osi_Time();
@@ -1981,7 +1981,6 @@ afs_RemoveAllConns(void)
     int i;
     struct server *ts, *nts;
     struct srvAddr *sa;
-    struct afs_conn *tc, *ntc;
 
     ObtainReadLock(&afs_xserver);
     ObtainWriteLock(&afs_xconn, 1001);
@@ -1992,15 +1991,7 @@ afs_RemoveAllConns(void)
             nts = ts->next;
             for (sa = ts->addr; sa; sa = sa->next_sa) {
                 if (sa->conns) {
-                    tc = sa->conns;
-                    while (tc) {
-                        ntc = tc->next;
-                        AFS_GUNLOCK();
-                        rx_DestroyConnection(tc->id);
-                        AFS_GLOCK();
-                        afs_osi_Free(tc, sizeof(struct afs_conn));
-                        tc = ntc;
-                    }
+                    afs_ReleaseConns(sa->conns);
                     sa->conns = NULL;
                 }
             }
index d22f2ab..fe7fb04 100644 (file)
@@ -52,39 +52,6 @@ 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 */
 #endif /* !AFS_PAG_MANAGER */
 
 
@@ -130,7 +97,7 @@ afs_GCUserData(int aforce)
            if (delFlag) {
                *lu = tu->next;
 #ifndef AFS_PAG_MANAGER
-               RemoveUserConns(tu);
+                afs_ReleaseConnsUser(tu);
 #endif
                afs_FreeTokens(&tu->tokens);
 
@@ -231,9 +198,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 +208,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;
+                   }
                }
            }
        }
index 37484d9..f8d17fb 100644 (file)
@@ -270,15 +270,15 @@ afs_CheckLocks(void)
     {
        struct srvAddr *sa;
        struct server *ts;
-       struct afs_conn *tc;
+        struct sa_conn_vector *tcv;
        for (i = 0; i < NSERVERS; i++) {
            for (ts = afs_servers[i]; ts; ts = ts->next) {
                if (ts->flags & SRVR_ISDOWN)
                    afs_warn("Server entry %p is marked down\n", ts);
                for (sa = ts->addr; sa; sa = sa->next_sa) {
-                   for (tc = sa->conns; tc; tc = tc->next) {
-                       if (tc->refCount)
-                           afs_warn("conn at %p (server %x) is held\n", tc,
+                    for (tcv = sa->conns; tcv; tcv = tcv->next) {
+                        if (tcv->refCount)
+                            afs_warn("conn at %p (server %x) is held\n", tcv,
                                     sa->sa_ip);
                    }
                }
index e515d3c..4ad9855 100644 (file)
@@ -1477,7 +1477,7 @@ afs_RemoteLookup(struct VenusFid *afid, struct vrequest *areq,
        tc = afs_Conn(afid, areq, SHARED_LOCK);
        if (tc) {
            if (serverp)
-               *serverp = tc->srvr->server;
+               *serverp = tc->parent->srvr->server;
            start = osi_Time();
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_XLOOKUP);
            RX_AFS_GUNLOCK();
@@ -2260,7 +2260,7 @@ afs_FetchStatus(struct vcache * avc, struct VenusFid * afid,
        tc = afs_Conn(afid, areq, SHARED_LOCK);
        avc->dchint = NULL;     /* invalidate hints */
        if (tc) {
-           avc->callback = tc->srvr->server;
+           avc->callback = tc->parent->srvr->server;
            start = osi_Time();
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
            RX_AFS_GUNLOCK();
index d0d5c3b..60671dd 100644 (file)
@@ -765,12 +765,12 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
            afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum,
                             &treq, SHARED_LOCK);
        if (tconn) {
-           if (tconn->srvr->server->flags & SNO_LHOSTS) {
+           if (tconn->parent->srvr->server->flags & SNO_LHOSTS) {
                type = 0;
                RX_AFS_GUNLOCK();
                code = VL_GetEntryByNameO(tconn->id, aname, tve);
                RX_AFS_GLOCK();
-           } else if (tconn->srvr->server->flags & SYES_LHOSTS) {
+           } else if (tconn->parent->srvr->server->flags & SYES_LHOSTS) {
                type = 1;
                RX_AFS_GUNLOCK();
                code = VL_GetEntryByNameN(tconn->id, aname, ntve);
@@ -780,7 +780,7 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
                RX_AFS_GUNLOCK();
                code = VL_GetEntryByNameU(tconn->id, aname, utve);
                RX_AFS_GLOCK();
-               if (!(tconn->srvr->server->flags & SVLSRV_UUID)) {
+               if (!(tconn->parent->srvr->server->flags & SVLSRV_UUID)) {
                    if (code == RXGEN_OPCODE) {
                        type = 1;
                        RX_AFS_GUNLOCK();
@@ -788,14 +788,14 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
                        RX_AFS_GLOCK();
                        if (code == RXGEN_OPCODE) {
                            type = 0;
-                           tconn->srvr->server->flags |= SNO_LHOSTS;
+                           tconn->parent->srvr->server->flags |= SNO_LHOSTS;
                            RX_AFS_GUNLOCK();
                            code = VL_GetEntryByNameO(tconn->id, aname, tve);
                            RX_AFS_GLOCK();
                        } else if (!code)
-                           tconn->srvr->server->flags |= SYES_LHOSTS;
+                           tconn->parent->srvr->server->flags |= SYES_LHOSTS;
                    } else if (!code)
-                       tconn->srvr->server->flags |= SVLSRV_UUID;
+                       tconn->parent->srvr->server->flags |= SVLSRV_UUID;
                }
                lastnvcode = code;
            }