diff mbox series

[net-next,v2] l2tp: avoid using drain_workqueue in l2tp_pre_exit_net

Message ID 20240823142257.692667-1-jchapman@katalix.com (mailing list archive)
State Accepted
Commit 73d33bd063c4cfef3db17f9bec3d202928ed8631
Delegated to: Netdev Maintainers
Headers show
Series [net-next,v2] l2tp: avoid using drain_workqueue in l2tp_pre_exit_net | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 16 this patch: 16
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/build_clang success Errors and warnings before: 16 this patch: 16
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 16 this patch: 16
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 31 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-08-25--21-00 (tests: 714)

Commit Message

James Chapman Aug. 23, 2024, 2:22 p.m. UTC
Recent commit fc7ec7f554d7 ("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: fc7ec7f554d7 ("l2tp: delete sessions using work queue")
Signed-off-by: James Chapman <jchapman@katalix.com>
---
 v2:
   - remove unneeded per-net net_closing flag (paolo)
   - remove loop waiting for idr lists to be empty (paolo)
   - add correct fixes tag (paolo)
   - in l2tp_exit_net warn if idr lists not empty
 v1: https://lore.kernel.org/netdev/20240819145208.3209296-1-jchapman@katalix.com/
---
 net/l2tp/l2tp_core.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

Comments

patchwork-bot+netdevbpf@kernel.org Aug. 27, 2024, 8:40 p.m. UTC | #1
Hello:

This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Fri, 23 Aug 2024 15:22:57 +0100 you wrote:
> Recent commit fc7ec7f554d7 ("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.
> 
> [...]

Here is the summary with links:
  - [net-next,v2] l2tp: avoid using drain_workqueue in l2tp_pre_exit_net
    https://git.kernel.org/netdev/net-next/c/73d33bd063c4

You are awesome, thank you!
diff mbox series

Patch

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index af87c781d6a6..e5e492284997 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1856,14 +1856,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);
 	}
 }
 
@@ -1871,8 +1871,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);
 }