Skip to contentSkip to conversation

Patch "tcp: fix possible deadlock in tcp_send_fin()" has been added to the 3.14-stable tree

PATCH [email protected] 1 participant 1 message Apr 29, 2015

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

tcp: fix possible deadlock in tcp_send_fin()

to the 3.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
tcp-fix-possible-deadlock-in-tcp_send_fin.patch
and it can be found in the queue-3.14 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From foo@baz Wed Apr 29 12:00:35 CEST 2015

From: Eric Dumazet <[email protected]>
Date: Tue, 21 Apr 2015 18:32:24 -0700
Subject: tcp: fix possible deadlock in tcp_send_fin()

From: Eric Dumazet <[email protected]>

[ Upstream commit d83769a580f1132ac26439f50068a29b02be535e ]

Using sk_stream_alloc_skb() in tcp_send_fin() is dangerous in case a huge process is killed by OOM, and tcp_mem[2] is hit.

To be able to free memory we need to make progress, so this patch allows FIN packets to not care about tcp_mem[2], if skb allocation succeeded.

In a follow-up patch, we might abort tcp_send_fin() infinite loop in case TIF_MEMDIE is set on this thread, as memory allocator did its best getting extra memory already.

This patch reverts d22e15371811 ("tcp: fix tcp fin memory accounting")

Fixes d22e15371811 ("tcp: fix tcp fin memory accounting")
---
 net/ipv4/tcp_output.c |   20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)
net/ipv4/tcp_output.c +19 -1
@@ -2595,6 +2595,21 @@ begin_fwd:
 	}
 }
 
+/* We allow to exceed memory limits for FIN packets to expedite
+ * connection tear down and (memory) recovery.
+ * Otherwise tcp_send_fin() could loop forever.
+ */
+static void sk_forced_wmem_schedule(struct sock *sk, int size)
+{
+	int amt, status;
+
+	if (size <= sk->sk_forward_alloc)
+		return;
+	amt = sk_mem_pages(size);
+	sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
+	sk_memory_allocated_add(sk, amt, &status);
+}
+
 /* Send a fin.  The caller locks the socket for us.  This cannot be
  * allowed to fail queueing a FIN frame under any circumstances.
  */
@@ -2617,11 +2632,14 @@ void tcp_send_fin(struct sock *sk)
 	} else {
 		/* Socket is locked, keep trying until memory is available. */
 		for (;;) {
-			skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
+			skb = alloc_skb_fclone(MAX_TCP_HEADER,
+					       sk->sk_allocation);
 			if (skb)
 				break;
 			yield();
 		}
+		skb_reserve(skb, MAX_TCP_HEADER);
+		sk_forced_wmem_schedule(sk, skb->truesize);
 		/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
 		tcp_init_nondata_skb(skb, tp->write_seq,
 				     TCPHDR_ACK | TCPHDR_FIN);

Patches currently in stable-queue which might be from [email protected] are

queue-3.14/net-fix-crash-in-build_skb.patch queue-3.14/tcp-avoid-looping-in-tcp_send_fin.patch queue-3.14/net-do-not-deplete-pfmemalloc-reserve.patch queue-3.14/tcp-fix-possible-deadlock-in-tcp_send_fin.patch