Commit 06870682 authored by Maxim Mikityanskiy's avatar Maxim Mikityanskiy Committed by Daniel Borkmann

xsk: Add rcu_read_lock around the XSK wakeup

The XSK wakeup callback in drivers makes some sanity checks before
triggering NAPI. However, some configuration changes may occur during
this function that affect the result of those checks. For example, the
interface can go down, and all the resources will be destroyed after the
checks in the wakeup function, but before it attempts to use these
resources. Wrap this callback in rcu_read_lock to allow driver to
synchronize_rcu before actually destroying the resources.

xsk_wakeup is a new function that encapsulates calling ndo_xsk_wakeup
wrapped into the RCU lock. After this commit, xsk_poll starts using
xsk_wakeup and checks xs->zc instead of ndo_xsk_wakeup != NULL to decide
ndo_xsk_wakeup should be called. It also fixes a bug introduced with the
need_wakeup feature: a non-zero-copy socket may be used with a driver
supporting zero-copy, and in this case ndo_xsk_wakeup should not be
called, so the xs->zc check is the correct one.

Fixes: 77cd0d7b ("xsk: add support for need_wakeup flag in AF_XDP rings")
Signed-off-by: default avatarMaxim Mikityanskiy <maximmi@mellanox.com>
Signed-off-by: default avatarBjörn Töpel <bjorn.topel@intel.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20191217162023.16011-2-maximmi@mellanox.com
parent e4730423
...@@ -334,12 +334,21 @@ bool xsk_umem_consume_tx(struct xdp_umem *umem, struct xdp_desc *desc) ...@@ -334,12 +334,21 @@ bool xsk_umem_consume_tx(struct xdp_umem *umem, struct xdp_desc *desc)
} }
EXPORT_SYMBOL(xsk_umem_consume_tx); EXPORT_SYMBOL(xsk_umem_consume_tx);
static int xsk_zc_xmit(struct xdp_sock *xs) static int xsk_wakeup(struct xdp_sock *xs, u8 flags)
{ {
struct net_device *dev = xs->dev; struct net_device *dev = xs->dev;
int err;
rcu_read_lock();
err = dev->netdev_ops->ndo_xsk_wakeup(dev, xs->queue_id, flags);
rcu_read_unlock();
return err;
}
return dev->netdev_ops->ndo_xsk_wakeup(dev, xs->queue_id, static int xsk_zc_xmit(struct xdp_sock *xs)
XDP_WAKEUP_TX); {
return xsk_wakeup(xs, XDP_WAKEUP_TX);
} }
static void xsk_destruct_skb(struct sk_buff *skb) static void xsk_destruct_skb(struct sk_buff *skb)
...@@ -453,19 +462,16 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock, ...@@ -453,19 +462,16 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
__poll_t mask = datagram_poll(file, sock, wait); __poll_t mask = datagram_poll(file, sock, wait);
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct xdp_sock *xs = xdp_sk(sk); struct xdp_sock *xs = xdp_sk(sk);
struct net_device *dev;
struct xdp_umem *umem; struct xdp_umem *umem;
if (unlikely(!xsk_is_bound(xs))) if (unlikely(!xsk_is_bound(xs)))
return mask; return mask;
dev = xs->dev;
umem = xs->umem; umem = xs->umem;
if (umem->need_wakeup) { if (umem->need_wakeup) {
if (dev->netdev_ops->ndo_xsk_wakeup) if (xs->zc)
dev->netdev_ops->ndo_xsk_wakeup(dev, xs->queue_id, xsk_wakeup(xs, umem->need_wakeup);
umem->need_wakeup);
else else
/* Poll needs to drive Tx also in copy mode */ /* Poll needs to drive Tx also in copy mode */
__xsk_sendmsg(sk); __xsk_sendmsg(sk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment