Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Two cases of overlapping changes, nothing fancy. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -105,6 +105,9 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
|
||||
|
||||
umem->dev = dev;
|
||||
umem->queue_id = queue_id;
|
||||
|
||||
dev_hold(dev);
|
||||
|
||||
if (force_copy)
|
||||
/* For copy-mode, we are done. */
|
||||
goto out_rtnl_unlock;
|
||||
@@ -124,7 +127,6 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
|
||||
goto err_unreg_umem;
|
||||
rtnl_unlock();
|
||||
|
||||
dev_hold(dev);
|
||||
umem->zc = true;
|
||||
return 0;
|
||||
|
||||
@@ -138,11 +140,13 @@ out_rtnl_unlock:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void xdp_umem_clear_dev(struct xdp_umem *umem)
|
||||
void xdp_umem_clear_dev(struct xdp_umem *umem)
|
||||
{
|
||||
struct netdev_bpf bpf;
|
||||
int err;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!umem->dev)
|
||||
return;
|
||||
|
||||
@@ -151,22 +155,17 @@ static void xdp_umem_clear_dev(struct xdp_umem *umem)
|
||||
bpf.xsk.umem = NULL;
|
||||
bpf.xsk.queue_id = umem->queue_id;
|
||||
|
||||
rtnl_lock();
|
||||
err = umem->dev->netdev_ops->ndo_bpf(umem->dev, &bpf);
|
||||
rtnl_unlock();
|
||||
|
||||
if (err)
|
||||
WARN(1, "failed to disable umem!\n");
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
xdp_clear_umem_at_qid(umem->dev, umem->queue_id);
|
||||
rtnl_unlock();
|
||||
|
||||
if (umem->zc) {
|
||||
dev_put(umem->dev);
|
||||
umem->zc = false;
|
||||
}
|
||||
dev_put(umem->dev);
|
||||
umem->dev = NULL;
|
||||
umem->zc = false;
|
||||
}
|
||||
|
||||
static void xdp_umem_unpin_pages(struct xdp_umem *umem)
|
||||
@@ -194,7 +193,9 @@ static void xdp_umem_unaccount_pages(struct xdp_umem *umem)
|
||||
|
||||
static void xdp_umem_release(struct xdp_umem *umem)
|
||||
{
|
||||
rtnl_lock();
|
||||
xdp_umem_clear_dev(umem);
|
||||
rtnl_unlock();
|
||||
|
||||
ida_simple_remove(&umem_ida, umem->id);
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
|
||||
u16 queue_id, u16 flags);
|
||||
void xdp_umem_clear_dev(struct xdp_umem *umem);
|
||||
bool xdp_umem_validate_queues(struct xdp_umem *umem);
|
||||
void xdp_get_umem(struct xdp_umem *umem);
|
||||
void xdp_put_umem(struct xdp_umem *umem);
|
||||
|
@@ -349,6 +349,22 @@ static int xsk_init_queue(u32 entries, struct xsk_queue **queue,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xsk_unbind_dev(struct xdp_sock *xs)
|
||||
{
|
||||
struct net_device *dev = xs->dev;
|
||||
|
||||
if (!dev || xs->state != XSK_BOUND)
|
||||
return;
|
||||
|
||||
xs->state = XSK_UNBOUND;
|
||||
|
||||
/* Wait for driver to stop using the xdp socket. */
|
||||
xdp_del_sk_umem(xs->umem, xs);
|
||||
xs->dev = NULL;
|
||||
synchronize_net();
|
||||
dev_put(dev);
|
||||
}
|
||||
|
||||
static int xsk_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -368,15 +384,7 @@ static int xsk_release(struct socket *sock)
|
||||
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
||||
local_bh_enable();
|
||||
|
||||
if (xs->dev) {
|
||||
struct net_device *dev = xs->dev;
|
||||
|
||||
/* Wait for driver to stop using the xdp socket. */
|
||||
xdp_del_sk_umem(xs->umem, xs);
|
||||
xs->dev = NULL;
|
||||
synchronize_net();
|
||||
dev_put(dev);
|
||||
}
|
||||
xsk_unbind_dev(xs);
|
||||
|
||||
xskq_destroy(xs->rx);
|
||||
xskq_destroy(xs->tx);
|
||||
@@ -426,7 +434,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&xs->mutex);
|
||||
if (xs->dev) {
|
||||
if (xs->state != XSK_READY) {
|
||||
err = -EBUSY;
|
||||
goto out_release;
|
||||
}
|
||||
@@ -506,6 +514,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
|
||||
out_unlock:
|
||||
if (err)
|
||||
dev_put(dev);
|
||||
else
|
||||
xs->state = XSK_BOUND;
|
||||
out_release:
|
||||
mutex_unlock(&xs->mutex);
|
||||
return err;
|
||||
@@ -534,6 +544,10 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&xs->mutex);
|
||||
if (xs->state != XSK_READY) {
|
||||
mutex_unlock(&xs->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
q = (optname == XDP_TX_RING) ? &xs->tx : &xs->rx;
|
||||
err = xsk_init_queue(entries, q, false);
|
||||
mutex_unlock(&xs->mutex);
|
||||
@@ -548,7 +562,7 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&xs->mutex);
|
||||
if (xs->umem) {
|
||||
if (xs->state != XSK_READY || xs->umem) {
|
||||
mutex_unlock(&xs->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
@@ -575,6 +589,10 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&xs->mutex);
|
||||
if (xs->state != XSK_READY) {
|
||||
mutex_unlock(&xs->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!xs->umem) {
|
||||
mutex_unlock(&xs->mutex);
|
||||
return -EINVAL;
|
||||
@@ -696,6 +714,9 @@ static int xsk_mmap(struct file *file, struct socket *sock,
|
||||
unsigned long pfn;
|
||||
struct page *qpg;
|
||||
|
||||
if (xs->state != XSK_READY)
|
||||
return -EBUSY;
|
||||
|
||||
if (offset == XDP_PGOFF_RX_RING) {
|
||||
q = READ_ONCE(xs->rx);
|
||||
} else if (offset == XDP_PGOFF_TX_RING) {
|
||||
@@ -727,6 +748,38 @@ static int xsk_mmap(struct file *file, struct socket *sock,
|
||||
size, vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static int xsk_notifier(struct notifier_block *this,
|
||||
unsigned long msg, void *ptr)
|
||||
{
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct net *net = dev_net(dev);
|
||||
struct sock *sk;
|
||||
|
||||
switch (msg) {
|
||||
case NETDEV_UNREGISTER:
|
||||
mutex_lock(&net->xdp.lock);
|
||||
sk_for_each(sk, &net->xdp.list) {
|
||||
struct xdp_sock *xs = xdp_sk(sk);
|
||||
|
||||
mutex_lock(&xs->mutex);
|
||||
if (xs->dev == dev) {
|
||||
sk->sk_err = ENETDOWN;
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_error_report(sk);
|
||||
|
||||
xsk_unbind_dev(xs);
|
||||
|
||||
/* Clear device references in umem. */
|
||||
xdp_umem_clear_dev(xs->umem);
|
||||
}
|
||||
mutex_unlock(&xs->mutex);
|
||||
}
|
||||
mutex_unlock(&net->xdp.lock);
|
||||
break;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct proto xsk_proto = {
|
||||
.name = "XDP",
|
||||
.owner = THIS_MODULE,
|
||||
@@ -798,6 +851,7 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol,
|
||||
sock_set_flag(sk, SOCK_RCU_FREE);
|
||||
|
||||
xs = xdp_sk(sk);
|
||||
xs->state = XSK_READY;
|
||||
mutex_init(&xs->mutex);
|
||||
spin_lock_init(&xs->rx_lock);
|
||||
spin_lock_init(&xs->tx_completion_lock);
|
||||
@@ -819,6 +873,10 @@ static const struct net_proto_family xsk_family_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct notifier_block xsk_netdev_notifier = {
|
||||
.notifier_call = xsk_notifier,
|
||||
};
|
||||
|
||||
static int __net_init xsk_net_init(struct net *net)
|
||||
{
|
||||
mutex_init(&net->xdp.lock);
|
||||
@@ -851,8 +909,15 @@ static int __init xsk_init(void)
|
||||
err = register_pernet_subsys(&xsk_net_ops);
|
||||
if (err)
|
||||
goto out_sk;
|
||||
|
||||
err = register_netdevice_notifier(&xsk_netdev_notifier);
|
||||
if (err)
|
||||
goto out_pernet;
|
||||
|
||||
return 0;
|
||||
|
||||
out_pernet:
|
||||
unregister_pernet_subsys(&xsk_net_ops);
|
||||
out_sk:
|
||||
sock_unregister(PF_XDP);
|
||||
out_proto:
|
||||
|
@@ -302,7 +302,7 @@ static inline void xskq_produce_flush_desc(struct xsk_queue *q)
|
||||
/* Order producer and data */
|
||||
smp_wmb(); /* B, matches C */
|
||||
|
||||
q->prod_tail = q->prod_head,
|
||||
q->prod_tail = q->prod_head;
|
||||
WRITE_ONCE(q->ring->producer, q->prod_tail);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user