rx: Remove RX_CALL_IDLE
[openafs.git] / src / afs / afs_conn.c
index f63ac63..be6ab2b 100644 (file)
@@ -134,7 +134,7 @@ 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;
+    struct sa_conn_vector *tcv, **lcv, *tcvn;
     for (sa = (xs)->addr; sa; sa = sa->next_sa) {
         lcv = &sa->conns;
         for (tcv = *lcv; tcv; lcv = &tcv->next, tcv = *lcv) {
@@ -146,8 +146,27 @@ release_conns_user_server(struct unixuser *xu, struct server *xs)
                     AFS_GUNLOCK();
                 for(cix = 0; cix < CVEC_LEN; ++cix) {
                     tc = &(tcv->cvec[cix]);
-                    if (tc->activated)
+                    if (tc->activated) {
+                        rx_SetConnSecondsUntilNatPing(tc->id, 0);
                         rx_DestroyConnection(tc->id);
+                       /* find another eligible connection */
+                       if (sa->natping == tc) {
+                           int cin;
+                           struct afs_conn *tcn;
+                           for (tcvn = sa->conns; tcvn; tcvn = tcvn->next) {
+                               if (tcvn == tcv)
+                                   continue;
+                               for(cin = 0; cin < CVEC_LEN; ++cin) {
+                                   tcn = &(tcvn->cvec[cin]);
+                                   if (tcn->activated) {
+                                       rx_SetConnSecondsUntilNatPing(tcn->id, 20);
+                                       sa->natping = tcn;
+                                       break;
+                                   }
+                               }
+                           }
+                       }
+                    }
                 }
                 if (glocked)
                     AFS_GLOCK();
@@ -161,26 +180,32 @@ release_conns_user_server(struct unixuser *xu, struct server *xs)
 
 
 static void
-release_conns_vector(struct sa_conn_vector *xcv)
+release_conns_vector(struct sa_conn_vector *tcv)
 {
     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;
+    struct sa_conn_vector *next;
+
+    while (tcv != NULL) {
+       next = 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 (tc->activated) {
+                rx_SetConnSecondsUntilNatPing(tc->id, 0);
+                rx_DestroyConnection(tc->id);
+               if (tcv->srvr->natping == tc)
+                   tcv->srvr->natping = NULL;
+            }
         }
         if (glocked)
             AFS_GLOCK();
         afs_osi_Free(tcv, sizeof(struct sa_conn_vector));
+       tcv = next;
     }
 
 }        /* release_conns_vector */
@@ -255,6 +280,7 @@ afs_Conn(struct VenusFid *afid, struct vrequest *areq,
     int notbusy;
     int i;
     struct srvAddr *sa1p;
+    afs_int32 replicated = -1; /* a single RO will increment to 0 */
 
     *rxconn = NULL;
 
@@ -277,6 +303,7 @@ afs_Conn(struct VenusFid *afid, struct vrequest *areq,
 
     /* First is always lowest rank, if it's up */
     if ((tv->status[0] == not_busy) && tv->serverHost[0]
+       && tv->serverHost[0]->addr
        && !(tv->serverHost[0]->addr->sa_flags & SRVR_ISDOWN) &&
        !(((areq->idleError > 0) || (areq->tokenError > 0))
          && (areq->skipserver[0] == 1)))
@@ -291,6 +318,8 @@ afs_Conn(struct VenusFid *afid, struct vrequest *areq,
      */
     for (notbusy = not_busy; (!lowp && (notbusy <= end_not_busy)); notbusy++) {
        for (i = 0; i < AFS_MAXHOSTS && tv->serverHost[i]; i++) {
+           if (tv->states & VRO)
+               replicated++;
            if (((areq->tokenError > 0)||(areq->idleError > 0))
                && (areq->skipserver[i] == 1))
                continue;
@@ -312,12 +341,20 @@ afs_Conn(struct VenusFid *afid, struct vrequest *areq,
            }
        }
     }
+    if ((replicated == -1) && (tv->states & VRO)) {
+       for (i = 0; i < AFS_MAXHOSTS && tv->serverHost[i]; i++) {
+           if (tv->states & VRO)
+               replicated++;
+       }
+    } else
+       replicated = 0;
+
     afs_PutVolume(tv, READ_LOCK);
 
     if (lowp) {
        tu = afs_GetUser(areq->uid, afid->Cell, SHARED_LOCK);
        tconn = afs_ConnBySA(lowp, fsport, afid->Cell, tu, 0 /*!force */ ,
-                            1 /*create */ , locktype, rxconn);
+                            1 /*create */ , locktype, replicated, rxconn);
 
        afs_PutUser(tu, SHARED_LOCK);
     }
@@ -335,6 +372,7 @@ afs_Conn(struct VenusFid *afid, struct vrequest *areq,
  * @param tu Connect as this user.
  * @param force_if_down
  * @param create
+ * @param replicated
  * @param locktype Specifies type of lock to be used for this function.
  *
  * @return The new connection.
@@ -342,7 +380,8 @@ afs_Conn(struct VenusFid *afid, struct vrequest *areq,
 struct afs_conn *
 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 rx_connection **rxconn)
+            afs_int32 locktype, afs_int32 replicated,
+            struct rx_connection **rxconn)
 {
     int glocked, foundvec;
     struct afs_conn *tc = NULL;
@@ -350,6 +389,7 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
     struct rx_securityClass *csec; /*Security class object */
     int isec; /*Security index */
     int service;
+    int isrep = (replicated > 0)?CONN_REPLICATED:0;
 
     *rxconn = NULL;
 
@@ -357,7 +397,8 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
     ObtainSharedLock(&afs_xconn, 15);
     foundvec = 0;
     for (tcv = sap->conns; tcv; tcv = tcv->next) {
-        if (tcv->user == tu && tcv->port == aport) {
+        if (tcv->user == tu && tcv->port == aport &&
+           (isrep == (tcv->flags & CONN_REPLICATED))) {
             /* return most eligible conn */
             if (!foundvec)
                 foundvec = 1;
@@ -394,6 +435,8 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
         tcv->port = aport;
         tcv->srvr = sap;
         tcv->next = sap->conns;
+       if (isrep)
+           tcv->flags |= CONN_REPLICATED;
         sap->conns = tcv;
 
         /* all struct afs_conn ptrs come from here */
@@ -410,6 +453,18 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
         return NULL;
     }
 
+    if (tc->refCount > 10000) {
+       static int warned;
+       if (!warned) {
+           warned = 1;
+           afs_warn("afs: Very high afs_conn refCount detected (conn %p, count %d)\n",
+                    tc, (int)tc->refCount);
+           afs_warn("afs: Trying to continue, but this may indicate an issue\n");
+           afs_warn("afs: that may eventually crash the machine. Please file\n");
+           afs_warn("afs: a bug report.\n");
+       }
+    }
+
     if (tu->states & UTokensBad) {
        /* we may still have an authenticated RPC connection here,
         * we'll have to create a new, unauthenticated, connection.
@@ -418,7 +473,7 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
         * bad, but that's somewhat trickier, due to locking
         * constraints (though not impossible).
         */
-       if (tc->id && (rx_SecurityClassOf(tc->id) != 0)) {
+       if (tc->id && (rx_SecurityClassOf(tc->id) != RX_SECIDX_NULL)) {
            tc->forceConnectFS = 1;     /* force recreation of connection */
        }
        tu->states &= ~UHasTokens;      /* remove the authentication info */
@@ -427,11 +482,13 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
     glocked = ISAFS_GLOCK();
     if (tc->forceConnectFS) {
        UpgradeSToWLock(&afs_xconn, 38);
-       csec = (struct rx_securityClass *)0;
        if (tc->id) {
+           if (sap->natping == tc)
+               sap->natping = NULL;
            if (glocked)
                 AFS_GUNLOCK();
-           rx_DestroyConnection(tc->id);
+            rx_SetConnSecondsUntilNatPing(tc->id, 0);
+            rx_DestroyConnection(tc->id);
            if (glocked)
                 AFS_GLOCK();
        }
@@ -455,18 +512,21 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
        if (service == 52) {
            rx_SetConnHardDeadTime(tc->id, afs_rx_harddead);
        }
-       /* set to a RX_CALL_TIMEOUT error to allow MTU retry to trigger */
-       rx_SetServerConnIdleDeadErr(tc->id, RX_CALL_DEAD);
-       rx_SetConnIdleDeadTime(tc->id, afs_rx_idledead);
-       rx_SetMsgsizeRetryErr(tc->id, RX_MSGSIZE);
+
+        /* Setting idle dead time to non-zero activates idle-dead
+        * RX_CALL_TIMEOUT errors. */
+       if (isrep)
+           rx_SetConnIdleDeadTime(tc->id, afs_rx_idledead_rep);
+       else
+           rx_SetConnIdleDeadTime(tc->id, afs_rx_idledead);
 
        /*
-        * Only do this for the base connection, not per-user.
-        * Will need to be revisited if/when CB gets security.
+        * Only do this for one connection
         */
-       if ((isec == 0) && (service != 52) && !(tu->states & UTokensBad) &&
-           (tu->viceId == UNDEFVID))
+       if ((service != 52) && (sap->natping == NULL)) {
+           sap->natping = tc;
            rx_SetConnSecondsUntilNatPing(tc->id, 20);
+       }
 
        tc->forceConnectFS = 0; /* apparently we're appropriately connected now */
        if (csec)
@@ -494,13 +554,14 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
  * @param areq The request.
  * @param aforce Force connection?
  * @param locktype Type of lock to be used.
+ * @param replicated
  *
  * @return The established connection.
  */
 struct afs_conn *
 afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell,
               struct vrequest *areq, int aforce, afs_int32 locktype,
-              struct rx_connection **rxconn)
+              afs_int32 replicated, struct rx_connection **rxconn)
 {
     struct unixuser *tu;
     struct afs_conn *tc = NULL;
@@ -526,7 +587,7 @@ afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell,
     for (sa = aserver->addr; sa; sa = sa->next_sa) {
        tc = afs_ConnBySA(sa, aport, acell, tu, aforce,
                          0 /*don't create one */ ,
-                         locktype, rxconn);
+                         locktype, replicated, rxconn);
        if (tc)
            break;
     }
@@ -535,7 +596,7 @@ afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell,
        for (sa = aserver->addr; sa; sa = sa->next_sa) {
            tc = afs_ConnBySA(sa, aport, acell, tu, aforce,
                              1 /*create one */ ,
-                             locktype, rxconn);
+                             locktype, replicated, rxconn);
            if (tc)
                break;
        }
@@ -556,13 +617,15 @@ afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell,
  * @param acell The cell where all of this happens.
  * @param areq The request.
  * @param locktype Type of lock to be used.
+ * @param replicated
  *
  * @return The established connection or NULL.
  */
 struct afs_conn *
 afs_ConnByMHosts(struct server *ahosts[], unsigned short aport,
                 afs_int32 acell, struct vrequest *areq,
-                afs_int32 locktype, struct rx_connection **rxconn)
+                afs_int32 locktype, afs_int32 replicated,
+                struct rx_connection **rxconn)
 {
     afs_int32 i;
     struct afs_conn *tconn;
@@ -575,7 +638,8 @@ afs_ConnByMHosts(struct server *ahosts[], unsigned short aport,
     for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
        if ((ts = ahosts[i]) == NULL)
            break;
-       tconn = afs_ConnByHost(ts, aport, acell, areq, 0, locktype, rxconn);
+       tconn = afs_ConnByHost(ts, aport, acell, areq, 0, locktype,
+                              replicated, rxconn);
        if (tconn) {
            return tconn;
        }
@@ -597,22 +661,8 @@ afs_PutConn(struct afs_conn *ac, struct rx_connection *rxconn,
     AFS_STATCNT(afs_PutConn);
     ac->refCount--;
     if (ac->refCount < 0) {
-       static int warned = 0;
-       /* So, someone is 'put'ing more refs than they got. From now on, we
-        * have no idea if the structure is actually still in use, so just
-        * set the refcount to a really negative number to make it unlikely
-        * that the count will ever reach 0 and the conn gets freed. This
-        * leaks memory, but the alternative is panicing, or risking memory
-        * corruption. */
-       ac->refCount = -10000;
-       if (!warned) {
-           warned = 1;
-           afs_warn("afs_PutConn: negative refCount with 0x%lx; this should "
-                    "not ever happen! Trying to carry on anyway, but please "
-                    "report this issue\n",
-                    (unsigned long)(uintptrsz)ac);
-       }
-       return;
+       osi_Panic("afs_PutConn: refcount imbalance 0x%lx %d",
+                 (unsigned long)(uintptrsz)ac, (int)ac->refCount);
     }
     ac->parent->refCount--;
     rx_PutConnection(rxconn);