rx: Skip rxi_CheckPeerDead if we are DALLY
[openafs.git] / src / rx / rx.c
index 53db0a3..52de6be 100644 (file)
@@ -67,6 +67,8 @@ extern afs_int32 afs_termState;
 #  include <WINNT\afsreg.h>
 # endif
 
+# include <afs/opr.h>
+
 # include "rx_user.h"
 #endif /* KERNEL */
 
@@ -1626,6 +1628,13 @@ rx_NewCall(struct rx_connection *conn)
     else
        call->mode = RX_MODE_SENDING;
 
+#ifdef AFS_RXERRQ_ENV
+    /* remember how many network errors the peer has when we started, so if
+     * more errors are encountered after the call starts, we know the other endpoint won't be
+     * responding to us */
+    call->neterr_gen = rx_atomic_read(&conn->peer->neterrs);
+#endif
+
     /* remember start time for call in case we have hard dead time limit */
     call->queueTime = queueTime;
     clock_GetTime(&call->startTime);
@@ -2910,6 +2919,51 @@ rxi_SetPeerMtu(struct rx_peer *peer, afs_uint32 host, afs_uint32 port, int mtu)
     MUTEX_EXIT(&rx_peerHashTable_lock);
 }
 
+#ifdef AFS_RXERRQ_ENV
+static void
+rxi_SetPeerDead(afs_uint32 host, afs_uint16 port)
+{
+    int hashIndex = PEER_HASH(host, port);
+    struct rx_peer *peer;
+
+    MUTEX_ENTER(&rx_peerHashTable_lock);
+
+    for (peer = rx_peerHashTable[hashIndex]; peer; peer = peer->next) {
+       if (peer->host == host && peer->port == port) {
+           break;
+       }
+    }
+
+    if (peer) {
+       rx_atomic_inc(&peer->neterrs);
+    }
+
+    MUTEX_EXIT(&rx_peerHashTable_lock);
+}
+
+void
+rxi_ProcessNetError(struct sock_extended_err *err, afs_uint32 addr, afs_uint16 port)
+{
+# ifdef AFS_ADAPT_PMTU
+    if (err->ee_errno == EMSGSIZE && err->ee_info >= 68) {
+       rxi_SetPeerMtu(NULL, addr, port, err->ee_info - RX_IPUDP_SIZE);
+       return;
+    }
+# endif
+    if (err->ee_origin == SO_EE_ORIGIN_ICMP && err->ee_type == ICMP_DEST_UNREACH) {
+       switch (err->ee_code) {
+       case ICMP_NET_UNREACH:
+       case ICMP_HOST_UNREACH:
+       case ICMP_PORT_UNREACH:
+       case ICMP_NET_ANO:
+       case ICMP_HOST_ANO:
+           rxi_SetPeerDead(addr, port);
+           break;
+       }
+    }
+}
+#endif /* AFS_RXERRQ_ENV */
+
 /* Find the peer process represented by the supplied (host,port)
  * combination.  If there is no appropriate active peer structure, a
  * new one will be allocated and initialized
@@ -2933,6 +2987,9 @@ rxi_FindPeer(afs_uint32 host, u_short port,
            pp = rxi_AllocPeer();       /* This bzero's *pp */
            pp->host = host;    /* set here or in InitPeerParams is zero */
            pp->port = port;
+#ifdef AFS_RXERRQ_ENV
+           rx_atomic_set(&pp->neterrs, 0);
+#endif
            MUTEX_INIT(&pp->peer_lock, "peer_lock", MUTEX_DEFAULT, 0);
            queue_Init(&pp->rpcStats);
            pp->next = rx_peerHashTable[hashIndex];
