diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2005-10-23 02:37:48 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2005-10-23 02:37:48 -0400 |
commit | 6fb9974f49f7a6032118c5b6caa6e08e7097913e (patch) | |
tree | a1e8f77c1c5cd6a45842f4f02582bb583e6d1019 /net | |
parent | 203755029e063066ecc4cf5eee1110ab946c2d88 (diff) |
[NEIGH] Fix add_timer race in neigh_add_timer
neigh_add_timer cannot use add_timer unconditionally. The reason is that
by the time it has obtained the write lock someone else (e.g., neigh_update)
could have already added a new timer.
So it should only use mod_timer and deal with its return value accordingly.
This bug would have led to rare neighbour cache entry leaks.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/neighbour.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 766caa0dd930..37d8d8c29522 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -816,10 +816,10 @@ static void neigh_timer_handler(unsigned long arg) | |||
816 | } | 816 | } |
817 | 817 | ||
818 | if (neigh->nud_state & NUD_IN_TIMER) { | 818 | if (neigh->nud_state & NUD_IN_TIMER) { |
819 | neigh_hold(neigh); | ||
820 | if (time_before(next, jiffies + HZ/2)) | 819 | if (time_before(next, jiffies + HZ/2)) |
821 | next = jiffies + HZ/2; | 820 | next = jiffies + HZ/2; |
822 | neigh_add_timer(neigh, next); | 821 | if (!mod_timer(&neigh->timer, next)) |
822 | neigh_hold(neigh); | ||
823 | } | 823 | } |
824 | if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { | 824 | if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { |
825 | struct sk_buff *skb = skb_peek(&neigh->arp_queue); | 825 | struct sk_buff *skb = skb_peek(&neigh->arp_queue); |