summaryrefslogtreecommitdiffstats
path: root/net/l2tp/l2tp_ppp.c
diff options
context:
space:
mode:
authorTom Parkin <tparkin@katalix.com>2013-03-19 06:11:23 +0000
committerDavid S. Miller <davem@davemloft.net>2013-03-20 12:10:39 -0400
commitf6e16b299bacaa71c6604a784f2d088a966f8c23 (patch)
tree115d199ee9cd9fb9dbc296d3daad259cd9e0d682 /net/l2tp/l2tp_ppp.c
parent7b7c0719cd7afee725b920d75ec6a500b76107e6 (diff)
downloadlinux-f6e16b299bacaa71c6604a784f2d088a966f8c23.tar.gz
linux-f6e16b299bacaa71c6604a784f2d088a966f8c23.tar.bz2
linux-f6e16b299bacaa71c6604a784f2d088a966f8c23.zip
l2tp: unhash l2tp sessions on delete, not on free
If we postpone unhashing of l2tp sessions until the structure is freed, we risk: 1. further packets arriving and getting queued while the pseudowire is being closed down 2. the recv path hitting "scheduling while atomic" errors in the case that recv drops the last reference to a session and calls l2tp_session_free while in atomic context As such, l2tp sessions should be unhashed from l2tp_core data structures early in the teardown process prior to calling pseudowire close. For pseudowires like l2tp_ppp which have multiple shutdown codepaths, provide an unhash hook. Signed-off-by: Tom Parkin <tparkin@katalix.com> Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp/l2tp_ppp.c')
-rw-r--r--net/l2tp/l2tp_ppp.c12
1 files changed, 3 insertions, 9 deletions
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 9d0eb8c13530..637a341c1e2d 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -466,19 +466,12 @@ static void pppol2tp_session_close(struct l2tp_session *session)
*/
static void pppol2tp_session_destruct(struct sock *sk)
{
- struct l2tp_session *session;
-
- if (sk->sk_user_data != NULL) {
- session = sk->sk_user_data;
- if (session == NULL)
- goto out;
-
+ struct l2tp_session *session = sk->sk_user_data;
+ if (session) {
sk->sk_user_data = NULL;
BUG_ON(session->magic != L2TP_SESSION_MAGIC);
l2tp_session_dec_refcount(session);
}
-
-out:
return;
}
@@ -509,6 +502,7 @@ static int pppol2tp_release(struct socket *sock)
/* Purge any queued data */
if (session != NULL) {
+ __l2tp_session_unhash(session);
l2tp_session_queue_purge(session);
sock_put(sk);
}