]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
net: remove napi_hash_del() from driver-facing API
authorJakub Kicinski <kuba@kernel.org>
Wed, 9 Sep 2020 17:37:51 +0000 (10:37 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Sep 2020 20:08:46 +0000 (13:08 -0700)
We allow drivers to call napi_hash_del() before calling
netif_napi_del() to batch RCU grace periods. This makes
the API asymmetric and leaks internal implementation details.
Soon we will want the grace period to protect more than just
the NAPI hash table.

Restructure the API and have drivers call a new function -
__netif_napi_del() if they want to take care of RCU waits.

Note that only core was checking the return status from
napi_hash_del() so the new helper does not report if the
NAPI was actually deleted.

Some notes on driver oddness:
 - veth observed the grace period before calling netif_napi_del()
   but that should not matter
 - myri10ge observed normal RCU flavor
 - bnx2x and enic did not actually observe the grace period
   (unless they did so implicitly)
 - virtio_net and enic only unhashed Rx NAPIs

The last two points seem to indicate that the calls to
napi_hash_del() were a left over rather than an optimization.
Regardless, it's easy enough to correct them.

This patch may introduce extra synchronize_net() calls for
interfaces which set NAPI_STATE_NO_BUSY_POLL and depend on
free_netdev() to call netif_napi_del(). This seems inevitable
since we want to use RCU for netpoll dev->napi_list traversal,
and almost no drivers set IFF_DISABLE_NETPOLL.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/veth.c
drivers/net/virtio_net.c
include/linux/netdevice.h
net/core/dev.c

index 7e4c93be4451d04f166feeee4d696afa6b4f5326..d8b1824c334d3b0d7b515b8f5dd11aa34190a909 100644 (file)
@@ -825,9 +825,9 @@ static inline void bnx2x_del_all_napi_cnic(struct bnx2x *bp)
        int i;
 
        for_each_rx_queue_cnic(bp, i) {
-               napi_hash_del(&bnx2x_fp(bp, i, napi));
-               netif_napi_del(&bnx2x_fp(bp, i, napi));
+               __netif_napi_del(&bnx2x_fp(bp, i, napi));
        }
+       synchronize_net();
 }
 
 static inline void bnx2x_del_all_napi(struct bnx2x *bp)
@@ -835,9 +835,9 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
        int i;
 
        for_each_eth_queue(bp, i) {
-               napi_hash_del(&bnx2x_fp(bp, i, napi));
-               netif_napi_del(&bnx2x_fp(bp, i, napi));
+               __netif_napi_del(&bnx2x_fp(bp, i, napi));
        }
+       synchronize_net();
 }
 
 int bnx2x_set_int_mode(struct bnx2x *bp);
index b167066af45040c523bb19cc74695c9dca8ae717..53f64ca673c3063c5edf58ffacea5b940379928f 100644 (file)
@@ -8634,10 +8634,9 @@ static void bnxt_del_napi(struct bnxt *bp)
        for (i = 0; i < bp->cp_nr_rings; i++) {
                struct bnxt_napi *bnapi = bp->bnapi[i];
 
-               napi_hash_del(&bnapi->napi);
-               netif_napi_del(&bnapi->napi);
+               __netif_napi_del(&bnapi->napi);
        }
-       /* We called napi_hash_del() before netif_napi_del(), we need
+       /* We called __netif_napi_del(), we need
         * to respect an RCU grace period before freeing napi structures.
         */
        synchronize_net();
index a4e307636f5ab209a172a50cb23b3ce24da24945..4f0329d8778f8974bd900fb660c941daa1c9d74d 100644 (file)
@@ -2529,13 +2529,15 @@ static void enic_dev_deinit(struct enic *enic)
 {
        unsigned int i;
 
-       for (i = 0; i < enic->rq_count; i++) {
-               napi_hash_del(&enic->napi[i]);
-               netif_napi_del(&enic->napi[i]);
-       }
+       for (i = 0; i < enic->rq_count; i++)
+               __netif_napi_del(&enic->napi[i]);
+
        if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX)
                for (i = 0; i < enic->wq_count; i++)
