History

tcp: refine tcp_write_queue_empty() implementation

Due to how tcp_sendmsg() is implemented, we can have an empty skb at the tail of the write queue. Most [1] tcp_write_queue_empty() callers want to know if there is anything to send (payload and/or FIN) Instead of checking if the sk_write_queue is empty, we need to test if tp->write_seq == tp->snd_nxt [1] tcp_send_fin() was the only caller that expected to see if an skb was in the write queue, I have changed the code to reuse the tcp_write_queue_tail() result.

Eric Dumazet committed 6 years ago

Commit ee2aabd1 parent 1f85e622 files · +13 −3Browse files

Unified · Split

2 files
  1. include/net/tcp.h +10 −1
  2. net/ipv4/tcp_output.c +3 −2
include/net/tcp.h+10−1
@@ -1766,9 +1766,18 @@ static inline bool tcp_skb_is_last(const struct sock *sk, · 1765 unmodified lines
1766 return skb_queue_is_last(&sk->sk_write_queue, skb);1766 return skb_queue_is_last(&sk->sk_write_queue, skb);
1767}1767}
1768 1768
1769/**
1770 * tcp_write_queue_empty - test if any payload (or FIN) is available in write queue
1771 * @sk: socket
1772 *
1773 * Since the write queue can have a temporary empty skb in it,
1774 * we must not use "return skb_queue_empty(&sk->sk_write_queue)"
1775 */
1769static inline bool tcp_write_queue_empty(const struct sock *sk)1776static inline bool tcp_write_queue_empty(const struct sock *sk)
1770{1777{
1771 return skb_queue_empty(&sk->sk_write_queue);1778 const struct tcp_sock *tp = tcp_sk(sk);
1779
1780 return tp->write_seq == tp->snd_nxt;
1772}1781}
1773 1782
1774static inline bool tcp_rtx_queue_empty(const struct sock *sk)1783static inline bool tcp_rtx_queue_empty(const struct sock *sk)
net/ipv4/tcp_output.c+3−2
@@ -3129,7 +3129,7 @@ void sk_forced_mem_schedule(struct sock *sk, int size) · 3128 unmodified lines
3129 */3129 */
3130void tcp_send_fin(struct sock *sk)3130void tcp_send_fin(struct sock *sk)
3131{3131{
3132 struct sk_buff *skb, *tskb = tcp_write_queue_tail(sk);3132 struct sk_buff *skb, *tskb, *tail = tcp_write_queue_tail(sk);
3133 struct tcp_sock *tp = tcp_sk(sk);3133 struct tcp_sock *tp = tcp_sk(sk);
3134 3134
3135 /* Optimization, tack on the FIN if we have one skb in write queue and3135 /* Optimization, tack on the FIN if we have one skb in write queue and
@@ -3137,6 +3137,7 @@ void tcp_send_fin(struct sock *sk) · 1 unmodified line
3137 * Note: in the latter case, FIN packet will be sent after a timeout,3137 * Note: in the latter case, FIN packet will be sent after a timeout,
3138 * as TCP stack thinks it has already been transmitted.3138 * as TCP stack thinks it has already been transmitted.
3139 */3139 */
3140 tskb = tail;
3140 if (!tskb && tcp_under_memory_pressure(sk))3141 if (!tskb && tcp_under_memory_pressure(sk))
3141 tskb = skb_rb_last(&sk->tcp_rtx_queue);3142 tskb = skb_rb_last(&sk->tcp_rtx_queue);
3142 3143
@@ -3144,7 +3145,7 @@ void tcp_send_fin(struct sock *sk) · 1 unmodified line
3144 TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN;3145 TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN;
3145 TCP_SKB_CB(tskb)->end_seq++;3146 TCP_SKB_CB(tskb)->end_seq++;
3146 tp->write_seq++;3147 tp->write_seq++;
3147 if (tcp_write_queue_empty(sk)) {3148 if (!tail) {
3148 /* This means tskb was already sent.3149 /* This means tskb was already sent.
3149 * Pretend we included the FIN on previous transmit.3150 * Pretend we included the FIN on previous transmit.
3150 * We need to set tp->snd_nxt to the value it would have3151 * We need to set tp->snd_nxt to the value it would have

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t