Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+20 -7
+1 -1
include/net/x25.h
··· 187 187 extern int x25_addr_aton(unsigned char *, struct x25_address *, 188 188 struct x25_address *); 189 189 extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *); 190 - extern void x25_destroy_socket(struct sock *); 190 + extern void x25_destroy_socket_from_timer(struct sock *); 191 191 extern int x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int); 192 192 extern void x25_kill_by_neigh(struct x25_neigh *); 193 193
+18 -5
net/x25/af_x25.c
··· 332 332 /* 333 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 338 * handler for deferred kills. 339 339 */ 340 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 349 * will touch it and we are (fairly 8-) ) safe. 350 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 354 struct sk_buff *skb; 355 355 356 - sock_hold(sk); 357 - lock_sock(sk); 358 356 x25_stop_heartbeat(sk); 359 357 x25_stop_timer(sk); 360 358 ··· 383 385 /* drop last reference so sock_put will free */ 384 386 __sock_put(sk); 385 387 } 388 + } 386 389 390 + void x25_destroy_socket_from_timer(struct sock *sk) 391 + { 392 + sock_hold(sk); 393 + bh_lock_sock(sk); 394 + __x25_destroy_socket(sk); 395 + bh_unlock_sock(sk); 396 + sock_put(sk); 397 + } 398 + 399 + static void x25_destroy_socket(struct sock *sk) 400 + { 401 + sock_hold(sk); 402 + lock_sock(sk); 403 + __x25_destroy_socket(sk); 387 404 release_sock(sk); 388 405 sock_put(sk); 389 406 }
+1 -1
net/x25/x25_timer.c
··· 113 113 (sk->sk_state == TCP_LISTEN && 114 114 sock_flag(sk, SOCK_DEAD))) { 115 115 bh_unlock_sock(sk); 116 - x25_destroy_socket(sk); 116 + x25_destroy_socket_from_timer(sk); 117 117 return; 118 118 } 119 119 break;