Message ID | 20250116231704.2402455-11-dw@davidwei.uk (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | io_uring zero copy rx | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Clearly marked for net-next, async |
netdev/apply | fail | Patch does not apply to net-next-0 |
On Thu, 16 Jan 2025 15:16:52 -0800 David Wei wrote: > Add helpers that properly prep or remove a memory provider for an rx > queue then restart the queue. > > Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> > Signed-off-by: David Wei <dw@davidwei.uk> Reviewed-by: Jakub Kicinski <kuba@kernel.org>
On Thu, 16 Jan 2025 15:16:52 -0800 David Wei wrote: > + ret = netdev_rx_queue_restart(dev, ifq_idx); > + if (ret) > + pr_devel("Could not restart queue %u after removing memory provider.\n", > + ifq_idx); devmem does a WARN_ON() in this case, probably better to keep it consistent? In case you need to respin
On 2025-01-16 17:52, Jakub Kicinski wrote: > On Thu, 16 Jan 2025 15:16:52 -0800 David Wei wrote: >> + ret = netdev_rx_queue_restart(dev, ifq_idx); >> + if (ret) >> + pr_devel("Could not restart queue %u after removing memory provider.\n", >> + ifq_idx); > > devmem does a WARN_ON() in this case, probably better to keep it > consistent? In case you need to respin Yeah I see it, thanks. It looks like I need to respin so I'll fix it up.
On Thu, 16 Jan 2025 15:16:52 -0800 David Wei wrote: > +static void __net_mp_close_rxq(struct net_device *dev, unsigned ifq_idx, > + struct pp_memory_provider_params *old_p) > +{ > + struct netdev_rx_queue *rxq; > + int ret; > + > + if (WARN_ON_ONCE(ifq_idx >= dev->real_num_rx_queues)) > + return; > + > + rxq = __netif_get_rx_queue(dev, ifq_idx); I think there's a small race between io_uring closing and the netdev unregister. We can try to uninstall twice, let's put /* Callers holding a netdev ref may get here after we already * went thru shutdown via dev_memory_provider_uninstall(). */ if (dev->reg_state > NETREG_REGISTERED && !rxq->mp_params.mp_ops) return; here, and in dev_memory_provider_uninstall() clear the pointers? > + if (WARN_ON_ONCE(rxq->mp_params.mp_ops != old_p->mp_ops || > + rxq->mp_params.mp_priv != old_p->mp_priv)) > + return; > + > + rxq->mp_params.mp_ops = NULL; > + rxq->mp_params.mp_priv = NULL; > + ret = netdev_rx_queue_restart(dev, ifq_idx); > + if (ret) > + pr_devel("Could not restart queue %u after removing memory provider.\n", > + ifq_idx); > +}
On 1/17/25 02:25, Jakub Kicinski wrote: > On Thu, 16 Jan 2025 15:16:52 -0800 David Wei wrote: >> +static void __net_mp_close_rxq(struct net_device *dev, unsigned ifq_idx, >> + struct pp_memory_provider_params *old_p) >> +{ >> + struct netdev_rx_queue *rxq; >> + int ret; >> + >> + if (WARN_ON_ONCE(ifq_idx >= dev->real_num_rx_queues)) >> + return; >> + >> + rxq = __netif_get_rx_queue(dev, ifq_idx); > > I think there's a small race between io_uring closing and the netdev > unregister. We can try to uninstall twice, let's put They're gated by checking ifq->netdev in io_uring code, which is cleared by them under a spin. So either io_uring does __net_mp_close_rxq() and ->uninstall does nothing, or vise versa. > /* Callers holding a netdev ref may get here after we already > * went thru shutdown via dev_memory_provider_uninstall(). > */ > if (dev->reg_state > NETREG_REGISTERED && > !rxq->mp_params.mp_ops) > return; > > here, and in dev_memory_provider_uninstall() clear the pointers? > >> + if (WARN_ON_ONCE(rxq->mp_params.mp_ops != old_p->mp_ops || >> + rxq->mp_params.mp_priv != old_p->mp_priv)) >> + return; >> + >> + rxq->mp_params.mp_ops = NULL; >> + rxq->mp_params.mp_priv = NULL; >> + ret = netdev_rx_queue_restart(dev, ifq_idx); >> + if (ret) >> + pr_devel("Could not restart queue %u after removing memory provider.\n", >> + ifq_idx); >> +}
diff --git a/include/net/page_pool/memory_provider.h b/include/net/page_pool/memory_provider.h index 4f0ffb8f6a0a..b3e665897767 100644 --- a/include/net/page_pool/memory_provider.h +++ b/include/net/page_pool/memory_provider.h @@ -22,6 +22,11 @@ bool net_mp_niov_set_dma_addr(struct net_iov *niov, dma_addr_t addr); void net_mp_niov_set_page_pool(struct page_pool *pool, struct net_iov *niov); void net_mp_niov_clear_page_pool(struct net_iov *niov); +int net_mp_open_rxq(struct net_device *dev, unsigned ifq_idx, + struct pp_memory_provider_params *p); +void net_mp_close_rxq(struct net_device *dev, unsigned ifq_idx, + struct pp_memory_provider_params *old_p); + /** * net_mp_netmem_place_in_cache() - give a netmem to a page pool * @pool: the page pool to place the netmem into diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c index e217a5838c87..e934568d4cd9 100644 --- a/net/core/netdev_rx_queue.c +++ b/net/core/netdev_rx_queue.c @@ -3,6 +3,7 @@ #include <linux/netdevice.h> #include <net/netdev_queues.h> #include <net/netdev_rx_queue.h> +#include <net/page_pool/memory_provider.h> #include "page_pool_priv.h" @@ -79,3 +80,68 @@ int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx) return err; } + +static int __net_mp_open_rxq(struct net_device *dev, unsigned ifq_idx, + struct pp_memory_provider_params *p) +{ + struct netdev_rx_queue *rxq; + int ret; + + if (ifq_idx >= dev->real_num_rx_queues) + return -EINVAL; + ifq_idx = array_index_nospec(ifq_idx, dev->real_num_rx_queues); + + rxq = __netif_get_rx_queue(dev, ifq_idx); + if (rxq->mp_params.mp_ops) + return -EEXIST; + + rxq->mp_params = *p; + ret = netdev_rx_queue_restart(dev, ifq_idx); + if (ret) { + rxq->mp_params.mp_ops = NULL; + rxq->mp_params.mp_priv = NULL; + } + return ret; +} + +int net_mp_open_rxq(struct net_device *dev, unsigned ifq_idx, + struct pp_memory_provider_params *p) +{ + int ret; + + rtnl_lock(); + ret = __net_mp_open_rxq(dev, ifq_idx, p); + rtnl_unlock(); + return ret; +} + +static void __net_mp_close_rxq(struct net_device *dev, unsigned ifq_idx, + struct pp_memory_provider_params *old_p) +{ + struct netdev_rx_queue *rxq; + int ret; + + if (WARN_ON_ONCE(ifq_idx >= dev->real_num_rx_queues)) + return; + + rxq = __netif_get_rx_queue(dev, ifq_idx); + + if (WARN_ON_ONCE(rxq->mp_params.mp_ops != old_p->mp_ops || + rxq->mp_params.mp_priv != old_p->mp_priv)) + return; + + rxq->mp_params.mp_ops = NULL; + rxq->mp_params.mp_priv = NULL; + ret = netdev_rx_queue_restart(dev, ifq_idx); + if (ret) + pr_devel("Could not restart queue %u after removing memory provider.\n", + ifq_idx); +} + +void net_mp_close_rxq(struct net_device *dev, unsigned ifq_idx, + struct pp_memory_provider_params *old_p) +{ + rtnl_lock(); + __net_mp_close_rxq(dev, ifq_idx, old_p); + rtnl_unlock(); +}