From 2957ed7b65e61b26e75a5c0b02d055ad3dde753e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 8 May 2007 18:34:17 -0700 Subject: [PATCH] --- yaml --- r: 55951 b: refs/heads/master c: 572a103ded0ad880f75ce83e99f0512fbb80b5b0 h: refs/heads/master i: 55949: a87dc6fb3c609a559606fdce263e3e43deb32cba 55947: 11e4d7a8a0b7585c0f10d7c135827181d1fbb471 55943: 63010f499448d733893d6ecbd08dd0e0f22f1888 55935: a0b3bc37627f648ae1c16934e6adf67148acbf76 v: v3 --- [refs] | 2 +- trunk/include/linux/netdevice.h | 2 ++ trunk/net/core/link_watch.c | 50 ++++++++++----------------------- 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/[refs] b/[refs] index 4a08d2e88a6b..c39a9a3c6167 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c33be3c362f1bc98f6e2d731a274ef138ae80741 +refs/heads/master: 572a103ded0ad880f75ce83e99f0512fbb80b5b0 diff --git a/trunk/include/linux/netdevice.h b/trunk/include/linux/netdevice.h index 30446222b396..f671cd2f133f 100644 --- a/trunk/include/linux/netdevice.h +++ b/trunk/include/linux/netdevice.h @@ -467,6 +467,8 @@ struct net_device /* device index hash chain */ struct hlist_node index_hlist; + struct net_device *link_watch_next; + /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, NETREG_REGISTERED, /* completed register_netdevice */ diff --git a/trunk/net/core/link_watch.c b/trunk/net/core/link_watch.c index e3c26a9ccad6..71a35da275d4 100644 --- a/trunk/net/core/link_watch.c +++ b/trunk/net/core/link_watch.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -28,7 +27,6 @@ enum lw_bits { LW_RUNNING = 0, - LW_SE_USED }; static unsigned long linkwatch_flags; @@ -37,17 +35,9 @@ static unsigned long linkwatch_nextevent; static void linkwatch_event(struct work_struct *dummy); static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); -static LIST_HEAD(lweventlist); +static struct net_device *lweventlist; static DEFINE_SPINLOCK(lweventlist_lock); -struct lw_event { - struct list_head list; - struct net_device *dev; -}; - -/* Avoid kmalloc() for most systems */ -static struct lw_event singleevent; - static unsigned char default_operstate(const struct net_device *dev) { if (!netif_carrier_ok(dev)) @@ -90,21 +80,23 @@ static void rfc2863_policy(struct net_device *dev) /* Must be called with the rtnl semaphore held */ void linkwatch_run_queue(void) { - struct list_head head, *n, *next; + struct net_device *next; spin_lock_irq(&lweventlist_lock); - list_replace_init(&lweventlist, &head); + next = lweventlist; + lweventlist = NULL; spin_unlock_irq(&lweventlist_lock); - list_for_each_safe(n, next, &head) { - struct lw_event *event = list_entry(n, struct lw_event, list); - struct net_device *dev = event->dev; + while (next) { + struct net_device *dev = next; - if (event == &singleevent) { - clear_bit(LW_SE_USED, &linkwatch_flags); - } else { - kfree(event); - } + next = dev->link_watch_next; + + /* + * Make sure the above read is complete since it can be + * rewritten as soon as we clear the bit below. + */ + smp_mb__before_clear_bit(); /* We are about to handle this device, * so new events can be accepted @@ -147,24 +139,12 @@ void linkwatch_fire_event(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { unsigned long flags; - struct lw_event *event; - - if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) { - event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC); - - if (unlikely(event == NULL)) { - clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); - return; - } - } else { - event = &singleevent; - } dev_hold(dev); - event->dev = dev; spin_lock_irqsave(&lweventlist_lock, flags); - list_add_tail(&event->list, &lweventlist); + dev->link_watch_next = lweventlist; + lweventlist = dev; spin_unlock_irqrestore(&lweventlist_lock, flags); if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) {