Commit 73d33bd0 authored by James Chapman's avatar James Chapman Committed by Jakub Kicinski

l2tp: avoid using drain_workqueue in l2tp_pre_exit_net

Recent commit fc7ec7f5 ("l2tp: delete sessions using work queue")
incorrectly uses drain_workqueue. The use of drain_workqueue in
l2tp_pre_exit_net is flawed because the workqueue is shared by all
nets and it is therefore possible for new work items to be queued
for other nets while drain_workqueue runs.

Instead of using drain_workqueue, use __flush_workqueue twice. The
first one will run all tunnel delete work items and any work already
queued. When tunnel delete work items are run, they may queue
new session delete work items, which the second __flush_workqueue will
run.

In l2tp_exit_net, warn if any of the net's idr lists are not empty.

Fixes: fc7ec7f5 ("l2tp: delete sessions using work queue")
Signed-off-by: default avatarJames Chapman <jchapman@katalix.com>
Link: https://patch.msgid.link/20240823142257.692667-1-jchapman@katalix.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent aed7136a
......@@ -1859,14 +1859,14 @@ static __net_exit void l2tp_pre_exit_net(struct net *net)
rcu_read_unlock_bh();
if (l2tp_wq) {
/* ensure that all TUNNEL_DELETE work items are run before
* draining the work queue since TUNNEL_DELETE requests may
* queue SESSION_DELETE work items for each session in the
* tunnel. drain_workqueue may otherwise warn if SESSION_DELETE
* requests are queued while the work queue is being drained.
/* Run all TUNNEL_DELETE work items just queued. */
__flush_workqueue(l2tp_wq);
/* Each TUNNEL_DELETE work item will queue a SESSION_DELETE
* work item for each session in the tunnel. Flush the
* workqueue again to process these.
*/
__flush_workqueue(l2tp_wq);
drain_workqueue(l2tp_wq);
}
}
......@@ -1874,8 +1874,11 @@ static __net_exit void l2tp_exit_net(struct net *net)
{
struct l2tp_net *pn = l2tp_pernet(net);
WARN_ON_ONCE(!idr_is_empty(&pn->l2tp_v2_session_idr));
idr_destroy(&pn->l2tp_v2_session_idr);
WARN_ON_ONCE(!idr_is_empty(&pn->l2tp_v3_session_idr));
idr_destroy(&pn->l2tp_v3_session_idr);
WARN_ON_ONCE(!idr_is_empty(&pn->l2tp_tunnel_idr));
idr_destroy(&pn->l2tp_tunnel_idr);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment