Skip to content

Commit fc7ec7f

Browse files
j-c-hdavem330
authored andcommitted
l2tp: delete sessions using work queue
When a tunnel is closed, l2tp_tunnel_closeall closes all sessions in the tunnel. Move the work of deleting each session to the work queue so that sessions are deleted using the same codepath whether they are closed by user API request or their parent tunnel is closing. This also avoids the locking dance in l2tp_tunnel_closeall where the tunnel's session list lock was unlocked and relocked in the loop. In l2tp_exit_net, use drain_workqueue instead of flush_workqueue because the processing of tunnel_delete work may queue session_delete work items which must also be processed. Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: Tom Parkin <tparkin@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 29717a4 commit fc7ec7f

File tree

2 files changed

+21
-16
lines changed

2 files changed

+21
-16
lines changed

net/l2tp/l2tp_core.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,18 +1282,8 @@ static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
12821282

12831283
spin_lock_bh(&tunnel->list_lock);
12841284
tunnel->acpt_newsess = false;
1285-
for (;;) {
1286-
session = list_first_entry_or_null(&tunnel->session_list,
1287-
struct l2tp_session, list);
1288-
if (!session)
1289-
break;
1290-
l2tp_session_inc_refcount(session);
1291-
list_del_init(&session->list);
1292-
spin_unlock_bh(&tunnel->list_lock);
1285+
list_for_each_entry(session, &tunnel->session_list, list)
12931286
l2tp_session_delete(session);
1294-
spin_lock_bh(&tunnel->list_lock);
1295-
l2tp_session_dec_refcount(session);
1296-
}
12971287
spin_unlock_bh(&tunnel->list_lock);
12981288
}
12991289

@@ -1631,18 +1621,31 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
16311621

16321622
void l2tp_session_delete(struct l2tp_session *session)
16331623
{
1634-
if (test_and_set_bit(0, &session->dead))
1635-
return;
1624+
if (!test_and_set_bit(0, &session->dead)) {
1625+
trace_delete_session(session);
1626+
l2tp_session_inc_refcount(session);
1627+
queue_work(l2tp_wq, &session->del_work);
1628+
}
1629+
}
1630+
EXPORT_SYMBOL_GPL(l2tp_session_delete);
1631+
1632+
/* Workqueue session deletion function */
1633+
static void l2tp_session_del_work(struct work_struct *work)
1634+
{
1635+
struct l2tp_session *session = container_of(work, struct l2tp_session,
1636+
del_work);
16361637

1637-
trace_delete_session(session);
16381638
l2tp_session_unhash(session);
16391639
l2tp_session_queue_purge(session);
16401640
if (session->session_close)
16411641
(*session->session_close)(session);
16421642

1643+
/* drop initial ref */
1644+
l2tp_session_dec_refcount(session);
1645+
1646+
/* drop workqueue ref */
16431647
l2tp_session_dec_refcount(session);
16441648
}
1645-
EXPORT_SYMBOL_GPL(l2tp_session_delete);
16461649

16471650
/* We come here whenever a session's send_seq, cookie_len or
16481651
* l2specific_type parameters are set.
@@ -1694,6 +1697,7 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
16941697
INIT_HLIST_NODE(&session->hlist);
16951698
INIT_LIST_HEAD(&session->clist);
16961699
INIT_LIST_HEAD(&session->list);
1700+
INIT_WORK(&session->del_work, l2tp_session_del_work);
16971701

16981702
if (cfg) {
16991703
session->pwtype = cfg->pw_type;
@@ -1751,7 +1755,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
17511755
rcu_read_unlock_bh();
17521756

17531757
if (l2tp_wq)
1754-
flush_workqueue(l2tp_wq);
1758+
drain_workqueue(l2tp_wq);
17551759
rcu_barrier();
17561760

17571761
idr_destroy(&pn->l2tp_v2_session_idr);

net/l2tp/l2tp_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct l2tp_session {
102102
int reorder_skip; /* set if skip to next nr */
103103
enum l2tp_pwtype pwtype;
104104
struct l2tp_stats stats;
105+
struct work_struct del_work;
105106

106107
/* Session receive handler for data packets.
107108
* Each pseudowire implementation should implement this callback in order to

0 commit comments

Comments
 (0)