diff options
author | Sven Wegener <sven.wegener@stealer.net> | 2008-08-10 05:17:59 -0400 |
---|---|---|
committer | Sven Wegener <sven.wegener@stealer.net> | 2008-08-11 05:45:40 -0400 |
commit | 8ab19ea36c5c5340ff598e4d15fc084eb65671dc (patch) | |
tree | 031f48201a1e3a07a22a8f6734d0bb1c806b2c28 /net/ipv4/ipvs/ip_vs_est.c | |
parent | bc0fde2fad007a81ecffceb25a893a6c3f1ed767 (diff) |
ipvs: Fix possible deadlock in estimator code
There is a slight chance for a deadlock in the estimator code. We can't call
del_timer_sync() while holding our lock, as the timer might be active and
spinning for the lock on another cpu. Work around this issue by using
try_to_del_timer_sync() and releasing the lock. We could actually delete the
timer outside of our lock, as the add and kill functions are only every called
from userspace via [gs]etsockopt() and are serialized by a mutex, but better
make this explicit.
Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
Cc: stable <stable@kernel.org>
Acked-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net/ipv4/ipvs/ip_vs_est.c')
-rw-r--r-- | net/ipv4/ipvs/ip_vs_est.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c index bc04eedd6dbb..1d6e58e502fd 100644 --- a/net/ipv4/ipvs/ip_vs_est.c +++ b/net/ipv4/ipvs/ip_vs_est.c | |||
@@ -170,8 +170,11 @@ void ip_vs_kill_estimator(struct ip_vs_stats *stats) | |||
170 | kfree(est); | 170 | kfree(est); |
171 | killed++; | 171 | killed++; |
172 | } | 172 | } |
173 | if (killed && est_list == NULL) | 173 | while (killed && !est_list && try_to_del_timer_sync(&est_timer) < 0) { |
174 | del_timer_sync(&est_timer); | 174 | write_unlock_bh(&est_lock); |
175 | cpu_relax(); | ||
176 | write_lock_bh(&est_lock); | ||
177 | } | ||
175 | write_unlock_bh(&est_lock); | 178 | write_unlock_bh(&est_lock); |
176 | } | 179 | } |
177 | 180 | ||