Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
authorJakub Kicinski <kuba@kernel.org>
Thu, 25 Jan 2024 22:00:54 +0000 (14:00 -0800)
committerJakub Kicinski <kuba@kernel.org>
Thu, 25 Jan 2024 22:20:08 +0000 (14:20 -0800)
Cross-merge networking fixes after downstream PR.

No conflicts or adjacent changes.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
38 files changed:
drivers/net/dsa/mt7530.c
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_dqo.h
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/google/gve/gve_rx.c
drivers/net/ethernet/google/gve/gve_rx_dqo.c
drivers/net/ethernet/google/gve/gve_tx.c
drivers/net/ethernet/google/gve/gve_tx_dqo.c
drivers/net/ethernet/google/gve/gve_utils.c
drivers/net/ethernet/google/gve/gve_utils.h
include/linux/inet_diag.h
include/linux/sock_diag.h
include/net/ip6_fib.h
net/core/sock_diag.c
net/dccp/diag.c
net/ipv4/inet_diag.c
net/ipv4/raw_diag.c
net/ipv4/tcp_diag.c
net/ipv4/udp_diag.c
net/ipv6/ip6_fib.c
net/ipv6/route.c
net/mptcp/mptcp_diag.c
net/netlink/diag.c
net/packet/diag.c
net/sctp/diag.c
net/smc/smc_diag.c
net/tipc/diag.c
net/tipc/node.c
net/tipc/socket.c
net/unix/diag.c
net/vmw_vsock/diag.c
net/xdp/xsk_diag.c
tools/testing/vsock/util.c
tools/testing/vsock/util.h
tools/testing/vsock/vsock_diag_test.c
tools/testing/vsock/vsock_test.c
tools/testing/vsock/vsock_test_zerocopy.c
tools/testing/vsock/vsock_uring_test.c

index 391c4dbdff4283d0b077608a59e4c95758eb24cf..cf2ff7680c15619e80f19898be03e3286aae0cf9 100644 (file)
@@ -2146,24 +2146,40 @@ mt7530_free_irq_common(struct mt7530_priv *priv)
 static void
 mt7530_free_irq(struct mt7530_priv *priv)
 {
-       mt7530_free_mdio_irq(priv);
+       struct device_node *mnp, *np = priv->dev->of_node;
+
+       mnp = of_get_child_by_name(np, "mdio");
+       if (!mnp)
+               mt7530_free_mdio_irq(priv);
+       of_node_put(mnp);
+
        mt7530_free_irq_common(priv);
 }
 
 static int
 mt7530_setup_mdio(struct mt7530_priv *priv)
 {
+       struct device_node *mnp, *np = priv->dev->of_node;
        struct dsa_switch *ds = priv->ds;
        struct device *dev = priv->dev;
        struct mii_bus *bus;
        static int idx;
-       int ret;
+       int ret = 0;
+
+       mnp = of_get_child_by_name(np, "mdio");
+
+       if (mnp && !of_device_is_available(mnp))
+               goto out;
 
        bus = devm_mdiobus_alloc(dev);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (!mnp)
+               ds->user_mii_bus = bus;
 
-       ds->user_mii_bus = bus;
        bus->priv = priv;
        bus->name = KBUILD_MODNAME "-mii";
        snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++);
@@ -2174,16 +2190,18 @@ mt7530_setup_mdio(struct mt7530_priv *priv)
        bus->parent = dev;
        bus->phy_mask = ~ds->phys_mii_mask;
 
-       if (priv->irq)
+       if (priv->irq && !mnp)
                mt7530_setup_mdio_irq(priv);
 
-       ret = devm_mdiobus_register(dev, bus);
+       ret = devm_of_mdiobus_register(dev, bus, mnp);
        if (ret) {
                dev_err(dev, "failed to register MDIO bus: %d\n", ret);
-               if (priv->irq)
+               if (priv->irq && !mnp)
                        mt7530_free_mdio_irq(priv);
        }
 
+out:
+       of_node_put(mnp);
        return ret;
 }
 
index b80349154604b11510637deebf908bbe3b73ac5e..fd290f3ad6ecf3d68844643e05cd9bc4a1af92be 100644 (file)
@@ -622,6 +622,55 @@ struct gve_ptype_lut {
        struct gve_ptype ptypes[GVE_NUM_PTYPES];
 };
 
+/* Parameters for allocating queue page lists */
+struct gve_qpls_alloc_cfg {
+       struct gve_qpl_config *qpl_cfg;
+       struct gve_queue_config *tx_cfg;
+       struct gve_queue_config *rx_cfg;
+
+       u16 num_xdp_queues;
+       bool raw_addressing;
+       bool is_gqi;
+
+       /* Allocated resources are returned here */
+       struct gve_queue_page_list *qpls;
+};
+
+/* Parameters for allocating resources for tx queues */
+struct gve_tx_alloc_rings_cfg {
+       struct gve_queue_config *qcfg;
+
+       /* qpls and qpl_cfg must already be allocated */
+       struct gve_queue_page_list *qpls;
+       struct gve_qpl_config *qpl_cfg;
+
+       u16 ring_size;
+       u16 start_idx;
+       u16 num_rings;
+       bool raw_addressing;
+
+       /* Allocated resources are returned here */
+       struct gve_tx_ring *tx;
+};
+
+/* Parameters for allocating resources for rx queues */
+struct gve_rx_alloc_rings_cfg {
+       /* tx config is also needed to determine QPL ids */
+       struct gve_queue_config *qcfg;
+       struct gve_queue_config *qcfg_tx;
+
+       /* qpls and qpl_cfg must already be allocated */
+       struct gve_queue_page_list *qpls;
+       struct gve_qpl_config *qpl_cfg;
+
+       u16 ring_size;
+       bool raw_addressing;
+       bool enable_header_split;
+
+       /* Allocated resources are returned here */
+       struct gve_rx_ring *rx;
+};
+
 /* GVE_QUEUE_FORMAT_UNSPECIFIED must be zero since 0 is the default value
  * when the entire configure_device_resources command is zeroed out and the
  * queue_format is not specified.
@@ -917,14 +966,14 @@ static inline bool gve_is_qpl(struct gve_priv *priv)
                priv->queue_format == GVE_DQO_QPL_FORMAT;
 }
 
-/* Returns the number of tx queue page lists
- */
-static inline u32 gve_num_tx_qpls(struct gve_priv *priv)
+/* Returns the number of tx queue page lists */
+static inline u32 gve_num_tx_qpls(const struct gve_queue_config *tx_cfg,
+                                 int num_xdp_queues,
+                                 bool is_qpl)
 {
-       if (!gve_is_qpl(priv))
+       if (!is_qpl)
                return 0;
-
-       return priv->tx_cfg.num_queues + priv->num_xdp_queues;
+       return tx_cfg->num_queues + num_xdp_queues;
 }
 
 /* Returns the number of XDP tx queue page lists
@@ -937,14 +986,13 @@ static inline u32 gve_num_xdp_qpls(struct gve_priv *priv)
        return priv->num_xdp_queues;
 }
 
-/* Returns the number of rx queue page lists
- */
-static inline u32 gve_num_rx_qpls(struct gve_priv *priv)
+/* Returns the number of rx queue page lists */
+static inline u32 gve_num_rx_qpls(const struct gve_queue_config *rx_cfg,
+                                 bool is_qpl)
 {
-       if (!gve_is_qpl(priv))
+       if (!is_qpl)
                return 0;
-
-       return priv->rx_cfg.num_queues;
+       return rx_cfg->num_queues;
 }
 
 static inline u32 gve_tx_qpl_id(struct gve_priv *priv, int tx_qid)
@@ -957,59 +1005,59 @@ static inline u32 gve_rx_qpl_id(struct gve_priv *priv, int rx_qid)
        return priv->tx_cfg.max_queues + rx_qid;
 }
 
+/* Returns the index into priv->qpls where a certain rx queue's QPL resides */
+static inline u32 gve_get_rx_qpl_id(const struct gve_queue_config *tx_cfg, int rx_qid)
+{
+       return tx_cfg->max_queues + rx_qid;
+}
+
 static inline u32 gve_tx_start_qpl_id(struct gve_priv *priv)
 {
        return gve_tx_qpl_id(priv, 0);
 }
 
-static inline u32 gve_rx_start_qpl_id(struct gve_priv *priv)
+/* Returns the index into priv->qpls where the first rx queue's QPL resides */
+static inline u32 gve_rx_start_qpl_id(const struct gve_queue_config *tx_cfg)
 {
-       return gve_rx_qpl_id(priv, 0);
+       return gve_get_rx_qpl_id(tx_cfg, 0);
 }
 
-/* Returns a pointer to the next available tx qpl in the list of qpls
- */
+/* Returns a pointer to the next available tx qpl in the list of qpls */
 static inline
-struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_priv *priv, int tx_qid)
+struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_tx_alloc_rings_cfg *cfg,
+                                             int tx_qid)
 {
-       int id = gve_tx_qpl_id(priv, tx_qid);
-
        /* QPL already in use */
-       if (test_bit(id, priv->qpl_cfg.qpl_id_map))
+       if (test_bit(tx_qid, cfg->qpl_cfg->qpl_id_map))
                return NULL;
-
-       set_bit(id, priv->qpl_cfg.qpl_id_map);
-       return &priv->qpls[id];
+       set_bit(tx_qid, cfg->qpl_cfg->qpl_id_map);
+       return &cfg->qpls[tx_qid];
 }
 
-/* Returns a pointer to the next available rx qpl in the list of qpls
- */
+/* Returns a pointer to the next available rx qpl in the list of qpls */
 static inline
-struct gve_queue_page_list *gve_assign_rx_qpl(struct gve_priv *priv, int rx_qid)
+struct gve_queue_page_list *gve_assign_rx_qpl(struct gve_rx_alloc_rings_cfg *cfg,
+                                             int rx_qid)
 {
-       int id = gve_rx_qpl_id(priv, rx_qid);
-
+       int id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx_qid);
        /* QPL already in use */
-       if (test_bit(id, priv->qpl_cfg.qpl_id_map))
+       if (test_bit(id, cfg->qpl_cfg->qpl_id_map))
                return NULL;
-
-       set_bit(id, priv->qpl_cfg.qpl_id_map);
-       return &priv->qpls[id];
+       set_bit(id, cfg->qpl_cfg->qpl_id_map);
+       return &cfg->qpls[id];
 }
 
-/* Unassigns the qpl with the given id
- */
-static inline void gve_unassign_qpl(struct gve_priv *priv, int id)
+/* Unassigns the qpl with the given id */
+static inline void gve_unassign_qpl(struct gve_qpl_config *qpl_cfg, int id)
 {
-       clear_bit(id, priv->qpl_cfg.qpl_id_map);
+       clear_bit(id, qpl_cfg->qpl_id_map);
 }
 
-/* Returns the correct dma direction for tx and rx qpls
- */
+/* Returns the correct dma direction for tx and rx qpls */
 static inline enum dma_data_direction gve_qpl_dma_dir(struct gve_priv *priv,
                                                      int id)
 {
-       if (id < gve_rx_start_qpl_id(priv))
+       if (id < gve_rx_start_qpl_id(&priv->tx_cfg))
                return DMA_TO_DEVICE;
        else
                return DMA_FROM_DEVICE;
@@ -1036,6 +1084,9 @@ static inline u32 gve_xdp_tx_start_queue_id(struct gve_priv *priv)
        return gve_xdp_tx_queue_id(priv, 0);
 }
 
+/* gqi napi handler defined in gve_main.c */
+int gve_napi_poll(struct napi_struct *napi, int budget);
+
 /* buffers */
 int gve_alloc_page(struct gve_priv *priv, struct device *dev,
                   struct page **page, dma_addr_t *dma,
@@ -1051,8 +1102,12 @@ int gve_xdp_xmit_one(struct gve_priv *priv, struct gve_tx_ring *tx,
 void gve_xdp_tx_flush(struct gve_priv *priv, u32 xdp_qid);
 bool gve_tx_poll(struct gve_notify_block *block, int budget);
 bool gve_xdp_poll(struct gve_notify_block *block, int budget);
-int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings);
-void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings);
+int gve_tx_alloc_rings_gqi(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_free_rings_gqi(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx);
+void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx);
 u32 gve_tx_load_event_counter(struct gve_priv *priv,
                              struct gve_tx_ring *tx);
 bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx);
@@ -1061,7 +1116,12 @@ void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx);
 int gve_rx_poll(struct gve_notify_block *block, int budget);
 bool gve_rx_work_pending(struct gve_rx_ring *rx);
 int gve_rx_alloc_rings(struct gve_priv *priv);
-void gve_rx_free_rings_gqi(struct gve_priv *priv);
+int gve_rx_alloc_rings_gqi(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg);
+void gve_rx_free_rings_gqi(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg);
+void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx);
+void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx);
 /* Reset */
 void gve_schedule_reset(struct gve_priv *priv);
 int gve_reset(struct gve_priv *priv, bool attempt_teardown);
index c36b93f0de15b569eafbcb7222492013782fd441..b81584829c40e8c5098867aea66dc5318882d2e3 100644 (file)
@@ -38,10 +38,18 @@ netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
                                         netdev_features_t features);
 bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean);
 int gve_rx_poll_dqo(struct gve_notify_block *block, int budget);
-int gve_tx_alloc_rings_dqo(struct gve_priv *priv);
-void gve_tx_free_rings_dqo(struct gve_priv *priv);
-int gve_rx_alloc_rings_dqo(struct gve_priv *priv);
-void gve_rx_free_rings_dqo(struct gve_priv *priv);
+int gve_tx_alloc_rings_dqo(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_free_rings_dqo(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_start_ring_dqo(struct gve_priv *priv, int idx);
+void gve_tx_stop_ring_dqo(struct gve_priv *priv, int idx);
+int gve_rx_alloc_rings_dqo(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg);
+void gve_rx_free_rings_dqo(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg);
+void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx);
+void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx);
 int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
                          struct napi_struct *napi);
 void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx);
@@ -93,4 +101,6 @@ gve_set_itr_coalesce_usecs_dqo(struct gve_priv *priv,
        gve_write_irq_doorbell_dqo(priv, block,
                                   gve_setup_itr_interval_dqo(usecs));
 }
+
+int gve_napi_poll_dqo(struct napi_struct *napi, int budget);
 #endif /* _GVE_DQO_H_ */
index 619bf63ec935b6b5222480bbc5ef139aec1823fc..db6d9ae7cd789cfe926489f5847fb33c35fe145c 100644 (file)
@@ -22,6 +22,7 @@
 #include "gve_dqo.h"
 #include "gve_adminq.h"
 #include "gve_register.h"
+#include "gve_utils.h"
 
 #define GVE_DEFAULT_RX_COPYBREAK       (256)
 
@@ -252,7 +253,7 @@ static irqreturn_t gve_intr_dqo(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int gve_napi_poll(struct napi_struct *napi, int budget)
+int gve_napi_poll(struct napi_struct *napi, int budget)
 {
        struct gve_notify_block *block;
        __be32 __iomem *irq_doorbell;
@@ -302,7 +303,7 @@ static int gve_napi_poll(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-static int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
+int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
 {
        struct gve_notify_block *block =
                container_of(napi, struct gve_notify_block, napi);
@@ -581,19 +582,59 @@ static void gve_teardown_device_resources(struct gve_priv *priv)
        gve_clear_device_resources_ok(priv);
 }
 
-static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-                        int (*gve_poll)(struct napi_struct *, int))
+static int gve_unregister_qpl(struct gve_priv *priv, u32 i)
 {
-       struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+       int err;
+
+       err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id);
+       if (err) {
+               netif_err(priv, drv, priv->dev,
+                         "Failed to unregister queue page list %d\n",
+                         priv->qpls[i].id);
+               return err;
+       }
 
-       netif_napi_add(priv->dev, &block->napi, gve_poll);
+       priv->num_registered_pages -= priv->qpls[i].num_entries;
+       return 0;
 }
 
-static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
+static int gve_register_qpl(struct gve_priv *priv, u32 i)
 {
-       struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+       int num_rx_qpls;
+       int pages;
+       int err;
+
+       /* Rx QPLs succeed Tx QPLs in the priv->qpls array. */
+       num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv));
+       if (i >= gve_rx_start_qpl_id(&priv->tx_cfg) + num_rx_qpls) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot register nonexisting QPL at index %d\n", i);
+               return -EINVAL;
+       }
+
+       pages = priv->qpls[i].num_entries;
+
+       if (pages + priv->num_registered_pages > priv->max_registered_pages) {
+               netif_err(priv, drv, priv->dev,
+                         "Reached max number of registered pages %llu > %llu\n",
+                         pages + priv->num_registered_pages,
+                         priv->max_registered_pages);
+               return -EINVAL;
+       }
 
