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;
|
bool zc;
|
||||||
/* Protects multiple processes in the control path */
|
/* Protects multiple processes in the control path */
|
||||||
struct mutex mutex;
|
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;
|
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;
|
u64 addr = (u64)(long)skb_shinfo(skb)->destructor_arg;
|
||||||
struct xdp_sock *xs = xdp_sk(skb->sk);
|
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));
|
WARN_ON_ONCE(xskq_produce_addr(xs->umem->cq, addr));
|
||||||
|
spin_unlock_irqrestore(&xs->tx_completion_lock, flags);
|
||||||
|
|
||||||
sock_wfree(skb);
|
sock_wfree(skb);
|
||||||
}
|
}
|
||||||
|
@ -268,15 +271,15 @@ static int xsk_generic_xmit(struct sock *sk, struct msghdr *m,
|
||||||
skb->destructor = xsk_destruct_skb;
|
skb->destructor = xsk_destruct_skb;
|
||||||
|
|
||||||
err = dev_direct_xmit(skb, xs->queue_id);
|
err = dev_direct_xmit(skb, xs->queue_id);
|
||||||
|
xskq_discard_desc(xs->tx);
|
||||||
/* Ignore NET_XMIT_CN as packet might have been sent */
|
/* Ignore NET_XMIT_CN as packet might have been sent */
|
||||||
if (err == NET_XMIT_DROP || err == NETDEV_TX_BUSY) {
|
if (err == NET_XMIT_DROP || err == NETDEV_TX_BUSY) {
|
||||||
err = -EAGAIN;
|
/* SKB completed but not sent */
|
||||||
/* SKB consumed by dev_direct_xmit() */
|
err = -EBUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sent_frame = true;
|
sent_frame = true;
|
||||||
xskq_discard_desc(xs->tx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -755,6 +758,7 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol,
|
||||||
|
|
||||||
xs = xdp_sk(sk);
|
xs = xdp_sk(sk);
|
||||||
mutex_init(&xs->mutex);
|
mutex_init(&xs->mutex);
|
||||||
|
spin_lock_init(&xs->tx_completion_lock);
|
||||||
|
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
sock_prot_inuse_add(net, &xsk_proto, 1);
|
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;
|
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)
|
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)
|
if (free_entries >= dcnt)
|
||||||
return free_entries;
|
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;
|
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;
|
return -ENOSPC;
|
||||||
|
|
||||||
ring->desc[q->prod_tail++ & q->ring_mask] = addr;
|
ring->desc[q->prod_tail++ & q->ring_mask] = addr;
|
||||||
|
|
|
@ -729,7 +729,7 @@ static void kick_tx(int fd)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0);
|
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;
|
return;
|
||||||
lassert(0);
|
lassert(0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue