@@ -1255,6 +1255,9 @@ static bool packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb)
spin_unlock(&sk->sk_receive_queue.lock);
}
+ if (po->pressure == has_room)
+ xchg(&po->pressure, !has_room);
+
return has_room;
}
@@ -1322,7 +1325,7 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f,
unsigned int idx, bool try_self,
unsigned int num)
{
- struct packet_sock *po;
+ struct packet_sock *po, *po_next;
unsigned int i, j;
po = pkt_sk(f->arr[idx]);
@@ -1331,7 +1334,9 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f,
i = j = min_t(int, po->rollover->sock, num - 1);
do {
- if (i != idx && packet_rcv_has_room(pkt_sk(f->arr[i]), skb)) {
+ po_next = pkt_sk(f->arr[i]);
+ if (po_next != po && !po_next->pressure &&
+ packet_rcv_has_room(po_next, skb)) {
if (i != j)
po->rollover->sock = i;
return i;
@@ -2956,6 +2961,9 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (skb == NULL)
goto out;
+ if (pkt_sk(sk)->pressure && !sk_rmem_alloc_get(sk))
+ xchg(&pkt_sk(sk)->pressure, 0);
+
if (pkt_sk(sk)->has_vnet_hdr) {
struct virtio_net_hdr vnet_hdr = { 0 };
@@ -3718,6 +3726,10 @@ static unsigned int packet_poll(struct file *file, struct socket *sock,
mask |= POLLOUT | POLLWRNORM;
}
spin_unlock_bh(&sk->sk_write_queue.lock);
+
+ if (po->pressure && !(mask & POLLIN))
+ xchg(&po->pressure, 0);
+
return mask;
}
@@ -105,6 +105,7 @@ struct packet_sock {
auxdata:1,
origdev:1,
has_vnet_hdr:1;
+ int pressure;
int ifindex; /* bound device */
__be16 num;
struct packet_rollover *rollover;