From: Marc Kleine-Budde mkl@pengutronix.de
mainline inclusion from mainline-v5.4-rc1 commit 8df9ffb888c021fa68f9075d545f2ec5eca37200 category: feature bugzilla: 38684 CVE: NA
---------------------------
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
Conflicts: net/can/af_can.c
Signed-off-by: Zhang Changzhong zhangchangzhong@huawei.com Reviewed-by: YueHaibing yuehaibing@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/can/dev.c | 2 ++ drivers/net/can/slcan.c | 1 + drivers/net/can/vcan.c | 1 + drivers/net/can/vxcan.c | 1 + include/linux/can/can-ml.h | 1 - net/can/af_can.c | 44 ++++++-------------------------------- 6 files changed, 12 insertions(+), 38 deletions(-)
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 1723c848d0c4..d9f6baa80e64 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -757,6 +757,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 + diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 3abce32b7dcf..4dfa459ef5c7 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -541,6 +541,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; diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 603f53b81d86..32efb4b5f22c 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -158,6 +158,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) diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 3cc957f0a529..a496753ea53b 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -158,6 +158,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() */ diff --git a/include/linux/can/can-ml.h b/include/linux/can/can-ml.h index 0a9d778de8af..79ccf6bfa232 100644 --- a/include/linux/can/can-ml.h +++ b/include/linux/can/can-ml.h @@ -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; };
diff --git a/net/can/af_can.c b/net/can/af_can.c index 91062e45ee21..c2baf6444f5c 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -326,10 +326,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.can_rx_alldev_list; - else - return (struct can_dev_rcv_lists *)dev->ml_priv; + } }
/** @@ -593,12 +595,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.can_rcvlists_lock);
@@ -823,7 +819,6 @@ 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; @@ -831,33 +826,8 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, 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.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.can_rcvlists_lock); - + WARN(!dev->ml_priv, + "No CAN mid layer private allocated, please fix your driver and use alloc_candev()!\n"); break; }