On Tue, 30 Jul 2024 02:26:05 +0000, Mina Almasry <almasrymina@xxxxxxxxxx> wrote: > Add netdev_rx_queue_restart() function to netdev_rx_queue.h Can you say more? As far as I understand, we just release the buffer submitted to the rx ring and get a new page pool. But I personally feel that the interface here is a bit too complicated. In particular, we also need to copy the rx struct memory, which means it is a dangerous operation for many pointers. Thanks. > > Signed-off-by: David Wei <dw@xxxxxxxxxxx> > Signed-off-by: Mina Almasry <almasrymina@xxxxxxxxxx> > Reviewed-by: Pavel Begunkov <asml.silence@xxxxxxxxx> > Reviewed-by: Jakub Kicinski <kuba@xxxxxxxxxx> > > --- > > v17: > - Use ASSERT_RTNL() (Jakub). > > v13: > - Add reviewed-by from Pavel (thanks!) > - Fixed comment (Pavel) > > v11: > - Fix not checking dev->queue_mgmt_ops (Pavel). > - Fix ndo_queue_mem_free call that passed the wrong pointer (David). > > v9: https://lore.kernel.org/all/20240502045410.3524155-4-dw@xxxxxxxxxxx/ > (submitted by David). > - fixed SPDX license identifier (Simon). > - Rebased on top of merged queue API definition, and changed > implementation to match that. > - Replace rtnl_lock() with rtnl_is_locked() to make it useable from my > netlink code where rtnl is already locked. > > --- > include/net/netdev_rx_queue.h | 3 ++ > net/core/Makefile | 1 + > net/core/netdev_rx_queue.c | 74 +++++++++++++++++++++++++++++++++++ > 3 files changed, 78 insertions(+) > create mode 100644 net/core/netdev_rx_queue.c > > diff --git a/include/net/netdev_rx_queue.h b/include/net/netdev_rx_queue.h > index aa1716fb0e53c..e78ca52d67fbf 100644 > --- a/include/net/netdev_rx_queue.h > +++ b/include/net/netdev_rx_queue.h > @@ -54,4 +54,7 @@ get_netdev_rx_queue_index(struct netdev_rx_queue *queue) > return index; > } > #endif > + > +int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq); > + > #endif > diff --git a/net/core/Makefile b/net/core/Makefile > index 62be9aef25285..f82232b358a2c 100644 > --- a/net/core/Makefile > +++ b/net/core/Makefile > @@ -19,6 +19,7 @@ obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o > > obj-y += net-sysfs.o > obj-y += hotdata.o > +obj-y += netdev_rx_queue.o > obj-$(CONFIG_PAGE_POOL) += page_pool.o page_pool_user.o > obj-$(CONFIG_PROC_FS) += net-procfs.o > obj-$(CONFIG_NET_PKTGEN) += pktgen.o > diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c > new file mode 100644 > index 0000000000000..da11720a59830 > --- /dev/null > +++ b/net/core/netdev_rx_queue.c > @@ -0,0 +1,74 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > + > +#include <linux/netdevice.h> > +#include <net/netdev_queues.h> > +#include <net/netdev_rx_queue.h> > + > +int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx) > +{ > + void *new_mem, *old_mem; > + int err; > + > + if (!dev->queue_mgmt_ops || !dev->queue_mgmt_ops->ndo_queue_stop || > + !dev->queue_mgmt_ops->ndo_queue_mem_free || > + !dev->queue_mgmt_ops->ndo_queue_mem_alloc || > + !dev->queue_mgmt_ops->ndo_queue_start) > + return -EOPNOTSUPP; > + > + ASSERT_RTNL(); > + > + new_mem = kvzalloc(dev->queue_mgmt_ops->ndo_queue_mem_size, GFP_KERNEL); > + if (!new_mem) > + return -ENOMEM; > + > + old_mem = kvzalloc(dev->queue_mgmt_ops->ndo_queue_mem_size, GFP_KERNEL); > + if (!old_mem) { > + err = -ENOMEM; > + goto err_free_new_mem; > + } > + > + err = dev->queue_mgmt_ops->ndo_queue_mem_alloc(dev, new_mem, rxq_idx); > + if (err) > + goto err_free_old_mem; > + > + err = dev->queue_mgmt_ops->ndo_queue_stop(dev, old_mem, rxq_idx); > + if (err) > + goto err_free_new_queue_mem; > + > + err = dev->queue_mgmt_ops->ndo_queue_start(dev, new_mem, rxq_idx); > + if (err) > + goto err_start_queue; > + > + dev->queue_mgmt_ops->ndo_queue_mem_free(dev, old_mem); > + > + kvfree(old_mem); > + kvfree(new_mem); > + > + return 0; > + > +err_start_queue: > + /* Restarting the queue with old_mem should be successful as we haven't > + * changed any of the queue configuration, and there is not much we can > + * do to recover from a failure here. > + * > + * WARN if we fail to recover the old rx queue, and at least free > + * old_mem so we don't also leak that. > + */ > + if (dev->queue_mgmt_ops->ndo_queue_start(dev, old_mem, rxq_idx)) { > + WARN(1, > + "Failed to restart old queue in error path. RX queue %d may be unhealthy.", > + rxq_idx); > + dev->queue_mgmt_ops->ndo_queue_mem_free(dev, old_mem); > + } > + > +err_free_new_queue_mem: > + dev->queue_mgmt_ops->ndo_queue_mem_free(dev, new_mem); > + > +err_free_old_mem: > + kvfree(old_mem); > + > +err_free_new_mem: > + kvfree(new_mem); > + > + return err; > +} > -- > 2.46.0.rc1.232.g9752f9e123-goog > >