net: relax rcvbuf limits
skb->truesize might be big even for a small packet.
Its even bigger after commit 87fb4b7b53
(net: more accurate skb
truesize) and big MTU.
We should allow queueing at least one packet per receiver, even with a
low RCVBUF setting.
Reported-by: Michal Simek <monstr@monstr.eu>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
a0a129f8b6
commit
0fd7bac6b6
@@ -637,12 +637,14 @@ static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Take into account size of receive queue and backlog queue
|
* Take into account size of receive queue and backlog queue
|
||||||
|
* Do not take into account this skb truesize,
|
||||||
|
* to allow even a single big packet to come.
|
||||||
*/
|
*/
|
||||||
static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff *skb)
|
static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc);
|
unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc);
|
||||||
|
|
||||||
return qsize + skb->truesize > sk->sk_rcvbuf;
|
return qsize > sk->sk_rcvbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The per-socket spinlock must be held here. */
|
/* The per-socket spinlock must be held here. */
|
||||||
|
@@ -288,11 +288,7 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct sk_buff_head *list = &sk->sk_receive_queue;
|
struct sk_buff_head *list = &sk->sk_receive_queue;
|
||||||
|
|
||||||
/* Cast sk->rcvbuf to unsigned... It's pointless, but reduces
|
if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) {
|
||||||
number of warnings when compiling with -W --ANK
|
|
||||||
*/
|
|
||||||
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
|
|
||||||
(unsigned)sk->sk_rcvbuf) {
|
|
||||||
atomic_inc(&sk->sk_drops);
|
atomic_inc(&sk->sk_drops);
|
||||||
trace_sock_rcvqueue_full(sk, skb);
|
trace_sock_rcvqueue_full(sk, skb);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@@ -1630,8 +1630,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||||||
if (snaplen > res)
|
if (snaplen > res)
|
||||||
snaplen = res;
|
snaplen = res;
|
||||||
|
|
||||||
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
|
if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
|
||||||
(unsigned)sk->sk_rcvbuf)
|
|
||||||
goto drop_n_acct;
|
goto drop_n_acct;
|
||||||
|
|
||||||
if (skb_shared(skb)) {
|
if (skb_shared(skb)) {
|
||||||
@@ -1762,8 +1761,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||||||
if (po->tp_version <= TPACKET_V2) {
|
if (po->tp_version <= TPACKET_V2) {
|
||||||
if (macoff + snaplen > po->rx_ring.frame_size) {
|
if (macoff + snaplen > po->rx_ring.frame_size) {
|
||||||
if (po->copy_thresh &&
|
if (po->copy_thresh &&
|
||||||
atomic_read(&sk->sk_rmem_alloc) + skb->truesize
|
atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) {
|
||||||
< (unsigned)sk->sk_rcvbuf) {
|
|
||||||
if (skb_shared(skb)) {
|
if (skb_shared(skb)) {
|
||||||
copy_skb = skb_clone(skb, GFP_ATOMIC);
|
copy_skb = skb_clone(skb, GFP_ATOMIC);
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user