diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/link_watch.c | 90 |
1 files changed, 67 insertions, 23 deletions
diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 71a35da275d4..b5f45799c2f3 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c | |||
@@ -77,11 +77,52 @@ static void rfc2863_policy(struct net_device *dev) | |||
77 | } | 77 | } |
78 | 78 | ||
79 | 79 | ||
80 | /* Must be called with the rtnl semaphore held */ | 80 | static int linkwatch_urgent_event(struct net_device *dev) |
81 | void linkwatch_run_queue(void) | 81 | { |
82 | return netif_running(dev) && netif_carrier_ok(dev) && | ||
83 | dev->qdisc != dev->qdisc_sleeping; | ||
84 | } | ||
85 | |||
86 | |||
87 | static void linkwatch_add_event(struct net_device *dev) | ||
88 | { | ||
89 | unsigned long flags; | ||
90 | |||
91 | spin_lock_irqsave(&lweventlist_lock, flags); | ||
92 | dev->link_watch_next = lweventlist; | ||
93 | lweventlist = dev; | ||
94 | spin_unlock_irqrestore(&lweventlist_lock, flags); | ||
95 | } | ||
96 | |||
97 | |||
98 | static void linkwatch_schedule_work(unsigned long delay) | ||
99 | { | ||
100 | if (test_and_set_bit(LW_RUNNING, &linkwatch_flags)) | ||
101 | return; | ||
102 | |||
103 | /* If we wrap around we'll delay it by at most HZ. */ | ||
104 | if (delay > HZ) | ||
105 | delay = 0; | ||
106 | |||
107 | schedule_delayed_work(&linkwatch_work, delay); | ||
108 | } | ||
109 | |||
110 | |||
111 | static void __linkwatch_run_queue(int urgent_only) | ||
82 | { | 112 | { |
83 | struct net_device *next; | 113 | struct net_device *next; |
84 | 114 | ||
115 | /* | ||
116 | * Limit the number of linkwatch events to one | ||
117 | * per second so that a runaway driver does not | ||
118 | * cause a storm of messages on the netlink | ||
119 | * socket. This limit does not apply to up events | ||
120 | * while the device qdisc is down. | ||
121 | */ | ||
122 | if (!urgent_only) | ||
123 | linkwatch_nextevent = jiffies + HZ; | ||
124 | clear_bit(LW_RUNNING, &linkwatch_flags); | ||
125 | |||
85 | spin_lock_irq(&lweventlist_lock); | 126 | spin_lock_irq(&lweventlist_lock); |
86 | next = lweventlist; | 127 | next = lweventlist; |
87 | lweventlist = NULL; | 128 | lweventlist = NULL; |
@@ -92,6 +133,11 @@ void linkwatch_run_queue(void) | |||
92 | 133 | ||
93 | next = dev->link_watch_next; | 134 | next = dev->link_watch_next; |
94 | 135 | ||
136 | if (urgent_only && !linkwatch_urgent_event(dev)) { | ||
137 | linkwatch_add_event(dev); | ||
138 | continue; | ||
139 | } | ||
140 | |||
95 | /* | 141 | /* |
96 | * Make sure the above read is complete since it can be | 142 | * Make sure the above read is complete since it can be |
97 | * rewritten as soon as we clear the bit below. | 143 | * rewritten as soon as we clear the bit below. |
@@ -116,21 +162,23 @@ void linkwatch_run_queue(void) | |||
116 | 162 | ||
117 | dev_put(dev); | 163 | dev_put(dev); |
118 | } | 164 | } |
165 | |||
166 | if (lweventlist) | ||
167 | linkwatch_schedule_work(linkwatch_nextevent - jiffies); | ||
119 | } | 168 | } |
120 | 169 | ||
121 | 170 | ||
122 | static void linkwatch_event(struct work_struct *dummy) | 171 | /* Must be called with the rtnl semaphore held */ |
172 | void linkwatch_run_queue(void) | ||
123 | { | 173 | { |
124 | /* Limit the number of linkwatch events to one | 174 | __linkwatch_run_queue(0); |
125 | * per second so that a runaway driver does not | 175 | } |
126 | * cause a storm of messages on the netlink | 176 | |
127 | * socket | ||
128 | */ | ||
129 | linkwatch_nextevent = jiffies + HZ; | ||
130 | clear_bit(LW_RUNNING, &linkwatch_flags); | ||
131 | 177 | ||
178 | static void linkwatch_event(struct work_struct *dummy) | ||
179 | { | ||
132 | rtnl_lock(); | 180 | rtnl_lock(); |
133 | linkwatch_run_queue(); | 181 | __linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies)); |
134 | rtnl_unlock(); | 182 | rtnl_unlock(); |
135 | } | 183 | } |
136 | 184 | ||
@@ -138,23 +186,19 @@ static void linkwatch_event(struct work_struct *dummy) | |||
138 | void linkwatch_fire_event(struct net_device *dev) | 186 | void linkwatch_fire_event(struct net_device *dev) |
139 | { | 187 | { |
140 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { | 188 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { |
141 | unsigned long flags; | 189 | unsigned long delay; |
142 | 190 | ||
143 | dev_hold(dev); | 191 | dev_hold(dev); |
144 | 192 | ||
145 | spin_lock_irqsave(&lweventlist_lock, flags); | 193 | linkwatch_add_event(dev); |
146 | dev->link_watch_next = lweventlist; | ||
147 | lweventlist = dev; | ||
148 | spin_unlock_irqrestore(&lweventlist_lock, flags); | ||
149 | 194 | ||
150 | if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { | 195 | delay = linkwatch_nextevent - jiffies; |
151 | unsigned long delay = linkwatch_nextevent - jiffies; | ||
152 | 196 | ||
153 | /* If we wrap around we'll delay it by at most HZ. */ | 197 | /* Minimise down-time: drop delay for up event. */ |
154 | if (delay > HZ) | 198 | if (linkwatch_urgent_event(dev)) |
155 | delay = 0; | 199 | delay = 0; |
156 | schedule_delayed_work(&linkwatch_work, delay); | 200 | |
157 | } | 201 | linkwatch_schedule_work(delay); |
158 | } | 202 | } |
159 | } | 203 | } |
160 | 204 | ||