Skip to content

Commit

Permalink
tcp: ensure epoll edge trigger wakeup when write queue is empty
Browse files Browse the repository at this point in the history
We currently rely on the setting of SOCK_NOSPACE in the write()
path to ensure that we wake up any epoll edge trigger waiters when
acks return to free space in the write queue. However, if we fail
to allocate even a single skb in the write queue, we could end up
waiting indefinitely.

Fix this by explicitly issuing a wakeup when we detect the condition
of an empty write queue and a return value of -EAGAIN. This allows
userspace to re-try as we expect this to be a temporary failure.

I've tested this approach by artificially making
sk_stream_alloc_skb() return NULL periodically. In that case,
epoll edge trigger waiters will hang indefinitely in epoll_wait()
without this patch.

Signed-off-by: Jason Baron <jbaron@akamai.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jason Baron authored and David S. Miller committed May 21, 2015
1 parent b92d581 commit ce5ec44
Showing 1 changed file with 6 additions and 0 deletions.
6 changes: 6 additions & 0 deletions net/ipv4/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,9 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
if (copied)
goto out;
out_err:
/* make sure we wake any epoll edge trigger waiter */
if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
sk->sk_write_space(sk);
return sk_stream_error(sk, flags, err);
}

Expand Down Expand Up @@ -1288,6 +1291,9 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
goto out;
out_err:
err = sk_stream_error(sk, flags, err);
/* make sure we wake any epoll edge trigger waiter */
if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
sk->sk_write_space(sk);
release_sock(sk);
return err;
}
Expand Down

0 comments on commit ce5ec44

Please sign in to comment.