Merge tag 'io_uring-5.10-2020-12-11' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / net / xdp / xsk.c
index cfbec39..6250447 100644 (file)
@@ -211,6 +211,14 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len,
        return 0;
 }
 
+static bool xsk_tx_writeable(struct xdp_sock *xs)
+{
+       if (xskq_cons_present_entries(xs->tx) > xs->tx->nentries / 2)
+               return false;
+
+       return true;
+}
+
 static bool xsk_is_bound(struct xdp_sock *xs)
 {
        if (READ_ONCE(xs->state) == XSK_BOUND) {
@@ -296,7 +304,8 @@ void xsk_tx_release(struct xsk_buff_pool *pool)
        rcu_read_lock();
        list_for_each_entry_rcu(xs, &pool->xsk_tx_list, tx_list) {
                __xskq_cons_release(xs->tx);
-               xs->sk.sk_write_space(&xs->sk);
+               if (xsk_tx_writeable(xs))
+                       xs->sk.sk_write_space(&xs->sk);
        }
        rcu_read_unlock();
 }
@@ -411,11 +420,7 @@ static int xsk_generic_xmit(struct sock *sk)
                skb_shinfo(skb)->destructor_arg = (void *)(long)desc.addr;
                skb->destructor = xsk_destruct_skb;
 
-               /* Hinder dev_direct_xmit from freeing the packet and
-                * therefore completing it in the destructor
-                */
-               refcount_inc(&skb->users);
-               err = dev_direct_xmit(skb, xs->queue_id);
+               err = __dev_direct_xmit(skb, xs->queue_id);
                if  (err == NETDEV_TX_BUSY) {
                        /* Tell user-space to retry the send */
                        skb->destructor = sock_wfree;
@@ -429,12 +434,10 @@ static int xsk_generic_xmit(struct sock *sk)
                /* Ignore NET_XMIT_CN as packet might have been sent */
                if (err == NET_XMIT_DROP) {
                        /* SKB completed but not sent */
-                       kfree_skb(skb);
                        err = -EBUSY;
                        goto out;
                }
 
-               consume_skb(skb);
                sent_frame = true;
        }
 
@@ -442,7 +445,8 @@ static int xsk_generic_xmit(struct sock *sk)
 
 out:
        if (sent_frame)
-               sk->sk_write_space(sk);
+               if (xsk_tx_writeable(xs))
+                       sk->sk_write_space(sk);
 
        mutex_unlock(&xs->mutex);
        return err;
@@ -477,11 +481,13 @@ static int xsk_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
 static __poll_t xsk_poll(struct file *file, struct socket *sock,
                             struct poll_table_struct *wait)
 {
-       __poll_t mask = datagram_poll(file, sock, wait);
+       __poll_t mask = 0;
        struct sock *sk = sock->sk;
        struct xdp_sock *xs = xdp_sk(sk);
        struct xsk_buff_pool *pool;
 
+       sock_poll_wait(file, sock, wait);
+
        if (unlikely(!xsk_is_bound(xs)))
                return mask;
 
@@ -497,7 +503,7 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
 
        if (xs->rx && !xskq_prod_is_empty(xs->rx))
                mask |= EPOLLIN | EPOLLRDNORM;
-       if (xs->tx && !xskq_cons_is_full(xs->tx))
+       if (xs->tx && xsk_tx_writeable(xs))
                mask |= EPOLLOUT | EPOLLWRNORM;
 
        return mask;
@@ -1147,7 +1153,7 @@ static void xsk_destruct(struct sock *sk)
                return;
 
        if (!xp_put_pool(xs->pool))
-               xdp_put_umem(xs->umem);
+               xdp_put_umem(xs->umem, !xs->pool);
 
        sk_refcnt_debug_dec(sk);
 }