Commit e42134b5 authored by David S. Miller's avatar David S. Miller

Merge branch 'tcp-mem-pressure-fixes'

Eric Dumazet says:

====================
tcp: final (?) round of mem pressure fixes

While working on prior patch series (e10b02ee "Merge branch
'net-reduce-tcp_memory_allocated-inflation'"), I found that we
could still have frozen TCP flows under memory pressure.

I thought we had solved this in 2015, but the fix was not complete.

v2: deal with zerocopy tx paths.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e8b03391 f54755f6
...@@ -951,6 +951,40 @@ static int tcp_downgrade_zcopy_pure(struct sock *sk, struct sk_buff *skb) ...@@ -951,6 +951,40 @@ static int tcp_downgrade_zcopy_pure(struct sock *sk, struct sk_buff *skb)
return 0; return 0;
} }
static int tcp_wmem_schedule(struct sock *sk, int copy)
{
int left;
if (likely(sk_wmem_schedule(sk, copy)))
return copy;
/* We could be in trouble if we have nothing queued.
* Use whatever is left in sk->sk_forward_alloc and tcp_wmem[0]
* to guarantee some progress.
*/
left = sock_net(sk)->ipv4.sysctl_tcp_wmem[0] - sk->sk_wmem_queued;
if (left > 0)
sk_forced_mem_schedule(sk, min(left, copy));
return min(copy, sk->sk_forward_alloc);
}
static int tcp_wmem_schedule(struct sock *sk, int copy)
{
int left;
if (likely(sk_wmem_schedule(sk, copy)))
return copy;
/* We could be in trouble if we have nothing queued.
* Use whatever is left in sk->sk_forward_alloc and tcp_wmem[0]
* to guarantee some progress.
*/
left = sock_net(sk)->ipv4.sysctl_tcp_wmem[0] - sk->sk_wmem_queued;
if (left > 0)
sk_forced_mem_schedule(sk, min(left, copy));
return min(copy, sk->sk_forward_alloc);
}
static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags, static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
struct page *page, int offset, size_t *size) struct page *page, int offset, size_t *size)
{ {
...@@ -986,7 +1020,11 @@ static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags, ...@@ -986,7 +1020,11 @@ static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
tcp_mark_push(tp, skb); tcp_mark_push(tp, skb);
goto new_segment; goto new_segment;
} }
if (tcp_downgrade_zcopy_pure(sk, skb) || !sk_wmem_schedule(sk, copy)) if (tcp_downgrade_zcopy_pure(sk, skb))
return NULL;
copy = tcp_wmem_schedule(sk, copy);
if (!copy)
return NULL; return NULL;
if (can_coalesce) { if (can_coalesce) {
...@@ -1334,8 +1372,11 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) ...@@ -1334,8 +1372,11 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
copy = min_t(int, copy, pfrag->size - pfrag->offset); copy = min_t(int, copy, pfrag->size - pfrag->offset);
if (tcp_downgrade_zcopy_pure(sk, skb) || if (tcp_downgrade_zcopy_pure(sk, skb))
!sk_wmem_schedule(sk, copy)) goto wait_for_space;
copy = tcp_wmem_schedule(sk, copy);
if (!copy)
goto wait_for_space; goto wait_for_space;
err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb, err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
...@@ -1362,7 +1403,8 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) ...@@ -1362,7 +1403,8 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
skb_shinfo(skb)->flags |= SKBFL_PURE_ZEROCOPY; skb_shinfo(skb)->flags |= SKBFL_PURE_ZEROCOPY;
if (!skb_zcopy_pure(skb)) { if (!skb_zcopy_pure(skb)) {
if (!sk_wmem_schedule(sk, copy)) copy = tcp_wmem_schedule(sk, copy);
if (!copy)
goto wait_for_space; goto wait_for_space;
} }
......
...@@ -3362,11 +3362,12 @@ void tcp_xmit_retransmit_queue(struct sock *sk) ...@@ -3362,11 +3362,12 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
*/ */
void sk_forced_mem_schedule(struct sock *sk, int size) void sk_forced_mem_schedule(struct sock *sk, int size)
{ {
int amt; int delta, amt;
if (size <= sk->sk_forward_alloc) delta = size - sk->sk_forward_alloc;
if (delta <= 0)
return; return;
amt = sk_mem_pages(size); amt = sk_mem_pages(delta);
sk->sk_forward_alloc += amt << PAGE_SHIFT; sk->sk_forward_alloc += amt << PAGE_SHIFT;
sk_memory_allocated_add(sk, amt); sk_memory_allocated_add(sk, amt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment