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>
This commit is contained in:
parent
a1870b9cc2
commit
14ebaf81e1
3 changed files with 20 additions and 7 deletions
|
@ -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 *);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue