Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c (revision 195826) +++ sys/netinet/tcp_input.c (working copy) @@ -2073,8 +2073,8 @@ /* * Compute the amount of data in flight first. - * We can inject new data into the pipe iff - * we have less than 1/2 the original window's + * We can inject new data into the pipe iff + * we have less than 1/2 the original window's * worth of data in flight. */ awnd = (tp->snd_nxt - tp->snd_fack) + Index: sys/netinet/tcp_sack.c =================================================================== --- sys/netinet/tcp_sack.c (revision 195826) +++ sys/netinet/tcp_sack.c (working copy) @@ -316,6 +316,8 @@ else TAILQ_INSERT_TAIL(&tp->snd_holes, hole, scblink); + tp->sack_hole_bytes += hole->end - hole->start; + /* Update SACK hint. */ if (tp->sack_nexthole == NULL) tp->sack_nexthole = hole; @@ -337,8 +339,22 @@ /* Remove this SACK hole. */ TAILQ_REMOVE(&tp->snd_holes, hole, scblink); + tp->sack_hole_bytes -= hole->end - hole->start; + /* Free this SACK hole. */ tcp_sackhole_free(tp, hole); + + /* +#ifdef INVARIANTS + if (TAILQ_EMPTY(&tp->snd_holes)) + KASSERT(tp->sack_hole_bytes == 0, + ("tp->sack_hole_bytes is %d instead of 0", tp->sack_hole_bytes)); +#endif + */ + if (TAILQ_EMPTY(&tp->snd_holes) && tp->sack_hole_bytes != 0) { + printf("tp->sack_hole_bytes is %d instead of 0", tp->sack_hole_bytes); + tp->sack_hole_bytes = 0; + } } /* @@ -499,14 +515,16 @@ */ continue; } else { - /* Move start of hole forward. */ + /* Shrink hole: slide start of hole forward. */ + tp->sack_hole_bytes -= sblkp->end - cur->start; cur->start = sblkp->end; cur->rxmit = SEQ_MAX(cur->rxmit, cur->start); } } else { /* Data acks at least the end of hole. */ if (SEQ_GEQ(sblkp->end, cur->end)) { - /* Move end of hole backward. */ + /* Shrink hole: slide end of hole backward. */ + tp->sack_hole_bytes -= sblkp->start - cur->end; cur->end = sblkp->start; cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); } else { @@ -523,6 +541,20 @@ += (temp->rxmit - temp->start); } + /* + * Adjust tp->sack_hole_bytes specially + * here because tcp_sackhole_insert + * adds bytes to the tally that were + * already accounted for. Undo the + * addition of cur->end-sblkp->end bytes + * and also adjust for number of bytes + * in the sack block i.e. + * sblkp->end-sblkp->start + */ + tp->sack_hole_bytes -= cur->end - + sblkp->end - + sblkp->end + + sblkp->start; cur->end = sblkp->start; cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); Index: sys/netinet/tcp_var.h =================================================================== --- sys/netinet/tcp_var.h (revision 195826) +++ sys/netinet/tcp_var.h (working copy) @@ -186,6 +186,8 @@ episode starts at this seq number */ struct sackhole *sack_nexthole; /* next hole to rexmt */ int sack_bytes_rexmit; /* # bytes rexmt this RTT */ + int sack_hole_bytes; /* # bytes not yet sacked by rcv'r + this recovery episode */ int t_rttlow; /* smallest observerved RTT */ u_int32_t rfbuf_ts; /* recv buffer autoscaling timestamp */ int rfbuf_cnt; /* recv buffer autoscaling byte count */