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) {