mirror of https://gitee.com/openkylin/linux.git
Merge branch 'af_xdp-fixes'
Magnus Karlsson says: ==================== This patch set fixes three bugs in the SKB TX path of AF_XDP. Details in the individual commits. The structure of the patch set is as follows: Patch 1: Fix for lost completion message Patch 2-3: Fix for possible multiple completions of single packet Patch 4: Fix potential race during error Changes from v1: * Added explanation of race in commit message of patch 4. ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
39d393cf20
|
@ -60,6 +60,10 @@ struct xdp_sock {
|
|||
bool zc;
|
||||
/* Protects multiple processes in the control path */
|
||||
struct mutex mutex;
|
||||
/* Mutual exclusion of NAPI TX thread and sendmsg error paths
|
||||
* in the SKB destructor callback.
|
||||
*/
|
||||
spinlock_t tx_completion_lock;
|
||||
u64 rx_dropped;
|
||||
};
|
||||
|
||||
|
|
|
@ -199,8 +199,11 @@ static void xsk_destruct_skb(struct sk_buff *skb)
|
|||
{
|
||||
u64 addr = (u64)(long)skb_shinfo(skb)->destructor_arg;
|
||||
struct xdp_sock *xs = xdp_sk(skb->sk);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&xs->tx_completion_lock, flags);
|
||||
WARN_ON_ONCE(xskq_produce_addr(xs->umem->cq, addr));
|
||||
spin_unlock_irqrestore(&xs->tx_completion_lock, flags);
|
||||
|
||||
sock_wfree(skb);
|
||||
}
|
||||
|
@ -268,15 +271,15 @@ static int xsk_generic_xmit(struct sock *sk, struct msghdr *m,
|
|||
skb->destructor = xsk_destruct_skb;
|
||||
|
||||
err = dev_direct_xmit(skb, xs->queue_id);
|
||||
xskq_discard_desc(xs->tx);
|
||||
/* Ignore NET_XMIT_CN as packet might have been sent */
|
||||
if (err == NET_XMIT_DROP || err == NETDEV_TX_BUSY) {
|
||||
err = -EAGAIN;
|
||||
/* SKB consumed by dev_direct_xmit() */
|
||||
/* SKB completed but not sent */
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sent_frame = true;
|
||||
xskq_discard_desc(xs->tx);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -755,6 +758,7 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol,
|
|||
|
||||
xs = xdp_sk(sk);
|
||||
mutex_init(&xs->mutex);
|
||||
spin_lock_init(&xs->tx_completion_lock);
|
||||
|
||||
local_bh_disable();
|
||||
sock_prot_inuse_add(net, &xsk_proto, 1);
|
||||
|
|
|
@ -62,14 +62,9 @@ static inline u32 xskq_nb_avail(struct xsk_queue *q, u32 dcnt)
|
|||
return (entries > dcnt) ? dcnt : entries;
|
||||
}
|
||||
|
||||
static inline u32 xskq_nb_free_lazy(struct xsk_queue *q, u32 producer)
|
||||
{
|
||||
return q->nentries - (producer - q->cons_tail);
|
||||
}
|
||||
|
||||
static inline u32 xskq_nb_free(struct xsk_queue *q, u32 producer, u32 dcnt)
|
||||
{
|
||||
u32 free_entries = xskq_nb_free_lazy(q, producer);
|
||||
u32 free_entries = q->nentries - (producer - q->cons_tail);
|
||||
|
||||
if (free_entries >= dcnt)
|
||||
return free_entries;
|
||||
|
@ -129,7 +124,7 @@ static inline int xskq_produce_addr(struct xsk_queue *q, u64 addr)
|
|||
{
|
||||
struct xdp_umem_ring *ring = (struct xdp_umem_ring *)q->ring;
|
||||
|
||||
if (xskq_nb_free(q, q->prod_tail, LAZY_UPDATE_THRESHOLD) == 0)
|
||||
if (xskq_nb_free(q, q->prod_tail, 1) == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
ring->desc[q->prod_tail++ & q->ring_mask] = addr;
|
||||
|
|
|
@ -729,7 +729,7 @@ static void kick_tx(int fd)
|
|||
int ret;
|
||||
|
||||
ret = sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0);
|
||||
if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN)
|
||||
if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN || errno == EBUSY)
|
||||
return;
|
||||
lassert(0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue