x25: Fix sleep from timer on socket destroy.
David S. Miller [Tue, 16 Jun 2009 12:40:30 +0000 (05:40 -0700)]
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>

include/net/x25.h
net/x25/af_x25.c
net/x25/x25_timer.c

index fc3f03d..2cda040 100644 (file)
@@ -187,7 +187,7 @@ extern int  x25_addr_ntoa(unsigned char *, struct x25_address *,
 extern int  x25_addr_aton(unsigned char *, struct x25_address *,
                          struct x25_address *);
 extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
-extern void x25_destroy_socket(struct sock *);
+extern void x25_destroy_socket_from_timer(struct sock *);
 extern int  x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
 extern void x25_kill_by_neigh(struct x25_neigh *);
 
index ed80af8..c51f309 100644 (file)
@@ -332,14 +332,14 @@ static unsigned int x25_new_lci(struct x25_neigh *nb)
 /*
  *     Deferred destroy.
  */
-void x25_destroy_socket(struct sock *);
+static void __x25_destroy_socket(struct sock *);
 
 /*
  *     handler for deferred kills.
  */
 static void x25_destroy_timer(unsigned long data)
 {
-       x25_destroy_socket((struct sock *)data);
+       x25_destroy_socket_from_timer((struct sock *)data);
 }
 
 /*
@@ -349,12 +349,10 @@ static void x25_destroy_timer(unsigned long data)
  *     will touch it and we are (fairly 8-) ) safe.
  *     Not static as it's used by the timer
  */
-void x25_destroy_socket(struct sock *sk)
+static void __x25_destroy_socket(struct sock *sk)
 {
        struct sk_buff *skb;
 
-       sock_hold(sk);
-       lock_sock(sk);
        x25_stop_heartbeat(sk);
        x25_stop_timer(sk);
 
@@ -385,7 +383,22 @@ void x25_destroy_socket(struct sock *sk)
                /* drop last reference so sock_put will free */
                __sock_put(sk);
        }
+}
 
+void x25_destroy_socket_from_timer(struct sock *sk)
+{
+       sock_hold(sk);
+       bh_lock_sock(sk);
+       __x25_destroy_socket(sk);
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
+
+static void x25_destroy_socket(struct sock *sk)
+{
+       sock_hold(sk);
+       lock_sock(sk);
+       __x25_destroy_socket(sk);
        release_sock(sk);
        sock_put(sk);
 }
index d3e3e54..5c5db1a 100644 (file)
@@ -113,7 +113,7 @@ static void x25_heartbeat_expiry(unsigned long param)
                            (sk->sk_state == TCP_LISTEN &&
                             sock_flag(sk, SOCK_DEAD))) {
                                bh_unlock_sock(sk);
-                               x25_destroy_socket(sk);
+                               x25_destroy_socket_from_timer(sk);
                                return;
                        }
                        break;