diff options
| author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-05-09 03:17:30 -0400 |
|---|---|---|
| committer | David S. Miller <davem@sunset.davemloft.net> | 2007-05-11 02:45:28 -0400 |
| commit | d9568ba91b1fdd1ea4fdbf9fcc76b867cca6c1d5 (patch) | |
| tree | da1f4e40d5d0a5e2ff3d5b6ca077917e0af71144 | |
| parent | db0ccffed91e234cad99a35f07d5a322f410baa2 (diff) | |
[NET] link_watch: Always schedule urgent events
Urgent events may be delayed if we already have a non-urgent event
queued for that device. This patch changes this by making sure that
an urgent event is always looked at immediately.
I've replaced the LW_RUNNING flag by LW_URGENT since whether work
is scheduled is already kept track by the work queue system.
The only complication is that we have to provide some exclusion for
the setting linkwatch_nextevent which is available in the actual
work function.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/core/link_watch.c | 60 |
1 files changed, 41 insertions, 19 deletions
diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 4674ae574128..a5e372b9ec4d 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | enum lw_bits { | 28 | enum lw_bits { |
| 29 | LW_RUNNING = 0, | 29 | LW_URGENT = 0, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | static unsigned long linkwatch_flags; | 32 | static unsigned long linkwatch_flags; |
| @@ -95,18 +95,41 @@ static void linkwatch_add_event(struct net_device *dev) | |||
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | 97 | ||
| 98 | static void linkwatch_schedule_work(unsigned long delay) | 98 | static void linkwatch_schedule_work(int urgent) |
| 99 | { | 99 | { |
| 100 | if (test_and_set_bit(LW_RUNNING, &linkwatch_flags)) | 100 | unsigned long delay = linkwatch_nextevent - jiffies; |
| 101 | |||
| 102 | if (test_bit(LW_URGENT, &linkwatch_flags)) | ||
| 101 | return; | 103 | return; |
| 102 | 104 | ||
| 103 | /* If we wrap around we'll delay it by at most HZ. */ | 105 | /* Minimise down-time: drop delay for up event. */ |
| 104 | if (delay > HZ) { | 106 | if (urgent) { |
| 105 | linkwatch_nextevent = jiffies; | 107 | if (test_and_set_bit(LW_URGENT, &linkwatch_flags)) |
| 108 | return; | ||
| 106 | delay = 0; | 109 | delay = 0; |
| 107 | } | 110 | } |
| 108 | 111 | ||
| 109 | schedule_delayed_work(&linkwatch_work, delay); | 112 | /* If we wrap around we'll delay it by at most HZ. */ |
| 113 | if (delay > HZ) | ||
| 114 | delay = 0; | ||
| 115 | |||
| 116 | /* | ||
| 117 | * This is true if we've scheduled it immeditately or if we don't | ||
| 118 | * need an immediate execution and it's already pending. | ||
| 119 | */ | ||
| 120 | if (schedule_delayed_work(&linkwatch_work, delay) == !delay) | ||
| 121 | return; | ||
| 122 | |||
| 123 | /* Don't bother if there is nothing urgent. */ | ||
| 124 | if (!test_bit(LW_URGENT, &linkwatch_flags)) | ||
| 125 | return; | ||
| 126 | |||
| 127 | /* It's already running which is good enough. */ | ||
| 128 | if (!cancel_delayed_work(&linkwatch_work)) | ||
| 129 | return; | ||
| 130 | |||
| 131 | /* Otherwise we reschedule it again for immediate exection. */ | ||
| 132 | schedule_delayed_work(&linkwatch_work, 0); | ||
| 110 | } | 133 | } |
| 111 | 134 | ||
| 112 | 135 | ||
| @@ -123,7 +146,11 @@ static void __linkwatch_run_queue(int urgent_only) | |||
| 123 | */ | 146 | */ |
| 124 | if (!urgent_only) | 147 | if (!urgent_only) |
| 125 | linkwatch_nextevent = jiffies + HZ; | 148 | linkwatch_nextevent = jiffies + HZ; |
| 126 | clear_bit(LW_RUNNING, &linkwatch_flags); | 149 | /* Limit wrap-around effect on delay. */ |
| 150 | else if (time_after(linkwatch_nextevent, jiffies + HZ)) | ||
| 151 | linkwatch_nextevent = jiffies; | ||
| 152 | |||
| 153 | clear_bit(LW_URGENT, &linkwatch_flags); | ||
| 127 | 154 | ||
| 128 | spin_lock_irq(&lweventlist_lock); | 155 | spin_lock_irq(&lweventlist_lock); |
| 129 | next = lweventlist; | 156 | next = lweventlist; |
| @@ -166,7 +193,7 @@ static void __linkwatch_run_queue(int urgent_only) | |||
| 166 | } | 193 | } |
| 167 | 194 | ||
| 168 | if (lweventlist) | 195 | if (lweventlist) |
| 169 | linkwatch_schedule_work(linkwatch_nextevent - jiffies); | 196 | linkwatch_schedule_work(0); |
| 170 | } | 197 | } |
| 171 | 198 | ||
| 172 | 199 | ||
| @@ -187,21 +214,16 @@ static void linkwatch_event(struct work_struct *dummy) | |||
| 187 | 214 | ||
| 188 | void linkwatch_fire_event(struct net_device *dev) | 215 | void linkwatch_fire_event(struct net_device *dev) |
| 189 | { | 216 | { |
| 190 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { | 217 | int urgent = linkwatch_urgent_event(dev); |
| 191 | unsigned long delay; | ||
| 192 | 218 | ||
| 219 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { | ||
| 193 | dev_hold(dev); | 220 | dev_hold(dev); |
| 194 | 221 | ||
| 195 | linkwatch_add_event(dev); | 222 | linkwatch_add_event(dev); |
| 223 | } else if (!urgent) | ||
| 224 | return; | ||
| 196 | 225 | ||
| 197 | delay = linkwatch_nextevent - jiffies; | 226 | linkwatch_schedule_work(urgent); |
| 198 | |||
| 199 | /* Minimise down-time: drop delay for up event. */ | ||
| 200 | if (linkwatch_urgent_event(dev)) | ||
| 201 | delay = 0; | ||
| 202 | |||
| 203 | linkwatch_schedule_work(delay); | ||
| 204 | } | ||
| 205 | } | 227 | } |
| 206 | 228 | ||
| 207 | EXPORT_SYMBOL(linkwatch_fire_event); | 229 | EXPORT_SYMBOL(linkwatch_fire_event); |
