diff options
Diffstat (limited to 'net/l2tp/l2tp_ppp.c')
| -rw-r--r-- | net/l2tp/l2tp_ppp.c | 60 | 
1 files changed, 26 insertions, 34 deletions
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 59f246d7b290..3b02f24ea9ec 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -416,20 +416,28 @@ abort:   * Session (and tunnel control) socket create/destroy.   *****************************************************************************/ +static void pppol2tp_put_sk(struct rcu_head *head) +{ +	struct pppol2tp_session *ps; + +	ps = container_of(head, typeof(*ps), rcu); +	sock_put(ps->__sk); +} +  /* Called by l2tp_core when a session socket is being closed.   */  static void pppol2tp_session_close(struct l2tp_session *session)  { -	struct sock *sk; - -	BUG_ON(session->magic != L2TP_SESSION_MAGIC); +	struct pppol2tp_session *ps; -	sk = pppol2tp_session_get_sock(session); -	if (sk) { -		if (sk->sk_socket) -			inet_shutdown(sk->sk_socket, SEND_SHUTDOWN); -		sock_put(sk); -	} +	ps = l2tp_session_priv(session); +	mutex_lock(&ps->sk_lock); +	ps->__sk = rcu_dereference_protected(ps->sk, +					     lockdep_is_held(&ps->sk_lock)); +	RCU_INIT_POINTER(ps->sk, NULL); +	if (ps->__sk) +		call_rcu(&ps->rcu, pppol2tp_put_sk); +	mutex_unlock(&ps->sk_lock);  }  /* Really kill the session socket. (Called from sock_put() if @@ -449,14 +457,6 @@ static void pppol2tp_session_destruct(struct sock *sk)  	}  } -static void pppol2tp_put_sk(struct rcu_head *head) -{ -	struct pppol2tp_session *ps; - -	ps = container_of(head, typeof(*ps), rcu); -	sock_put(ps->__sk); -} -  /* Called when the PPPoX socket (session) is closed.   */  static int pppol2tp_release(struct socket *sock) @@ -480,26 +480,17 @@ static int pppol2tp_release(struct socket *sock)  	sock_orphan(sk);  	sock->sk = NULL; +	/* If the socket is associated with a session, +	 * l2tp_session_delete will call pppol2tp_session_close which +	 * will drop the session's ref on the socket. +	 */  	session = pppol2tp_sock_to_session(sk); - -	if (session != NULL) { -		struct pppol2tp_session *ps; - +	if (session) {  		l2tp_session_delete(session); - -		ps = l2tp_session_priv(session); -		mutex_lock(&ps->sk_lock); -		ps->__sk = rcu_dereference_protected(ps->sk, -						     lockdep_is_held(&ps->sk_lock)); -		RCU_INIT_POINTER(ps->sk, NULL); -		mutex_unlock(&ps->sk_lock); -		call_rcu(&ps->rcu, pppol2tp_put_sk); - -		/* Rely on the sock_put() call at the end of the function for -		 * dropping the reference held by pppol2tp_sock_to_session(). -		 * The last reference will be dropped by pppol2tp_put_sk(). -		 */ +		/* drop the ref obtained by pppol2tp_sock_to_session */ +		sock_put(sk);  	} +  	release_sock(sk);  	/* This will delete the session context via @@ -796,6 +787,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,  out_no_ppp:  	/* This is how we get the session context from the socket. */ +	sock_hold(sk);  	sk->sk_user_data = session;  	rcu_assign_pointer(ps->sk, sk);  	mutex_unlock(&ps->sk_lock);  | 