@@ -3200,6 +3257,11 @@ rxi_ReceivePacket(struct rx_packet *np, osi_socket socket,
         */
 
        if (peer && (peer->refCount > 0)) {
+#ifdef AFS_RXERRQ_ENV
+           if (rx_atomic_read(&peer->neterrs)) {
+               rx_atomic_set(&peer->neterrs, 0);
+           }
+#endif
            MUTEX_ENTER(&peer->peer_lock);
            peer->bytesReceived += np->length;
            MUTEX_EXIT(&peer->peer_lock);
@@ -3254,6 +3316,12 @@ rxi_ReceivePacket(struct rx_packet *np, osi_socket socket,
         return np;
     }
 
+#ifdef AFS_RXERRQ_ENV
+    if (rx_atomic_read(&conn->peer->neterrs)) {
+       rx_atomic_set(&conn->peer->neterrs, 0);
+    }
+#endif
+
     /* If we're doing statistics, then account for the incoming packet */
     if (rx_stats_active) {
        MUTEX_ENTER(&conn->peer->peer_lock);
@@ -5873,6 +5941,50 @@ rxi_SendXmitList(struct rx_call *call, struct rx_packet **list, int len,
     }
 }
 
+/**
+ * Check if the peer for the given call is known to be dead
+ *
+ * If the call's peer appears dead (it has encountered fatal network errors
+ * since the call started) the call is killed with RX_CALL_DEAD if the call
+ * is active. Otherwise, we do nothing.
+ *
+ * @param[in] call  The call to check
+ *
+ * @return status
+ *  @retval 0 The call is fine, and we haven't done anything to the call
+ *  @retval nonzero The call's peer appears dead, and the call has been
+ *                  terminated if it was active
+ *
+ * @pre call->lock must be locked
+ */
+static int
+rxi_CheckPeerDead(struct rx_call *call)
+{
+#ifdef AFS_RXERRQ_ENV
+    int peererrs;
+
+    if (call->state == RX_STATE_DALLY) {
+       return 0;
+    }
+
+    peererrs = rx_atomic_read(&call->conn->peer->neterrs);
+    if (call->neterr_gen < peererrs) {
+       /* we have received network errors since this call started; kill
+        * the call */
+       if (call->state == RX_STATE_ACTIVE) {
+           rxi_CallError(call, RX_CALL_DEAD);
+       }
+       return -1;
+    }
+    if (call->neterr_gen > peererrs) {
+       /* someone has reset the number of peer errors; set the call error gen
+        * so we can detect if more errors are encountered */
+       call->neterr_gen = peererrs;
+    }
+#endif
+    return 0;
+}
+
 static void
 rxi_Resend(struct rxevent *event, void *arg0, void *arg1, int istack)
 {
@@ -5894,6 +6006,8 @@ rxi_Resend(struct rxevent *event, void *arg0, void *arg1, int istack)
        call->resendEvent = NULL;
     }
 
+    rxi_CheckPeerDead(call);
+
     if (rxi_busyChannelError && (call->flags & RX_CALL_PEER_BUSY)) {
        rxi_CheckBusy(call);
     }
@@ -6179,6 +6293,10 @@ rxi_CheckCall(struct rx_call *call)
     int idle_timeout = 0;
     afs_int32  clock_diff = 0;
 
+    if (rxi_CheckPeerDead(call)) {
+       return -1;
+    }
+
     now = clock_Sec();
 
     /* Large swings in the clock can have a significant impact on
@@ -6221,7 +6339,7 @@ rxi_CheckCall(struct rx_call *call)
      * number of seconds. */
     if (now > (call->lastReceiveTime + deadTime)) {
        if (call->state == RX_STATE_ACTIVE) {
-#ifdef ADAPT_PMTU
+#ifdef AFS_ADAPT_PMTU
 # if defined(KERNEL) && defined(AFS_SUN5_ENV)
            ire_t *ire;
 #  if defined(AFS_SUN510_ENV) && defined(GLOBAL_NETSTACKID)
@@ -6247,7 +6365,7 @@ rxi_CheckCall(struct rx_call *call)
            netstack_rele(ns);
 #  endif
 # endif
-#endif /* ADAPT_PMTU */
+#endif /* AFS_ADAPT_PMTU */
            cerror = RX_CALL_DEAD;
            goto mtuout;
        } else {