-                       netif_napi_del(&enic->napi[enic_cq_wq(enic, i)]);
+                       __netif_napi_del(&enic->napi[enic_cq_wq(enic, i)]);
+
+       /* observe RCU grace period after __netif_napi_del() calls */
+       synchronize_net();
 
        enic_free_vnic_resources(enic);
        enic_clear_intr_mode(enic);
index 2e35c5706cf10440db068131964ef029deeb7217..df389a11d3af6c7a9b551e1f559093dc3120aaee 100644 (file)
@@ -1029,10 +1029,10 @@ static void ixgbe_free_q_vector(struct ixgbe_adapter *adapter, int v_idx)
                WRITE_ONCE(adapter->rx_ring[ring->queue_index], NULL);
 
        adapter->q_vector[v_idx] = NULL;
-       napi_hash_del(&q_vector->napi);
-       netif_napi_del(&q_vector->napi);
+       __netif_napi_del(&q_vector->napi);
 
        /*
+        * after a call to __netif_napi_del() napi may still be used and
         * ixgbe_get_stats64() might access the rings on this vector,
         * we must wait a grace period before freeing it.
         */
index 4a5beafa04932fcbe04dba5f1ff80dae5929d59d..1634ca6d4a8f02ec9e86c287d5eb0d4807648dc5 100644 (file)
@@ -3543,11 +3543,10 @@ static void myri10ge_free_slices(struct myri10ge_priv *mgp)
                                          ss->fw_stats, ss->fw_stats_bus);
                        ss->fw_stats = NULL;
                }
-               napi_hash_del(&ss->napi);
-               netif_napi_del(&ss->napi);
+               __netif_napi_del(&ss->napi);
        }
        /* Wait till napi structs are no longer used, and then free ss. */
-       synchronize_rcu();
+       synchronize_net();
        kfree(mgp->ss);
        mgp->ss = NULL;
 }
index 7de8f0ea3f6bf979fd8033ac1c4fbb00323d431a..091e5b4ba04238ef243a76b5ea858b41ec2f041b 100644 (file)
@@ -897,14 +897,13 @@ static void veth_napi_del(struct net_device *dev)
                struct veth_rq *rq = &priv->rq[i];
 
                napi_disable(&rq->xdp_napi);
-               napi_hash_del(&rq->xdp_napi);
+               __netif_napi_del(&rq->xdp_napi);
        }
        synchronize_net();
 
        for (i = 0; i < dev->real_num_rx_queues; i++) {
                struct veth_rq *rq = &priv->rq[i];
 
-               netif_napi_del(&rq->xdp_napi);
                rq->rx_notify_masked = false;
                ptr_ring_cleanup(&rq->xdp_ring, veth_ptr_free);
        }
index 263b005981bd7837277e65280c2ff3df38f17730..7145c83c6c8c155076d814cb64782fbb5dbb22d6 100644 (file)
@@ -2604,12 +2604,11 @@ static void virtnet_free_queues(struct virtnet_info *vi)
        int i;
 
        for (i = 0; i < vi->max_queue_pairs; i++) {
-               napi_hash_del(&vi->rq[i].napi);
-               netif_napi_del(&vi->rq[i].napi);
-               netif_napi_del(&vi->sq[i].napi);
+               __netif_napi_del(&vi->rq[i].napi);
+               __netif_napi_del(&vi->sq[i].napi);
        }
 
-       /* We called napi_hash_del() before netif_napi_del(),
+       /* We called __netif_napi_del(),
         * we need to respect an RCU grace period before freeing vi->rq
         */
        synchronize_net();
index 7f9fcfd1594264728cb90fa7b8f589ee666f9343..74ed9521509101dbeda99ac5430bb5d410d9f854 100644 (file)
@@ -70,6 +70,7 @@ struct udp_tunnel_nic;
 struct bpf_prog;
 struct xdp_buff;
 
+void synchronize_net(void);
 void netdev_set_default_ethtool_ops(struct net_device *dev,
                                    const struct ethtool_ops *ops);
 
