[source] generic: net: tcp: backport tcp tx performance patches

LEDE Commits lede-commits at lists.infradead.org
Sun Oct 8 06:35:47 PDT 2017


stintel pushed a commit to source.git, branch master:
https://git.lede-project.org/b2ea46fe236ae02d845f94cf984cbc1786870333

commit b2ea46fe236ae02d845f94cf984cbc1786870333
Author: Pavel Kubelun <be.dissent at gmail.com>
AuthorDate: Tue Jul 25 03:57:31 2017 -0400

    generic: net: tcp: backport tcp tx performance patches
    
    An overall throughput gain of 22 % for heavy TCP use over a single TX queue.
    
    Original patchset comment
    https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v4.13&id=3f4888adae7c1619b990d98a9b967536f71822b8
    
    Signed-off-by: Pavel Kubelun <be.dissent at gmail.com>
---
 .../024-1-tcp-tsq-add-tsq_flags-tsq_enum.patch     |  90 +++++++++++
 ...-remove-one-locked-operation-in-tcp_wfree.patch |  48 ++++++
 ...-tcp-tsq-add-shortcut-in-tcp_tasklet_func.patch |  71 +++++++++
 ...4-4-tcp-tsq-avoid-one-atomic-in-tcp_wfree.patch |  38 +++++
 ...q-add-a-shortcut-in-tcp_small_queue_check.patch |  37 +++++
 ...tcp-tcp_mtu_probe-is-likely-to-exit-early.patch |  55 +++++++
 ...nize-struct-sock-for-better-data-locality.patch | 157 ++++++++++++++++++
 ...tsq-move-tsq_flags-close-to-sk_wmem_alloc.patch | 176 +++++++++++++++++++++
 ...add-a-missing-barrier-in-tcp_tasklet_func.patch |  40 +++++
 9 files changed, 712 insertions(+)

