rx: Tidy up currentPacket handling
[openafs.git] / src / rx / rx_rdwr.c
index 3e05e14..a711572 100644 (file)
 # include "rx/rx_kernel.h"
 # include "afs/lock.h"
 #else /* KERNEL */
-# include <sys/types.h>
-# include <string.h>
-# ifdef AFS_NT40_ENV
-#  include <winsock2.h>
-# else /* !AFS_NT40_ENV */
-#  include <sys/socket.h>
-#  include <sys/file.h>
-#  include <netdb.h>
-#  include <netinet/in.h>
-#  include <sys/stat.h>
-#  include <sys/time.h>
-#  include <unistd.h>
-# endif /* !AFS_NT40_ENV */
+# include <roken.h>
 #endif /* KERNEL */
 
 #include "rx.h"
 #include "rx_clock.h"
 #include "rx_queue.h"
 #include "rx_globals.h"
+#include "rx_atomic.h"
+#include "rx_internal.h"
+#include "rx_conn.h"
+#include "rx_call.h"
+#include "rx_packet.h"
 
 #ifdef RX_LOCKS_DB
 /* rxdb_fileID is used to identify the lock location, along with line#. */
@@ -84,7 +77,6 @@ int
 rxi_ReadProc(struct rx_call *call, char *buf,
             int nbytes)
 {
-    struct rx_packet *cp = call->currentPacket;
     struct rx_packet *rp;
     int requestCount;
     unsigned int t;
@@ -153,7 +145,7 @@ rxi_ReadProc(struct rx_call *call, char *buf,
                            return 0;
                        }
                        call->rnext++;
-                       cp = call->currentPacket = rp;
+                       call->currentPacket = rp;
 #ifdef RX_TRACK_PACKETS
                        call->currentPacket->flags |= RX_PKTFLAG_CP;
 #endif
@@ -161,10 +153,10 @@ rxi_ReadProc(struct rx_call *call, char *buf,
                        /* begin at the beginning [ more or less ], continue
                         * on until the end, then stop. */
                        call->curpos =
-                           (char *)cp->wirevec[1].iov_base +
+                           (char *) call->currentPacket->wirevec[1].iov_base +
                            call->conn->securityHeaderSize;
                        call->curlen =
-                           cp->wirevec[1].iov_len -
+                           call->currentPacket->wirevec[1].iov_len -
                            call->conn->securityHeaderSize;
 
                        /* Notice that this code works correctly if the data
@@ -174,8 +166,8 @@ rxi_ReadProc(struct rx_call *call, char *buf,
                         * (no yields, etc.).  If it didn't, this would be a
                         * problem because a value of zero for call->nLeft
                         * normally means that there is no read packet */
-                       call->nLeft = cp->length;
-                       hadd32(call->bytesRcvd, cp->length);
+                       call->nLeft = call->currentPacket->length;
+                       hadd32(call->bytesRcvd, call->currentPacket->length);
 
                        /* Send a hard ack for every rxi_HardAckRate+1 packets
                         * consumed. Otherwise schedule an event to send
@@ -184,29 +176,13 @@ rxi_ReadProc(struct rx_call *call, char *buf,
                        call->nHardAcks++;
                        if (!(call->flags & RX_CALL_RECEIVE_DONE)) {
                            if (call->nHardAcks > (u_short) rxi_HardAckRate) {
-                               rxevent_Cancel(call->delayedAckEvent, call,
+                               rxevent_Cancel(&call->delayedAckEvent, call,
                                               RX_CALL_REFCOUNT_DELAY);
                                rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
                            } else {
-                               struct clock when, now;
-                               clock_GetTime(&now);
-                               when = now;
                                /* Delay to consolidate ack packets */
-                               clock_Add(&when, &rx_hardAckDelay);
-                               if (!call->delayedAckEvent
-                                   || clock_Gt(&call->delayedAckEvent->
-                                               eventTime, &when)) {
-                                   rxevent_Cancel(call->delayedAckEvent,
-                                                  call,
-                                                  RX_CALL_REFCOUNT_DELAY);
-                                    MUTEX_ENTER(&rx_refcnt_mutex);
-                                   CALL_HOLD(call, RX_CALL_REFCOUNT_DELAY);
-                                    MUTEX_EXIT(&rx_refcnt_mutex);
-                                    call->delayedAckEvent =
-                                     rxevent_PostNow(&when, &now,
-                                                    rxi_SendDelayedAck, call,
-                                                    0);
-                               }
+                               rxi_PostDelayedAckEvent(call,
+                                                       &rx_hardAckDelay);
                            }
                        }
                        break;