-       netif_napi_del(&block->napi);
+       err = gve_adminq_register_page_list(priv, &priv->qpls[i]);
+       if (err) {
+               netif_err(priv, drv, priv->dev,
+                         "failed to register queue page list %d\n",
+                         priv->qpls[i].id);
+               /* This failure will trigger a reset - no need to clean
+                * up
+                */
+               return err;
+       }
+
+       priv->num_registered_pages += pages;
+       return 0;
 }
 
 static int gve_register_xdp_qpls(struct gve_priv *priv)
@@ -602,55 +643,41 @@ static int gve_register_xdp_qpls(struct gve_priv *priv)
        int err;
        int i;
 
-       start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv));
+       start_id = gve_xdp_tx_start_queue_id(priv);
        for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) {
-               err = gve_adminq_register_page_list(priv, &priv->qpls[i]);
-               if (err) {
-                       netif_err(priv, drv, priv->dev,
-                                 "failed to register queue page list %d\n",
-                                 priv->qpls[i].id);
-                       /* This failure will trigger a reset - no need to clean
-                        * up
-                        */
+               err = gve_register_qpl(priv, i);
+               /* This failure will trigger a reset - no need to clean up */
+               if (err)
                        return err;
-               }
        }
        return 0;
 }
 
 static int gve_register_qpls(struct gve_priv *priv)
 {
+       int num_tx_qpls, num_rx_qpls;
        int start_id;
        int err;
        int i;
 
-       start_id = gve_tx_start_qpl_id(priv);
-       for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) {
-               err = gve_adminq_register_page_list(priv, &priv->qpls[i]);
-               if (err) {
-                       netif_err(priv, drv, priv->dev,
-                                 "failed to register queue page list %d\n",
-                                 priv->qpls[i].id);
-                       /* This failure will trigger a reset - no need to clean
-                        * up
-                        */
+       num_tx_qpls = gve_num_tx_qpls(&priv->tx_cfg, gve_num_xdp_qpls(priv),
+                                     gve_is_qpl(priv));
+       num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv));
+
+       for (i = 0; i < num_tx_qpls; i++) {
+               err = gve_register_qpl(priv, i);
+               if (err)
                        return err;
-               }
        }
 
-       start_id = gve_rx_start_qpl_id(priv);
-       for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) {
-               err = gve_adminq_register_page_list(priv, &priv->qpls[i]);
-               if (err) {
-                       netif_err(priv, drv, priv->dev,
-                                 "failed to register queue page list %d\n",
-                                 priv->qpls[i].id);
-                       /* This failure will trigger a reset - no need to clean
-                        * up
-                        */
+       /* there might be a gap between the tx and rx qpl ids */
+       start_id = gve_rx_start_qpl_id(&priv->tx_cfg);
+       for (i = 0; i < num_rx_qpls; i++) {
+               err = gve_register_qpl(priv, start_id + i);
+               if (err)
                        return err;
-               }
        }
+
        return 0;
 }
 
@@ -660,48 +687,40 @@ static int gve_unregister_xdp_qpls(struct gve_priv *priv)
        int err;
        int i;
 
-       start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv));
+       start_id = gve_xdp_tx_start_queue_id(priv);
        for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) {
-               err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id);
-               /* This failure will trigger a reset - no need to clean up */
-               if (err) {
-                       netif_err(priv, drv, priv->dev,
-                                 "Failed to unregister queue page list %d\n",
-                                 priv->qpls[i].id);
+               err = gve_unregister_qpl(priv, i);
+               /* This failure will trigger a reset - no need to clean */
+               if (err)
                        return err;
-               }
        }
        return 0;
 }
 
 static int gve_unregister_qpls(struct gve_priv *priv)
 {
+       int num_tx_qpls, num_rx_qpls;
        int start_id;
        int err;
        int i;
 
-       start_id = gve_tx_start_qpl_id(priv);
-       for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) {
-               err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id);
-               /* This failure will trigger a reset - no need to clean up */
-               if (err) {
-                       netif_err(priv, drv, priv->dev,
-                                 "Failed to unregister queue page list %d\n",
-                                 priv->qpls[i].id);
+       num_tx_qpls = gve_num_tx_qpls(&priv->tx_cfg, gve_num_xdp_qpls(priv),
+                                     gve_is_qpl(priv));
+       num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv));
+
+       for (i = 0; i < num_tx_qpls; i++) {
+               err = gve_unregister_qpl(priv, i);
+               /* This failure will trigger a reset - no need to clean */
+               if (err)
                        return err;
-               }
        }
 
-       start_id = gve_rx_start_qpl_id(priv);
-       for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) {
-               err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id);
-               /* This failure will trigger a reset - no need to clean up */
-               if (err) {
-                       netif_err(priv, drv, priv->dev,
-                                 "Failed to unregister queue page list %d\n",
-                                 priv->qpls[i].id);
+       start_id = gve_rx_start_qpl_id(&priv->tx_cfg);
+       for (i = 0; i < num_rx_qpls; i++) {
+               err = gve_unregister_qpl(priv, start_id + i);
+               /* This failure will trigger a reset - no need to clean */
+               if (err)
                        return err;
-               }
        }
        return 0;
 }
@@ -776,120 +795,124 @@ static int gve_create_rings(struct gve_priv *priv)
        return 0;
 }
 
-static void add_napi_init_xdp_sync_stats(struct gve_priv *priv,
-                                        int (*napi_poll)(struct napi_struct *napi,
-                                                         int budget))
+static void init_xdp_sync_stats(struct gve_priv *priv)
 {
        int start_id = gve_xdp_tx_start_queue_id(priv);
        int i;
 
-       /* Add xdp tx napi & init sync stats*/
+       /* Init stats */
        for (i = start_id; i < start_id + priv->num_xdp_queues; i++) {
                int ntfy_idx = gve_tx_idx_to_ntfy(priv, i);
 
                u64_stats_init(&priv->tx[i].statss);
                priv->tx[i].ntfy_id = ntfy_idx;
-               gve_add_napi(priv, ntfy_idx, napi_poll);
        }
 }
 
-static void add_napi_init_sync_stats(struct gve_priv *priv,
-                                    int (*napi_poll)(struct napi_struct *napi,
-                                                     int budget))
+static void gve_init_sync_stats(struct gve_priv *priv)
 {
        int i;
 
-       /* Add tx napi & init sync stats*/
-       for (i = 0; i < gve_num_tx_queues(priv); i++) {
-               int ntfy_idx = gve_tx_idx_to_ntfy(priv, i);
-
+       for (i = 0; i < priv->tx_cfg.num_queues; i++)
                u64_stats_init(&priv->tx[i].statss);
-               priv->tx[i].ntfy_id = ntfy_idx;
-               gve_add_napi(priv, ntfy_idx, napi_poll);
-       }
-       /* Add rx napi  & init sync stats*/
-       for (i = 0; i < priv->rx_cfg.num_queues; i++) {
-               int ntfy_idx = gve_rx_idx_to_ntfy(priv, i);
 
+       /* Init stats for XDP TX queues */
+       init_xdp_sync_stats(priv);
+
+       for (i = 0; i < priv->rx_cfg.num_queues; i++)
                u64_stats_init(&priv->rx[i].statss);
-               priv->rx[i].ntfy_id = ntfy_idx;
-               gve_add_napi(priv, ntfy_idx, napi_poll);
+}
+
+static void gve_tx_get_curr_alloc_cfg(struct gve_priv *priv,
+                                     struct gve_tx_alloc_rings_cfg *cfg)
+{
+       cfg->qcfg = &priv->tx_cfg;
+       cfg->raw_addressing = !gve_is_qpl(priv);
+       cfg->qpls = priv->qpls;
+       cfg->qpl_cfg = &priv->qpl_cfg;
+       cfg->ring_size = priv->tx_desc_cnt;
+       cfg->start_idx = 0;
+       cfg->num_rings = gve_num_tx_queues(priv);
+       cfg->tx = priv->tx;
+}
+
+static void gve_tx_stop_rings(struct gve_priv *priv, int start_id, int num_rings)
+{
+       int i;
+
+       if (!priv->tx)
+               return;
+
+       for (i = start_id; i < start_id + num_rings; i++) {
+               if (gve_is_gqi(priv))
+                       gve_tx_stop_ring_gqi(priv, i);
+               else
+                       gve_tx_stop_ring_dqo(priv, i);
        }
 }
 
-static void gve_tx_free_rings(struct gve_priv *priv, int start_id, int num_rings)
+static void gve_tx_start_rings(struct gve_priv *priv, int start_id,
+                              int num_rings)
 {
-       if (gve_is_gqi(priv)) {
-               gve_tx_free_rings_gqi(priv, start_id, num_rings);
-       } else {
-               gve_tx_free_rings_dqo(priv);
+       int i;
+
+       for (i = start_id; i < start_id + num_rings; i++) {
+               if (gve_is_gqi(priv))
+                       gve_tx_start_ring_gqi(priv, i);
+               else
+                       gve_tx_start_ring_dqo(priv, i);
        }
 }
 
 static int gve_alloc_xdp_rings(struct gve_priv *priv)
 {
-       int start_id;
+       struct gve_tx_alloc_rings_cfg cfg = {0};
        int err = 0;
 
        if (!priv->num_xdp_queues)
                return 0;
 
-       start_id = gve_xdp_tx_start_queue_id(priv);
-       err = gve_tx_alloc_rings(priv, start_id, priv->num_xdp_queues);
+       gve_tx_get_curr_alloc_cfg(priv, &cfg);
+       cfg.start_idx = gve_xdp_tx_start_queue_id(priv);
+       cfg.num_rings = priv->num_xdp_queues;
+
+       err = gve_tx_alloc_rings_gqi(priv, &cfg);
        if (err)
                return err;
-       add_napi_init_xdp_sync_stats(priv, gve_napi_poll);
+
+       gve_tx_start_rings(priv, cfg.start_idx, cfg.num_rings);
+       init_xdp_sync_stats(priv);
 
        return 0;
 }
 
-static int gve_alloc_rings(struct gve_priv *priv)
+static int gve_alloc_rings(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
+                          struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
 {
        int err;
 
-       /* Setup tx rings */
-       priv->tx = kvcalloc(priv->tx_cfg.max_queues, sizeof(*priv->tx),
-                           GFP_KERNEL);
-       if (!priv->tx)
-               return -ENOMEM;
-
        if (gve_is_gqi(priv))
-               err = gve_tx_alloc_rings(priv, 0, gve_num_tx_queues(priv));
+               err = gve_tx_alloc_rings_gqi(priv, tx_alloc_cfg);
        else
-               err = gve_tx_alloc_rings_dqo(priv);
+               err = gve_tx_alloc_rings_dqo(priv, tx_alloc_cfg);
        if (err)
-               goto free_tx;
-
-       /* Setup rx rings */
-       priv->rx = kvcalloc(priv->rx_cfg.max_queues, sizeof(*priv->rx),
-                           GFP_KERNEL);
-       if (!priv->rx) {
-               err = -ENOMEM;
-               goto free_tx_queue;
-       }
+               return err;
 
        if (gve_is_gqi(priv))
-               err = gve_rx_alloc_rings(priv);
+               err = gve_rx_alloc_rings_gqi(priv, rx_alloc_cfg);
        else
-               err = gve_rx_alloc_rings_dqo(priv);
+               err = gve_rx_alloc_rings_dqo(priv, rx_alloc_cfg);
        if (err)
-               goto free_rx;
-
-       if (gve_is_gqi(priv))
-               add_napi_init_sync_stats(priv, gve_napi_poll);
-       else
-               add_napi_init_sync_stats(priv, gve_napi_poll_dqo);
+               goto free_tx;
 
        return 0;
 
-free_rx:
-       kvfree(priv->rx);
-       priv->rx = NULL;
-free_tx_queue:
-       gve_tx_free_rings(priv, 0, gve_num_tx_queues(priv));
 free_tx:
-       kvfree(priv->tx);
-       priv->tx = NULL;
+       if (gve_is_gqi(priv))
+               gve_tx_free_rings_gqi(priv, tx_alloc_cfg);
+       else
+               gve_tx_free_rings_dqo(priv, tx_alloc_cfg);
        return err;
 }
 
@@ -937,52 +960,30 @@ static int gve_destroy_rings(struct gve_priv *priv)
        return 0;
 }
 
-static void gve_rx_free_rings(struct gve_priv *priv)
-{
-       if (gve_is_gqi(priv))
-               gve_rx_free_rings_gqi(priv);
-       else
-               gve_rx_free_rings_dqo(priv);
-}
-
 static void gve_free_xdp_rings(struct gve_priv *priv)
 {
-       int ntfy_idx, start_id;
-       int i;
+       struct gve_tx_alloc_rings_cfg cfg = {0};
+
+       gve_tx_get_curr_alloc_cfg(priv, &cfg);
+       cfg.start_idx = gve_xdp_tx_start_queue_id(priv);
+       cfg.num_rings = priv->num_xdp_queues;
 
-       start_id = gve_xdp_tx_start_queue_id(priv);
        if (priv->tx) {
-               for (i = start_id; i <  start_id + priv->num_xdp_queues; i++) {
-                       ntfy_idx = gve_tx_idx_to_ntfy(priv, i);
-                       gve_remove_napi(priv, ntfy_idx);
-               }
-               gve_tx_free_rings(priv, start_id, priv->num_xdp_queues);
+               gve_tx_stop_rings(priv, cfg.start_idx, cfg.num_rings);
+               gve_tx_free_rings_gqi(priv, &cfg);
        }
 }
 
-static void gve_free_rings(struct gve_priv *priv)
+static void gve_free_rings(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *tx_cfg,
+                          struct gve_rx_alloc_rings_cfg *rx_cfg)
 {
-       int num_tx_queues = gve_num_tx_queues(priv);
-       int ntfy_idx;
-       int i;
-
-       if (priv->tx) {
-               for (i = 0; i < num_tx_queues; i++) {
-                       ntfy_idx = gve_tx_idx_to_ntfy(priv, i);
-                       gve_remove_napi(priv, ntfy_idx);
-               }
-               gve_tx_free_rings(priv, 0, num_tx_queues);
-               kvfree(priv->tx);
-               priv->tx = NULL;
-       }
-       if (priv->rx) {
-               for (i = 0; i < priv->rx_cfg.num_queues; i++) {
-                       ntfy_idx = gve_rx_idx_to_ntfy(priv, i);
-                       gve_remove_napi(priv, ntfy_idx);
-               }
-               gve_rx_free_rings(priv);
-               kvfree(priv->rx);
-               priv->rx = NULL;
+       if (gve_is_gqi(priv)) {
+               gve_tx_free_rings_gqi(priv, tx_cfg);
+               gve_rx_free_rings_gqi(priv, rx_cfg);
+       } else {
+               gve_tx_free_rings_dqo(priv, tx_cfg);
+               gve_rx_free_rings_dqo(priv, rx_cfg);
        }
 }
 
@@ -1004,21 +1005,13 @@ int gve_alloc_page(struct gve_priv *priv, struct device *dev,
        return 0;
 }
 
-static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id,
-                                    int pages)
+static int gve_alloc_queue_page_list(struct gve_priv *priv,
+                                    struct gve_queue_page_list *qpl,
+                                    u32 id, int pages)
 {
-       struct gve_queue_page_list *qpl = &priv->qpls[id];
        int err;
        int i;
 
-       if (pages + priv->num_registered_pages > priv->max_registered_pages) {
-               netif_err(priv, drv, priv->dev,
-                         "Reached max number of registered pages %llu > %llu\n",
-                         pages + priv->num_registered_pages,
-                         priv->max_registered_pages);
-               return -EINVAL;
-       }
-
        qpl->id = id;
        qpl->num_entries = 0;
        qpl->pages = kvcalloc(pages, sizeof(*qpl->pages), GFP_KERNEL);
@@ -1039,7 +1032,6 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id,
                        return -ENOMEM;
                qpl->num_entries++;
        }
-       priv->num_registered_pages += pages;
 
        return 0;
 }
@@ -1053,9 +1045,10 @@ void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
                put_page(page);
 }
 
-static void gve_free_queue_page_list(struct gve_priv *priv, u32 id)
+static void gve_free_queue_page_list(struct gve_priv *priv,
+                                    struct gve_queue_page_list *qpl,
+                                    int id)
 {
-       struct gve_queue_page_list *qpl = &priv->qpls[id];
        int i;
 
        if (!qpl->pages)
@@ -1072,19 +1065,30 @@ static void gve_free_queue_page_list(struct gve_priv *priv, u32 id)
 free_pages:
        kvfree(qpl->pages);
        qpl->pages = NULL;
-       priv->num_registered_pages -= qpl->num_entries;
 }
 
