rx-init-mutex-before-calling-getudpsocket-20030313
[openafs.git] / src / rx / rx.c
index 4651215..8412813 100644 (file)
@@ -256,7 +256,6 @@ assert(pthread_once(&rx_once_init, rxi_InitPthread)==0);
  */
 
 #ifdef RX_ENABLE_LOCKS
-static int rxi_ServerThreadSelectingCall;
 static afs_kmutex_t rx_rpc_stats;
 void rxi_StartUnlocked();
 #endif
@@ -399,6 +398,8 @@ int rx_Init(u_int port)
     rxi_InitializeThreadSupport();
 #endif
 
+    MUTEX_INIT(&rx_stats_mutex, "rx_stats_mutex",MUTEX_DEFAULT,0);
+
     /* Allocate and initialize a socket for client and perhaps server
      * connections. */
 
@@ -413,7 +414,6 @@ int rx_Init(u_int port)
 #ifdef RX_LOCKS_DB
     rxdb_init();
 #endif /* RX_LOCKS_DB */
-    MUTEX_INIT(&rx_stats_mutex, "rx_stats_mutex",MUTEX_DEFAULT,0);
     MUTEX_INIT(&rx_rpc_stats, "rx_rpc_stats",MUTEX_DEFAULT,0);
     MUTEX_INIT(&rx_freePktQ_lock, "rx_freePktQ_lock",MUTEX_DEFAULT,0);
     MUTEX_INIT(&freeSQEList_lock, "freeSQEList lock",MUTEX_DEFAULT,0);
@@ -426,13 +426,12 @@ int rx_Init(u_int port)
 #ifndef KERNEL
     MUTEX_INIT(&rxi_keyCreate_lock, "rxi_keyCreate_lock", MUTEX_DEFAULT, 0);
 #endif /* !KERNEL */
-    CV_INIT(&rx_serverPool_cv, "rx_serverPool_cv",CV_DEFAULT, 0);
 #if defined(KERNEL) && defined(AFS_HPUX110_ENV)
     if ( !uniprocessor )
       rx_sleepLock = alloc_spinlock(LAST_HELD_ORDER-10, "rx_sleepLock");
 #endif /* KERNEL && AFS_HPUX110_ENV */
 #else /* RX_ENABLE_LOCKS */
-#if defined(KERNEL) && defined(AFS_GLOBAL_SUNLOCK) && !defined(AFS_HPUX_ENV)
+#if defined(KERNEL) && defined(AFS_GLOBAL_SUNLOCK) && !defined(AFS_HPUX_ENV) && !defined(AFS_OBSD_ENV)
     mutex_init(&afs_rxglobal_lock, "afs_rxglobal_lock", MUTEX_DEFAULT, NULL);
 #endif /* AFS_GLOBAL_SUNLOCK */
 #endif /* RX_ENABLE_LOCKS */
@@ -635,7 +634,7 @@ void rxi_StartServerProcs(int nExistingProcs)
 void rx_StartServer(int donateMe)
 {
     register struct rx_service *service;
-    register int i;
+    register int i, nProcs=0;
     SPLVAR;
     clock_NewTime();
 
@@ -896,7 +895,7 @@ static void rxi_DestroyConnectionNoLock(register struct rx_connection *conn)
                                   RX_CALL_REFCOUNT_DELAY);
                    if (call->state == RX_STATE_PRECALL ||
                        call->state == RX_STATE_ACTIVE) {
-                       rxi_SendAck(call, 0, 0, 0, 0, RX_ACK_DELAY, 0);
+                       rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
                    } else {
                        rxi_AckAll(NULL, call, 0);
                    }
