diff options
author | Marc Kleine-Budde <mkl@pengutronix.de> | 2018-10-08 03:02:39 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2019-09-04 07:29:15 -0400 |
commit | 8df9ffb888c021fa68f9075d545f2ec5eca37200 (patch) | |
tree | c783503e0599f77685c82925a36bfa3f0a2a9794 | |
parent | ffd956eef69b212a724b1cc4cdc61828f3ad9104 (diff) |
can: make use of preallocated can_ml_priv for per device struct can_dev_rcv_lists
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>
-rw-r--r-- | drivers/net/can/dev.c | 2 | ||||
-rw-r--r-- | drivers/net/can/slcan.c | 1 | ||||
-rw-r--r-- | drivers/net/can/vcan.c | 1 | ||||
-rw-r--r-- | drivers/net/can/vxcan.c | 1 | ||||
-rw-r--r-- | include/linux/can/can-ml.h | 1 | ||||
-rw-r--r-- | net/can/af_can.c | 45 |
6 files changed, 12 insertions, 39 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 9e688dc29521..b429550c4cc2 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c | |||
@@ -746,6 +746,8 @@ struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max, | |||
746 | priv = netdev_priv(dev); | 746 | priv = netdev_priv(dev); |
747 | priv->dev = dev; | 747 | priv->dev = dev; |
748 | 748 | ||
749 | dev->ml_priv = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN); | ||
750 | |||
749 | if (echo_skb_max) { | 751 | if (echo_skb_max) { |
750 | priv->echo_skb_max = echo_skb_max; | 752 | priv->echo_skb_max = echo_skb_max; |
751 | priv->echo_skb = (void *)priv + | 753 | priv->echo_skb = (void *)priv + |
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 5b2e95425e69..bb6032211043 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c | |||
@@ -536,6 +536,7 @@ static struct slcan *slc_alloc(void) | |||
536 | 536 | ||
537 | dev->base_addr = i; | 537 | dev->base_addr = i; |
538 | sl = netdev_priv(dev); | 538 | sl = netdev_priv(dev); |
539 | dev->ml_priv = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN); | ||
539 | 540 | ||
540 | /* Initialize channel control data */ | 541 | /* Initialize channel control data */ |
541 | sl->magic = SLCAN_MAGIC; | 542 | sl->magic = SLCAN_MAGIC; |
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 6973ae09a37a..39ca14b0585d 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c | |||
@@ -153,6 +153,7 @@ static void vcan_setup(struct net_device *dev) | |||
153 | dev->addr_len = 0; | 153 | dev->addr_len = 0; |
154 | dev->tx_queue_len = 0; | 154 | dev->tx_queue_len = 0; |
155 | dev->flags = IFF_NOARP; | 155 | dev->flags = IFF_NOARP; |
156 | dev->ml_priv = netdev_priv(dev); | ||
156 | 157 | ||
157 | /* set flags according to driver capabilities */ | 158 | /* set flags according to driver capabilities */ |
158 | if (echo) | 159 | if (echo) |
diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 4c3eed796432..d6ba9426be4d 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c | |||
@@ -147,6 +147,7 @@ static void vxcan_setup(struct net_device *dev) | |||
147 | dev->flags = (IFF_NOARP|IFF_ECHO); | 147 | dev->flags = (IFF_NOARP|IFF_ECHO); |
148 | dev->netdev_ops = &vxcan_netdev_ops; | 148 | dev->netdev_ops = &vxcan_netdev_ops; |
149 | dev->needs_free_netdev = true; | 149 | dev->needs_free_netdev = true; |
150 | dev->ml_priv = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN); | ||
150 | } | 151 | } |
151 | 152 | ||
152 | /* forward declaration for rtnl_create_link() */ | 153 | /* 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 { | |||
55 | struct hlist_head rx[RX_MAX]; | 55 | struct hlist_head rx[RX_MAX]; |
56 | struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ]; | 56 | struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ]; |
57 | struct hlist_head rx_eff[CAN_EFF_RCV_ARRAY_SZ]; | 57 | struct hlist_head rx_eff[CAN_EFF_RCV_ARRAY_SZ]; |
58 | int remove_on_zero_entries; | ||
59 | int entries; | 58 | int entries; |
60 | }; | 59 | }; |
61 | 60 | ||
diff --git a/net/can/af_can.c b/net/can/af_can.c index 723299daa04e..6ed85e2f72f0 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c | |||
@@ -302,10 +302,12 @@ EXPORT_SYMBOL(can_send); | |||
302 | static struct can_dev_rcv_lists *can_dev_rcv_lists_find(struct net *net, | 302 | static struct can_dev_rcv_lists *can_dev_rcv_lists_find(struct net *net, |
303 | struct net_device *dev) | 303 | struct net_device *dev) |
304 | { | 304 | { |
305 | if (!dev) | 305 | if (dev) { |
306 | struct can_ml_priv *ml_priv = dev->ml_priv; | ||
307 | return &ml_priv->dev_rcv_lists; | ||
308 | } else { | ||
306 | return net->can.rx_alldev_list; | 309 | return net->can.rx_alldev_list; |
307 | else | 310 | } |
308 | return (struct can_dev_rcv_lists *)dev->ml_priv; | ||
309 | } | 311 | } |
310 | 312 | ||
311 | /** | 313 | /** |
@@ -561,12 +563,6 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, | |||
561 | if (rcv_lists_stats->rcv_entries > 0) | 563 | if (rcv_lists_stats->rcv_entries > 0) |
562 | rcv_lists_stats->rcv_entries--; | 564 | rcv_lists_stats->rcv_entries--; |
563 | 565 | ||
564 | /* remove device structure requested by NETDEV_UNREGISTER */ | ||
565 | if (dev_rcv_lists->remove_on_zero_entries && !dev_rcv_lists->entries) { | ||
566 | kfree(dev_rcv_lists); | ||
567 | dev->ml_priv = NULL; | ||
568 | } | ||
569 | |||
570 | out: | 566 | out: |
571 | spin_unlock(&net->can.rcvlists_lock); | 567 | spin_unlock(&net->can.rcvlists_lock); |
572 | 568 | ||
@@ -788,41 +784,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, | |||
788 | void *ptr) | 784 | void *ptr) |
789 | { | 785 | { |
790 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 786 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
791 | struct can_dev_rcv_lists *dev_rcv_lists; | ||
792 | 787 | ||
793 | if (dev->type != ARPHRD_CAN) | 788 | if (dev->type != ARPHRD_CAN) |
794 | return NOTIFY_DONE; | 789 | return NOTIFY_DONE; |
795 | 790 | ||
796 | switch (msg) { | 791 | switch (msg) { |
797 | case NETDEV_REGISTER: | 792 | case NETDEV_REGISTER: |
798 | 793 | WARN(!dev->ml_priv, | |
799 | /* create new dev_rcv_lists for this device */ | 794 | "No CAN mid layer private allocated, please fix your driver and use alloc_candev()!\n"); |
800 | dev_rcv_lists = kzalloc(sizeof(*dev_rcv_lists), GFP_KERNEL); | ||
801 | if (!dev_rcv_lists) | ||
802 | return NOTIFY_DONE; | ||
803 | BUG_ON(dev->ml_priv); | ||
804 | dev->ml_priv = dev_rcv_lists; | ||
805 | |||
806 | break; | ||
807 | |||
808 | case NETDEV_UNREGISTER: | ||
809 | spin_lock(&dev_net(dev)->can.rcvlists_lock); | ||
810 | |||
811 | dev_rcv_lists = dev->ml_priv; | ||
812 | if (dev_rcv_lists) { | ||
813 | if (dev_rcv_lists->entries) | ||
814 | dev_rcv_lists->remove_on_zero_entries = 1; | ||
815 | else { | ||
816 | kfree(dev_rcv_lists); | ||
817 | dev->ml_priv = NULL; | ||
818 | } | ||
819 | } else { | ||
820 | pr_err("can: notifier: receive list not found for dev %s\n", | ||
821 | dev->name); | ||
822 | } | ||
823 | |||
824 | spin_unlock(&dev_net(dev)->can.rcvlists_lock); | ||
825 | |||
826 | break; | 795 | break; |
827 | } | 796 | } |
828 | 797 | ||