-static int gve_alloc_xdp_qpls(struct gve_priv *priv)
+static void gve_free_n_qpls(struct gve_priv *priv,
+                           struct gve_queue_page_list *qpls,
+                           int start_id,
+                           int num_qpls)
+{
+       int i;
+
+       for (i = start_id; i < start_id + num_qpls; i++)
+               gve_free_queue_page_list(priv, &qpls[i], i);
+}
+
+static int gve_alloc_n_qpls(struct gve_priv *priv,
+                           struct gve_queue_page_list *qpls,
+                           int page_count,
+                           int start_id,
+                           int num_qpls)
 {
-       int start_id;
-       int i, j;
        int err;
+       int i;
 
-       start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv));
-       for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) {
-               err = gve_alloc_queue_page_list(priv, i,
-                                               priv->tx_pages_per_qpl);
+       for (i = start_id; i < start_id + num_qpls; i++) {
+               err = gve_alloc_queue_page_list(priv, &qpls[i], i, page_count);
                if (err)
                        goto free_qpls;
        }
@@ -1092,95 +1096,89 @@ static int gve_alloc_xdp_qpls(struct gve_priv *priv)
        return 0;
 
 free_qpls:
-       for (j = start_id; j <= i; j++)
-               gve_free_queue_page_list(priv, j);
+       /* Must include the failing QPL too for gve_alloc_queue_page_list fails
+        * without cleaning up.
+        */
+       gve_free_n_qpls(priv, qpls, start_id, i - start_id + 1);
        return err;
 }
 
-static int gve_alloc_qpls(struct gve_priv *priv)
+static int gve_alloc_qpls(struct gve_priv *priv,
+                         struct gve_qpls_alloc_cfg *cfg)
 {
-       int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues;
+       int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues;
+       int rx_start_id, tx_num_qpls, rx_num_qpls;
+       struct gve_queue_page_list *qpls;
        int page_count;
-       int start_id;
-       int i, j;
        int err;
 
-       if (!gve_is_qpl(priv))
+       if (cfg->raw_addressing)
                return 0;
 
-       priv->qpls = kvcalloc(max_queues, sizeof(*priv->qpls), GFP_KERNEL);
-       if (!priv->qpls)
+       qpls = kvcalloc(max_queues, sizeof(*qpls), GFP_KERNEL);
+       if (!qpls)
                return -ENOMEM;
 
-       start_id = gve_tx_start_qpl_id(priv);
-       page_count = priv->tx_pages_per_qpl;
-       for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) {
-               err = gve_alloc_queue_page_list(priv, i,
-                                               page_count);
-               if (err)
-                       goto free_qpls;
+       cfg->qpl_cfg->qpl_map_size = BITS_TO_LONGS(max_queues) *
+               sizeof(unsigned long) * BITS_PER_BYTE;
+       cfg->qpl_cfg->qpl_id_map = kvcalloc(BITS_TO_LONGS(max_queues),
+                                           sizeof(unsigned long), GFP_KERNEL);
+       if (!cfg->qpl_cfg->qpl_id_map) {
+               err = -ENOMEM;
+               goto free_qpl_array;
        }
 
-       start_id = gve_rx_start_qpl_id(priv);
+       /* Allocate TX QPLs */
+       page_count = priv->tx_pages_per_qpl;
+       tx_num_qpls = gve_num_tx_qpls(cfg->tx_cfg, cfg->num_xdp_queues,
+                                     gve_is_qpl(priv));
+       err = gve_alloc_n_qpls(priv, qpls, page_count, 0, tx_num_qpls);
+       if (err)
+               goto free_qpl_map;
 
+       /* Allocate RX QPLs */
+       rx_start_id = gve_rx_start_qpl_id(cfg->tx_cfg);
        /* For GQI_QPL number of pages allocated have 1:1 relationship with
         * number of descriptors. For DQO, number of pages required are
         * more than descriptors (because of out of order completions).
         */
-       page_count = priv->queue_format == GVE_GQI_QPL_FORMAT ?
-               priv->rx_data_slot_cnt : priv->rx_pages_per_qpl;
-       for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) {
-               err = gve_alloc_queue_page_list(priv, i,
-                                               page_count);
-               if (err)
-                       goto free_qpls;
-       }
-
-       priv->qpl_cfg.qpl_map_size = BITS_TO_LONGS(max_queues) *
-                                    sizeof(unsigned long) * BITS_PER_BYTE;
-       priv->qpl_cfg.qpl_id_map = kvcalloc(BITS_TO_LONGS(max_queues),
-                                           sizeof(unsigned long), GFP_KERNEL);
-       if (!priv->qpl_cfg.qpl_id_map) {
-               err = -ENOMEM;
-               goto free_qpls;
-       }
+       page_count = cfg->is_gqi ? priv->rx_data_slot_cnt : priv->rx_pages_per_qpl;
+       rx_num_qpls = gve_num_rx_qpls(cfg->rx_cfg, gve_is_qpl(priv));
+       err = gve_alloc_n_qpls(priv, qpls, page_count, rx_start_id, rx_num_qpls);
+       if (err)
+               goto free_tx_qpls;
 
+       cfg->qpls = qpls;
        return 0;
 
-free_qpls:
-       for (j = 0; j <= i; j++)
-               gve_free_queue_page_list(priv, j);
-       kvfree(priv->qpls);
-       priv->qpls = NULL;
+free_tx_qpls:
+       gve_free_n_qpls(priv, qpls, 0, tx_num_qpls);
+free_qpl_map:
+       kvfree(cfg->qpl_cfg->qpl_id_map);
+       cfg->qpl_cfg->qpl_id_map = NULL;
+free_qpl_array:
+       kvfree(qpls);
        return err;
 }
 