@@ -488,20 +489,6 @@ static inline bool napi_complete(struct napi_struct *n)
        return napi_complete_done(n, 0);
 }
 
-/**
- *     napi_hash_del - remove a NAPI from global table
- *     @napi: NAPI context
- *
- * Warning: caller must observe RCU grace period
- * before freeing memory containing @napi, if
- * this function returns true.
- * Note: core networking stack automatically calls it
- * from netif_napi_del().
- * Drivers might want to call this helper to combine all
- * the needed RCU grace periods into a single one.
- */
-bool napi_hash_del(struct napi_struct *napi);
-
 /**
  *     napi_disable - prevent NAPI from scheduling
  *     @n: NAPI context
@@ -2367,13 +2354,27 @@ static inline void netif_tx_napi_add(struct net_device *dev,
        netif_napi_add(dev, napi, poll, weight);
 }
 
+/**
+ *  __netif_napi_del - remove a NAPI context
+ *  @napi: NAPI context
+ *
+ * Warning: caller must observe RCU grace period before freeing memory
+ * containing @napi. Drivers might want to call this helper to combine
+ * all the needed RCU grace periods into a single one.
+ */
+void __netif_napi_del(struct napi_struct *napi);
+
 /**
  *  netif_napi_del - remove a NAPI context
  *  @napi: NAPI context
  *
  *  netif_napi_del() removes a NAPI context from the network device NAPI list
  */
-void netif_napi_del(struct napi_struct *napi);
+static inline void netif_napi_del(struct napi_struct *napi)
+{
+       __netif_napi_del(napi);
+       synchronize_net();
+}
 
 struct napi_gro_cb {
        /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */
@@ -2797,7 +2798,6 @@ static inline void unregister_netdevice(struct net_device *dev)
 int netdev_refcnt_read(const struct net_device *dev);
 void free_netdev(struct net_device *dev);
 void netdev_freemem(struct net_device *dev);
-void synchronize_net(void);
 int init_dummy_netdev(struct net_device *dev);
 
 struct net_device *netdev_get_xmit_slave(struct net_device *dev,
index 152ad3b578deb0122bed07da30f3cd0ee5223685..205b7339d4ae7aca531449e941a319b78298fddc 100644 (file)
@@ -6555,20 +6555,15 @@ static void napi_hash_add(struct napi_struct *napi)
 /* Warning : caller is responsible to make sure rcu grace period
  * is respected before freeing memory containing @napi
  */
-bool napi_hash_del(struct napi_struct *napi)
+static void napi_hash_del(struct napi_struct *napi)
 {
-       bool rcu_sync_needed = false;
-
        spin_lock(&napi_hash_lock);
 
-       if (test_and_clear_bit(NAPI_STATE_HASHED, &napi->state)) {
-               rcu_sync_needed = true;
+       if (test_and_clear_bit(NAPI_STATE_HASHED, &napi->state))
                hlist_del_rcu(&napi->napi_hash_node);
-       }
+
        spin_unlock(&napi_hash_lock);
-       return rcu_sync_needed;
 }
-EXPORT_SYMBOL_GPL(napi_hash_del);
 
 static enum hrtimer_restart napi_watchdog(struct hrtimer *timer)
 {
@@ -6653,18 +6648,16 @@ static void flush_gro_hash(struct napi_struct *napi)
 }
 
 /* Must be called in process context */
-void netif_napi_del(struct napi_struct *napi)
+void __netif_napi_del(struct napi_struct *napi)
 {
-       might_sleep();
-       if (napi_hash_del(napi))
-               synchronize_net();
+       napi_hash_del(napi);
        list_del_init(&napi->dev_list);
        napi_free_frags(napi);
 
        flush_gro_hash(napi);
        napi->gro_bitmask = 0;
 }
-EXPORT_SYMBOL(netif_napi_del);
+EXPORT_SYMBOL(__netif_napi_del);
 
 static int napi_poll(struct napi_struct *n, struct list_head *repoll)
 {