X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fcore%2Fdst.c;h=3bf6cc4348141ef8961475dce214c91dcf07bb72;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=9f14ae8a767390c0a0c4e747d4b15e279ea8556a;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/core/dst.c b/net/core/dst.c index 9f14ae8a7..3bf6cc434 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -19,8 +19,6 @@ #include -const char dst_underflow_bug_msg[] = KERN_DEBUG "BUG: dst underflow %d: %p at %p\n"; - /* Locking strategy: * 1) Garbage collection state of dead destination cache * entries is protected by dst_lock. @@ -34,7 +32,7 @@ static struct dst_entry *dst_garbage_list; #if RT_CACHE_DEBUG >= 2 static atomic_t dst_total = ATOMIC_INIT(0); #endif -static spinlock_t dst_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(dst_lock); static unsigned long dst_gc_timer_expires; static unsigned long dst_gc_timer_inc = DST_GC_MAX; @@ -108,9 +106,9 @@ static int dst_discard_in(struct sk_buff *skb) return 0; } -static int dst_discard_out(struct sk_buff **pskb) +static int dst_discard_out(struct sk_buff *skb) { - kfree_skb(*pskb); + kfree_skb(skb); return 0; } @@ -171,6 +169,8 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) struct neighbour *neigh; struct hh_cache *hh; + smp_rmb(); + again: neigh = dst->neighbour; hh = dst->hh; @@ -220,31 +220,28 @@ again: * * Commented and originally written by Alexey. */ -static void dst_ifdown(struct dst_entry *dst, int unregister) +static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, + int unregister) { - struct net_device *dev = dst->dev; + if (dst->ops->ifdown) + dst->ops->ifdown(dst, dev, unregister); + + if (dev != dst->dev) + return; if (!unregister) { dst->input = dst_discard_in; dst->output = dst_discard_out; - } - - do { - if (unregister) { - dst->dev = &loopback_dev; - dev_hold(&loopback_dev); + } else { + dst->dev = &loopback_dev; + dev_hold(&loopback_dev); + dev_put(dev); + if (dst->neighbour && dst->neighbour->dev == dev) { + dst->neighbour->dev = &loopback_dev; dev_put(dev); - if (dst->neighbour && dst->neighbour->dev == dev) { - dst->neighbour->dev = &loopback_dev; - dev_put(dev); - dev_hold(&loopback_dev); - } + dev_hold(&loopback_dev); } - - if (dst->ops->ifdown) - dst->ops->ifdown(dst, unregister); - } while ((dst = dst->child) && dst->flags & DST_NOHASH && - dst->dev == dev); + } } static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -257,8 +254,7 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void case NETDEV_DOWN: spin_lock_bh(&dst_lock); for (dst = dst_garbage_list; dst; dst = dst->next) { - if (dst->dev == dev) - dst_ifdown(dst, event != NETDEV_DOWN); + dst_ifdown(dst, dev, event != NETDEV_DOWN); } spin_unlock_bh(&dst_lock); break; @@ -266,7 +262,7 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void return NOTIFY_DONE; } -struct notifier_block dst_dev_notifier = { +static struct notifier_block dst_dev_notifier = { .notifier_call = dst_dev_event, }; @@ -275,7 +271,6 @@ void __init dst_init(void) register_netdevice_notifier(&dst_dev_notifier); } -EXPORT_SYMBOL(dst_underflow_bug_msg); EXPORT_SYMBOL(__dst_free); EXPORT_SYMBOL(dst_alloc); EXPORT_SYMBOL(dst_destroy);