-static void gve_free_xdp_qpls(struct gve_priv *priv)
-{
-       int start_id;
-       int i;
-
-       start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv));
-       for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++)
-               gve_free_queue_page_list(priv, i);
-}
-
-static void gve_free_qpls(struct gve_priv *priv)
+static void gve_free_qpls(struct gve_priv *priv,
+                         struct gve_qpls_alloc_cfg *cfg)
 {
-       int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues;
+       int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues;
+       struct gve_queue_page_list *qpls = cfg->qpls;
        int i;
 
-       if (!priv->qpls)
+       if (!qpls)
                return;
 
-       kvfree(priv->qpl_cfg.qpl_id_map);
-       priv->qpl_cfg.qpl_id_map = NULL;
+       kvfree(cfg->qpl_cfg->qpl_id_map);
+       cfg->qpl_cfg->qpl_id_map = NULL;
 
        for (i = 0; i < max_queues; i++)
-               gve_free_queue_page_list(priv, i);
+               gve_free_queue_page_list(priv, &qpls[i], i);
 
-       kvfree(priv->qpls);
-       priv->qpls = NULL;
+       kvfree(qpls);
+       cfg->qpls = NULL;
 }
 
 /* Use this to schedule a reset when the device is capable of continuing
@@ -1291,34 +1289,160 @@ static void gve_drain_page_cache(struct gve_priv *priv)
        }
 }
 
-static int gve_open(struct net_device *dev)
+static void gve_qpls_get_curr_alloc_cfg(struct gve_priv *priv,
+                                       struct gve_qpls_alloc_cfg *cfg)
+{
+         cfg->raw_addressing = !gve_is_qpl(priv);
+         cfg->is_gqi = gve_is_gqi(priv);
+         cfg->num_xdp_queues = priv->num_xdp_queues;
+         cfg->qpl_cfg = &priv->qpl_cfg;
+         cfg->tx_cfg = &priv->tx_cfg;
+         cfg->rx_cfg = &priv->rx_cfg;
+         cfg->qpls = priv->qpls;
+}
+
+static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv,
+                                     struct gve_rx_alloc_rings_cfg *cfg)
+{
+       cfg->qcfg = &priv->rx_cfg;
+       cfg->qcfg_tx = &priv->tx_cfg;
+       cfg->raw_addressing = !gve_is_qpl(priv);
+       cfg->qpls = priv->qpls;
+       cfg->qpl_cfg = &priv->qpl_cfg;
+       cfg->ring_size = priv->rx_desc_cnt;
+       cfg->rx = priv->rx;
+}
+
+static void gve_get_curr_alloc_cfgs(struct gve_priv *priv,
+                                   struct gve_qpls_alloc_cfg *qpls_alloc_cfg,
+                                   struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
+                                   struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
+{
+       gve_qpls_get_curr_alloc_cfg(priv, qpls_alloc_cfg);
+       gve_tx_get_curr_alloc_cfg(priv, tx_alloc_cfg);
+       gve_rx_get_curr_alloc_cfg(priv, rx_alloc_cfg);
+}
+
+static void gve_rx_start_rings(struct gve_priv *priv, int num_rings)
+{
+       int i;
+
+       for (i = 0; i < num_rings; i++) {
+               if (gve_is_gqi(priv))
+                       gve_rx_start_ring_gqi(priv, i);
+               else
+                       gve_rx_start_ring_dqo(priv, i);
+       }
+}
+
+static void gve_rx_stop_rings(struct gve_priv *priv, int num_rings)
+{
+       int i;
+
+       if (!priv->rx)
+               return;
+
+       for (i = 0; i < num_rings; i++) {
+               if (gve_is_gqi(priv))
+                       gve_rx_stop_ring_gqi(priv, i);
+               else
+                       gve_rx_stop_ring_dqo(priv, i);
+       }
+}
+
+static void gve_queues_mem_free(struct gve_priv *priv,
+                               struct gve_qpls_alloc_cfg *qpls_alloc_cfg,
+                               struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
+                               struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
+{
+       gve_free_rings(priv, tx_alloc_cfg, rx_alloc_cfg);
+       gve_free_qpls(priv, qpls_alloc_cfg);
+}
+
+static int gve_queues_mem_alloc(struct gve_priv *priv,
+                               struct gve_qpls_alloc_cfg *qpls_alloc_cfg,
+                               struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
+                               struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
 {
-       struct gve_priv *priv = netdev_priv(dev);
        int err;
 
+       err = gve_alloc_qpls(priv, qpls_alloc_cfg);
+       if (err) {
+               netif_err(priv, drv, priv->dev, "Failed to alloc QPLs\n");
+               return err;
+       }
+       tx_alloc_cfg->qpls = qpls_alloc_cfg->qpls;
+       rx_alloc_cfg->qpls = qpls_alloc_cfg->qpls;
+       err = gve_alloc_rings(priv, tx_alloc_cfg, rx_alloc_cfg);
+       if (err) {
+               netif_err(priv, drv, priv->dev, "Failed to alloc rings\n");
+               goto free_qpls;
+       }
+
+       return 0;
+
+free_qpls:
+       gve_free_qpls(priv, qpls_alloc_cfg);
+       return err;
+}
+
+static void gve_queues_mem_remove(struct gve_priv *priv)
+{
+       struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+       struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+       struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+
+       gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+                               &tx_alloc_cfg, &rx_alloc_cfg);
+       gve_queues_mem_free(priv, &qpls_alloc_cfg,
+                           &tx_alloc_cfg, &rx_alloc_cfg);
+       priv->qpls = NULL;
+       priv->tx = NULL;
+       priv->rx = NULL;
+}
+
+/* The passed-in queue memory is stored into priv and the queues are made live.
+ * No memory is allocated. Passed-in memory is freed on errors.
+ */
+static int gve_queues_start(struct gve_priv *priv,
+                           struct gve_qpls_alloc_cfg *qpls_alloc_cfg,
+                           struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
+                           struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
+{
+       struct net_device *dev = priv->dev;
+       int err;
+
+       /* Record new resources into priv */
+       priv->qpls = qpls_alloc_cfg->qpls;
+       priv->tx = tx_alloc_cfg->tx;
+       priv->rx = rx_alloc_cfg->rx;
+
+       /* Record new configs into priv */
+       priv->qpl_cfg = *qpls_alloc_cfg->qpl_cfg;
+       priv->tx_cfg = *tx_alloc_cfg->qcfg;
+       priv->rx_cfg = *rx_alloc_cfg->qcfg;
+       priv->tx_desc_cnt = tx_alloc_cfg->ring_size;
+       priv->rx_desc_cnt = rx_alloc_cfg->ring_size;
+
        if (priv->xdp_prog)
                priv->num_xdp_queues = priv->rx_cfg.num_queues;
        else
                priv->num_xdp_queues = 0;
 
-       err = gve_alloc_qpls(priv);
-       if (err)
-               return err;
-
-       err = gve_alloc_rings(priv);
-       if (err)
-               goto free_qpls;
+       gve_tx_start_rings(priv, 0, tx_alloc_cfg->num_rings);
+       gve_rx_start_rings(priv, rx_alloc_cfg->qcfg->num_queues);
+       gve_init_sync_stats(priv);
 
        err = netif_set_real_num_tx_queues(dev, priv->tx_cfg.num_queues);
        if (err)
-               goto free_rings;
+               goto stop_and_free_rings;
        err = netif_set_real_num_rx_queues(dev, priv->rx_cfg.num_queues);
        if (err)
-               goto free_rings;
+               goto stop_and_free_rings;
 
        err = gve_reg_xdp_info(priv, dev);
        if (err)
-               goto free_rings;
+               goto stop_and_free_rings;
 
        err = gve_register_qpls(priv);
        if (err)
@@ -1346,32 +1470,53 @@ static int gve_open(struct net_device *dev)
        priv->interface_up_cnt++;
        return 0;
 
-free_rings:
-       gve_free_rings(priv);
-free_qpls:
-       gve_free_qpls(priv);
-       return err;
-
 reset:
-       /* This must have been called from a reset due to the rtnl lock
-        * so just return at this point.
-        */
        if (gve_get_reset_in_progress(priv))
-               return err;
-       /* Otherwise reset before returning */
+               goto stop_and_free_rings;
        gve_reset_and_teardown(priv, true);
        /* if this fails there is nothing we can do so just ignore the return */
        gve_reset_recovery(priv, false);
        /* return the original error */
        return err;
+stop_and_free_rings:
+       gve_tx_stop_rings(priv, 0, gve_num_tx_queues(priv));
+       gve_rx_stop_rings(priv, priv->rx_cfg.num_queues);
+       gve_queues_mem_remove(priv);
+       return err;
 }
 
-static int gve_close(struct net_device *dev)
+static int gve_open(struct net_device *dev)
 {
+       struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+       struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+       struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
        struct gve_priv *priv = netdev_priv(dev);
        int err;
 
-       netif_carrier_off(dev);
+       gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+                               &tx_alloc_cfg, &rx_alloc_cfg);
+
+       err = gve_queues_mem_alloc(priv, &qpls_alloc_cfg,
+                                  &tx_alloc_cfg, &rx_alloc_cfg);
+       if (err)
+               return err;
+
+       /* No need to free on error: ownership of resources is lost after
+        * calling gve_queues_start.
+        */
+       err = gve_queues_start(priv, &qpls_alloc_cfg,
+                              &tx_alloc_cfg, &rx_alloc_cfg);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int gve_queues_stop(struct gve_priv *priv)
+{
+       int err;
+
+       netif_carrier_off(priv->dev);
        if (gve_get_device_rings_ok(priv)) {
                gve_turndown(priv);
                gve_drain_page_cache(priv);
@@ -1386,8 +1531,10 @@ static int gve_close(struct net_device *dev)
        del_timer_sync(&priv->stats_report_timer);
 
        gve_unreg_xdp_info(priv);
-       gve_free_rings(priv);
-       gve_free_qpls(priv);
+
+       gve_tx_stop_rings(priv, 0, gve_num_tx_queues(priv));
+       gve_rx_stop_rings(priv, priv->rx_cfg.num_queues);
+
        priv->interface_down_cnt++;
        return 0;
 
@@ -1402,10 +1549,26 @@ err:
        return gve_reset_recovery(priv, false);
 }
 
+static int gve_close(struct net_device *dev)
+{
+       struct gve_priv *priv = netdev_priv(dev);
+       int err;
+
+       err = gve_queues_stop(priv);
+       if (err)
+               return err;
+
+       gve_queues_mem_remove(priv);
+       return 0;
+}
+
 static int gve_remove_xdp_queues(struct gve_priv *priv)
 {
+       int qpl_start_id;
        int err;
 
+       qpl_start_id = gve_xdp_tx_start_queue_id(priv);
+
        err = gve_destroy_xdp_rings(priv);
        if (err)
                return err;
@@ -1416,18 +1579,22 @@ static int gve_remove_xdp_queues(struct gve_priv *priv)
 
        gve_unreg_xdp_info(priv);
        gve_free_xdp_rings(priv);
-       gve_free_xdp_qpls(priv);
+
+       gve_free_n_qpls(priv, priv->qpls, qpl_start_id, gve_num_xdp_qpls(priv));
        priv->num_xdp_queues = 0;
        return 0;
 }
 
 static int gve_add_xdp_queues(struct gve_priv *priv)
 {
+       int start_id;
        int err;
 
-       priv->num_xdp_queues = priv->tx_cfg.num_queues;
+       priv->num_xdp_queues = priv->rx_cfg.num_queues;
 
-       err = gve_alloc_xdp_qpls(priv);
+       start_id = gve_xdp_tx_start_queue_id(priv);
+       err = gve_alloc_n_qpls(priv, priv->qpls, priv->tx_pages_per_qpl,
+                              start_id, gve_num_xdp_qpls(priv));
        if (err)
                goto err;
 
@@ -1452,7 +1619,7 @@ static int gve_add_xdp_queues(struct gve_priv *priv)
 free_xdp_rings:
        gve_free_xdp_rings(priv);
 free_xdp_qpls:
-       gve_free_xdp_qpls(priv);
+       gve_free_n_qpls(priv, priv->qpls, start_id, gve_num_xdp_qpls(priv));
 err:
        priv->num_xdp_queues = 0;
        return err;
@@ -1702,42 +1869,87 @@ static int gve_xdp(struct net_device *dev, struct netdev_bpf *xdp)
        }
 }
 
+static int gve_adjust_config(struct gve_priv *priv,
+                            struct gve_qpls_alloc_cfg *qpls_alloc_cfg,
+                            struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
+                            struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
+{
+       int err;
+
+       /* Allocate resources for the new confiugration */
+       err = gve_queues_mem_alloc(priv, qpls_alloc_cfg,
+                                  tx_alloc_cfg, rx_alloc_cfg);
+       if (err) {
+               netif_err(priv, drv, priv->dev,
+                         "Adjust config failed to alloc new queues");
+               return err;
+       }
+
+       /* Teardown the device and free existing resources */
+       err = gve_close(priv->dev);
+       if (err) {
+               netif_err(priv, drv, priv->dev,
+                         "Adjust config failed to close old queues");
+               gve_queues_mem_free(priv, qpls_alloc_cfg,
+                                   tx_alloc_cfg, rx_alloc_cfg);
+               return err;
+       }
+
+       /* Bring the device back up again with the new resources. */
+       err = gve_queues_start(priv, qpls_alloc_cfg,
+                              tx_alloc_cfg, rx_alloc_cfg);
+       if (err) {
+               netif_err(priv, drv, priv->dev,
+                         "Adjust config failed to start new queues, !!! DISABLING ALL QUEUES !!!\n");
+               /* No need to free on error: ownership of resources is lost after
+                * calling gve_queues_start.
+                */
+               gve_turndown(priv);
+               return err;
+       }
+
+       return 0;
+}
+
 int gve_adjust_queues(struct gve_priv *priv,
                      struct gve_queue_config new_rx_config,
                      struct gve_queue_config new_tx_config)
 {
+       struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+       struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+       struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+       struct gve_qpl_config new_qpl_cfg;
        int err;
 
-       if (netif_carrier_ok(priv->dev)) {
-               /* To make this process as simple as possible we teardown the
-                * device, set the new configuration, and then bring the device
-                * up again.
-                */
-               err = gve_close(priv->dev);
-               /* we have already tried to reset in close,
-                * just fail at this point
-                */
-               if (err)
-                       return err;
-               priv->tx_cfg = new_tx_config;
-               priv->rx_cfg = new_rx_config;
+       gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+                               &tx_alloc_cfg, &rx_alloc_cfg);
 
-               err = gve_open(priv->dev);
-               if (err)
-                       goto err;
+       /* qpl_cfg is not read-only, it contains a map that gets updated as
+        * rings are allocated, which is why we cannot use the yet unreleased
+        * one in priv.
+        */
+       qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+       tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+       rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
+       /* Relay the new config from ethtool */
+       qpls_alloc_cfg.tx_cfg = &new_tx_config;
+       tx_alloc_cfg.qcfg = &new_tx_config;
+       rx_alloc_cfg.qcfg_tx = &new_tx_config;
+       qpls_alloc_cfg.rx_cfg = &new_rx_config;
+       rx_alloc_cfg.qcfg = &new_rx_config;
+       tx_alloc_cfg.num_rings = new_tx_config.num_queues;
 
-               return 0;
+       if (netif_carrier_ok(priv->dev)) {
+               err = gve_adjust_config(priv, &qpls_alloc_cfg,
+                                       &tx_alloc_cfg, &rx_alloc_cfg);
+               return err;
        }
        /* Set the config for the next up. */
        priv->tx_cfg = new_tx_config;
        priv->rx_cfg = new_rx_config;
 
        return 0;
-err:
-       netif_err(priv, drv, priv->dev,
-                 "Adjust queues failed! !!! DISABLING ALL QUEUES !!!\n");
-       gve_turndown(priv);
-       return err;
 }
 
 static void gve_turndown(struct gve_priv *priv)
@@ -1857,36 +2069,37 @@ static int gve_set_features(struct net_device *netdev,
                            netdev_features_t features)
 {
        const netdev_features_t orig_features = netdev->features;
+       struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+       struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+       struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
        struct gve_priv *priv = netdev_priv(netdev);
+       struct gve_qpl_config new_qpl_cfg;
        int err;
 
+       gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+                               &tx_alloc_cfg, &rx_alloc_cfg);
+       /* qpl_cfg is not read-only, it contains a map that gets updated as
+        * rings are allocated, which is why we cannot use the yet unreleased
+        * one in priv.
+        */
+       qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+       tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+       rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
        if ((netdev->features & NETIF_F_LRO) != (features & NETIF_F_LRO)) {
                netdev->features ^= NETIF_F_LRO;
                if (netif_carrier_ok(netdev)) {
-                       /* To make this process as simple as possible we
-                        * teardown the device, set the new configuration,
-                        * and then bring the device up again.
-                        */
-                       err = gve_close(netdev);
-                       /* We have already tried to reset in close, just fail
-                        * at this point.
-                        */
-                       if (err)
-                               goto err;
-
-                       err = gve_open(netdev);
-                       if (err)
-                               goto err;
+                       err = gve_adjust_config(priv, &qpls_alloc_cfg,
+                                               &tx_alloc_cfg, &rx_alloc_cfg);
+                       if (err) {
+                               /* Revert the change on error. */
+                               netdev->features = orig_features;
+                               return err;
+                       }
                }
        }
 
        return 0;
-err:
-       /* Reverts the change on error. */
-       netdev->features = orig_features;
-       netif_err(priv, drv, netdev,
-                 "Set features failed! !!! DISABLING ALL QUEUES !!!\n");
-       return err;
 }
 
 static const struct net_device_ops gve_netdev_ops = {
@@ -2051,6 +2264,8 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
                goto err;
        }
 
+       priv->num_registered_pages = 0;
+
        if (skip_describe_device)
                goto setup_device;
 
@@ -2080,7 +2295,6 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
        if (!gve_is_gqi(priv))
                netif_set_tso_max_size(priv->dev, GVE_DQO_TX_MAX);
 
-       priv->num_registered_pages = 0;
        priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK;
        /* gvnic has one Notification Block per MSI-x vector, except for the
         * management vector
index 7a8dc5386ffff9bd99d94eced337cf276551a88f..c294a1595b6acf03dcc549373acdb231726659e5 100644 (file)
@@ -23,7 +23,9 @@ static void gve_rx_free_buffer(struct device *dev,
        gve_free_page(dev, page_info->page, dma, DMA_FROM_DEVICE);
 }
 
-static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx)
+static void gve_rx_unfill_pages(struct gve_priv *priv,
+                               struct gve_rx_ring *rx,
+                               struct gve_rx_alloc_rings_cfg *cfg)
 {
        u32 slots = rx->mask + 1;
        int i;
@@ -36,7 +38,7 @@ static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx)
                for (i = 0; i < slots; i++)
                        page_ref_sub(rx->data.page_info[i].page,
                                     rx->data.page_info[i].pagecnt_bias - 1);
-               gve_unassign_qpl(priv, rx->data.qpl->id);
+               gve_unassign_qpl(cfg->qpl_cfg, rx->data.qpl->id);
                rx->data.qpl = NULL;
 
                for (i = 0; i < rx->qpl_copy_pool_mask + 1; i++) {
@@ -49,16 +51,26 @@ static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx)
        rx->data.page_info = NULL;
 }
 
-static void gve_rx_free_ring(struct gve_priv *priv, int idx)
+void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx)
+{
+       int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
+
+       if (!gve_rx_was_added_to_block(priv, idx))
+               return;
+
+       gve_remove_napi(priv, ntfy_idx);
+       gve_rx_remove_from_block(priv, idx);
+}
+
+static void gve_rx_free_ring_gqi(struct gve_priv *priv, struct gve_rx_ring *rx,
+                                struct gve_rx_alloc_rings_cfg *cfg)
 {
-       struct gve_rx_ring *rx = &priv->rx[idx];
        struct device *dev = &priv->pdev->dev;
        u32 slots = rx->mask + 1;
+       int idx = rx->q_num;
        size_t bytes;
 
-       gve_rx_remove_from_block(priv, idx);
-
-       bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt;
+       bytes = sizeof(struct gve_rx_desc) * cfg->ring_size;
        dma_free_coherent(dev, bytes, rx->desc.desc_ring, rx->desc.bus);
        rx->desc.desc_ring = NULL;
 
@@ -66,7 +78,7 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx)
                          rx->q_resources, rx->q_resources_bus);
        rx->q_resources = NULL;
 
-       gve_rx_unfill_pages(priv, rx);
+       gve_rx_unfill_pages(priv, rx, cfg);
 
        bytes = sizeof(*rx->data.data_ring) * slots;
        dma_free_coherent(dev, bytes, rx->data.data_ring,
@@ -108,7 +120,8 @@ static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev,
        return 0;
 }
 
-static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
+static int gve_rx_prefill_pages(struct gve_rx_ring *rx,
+                               struct gve_rx_alloc_rings_cfg *cfg)
 {
        struct gve_priv *priv = rx->gve;
        u32 slots;
@@ -127,7 +140,7 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
                return -ENOMEM;
 
        if (!rx->data.raw_addressing) {
-               rx->data.qpl = gve_assign_rx_qpl(priv, rx->q_num);
+               rx->data.qpl = gve_assign_rx_qpl(cfg, rx->q_num);
                if (!rx->data.qpl) {
                        kvfree(rx->data.page_info);
                        rx->data.page_info = NULL;
@@ -185,7 +198,7 @@ alloc_err_qpl:
                page_ref_sub(rx->data.page_info[i].page,
                             rx->data.page_info[i].pagecnt_bias - 1);
 
-       gve_unassign_qpl(priv, rx->data.qpl->id);
+       gve_unassign_qpl(cfg->qpl_cfg, rx->data.qpl->id);
        rx->data.qpl = NULL;
 
        return err;
@@ -207,13 +220,23 @@ static void gve_rx_ctx_clear(struct gve_rx_ctx *ctx)
        ctx->drop_pkt = false;
 }
 
-static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
+void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx)
+{
+       int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
+
+       gve_rx_add_to_block(priv, idx);
+       gve_add_napi(priv, ntfy_idx, gve_napi_poll);
+}
+
+static int gve_rx_alloc_ring_gqi(struct gve_priv *priv,
+                                struct gve_rx_alloc_rings_cfg *cfg,
+                                struct gve_rx_ring *rx,
+                                int idx)
 {
-       struct gve_rx_ring *rx = &priv->rx[idx];
        struct device *hdev = &priv->pdev->dev;
+       u32 slots = priv->rx_data_slot_cnt;
        int filled_pages;
        size_t bytes;
-       u32 slots;
        int err;
 
        netif_dbg(priv, drv, priv->dev, "allocating rx ring\n");
@@ -223,9 +246,8 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
        rx->gve = priv;
        rx->q_num = idx;
 
-       slots = priv->rx_data_slot_cnt;
        rx->mask = slots - 1;
-       rx->data.raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT;
+       rx->data.raw_addressing = cfg->raw_addressing;
 
        /* alloc rx data ring */
        bytes = sizeof(*rx->data.data_ring) * slots;
@@ -246,7 +268,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
                goto abort_with_slots;
        }
 
-       filled_pages = gve_prefill_rx_pages(rx);
+       filled_pages = gve_rx_prefill_pages(rx, cfg);
        if (filled_pages < 0) {
                err = -ENOMEM;
                goto abort_with_copy_pool;
@@ -269,7 +291,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
                  (unsigned long)rx->data.data_bus);
 
        /* alloc rx desc ring */
-       bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt;
+       bytes = sizeof(struct gve_rx_desc) * cfg->ring_size;
        rx->desc.desc_ring = dma_alloc_coherent(hdev, bytes, &rx->desc.bus,
                                                GFP_KERNEL);
        if (!rx->desc.desc_ring) {
@@ -277,15 +299,11 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
                goto abort_with_q_resources;
        }
        rx->cnt = 0;
-       rx->db_threshold = priv->rx_desc_cnt / 2;
+       rx->db_threshold = slots / 2;
        rx->desc.seqno = 1;
 
-       /* Allocating half-page buffers allows page-flipping which is faster
-        * than copying or allocating new pages.
-        */
        rx->packet_buffer_size = GVE_DEFAULT_RX_BUFFER_SIZE;
        gve_rx_ctx_clear(&rx->ctx);
-       gve_rx_add_to_block(priv, idx);
 
        return 0;
 
@@ -294,7 +312,7 @@ abort_with_q_resources:
                          rx->q_resources, rx->q_resources_bus);
        rx->q_resources = NULL;
 abort_filled:
-       gve_rx_unfill_pages(priv, rx);
+       gve_rx_unfill_pages(priv, rx, cfg);
 abort_with_copy_pool:
        kvfree(rx->qpl_copy_pool);
        rx->qpl_copy_pool = NULL;
@@ -306,36 +324,58 @@ abort_with_slots:
        return err;
 }
 
-int gve_rx_alloc_rings(struct gve_priv *priv)
+int gve_rx_alloc_rings_gqi(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg)
 {
+       struct gve_rx_ring *rx;
        int err = 0;
-       int i;
+       int i, j;
 
-       for (i = 0; i < priv->rx_cfg.num_queues; i++) {
-               err = gve_rx_alloc_ring(priv, i);
+       if (!cfg->raw_addressing && !cfg->qpls) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc QPL ring before allocing QPLs\n");
+               return -EINVAL;
+       }
+
+       rx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_rx_ring),
+                     GFP_KERNEL);
+       if (!rx)
+               return -ENOMEM;
+
+       for (i = 0; i < cfg->qcfg->num_queues; i++) {
+               err = gve_rx_alloc_ring_gqi(priv, cfg, &rx[i], i);
                if (err) {
                        netif_err(priv, drv, priv->dev,
                                  "Failed to alloc rx ring=%d: err=%d\n",
                                  i, err);
-                       break;
+                       goto cleanup;
                }
        }
-       /* Unallocate if there was an error */
-       if (err) {
-               int j;
 
-               for (j = 0; j < i; j++)
-                       gve_rx_free_ring(priv, j);
-       }
+       cfg->rx = rx;
+       return 0;
+
+cleanup:
+       for (j = 0; j < i; j++)
+               gve_rx_free_ring_gqi(priv, &rx[j], cfg);
+       kvfree(rx);
        return err;
 }
 
-void gve_rx_free_rings_gqi(struct gve_priv *priv)
+void gve_rx_free_rings_gqi(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg)
 {
+       struct gve_rx_ring *rx = cfg->rx;
        int i;
 
-       for (i = 0; i < priv->rx_cfg.num_queues; i++)
-               gve_rx_free_ring(priv, i);
+       if (!rx)
+               return;
+
+       for (i = 0; i < cfg->qcfg->num_queues;  i++)
+               gve_rx_free_ring_gqi(priv, &rx[i], cfg);
+
+       kvfree(rx);
+       cfg->rx = NULL;
 }
 
 void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx)
index f281e42a7ef9680e2049a185782a37d402c7f886..8e6aeb5b3ed41346b73d044df6a96504a29bf411 100644 (file)
@@ -199,20 +199,30 @@ static int gve_alloc_page_dqo(struct gve_rx_ring *rx,
        return 0;
 }
 
-static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx)
+void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx)
+{
+       int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
+
+       if (!gve_rx_was_added_to_block(priv, idx))
+               return;
+
+       gve_remove_napi(priv, ntfy_idx);
+       gve_rx_remove_from_block(priv, idx);
+}
+
+static void gve_rx_free_ring_dqo(struct gve_priv *priv, struct gve_rx_ring *rx,
+                                struct gve_rx_alloc_rings_cfg *cfg)
 {
-       struct gve_rx_ring *rx = &priv->rx[idx];
        struct device *hdev = &priv->pdev->dev;
        size_t completion_queue_slots;
        size_t buffer_queue_slots;
+       int idx = rx->q_num;
        size_t size;
        int i;
 
        completion_queue_slots = rx->dqo.complq.mask + 1;
        buffer_queue_slots = rx->dqo.bufq.mask + 1;
 
-       gve_rx_remove_from_block(priv, idx);
-
        if (rx->q_resources) {
                dma_free_coherent(hdev, sizeof(*rx->q_resources),
                                  rx->q_resources, rx->q_resources_bus);
@@ -226,7 +236,7 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx)
                        gve_free_page_dqo(priv, bs, !rx->dqo.qpl);
        }
        if (rx->dqo.qpl) {
-               gve_unassign_qpl(priv, rx->dqo.qpl->id);
+               gve_unassign_qpl(cfg->qpl_cfg, rx->dqo.qpl->id);
                rx->dqo.qpl = NULL;
        }
 