@@ -236,7 +212,6 @@ rxi_ReadProc(struct rx_call *call, char *buf,
                    osi_rxSleep(&call->rq);
 #endif
                }
-                cp = call->currentPacket;
 
                call->startWait = 0;
 #ifdef RX_ENABLE_LOCKS
@@ -257,7 +232,7 @@ rxi_ReadProc(struct rx_call *call, char *buf,
             * number of bytes read in the length field of the packet struct.  On
             * the final portion of a received packet, it's almost certain that
             * call->nLeft will be smaller than the final buffer. */
-           while (nbytes && cp) {
+           while (nbytes && call->currentPacket) {
                t = MIN((int)call->curlen, nbytes);
                t = MIN(t, (int)call->nLeft);
                memcpy(buf, call->curpos, t);
@@ -272,23 +247,24 @@ rxi_ReadProc(struct rx_call *call, char *buf,
 #ifdef RX_TRACK_PACKETS
                    call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-                   rxi_FreePacket(cp);
-                   cp = call->currentPacket = (struct rx_packet *)0;
+                   rxi_FreePacket(call->currentPacket);
+                   call->currentPacket = NULL;
                } else if (!call->curlen) {
                    /* need to get another struct iov */
-                   if (++call->curvec >= cp->niovecs) {
+                   if (++call->curvec >= call->currentPacket->niovecs) {
                        /* current packet is exhausted, get ready for another */
                        /* don't worry about curvec and stuff, they get set somewhere else */
 #ifdef RX_TRACK_PACKETS
                        call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-                       rxi_FreePacket(cp);
-                       cp = call->currentPacket = (struct rx_packet *)0;
+                       rxi_FreePacket(call->currentPacket);
+                       call->currentPacket = NULL;
                        call->nLeft = 0;
                    } else {
                        call->curpos =
-                           (char *)cp->wirevec[call->curvec].iov_base;
-                       call->curlen = cp->wirevec[call->curvec].iov_len;
+                           call->currentPacket->wirevec[call->curvec].iov_base;
+                       call->curlen =
+                           call->currentPacket->wirevec[call->curvec].iov_len;
                    }
                }
            }
@@ -306,9 +282,6 @@ int
 rx_ReadProc(struct rx_call *call, char *buf, int nbytes)
 {
     int bytes;
-    int tcurlen;
-    int tnLeft;
-    char *tcurpos;
     SPLVAR;
 
     /* Free any packets from the last call to ReadvProc/WritevProc */
@@ -323,15 +296,12 @@ rx_ReadProc(struct rx_call *call, char *buf, int nbytes)
      * Most common case, all of the data is in the current iovec.
      * We are relying on nLeft being zero unless the call is in receive mode.
      */
-    tcurlen = call->curlen;
-    tnLeft = call->nLeft;
-    if (!call->error && tcurlen > nbytes && tnLeft > nbytes) {
-       tcurpos = call->curpos;
-        memcpy(buf, tcurpos, nbytes);
+    if (!call->error && call->curlen > nbytes && call->nLeft > nbytes) {
+        memcpy(buf, call->curpos, nbytes);
 
-       call->curpos = tcurpos + nbytes;
-       call->curlen = tcurlen - nbytes;
-       call->nLeft = tnLeft - nbytes;
+       call->curpos += nbytes;
+       call->curlen -= nbytes;
+       call->nLeft  -= nbytes;
 
         if (!call->nLeft && call->currentPacket != NULL) {
             /* out of packet.  Get another one. */
@@ -352,9 +322,6 @@ int
 rx_ReadProc32(struct rx_call *call, afs_int32 * value)
 {
     int bytes;
-    int tcurlen;
-    int tnLeft;
-    char *tcurpos;
     SPLVAR;
 
     /* Free any packets from the last call to ReadvProc/WritevProc */
@@ -369,17 +336,15 @@ rx_ReadProc32(struct rx_call *call, afs_int32 * value)
      * Most common case, all of the data is in the current iovec.
      * We are relying on nLeft being zero unless the call is in receive mode.
      */
-    tcurlen = call->curlen;
-    tnLeft = call->nLeft;
-    if (!call->error && tcurlen >= sizeof(afs_int32)
-       && tnLeft >= sizeof(afs_int32)) {
-       tcurpos = call->curpos;
+    if (!call->error && call->curlen >= sizeof(afs_int32)
+       && call->nLeft >= sizeof(afs_int32)) {
 
-        memcpy((char *)value, tcurpos, sizeof(afs_int32));
+        memcpy((char *)value, call->curpos, sizeof(afs_int32));
+
+        call->curpos += sizeof(afs_int32);
+       call->curlen -= sizeof(afs_int32);
+       call->nLeft  -= sizeof(afs_int32);
 
-        call->curpos = tcurpos + sizeof(afs_int32);
-       call->curlen = (u_short)(tcurlen - sizeof(afs_int32));
-       call->nLeft = (u_short)(tnLeft - sizeof(afs_int32));
         if (!call->nLeft && call->currentPacket != NULL) {
             /* out of packet.  Get another one. */
             rxi_FreePacket(call->currentPacket);
@@ -408,13 +373,11 @@ rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
     int didHardAck = 0;
     unsigned int t;
     struct rx_packet *rp;
-    struct rx_packet *curp;
     struct iovec *call_iov;
     struct iovec *cur_iov = NULL;
 
-    curp = call->currentPacket;
-    if (curp) {
-       cur_iov = &curp->wirevec[call->curvec];
+    if (call->currentPacket) {
+       cur_iov = &call->currentPacket->wirevec[call->curvec];
     }
     call_iov = &call->iov[call->iovNext];
 
@@ -456,19 +419,19 @@ rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
                        return 1;
                    }
                    call->rnext++;
-                   curp = call->currentPacket = rp;
+                   call->currentPacket = rp;
 #ifdef RX_TRACK_PACKETS
                    call->currentPacket->flags |= RX_PKTFLAG_CP;
 #endif
                    call->curvec = 1;   /* 0th vec is always header */
-                   cur_iov = &curp->wirevec[1];
+                   cur_iov = &call->currentPacket->wirevec[1];
                    /* begin at the beginning [ more or less ], continue
                     * on until the end, then stop. */
                    call->curpos =
-                       (char *)curp->wirevec[1].iov_base +
+                       (char *)call->currentPacket->wirevec[1].iov_base +
                        call->conn->securityHeaderSize;
                    call->curlen =
-                       curp->wirevec[1].iov_len -
+                       call->currentPacket->wirevec[1].iov_len -
                        call->conn->securityHeaderSize;
 
                    /* Notice that this code works correctly if the data
@@ -478,8 +441,8 @@ rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
                     * (no yields, etc.).  If it didn't, this would be a
                     * problem because a value of zero for call->nLeft
                     * normally means that there is no read packet */
-                   call->nLeft = curp->length;
-                   hadd32(call->bytesRcvd, curp->length);
+                   call->nLeft = call->currentPacket->length;
+                   hadd32(call->bytesRcvd, call->currentPacket->length);
 
                    /* Send a hard ack for every rxi_HardAckRate+1 packets
                     * consumed. Otherwise schedule an event to send
@@ -499,7 +462,9 @@ rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
         * number of bytes read in the length field of the packet struct.  On
         * the final portion of a received packet, it's almost certain that
         * call->nLeft will be smaller than the final buffer. */
-       while (call->iovNBytes && call->iovNext < call->iovMax && curp) {
+       while (call->iovNBytes
+              && call->iovNext < call->iovMax
+              && call->currentPacket) {
 
            t = MIN((int)call->curlen, call->iovNBytes);
            t = MIN(t, (int)call->nLeft);
@@ -515,28 +480,28 @@ rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
            if (!call->nLeft) {
                /* out of packet.  Get another one. */
 #ifdef RX_TRACK_PACKETS
-                curp->flags &= ~RX_PKTFLAG_CP;
-                curp->flags |= RX_PKTFLAG_IOVQ;
+                call->currentPacket->flags &= ~RX_PKTFLAG_CP;
+                call->currentPacket->flags |= RX_PKTFLAG_IOVQ;
 #endif
-               queue_Append(&call->iovq, curp);
+               queue_Append(&call->iovq, call->currentPacket);
 #ifdef RXDEBUG_PACKET
                 call->iovqc++;
 #endif /* RXDEBUG_PACKET */
-               curp = call->currentPacket = (struct rx_packet *)0;
+               call->currentPacket = NULL;
            } else if (!call->curlen) {
                /* need to get another struct iov */
-               if (++call->curvec >= curp->niovecs) {
+               if (++call->curvec >= call->currentPacket->niovecs) {
                    /* current packet is exhausted, get ready for another */
                    /* don't worry about curvec and stuff, they get set somewhere else */
 #ifdef RX_TRACK_PACKETS
-                   curp->flags &= ~RX_PKTFLAG_CP;
-                   curp->flags |= RX_PKTFLAG_IOVQ;
+                   call->currentPacket->flags &= ~RX_PKTFLAG_CP;
+                   call->currentPacket->flags |= RX_PKTFLAG_IOVQ;
 #endif
-                   queue_Append(&call->iovq, curp);
+                   queue_Append(&call->iovq, call->currentPacket);
 #ifdef RXDEBUG_PACKET
                     call->iovqc++;
 #endif /* RXDEBUG_PACKET */
-                   curp = call->currentPacket = (struct rx_packet *)0;
+                   call->currentPacket = NULL;
                    call->nLeft = 0;
                } else {
                    cur_iov++;
@@ -551,26 +516,13 @@ rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
      * send a hard ack. */
     if (didConsume && (!(call->flags & RX_CALL_RECEIVE_DONE))) {
        if (call->nHardAcks > (u_short) rxi_HardAckRate) {
-           rxevent_Cancel(call->delayedAckEvent, call,
+           rxevent_Cancel(&call->delayedAckEvent, call,
                           RX_CALL_REFCOUNT_DELAY);
            rxi_SendAck(call, 0, serial, RX_ACK_DELAY, 0);
            didHardAck = 1;
        } else {
-           struct clock when, now;
-           clock_GetTime(&now);
-           when = now;
            /* Delay to consolidate ack packets */
-           clock_Add(&when, &rx_hardAckDelay);
-           if (!call->delayedAckEvent
-               || clock_Gt(&call->delayedAckEvent->eventTime, &when)) {
-               rxevent_Cancel(call->delayedAckEvent, call,
-                              RX_CALL_REFCOUNT_DELAY);
-                MUTEX_ENTER(&rx_refcnt_mutex);
-               CALL_HOLD(call, RX_CALL_REFCOUNT_DELAY);
-                MUTEX_EXIT(&rx_refcnt_mutex);
-               call->delayedAckEvent =
-                   rxevent_PostNow(&when, &now, rxi_SendDelayedAck, call, 0);
-           }
+           rxi_PostDelayedAckEvent(call, &rx_hardAckDelay);
        }
     }
     return didHardAck;
@@ -676,7 +628,6 @@ rxi_WriteProc(struct rx_call *call, char *buf,
              int nbytes)
 {
     struct rx_connection *conn = call->conn;
-    struct rx_packet *cp = call->currentPacket;
     unsigned int t;
     int requestCount = nbytes;
 
@@ -692,12 +643,12 @@ rxi_WriteProc(struct rx_call *call, char *buf,
        if ((conn->type == RX_SERVER_CONNECTION)
            && (call->mode == RX_MODE_RECEIVING)) {
            call->mode = RX_MODE_SENDING;
-           if (cp) {
+           if (call->currentPacket) {
 #ifdef RX_TRACK_PACKETS
-               cp->flags &= ~RX_PKTFLAG_CP;
+               call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-               rxi_FreePacket(cp);
-               cp = call->currentPacket = (struct rx_packet *)0;
+               rxi_FreePacket(call->currentPacket);
+               call->currentPacket = NULL;
                call->nLeft = 0;
                call->nFree = 0;
            }
@@ -713,50 +664,44 @@ rxi_WriteProc(struct rx_call *call, char *buf,
     do {
        if (call->nFree == 0) {
            MUTEX_ENTER(&call->lock);
-            cp = call->currentPacket;
             if (call->error)
                 call->mode = RX_MODE_ERROR;
-           if (!call->error && cp) {
-                /* Clear the current packet now so that if
-                 * we are forced to wait and drop the lock
-                 * the packet we are planning on using
-                 * cannot be freed.
-                 */
-#ifdef RX_TRACK_PACKETS
-                cp->flags &= ~RX_PKTFLAG_CP;
-#endif
-               call->currentPacket = (struct rx_packet *)0;
+           if (!call->error && call->currentPacket) {
                clock_NewTime();        /* Bogus:  need new time package */
                /* The 0, below, specifies that it is not the last packet:
                 * there will be others. PrepareSendPacket may
                 * alter the packet length by up to
                 * conn->securityMaxTrailerSize */
-               hadd32(call->bytesSent, cp->length);
-               rxi_PrepareSendPacket(call, cp, 0);
+               hadd32(call->bytesSent, call->currentPacket->length);
+               rxi_PrepareSendPacket(call, call->currentPacket, 0);
 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
                 /* PrepareSendPacket drops the call lock */
                 rxi_WaitforTQBusy(call);
 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
 #ifdef RX_TRACK_PACKETS
-               cp->flags |= RX_PKTFLAG_TQ;
+               call->currentPacket->flags |= RX_PKTFLAG_TQ;
 #endif
-               queue_Append(&call->tq, cp);
+               queue_Append(&call->tq, call->currentPacket);
 #ifdef RXDEBUG_PACKET
                 call->tqc++;
 #endif /* RXDEBUG_PACKET */
-                cp = (struct rx_packet *)0;
-               if (!
-                   (call->
-                    flags & (RX_CALL_FAST_RECOVER |
-                             RX_CALL_FAST_RECOVER_WAIT))) {
-                   rxi_Start(0, call, 0, 0);
+#ifdef RX_TRACK_PACKETS
+                call->currentPacket->flags &= ~RX_PKTFLAG_CP;
+#endif
+                call->currentPacket = NULL;
+
+               /* If the call is in recovery, let it exhaust its current
+                * retransmit queue before forcing it to send new packets
+                */
+               if (!(call->flags & (RX_CALL_FAST_RECOVER))) {
+                   rxi_Start(call, 0);
                }
-           } else if (cp) {
+           } else if (call->currentPacket) {
 #ifdef RX_TRACK_PACKETS
-               cp->flags &= ~RX_PKTFLAG_CP;
+               call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-               rxi_FreePacket(cp);
-               cp = call->currentPacket = (struct rx_packet *)0;
+               rxi_FreePacket(call->currentPacket);
+               call->currentPacket = NULL;
            }
            /* Wait for transmit window to open up */
            while (!call->error
@@ -780,28 +725,28 @@ rxi_WriteProc(struct rx_call *call, char *buf,
                }
 #endif /* RX_ENABLE_LOCKS */
            }
-           if ((cp = rxi_AllocSendPacket(call, nbytes))) {
+           if ((call->currentPacket = rxi_AllocSendPacket(call, nbytes))) {
 #ifdef RX_TRACK_PACKETS
-               cp->flags |= RX_PKTFLAG_CP;
+               call->currentPacket->flags |= RX_PKTFLAG_CP;
 #endif
-               call->currentPacket = cp;
-               call->nFree = cp->length;
+               call->nFree = call->currentPacket->length;
                call->curvec = 1;       /* 0th vec is always header */
                /* begin at the beginning [ more or less ], continue
                 * on until the end, then stop. */
                call->curpos =
-                   (char *)cp->wirevec[1].iov_base +
+                   (char *) call->currentPacket->wirevec[1].iov_base +
                    call->conn->securityHeaderSize;
                call->curlen =
-                   cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
+                   call->currentPacket->wirevec[1].iov_len -
+                   call->conn->securityHeaderSize;
            }
            if (call->error) {
                 call->mode = RX_MODE_ERROR;
-               if (cp) {
+               if (call->currentPacket) {
 #ifdef RX_TRACK_PACKETS
-                   cp->flags &= ~RX_PKTFLAG_CP;
+                   call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-                   rxi_FreePacket(cp);
+                   rxi_FreePacket(call->currentPacket);
                    call->currentPacket = NULL;
                }
                MUTEX_EXIT(&call->lock);
@@ -810,18 +755,19 @@ rxi_WriteProc(struct rx_call *call, char *buf,
            MUTEX_EXIT(&call->lock);
        }
 
-       if (cp && (int)call->nFree < nbytes) {
+       if (call->currentPacket && (int)call->nFree < nbytes) {
            /* Try to extend the current buffer */
            int len, mud;
-           len = cp->length;
+           len = call->currentPacket->length;
            mud = rx_MaxUserDataSize(call);
            if (mud > len) {
                int want;
                want = MIN(nbytes - (int)call->nFree, mud - len);
-               rxi_AllocDataBuf(cp, want, RX_PACKET_CLASS_SEND_CBUF);
-               if (cp->length > (unsigned)mud)
-                   cp->length = mud;
-               call->nFree += (cp->length - len);
+               rxi_AllocDataBuf(call->currentPacket, want,
+                                RX_PACKET_CLASS_SEND_CBUF);
+               if (call->currentPacket->length > (unsigned)mud)
+                   call->currentPacket->length = mud;
+               call->nFree += (call->currentPacket->length - len);
            }
        }
 
@@ -829,7 +775,7 @@ rxi_WriteProc(struct rx_call *call, char *buf,
         * and return.  Don't ship a buffer that's full immediately to
         * the peer--we don't know if it's the last buffer yet */
 
-       if (!cp) {
+       if (!call->currentPacket) {
            call->nFree = 0;
        }
 
@@ -846,12 +792,14 @@ rxi_WriteProc(struct rx_call *call, char *buf,
 
            if (!call->curlen) {
                /* need to get another struct iov */
-               if (++call->curvec >= cp->niovecs) {
+               if (++call->curvec >= call->currentPacket->niovecs) {
                    /* current packet is full, extend or send it */
                    call->nFree = 0;
                } else {
-                   call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
-                   call->curlen = cp->wirevec[call->curvec].iov_len;
+                   call->curpos =
+                       call->currentPacket->wirevec[call->curvec].iov_base;
+                   call->curlen =
+                       call->currentPacket->wirevec[call->curvec].iov_len;
                }
            }
        }                       /* while bytes to send and room to send them */
@@ -956,12 +904,12 @@ rx_WriteProc32(struct rx_call *call, afs_int32 * value)
  * LOCKS USED -- called at netpri.
  */
 
-int
+static int
 rxi_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
                int nbytes)
 {
     struct rx_connection *conn = call->conn;
-    struct rx_packet *cp = call->currentPacket;
+    struct rx_packet *cp;
     int requestCount;
     int nextio;
     /* Temporary values, real work is done in rxi_WritevProc */
@@ -985,12 +933,12 @@ rxi_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
        if ((conn->type == RX_SERVER_CONNECTION)
            && (call->mode == RX_MODE_RECEIVING)) {
            call->mode = RX_MODE_SENDING;
-           if (cp) {
+           if (call->currentPacket) {
 #ifdef RX_TRACK_PACKETS
-               cp->flags &= ~RX_PKTFLAG_CP;
+               call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-               rxi_FreePacket(cp);
-               cp = call->currentPacket = (struct rx_packet *)0;
+               rxi_FreePacket(call->currentPacket);
+               call->currentPacket = NULL;
                call->nLeft = 0;
                call->nFree = 0;
            }
@@ -1004,6 +952,7 @@ rxi_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
     tcurvec = call->curvec;
     tcurpos = call->curpos;
     tcurlen = call->curlen;
+    cp = call->currentPacket;
     do {
        int t;
 
@@ -1098,7 +1047,6 @@ rx_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
 int
 rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
 {
-    struct rx_packet *cp = NULL;
 #ifdef RX_TRACK_PACKETS
     struct rx_packet *p, *np;
 #endif
@@ -1121,21 +1069,20 @@ rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
     rxi_WaitforTQBusy(call);
 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
-    cp = call->currentPacket;
 
     if (call->error) {
         call->mode = RX_MODE_ERROR;
        MUTEX_EXIT(&call->lock);
-       if (cp) {
+       if (call->currentPacket) {
 #ifdef RX_TRACK_PACKETS
-            cp->flags &= ~RX_PKTFLAG_CP;
-            cp->flags |= RX_PKTFLAG_IOVQ;
+            call->currentPacket->flags &= ~RX_PKTFLAG_CP;
+            call->currentPacket->flags |= RX_PKTFLAG_IOVQ;
 #endif
-           queue_Prepend(&call->iovq, cp);
+           queue_Prepend(&call->iovq, call->currentPacket);
 #ifdef RXDEBUG_PACKET
             call->iovqc++;
 #endif /* RXDEBUG_PACKET */
-           call->currentPacket = (struct rx_packet *)0;
+           call->currentPacket = NULL;
        }
 #ifdef RXDEBUG_PACKET
         call->iovqc -=
@@ -1155,23 +1102,23 @@ rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
     tmpqc = 0;
 #endif /* RXDEBUG_PACKET */
     do {
-       if (call->nFree == 0 && cp) {
+       if (call->nFree == 0 && call->currentPacket) {
            clock_NewTime();    /* Bogus:  need new time package */
            /* The 0, below, specifies that it is not the last packet:
             * there will be others. PrepareSendPacket may
             * alter the packet length by up to
             * conn->securityMaxTrailerSize */
-           hadd32(call->bytesSent, cp->length);
-           rxi_PrepareSendPacket(call, cp, 0);
+           hadd32(call->bytesSent, call->currentPacket->length);
+           rxi_PrepareSendPacket(call, call->currentPacket, 0);
 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
             /* PrepareSendPacket drops the call lock */
             rxi_WaitforTQBusy(call);
 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
-           queue_Append(&tmpq, cp);
+           queue_Append(&tmpq, call->currentPacket);
 #ifdef RXDEBUG_PACKET
             tmpqc++;
 #endif /* RXDEBUG_PACKET */
-            cp = call->currentPacket = (struct rx_packet *)0;
+            call->currentPacket = NULL;
 
            /* The head of the iovq is now the current packet */
            if (nbytes) {
@@ -1184,25 +1131,23 @@ rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
                         rxi_FreePackets(0, &tmpq);
                    return 0;
                }
-               cp = queue_First(&call->iovq, rx_packet);
-               queue_Remove(cp);
+               call->currentPacket = queue_First(&call->iovq, rx_packet);
+               queue_Remove(call->currentPacket);
 #ifdef RX_TRACK_PACKETS
-                cp->flags &= ~RX_PKTFLAG_IOVQ;
+                call->currentPacket->flags &= ~RX_PKTFLAG_IOVQ;
+               call->currentPacket->flags |= RX_PKTFLAG_CP;
 #endif
 #ifdef RXDEBUG_PACKET
                 call->iovqc--;
 #endif /* RXDEBUG_PACKET */
-#ifdef RX_TRACK_PACKETS
-                cp->flags |= RX_PKTFLAG_CP;
-#endif
-               call->currentPacket = cp;
-               call->nFree = cp->length;
+               call->nFree = call->currentPacket->length;
                call->curvec = 1;
                call->curpos =
-                   (char *)cp->wirevec[1].iov_base +
+                   (char *) call->currentPacket->wirevec[1].iov_base +
                    call->conn->securityHeaderSize;
                call->curlen =
-                   cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
+                   call->currentPacket->wirevec[1].iov_len -
+                   call->conn->securityHeaderSize;
            }
        }
 
@@ -1212,15 +1157,15 @@ rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
                || iov[nextio].iov_len > (int)call->curlen) {
                call->error = RX_PROTOCOL_ERROR;
                 MUTEX_EXIT(&call->lock);
-               if (cp) {
+               if (call->currentPacket) {
 #ifdef RX_TRACK_PACKETS
-                   cp->flags &= ~RX_PKTFLAG_CP;
+                   call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-                    queue_Prepend(&tmpq, cp);
+                    queue_Prepend(&tmpq, call->currentPacket);
 #ifdef RXDEBUG_PACKET
                     tmpqc++;
 #endif /* RXDEBUG_PACKET */
-                    cp = call->currentPacket = (struct rx_packet *)0;
+                    call->currentPacket = NULL;
                }
 #ifdef RXDEBUG_PACKET
                 tmpqc -=
@@ -1234,11 +1179,13 @@ rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
            call->nFree -= iov[nextio].iov_len;
            nextio++;
            if (call->curlen == 0) {
-               if (++call->curvec > cp->niovecs) {
+               if (++call->curvec > call->currentPacket->niovecs) {
                    call->nFree = 0;
                } else {
-                   call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
-                   call->curlen = cp->wirevec[call->curvec].iov_len;
+                   call->curpos =
+                       call->currentPacket->wirevec[call->curvec].iov_base;
+                   call->curlen =
+                       call->currentPacket->wirevec[call->curvec].iov_len;
                }
            }
        }
@@ -1259,8 +1206,11 @@ rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
 
     queue_SpliceAppend(&call->tq, &tmpq);
 
-    if (!(call->flags & (RX_CALL_FAST_RECOVER | RX_CALL_FAST_RECOVER_WAIT))) {
-       rxi_Start(0, call, 0, 0);
+    /* If the call is in recovery, let it exhaust its current retransmit
+     * queue before forcing it to send new packets
+     */
+    if (!(call->flags & RX_CALL_FAST_RECOVER)) {
+       rxi_Start(call, 0);
     }
 
     /* Wait for the length of the transmit queue to fall below call->twind */
@@ -1276,18 +1226,15 @@ rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
        call->startWait = 0;
     }
 
-    /* cp is no longer valid since we may have given up the lock */
-    cp = call->currentPacket;
-
     if (call->error) {
         call->mode = RX_MODE_ERROR;
         call->currentPacket = NULL;
         MUTEX_EXIT(&call->lock);
-       if (cp) {
+       if (call->currentPacket) {
 #ifdef RX_TRACK_PACKETS
-           cp->flags &= ~RX_PKTFLAG_CP;
+           call->currentPacket->flags &= ~RX_PKTFLAG_CP;
 #endif
-           rxi_FreePacket(cp);
+           rxi_FreePacket(call->currentPacket);
        }
        return 0;
     }
@@ -1386,10 +1333,12 @@ rxi_FlushWrite(struct rx_call *call)
 #ifdef RXDEBUG_PACKET
         call->tqc++;
 #endif /* RXDEBUG_PACKET */
-       if (!
-           (call->
-            flags & (RX_CALL_FAST_RECOVER | RX_CALL_FAST_RECOVER_WAIT))) {
-           rxi_Start(0, call, 0, 0);
+
+       /* If the call is in recovery, let it exhaust its current retransmit
+        * queue before forcing it to send new packets
+        */
+       if (!(call->flags & RX_CALL_FAST_RECOVER)) {
+           rxi_Start(call, 0);
        }
         MUTEX_EXIT(&call->lock);
     }