Rx: rxi_FreeCall conn_call_lock vs call->lock deadlock
[openafs.git] / src / rx / rx.c
index f62ffd1..f4037af 100644 (file)
@@ -2677,16 +2677,16 @@ rxi_NewCall(struct rx_connection *conn, int channel)
  *
  * call->lock amd rx_refcnt_mutex are held upon entry.
  * haveCTLock is set when called from rxi_ReapConnections.
+ *
+ * return 1 if the call is freed, 0 if not.
  */
-static void
+static int
 rxi_FreeCall(struct rx_call *call, int haveCTLock)
 {
     int channel = call->channel;
     struct rx_connection *conn = call->conn;
+    u_char state = call->state;
 
-
-    if (call->state == RX_STATE_DALLY || call->state == RX_STATE_HOLD)
-       (*call->callNumber)++;
     /*
      * We are setting the state to RX_STATE_RESET to
      * ensure that no one else will attempt to use this
@@ -2699,10 +2699,24 @@ rxi_FreeCall(struct rx_call *call, int haveCTLock)
     MUTEX_EXIT(&rx_refcnt_mutex);
     rxi_ResetCall(call, 0);
 
-    MUTEX_ENTER(&conn->conn_call_lock);
-    if (call->conn->call[channel] == call)
-        call->conn->call[channel] = 0;
-    MUTEX_EXIT(&conn->conn_call_lock);
+    if (MUTEX_TRYENTER(&conn->conn_call_lock))
+    {
+        if (state == RX_STATE_DALLY || state == RX_STATE_HOLD)
+            (*call->callNumber)++;
+
+        if (call->conn->call[channel] == call)
+            call->conn->call[channel] = 0;
+        MUTEX_EXIT(&conn->conn_call_lock);
+    } else {
+        /*
+         * We couldn't obtain the conn_call_lock so we can't
+         * disconnect the call from the connection.  Set the
+         * call state to dally so that the call can be reused.
+         */
+        MUTEX_ENTER(&rx_refcnt_mutex);
+        call->state = RX_STATE_DALLY;
+        return 0;
+    }
 
     MUTEX_ENTER(&rx_freeCallQueue_lock);
     SET_CALL_QUEUE_LOCK(call, &rx_freeCallQueue_lock);
@@ -2752,6 +2766,7 @@ rxi_FreeCall(struct rx_call *call, int haveCTLock)
        MUTEX_EXIT(&conn->conn_data_lock);
     }
     MUTEX_ENTER(&rx_refcnt_mutex);
+    return 1;
 }
 
 rx_atomic_t rxi_Allocsize = RX_ATOMIC_INIT(0);
@@ -6143,6 +6158,31 @@ rxi_CheckCall(struct rx_call *call)
     int cerror = 0;
     int newmtu = 0;
     int idle_timeout = 0;
+    afs_int32  clock_diff = 0;
+
+    now = clock_Sec();
+
+    /* Large swings in the clock can have a significant impact on
+     * the performance of RX call processing.  Forward clock shifts
+     * will result in premature event triggering or timeouts.
+     * Backward shifts can result in calls not completing until
+     * the clock catches up with the original start clock value.
+     *
+     * If a backward clock shift of more than five minutes is noticed,
+     * just fail the call.
+     */
+    if (now < call->lastSendTime)
+        clock_diff = call->lastSendTime - now;
+    if (now < call->startWait)
+        clock_diff = MAX(clock_diff, call->startWait - now);
+    if (now < call->lastReceiveTime)
+        clock_diff = MAX(clock_diff, call->lastReceiveTime - now);
+    if (clock_diff > 5 * 60)
+    {
+       if (call->state == RX_STATE_ACTIVE)
+           rxi_CallError(call, RX_CALL_TIMEOUT);
+       return -1;
+    }
 
 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
     if (call->flags & RX_CALL_TQ_BUSY) {
@@ -6157,7 +6197,6 @@ rxi_CheckCall(struct rx_call *call)
                    ((afs_uint32) call->rtt_dev << 1) + 1023) >> 10;
 
     deadTime = conn->secondsUntilDead + fudgeFactor;
-    now = clock_Sec();
     /* These are computed to the second (+- 1 second).  But that's
      * good enough for these values, which should be a significant
      * number of seconds. */
@@ -6203,10 +6242,12 @@ rxi_CheckCall(struct rx_call *call)
            rxevent_Cancel(&call->growMTUEvent, call,
                           RX_CALL_REFCOUNT_ALIVE);
             MUTEX_ENTER(&rx_refcnt_mutex);
-           if (call->refCount == 0) {
-               rxi_FreeCall(call, haveCTLock);
+            /* if rxi_FreeCall returns 1 it has freed the call */
+           if (call->refCount == 0 &&
+                rxi_FreeCall(call, haveCTLock))
+            {
                 MUTEX_EXIT(&rx_refcnt_mutex);
-               return -2;
+                return -2;
            }
             MUTEX_EXIT(&rx_refcnt_mutex);
            return -1;