@@ -251,17 +261,26 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx)
        netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx);
 }
 
-static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
+void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx)
+{
+       int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
+
+       gve_rx_add_to_block(priv, idx);
+       gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo);
+}
+
+static int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
+                                struct gve_rx_alloc_rings_cfg *cfg,
+                                struct gve_rx_ring *rx,
+                                int idx)
 {
-       struct gve_rx_ring *rx = &priv->rx[idx];
        struct device *hdev = &priv->pdev->dev;
        size_t size;
        int i;
 
-       const u32 buffer_queue_slots =
-               priv->queue_format == GVE_DQO_RDA_FORMAT ?
-               priv->options_dqo_rda.rx_buff_ring_entries : priv->rx_desc_cnt;
-       const u32 completion_queue_slots = priv->rx_desc_cnt;
+       const u32 buffer_queue_slots = cfg->raw_addressing ?
+               priv->options_dqo_rda.rx_buff_ring_entries : cfg->ring_size;
+       const u32 completion_queue_slots = cfg->ring_size;
 
        netif_dbg(priv, drv, priv->dev, "allocating rx ring DQO\n");
 
@@ -274,7 +293,7 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
        rx->ctx.skb_head = NULL;
        rx->ctx.skb_tail = NULL;
 
-       rx->dqo.num_buf_states = priv->queue_format == GVE_DQO_RDA_FORMAT ?
+       rx->dqo.num_buf_states = cfg->raw_addressing ?
                min_t(s16, S16_MAX, buffer_queue_slots * 4) :
                priv->rx_pages_per_qpl;
        rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
@@ -308,8 +327,8 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
        if (!rx->dqo.bufq.desc_ring)
                goto err;
 
-       if (priv->queue_format != GVE_DQO_RDA_FORMAT) {
-               rx->dqo.qpl = gve_assign_rx_qpl(priv, rx->q_num);
+       if (!cfg->raw_addressing) {
+               rx->dqo.qpl = gve_assign_rx_qpl(cfg, rx->q_num);
                if (!rx->dqo.qpl)
                        goto err;
                rx->dqo.next_qpl_page_idx = 0;
@@ -320,12 +339,10 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
        if (!rx->q_resources)
                goto err;
 
-       gve_rx_add_to_block(priv, idx);
-
        return 0;
 
 err:
-       gve_rx_free_ring_dqo(priv, idx);
+       gve_rx_free_ring_dqo(priv, rx, cfg);
        return -ENOMEM;
 }
 
@@ -337,13 +354,26 @@ void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx)
        iowrite32(rx->dqo.bufq.tail, &priv->db_bar2[index]);
 }
 
-int gve_rx_alloc_rings_dqo(struct gve_priv *priv)
+int gve_rx_alloc_rings_dqo(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg)
 {
-       int err = 0;
+       struct gve_rx_ring *rx;
+       int err;
        int i;
 
-       for (i = 0; i < priv->rx_cfg.num_queues; i++) {
-               err = gve_rx_alloc_ring_dqo(priv, i);
+       if (!cfg->raw_addressing && !cfg->qpls) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc QPL ring before allocing QPLs\n");
+               return -EINVAL;
+       }
+
+       rx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_rx_ring),
+                     GFP_KERNEL);
+       if (!rx)
+               return -ENOMEM;
+
+       for (i = 0; i < cfg->qcfg->num_queues; i++) {
+               err = gve_rx_alloc_ring_dqo(priv, cfg, &rx[i], i);
                if (err) {
                        netif_err(priv, drv, priv->dev,
                                  "Failed to alloc rx ring=%d: err=%d\n",
@@ -352,21 +382,30 @@ int gve_rx_alloc_rings_dqo(struct gve_priv *priv)
                }
        }
 
+       cfg->rx = rx;
        return 0;
 
 err:
        for (i--; i >= 0; i--)
-               gve_rx_free_ring_dqo(priv, i);
-
+               gve_rx_free_ring_dqo(priv, &rx[i], cfg);
+       kvfree(rx);
        return err;
 }
 
-void gve_rx_free_rings_dqo(struct gve_priv *priv)
+void gve_rx_free_rings_dqo(struct gve_priv *priv,
+                          struct gve_rx_alloc_rings_cfg *cfg)
 {
+       struct gve_rx_ring *rx = cfg->rx;
        int i;
 
-       for (i = 0; i < priv->rx_cfg.num_queues; i++)
-               gve_rx_free_ring_dqo(priv, i);
+       if (!rx)
+               return;
+
+       for (i = 0; i < cfg->qcfg->num_queues;  i++)
+               gve_rx_free_ring_dqo(priv, &rx[i], cfg);
+
+       kvfree(rx);
+       cfg->rx = NULL;
 }
 
 void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
index 07ba124780dfae7419af27c8b31807a8ded43fe2..4b9853adc1132e8e1242031f0fda306c85814dd3 100644 (file)
@@ -196,29 +196,36 @@ static int gve_clean_xdp_done(struct gve_priv *priv, struct gve_tx_ring *tx,
 static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx,
                             u32 to_do, bool try_to_wake);
 
-static void gve_tx_free_ring(struct gve_priv *priv, int idx)
+void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx)
 {
+       int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx);
        struct gve_tx_ring *tx = &priv->tx[idx];
+
+       if (!gve_tx_was_added_to_block(priv, idx))
+               return;
+
+       gve_remove_napi(priv, ntfy_idx);
+       gve_clean_tx_done(priv, tx, priv->tx_desc_cnt, false);
+       netdev_tx_reset_queue(tx->netdev_txq);
+       gve_tx_remove_from_block(priv, idx);
+}
+
+static void gve_tx_free_ring_gqi(struct gve_priv *priv, struct gve_tx_ring *tx,
+                                struct gve_tx_alloc_rings_cfg *cfg)
+{
        struct device *hdev = &priv->pdev->dev;
+       int idx = tx->q_num;
        size_t bytes;
        u32 slots;
 
-       gve_tx_remove_from_block(priv, idx);
        slots = tx->mask + 1;
-       if (tx->q_num < priv->tx_cfg.num_queues) {
-               gve_clean_tx_done(priv, tx, priv->tx_desc_cnt, false);
-               netdev_tx_reset_queue(tx->netdev_txq);
-       } else {
-               gve_clean_xdp_done(priv, tx, priv->tx_desc_cnt);
-       }
-
        dma_free_coherent(hdev, sizeof(*tx->q_resources),
                          tx->q_resources, tx->q_resources_bus);
        tx->q_resources = NULL;
 
        if (!tx->raw_addressing) {
                gve_tx_fifo_release(priv, &tx->tx_fifo);
-               gve_unassign_qpl(priv, tx->tx_fifo.qpl->id);
+               gve_unassign_qpl(cfg->qpl_cfg, tx->tx_fifo.qpl->id);
                tx->tx_fifo.qpl = NULL;
        }
 
@@ -232,11 +239,23 @@ static void gve_tx_free_ring(struct gve_priv *priv, int idx)
        netif_dbg(priv, drv, priv->dev, "freed tx queue %d\n", idx);
 }
 
-static int gve_tx_alloc_ring(struct gve_priv *priv, int idx)
+void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx)
 {
+       int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx);
        struct gve_tx_ring *tx = &priv->tx[idx];
+
+       gve_tx_add_to_block(priv, idx);
+
+       tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx);
+       gve_add_napi(priv, ntfy_idx, gve_napi_poll);
+}
+
+static int gve_tx_alloc_ring_gqi(struct gve_priv *priv,
+                                struct gve_tx_alloc_rings_cfg *cfg,
+                                struct gve_tx_ring *tx,
+                                int idx)
+{
        struct device *hdev = &priv->pdev->dev;
-       u32 slots = priv->tx_desc_cnt;
        size_t bytes;
 
        /* Make sure everything is zeroed to start */
@@ -245,23 +264,23 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx)
        spin_lock_init(&tx->xdp_lock);
        tx->q_num = idx;
 
-       tx->mask = slots - 1;
+       tx->mask = cfg->ring_size - 1;
 
        /* alloc metadata */
-       tx->info = vcalloc(slots, sizeof(*tx->info));
+       tx->info = vcalloc(cfg->ring_size, sizeof(*tx->info));
        if (!tx->info)
                return -ENOMEM;
 
        /* alloc tx queue */
-       bytes = sizeof(*tx->desc) * slots;
+       bytes = sizeof(*tx->desc) * cfg->ring_size;
        tx->desc = dma_alloc_coherent(hdev, bytes, &tx->bus, GFP_KERNEL);
        if (!tx->desc)
                goto abort_with_info;
 
-       tx->raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT;
-       tx->dev = &priv->pdev->dev;
+       tx->raw_addressing = cfg->raw_addressing;
+       tx->dev = hdev;
        if (!tx->raw_addressing) {
-               tx->tx_fifo.qpl = gve_assign_tx_qpl(priv, idx);
+               tx->tx_fifo.qpl = gve_assign_tx_qpl(cfg, idx);
                if (!tx->tx_fifo.qpl)
                        goto abort_with_desc;
                /* map Tx FIFO */
@@ -277,12 +296,6 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx)
        if (!tx->q_resources)
                goto abort_with_fifo;
 
-       netif_dbg(priv, drv, priv->dev, "tx[%d]->bus=%lx\n", idx,
-                 (unsigned long)tx->bus);
-       if (idx < priv->tx_cfg.num_queues)
-               tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx);
-       gve_tx_add_to_block(priv, idx);
-
        return 0;
 
 abort_with_fifo:
@@ -290,7 +303,7 @@ abort_with_fifo:
                gve_tx_fifo_release(priv, &tx->tx_fifo);
 abort_with_qpl:
        if (!tx->raw_addressing)
-               gve_unassign_qpl(priv, tx->tx_fifo.qpl->id);
+               gve_unassign_qpl(cfg->qpl_cfg, tx->tx_fifo.qpl->id);
 abort_with_desc:
        dma_free_coherent(hdev, bytes, tx->desc, tx->bus);
        tx->desc = NULL;
@@ -300,36 +313,73 @@ abort_with_info:
        return -ENOMEM;
 }
 
-int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings)
+int gve_tx_alloc_rings_gqi(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg)
 {
+       struct gve_tx_ring *tx = cfg->tx;
        int err = 0;
-       int i;
+       int i, j;
+
+       if (!cfg->raw_addressing && !cfg->qpls) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc QPL ring before allocing QPLs\n");
+               return -EINVAL;
+       }
+
+       if (cfg->start_idx + cfg->num_rings > cfg->qcfg->max_queues) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc more than the max num of Tx rings\n");
+               return -EINVAL;
+       }
+
+       if (cfg->start_idx == 0) {
+               tx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_tx_ring),
+                             GFP_KERNEL);
+               if (!tx)
+                       return -ENOMEM;
+       } else if (!tx) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc tx rings from a nonzero start idx without tx array\n");
+               return -EINVAL;
+       }
 
-       for (i = start_id; i < start_id + num_rings; i++) {
-               err = gve_tx_alloc_ring(priv, i);
+       for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) {
+               err = gve_tx_alloc_ring_gqi(priv, cfg, &tx[i], i);
                if (err) {
                        netif_err(priv, drv, priv->dev,
                                  "Failed to alloc tx ring=%d: err=%d\n",
                                  i, err);
-                       break;
+                       goto cleanup;
                }
        }
-       /* Unallocate if there was an error */
-       if (err) {
-               int j;
 
-               for (j = start_id; j < i; j++)
-                       gve_tx_free_ring(priv, j);
-       }
+       cfg->tx = tx;
+       return 0;
+
+cleanup:
+       for (j = 0; j < i; j++)
+               gve_tx_free_ring_gqi(priv, &tx[j], cfg);
+       if (cfg->start_idx == 0)
+               kvfree(tx);
        return err;
 }
 
-void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings)
+void gve_tx_free_rings_gqi(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg)
 {
+       struct gve_tx_ring *tx = cfg->tx;
        int i;
 
-       for (i = start_id; i < start_id + num_rings; i++)
-               gve_tx_free_ring(priv, i);
+       if (!tx)
+               return;
+
+       for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++)
+               gve_tx_free_ring_gqi(priv, &tx[i], cfg);
+
+       if (cfg->start_idx == 0) {
+               kvfree(tx);
+               cfg->tx = NULL;
+       }
 }
 
 /* gve_tx_avail - Calculates the number of slots available in the ring
index f59c4710f118822e30be39476f75b59595328ee0..bc34b6cd3a3e5c767f1abec52b46f9c72d7d457e 100644 (file)
@@ -188,13 +188,27 @@ static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx)
        }
 }
 
-static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx)
+void gve_tx_stop_ring_dqo(struct gve_priv *priv, int idx)
 {
+       int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx);
        struct gve_tx_ring *tx = &priv->tx[idx];
-       struct device *hdev = &priv->pdev->dev;
-       size_t bytes;
 
+       if (!gve_tx_was_added_to_block(priv, idx))
+               return;
+
+       gve_remove_napi(priv, ntfy_idx);
+       gve_clean_tx_done_dqo(priv, tx, /*napi=*/NULL);
+       netdev_tx_reset_queue(tx->netdev_txq);
+       gve_tx_clean_pending_packets(tx);
        gve_tx_remove_from_block(priv, idx);
+}
+
+static void gve_tx_free_ring_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
+                                struct gve_tx_alloc_rings_cfg *cfg)
+{
+       struct device *hdev = &priv->pdev->dev;
+       int idx = tx->q_num;
+       size_t bytes;
 
        if (tx->q_resources) {
                dma_free_coherent(hdev, sizeof(*tx->q_resources),
@@ -223,7 +237,7 @@ static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx)
        tx->dqo.tx_qpl_buf_next = NULL;
 
        if (tx->dqo.qpl) {
-               gve_unassign_qpl(priv, tx->dqo.qpl->id);
+               gve_unassign_qpl(cfg->qpl_cfg, tx->dqo.qpl->id);
                tx->dqo.qpl = NULL;
        }
 
@@ -253,9 +267,22 @@ static int gve_tx_qpl_buf_init(struct gve_tx_ring *tx)
        return 0;
 }
 
-static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
+void gve_tx_start_ring_dqo(struct gve_priv *priv, int idx)
 {
+       int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx);
        struct gve_tx_ring *tx = &priv->tx[idx];
+
+       gve_tx_add_to_block(priv, idx);
+
+       tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx);
+       gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo);
+}
+
+static int gve_tx_alloc_ring_dqo(struct gve_priv *priv,
+                                struct gve_tx_alloc_rings_cfg *cfg,
+                                struct gve_tx_ring *tx,
+                                int idx)
+{
        struct device *hdev = &priv->pdev->dev;
        int num_pending_packets;
        size_t bytes;
@@ -263,12 +290,11 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
 
        memset(tx, 0, sizeof(*tx));
        tx->q_num = idx;
-       tx->dev = &priv->pdev->dev;
-       tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx);
+       tx->dev = hdev;
        atomic_set_release(&tx->dqo_compl.hw_tx_head, 0);
 
        /* Queue sizes must be a power of 2 */
-       tx->mask = priv->tx_desc_cnt - 1;
+       tx->mask = cfg->ring_size - 1;
        tx->dqo.complq_mask = priv->queue_format == GVE_DQO_RDA_FORMAT ?
                priv->options_dqo_rda.tx_comp_ring_entries - 1 :
                tx->mask;
@@ -327,8 +353,8 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
        if (!tx->q_resources)
                goto err;
 
-       if (gve_is_qpl(priv)) {
-               tx->dqo.qpl = gve_assign_tx_qpl(priv, idx);
+       if (!cfg->raw_addressing) {
+               tx->dqo.qpl = gve_assign_tx_qpl(cfg, idx);
                if (!tx->dqo.qpl)
                        goto err;
 
@@ -336,22 +362,45 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
                        goto err;
        }
 
-       gve_tx_add_to_block(priv, idx);
-
        return 0;
 
 err:
-       gve_tx_free_ring_dqo(priv, idx);
+       gve_tx_free_ring_dqo(priv, tx, cfg);
        return -ENOMEM;
 }
 
