can: make use of preallocated can_ml_priv for per device struct can_dev_rcv_lists
authorMarc Kleine-Budde <mkl@pengutronix.de>
Mon, 8 Oct 2018 07:02:39 +0000 (09:02 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Wed, 4 Sep 2019 11:29:15 +0000 (13:29 +0200)
This patch removes the old method of allocating the per device protocol
specific memory via a netdevice_notifier. This had the drawback, that
the allocation can fail, leading to a lot of null pointer checks in the
code. This also makes the live cycle management of this memory quite
complicated.

This patch switches from the allocating the struct can_dev_rcv_lists in
a NETDEV_REGISTER call to using the dev->ml_priv, which is allocated by
the driver since the previous patch.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/dev.c
drivers/net/can/slcan.c
drivers/net/can/vcan.c
drivers/net/can/vxcan.c
include/linux/can/can-ml.h
net/can/af_can.c

index 9e688dc..b429550 100644 (file)
@@ -746,6 +746,8 @@ struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
        priv = netdev_priv(dev);
        priv->dev = dev;
 
+       dev->ml_priv = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN);
+
        if (echo_skb_max) {
                priv->echo_skb_max = echo_skb_max;
                priv->echo_skb = (void *)priv +
index 5b2e954..bb60322 100644 (file)
@@ -536,6 +536,7 @@ static struct slcan *slc_alloc(void)
 
        dev->base_addr  = i;
        sl = netdev_priv(dev);
+       dev->ml_priv = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN);
 
        /* Initialize channel control data */
        sl->magic = SLCAN_MAGIC;
index 6973ae0..39ca14b 100644 (file)
@@ -153,6 +153,7 @@ static void vcan_setup(struct net_device *dev)
        dev->addr_len           = 0;
        dev->tx_queue_len       = 0;
        dev->flags              = IFF_NOARP;
+       dev->ml_priv            = netdev_priv(dev);
 
        /* set flags according to driver capabilities */
        if (echo)
index 4c3eed7..d6ba942 100644 (file)
@@ -147,6 +147,7 @@ static void vxcan_setup(struct net_device *dev)
        dev->flags              = (IFF_NOARP|IFF_ECHO);
        dev->netdev_ops         = &vxcan_netdev_ops;
        dev->needs_free_netdev  = true;
+       dev->ml_priv            = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
 }
 
 /* forward declaration for rtnl_create_link() */
index 0a9d778..79ccf6b 100644 (file)
@@ -55,7 +55,6 @@ struct can_dev_rcv_lists {
        struct hlist_head rx[RX_MAX];
        struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ];
        struct hlist_head rx_eff[CAN_EFF_RCV_ARRAY_SZ];
-       int remove_on_zero_entries;
        int entries;
 };
 
index 723299d..6ed85e2 100644 (file)
@@ -302,10 +302,12 @@ EXPORT_SYMBOL(can_send);
 static struct can_dev_rcv_lists *can_dev_rcv_lists_find(struct net *net,
                                                        struct net_device *dev)
 {
-       if (!dev)
+       if (dev) {
+               struct can_ml_priv *ml_priv = dev->ml_priv;
+               return &ml_priv->dev_rcv_lists;
+       } else {
                return net->can.rx_alldev_list;
-       else
-               return (struct can_dev_rcv_lists *)dev->ml_priv;
+       }
 }
 
 /**
@@ -561,12 +563,6 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
        if (rcv_lists_stats->rcv_entries > 0)
                rcv_lists_stats->rcv_entries--;
 
-       /* remove device structure requested by NETDEV_UNREGISTER */
-       if (dev_rcv_lists->remove_on_zero_entries && !dev_rcv_lists->entries) {
-               kfree(dev_rcv_lists);
-               dev->ml_priv = NULL;
-       }
-
  out:
        spin_unlock(&net->can.rcvlists_lock);
 
@@ -788,41 +784,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
                        void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-       struct can_dev_rcv_lists *dev_rcv_lists;
 
        if (dev->type != ARPHRD_CAN)
                return NOTIFY_DONE;
 
        switch (msg) {
        case NETDEV_REGISTER:
-
-               /* create new dev_rcv_lists for this device */
-               dev_rcv_lists = kzalloc(sizeof(*dev_rcv_lists), GFP_KERNEL);
-               if (!dev_rcv_lists)
-                       return NOTIFY_DONE;
-               BUG_ON(dev->ml_priv);
-               dev->ml_priv = dev_rcv_lists;
-
-               break;
-
-       case NETDEV_UNREGISTER:
-               spin_lock(&dev_net(dev)->can.rcvlists_lock);
-
-               dev_rcv_lists = dev->ml_priv;
-               if (dev_rcv_lists) {
-                       if (dev_rcv_lists->entries)
-                               dev_rcv_lists->remove_on_zero_entries = 1;
-                       else {
-                               kfree(dev_rcv_lists);
-                               dev->ml_priv = NULL;
-                       }
-               } else {
-                       pr_err("can: notifier: receive list not found for dev %s\n",
-                              dev->name);
-               }
-
-               spin_unlock(&dev_net(dev)->can.rcvlists_lock);
-
+               WARN(!dev->ml_priv,
+                    "No CAN mid layer private allocated, please fix your driver and use alloc_candev()!\n");
                break;
        }