From 9df35800656ecb680d2cc52d5c49c3cb0508a51e Mon Sep 17 00:00:00 2001 From: hartkopp Date: Sun, 24 Jan 2010 21:35:06 +0000 Subject: [PATCH] Consistently clean up the reference dev->ml_priv when the device receiver list is (to be) removed. Cleanly separate find_dev_rcv_lists() function for 2.6.26+ as we do not need the fallback. git-svn-id: svn://svn.berlios.de//socketcan/trunk@1119 030b6a49-0b11-0410-94ab-b0dab22257f2 --- kernel/2.6/net/can/af_can.c | 38 +++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/kernel/2.6/net/can/af_can.c b/kernel/2.6/net/can/af_can.c index 5f37132..14dbba5 100644 --- a/kernel/2.6/net/can/af_can.c +++ b/kernel/2.6/net/can/af_can.c @@ -373,33 +373,34 @@ EXPORT_SYMBOL(can_send); * af_can rx path */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) { - struct dev_rcv_lists *d = NULL; - struct hlist_node *n; - - /* find receive list for this device */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) /* + * find receive list for this device + * * Since 2.6.26 a new "midlevel private" ml_priv pointer has been * introduced in struct net_device. We use this pointer to omit the * linear walk through the can_rx_dev_list. A similar speedup has been * queued for 2.6.34 mainline but using the new netdev_rcu lists. + * Therefore the can_rx_dev_list is still needed (e.g. in proc.c) */ /* dev == NULL is the indicator for the 'all' filterlist */ if (!dev) return &can_rx_alldev_list; - - /* do not search in rcu list when we have a direct reference */ - if (dev->ml_priv) + else return (struct dev_rcv_lists *)dev->ml_priv; - - /* fall back to standard behaviour */ -#endif +} +#else +static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) +{ + struct dev_rcv_lists *d = NULL; + struct hlist_node *n; /* + * find receive list for this device + * * The hlist_for_each_entry*() macros curse through the list * using the pointer variable n and set d to the containing * struct in each list iteration. Therefore, after list @@ -417,6 +418,7 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) return n ? d : NULL; } +#endif /** * find_rcv_list - determine optimal filterlist inside device filter struct @@ -654,9 +656,12 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, can_pstats.rcv_entries--; /* remove device structure requested by NETDEV_UNREGISTER */ - if (d->remove_on_zero_entries && !d->entries) + if (d->remove_on_zero_entries && !d->entries) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + dev->ml_priv = NULL; +#endif hlist_del_rcu(&d->list); - else + } else d = NULL; out: @@ -934,6 +939,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, spin_lock(&can_rcvlists_lock); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + BUG_ON(dev->ml_priv); dev->ml_priv = d; #endif hlist_add_head_rcu(&d->list, &can_rx_dev_list); @@ -1056,6 +1062,10 @@ static __exit void can_exit(void) hlist_del(&can_rx_alldev_list.list); hlist_for_each_entry_safe(d, n, next, &can_rx_dev_list, list) { hlist_del(&d->list); + BUG_ON(d->entries); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + d->dev->ml_priv = NULL; +#endif kfree(d); } spin_unlock(&can_rcvlists_lock); -- 2.39.2