-int gve_tx_alloc_rings_dqo(struct gve_priv *priv)
+int gve_tx_alloc_rings_dqo(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg)
 {
+       struct gve_tx_ring *tx = cfg->tx;
        int err = 0;
-       int i;
+       int i, j;
 
-       for (i = 0; i < priv->tx_cfg.num_queues; i++) {
-               err = gve_tx_alloc_ring_dqo(priv, i);
+       if (!cfg->raw_addressing && !cfg->qpls) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc QPL ring before allocing QPLs\n");
+               return -EINVAL;
+       }
+
+       if (cfg->start_idx + cfg->num_rings > cfg->qcfg->max_queues) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc more than the max num of Tx rings\n");
+               return -EINVAL;
+       }
+
+       if (cfg->start_idx == 0) {
+               tx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_tx_ring),
+                             GFP_KERNEL);
+               if (!tx)
+                       return -ENOMEM;
+       } else if (!tx) {
+               netif_err(priv, drv, priv->dev,
+                         "Cannot alloc tx rings from a nonzero start idx without tx array\n");
+               return -EINVAL;
+       }
+
+       for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) {
+               err = gve_tx_alloc_ring_dqo(priv, cfg, &tx[i], i);
                if (err) {
                        netif_err(priv, drv, priv->dev,
                                  "Failed to alloc tx ring=%d: err=%d\n",
@@ -360,27 +409,32 @@ int gve_tx_alloc_rings_dqo(struct gve_priv *priv)
                }
        }
 
+       cfg->tx = tx;
        return 0;
 
 err:
-       for (i--; i >= 0; i--)
-               gve_tx_free_ring_dqo(priv, i);
-
+       for (j = 0; j < i; j++)
+               gve_tx_free_ring_dqo(priv, &tx[j], cfg);
+       if (cfg->start_idx == 0)
+               kvfree(tx);
        return err;
 }
 
-void gve_tx_free_rings_dqo(struct gve_priv *priv)
+void gve_tx_free_rings_dqo(struct gve_priv *priv,
+                          struct gve_tx_alloc_rings_cfg *cfg)
 {
+       struct gve_tx_ring *tx = cfg->tx;
        int i;
 
-       for (i = 0; i < priv->tx_cfg.num_queues; i++) {
-               struct gve_tx_ring *tx = &priv->tx[i];
+       if (!tx)
+               return;
 
-               gve_clean_tx_done_dqo(priv, tx, /*napi=*/NULL);
-               netdev_tx_reset_queue(tx->netdev_txq);
-               gve_tx_clean_pending_packets(tx);
+       for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++)
+               gve_tx_free_ring_dqo(priv, &tx[i], cfg);
 
-               gve_tx_free_ring_dqo(priv, i);
+       if (cfg->start_idx == 0) {
+               kvfree(tx);
+               cfg->tx = NULL;
        }
 }
 
index 26e08d7532702afcf21f3cdea7174a3d77be287c..535b1796b91d654fe5e60aae37e11b9ea9df9744 100644 (file)
@@ -8,6 +8,14 @@
 #include "gve_adminq.h"
 #include "gve_utils.h"
 
+bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx)
+{
+       struct gve_notify_block *block =
+                       &priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
+
+       return block->tx != NULL;
+}
+
 void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx)
 {
        struct gve_notify_block *block =
@@ -30,6 +38,14 @@ void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx)
                            queue_idx);
 }
 
+bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx)
+{
+       struct gve_notify_block *block =
+                       &priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
+
+       return block->rx != NULL;
+}
+
 void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
 {
        struct gve_notify_block *block =
@@ -81,3 +97,18 @@ void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info)
                page_ref_add(page_info->page, INT_MAX - pagecount);
        }
 }
+
+void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
+                 int (*gve_poll)(struct napi_struct *, int))
+{
+       struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+       netif_napi_add(priv->dev, &block->napi, gve_poll);
+}
+
+void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
+{
+       struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+       netif_napi_del(&block->napi);
+}
index 324fd98a611242f367c866299345ae666f67982f..277921a629f7bc41f8fed373838657c49e0ab58f 100644 (file)
 
 #include "gve.h"
 
+bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx);
 void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx);
 void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx);
 
+bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx);
 void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx);
 void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx);
 
@@ -23,5 +25,8 @@ struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
 /* Decrement pagecnt_bias. Set it back to INT_MAX if it reached zero. */
 void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info);
 
+void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
+                 int (*gve_poll)(struct napi_struct *, int));
+void gve_remove_napi(struct gve_priv *priv, int ntfy_idx);
 #endif /* _GVE_UTILS_H */
 
index 84abb30a3fbb13a61ed786bf32e0f72c0bbfbdd2..a9033696b0aad36ab9abd47e4b68e272053019d7 100644 (file)
@@ -8,6 +8,7 @@
 struct inet_hashinfo;
 
 struct inet_diag_handler {
+       struct module   *owner;
        void            (*dump)(struct sk_buff *skb,
                                struct netlink_callback *cb,
                                const struct inet_diag_req_v2 *r);
index 0b9ecd8cf9793bc26138a0a36474e78773fb4f31..110978dc9af1b19194644151af5456b8c6644cf9 100644 (file)
@@ -13,6 +13,7 @@ struct nlmsghdr;
 struct sock;
 
 struct sock_diag_handler {
+       struct module *owner;
        __u8 family;
        int (*dump)(struct sk_buff *skb, struct nlmsghdr *nlh);
        int (*get_info)(struct sk_buff *skb, struct sock *sk);
@@ -22,8 +23,13 @@ struct sock_diag_handler {
 int sock_diag_register(const struct sock_diag_handler *h);
 void sock_diag_unregister(const struct sock_diag_handler *h);
 
-void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh));
-void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh));
+struct sock_diag_inet_compat {
+       struct module *owner;
+       int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh);
+};
+
+void sock_diag_register_inet_compat(const struct sock_diag_inet_compat *ptr);
+void sock_diag_unregister_inet_compat(const struct sock_diag_inet_compat *ptr);
 
 u64 __sock_gen_cookie(struct sock *sk);
 
index 9ba6413fd2e3ea166a516181115a1658c6d5ad03..360b12e61850735f1b2e5bbf7302320298b712b1 100644 (file)
 
 #define RT6_DEBUG 2
 
-#if RT6_DEBUG >= 3
-#define RT6_TRACE(x...) pr_debug(x)
-#else
-#define RT6_TRACE(x...) do { ; } while (0)
-#endif
-
 struct rt6_info;
 struct fib6_info;
 
index b1e29e18d1d60cb5c87c884652f547c083ba81cd..6541228380252d597821b084df34176bff4ada83 100644 (file)
 #include <linux/inet_diag.h>
 #include <linux/sock_diag.h>
 
-static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
-static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
-static DEFINE_MUTEX(sock_diag_table_mutex);
+static const struct sock_diag_handler __rcu *sock_diag_handlers[AF_MAX];
+
+static struct sock_diag_inet_compat __rcu *inet_rcv_compat;
+
 static struct workqueue_struct *broadcast_wq;
 
 DEFINE_COOKIE(sock_cookie);
@@ -122,6 +123,24 @@ static size_t sock_diag_nlmsg_size(void)
               + nla_total_size_64bit(sizeof(struct tcp_info))); /* INET_DIAG_INFO */
 }
 
+static const struct sock_diag_handler *sock_diag_lock_handler(int family)
+{
+       const struct sock_diag_handler *handler;
+
+       rcu_read_lock();
+       handler = rcu_dereference(sock_diag_handlers[family]);
+       if (handler && !try_module_get(handler->owner))
+               handler = NULL;
+       rcu_read_unlock();
+
+       return handler;
+}
+
+static void sock_diag_unlock_handler(const struct sock_diag_handler *handler)
+{
+       module_put(handler->owner);
+}
+
 static void sock_diag_broadcast_destroy_work(struct work_struct *work)
 {
        struct broadcast_sk *bsk =
@@ -138,12 +157,12 @@ static void sock_diag_broadcast_destroy_work(struct work_struct *work)
        if (!skb)
                goto out;
 
-       mutex_lock(&sock_diag_table_mutex);
-       hndl = sock_diag_handlers[sk->sk_family];
-       if (hndl && hndl->get_info)
-               err = hndl->get_info(skb, sk);
-       mutex_unlock(&sock_diag_table_mutex);
-
+       hndl = sock_diag_lock_handler(sk->sk_family);
+       if (hndl) {
+               if (hndl->get_info)
+                       err = hndl->get_info(skb, sk);
+               sock_diag_unlock_handler(hndl);
+       }
        if (!err)
                nlmsg_multicast(sock_net(sk)->diag_nlsk, skb, 0, group,
                                GFP_KERNEL);
@@ -166,51 +185,45 @@ void sock_diag_broadcast_destroy(struct sock *sk)
        queue_work(broadcast_wq, &bsk->work);
 }
 
-void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
+void sock_diag_register_inet_compat(const struct sock_diag_inet_compat *ptr)
 {
-       mutex_lock(&sock_diag_table_mutex);
-       inet_rcv_compat = fn;
-       mutex_unlock(&sock_diag_table_mutex);
+       xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat,
+            ptr);
 }
 EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat);
 
-void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
+void sock_diag_unregister_inet_compat(const struct sock_diag_inet_compat *ptr)
 {
-       mutex_lock(&sock_diag_table_mutex);
-       inet_rcv_compat = NULL;
-       mutex_unlock(&sock_diag_table_mutex);
+       const struct sock_diag_inet_compat *old;
+
+       old = xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat,
+                  NULL);
+       WARN_ON_ONCE(old != ptr);
 }
 EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat);
 
 int sock_diag_register(const struct sock_diag_handler *hndl)
 {
-       int err = 0;
+       int family = hndl->family;
 
-       if (hndl->family >= AF_MAX)
+       if (family >= AF_MAX)
                return -EINVAL;
 
-       mutex_lock(&sock_diag_table_mutex);
-       if (sock_diag_handlers[hndl->family])
-               err = -EBUSY;
-       else
-               sock_diag_handlers[hndl->family] = hndl;
-       mutex_unlock(&sock_diag_table_mutex);
-
-       return err;
+       return !cmpxchg((const struct sock_diag_handler **)
+                               &sock_diag_handlers[family],
+                       NULL, hndl) ? 0 : -EBUSY;
 }
 EXPORT_SYMBOL_GPL(sock_diag_register);
 
-void sock_diag_unregister(const struct sock_diag_handler *hnld)
+void sock_diag_unregister(const struct sock_diag_handler *hndl)
 {
-       int family = hnld->family;
+       int family = hndl->family;
 
        if (family >= AF_MAX)
                return;
 
-       mutex_lock(&sock_diag_table_mutex);
-       BUG_ON(sock_diag_handlers[family] != hnld);
-       sock_diag_handlers[family] = NULL;
-       mutex_unlock(&sock_diag_table_mutex);
+       xchg((const struct sock_diag_handler **)&sock_diag_handlers[family],
+            NULL);
 }
 EXPORT_SYMBOL_GPL(sock_diag_unregister);
 
@@ -227,20 +240,20 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh)
                return -EINVAL;
        req->sdiag_family = array_index_nospec(req->sdiag_family, AF_MAX);
 
-       if (sock_diag_handlers[req->sdiag_family] == NULL)
+       if (!rcu_access_pointer(sock_diag_handlers[req->sdiag_family]))
                sock_load_diag_module(req->sdiag_family, 0);
 
-       mutex_lock(&sock_diag_table_mutex);
-       hndl = sock_diag_handlers[req->sdiag_family];
+       hndl = sock_diag_lock_handler(req->sdiag_family);
        if (hndl == NULL)
-               err = -ENOENT;
-       else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY)
+               return -ENOENT;
+
+       if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY)
                err = hndl->dump(skb, nlh);
        else if (nlh->nlmsg_type == SOCK_DESTROY && hndl->destroy)
                err = hndl->destroy(skb, nlh);
        else
                err = -EOPNOTSUPP;
-       mutex_unlock(&sock_diag_table_mutex);
+       sock_diag_unlock_handler(hndl);
 
        return err;
 }
@@ -248,20 +261,27 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh)
 static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
                             struct netlink_ext_ack *extack)
 {
+       const struct sock_diag_inet_compat *ptr;
        int ret;
 
        switch (nlh->nlmsg_type) {
        case TCPDIAG_GETSOCK:
        case DCCPDIAG_GETSOCK:
-               if (inet_rcv_compat == NULL)
+
+               if (!rcu_access_pointer(inet_rcv_compat))
                        sock_load_diag_module(AF_INET, 0);
 
-               mutex_lock(&sock_diag_table_mutex);
-               if (inet_rcv_compat != NULL)
-                       ret = inet_rcv_compat(skb, nlh);
-               else
-                       ret = -EOPNOTSUPP;
-               mutex_unlock(&sock_diag_table_mutex);
+               rcu_read_lock();
+               ptr = rcu_dereference(inet_rcv_compat);
+               if (ptr && !try_module_get(ptr->owner))
+                       ptr = NULL;
+               rcu_read_unlock();
+
+               ret = -EOPNOTSUPP;
+               if (ptr) {
+                       ret = ptr->fn(skb, nlh);
+                       module_put(ptr->owner);
+               }
 
                return ret;
        case SOCK_DIAG_BY_FAMILY:
@@ -272,13 +292,9 @@ static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
        }
 }
 
-static DEFINE_MUTEX(sock_diag_mutex);
-
 static void sock_diag_rcv(struct sk_buff *skb)
 {
-       mutex_lock(&sock_diag_mutex);
        netlink_rcv_skb(skb, &sock_diag_rcv_msg);
-       mutex_unlock(&sock_diag_mutex);
 }
 
 static int sock_diag_bind(struct net *net, int group)
@@ -286,12 +302,12 @@ static int sock_diag_bind(struct net *net, int group)
        switch (group) {
        case SKNLGRP_INET_TCP_DESTROY:
        case SKNLGRP_INET_UDP_DESTROY:
-               if (!sock_diag_handlers[AF_INET])
+               if (!rcu_access_pointer(sock_diag_handlers[AF_INET]))
                        sock_load_diag_module(AF_INET, 0);
                break;
        case SKNLGRP_INET6_TCP_DESTROY:
        case SKNLGRP_INET6_UDP_DESTROY:
-               if (!sock_diag_handlers[AF_INET6])
+               if (!rcu_access_pointer(sock_diag_handlers[AF_INET6]))
                        sock_load_diag_module(AF_INET6, 0);
                break;
        }
