|
@@ -416,10 +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 pppol2tp_session *ps;
|
|
|
+
|
|
|
+ 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
|
|
@@ -439,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)
|
|
@@ -470,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
|
|
@@ -786,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);
|