@@ -1395,7 +1394,7 @@ void rx_WakeupServerProcs(void)
 struct rx_call *rx_GetCall(int tno, struct rx_service *cur_service, osi_socket *socketp)
 {
     struct rx_serverQueueEntry *sq;
-    register struct rx_call *call = (struct rx_call *) 0, *choice2;
+    register struct rx_call *call = (struct rx_call *) 0;
     struct rx_service *service = NULL;
     SPLVAR;
 
@@ -1417,8 +1416,8 @@ struct rx_call *rx_GetCall(int tno, struct rx_service *cur_service, osi_socket *
     }
     while (1) {
        if (queue_IsNotEmpty(&rx_incomingCallQueue)) {
-           register struct rx_call *tcall, *ncall;
-           choice2 = (struct rx_call *) 0;
+           register struct rx_call *tcall, *ncall, *choice2 = NULL;
+
            /* Scan for eligible incoming calls.  A call is not eligible
             * if the maximum number of calls for its service type are
             * already executing */
@@ -1427,66 +1426,61 @@ struct rx_call *rx_GetCall(int tno, struct rx_service *cur_service, osi_socket *
             * have all their input data available immediately.  This helps 
             * keep threads from blocking, waiting for data from the client. */
            for (queue_Scan(&rx_incomingCallQueue, tcall, ncall, rx_call)) {
-             service = tcall->conn->service;
-             if (!QuotaOK(service)) {
-               continue;
-             }
-             if (!tno || !tcall->queue_item_header.next  ) {
-               /* If we're thread 0, then  we'll just use 
-                * this call. If we haven't been able to find an optimal 
-                * choice, and we're at the end of the list, then use a 
-                * 2d choice if one has been identified.  Otherwise... */
-               call = (choice2 ? choice2 : tcall);
-               service = call->conn->service;
-             } else if (!queue_IsEmpty(&tcall->rq)) {
-               struct rx_packet *rp;
-               rp = queue_First(&tcall->rq, rx_packet);
-               if (rp->header.seq == 1) {
-                 if (!meltdown_1pkt ||             
-                     (rp->header.flags & RX_LAST_PACKET)) {
-                   call = tcall;
-                 } else if (rxi_2dchoice && !choice2 &&
-                            !(tcall->flags & RX_CALL_CLEARED) &&
-                            (tcall->rprev > rxi_HardAckRate)) {
-                   choice2 = tcall;
-                 } else rxi_md2cnt++;
+               service = tcall->conn->service;
+               if (!QuotaOK(service)) {
+                   continue;
+               }
+               if (tno==rxi_fcfs_thread_num || !tcall->queue_item_header.next  ) {
+                   /* If we're the fcfs thread , then  we'll just use 
+                    * this call. If we haven't been able to find an optimal 
+                    * choice, and we're at the end of the list, then use a 
+                    * 2d choice if one has been identified.  Otherwise... */
+                   call = (choice2 ? choice2 : tcall);
+                   service = call->conn->service;
+               } else if (!queue_IsEmpty(&tcall->rq)) {
+                   struct rx_packet *rp;
+                   rp = queue_First(&tcall->rq, rx_packet);
+                   if (rp->header.seq == 1) {
+                       if (!meltdown_1pkt ||
+                           (rp->header.flags & RX_LAST_PACKET)) {
+                           call = tcall;
+                       } else if (rxi_2dchoice && !choice2 &&
+                                  !(tcall->flags & RX_CALL_CLEARED) &&
+                                  (tcall->rprev > rxi_HardAckRate)) {
+                           choice2 = tcall;
+                       } else rxi_md2cnt++;
+                   }
+               }
+               if (call) {
+                   break;
+               } else {
+                   ReturnToServerPool(service);
                }
-             }
-             if (call)  {
-               break;
-             } else {
-                 ReturnToServerPool(service);
-             }
            }
-         }
+       }
 
        if (call) {
            queue_Remove(call);
-           rxi_ServerThreadSelectingCall = 1;
            MUTEX_EXIT(&rx_serverPool_lock);
            MUTEX_ENTER(&call->lock);
-           MUTEX_ENTER(&rx_serverPool_lock);
-
-           if (queue_IsEmpty(&call->rq) ||
-               queue_First(&call->rq, rx_packet)->header.seq != 1)
-             rxi_SendAck(call, 0, 0, 0, 0, RX_ACK_DELAY, 0);
 
-           CLEAR_CALL_QUEUE_LOCK(call);
-           if (call->error) {
+           if (call->state != RX_STATE_PRECALL || call->error) {
                MUTEX_EXIT(&call->lock);
+               MUTEX_ENTER(&rx_serverPool_lock);
                ReturnToServerPool(service);
-               rxi_ServerThreadSelectingCall = 0;
-               CV_SIGNAL(&rx_serverPool_cv);
-               call = (struct rx_call*)0;
+               call = NULL;
                continue;
            }
-           call->flags &= (~RX_CALL_WAIT_PROC);
+
+           if (queue_IsEmpty(&call->rq) ||
+               queue_First(&call->rq, rx_packet)->header.seq != 1)
+               rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
+
+           CLEAR_CALL_QUEUE_LOCK(call);
+           call->flags &= ~RX_CALL_WAIT_PROC;
            MUTEX_ENTER(&rx_stats_mutex);
            rx_nWaiting--;
            MUTEX_EXIT(&rx_stats_mutex);
-           rxi_ServerThreadSelectingCall = 0;
-           CV_SIGNAL(&rx_serverPool_cv);
-           MUTEX_EXIT(&rx_serverPool_lock);
            break;
        }
        else {
@@ -1585,8 +1579,8 @@ struct rx_call *rx_GetCall(int tno, struct rx_service *cur_service, osi_socket *
        for (queue_Scan(&rx_incomingCallQueue, tcall, ncall, rx_call)) {
          service = tcall->conn->service;
          if (QuotaOK(service)) {
-            if (!tno || !tcall->queue_item_header.next  ) {
-                /* If we're thread 0, then  we'll just use 
+            if (tno==rxi_fcfs_thread_num || !tcall->queue_item_header.next  ) {
+                /* If we're the fcfs thread, then  we'll just use 
                  * this call. If we haven't been able to find an optimal 
                  * choice, and we're at the end of the list, then use a 
                  * 2d choice if one has been identified.  Otherwise... */
@@ -1620,7 +1614,7 @@ struct rx_call *rx_GetCall(int tno, struct rx_service *cur_service, osi_socket *
        if (queue_IsEmpty(&call->rq) ||
            queue_First(&call->rq, rx_packet)->header.seq != 1 ||
            call->rprev != queue_Last(&call->rq, rx_packet)->header.seq)
-         rxi_SendAck(call, 0, 0, 0, 0, RX_ACK_DELAY, 0);
+         rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
 
        call->flags &= (~RX_CALL_WAIT_PROC);
        service->nRequestsRunning++;
@@ -2207,7 +2201,6 @@ struct rx_connection *rxi_FindConnection(osi_socket socket,
 {
     int hashindex, flag;
     register struct rx_connection *conn;
-    struct rx_peer *peer;
     hashindex = CONN_HASH(host, port, cid, epoch, type);
     MUTEX_ENTER(&rx_connHashTable_lock);
     rxLastConn ? (conn = rxLastConn, flag = 0) :
@@ -2224,13 +2217,12 @@ struct rx_connection *rxi_FindConnection(osi_socket socket,
            MUTEX_EXIT(&rx_connHashTable_lock);
            return (struct rx_connection *) 0;
        }
-       /* epoch's high order bits mean route for security reasons only on
-        * the cid, not the host and port fields.
-        */
-       if (conn->epoch & 0x80000000) break;
-       if (((type == RX_CLIENT_CONNECTION) 
-            || (pp->host == host)) && (pp->port == port))
-         break;
+       if (pp->host == host && pp->port == port)
+           break;
+       if (type == RX_CLIENT_CONNECTION && pp->port == port)
+           break;
+       if (type == RX_CLIENT_CONNECTION && (conn->epoch & 0x80000000))
+           break;
       }
       if ( !flag )
       {
@@ -2262,7 +2254,7 @@ struct rx_connection *rxi_FindConnection(osi_socket socket,
        CV_INIT(&conn->conn_call_cv, "conn call cv", CV_DEFAULT, 0);
        conn->next = rx_connHashTable[hashindex];
        rx_connHashTable[hashindex] = conn;
-       peer = conn->peer = rxi_FindPeer(host, port, 0, 1);
+       conn->peer = rxi_FindPeer(host, port, 0, 1);
        conn->type = RX_SERVER_CONNECTION;
        conn->lastSendTime = clock_Sec();   /* don't GC immediately */
        conn->epoch = epoch;
@@ -2277,6 +2269,7 @@ struct rx_connection *rxi_FindConnection(osi_socket socket,
        conn->nSpecific = 0;
        conn->specific = NULL;
        rx_SetConnDeadTime(conn, service->connDeadTime);
+       rx_SetConnIdleDeadTime(conn, service->idleDeadTime);
        /* Notify security object of the new connection */
        RXS_NewConnection(conn->securityObject, conn);
        /* XXXX Connection timeout? */
@@ -2285,27 +2278,9 @@ struct rx_connection *rxi_FindConnection(osi_socket socket,
        rx_stats.nServerConns++;
        MUTEX_EXIT(&rx_stats_mutex);
     }
-    else
-    {
-    /* Ensure that the peer structure is set up in such a way that
-    ** replies in this connection go back to that remote interface
-    ** from which the last packet was sent out. In case, this packet's
-    ** source IP address does not match the peer struct for this conn,
-    ** then drop the refCount on conn->peer and get a new peer structure.
-    ** We can check the host,port field in the peer structure without the
-    ** rx_peerHashTable_lock because the peer structure has its refCount
-    ** incremented and the only time the host,port in the peer struct gets
-    ** updated is when the peer structure is created.
-    */
-       if (conn->peer->host == host )
-               peer = conn->peer; /* no change to the peer structure */
-       else
-               peer = rxi_FindPeer(host, port, conn->peer, 1);
-    }
 
     MUTEX_ENTER(&conn->conn_data_lock);
     conn->refCount++;
-    conn->peer = peer;
     MUTEX_EXIT(&conn->conn_data_lock);
 
     rxLastConn = conn; /* store this connection as the last conn used */
@@ -2728,8 +2703,11 @@ struct rx_packet *rxi_ReceivePacket(register struct rx_packet *np,
            /* Respond immediately to ack packets requesting acknowledgement
              * (ping packets) */
            if (np->header.flags & RX_REQUEST_ACK) {
-               if (call->error) (void) rxi_SendCallAbort(call, 0, 1, 0);
-               else (void) rxi_SendAck(call, 0, 0, 0, 0, RX_ACK_PING_RESPONSE, 1);
+               if (call->error)
+                   (void) rxi_SendCallAbort(call, 0, 1, 0);
+               else
+                   (void) rxi_SendAck(call, 0, np->header.serial,
+                                      RX_ACK_PING_RESPONSE, 1);
            }
            np = rxi_ReceiveAckPacket(call, np, 1);
            break;
@@ -2869,7 +2847,7 @@ static void rxi_CheckReachEvent(struct rxevent *event,
 
        if (call) {
            if (call != acall) MUTEX_ENTER(&call->lock);
-           rxi_SendAck(call, NULL, 0, 0, 0, RX_ACK_PING, 0);
+           rxi_SendAck(call, NULL, 0, RX_ACK_PING, 0);
            if (call != acall) MUTEX_EXIT(&call->lock);
 
            clock_GetTime(&when);
@@ -2944,7 +2922,7 @@ struct rx_packet *rxi_ReceiveDataPacket(register struct rx_call *call,
        register struct rx_packet *np, int istack, osi_socket socket, 
        afs_uint32 host, u_short port, int *tnop, struct rx_call **newcallp)
 {
-    int ackNeeded = 0;
+    int ackNeeded = 0; /* 0 means no, otherwise ack_reason */
     int newPackets = 0;
     int didHardAck = 0;
     int haveLast = 0;
@@ -3036,8 +3014,7 @@ struct rx_packet *rxi_ReceiveDataPacket(register struct rx_call *call,
                dpf (("packet %x dropped on receipt - duplicate", np));
                rxevent_Cancel(call->delayedAckEvent, call,
                               RX_CALL_REFCOUNT_DELAY);
-               np = rxi_SendAck(call, np, seq, serial,
-                                flags, RX_ACK_DUPLICATE, istack);
+               np = rxi_SendAck(call, np, serial, RX_ACK_DUPLICATE, istack);
                ackNeeded = 0;
                call->rprev = seq;
                continue;
@@ -3054,7 +3031,7 @@ struct rx_packet *rxi_ReceiveDataPacket(register struct rx_call *call,
            /* If an ack is requested then set a flag to make sure we
             * send an acknowledgement for this packet */
            if (flags & RX_REQUEST_ACK) {
-               ackNeeded = 1;
+               ackNeeded = RX_ACK_REQUESTED;
            }
 
            /* Keep track of whether we have received the last packet */
@@ -3122,8 +3099,7 @@ struct rx_packet *rxi_ReceiveDataPacket(register struct rx_call *call,
                MUTEX_EXIT(&rx_stats_mutex);
                rxevent_Cancel(call->delayedAckEvent, call,
                               RX_CALL_REFCOUNT_DELAY);
-               np = rxi_SendAck(call, np, seq, serial,
-                                flags, RX_ACK_DUPLICATE, istack);
+               np = rxi_SendAck(call, np, serial, RX_ACK_DUPLICATE, istack);
                ackNeeded = 0;
                call->rprev = seq;
                continue;
@@ -3135,8 +3111,8 @@ struct rx_packet *rxi_ReceiveDataPacket(register struct rx_call *call,
            if ((call->rnext + call->rwind) <= seq) {
                rxevent_Cancel(call->delayedAckEvent, call,
                               RX_CALL_REFCOUNT_DELAY);
-               np = rxi_SendAck(call, np, seq, serial,
-                                flags, RX_ACK_EXCEEDS_WINDOW, istack);
+               np = rxi_SendAck(call, np, serial,
+                                RX_ACK_EXCEEDS_WINDOW, istack);
                ackNeeded = 0;
                call->rprev = seq;
                continue;
@@ -3152,8 +3128,8 @@ struct rx_packet *rxi_ReceiveDataPacket(register struct rx_call *call,
                    MUTEX_EXIT(&rx_stats_mutex);
                    rxevent_Cancel(call->delayedAckEvent, call,
                                   RX_CALL_REFCOUNT_DELAY);
-                   np = rxi_SendAck(call, np, seq, serial, 
-                                    flags, RX_ACK_DUPLICATE, istack);
+                   np = rxi_SendAck(call, np, serial, 
+                                    RX_ACK_DUPLICATE, istack);
                    ackNeeded = 0;
                    call->rprev = seq;
                    goto nextloop;
@@ -3203,7 +3179,7 @@ struct rx_packet *rxi_ReceiveDataPacket(register struct rx_call *call,
            /* We need to send an ack of the packet is out of sequence, 
             * or if an ack was requested by the peer. */
            if (seq != prev+1 || missing || (flags & RX_REQUEST_ACK)) {
-               ackNeeded = 1;
+               ackNeeded = RX_ACK_OUT_OF_SEQUENCE;
            }
 
            /* Acknowledge the last packet for each call */
@@ -3221,7 +3197,7 @@ nextloop:;
         * If the receiver is waiting for an iovec, fill the iovec
         * using the data from the receive queue */
        if (call->flags & RX_CALL_IOVEC_WAIT) {
-           didHardAck = rxi_FillReadVec(call, seq, serial, flags); 
+           didHardAck = rxi_FillReadVec(call, serial); 
            /* the call may have been aborted */
            if (call->error) {
                return NULL;
@@ -3252,12 +3228,10 @@ nextloop:;
      * the server's reply. */
     if (ackNeeded) {
        rxevent_Cancel(call->delayedAckEvent, call, RX_CALL_REFCOUNT_DELAY);
-       np = rxi_SendAck(call, np, seq, serial, flags,
-                        RX_ACK_REQUESTED, istack);
+       np = rxi_SendAck(call, np, serial, ackNeeded, istack);
     } else if (call->nSoftAcks > (u_short)rxi_SoftAckRate) {
        rxevent_Cancel(call->delayedAckEvent, call, RX_CALL_REFCOUNT_DELAY);
-       np = rxi_SendAck(call, np, seq, serial, flags,
-                        RX_ACK_IDLE, istack);
+       np = rxi_SendAck(call, np, serial, RX_ACK_IDLE, istack);
     } else if (call->nSoftAcks) {
        clock_GetTime(&when);
        if (haveLast && !(flags & RX_CLIENT_INITIATED)) {
@@ -3303,6 +3277,7 @@ static void rxi_UpdatePeerReach(struct rx_connection *conn, struct rx_call *acal
            struct rx_call *call = conn->call[i];
            if (call) {
                if (call != acall) MUTEX_ENTER(&call->lock);
+               /* tnop can be null if newcallp is null */
                TryAttach(call, (osi_socket) -1, NULL, NULL, 1);
                if (call != acall) MUTEX_EXIT(&call->lock);
            }
@@ -3311,6 +3286,27 @@ static void rxi_UpdatePeerReach(struct rx_connection *conn, struct rx_call *acal
        MUTEX_EXIT(&conn->conn_data_lock);
 }
 
+/* rxi_ComputePeerNetStats
+ *
+ * Called exclusively by rxi_ReceiveAckPacket to compute network link
+ * estimates (like RTT and throughput) based on ack packets.  Caller
+ * must ensure that the packet in question is the right one (i.e.
+ * serial number matches).
+ */
+static void
+rxi_ComputePeerNetStats(struct rx_call *call, struct rx_packet *p,
+       struct rx_ackPacket *ap, struct rx_packet *np)
+{
+    struct rx_peer *peer = call->conn->peer;
+
+    /* Use RTT if not delayed by client. */
+    if (ap->reason != RX_ACK_DELAY)
+       rxi_ComputeRoundTripTime(p, &p->timeSent, peer);
+#ifdef ADAPT_WINDOW
+    rxi_ComputeRate(peer, call, p, np, ap->reason);
+#endif
+}
+
 /* The real smarts of the whole thing.  */
 struct rx_packet *rxi_ReceiveAckPacket(register struct rx_call *call, 
        struct rx_packet *np, int istack)
@@ -3376,15 +3372,6 @@ struct rx_packet *rxi_ReceiveAckPacket(register struct rx_call *call,
     }
 #endif
 
-    /* if a server connection has been re-created, it doesn't remember what
-       serial # it was up to.  An ack will tell us, since the serial field
-       contains the largest serial received by the other side */
-    MUTEX_ENTER(&conn->conn_data_lock);
-    if ((conn->type == RX_SERVER_CONNECTION) && (conn->serial < serial)) {
-       conn->serial = serial+1;
-    }
-    MUTEX_EXIT(&conn->conn_data_lock);
-
     /* Update the outgoing packet skew value to the latest value of
      * the peer's incoming packet skew value.  The ack packet, of
      * course, could arrive out of order, but that won't affect things
@@ -3400,22 +3387,9 @@ struct rx_packet *rxi_ReceiveAckPacket(register struct rx_call *call,
     for (queue_Scan(&call->tq, tp, nxp, rx_packet)) {
        if (tp->header.seq >= first) break;
        call->tfirst = tp->header.seq + 1;
-       if (tp->header.serial == serial) {
-         /* Use RTT if not delayed by client. */
-         if (ap->reason != RX_ACK_DELAY)
-             rxi_ComputeRoundTripTime(tp, &tp->timeSent, peer);
-#ifdef ADAPT_WINDOW
-         rxi_ComputeRate(peer, call, tp, np, ap->reason);
-#endif
-       }
-       else if (tp->firstSerial == serial) {
-           /* Use RTT if not delayed by client. */
-           if (ap->reason != RX_ACK_DELAY)
-               rxi_ComputeRoundTripTime(tp, &tp->firstSent, peer);
-#ifdef ADAPT_WINDOW
-         rxi_ComputeRate(peer, call, tp, np, ap->reason);
-#endif
-       }
+       if (serial && (tp->header.serial == serial ||
+                      tp->firstSerial == serial))
+           rxi_ComputePeerNetStats(call, tp, ap, np);
 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
     /* XXX Hack. Because we have to release the global rx lock when sending
      * packets (osi_NetSend) we drop all acks while we're traversing the tq
@@ -3468,30 +3442,12 @@ struct rx_packet *rxi_ReceiveAckPacket(register struct rx_call *call,
          * of this packet */
 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
 #ifdef RX_ENABLE_LOCKS
-       if (tp->header.seq >= first) {
-#endif /* RX_ENABLE_LOCKS */
-#endif /* AFS_GLOBAL_RXLOCK_KERNEL */
-       if (tp->header.serial == serial) {
-           /* Use RTT if not delayed by client. */
-           if (ap->reason != RX_ACK_DELAY)
-               rxi_ComputeRoundTripTime(tp, &tp->timeSent, peer);
-#ifdef ADAPT_WINDOW
-         rxi_ComputeRate(peer, call, tp, np, ap->reason);
-#endif
-       }
-       else if ((tp->firstSerial == serial)) {
-           /* Use RTT if not delayed by client. */
-           if (ap->reason != RX_ACK_DELAY)
-               rxi_ComputeRoundTripTime(tp, &tp->firstSent, peer);
-#ifdef ADAPT_WINDOW
-         rxi_ComputeRate(peer, call, tp, np, ap->reason);
-#endif
-       }
-#ifdef AFS_GLOBAL_RXLOCK_KERNEL
-#ifdef RX_ENABLE_LOCKS
-       }
+       if (tp->header.seq >= first)
 #endif /* RX_ENABLE_LOCKS */
 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
+           if (serial && (tp->header.serial == serial ||
+                          tp->firstSerial == serial))
+               rxi_ComputePeerNetStats(call, tp, ap, np);
 
        /* Set the acknowledge flag per packet based on the
          * information in the ack packet. An acknowlegded packet can
@@ -3819,8 +3775,9 @@ struct rx_packet *rxi_ReceiveResponsePacket(register struct rx_connection *conn,
            struct rx_call *call = conn->call[i];
            if (call) {
                MUTEX_ENTER(&call->lock);
-                if (call->state == RX_STATE_PRECALL)
-                    rxi_AttachServerProc(call, (osi_socket) -1, NULL, NULL);
+               if (call->state == RX_STATE_PRECALL)
+                   rxi_AttachServerProc(call, (osi_socket) -1, NULL, NULL);
+                   /* tnop can be null if newcallp is null */
                MUTEX_EXIT(&call->lock);
            }
        }
@@ -3880,23 +3837,12 @@ void rxi_AttachServerProc(register struct rx_call *call,
 {
     register struct rx_serverQueueEntry *sq;
     register struct rx_service *service = call->conn->service;
-#ifdef RX_ENABLE_LOCKS
     register int haveQuota = 0;
-#endif /* RX_ENABLE_LOCKS */
+
     /* May already be attached */
     if (call->state == RX_STATE_ACTIVE) return;
 
     MUTEX_ENTER(&rx_serverPool_lock);
-#ifdef RX_ENABLE_LOCKS
-    while(rxi_ServerThreadSelectingCall) {
-       MUTEX_EXIT(&call->lock);
-       CV_WAIT(&rx_serverPool_cv, &rx_serverPool_lock);
-       MUTEX_EXIT(&rx_serverPool_lock);
-       MUTEX_ENTER(&call->lock);
-       MUTEX_ENTER(&rx_serverPool_lock);
-       /* Call may have been attached */
-       if (call->state == RX_STATE_ACTIVE) return;
-    }
 
     haveQuota = QuotaOK(service);
     if ((!haveQuota) || queue_IsEmpty(&rx_idleServerQueue)) {
@@ -3904,8 +3850,11 @@ void rxi_AttachServerProc(register struct rx_call *call,
          * put the call on the incoming call queue (unless it's
          * already on the queue).
          */
+#ifdef RX_ENABLE_LOCKS
        if (haveQuota)
            ReturnToServerPool(service);
+#endif /* RX_ENABLE_LOCKS */
+
        if (!(call->flags & RX_CALL_WAIT_PROC)) {
            call->flags |= RX_CALL_WAIT_PROC;
            MUTEX_ENTER(&rx_stats_mutex);
@@ -3916,20 +3865,6 @@ void rxi_AttachServerProc(register struct rx_call *call,
            queue_Append(&rx_incomingCallQueue, call);
        }
     }
-#else /* RX_ENABLE_LOCKS */
-    if (!QuotaOK(service) || queue_IsEmpty(&rx_idleServerQueue)) {
-       /* If there are no processes available to service this call,
-         * put the call on the incoming call queue (unless it's
-         * already on the queue).
-         */
-       if (!(call->flags & RX_CALL_WAIT_PROC)) {
-           call->flags |= RX_CALL_WAIT_PROC;
-           rx_nWaiting++;
-           rxi_calltrace(RX_CALL_ARRIVAL, call);
-           queue_Append(&rx_incomingCallQueue, call);
-       }
-    }
-#endif /* RX_ENABLE_LOCKS */
     else {
        sq = queue_First(&rx_idleServerQueue, rx_serverQueueEntry);
 
@@ -3960,7 +3895,7 @@ void rxi_AttachServerProc(register struct rx_call *call,
        if (call->flags & RX_CALL_CLEARED) {
            /* send an ack now to start the packet flow up again */
            call->flags &= ~RX_CALL_CLEARED;
-           rxi_SendAck(call, 0, 0, 0, 0, RX_ACK_IDLE, 0);
+           rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
        }
 #ifdef RX_ENABLE_LOCKS
        CV_SIGNAL(&sq->cv);
@@ -4007,12 +3942,12 @@ void rxi_SendDelayedAck(struct rxevent *event, register struct rx_call *call, ch
            call->delayedAckEvent = NULL;
        CALL_RELE(call, RX_CALL_REFCOUNT_DELAY);
     }
-    (void) rxi_SendAck(call, 0, 0, 0, 0, RX_ACK_DELAY, 0);
+    (void) rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
     if (event)
        MUTEX_EXIT(&call->lock);
 #else /* RX_ENABLE_LOCKS */
     if (event) call->delayedAckEvent = NULL;
-    (void) rxi_SendAck(call, 0, 0, 0, 0, RX_ACK_DELAY, 0);
+    (void) rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
 #endif /* RX_ENABLE_LOCKS */
 }
 
@@ -4420,8 +4355,8 @@ void rxi_ResetCall(register struct rx_call *call, register int newcall)
 */
 
 struct rx_packet *rxi_SendAck(register struct rx_call *call, 
-       register struct rx_packet *optionalPacket, int seq, int serial, 
-       int pflags, int reason, int istack)
+       register struct rx_packet *optionalPacket, int serial, 
+       int reason, int istack)
 {
     struct rx_ackPacket *ap;
     register struct rx_packet *rqp;
@@ -4473,7 +4408,7 @@ struct rx_packet *rxi_SendAck(register struct rx_call *call,
 
     /* The skew computation used to be bogus, I think it's better now. */
     /* We should start paying attention to skew.    XXX  */
-    ap->serial = htonl(call->conn->maxSerial);
+    ap->serial = htonl(serial);
     ap->maxSkew        = 0;    /* used to be peer->inPacketSkew */
 
     ap->firstPacket = htonl(call->rnext); /* First packet not yet forwarded to reader */
@@ -4523,7 +4458,7 @@ struct rx_packet *rxi_SendAck(register struct rx_call *call,
     p->header.serviceId = call->conn->serviceId;
     p->header.cid = (call->conn->cid | call->channel);
     p->header.callNumber = *call->callNumber;
-    p->header.seq = seq;
+    p->header.seq = 0;
     p->header.securityIndex = call->conn->securityIndex;
     p->header.epoch = call->conn->epoch;
     p->header.type = RX_PACKET_TYPE_ACK;
@@ -4671,9 +4606,9 @@ static void rxi_SendList(struct rx_call *call, struct rx_packet **list,
     CALL_HOLD(call, RX_CALL_REFCOUNT_SEND);
     MUTEX_EXIT(&call->lock);
     if (len > 1) {
-       rxi_SendPacketList(conn, list, len, istack);
+       rxi_SendPacketList(call, conn, list, len, istack);
     } else {
-       rxi_SendPacket(conn, list[0], istack);
+       rxi_SendPacket(call, conn, list[0], istack);
     }
     MUTEX_ENTER(&call->lock);
     CALL_RELE(call, RX_CALL_REFCOUNT_SEND);
@@ -5119,7 +5054,7 @@ void rxi_Send(register struct rx_call *call, register struct rx_packet *p,
     /* Actually send the packet, filling in more connection-specific fields */
     CALL_HOLD(call, RX_CALL_REFCOUNT_SEND);
     MUTEX_EXIT(&call->lock);
-    rxi_SendPacket(conn, p, istack);
+    rxi_SendPacket(call, conn, p, istack);
     MUTEX_ENTER(&call->lock);
     CALL_RELE(call, RX_CALL_REFCOUNT_SEND);
 
@@ -5144,7 +5079,6 @@ int rxi_CheckCall(register struct rx_call *call)
 #endif /* RX_ENABLE_LOCKS */
 {
     register struct rx_connection *conn = call->conn;
-    register struct rx_service *tservice;
     afs_uint32 now;
     afs_uint32 deadTime;
 
@@ -5191,10 +5125,8 @@ int rxi_CheckCall(register struct rx_call *call)
          * attached process can die reasonably gracefully. */
     }
     /* see if we have a non-activity timeout */
-    tservice = conn->service;
-    if ((conn->type == RX_SERVER_CONNECTION) && call->startWait
-       && tservice->idleDeadTime
-       && ((call->startWait + tservice->idleDeadTime) < now)) {
+    if (call->startWait && conn->idleDeadTime
+       && ((call->startWait + conn->idleDeadTime) < now)) {
        if (call->state == RX_STATE_ACTIVE) {
            rxi_CallError(call, RX_CALL_TIMEOUT);
            return -1;
@@ -5248,7 +5180,7 @@ void rxi_KeepAliveEvent(struct rxevent *event, register struct rx_call *call,
       /* Don't try to send keepalives if there is unacknowledged data */
       /* the rexmit code should be good enough, this little hack 
        * doesn't quite work XXX */
-       (void) rxi_SendAck(call, NULL, 0, 0, 0, RX_ACK_PING, 0);
+       (void) rxi_SendAck(call, NULL, 0, RX_ACK_PING, 0);
     }
     rxi_ScheduleKeepAliveEvent(call);
     MUTEX_EXIT(&call->lock);
@@ -6358,8 +6290,10 @@ void shutdown_rx(void)
 {
     struct rx_serverQueueEntry *np;
     register int i, j;
+#ifndef KERNEL
     register struct rx_call *call;
     register struct rx_serverQueueEntry *sq;
+#endif /* KERNEL */
 
     LOCK_RX_INIT
     if (rxinit_status == 1) {