diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/link_watch.c | 50 |
1 files changed, 15 insertions, 35 deletions
diff --git a/net/core/link_watch.c b/net/core/link_watch.c index e3c26a9ccad6..71a35da275d4 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
20 | #include <linux/jiffies.h> | 20 | #include <linux/jiffies.h> |
21 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
22 | #include <linux/list.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
25 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
@@ -28,7 +27,6 @@ | |||
28 | 27 | ||
29 | enum lw_bits { | 28 | enum lw_bits { |
30 | LW_RUNNING = 0, | 29 | LW_RUNNING = 0, |
31 | LW_SE_USED | ||
32 | }; | 30 | }; |
33 | 31 | ||
34 | static unsigned long linkwatch_flags; | 32 | static unsigned long linkwatch_flags; |
@@ -37,17 +35,9 @@ static unsigned long linkwatch_nextevent; | |||
37 | static void linkwatch_event(struct work_struct *dummy); | 35 | static void linkwatch_event(struct work_struct *dummy); |
38 | static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); | 36 | static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); |
39 | 37 | ||
40 | static LIST_HEAD(lweventlist); | 38 | static struct net_device *lweventlist; |
41 | static DEFINE_SPINLOCK(lweventlist_lock); | 39 | static DEFINE_SPINLOCK(lweventlist_lock); |
42 | 40 | ||
43 | struct lw_event { | ||
44 | struct list_head list; | ||
45 | struct net_device *dev; | ||
46 | }; | ||
47 | |||
48 | /* Avoid kmalloc() for most systems */ | ||
49 | static struct lw_event singleevent; | ||
50 | |||
51 | static unsigned char default_operstate(const struct net_device *dev) | 41 | static unsigned char default_operstate(const struct net_device *dev) |
52 | { | 42 | { |
53 | if (!netif_carrier_ok(dev)) | 43 | if (!netif_carrier_ok(dev)) |
@@ -90,21 +80,23 @@ static void rfc2863_policy(struct net_device *dev) | |||
90 | /* Must be called with the rtnl semaphore held */ | 80 | /* Must be called with the rtnl semaphore held */ |
91 | void linkwatch_run_queue(void) | 81 | void linkwatch_run_queue(void) |
92 | { | 82 | { |
93 | struct list_head head, *n, *next; | 83 | struct net_device *next; |
94 | 84 | ||
95 | spin_lock_irq(&lweventlist_lock); | 85 | spin_lock_irq(&lweventlist_lock); |
96 | list_replace_init(&lweventlist, &head); | 86 | next = lweventlist; |
87 | lweventlist = NULL; | ||
97 | spin_unlock_irq(&lweventlist_lock); | 88 | spin_unlock_irq(&lweventlist_lock); |
98 | 89 | ||
99 | list_for_each_safe(n, next, &head) { | 90 | while (next) { |
100 | struct lw_event *event = list_entry(n, struct lw_event, list); | 91 | struct net_device *dev = next; |
101 | struct net_device *dev = event->dev; | ||
102 | 92 | ||
103 | if (event == &singleevent) { | 93 | next = dev->link_watch_next; |
104 | clear_bit(LW_SE_USED, &linkwatch_flags); | 94 | |
105 | } else { | 95 | /* |
106 | kfree(event); | 96 | * Make sure the above read is complete since it can be |
107 | } | 97 | * rewritten as soon as we clear the bit below. |
98 | */ | ||
99 | smp_mb__before_clear_bit(); | ||
108 | 100 | ||
109 | /* We are about to handle this device, | 101 | /* We are about to handle this device, |
110 | * so new events can be accepted | 102 | * so new events can be accepted |
@@ -147,24 +139,12 @@ void linkwatch_fire_event(struct net_device *dev) | |||
147 | { | 139 | { |
148 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { | 140 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { |
149 | unsigned long flags; | 141 | unsigned long flags; |
150 | struct lw_event *event; | ||
151 | |||
152 | if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) { | ||
153 | event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC); | ||
154 | |||
155 | if (unlikely(event == NULL)) { | ||
156 | clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); | ||
157 | return; | ||
158 | } | ||
159 | } else { | ||
160 | event = &singleevent; | ||
161 | } | ||
162 | 142 | ||
163 | dev_hold(dev); | 143 | dev_hold(dev); |
164 | event->dev = dev; | ||
165 | 144 | ||
166 | spin_lock_irqsave(&lweventlist_lock, flags); | 145 | spin_lock_irqsave(&lweventlist_lock, flags); |
167 | list_add_tail(&event->list, &lweventlist); | 146 | dev->link_watch_next = lweventlist; |
147 | lweventlist = dev; | ||
168 | spin_unlock_irqrestore(&lweventlist_lock, flags); | 148 | spin_unlock_irqrestore(&lweventlist_lock, flags); |
169 | 149 | ||
170 | if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { | 150 | if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { |