浏览代码

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>
David S. Miller 16 年之前
父节点
当前提交
14ebaf81e1
共有 3 个文件被更改,包括 20 次插入7 次删除
  1. 1 1
      include/net/x25.h
  2. 18 5
      net/x25/af_x25.c
  3. 1 1
      net/x25/x25_timer.c

+ 1 - 1
include/net/x25.h

@@ -187,7 +187,7 @@ extern int  x25_addr_ntoa(unsigned char *, struct x25_address *,
 extern int  x25_addr_aton(unsigned char *, struct x25_address *,
 extern int  x25_addr_aton(unsigned char *, struct x25_address *,
 			  struct x25_address *);
 			  struct x25_address *);
 extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
 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 int  x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
 extern void x25_kill_by_neigh(struct x25_neigh *);
 extern void x25_kill_by_neigh(struct x25_neigh *);
 
 

+ 18 - 5
net/x25/af_x25.c

@@ -332,14 +332,14 @@ static unsigned int x25_new_lci(struct x25_neigh *nb)
 /*
 /*
  *	Deferred destroy.
  *	Deferred destroy.
  */
  */
-void x25_destroy_socket(struct sock *);
+static void __x25_destroy_socket(struct sock *);
 
 
 /*
 /*
  *	handler for deferred kills.
  *	handler for deferred kills.
  */
  */
 static void x25_destroy_timer(unsigned long data)
 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.
  *	will touch it and we are (fairly 8-) ) safe.
  *	Not static as it's used by the timer
  *	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;
 	struct sk_buff *skb;
 
 
-	sock_hold(sk);
-	lock_sock(sk);
 	x25_stop_heartbeat(sk);
 	x25_stop_heartbeat(sk);
 	x25_stop_timer(sk);
 	x25_stop_timer(sk);
 
 
@@ -385,7 +383,22 @@ void x25_destroy_socket(struct sock *sk)
 		/* drop last reference so sock_put will free */
 		/* drop last reference so sock_put will free */
 		__sock_put(sk);
 		__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);
 	release_sock(sk);
 	sock_put(sk);
 	sock_put(sk);
 }
 }

+ 1 - 1
net/x25/x25_timer.c

@@ -113,7 +113,7 @@ static void x25_heartbeat_expiry(unsigned long param)
 			    (sk->sk_state == TCP_LISTEN &&
 			    (sk->sk_state == TCP_LISTEN &&
 			     sock_flag(sk, SOCK_DEAD))) {
 			     sock_flag(sk, SOCK_DEAD))) {
 				bh_unlock_sock(sk);
 				bh_unlock_sock(sk);
-				x25_destroy_socket(sk);
+				x25_destroy_socket_from_timer(sk);
 				return;
 				return;
 			}
 			}
 			break;
 			break;