]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
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 e598007a4be49f3c3201455c7e2f63c48a19eb44..3e91a748c344e5a8c30db2e6fa1318d04cacac33 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 7bdbb2c19089093f7f306c139fa121f3d040da1d..609403c846db1bbe89ae0cdfc6398ec430f3efb5 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 dbbf9c84bfb26f163a62963eb7247ea8ba3746b8..1ee329def0dd157e4fd2faaf1c90ad812e2c2aa0 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 037edf1202a5e8044ca54104e4b332b1aad24d6d..85064b7a0b21ae45211f7145dbcac4fdb0c4d924 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 8e7a883510b5349cd4c87dee766e29a1a006970d..a10ed87bbf88ed7387dee52ef857517decb124cb 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 bb1baf469c4fa84fcd1da7a0cc080f53e33b7bd9..3cab748a80a45b46f5509cf397cb3d937a3a8225 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 91f56e73b8f321e5d2bf8159d785c800151a5eed..fc4873c2c3654e1892c6dca4364251f8736369ff 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,9 +585,39 @@ 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
@@ -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 7de98c12448941c5433a4a54b959e35c1a0a6e0e..fa569c960e8b4c42fee95af6234102c1e7432d66 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 06d4d0cc2d6c9049c7fc4107b6e6fe74b3a9cd51..7f76064cbe046c429b6b8fe489f72049c1202fe8 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 a194cdb7b4125323f08b916db5995e7d0c5031c6..a1a8562884f04d10e34902834e295da48aa29f3d 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 2cd52427ae27b571798074300e4255f084e0bb8f..5bd07d80a99cf237e439eb29f4c55b0a07e5a2a4 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 38570622bb27fb61dac1c008f407a3ee05296154..1327298cf62b97c52911f38da742df6af75c9bda 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 6043425218096d347b188525aadc4357e6a7cfb3..407c9cdfd87e4bd6ba49f5d7afc1ccb607da4718 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 d22f2abe749effcca5ec96ae4b9e9e5997c0a3e7..fe7fb048f9016e1944b49a263badd30db724ed7a 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 37484d9ea60d9125655945209ed3628e9adf123d..f8d17fb3a603604d13361af18013a13cf9782202 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 e515d3c9d2c92e66b12f34ccffc017160b37d491..4ad9855fcfbdc6f0c55b67d68cd57bac4348d0aa 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 d0d5c3b5c64adcd25b440f427aa37d5dfcf9ea64..60671dd58584c13d09d4b94e410f56fb4078f0a1 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;
            }