return prb_lookup_block(po, &po->rx_ring, idx, TP_STATUS_KERNEL);
 }
 
-static int packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb)
+static int __packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb)
 {
        struct sock *sk = &po->sk;
        int ret = ROOM_NONE;
 
        if (po->prot_hook.func != tpacket_rcv) {
                int avail = sk->sk_rcvbuf - atomic_read(&sk->sk_rmem_alloc)
-                                         - skb->truesize;
+                                         - (skb ? skb->truesize : 0);
                if (avail > (sk->sk_rcvbuf >> ROOM_POW_OFF))
                        return ROOM_NORMAL;
                else if (avail > 0)
                        return ROOM_NONE;
        }
 
-       spin_lock(&sk->sk_receive_queue.lock);
        if (po->tp_version == TPACKET_V3) {
                if (__tpacket_v3_has_room(po, ROOM_POW_OFF))
                        ret = ROOM_NORMAL;
                else if (__tpacket_has_room(po, 0))
                        ret = ROOM_LOW;
        }
-       spin_unlock(&sk->sk_receive_queue.lock);
+
+       return ret;
+}
+
+static int packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb)
+{
+       int ret;
+       bool has_room;
+
+       if (po->prot_hook.func == tpacket_rcv) {
+               spin_lock(&po->sk.sk_receive_queue.lock);
+               ret = __packet_rcv_has_room(po, skb);
+               spin_unlock(&po->sk.sk_receive_queue.lock);
+       } else {
+               ret = __packet_rcv_has_room(po, skb);
+       }
+
+       has_room = ret == ROOM_NORMAL;
+       if (po->pressure == has_room)
+               xchg(&po->pressure, !has_room);
 
        return ret;
 }
                                          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]);
 
        i = j = min_t(int, po->rollover->sock, num - 1);
        do {
-               if (i != idx &&
-                   packet_rcv_has_room(pkt_sk(f->arr[i]), skb) == ROOM_NORMAL) {
+               po_next = pkt_sk(f->arr[i]);
+               if (po_next != po && !po_next->pressure &&
+                   packet_rcv_has_room(po_next, skb) == ROOM_NORMAL) {
                        if (i != j)
                                po->rollover->sock = i;
                        return i;
        if (skb == NULL)
                goto out;
 
+       if (pkt_sk(sk)->pressure)
+               packet_rcv_has_room(pkt_sk(sk), NULL);
+
        if (pkt_sk(sk)->has_vnet_hdr) {
                struct virtio_net_hdr vnet_hdr = { 0 };
 
                        TP_STATUS_KERNEL))
                        mask |= POLLIN | POLLRDNORM;
        }
+       if (po->pressure && __packet_rcv_has_room(po, NULL) == ROOM_NORMAL)
+               xchg(&po->pressure, 0);
        spin_unlock_bh(&sk->sk_receive_queue.lock);
        spin_lock_bh(&sk->sk_write_queue.lock);
        if (po->tx_ring.pg_vec) {