diff options
author | James Chapman <[email protected]> | 2024-07-29 16:38:12 +0100 |
---|---|---|
committer | David S. Miller <[email protected]> | 2024-07-31 09:25:13 +0100 |
commit | 0aa45570c3241e3bdba1a8b5b30d200c819b5b15 (patch) | |
tree | db23f65675c903124d1b935c7766b751b3c164e9 | |
parent | 89b768ec2dfefaeba5212de14fc71368e12d06ba (diff) |
l2tp: add idr consistency check in session_register
l2tp_session_register uses an idr_alloc then idr_replace pattern to
insert sessions into the session IDR. To catch invalid locking, add a
WARN_ON_ONCE if the IDR entry is modified by another thread between
alloc and replace steps.
Also add comments to make expectations clear.
Signed-off-by: James Chapman <[email protected]>
Signed-off-by: Tom Parkin <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
-rw-r--r-- | net/l2tp/l2tp_core.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index cd9b157e8b4d..fd03c17dd20c 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -474,6 +474,7 @@ int l2tp_session_register(struct l2tp_session *session, { struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); struct l2tp_session *other_session = NULL; + void *old = NULL; u32 session_key; int err; @@ -517,13 +518,19 @@ int l2tp_session_register(struct l2tp_session *session, WRITE_ONCE(session->tunnel, tunnel); list_add_rcu(&session->list, &tunnel->session_list); + /* this makes session available to lockless getters */ if (tunnel->version == L2TP_HDR_VER_3) { if (!other_session) - idr_replace(&pn->l2tp_v3_session_idr, session, session_key); + old = idr_replace(&pn->l2tp_v3_session_idr, session, session_key); } else { - idr_replace(&pn->l2tp_v2_session_idr, session, session_key); + old = idr_replace(&pn->l2tp_v2_session_idr, session, session_key); } + /* old should be NULL, unless something removed or modified + * the IDR entry after our idr_alloc_32 above (which shouldn't + * happen). + */ + WARN_ON_ONCE(old); out: spin_unlock_bh(&pn->l2tp_session_idr_lock); spin_unlock_bh(&tunnel->list_lock); |