diff options
author | David S. Miller <davem@davemloft.net> | 2009-06-16 08:40:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-16 08:40:30 -0400 |
commit | 14ebaf81e13ce66bff275380b246796fd16cbfa1 (patch) | |
tree | 6da2824a42a07f325787130d093e1a986fa29110 /net/x25 | |
parent | a1870b9cc280fe16fed13994810f8a1687be3bcf (diff) |
x25: Fix sleep from timer on socket destroy.
If socket destuction gets delayed to a timer, we try to
lock_sock() from that timer which won't work.
Use bh_lock_sock() in that case.
Signed-off-by: David S. Miller <davem@davemloft.net>
Tested-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'net/x25')
-rw-r--r-- | net/x25/af_x25.c | 23 | ||||
-rw-r--r-- | net/x25/x25_timer.c | 2 |
2 files changed, 19 insertions, 6 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index ed80af8ca5fb..c51f3095739c 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -332,14 +332,14 @@ static unsigned int x25_new_lci(struct x25_neigh *nb) | |||
332 | /* | 332 | /* |
333 | * Deferred destroy. | 333 | * Deferred destroy. |
334 | */ | 334 | */ |
335 | void x25_destroy_socket(struct sock *); | 335 | static void __x25_destroy_socket(struct sock *); |
336 | 336 | ||
337 | /* | 337 | /* |
338 | * handler for deferred kills. | 338 | * handler for deferred kills. |
339 | */ | 339 | */ |
340 | static void x25_destroy_timer(unsigned long data) | 340 | static void x25_destroy_timer(unsigned long data) |
341 | { | 341 | { |
342 | x25_destroy_socket((struct sock *)data); | 342 | x25_destroy_socket_from_timer((struct sock *)data); |
343 | } | 343 | } |
344 | 344 | ||
345 | /* | 345 | /* |
@@ -349,12 +349,10 @@ static void x25_destroy_timer(unsigned long data) | |||
349 | * will touch it and we are (fairly 8-) ) safe. | 349 | * will touch it and we are (fairly 8-) ) safe. |
350 | * Not static as it's used by the timer | 350 | * Not static as it's used by the timer |
351 | */ | 351 | */ |
352 | void x25_destroy_socket(struct sock *sk) | 352 | static void __x25_destroy_socket(struct sock *sk) |
353 | { | 353 | { |
354 | struct sk_buff *skb; | 354 | struct sk_buff *skb; |
355 | 355 | ||
356 | sock_hold(sk); | ||
357 | lock_sock(sk); | ||
358 | x25_stop_heartbeat(sk); | 356 | x25_stop_heartbeat(sk); |
359 | x25_stop_timer(sk); | 357 | x25_stop_timer(sk); |
360 | 358 | ||
@@ -385,7 +383,22 @@ void x25_destroy_socket(struct sock *sk) | |||
385 | /* drop last reference so sock_put will free */ | 383 | /* drop last reference so sock_put will free */ |
386 | __sock_put(sk); | 384 | __sock_put(sk); |
387 | } | 385 | } |
386 | } | ||
388 | 387 | ||
388 | void x25_destroy_socket_from_timer(struct sock *sk) | ||
389 | { | ||
390 | sock_hold(sk); | ||
391 | bh_lock_sock(sk); | ||
392 | __x25_destroy_socket(sk); | ||
393 | bh_unlock_sock(sk); | ||
394 | sock_put(sk); | ||
395 | } | ||
396 | |||
397 | static void x25_destroy_socket(struct sock *sk) | ||
398 | { | ||
399 | sock_hold(sk); | ||
400 | lock_sock(sk); | ||
401 | __x25_destroy_socket(sk); | ||
389 | release_sock(sk); | 402 | release_sock(sk); |
390 | sock_put(sk); | 403 | sock_put(sk); |
391 | } | 404 | } |
diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c index d3e3e54db936..5c5db1a36399 100644 --- a/net/x25/x25_timer.c +++ b/net/x25/x25_timer.c | |||
@@ -113,7 +113,7 @@ static void x25_heartbeat_expiry(unsigned long param) | |||
113 | (sk->sk_state == TCP_LISTEN && | 113 | (sk->sk_state == TCP_LISTEN && |
114 | sock_flag(sk, SOCK_DEAD))) { | 114 | sock_flag(sk, SOCK_DEAD))) { |
115 | bh_unlock_sock(sk); | 115 | bh_unlock_sock(sk); |
116 | x25_destroy_socket(sk); | 116 | x25_destroy_socket_from_timer(sk); |
117 | return; | 117 | return; |
118 | } | 118 | } |
119 | break; | 119 | break; |