xsk: Rollback reservation at NETDEV_TX_BUSY
authorMagnus Karlsson <magnus.karlsson@intel.com>
Fri, 18 Dec 2020 13:45:25 +0000 (14:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 17 Jan 2021 13:17:05 +0000 (14:17 +0100)
commit b1b95cb5c0a9694d47d5f845ba97e226cfda957d upstream.

Rollback the reservation in the completion ring when we get a
NETDEV_TX_BUSY. When this error is received from the driver, we are
supposed to let the user application retry the transmit again. And in
order to do this, we need to roll back the failed send so it can be
retried. Unfortunately, we did not cancel the reservation we had made
in the completion ring. By not doing this, we actually make the
completion ring one entry smaller per NETDEV_TX_BUSY error we get, and
after enough of these errors the completion ring will be of size zero
and transmit will stop working.

Fix this by cancelling the reservation when we get a NETDEV_TX_BUSY
error.

Fixes: 642e450b6b59 ("xsk: Do not discard packet when NETDEV_TX_BUSY")
Reported-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Björn Töpel <bjorn.topel@intel.com>
Link: https://lore.kernel.org/bpf/20201218134525.13119-3-magnus.karlsson@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/xdp/xsk.c
net/xdp/xsk_queue.h

index f20eba841460becfcdbdf011592aca6a4995d4d9..d5f42c62fd79ef6bc4063e3ab0e5f45575c3f60b 100644 (file)
@@ -428,6 +428,9 @@ static int xsk_generic_xmit(struct sock *sk)
                if  (err == NETDEV_TX_BUSY) {
                        /* Tell user-space to retry the send */
                        skb->destructor = sock_wfree;
+                       spin_lock_irqsave(&xs->pool->cq_lock, flags);
+                       xskq_prod_cancel(xs->pool->cq);
+                       spin_unlock_irqrestore(&xs->pool->cq_lock, flags);
                        /* Free skb without triggering the perf drop trace */
                        consume_skb(skb);
                        err = -EAGAIN;
index 9e71b9f27679b91f25d031586f7f99b466ff7502..ef6de0fb4e312d7766eb631bf99e311ef5eb26c1 100644 (file)
@@ -286,6 +286,11 @@ static inline bool xskq_prod_is_full(struct xsk_queue *q)
        return !free_entries;
 }
 
+static inline void xskq_prod_cancel(struct xsk_queue *q)
+{
+       q->cached_prod--;
+}
+
 static inline int xskq_prod_reserve(struct xsk_queue *q)
 {
        if (xskq_prod_is_full(q))