diff --git a/target/linux/generic/backport-4.9/024-1-tcp-tsq-add-tsq_flags-tsq_enum.patch b/target/linux/generic/backport-4.9/024-1-tcp-tsq-add-tsq_flags-tsq_enum.patch
new file mode 100644
index 0000000..2031149
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-1-tcp-tsq-add-tsq_flags-tsq_enum.patch
@@ -0,0 +1,90 @@
+From 40fc3423b983b864bf70b03199191260ae9b2ea6 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:50 -0800
+Subject: [PATCH 01/10] tcp: tsq: add tsq_flags / tsq_enum
+
+This is a cleanup, to ease code review of following patches.
+
+Old 'enum tsq_flags' is renamed, and a new enumeration is added
+with the flags used in cmpxchg() operations as opposed to
+single bit operations.
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ include/linux/tcp.h   | 11 ++++++++++-
+ net/ipv4/tcp_output.c | 16 ++++++++--------
+ 2 files changed, 18 insertions(+), 9 deletions(-)
+
+--- a/include/linux/tcp.h
++++ b/include/linux/tcp.h
+@@ -367,7 +367,7 @@ struct tcp_sock {
+ 	u32	*saved_syn;
+ };
+ 
+-enum tsq_flags {
++enum tsq_enum {
+ 	TSQ_THROTTLED,
+ 	TSQ_QUEUED,
+ 	TCP_TSQ_DEFERRED,	   /* tcp_tasklet_func() found socket was owned */
+@@ -378,6 +378,15 @@ enum tsq_flags {
+ 				    */
+ };
+ 
++enum tsq_flags {
++	TSQF_THROTTLED			= (1UL << TSQ_THROTTLED),
++	TSQF_QUEUED			= (1UL << TSQ_QUEUED),
++	TCPF_TSQ_DEFERRED		= (1UL << TCP_TSQ_DEFERRED),
++	TCPF_WRITE_TIMER_DEFERRED	= (1UL << TCP_WRITE_TIMER_DEFERRED),
++	TCPF_DELACK_TIMER_DEFERRED	= (1UL << TCP_DELACK_TIMER_DEFERRED),
++	TCPF_MTU_REDUCED_DEFERRED	= (1UL << TCP_MTU_REDUCED_DEFERRED),
++};
++
+ static inline struct tcp_sock *tcp_sk(const struct sock *sk)
+ {
+ 	return (struct tcp_sock *)sk;
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -784,10 +784,10 @@ static void tcp_tasklet_func(unsigned lo
+ 	}
+ }
+ 
+-#define TCP_DEFERRED_ALL ((1UL << TCP_TSQ_DEFERRED) |		\
+-			  (1UL << TCP_WRITE_TIMER_DEFERRED) |	\
+-			  (1UL << TCP_DELACK_TIMER_DEFERRED) |	\
+-			  (1UL << TCP_MTU_REDUCED_DEFERRED))
++#define TCP_DEFERRED_ALL (TCPF_TSQ_DEFERRED |		\
++			  TCPF_WRITE_TIMER_DEFERRED |	\
++			  TCPF_DELACK_TIMER_DEFERRED |	\
++			  TCPF_MTU_REDUCED_DEFERRED)
+ /**
+  * tcp_release_cb - tcp release_sock() callback
+  * @sk: socket
+@@ -808,7 +808,7 @@ void tcp_release_cb(struct sock *sk)
+ 		nflags = flags & ~TCP_DEFERRED_ALL;
+ 	} while (cmpxchg(&tp->tsq_flags, flags, nflags) != flags);
+ 
+-	if (flags & (1UL << TCP_TSQ_DEFERRED))
++	if (flags & TCPF_TSQ_DEFERRED)
+ 		tcp_tsq_handler(sk);
+ 
+ 	/* Here begins the tricky part :
+@@ -822,15 +822,15 @@ void tcp_release_cb(struct sock *sk)
+ 	 */
+ 	sock_release_ownership(sk);
+ 
+-	if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
++	if (flags & TCPF_WRITE_TIMER_DEFERRED) {
+ 		tcp_write_timer_handler(sk);
+ 		__sock_put(sk);
+ 	}
+-	if (flags & (1UL << TCP_DELACK_TIMER_DEFERRED)) {
++	if (flags & TCPF_DELACK_TIMER_DEFERRED) {
+ 		tcp_delack_timer_handler(sk);
+ 		__sock_put(sk);
+ 	}
+-	if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) {
++	if (flags & TCPF_MTU_REDUCED_DEFERRED) {
+ 		inet_csk(sk)->icsk_af_ops->mtu_reduced(sk);
+ 		__sock_put(sk);
+ 	}
diff --git a/target/linux/generic/backport-4.9/024-2-tcp-tsq-remove-one-locked-operation-in-tcp_wfree.patch b/target/linux/generic/backport-4.9/024-2-tcp-tsq-remove-one-locked-operation-in-tcp_wfree.patch
new file mode 100644
index 0000000..914be60
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-2-tcp-tsq-remove-one-locked-operation-in-tcp_wfree.patch
@@ -0,0 +1,48 @@
+From 408f0a6c21e124cc4f6c7aa370b38aa47e55428d Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:51 -0800
+Subject: [PATCH 02/10] tcp: tsq: remove one locked operation in tcp_wfree()
+
+Instead of atomically clear TSQ_THROTTLED and atomically set TSQ_QUEUED
+bits, use one cmpxchg() to perform a single locked operation.
+
+Since the following patch will also set TCP_TSQ_DEFERRED here,
+this cmpxchg() will make this addition free.
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/ipv4/tcp_output.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -860,6 +860,7 @@ void tcp_wfree(struct sk_buff *skb)
+ {
+ 	struct sock *sk = skb->sk;
+ 	struct tcp_sock *tp = tcp_sk(sk);
++	unsigned long flags, nval, oval;
+ 	int wmem;
+ 
+ 	/* Keep one reference on sk_wmem_alloc.
+@@ -877,11 +878,17 @@ void tcp_wfree(struct sk_buff *skb)
+ 	if (wmem >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current)
+ 		goto out;
+ 
+-	if (test_and_clear_bit(TSQ_THROTTLED, &tp->tsq_flags) &&
+-	    !test_and_set_bit(TSQ_QUEUED, &tp->tsq_flags)) {
+-		unsigned long flags;
++	for (oval = READ_ONCE(tp->tsq_flags);; oval = nval) {
+ 		struct tsq_tasklet *tsq;
+ 
++		if (!(oval & TSQF_THROTTLED) || (oval & TSQF_QUEUED))
++			goto out;
++
++		nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED;
++		nval = cmpxchg(&tp->tsq_flags, oval, nval);
++		if (nval != oval)
++			continue;
++
+ 		/* queue this socket to tasklet queue */
+ 		local_irq_save(flags);
+ 		tsq = this_cpu_ptr(&tsq_tasklet);
diff --git a/target/linux/generic/backport-4.9/024-3-tcp-tsq-add-shortcut-in-tcp_tasklet_func.patch b/target/linux/generic/backport-4.9/024-3-tcp-tsq-add-shortcut-in-tcp_tasklet_func.patch
new file mode 100644
index 0000000..8f45c23
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-3-tcp-tsq-add-shortcut-in-tcp_tasklet_func.patch
@@ -0,0 +1,71 @@
+From b223feb9de2a65c533ff95c08e834fa732906ea5 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:52 -0800
+Subject: [PATCH 03/10] tcp: tsq: add shortcut in tcp_tasklet_func()
+
+Under high stress, I've seen tcp_tasklet_func() consuming
+~700 usec, handling ~150 tcp sockets.
+
+By setting TCP_TSQ_DEFERRED in tcp_wfree(), we give a chance
+for other cpus/threads entering tcp_write_xmit() to grab it,
+allowing tcp_tasklet_func() to skip sockets that already did
+an xmit cycle.
+
+In the future, we might give to ACK processing an increased
+budget to reduce even more tcp_tasklet_func() amount of work.
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/ipv4/tcp_output.c | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -767,19 +767,19 @@ static void tcp_tasklet_func(unsigned lo
+ 	list_for_each_safe(q, n, &list) {
+ 		tp = list_entry(q, struct tcp_sock, tsq_node);
+ 		list_del(&tp->tsq_node);
++		clear_bit(TSQ_QUEUED, &tp->tsq_flags);
+ 
+ 		sk = (struct sock *)tp;
+-		bh_lock_sock(sk);
+-
+-		if (!sock_owned_by_user(sk)) {
+-			tcp_tsq_handler(sk);
+-		} else {
+-			/* defer the work to tcp_release_cb() */
+-			set_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
++		if (!sk->sk_lock.owned &&
++		    test_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags)) {
++			bh_lock_sock(sk);
++			if (!sock_owned_by_user(sk)) {
++				clear_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
++				tcp_tsq_handler(sk);
++			}
++			bh_unlock_sock(sk);
+ 		}
+-		bh_unlock_sock(sk);
+ 
+-		clear_bit(TSQ_QUEUED, &tp->tsq_flags);
+ 		sk_free(sk);
+ 	}
+ }
+@@ -884,7 +884,7 @@ void tcp_wfree(struct sk_buff *skb)
+ 		if (!(oval & TSQF_THROTTLED) || (oval & TSQF_QUEUED))
+ 			goto out;
+ 
+-		nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED;
++		nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED | TCPF_TSQ_DEFERRED;
+ 		nval = cmpxchg(&tp->tsq_flags, oval, nval);
+ 		if (nval != oval)
+ 			continue;
+@@ -2179,6 +2179,8 @@ static bool tcp_write_xmit(struct sock *
+ 		    unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
+ 			break;
+ 
++		if (test_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags))
++			clear_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
+ 		if (tcp_small_queue_check(sk, skb, 0))
+ 			break;
+ 
diff --git a/target/linux/generic/backport-4.9/024-4-tcp-tsq-avoid-one-atomic-in-tcp_wfree.patch b/target/linux/generic/backport-4.9/024-4-tcp-tsq-avoid-one-atomic-in-tcp_wfree.patch
new file mode 100644
index 0000000..a25cdb5
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-4-tcp-tsq-avoid-one-atomic-in-tcp_wfree.patch
@@ -0,0 +1,38 @@
+From a9b204d1564702b704ad6fe74f10a102c7b87ba3 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:53 -0800
+Subject: [PATCH 04/10] tcp: tsq: avoid one atomic in tcp_wfree()
+
+Under high load, tcp_wfree() has an atomic operation trying
+to schedule a tasklet over and over.
+
+We can schedule it only if our per cpu list was empty.
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/ipv4/tcp_output.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -880,6 +880,7 @@ void tcp_wfree(struct sk_buff *skb)
+ 
+ 	for (oval = READ_ONCE(tp->tsq_flags);; oval = nval) {
+ 		struct tsq_tasklet *tsq;
++		bool empty;
+ 
+ 		if (!(oval & TSQF_THROTTLED) || (oval & TSQF_QUEUED))
+ 			goto out;
+@@ -892,8 +893,10 @@ void tcp_wfree(struct sk_buff *skb)
+ 		/* queue this socket to tasklet queue */
+ 		local_irq_save(flags);
+ 		tsq = this_cpu_ptr(&tsq_tasklet);
++		empty = list_empty(&tsq->head);
+ 		list_add(&tp->tsq_node, &tsq->head);
+-		tasklet_schedule(&tsq->tasklet);
++		if (empty)
++			tasklet_schedule(&tsq->tasklet);
+ 		local_irq_restore(flags);
+ 		return;
+ 	}
diff --git a/target/linux/generic/backport-4.9/024-5-tcp-tsq-add-a-shortcut-in-tcp_small_queue_check.patch b/target/linux/generic/backport-4.9/024-5-tcp-tsq-add-a-shortcut-in-tcp_small_queue_check.patch
new file mode 100644
index 0000000..dd1a37e
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-5-tcp-tsq-add-a-shortcut-in-tcp_small_queue_check.patch
@@ -0,0 +1,37 @@
+From 75eefc6c59fd2c5f1ab95a3a113c217237d12a31 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:54 -0800
+Subject: [PATCH 05/10] tcp: tsq: add a shortcut in tcp_small_queue_check()
+
+Always allow the two first skbs in write queue to be sent,
+regardless of sk_wmem_alloc/sk_pacing_rate values.
+
+This helps a lot in situations where TX completions are delayed either
+because of driver latencies or softirq latencies.
+
+Test is done with no cache line misses.
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/ipv4/tcp_output.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -2084,6 +2084,15 @@ static bool tcp_small_queue_check(struct
+ 	limit <<= factor;
+ 
+ 	if (atomic_read(&sk->sk_wmem_alloc) > limit) {
++		/* Always send the 1st or 2nd skb in write queue.
++		 * No need to wait for TX completion to call us back,
++		 * after softirq/tasklet schedule.
++		 * This helps when TX completions are delayed too much.
++		 */
++		if (skb == sk->sk_write_queue.next ||
++		    skb->prev == sk->sk_write_queue.next)
++			return false;
++
+ 		set_bit(TSQ_THROTTLED, &tcp_sk(sk)->tsq_flags);
+ 		/* It is possible TX completion already happened
+ 		 * before we set TSQ_THROTTLED, so we must
diff --git a/target/linux/generic/backport-4.9/024-6-tcp-tcp_mtu_probe-is-likely-to-exit-early.patch b/target/linux/generic/backport-4.9/024-6-tcp-tcp_mtu_probe-is-likely-to-exit-early.patch
new file mode 100644
index 0000000..f0ae2a9
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-6-tcp-tcp_mtu_probe-is-likely-to-exit-early.patch
@@ -0,0 +1,55 @@
+From 12a59abc22d6664f7d3944f625ceefee92de8820 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:55 -0800
+Subject: [PATCH 06/10] tcp: tcp_mtu_probe() is likely to exit early
+
+Adding a likely() in tcp_mtu_probe() moves its code which used to
+be inlined in front of tcp_write_xmit()
+
+We still have a cache line miss to access icsk->icsk_mtup.enabled,
+we will probably have to reorganize fields to help data locality.
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/ipv4/tcp_output.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -1925,26 +1925,26 @@ static inline void tcp_mtu_check_reprobe
+  */
+ static int tcp_mtu_probe(struct sock *sk)
+ {
+-	struct tcp_sock *tp = tcp_sk(sk);
+ 	struct inet_connection_sock *icsk = inet_csk(sk);
++	struct tcp_sock *tp = tcp_sk(sk);
+ 	struct sk_buff *skb, *nskb, *next;
+ 	struct net *net = sock_net(sk);
+-	int len;
+ 	int probe_size;
+ 	int size_needed;
+-	int copy;
++	int copy, len;
+ 	int mss_now;
+ 	int interval;
+ 
+ 	/* Not currently probing/verifying,
+ 	 * not in recovery,
+ 	 * have enough cwnd, and
+-	 * not SACKing (the variable headers throw things off) */
+-	if (!icsk->icsk_mtup.enabled ||
+-	    icsk->icsk_mtup.probe_size ||
+-	    inet_csk(sk)->icsk_ca_state != TCP_CA_Open ||
+-	    tp->snd_cwnd < 11 ||
+-	    tp->rx_opt.num_sacks || tp->rx_opt.dsack)
++	 * not SACKing (the variable headers throw things off)
++	 */
++	if (likely(!icsk->icsk_mtup.enabled ||
++		   icsk->icsk_mtup.probe_size ||
++		   inet_csk(sk)->icsk_ca_state != TCP_CA_Open ||
++		   tp->snd_cwnd < 11 ||
++		   tp->rx_opt.num_sacks || tp->rx_opt.dsack))
+ 		return -1;
+ 
+ 	/* Use binary search for probe_size between tcp_mss_base,
diff --git a/target/linux/generic/backport-4.9/024-7-net-reorganize-struct-sock-for-better-data-locality.patch b/target/linux/generic/backport-4.9/024-7-net-reorganize-struct-sock-for-better-data-locality.patch
new file mode 100644
index 0000000..e8c1915
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-7-net-reorganize-struct-sock-for-better-data-locality.patch
@@ -0,0 +1,157 @@
+From 9115e8cd2a0c6eaaa900c462721f12e1d45f326c Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:56 -0800
+Subject: [PATCH 07/10] net: reorganize struct sock for better data locality
+
+Group fields used in TX path, and keep some cache lines mostly read
+to permit sharing among cpus.
+
+Gained two 4 bytes holes on 64bit arches.
+
+Added a place holder for tcp tsq_flags, next to sk_wmem_alloc
+to speed up tcp_wfree() in the following patch.
+
+I have not added ____cacheline_aligned_in_smp, this might be done later.
+I prefer doing this once inet and tcp/udp sockets reorg is also done.
+
+Tested with both TCP and UDP.
+
+UDP receiver performance under flood increased by ~20 % :
+Accessing sk_filter/sk_wq/sk_napi_id no longer stalls because sk_drops
+was moved away from a critical cache line, now mostly read and shared.
+
+	/* --- cacheline 4 boundary (256 bytes) --- */
+	unsigned int               sk_napi_id;           /* 0x100   0x4 */
+	int                        sk_rcvbuf;            /* 0x104   0x4 */
+	struct sk_filter *         sk_filter;            /* 0x108   0x8 */
+	union {
+		struct socket_wq * sk_wq;                /*         0x8 */
+		struct socket_wq * sk_wq_raw;            /*         0x8 */
+	};                                               /* 0x110   0x8 */
+	struct xfrm_policy *       sk_policy[2];         /* 0x118  0x10 */
+	struct dst_entry *         sk_rx_dst;            /* 0x128   0x8 */
+	struct dst_entry *         sk_dst_cache;         /* 0x130   0x8 */
+	atomic_t                   sk_omem_alloc;        /* 0x138   0x4 */
+	int                        sk_sndbuf;            /* 0x13c   0x4 */
+	/* --- cacheline 5 boundary (320 bytes) --- */
+	int                        sk_wmem_queued;       /* 0x140   0x4 */
+	atomic_t                   sk_wmem_alloc;        /* 0x144   0x4 */
+	long unsigned int          sk_tsq_flags;         /* 0x148   0x8 */
+	struct sk_buff *           sk_send_head;         /* 0x150   0x8 */
+	struct sk_buff_head        sk_write_queue;       /* 0x158  0x18 */
+	__s32                      sk_peek_off;          /* 0x170   0x4 */
+	int                        sk_write_pending;     /* 0x174   0x4 */
+	long int                   sk_sndtimeo;          /* 0x178   0x8 */
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Tested-by: Paolo Abeni <pabeni at redhat.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ include/net/sock.h | 51 +++++++++++++++++++++++++++------------------------
+ 1 file changed, 27 insertions(+), 24 deletions(-)
+
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -343,6 +343,9 @@ struct sock {
+ #define sk_rxhash		__sk_common.skc_rxhash
+ 
+ 	socket_lock_t		sk_lock;
++	atomic_t		sk_drops;
++	int			sk_rcvlowat;
++	struct sk_buff_head	sk_error_queue;
+ 	struct sk_buff_head	sk_receive_queue;
+ 	/*
+ 	 * The backlog queue is special, it is always used with
+@@ -359,14 +362,13 @@ struct sock {
+ 		struct sk_buff	*tail;
+ 	} sk_backlog;
+ #define sk_rmem_alloc sk_backlog.rmem_alloc
+-	int			sk_forward_alloc;
+ 
+-	__u32			sk_txhash;
++	int			sk_forward_alloc;
+ #ifdef CONFIG_NET_RX_BUSY_POLL
+-	unsigned int		sk_napi_id;
+ 	unsigned int		sk_ll_usec;
++	/* ===== mostly read cache line ===== */
++	unsigned int		sk_napi_id;
+ #endif
+-	atomic_t		sk_drops;
+ 	int			sk_rcvbuf;
+ 
+ 	struct sk_filter __rcu	*sk_filter;
+@@ -379,11 +381,30 @@ struct sock {
+ #endif
+ 	struct dst_entry	*sk_rx_dst;
+ 	struct dst_entry __rcu	*sk_dst_cache;
+-	/* Note: 32bit hole on 64bit arches */
+-	atomic_t		sk_wmem_alloc;
+ 	atomic_t		sk_omem_alloc;
+ 	int			sk_sndbuf;
++
++	/* ===== cache line for TX ===== */
++	int			sk_wmem_queued;
++	atomic_t		sk_wmem_alloc;
++	unsigned long		sk_tsq_flags;
++	struct sk_buff		*sk_send_head;
+ 	struct sk_buff_head	sk_write_queue;
++	__s32			sk_peek_off;
++	int			sk_write_pending;
++	long			sk_sndtimeo;
++	struct timer_list	sk_timer;
++	__u32			sk_priority;
++	__u32			sk_mark;
++	u32			sk_pacing_rate; /* bytes per second */
++	u32			sk_max_pacing_rate;
++	struct page_frag	sk_frag;
++	netdev_features_t	sk_route_caps;
++	netdev_features_t	sk_route_nocaps;
++	int			sk_gso_type;
++	unsigned int		sk_gso_max_size;
++	gfp_t			sk_allocation;
++	__u32			sk_txhash;
+ 
+ 	/*
+ 	 * Because of non atomicity rules, all
+@@ -399,41 +420,23 @@ struct sock {
+ #define SK_PROTOCOL_MAX U8_MAX
+ 	kmemcheck_bitfield_end(flags);
+ 
+-	int			sk_wmem_queued;
+-	gfp_t			sk_allocation;
+-	u32			sk_pacing_rate; /* bytes per second */
+-	u32			sk_max_pacing_rate;
+-	netdev_features_t	sk_route_caps;
+-	netdev_features_t	sk_route_nocaps;
+-	int			sk_gso_type;
+-	unsigned int		sk_gso_max_size;
+ 	u16			sk_gso_max_segs;
+-	int			sk_rcvlowat;
+ 	unsigned long	        sk_lingertime;
+-	struct sk_buff_head	sk_error_queue;
+ 	struct proto		*sk_prot_creator;
+ 	rwlock_t		sk_callback_lock;
+ 	int			sk_err,
+ 				sk_err_soft;
+ 	u32			sk_ack_backlog;
+ 	u32			sk_max_ack_backlog;
+-	__u32			sk_priority;
+-	__u32			sk_mark;
+ 	struct pid		*sk_peer_pid;
+ 	const struct cred	*sk_peer_cred;
+ 	long			sk_rcvtimeo;
+-	long			sk_sndtimeo;
+-	struct timer_list	sk_timer;
+ 	ktime_t			sk_stamp;
+ 	u16			sk_tsflags;
+ 	u8			sk_shutdown;
+ 	u32			sk_tskey;
+ 	struct socket		*sk_socket;
+ 	void			*sk_user_data;
+-	struct page_frag	sk_frag;
+-	struct sk_buff		*sk_send_head;
+-	__s32			sk_peek_off;
+-	int			sk_write_pending;
+ #ifdef CONFIG_SECURITY
+ 	void			*sk_security;
+ #endif
diff --git a/target/linux/generic/backport-4.9/024-8-tcp-tsq-move-tsq_flags-close-to-sk_wmem_alloc.patch b/target/linux/generic/backport-4.9/024-8-tcp-tsq-move-tsq_flags-close-to-sk_wmem_alloc.patch
new file mode 100644
index 0000000..545fe60
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-8-tcp-tsq-move-tsq_flags-close-to-sk_wmem_alloc.patch
@@ -0,0 +1,176 @@
+From 7aa5470c2c09265902b5e4289afa82e4e7c2987e Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Sat, 3 Dec 2016 11:14:57 -0800
+Subject: [PATCH 08/10] tcp: tsq: move tsq_flags close to sk_wmem_alloc
+
+tsq_flags being in the same cache line than sk_wmem_alloc
+makes a lot of sense. Both fields are changed from tcp_wfree()
+and more generally by various TSQ related functions.
+
+Prior patch made room in struct sock and added sk_tsq_flags,
+this patch deletes tsq_flags from struct tcp_sock.
+
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ include/linux/tcp.h   |  1 -
+ net/ipv4/tcp.c        |  4 ++--
+ net/ipv4/tcp_ipv4.c   |  2 +-
+ net/ipv4/tcp_output.c | 24 +++++++++++-------------
+ net/ipv4/tcp_timer.c  |  4 ++--
+ net/ipv6/tcp_ipv6.c   |  2 +-
+ 6 files changed, 17 insertions(+), 20 deletions(-)
+
+--- a/include/linux/tcp.h
++++ b/include/linux/tcp.h
+@@ -192,7 +192,6 @@ struct tcp_sock {
+ 	u32	tsoffset;	/* timestamp offset */
+ 
+ 	struct list_head tsq_node; /* anchor in tsq_tasklet.head list */
+-	unsigned long	tsq_flags;
+ 
+ 	/* Data for direct copy to user */
+ 	struct {
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -665,9 +665,9 @@ static void tcp_push(struct sock *sk, in
+ 	if (tcp_should_autocork(sk, skb, size_goal)) {
+ 
+ 		/* avoid atomic op if TSQ_THROTTLED bit is already set */
+-		if (!test_bit(TSQ_THROTTLED, &tp->tsq_flags)) {
++		if (!test_bit(TSQ_THROTTLED, &sk->sk_tsq_flags)) {
+ 			NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING);
+-			set_bit(TSQ_THROTTLED, &tp->tsq_flags);
++			set_bit(TSQ_THROTTLED, &sk->sk_tsq_flags);
+ 		}
+ 		/* It is possible TX completion already happened
+ 		 * before we set TSQ_THROTTLED.
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -446,7 +446,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb
+ 			if (!sock_owned_by_user(sk)) {
+ 				tcp_v4_mtu_reduced(sk);
+ 			} else {
+-				if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags))
++				if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &sk->sk_tsq_flags))
+ 					sock_hold(sk);
+ 			}
+ 			goto out;
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -767,14 +767,15 @@ static void tcp_tasklet_func(unsigned lo
+ 	list_for_each_safe(q, n, &list) {
+ 		tp = list_entry(q, struct tcp_sock, tsq_node);
+ 		list_del(&tp->tsq_node);
+-		clear_bit(TSQ_QUEUED, &tp->tsq_flags);
+ 
+ 		sk = (struct sock *)tp;
++		clear_bit(TSQ_QUEUED, &sk->sk_tsq_flags);
++
+ 		if (!sk->sk_lock.owned &&
+-		    test_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags)) {
++		    test_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags)) {
+ 			bh_lock_sock(sk);
+ 			if (!sock_owned_by_user(sk)) {
+-				clear_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
++				clear_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags);
+ 				tcp_tsq_handler(sk);
+ 			}
+ 			bh_unlock_sock(sk);
+@@ -797,16 +798,15 @@ static void tcp_tasklet_func(unsigned lo
+  */
+ void tcp_release_cb(struct sock *sk)
+ {
+-	struct tcp_sock *tp = tcp_sk(sk);
+ 	unsigned long flags, nflags;
+ 
+ 	/* perform an atomic operation only if at least one flag is set */
+ 	do {
+-		flags = tp->tsq_flags;
++		flags = sk->sk_tsq_flags;
+ 		if (!(flags & TCP_DEFERRED_ALL))
+ 			return;
+ 		nflags = flags & ~TCP_DEFERRED_ALL;
+-	} while (cmpxchg(&tp->tsq_flags, flags, nflags) != flags);
++	} while (cmpxchg(&sk->sk_tsq_flags, flags, nflags) != flags);
+ 
+ 	if (flags & TCPF_TSQ_DEFERRED)
+ 		tcp_tsq_handler(sk);
+@@ -878,7 +878,7 @@ void tcp_wfree(struct sk_buff *skb)
+ 	if (wmem >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current)
+ 		goto out;
+ 
+-	for (oval = READ_ONCE(tp->tsq_flags);; oval = nval) {
++	for (oval = READ_ONCE(sk->sk_tsq_flags);; oval = nval) {
+ 		struct tsq_tasklet *tsq;
+ 		bool empty;
+ 
+@@ -886,7 +886,7 @@ void tcp_wfree(struct sk_buff *skb)
+ 			goto out;
+ 
+ 		nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED | TCPF_TSQ_DEFERRED;
+-		nval = cmpxchg(&tp->tsq_flags, oval, nval);
++		nval = cmpxchg(&sk->sk_tsq_flags, oval, nval);
+ 		if (nval != oval)
+ 			continue;
+ 
+@@ -2093,7 +2093,7 @@ static bool tcp_small_queue_check(struct
+ 		    skb->prev == sk->sk_write_queue.next)
+ 			return false;
+ 
+-		set_bit(TSQ_THROTTLED, &tcp_sk(sk)->tsq_flags);
++		set_bit(TSQ_THROTTLED, &sk->sk_tsq_flags);
+ 		/* It is possible TX completion already happened
+ 		 * before we set TSQ_THROTTLED, so we must
+ 		 * test again the condition.
+@@ -2191,8 +2191,8 @@ static bool tcp_write_xmit(struct sock *
+ 		    unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
+ 			break;
+ 
+-		if (test_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags))
+-			clear_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
++		if (test_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags))
++			clear_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags);
+ 		if (tcp_small_queue_check(sk, skb, 0))
+ 			break;
+ 
+@@ -3495,8 +3495,6 @@ void tcp_send_ack(struct sock *sk)
+ 	/* We do not want pure acks influencing TCP Small Queues or fq/pacing
+ 	 * too much.
+ 	 * SKB_TRUESIZE(max(1 .. 66, MAX_TCP_HEADER)) is unfortunately ~784
+-	 * We also avoid tcp_wfree() overhead (cache line miss accessing
+-	 * tp->tsq_flags) by using regular sock_wfree()
+ 	 */
+ 	skb_set_tcp_pure_ack(buff);
+ 
+--- a/net/ipv4/tcp_timer.c
++++ b/net/ipv4/tcp_timer.c
+@@ -311,7 +311,7 @@ static void tcp_delack_timer(unsigned lo
+ 		inet_csk(sk)->icsk_ack.blocked = 1;
+ 		__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
+ 		/* deleguate our work to tcp_release_cb() */
+-		if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags))
++		if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags))
+ 			sock_hold(sk);
+ 	}
+ 	bh_unlock_sock(sk);
+@@ -594,7 +594,7 @@ static void tcp_write_timer(unsigned lon
+ 		tcp_write_timer_handler(sk);
+ 	} else {
+ 		/* delegate our work to tcp_release_cb() */
+-		if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags))
++		if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &sk->sk_tsq_flags))
+ 			sock_hold(sk);
+ 	}
+ 	bh_unlock_sock(sk);
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -404,7 +404,7 @@ static void tcp_v6_err(struct sk_buff *s
+ 		if (!sock_owned_by_user(sk))
+ 			tcp_v6_mtu_reduced(sk);
+ 		else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED,
+-					   &tp->tsq_flags))
++					   &sk->sk_tsq_flags))
+ 			sock_hold(sk);
+ 		goto out;
+ 	}
diff --git a/target/linux/generic/backport-4.9/024-9-tcp-add-a-missing-barrier-in-tcp_tasklet_func.patch b/target/linux/generic/backport-4.9/024-9-tcp-add-a-missing-barrier-in-tcp_tasklet_func.patch
new file mode 100644
index 0000000..d2b8de6
--- /dev/null
+++ b/target/linux/generic/backport-4.9/024-9-tcp-add-a-missing-barrier-in-tcp_tasklet_func.patch
@@ -0,0 +1,40 @@
+From 0a9648f1293966c838dc570da73c15a76f4c89d6 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet at google.com>
+Date: Wed, 21 Dec 2016 05:42:43 -0800
+Subject: [PATCH 09/10] tcp: add a missing barrier in tcp_tasklet_func()
+
+Madalin reported crashes happening in tcp_tasklet_func() on powerpc64
+
+Before TSQ_QUEUED bit is cleared, we must ensure the changes done
+by list_del(&tp->tsq_node); are committed to memory, otherwise
+corruption might happen, as an other cpu could catch TSQ_QUEUED
+clearance too soon.
+
+We can notice that old kernels were immune to this bug, because
+TSQ_QUEUED was cleared after a bh_lock_sock(sk)/bh_unlock_sock(sk)
+section, but they could have missed a kick to write additional bytes,
+when NIC interrupts for a given flow are spread to multiple cpus.
+
+Affected TCP flows would need an incoming ACK or RTO timer to add more
+packets to the pipe. So overall situation should be better now.
+
+Fixes: b223feb9de2a ("tcp: tsq: add shortcut in tcp_tasklet_func()")
+Signed-off-by: Eric Dumazet <edumazet at google.com>
+Reported-by: Madalin Bucur <madalin.bucur at nxp.com>
+Tested-by: Madalin Bucur <madalin.bucur at nxp.com>
+Tested-by: Xing Lei <xing.lei at nxp.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/ipv4/tcp_output.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -769,6 +769,7 @@ static void tcp_tasklet_func(unsigned lo
+ 		list_del(&tp->tsq_node);
+ 
+ 		sk = (struct sock *)tp;
++		smp_mb__before_atomic();
+ 		clear_bit(TSQ_QUEUED, &sk->sk_tsq_flags);
+ 
+ 		if (!sk->sk_lock.owned &&



More information about the lede-commits mailing list