index 8a82c5a2c5a8c9ed8885b53744ff13c2bee657d8..f5019d95c3ae535555cc2b4d4885c718227fec67 100644 (file)
@@ -58,6 +58,7 @@ static int dccp_diag_dump_one(struct netlink_callback *cb,
 }
 
 static const struct inet_diag_handler dccp_diag_handler = {
+       .owner           = THIS_MODULE,
        .dump            = dccp_diag_dump,
        .dump_one        = dccp_diag_dump_one,
        .idiag_get_info  = dccp_diag_get_info,
index 8e6b6aa0579e1c94def819a1f9eab8b946771ba7..7adace541fe292851a66ccc4de1da2a60ac4714e 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/inet_diag.h>
 #include <linux/sock_diag.h>
 
-static const struct inet_diag_handler **inet_diag_table;
+static const struct inet_diag_handler __rcu **inet_diag_table;
 
 struct inet_diag_entry {
        const __be32 *saddr;
@@ -48,28 +48,28 @@ struct inet_diag_entry {
 #endif
 };
 
-static DEFINE_MUTEX(inet_diag_table_mutex);
-
 static const struct inet_diag_handler *inet_diag_lock_handler(int proto)
 {
-       if (proto < 0 || proto >= IPPROTO_MAX) {
-               mutex_lock(&inet_diag_table_mutex);
-               return ERR_PTR(-ENOENT);
-       }
+       const struct inet_diag_handler *handler;
 
-       if (!inet_diag_table[proto])
+       if (proto < 0 || proto >= IPPROTO_MAX)
+               return NULL;
+
+       if (!READ_ONCE(inet_diag_table[proto]))
                sock_load_diag_module(AF_INET, proto);
 
-       mutex_lock(&inet_diag_table_mutex);
-       if (!inet_diag_table[proto])
-               return ERR_PTR(-ENOENT);
+       rcu_read_lock();
+       handler = rcu_dereference(inet_diag_table[proto]);
+       if (handler && !try_module_get(handler->owner))
+               handler = NULL;
+       rcu_read_unlock();
 
-       return inet_diag_table[proto];
+       return handler;
 }
 
 static void inet_diag_unlock_handler(const struct inet_diag_handler *handler)
 {
-       mutex_unlock(&inet_diag_table_mutex);
+       module_put(handler->owner);
 }
 
 void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk)
@@ -104,9 +104,12 @@ static size_t inet_sk_attr_size(struct sock *sk,
        const struct inet_diag_handler *handler;
        size_t aux = 0;
 
-       handler = inet_diag_table[req->sdiag_protocol];
+       rcu_read_lock();
+       handler = rcu_dereference(inet_diag_table[req->sdiag_protocol]);
+       DEBUG_NET_WARN_ON_ONCE(!handler);
        if (handler && handler->idiag_get_aux_size)
                aux = handler->idiag_get_aux_size(sk, net_admin);
+       rcu_read_unlock();
 
        return    nla_total_size(sizeof(struct tcp_info))
                + nla_total_size(sizeof(struct inet_diag_msg))
@@ -244,10 +247,16 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
        struct nlmsghdr  *nlh;
        struct nlattr *attr;
        void *info = NULL;
+       int protocol;
 
        cb_data = cb->data;
-       handler = inet_diag_table[inet_diag_get_protocol(req, cb_data)];
-       BUG_ON(!handler);
+       protocol = inet_diag_get_protocol(req, cb_data);
+
+       /* inet_diag_lock_handler() made sure inet_diag_table[] is stable. */
+       handler = rcu_dereference_protected(inet_diag_table[protocol], 1);
+       DEBUG_NET_WARN_ON_ONCE(!handler);
+       if (!handler)
+               return -ENXIO;
 
        nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
                        cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags);
@@ -605,9 +614,10 @@ static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb,
        protocol = inet_diag_get_protocol(req, &dump_data);
 
        handler = inet_diag_lock_handler(protocol);
-       if (IS_ERR(handler)) {
-               err = PTR_ERR(handler);
-       } else if (cmd == SOCK_DIAG_BY_FAMILY) {
+       if (!handler)
+               return -ENOENT;
+
+       if (cmd == SOCK_DIAG_BY_FAMILY) {
                struct netlink_callback cb = {
                        .nlh = nlh,
                        .skb = in_skb,
@@ -1035,6 +1045,10 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
                        num = 0;
                        ilb = &hashinfo->lhash2[i];
 
+                       if (hlist_nulls_empty(&ilb->nulls_head)) {
+                               s_num = 0;
+                               continue;
+                       }
                        spin_lock(&ilb->lock);
                        sk_nulls_for_each(sk, node, &ilb->nulls_head) {
                                struct inet_sock *inet = inet_sk(sk);
@@ -1099,6 +1113,10 @@ resume_bind_walk:
                        accum = 0;
                        ibb = &hashinfo->bhash2[i];
 
+                       if (hlist_empty(&ibb->chain)) {
+                               s_num = 0;
+                               continue;
+                       }
                        spin_lock_bh(&ibb->lock);
                        inet_bind_bucket_for_each(tb2, &ibb->chain) {
                                if (!net_eq(ib2_net(tb2), net))
@@ -1259,12 +1277,12 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 again:
        prev_min_dump_alloc = cb->min_dump_alloc;
        handler = inet_diag_lock_handler(protocol);
-       if (!IS_ERR(handler))
+       if (handler) {
                handler->dump(skb, cb, r);
-       else
-               err = PTR_ERR(handler);
-       inet_diag_unlock_handler(handler);
-
+               inet_diag_unlock_handler(handler);
+       } else {
+               err = -ENOENT;
+       }
        /* The skb is not large enough to fit one sk info and
         * inet_sk_diag_fill() has requested for a larger skb.
         */
@@ -1457,10 +1475,9 @@ int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk)
        }
 
        handler = inet_diag_lock_handler(sk->sk_protocol);
-       if (IS_ERR(handler)) {
-               inet_diag_unlock_handler(handler);
+       if (!handler) {
                nlmsg_cancel(skb, nlh);
-               return PTR_ERR(handler);
+               return -ENOENT;
        }
 
        attr = handler->idiag_info_size
@@ -1479,6 +1496,7 @@ int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk)
 }
 
 static const struct sock_diag_handler inet_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_INET,
        .dump = inet_diag_handler_cmd,
        .get_info = inet_diag_handler_get_info,
@@ -1486,6 +1504,7 @@ static const struct sock_diag_handler inet_diag_handler = {
 };
 
 static const struct sock_diag_handler inet6_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_INET6,
        .dump = inet_diag_handler_cmd,
        .get_info = inet_diag_handler_get_info,
@@ -1495,20 +1514,12 @@ static const struct sock_diag_handler inet6_diag_handler = {
 int inet_diag_register(const struct inet_diag_handler *h)
 {
        const __u16 type = h->idiag_type;
-       int err = -EINVAL;
 
        if (type >= IPPROTO_MAX)
-               goto out;
+               return -EINVAL;
 
-       mutex_lock(&inet_diag_table_mutex);
-       err = -EEXIST;
-       if (!inet_diag_table[type]) {
-               inet_diag_table[type] = h;
-               err = 0;
-       }
-       mutex_unlock(&inet_diag_table_mutex);
-out:
-       return err;
+       return !cmpxchg((const struct inet_diag_handler **)&inet_diag_table[type],
+                       NULL, h) ? 0 : -EEXIST;
 }
 EXPORT_SYMBOL_GPL(inet_diag_register);
 
@@ -1519,12 +1530,16 @@ void inet_diag_unregister(const struct inet_diag_handler *h)
        if (type >= IPPROTO_MAX)
                return;
 
-       mutex_lock(&inet_diag_table_mutex);
-       inet_diag_table[type] = NULL;
-       mutex_unlock(&inet_diag_table_mutex);
+       xchg((const struct inet_diag_handler **)&inet_diag_table[type],
+            NULL);
 }
 EXPORT_SYMBOL_GPL(inet_diag_unregister);
 
+static const struct sock_diag_inet_compat inet_diag_compat = {
+       .owner  = THIS_MODULE,
+       .fn     = inet_diag_rcv_msg_compat,
+};
+
 static int __init inet_diag_init(void)
 {
        const int inet_diag_table_size = (IPPROTO_MAX *
@@ -1543,7 +1558,7 @@ static int __init inet_diag_init(void)
        if (err)
                goto out_free_inet;
 
-       sock_diag_register_inet_compat(inet_diag_rcv_msg_compat);
+       sock_diag_register_inet_compat(&inet_diag_compat);
 out:
        return err;
 
@@ -1558,7 +1573,7 @@ static void __exit inet_diag_exit(void)
 {
        sock_diag_unregister(&inet6_diag_handler);
        sock_diag_unregister(&inet_diag_handler);
-       sock_diag_unregister_inet_compat(inet_diag_rcv_msg_compat);
+       sock_diag_unregister_inet_compat(&inet_diag_compat);
        kfree(inet_diag_table);
 }
 
index fe2140c8375c8ebcc69880142c42655233007900..cc793bd8de258c3a12f11e95cec81c5ae4b9a7f6 100644 (file)
@@ -213,6 +213,7 @@ static int raw_diag_destroy(struct sk_buff *in_skb,
 #endif
 
 static const struct inet_diag_handler raw_diag_handler = {
+       .owner                  = THIS_MODULE,
        .dump                   = raw_diag_dump,
        .dump_one               = raw_diag_dump_one,
        .idiag_get_info         = raw_diag_get_info,
index 4cbe4b44425a6a5daf55abe348c167932ca07222..f428ecf9120f2f596e1d67db2b2a0d0d0e211905 100644 (file)
@@ -222,6 +222,7 @@ static int tcp_diag_destroy(struct sk_buff *in_skb,
 #endif
 
 static const struct inet_diag_handler tcp_diag_handler = {
+       .owner                  = THIS_MODULE,
        .dump                   = tcp_diag_dump,
        .dump_one               = tcp_diag_dump_one,
        .idiag_get_info         = tcp_diag_get_info,
index dc41a22ee80e829582349e8e644f204eff07df0e..38cb3a28e4ed6d54f7078afa2700e71db9ce4b85 100644 (file)
@@ -237,6 +237,7 @@ static int udplite_diag_destroy(struct sk_buff *in_skb,
 #endif
 
 static const struct inet_diag_handler udp_diag_handler = {
+       .owner           = THIS_MODULE,
        .dump            = udp_diag_dump,
        .dump_one        = udp_diag_dump_one,
        .idiag_get_info  = udp_diag_get_info,
@@ -260,6 +261,7 @@ static int udplite_diag_dump_one(struct netlink_callback *cb,
 }
 
 static const struct inet_diag_handler udplite_diag_handler = {
+       .owner           = THIS_MODULE,
        .dump            = udplite_diag_dump,
        .dump_one        = udplite_diag_dump_one,
        .idiag_get_info  = udp_diag_get_info,
index 4fc2cae0d116c55fa1aa6f9f49b83160950a0e42..38a0348b1d17803772264389865b503b929e8c95 100644 (file)
@@ -751,8 +751,6 @@ static struct fib6_node *fib6_add_1(struct net *net,
        int     bit;
        __be32  dir = 0;
 
-       RT6_TRACE("fib6_add_1\n");
-
        /* insert node in tree */
 
        fn = root;
@@ -1803,7 +1801,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                                            lockdep_is_held(&table->tb6_lock));
                struct fib6_info *new_fn_leaf;
 
-               RT6_TRACE("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter);
+               pr_debug("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter);
                iter++;
 
                WARN_ON(fn->fn_flags & RTN_RTINFO);
@@ -1866,7 +1864,8 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                FOR_WALKERS(net, w) {
                        if (!child) {
                                if (w->node == fn) {
-                                       RT6_TRACE("W %p adjusted by delnode 1, s=%d/%d\n", w, w->state, nstate);
+                                       pr_debug("W %p adjusted by delnode 1, s=%d/%d\n",
+                                                w, w->state, nstate);
                                        w->node = pn;
                                        w->state = nstate;
                                }
@@ -1874,10 +1873,12 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                                if (w->node == fn) {
                                        w->node = child;
                                        if (children&2) {
-                                               RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
+                                               pr_debug("W %p adjusted by delnode 2, s=%d\n",
+                                                        w, w->state);
                                                w->state = w->state >= FWS_R ? FWS_U : FWS_INIT;
                                        } else {
-                                               RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
+                                               pr_debug("W %p adjusted by delnode 2, s=%d\n",
+                                                        w, w->state);
                                                w->state = w->state >= FWS_C ? FWS_U : FWS_INIT;
                                        }
                                }
@@ -1905,8 +1906,6 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
        struct net *net = info->nl_net;
        bool notify_del = false;
 
-       RT6_TRACE("fib6_del_route\n");
-
        /* If the deleted route is the first in the node and it is not part of
         * a multipath route, then we need to replace it with the next route
         * in the node, if exists.
@@ -1955,7 +1954,7 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
        read_lock(&net->ipv6.fib6_walker_lock);
        FOR_WALKERS(net, w) {
                if (w->state == FWS_C && w->leaf == rt) {
-                       RT6_TRACE("walker %p adjusted by delroute\n", w);
+                       pr_debug("walker %p adjusted by delroute\n", w);
                        w->leaf = rcu_dereference_protected(rt->fib6_next,
                                            lockdep_is_held(&table->tb6_lock));
                        if (!w->leaf)
@@ -2293,7 +2292,7 @@ static int fib6_age(struct fib6_info *rt, void *arg)
 
        if (rt->fib6_flags & RTF_EXPIRES && rt->expires) {
                if (time_after(now, rt->expires)) {
-                       RT6_TRACE("expiring %p\n", rt);
+                       pr_debug("expiring %p\n", rt);
                        return -1;
                }
                gc_args->more++;
index ea1dec8448fce8ccf29be650301e937cfce6bd7a..63b4c60565820c712a9f1b1f43c14785e932f803 100644 (file)
@@ -2085,12 +2085,12 @@ static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
         */
        if (!(rt->rt6i_flags & RTF_EXPIRES)) {
                if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
-                       RT6_TRACE("aging clone %p\n", rt);
+                       pr_debug("aging clone %p\n", rt);
                        rt6_remove_exception(bucket, rt6_ex);
                        return;
                }
        } else if (time_after(jiffies, rt->dst.expires)) {
-               RT6_TRACE("purging expired route %p\n", rt);
+               pr_debug("purging expired route %p\n", rt);
                rt6_remove_exception(bucket, rt6_ex);
                return;
        }
@@ -2101,8 +2101,8 @@ static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
                neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
 
                if (!(neigh && (neigh->flags & NTF_ROUTER))) {
-                       RT6_TRACE("purging route %p via non-router but gateway\n",
-                                 rt);
+                       pr_debug("purging route %p via non-router but gateway\n",
+                                rt);
                        rt6_remove_exception(bucket, rt6_ex);
                        return;
                }
index 5409c2ea3f5728a05999db17b7af1b1fb56f757e..bd8ff5950c8d33766a0da971dc127f106feb8481 100644 (file)
@@ -225,6 +225,7 @@ static void mptcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 }
 
 static const struct inet_diag_handler mptcp_diag_handler = {
+       .owner           = THIS_MODULE,
        .dump            = mptcp_diag_dump,
        .dump_one        = mptcp_diag_dump_one,
        .idiag_get_info  = mptcp_diag_get_info,
index 1eeff9422856eb9006e25b21ef188280b4cff7f6..e12c90d5f6ad29446ea1990c88c19bcb0ee856c3 100644 (file)
@@ -241,6 +241,7 @@ static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 }
 
 static const struct sock_diag_handler netlink_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_NETLINK,
        .dump = netlink_diag_handler_dump,
 };
index 9a7980e3309d6a2950688f8b69b08c15c288f601..b3bd2f6c2bf7be7b1436aa1a7fad6ef3f77217ad 100644 (file)
@@ -245,6 +245,7 @@ static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 }
 
 static const struct sock_diag_handler packet_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_PACKET,
        .dump = packet_diag_handler_dump,
 };
index eb05131ff1dd671e734457e28b2d7b64eab07f85..23359e522273f0377080007c75eb2c276945f781 100644 (file)
@@ -507,6 +507,7 @@ done:
 }
 
 static const struct inet_diag_handler sctp_diag_handler = {
+       .owner           = THIS_MODULE,
        .dump            = sctp_diag_dump,
        .dump_one        = sctp_diag_dump_one,
        .idiag_get_info  = sctp_diag_get_info,
index 5a33908015f3e3197ad11869c6f5134799307c56..6fdb2d96777ad704c394709ec845f9ddef5e599a 100644 (file)
@@ -255,6 +255,7 @@ static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 }
 
 static const struct sock_diag_handler smc_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_SMC,
        .dump = smc_diag_handler_dump,
 };
index 18733451c9e0c23a63d9400d408979aab46ecf19..54dde8c4e4d46d8556b9cc5396c863d24306d547 100644 (file)
@@ -95,6 +95,7 @@ static int tipc_sock_diag_handler_dump(struct sk_buff *skb,
 }
 
 static const struct sock_diag_handler tipc_sock_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_TIPC,
        .dump = tipc_sock_diag_handler_dump,
 };
index 3105abe97bb9cc64f6f10e9ae3cb670fc0fbcb6e..c1e890a824347833b1d1450ec7948bcafba2bab7 100644 (file)
@@ -86,8 +86,6 @@ struct tipc_bclink_entry {
  * @lock: rwlock governing access to structure
  * @net: the applicable net namespace
  * @hash: links to adjacent nodes in unsorted hash chain
- * @inputq: pointer to input queue containing messages for msg event
- * @namedq: pointer to name table input queue with name table messages
  * @active_links: bearer ids of active links, used as index into links[] array
  * @links: array containing references to all links to node
  * @bc_entry: broadcast link entry
index bb1118d02f9532f2f7f32e3de8c1275ad935ca49..7e4135db58163501e9ad011fa6c78975fbe53e75 100644 (file)
@@ -80,7 +80,6 @@ struct sockaddr_pair {
  * @phdr: preformatted message header used when sending messages
  * @cong_links: list of congested links
  * @publications: list of publications for port
- * @blocking_link: address of the congested link we are currently sleeping on
  * @pub_count: total # of publications port has made during its lifetime
  * @conn_timeout: the time we can wait for an unresponded setup request
  * @probe_unacked: probe has not received ack yet
index bec09a3a1d44ce56d43e16583fdf3b417cce4033..c3648b706509653480b71ea26ec4f8462f1a3c42 100644 (file)
@@ -322,6 +322,7 @@ static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 }
 
 static const struct sock_diag_handler unix_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_UNIX,
        .dump = unix_diag_handler_dump,
 };
index 2e29994f92ffa2facee45cd53ec791034182508c..ab87ef66c1e88765911a3b6ff89b7fc720b6d692 100644 (file)
@@ -157,6 +157,7 @@ static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 }
 
 static const struct sock_diag_handler vsock_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_VSOCK,
        .dump = vsock_diag_handler_dump,
 };
index 9f8955367275e2439d910f978fc3b2b7a1669978..09dcea0cbbed97d9a41e88224994279cfbf8c536 100644 (file)
@@ -194,6 +194,7 @@ static int xsk_diag_handler_dump(struct sk_buff *nlskb, struct nlmsghdr *hdr)
 }
 
 static const struct sock_diag_handler xsk_diag_handler = {
+       .owner = THIS_MODULE,
        .family = AF_XDP,
        .dump = xsk_diag_handler_dump,
 };
index ae2b33c21c452a7305bf4239aee33036327f8e8c..554b290fefdc244fb1ec5ec6cf7910eaf5f92aa6 100644 (file)
@@ -33,8 +33,7 @@ void init_signals(void)
        signal(SIGPIPE, SIG_IGN);
 }
 
-/* Parse a CID in string representation */
-unsigned int parse_cid(const char *str)
+static unsigned int parse_uint(const char *str, const char *err_str)
 {
        char *endptr = NULL;
        unsigned long n;
@@ -42,12 +41,24 @@ unsigned int parse_cid(const char *str)
        errno = 0;
        n = strtoul(str, &endptr, 10);
        if (errno || *endptr != '\0') {
-               fprintf(stderr, "malformed CID \"%s\"\n", str);
+               fprintf(stderr, "malformed %s \"%s\"\n", err_str, str);
                exit(EXIT_FAILURE);
        }
        return n;
 }
 
+/* Parse a CID in string representation */
+unsigned int parse_cid(const char *str)
+{
+       return parse_uint(str, "CID");
+}
+
+/* Parse a port in string representation */
+unsigned int parse_port(const char *str)
+{
+       return parse_uint(str, "port");
+}
+
 /* Wait for the remote to close the connection */
 void vsock_wait_remote_close(int fd)
 {
index 03c88d0cb8610b5d106379fe36a61c8734cd4f5f..e95e62485959eb4c6e2e268125adba9a082dabb8 100644 (file)
@@ -12,10 +12,13 @@ enum test_mode {
        TEST_MODE_SERVER
 };
 
+#define DEFAULT_PEER_PORT      1234
+
 /* Test runner options */
 struct test_opts {
        enum test_mode mode;
        unsigned int peer_cid;
+       unsigned int peer_port;
 };
 
 /* A test case definition.  Test functions must print failures to stderr and
@@ -35,6 +38,7 @@ struct test_case {
 
 void init_signals(void);
 unsigned int parse_cid(const char *str);
+unsigned int parse_port(const char *str);
 int vsock_stream_connect(unsigned int cid, unsigned int port);
 int vsock_bind_connect(unsigned int cid, unsigned int port,
                       unsigned int bind_port, int type);
index fa927ad16f8a227bf5677e16145f58598208e643..9d61b1f1c4c33427a7f7ad1c59f5e949361db25d 100644 (file)
@@ -342,7 +342,7 @@ static void test_listen_socket_server(const struct test_opts *opts)
        } addr = {
                .svm = {
                        .svm_family = AF_VSOCK,
-                       .svm_port = 1234,
+                       .svm_port = opts->peer_port,
                        .svm_cid = VMADDR_CID_ANY,
                },
        };
@@ -378,7 +378,7 @@ static void test_connect_client(const struct test_opts *opts)
        LIST_HEAD(sockets);
        struct vsock_stat *st;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -403,7 +403,7 @@ static void test_connect_server(const struct test_opts *opts)
        LIST_HEAD(sockets);
        int client_fd;
 
-       client_fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       client_fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (client_fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -461,6 +461,11 @@ static const struct option longopts[] = {
                .has_arg = required_argument,
                .val = 'p',
        },
+       {
+               .name = "peer-port",
+               .has_arg = required_argument,
+               .val = 'q',
+       },
        {
                .name = "list",
                .has_arg = no_argument,
@@ -481,7 +486,7 @@ static const struct option longopts[] = {
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
+       fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--peer-port=<port>] [--list] [--skip=<test_id>]\n"
                "\n"
                "  Server: vsock_diag_test --control-port=1234 --mode=server --peer-cid=3\n"
                "  Client: vsock_diag_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
@@ -503,9 +508,11 @@ static void usage(void)
                "  --control-port <port>  Server port to listen on/connect to\n"
                "  --mode client|server   Server or client mode\n"
                "  --peer-cid <cid>       CID of the other side\n"
+               "  --peer-port <port>     AF_VSOCK port used for the test [default: %d]\n"
                "  --list                 List of tests that will be executed\n"
                "  --skip <test_id>       Test ID to skip;\n"
-               "                         use multiple --skip options to skip more tests\n"
+               "                         use multiple --skip options to skip more tests\n",
+               DEFAULT_PEER_PORT
                );
        exit(EXIT_FAILURE);
 }
@@ -517,6 +524,7 @@ int main(int argc, char **argv)
        struct test_opts opts = {
                .mode = TEST_MODE_UNSET,
                .peer_cid = VMADDR_CID_ANY,
+               .peer_port = DEFAULT_PEER_PORT,
        };
 
        init_signals();
@@ -544,6 +552,9 @@ int main(int argc, char **argv)
                case 'p':
                        opts.peer_cid = parse_cid(optarg);
                        break;
+               case 'q':
+                       opts.peer_port = parse_port(optarg);
+                       break;
                case 'P':
                        control_port = optarg;
                        break;
index 66246d81d65499cc46703df552c627bb082f573e..f851f8961247000d86a40919dbc5594cc01eb095 100644 (file)
@@ -34,7 +34,7 @@ static void test_stream_connection_reset(const struct test_opts *opts)
        } addr = {
                .svm = {
                        .svm_family = AF_VSOCK,
-                       .svm_port = 1234,
+                       .svm_port = opts->peer_port,
                        .svm_cid = opts->peer_cid,
                },
        };
@@ -70,7 +70,7 @@ static void test_stream_bind_only_client(const struct test_opts *opts)
        } addr = {
                .svm = {
                        .svm_family = AF_VSOCK,
-                       .svm_port = 1234,
+                       .svm_port = opts->peer_port,
                        .svm_cid = opts->peer_cid,
                },
        };
@@ -112,7 +112,7 @@ static void test_stream_bind_only_server(const struct test_opts *opts)
        } addr = {
                .svm = {
                        .svm_family = AF_VSOCK,
-                       .svm_port = 1234,
+                       .svm_port = opts->peer_port,
                        .svm_cid = VMADDR_CID_ANY,
                },
        };
@@ -138,7 +138,7 @@ static void test_stream_client_close_client(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -152,7 +152,7 @@ static void test_stream_client_close_server(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -173,7 +173,7 @@ static void test_stream_server_close_client(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -194,7 +194,7 @@ static void test_stream_server_close_server(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -215,7 +215,7 @@ static void test_stream_multiconn_client(const struct test_opts *opts)
        int i;
 
        for (i = 0; i < MULTICONN_NFDS; i++) {
-               fds[i] = vsock_stream_connect(opts->peer_cid, 1234);
+               fds[i] = vsock_stream_connect(opts->peer_cid, opts->peer_port);
                if (fds[i] < 0) {
                        perror("connect");
                        exit(EXIT_FAILURE);
@@ -239,7 +239,7 @@ static void test_stream_multiconn_server(const struct test_opts *opts)
        int i;
 
        for (i = 0; i < MULTICONN_NFDS; i++) {
-               fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+               fds[i] = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
                if (fds[i] < 0) {
                        perror("accept");
                        exit(EXIT_FAILURE);
@@ -267,9 +267,9 @@ static void test_msg_peek_client(const struct test_opts *opts,
        int i;
 
        if (seqpacket)
-               fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+               fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
        else
-               fd = vsock_stream_connect(opts->peer_cid, 1234);
+               fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
 
        if (fd < 0) {
                perror("connect");
@@ -295,9 +295,9 @@ static void test_msg_peek_server(const struct test_opts *opts,
        int fd;
 
        if (seqpacket)
-               fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+               fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        else
-               fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+               fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
 
        if (fd < 0) {
                perror("accept");
@@ -363,7 +363,7 @@ static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
        int msg_count;
        int fd;
 
-       fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+       fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -434,7 +434,7 @@ static void test_seqpacket_msg_bounds_server(const struct test_opts *opts)
        struct msghdr msg = {0};
        struct iovec iov = {0};
 
-       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -505,7 +505,7 @@ static void test_seqpacket_msg_trunc_client(const struct test_opts *opts)
        int fd;
        char buf[MESSAGE_TRUNC_SZ];
 
-       fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+       fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -524,7 +524,7 @@ static void test_seqpacket_msg_trunc_server(const struct test_opts *opts)
        struct msghdr msg = {0};
        struct iovec iov = {0};
 
-       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -575,7 +575,7 @@ static void test_seqpacket_timeout_client(const struct test_opts *opts)
        time_t read_enter_ns;
        time_t read_overhead_ns;
 
-       fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+       fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -620,7 +620,7 @@ static void test_seqpacket_timeout_server(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -639,7 +639,7 @@ static void test_seqpacket_bigmsg_client(const struct test_opts *opts)
 
        len = sizeof(sock_buf_size);
 
-       fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+       fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -671,7 +671,7 @@ static void test_seqpacket_bigmsg_server(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -692,7 +692,7 @@ static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opt
        unsigned char *buf2;
        int buf_size = getpagesize() * 3;
 
-       fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+       fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -732,7 +732,7 @@ static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opt
        int flags = MAP_PRIVATE | MAP_ANONYMOUS;
        int i;
 
-       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -808,7 +808,7 @@ static void test_stream_poll_rcvlowat_server(const struct test_opts *opts)
        int fd;
        int i;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -839,7 +839,7 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
        short poll_flags;
        int fd;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -906,9 +906,9 @@ static void test_inv_buf_client(const struct test_opts *opts, bool stream)
        int fd;
 
        if (stream)
-               fd = vsock_stream_connect(opts->peer_cid, 1234);
+               fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        else
-               fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+               fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
 
        if (fd < 0) {
                perror("connect");
@@ -941,9 +941,9 @@ static void test_inv_buf_server(const struct test_opts *opts, bool stream)
        int fd;
 
        if (stream)
-               fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+               fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        else
-               fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+               fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
 
        if (fd < 0) {
                perror("accept");
@@ -986,7 +986,7 @@ static void test_stream_virtio_skb_merge_client(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -1015,7 +1015,7 @@ static void test_stream_virtio_skb_merge_server(const struct test_opts *opts)
        unsigned char buf[64];
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -1108,7 +1108,7 @@ static void test_stream_shutwr_client(const struct test_opts *opts)
 
        sigaction(SIGPIPE, &act, NULL);
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -1130,7 +1130,7 @@ static void test_stream_shutwr_server(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -1151,7 +1151,7 @@ static void test_stream_shutrd_client(const struct test_opts *opts)
 
        sigaction(SIGPIPE, &act, NULL);
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -1170,7 +1170,7 @@ static void test_stream_shutrd_server(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -1193,7 +1193,7 @@ static void test_double_bind_connect_server(const struct test_opts *opts)
        struct sockaddr_vm sa_client;
        socklen_t socklen_client = sizeof(sa_client);
 
-       listen_fd = vsock_stream_listen(VMADDR_CID_ANY, 1234);
+       listen_fd = vsock_stream_listen(VMADDR_CID_ANY, opts->peer_port);
 
        for (i = 0; i < 2; i++) {
                control_writeln("LISTENING");
@@ -1226,7 +1226,13 @@ static void test_double_bind_connect_client(const struct test_opts *opts)
                /* Wait until server is ready to accept a new connection */
                control_expectln("LISTENING");
 
-               client_fd = vsock_bind_connect(opts->peer_cid, 1234, 4321, SOCK_STREAM);
+               /* We use 'peer_port + 1' as "some" port for the 'bind()'
+                * call. It is safe for overflow, but must be considered,
+                * when running multiple test applications simultaneously
+                * where 'peer-port' argument differs by 1.
+                */
+               client_fd = vsock_bind_connect(opts->peer_cid, opts->peer_port,
+                                              opts->peer_port + 1, SOCK_STREAM);
 
                close(client_fd);
        }
@@ -1246,7 +1252,7 @@ static void test_stream_rcvlowat_def_cred_upd_client(const struct test_opts *opt
        void *buf;
        int fd;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -1282,7 +1288,7 @@ static void test_stream_credit_update_test(const struct test_opts *opts,
        void *buf;
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -1542,6 +1548,11 @@ static const struct option longopts[] = {
                .has_arg = required_argument,
                .val = 'p',
        },
+       {
+               .name = "peer-port",
+               .has_arg = required_argument,
+               .val = 'q',
+       },
        {
                .name = "list",
                .has_arg = no_argument,
@@ -1562,7 +1573,7 @@ static const struct option longopts[] = {
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n"
+       fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--peer-port=<port>] [--list] [--skip=<test_id>]\n"
                "\n"
                "  Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n"
                "  Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
@@ -1577,6 +1588,9 @@ static void usage(void)
                "connect to.\n"
                "\n"
                "The CID of the other side must be given with --peer-cid=<cid>.\n"
+               "During the test, two AF_VSOCK ports will be used: the port\n"
+               "specified with --peer-port=<port> (or the default port)\n"
+               "and the next one.\n"
                "\n"
                "Options:\n"
                "  --help                 This help message\n"
@@ -1584,9 +1598,11 @@ static void usage(void)
                "  --control-port <port>  Server port to listen on/connect to\n"
                "  --mode client|server   Server or client mode\n"
                "  --peer-cid <cid>       CID of the other side\n"
+               "  --peer-port <port>     AF_VSOCK port used for the test [default: %d]\n"
                "  --list                 List of tests that will be executed\n"
                "  --skip <test_id>       Test ID to skip;\n"
-               "                         use multiple --skip options to skip more tests\n"
+               "                         use multiple --skip options to skip more tests\n",
+               DEFAULT_PEER_PORT
                );
        exit(EXIT_FAILURE);
 }
@@ -1598,6 +1614,7 @@ int main(int argc, char **argv)
        struct test_opts opts = {
                .mode = TEST_MODE_UNSET,
                .peer_cid = VMADDR_CID_ANY,
+               .peer_port = DEFAULT_PEER_PORT,
        };
 
        srand(time(NULL));
@@ -1626,6 +1643,9 @@ int main(int argc, char **argv)
                case 'p':
                        opts.peer_cid = parse_cid(optarg);
                        break;
+               case 'q':
+                       opts.peer_port = parse_port(optarg);
+                       break;
                case 'P':
                        control_port = optarg;
                        break;
index a16ff76484e6294871895d45fb876bbd681399df..04c376b6937f51bea284bbb3fed25eb61166297c 100644 (file)
@@ -152,9 +152,9 @@ static void test_client(const struct test_opts *opts,
        int fd;
 
        if (sock_seqpacket)
-               fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
+               fd = vsock_seqpacket_connect(opts->peer_cid, opts->peer_port);
        else
-               fd = vsock_stream_connect(opts->peer_cid, 1234);
+               fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
 
        if (fd < 0) {
                perror("connect");
@@ -248,9 +248,9 @@ static void test_server(const struct test_opts *opts,
        int fd;
 
        if (sock_seqpacket)
-               fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
+               fd = vsock_seqpacket_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        else
-               fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+               fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
 
        if (fd < 0) {
                perror("accept");
@@ -323,7 +323,7 @@ void test_stream_msgzcopy_empty_errq_client(const struct test_opts *opts)
        ssize_t res;
        int fd;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -347,7 +347,7 @@ void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts)
 {
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
index d976d35f0ba9125054cce68a4017204f40de2c0b..6c3e6f70c457da2ab6c0b993e90e1a5b4f8ac439 100644 (file)
@@ -66,7 +66,7 @@ static void vsock_io_uring_client(const struct test_opts *opts,
        struct msghdr msg;
        int fd;
 
-       fd = vsock_stream_connect(opts->peer_cid, 1234);
+       fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
        if (fd < 0) {
                perror("connect");
                exit(EXIT_FAILURE);
@@ -120,7 +120,7 @@ static void vsock_io_uring_server(const struct test_opts *opts,
        void *data;
        int fd;
 
-       fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+       fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
        if (fd < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
@@ -247,6 +247,11 @@ static const struct option longopts[] = {
                .has_arg = required_argument,
                .val = 'p',
        },
+       {
+               .name = "peer-port",
+               .has_arg = required_argument,
+               .val = 'q',
+       },
        {
                .name = "help",
                .has_arg = no_argument,
@@ -257,7 +262,7 @@ static const struct option longopts[] = {
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: vsock_uring_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid>\n"
+       fprintf(stderr, "Usage: vsock_uring_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--peer-port=<port>]\n"
                "\n"
                "  Server: vsock_uring_test --control-port=1234 --mode=server --peer-cid=3\n"
                "  Client: vsock_uring_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n"
@@ -271,6 +276,8 @@ static void usage(void)
                "  --control-port <port>  Server port to listen on/connect to\n"
                "  --mode client|server   Server or client mode\n"
                "  --peer-cid <cid>       CID of the other side\n"
+               "  --peer-port <port>     AF_VSOCK port used for the test [default: %d]\n",
+               DEFAULT_PEER_PORT
                );
        exit(EXIT_FAILURE);
 }
@@ -282,6 +289,7 @@ int main(int argc, char **argv)
        struct test_opts opts = {
                .mode = TEST_MODE_UNSET,
                .peer_cid = VMADDR_CID_ANY,
+               .peer_port = DEFAULT_PEER_PORT,
        };
 
        init_signals();
@@ -309,6 +317,9 @@ int main(int argc, char **argv)
                case 'p':
                        opts.peer_cid = parse_cid(optarg);
                        break;
+               case 'q':
+                       opts.peer_port = parse_port(optarg);
+                       break;
                case 'P':
                        control_port = optarg;
                        break;