From: Simon Wunderlich <sw@simonwunderlich.de>
To: netdev@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
b.a.t.m.a.n@lists.open-mesh.org,
Sven Eckelmann <sven@narfation.org>,
Sashiko <sashiko-bot@kernel.org>,
Simon Wunderlich <sw@simonwunderlich.de>
Subject: [PATCH net-next 6/9] batman-adv: tt: queue local DEL event under bucket lock
Date: Wed, 30 Sep 2026 11:45:55 +0200 [thread overview]
Message-ID: <20260930094558.3723766-7-sw@simonwunderlich.de> (raw)
In-Reply-To: <20260930094558.3723766-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
batadv_tt_local_remove() sets BATADV_TT_CLIENT_PENDING on an already
announced local entry and only afterwards queues the DEL change event. It
holds neither the hash bucket list_lock nor bat_priv->tt.commit_lock.
It can therefore be potentially interrupted in the middle:
CPU0 CPU1
batadv_tt_local_remove()
flags |= ..._PENDING;
batadv_tt_local_commit_changes()
..._purge_pending_clients()
hlist_del_rcu(&...->hash_entry);
batadv_tt_local_update_crc()
atomic_inc(&bat_priv->tt.vn);
batadv_tt_local_event()
/* DEL queued only now */
The client then disappears from the local table and from the CRC of the new
TTVN after batadv_tt_local_commit_changes() without a DEL change being
announced for it. Neighbours receiving the new CRC without previously
seeing the DEL will try to recover via a full table request.
Move the event into batadv_tt_local_mark_removed() and hold the bucket
list_lock of the entry around both the flag change and the DEL event to
avoid this scenario.
Fixes: 976b159b3c12 ("batman-adv: tt: use protected flag modifications")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831135117.574836-1-sw%40simonwunderlich.de?part=12
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 64 ++++++++++++++++++++----------
1 file changed, 44 insertions(+), 20 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index c904d67791f8f..c229c51cafa72 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1427,13 +1427,20 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
* @message: debug message describing the reason for the change
*
* Schedule the TT change announcement for the entry. The caller must already
- * have added BATADV_TT_CLIENT_PENDING to the @tt_local_entry
+ * have added BATADV_TT_CLIENT_PENDING to the @tt_local_entry and must hold the
+ * hash bucket list_lock of @tt_local_entry since setting the flag.
*/
static void
batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry,
u16 flags, const char *message)
{
+ struct batadv_hashtable *hash = bat_priv->tt.local_hash;
+ u32 i;
+
+ i = batadv_choose_tt(&tt_local_entry->common, hash->size);
+ lockdep_assert_held(&hash->list_locks[i]);
+
batadv_tt_local_event(bat_priv, tt_local_entry, flags);
batadv_dbg(BATADV_DBG_TT, bat_priv,
@@ -1443,20 +1450,37 @@ batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
}
/**
- * batadv_tt_local_mark_removed() - mark a local entry as removed
+ * batadv_tt_local_mark_removed() - mark a local entry as removed and queue DEL
+ * @bat_priv: the bat priv with all the mesh interface information
* @tt_local_entry: local TT entry to mark
+ * @message: message to append to the log on deletion
* @roaming: true if the deletion is due to a roaming event
* @curr_flags: pointer to store the flags of the entry before it was marked
*
+ * An already announced entry is marked as BATADV_TT_CLIENT_PENDING and the
+ * (roamed) DEL change is queued. Both happen under the hash bucket list_lock
+ * of the entry to prevent concurrent batadv_tt_local_purge_pending_clients()
+ * from removing the entry.
+ *
* Return: true if the entry has to be kept in the local table until the next
* ttvn increment, false if it can be purged immediately.
*/
static bool
-batadv_tt_local_mark_removed(struct batadv_tt_local_entry *tt_local_entry,
- bool roaming, u16 *curr_flags)
+batadv_tt_local_mark_removed(struct batadv_priv *bat_priv,
+ struct batadv_tt_local_entry *tt_local_entry,
+ const char *message, bool roaming, u16 *curr_flags)
{
+ spinlock_t *list_lock; /* protects write access to the hash lists */
struct batadv_tt_common_entry *common = &tt_local_entry->common;
+ struct batadv_hashtable *hash = bat_priv->tt.local_hash;
bool pending = false;
+ u16 flags;
+ u32 i;
+
+ i = batadv_choose_tt(common, hash->size);
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
scoped_guard(spinlock_bh, &common->flags_lock) {
*curr_flags = common->flags;
@@ -1474,6 +1498,17 @@ batadv_tt_local_mark_removed(struct batadv_tt_local_entry *tt_local_entry,
}
}
+ if (pending) {
+ flags = BATADV_TT_CLIENT_DEL;
+ if (roaming)
+ flags |= BATADV_TT_CLIENT_ROAM;
+
+ batadv_tt_local_set_pending_event(bat_priv, tt_local_entry,
+ flags, message);
+ }
+
+ spin_unlock_bh(list_lock);
+
return pending;
}
@@ -1532,28 +1567,17 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
{
struct batadv_tt_local_entry *tt_local_entry;
u16 curr_flags;
- u16 flags;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
return BATADV_NO_FLAGS;
- if (batadv_tt_local_mark_removed(tt_local_entry, roaming, &curr_flags)) {
- /* queue (roamed) del event which was prepared by
- * batadv_tt_local_mark_removed()
- */
- flags = BATADV_TT_CLIENT_DEL;
- if (roaming)
- flags |= BATADV_TT_CLIENT_ROAM;
-
- batadv_tt_local_set_pending_event(bat_priv, tt_local_entry,
- flags, message);
- } else {
- /* if this client has been added right now, it is possible to
- * immediately purge it
- */
+ /* if this client has been added right now, it is possible to
+ * immediately purge it
+ */
+ if (!batadv_tt_local_mark_removed(bat_priv, tt_local_entry, message,
+ roaming, &curr_flags))
batadv_tt_local_remove_now(bat_priv, tt_local_entry);
- }
batadv_tt_local_entry_put(tt_local_entry);
--
2.47.3
next prev parent reply other threads:[~2026-09-30 9:49 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-30 9:45 [PATCH net-next 0/9] pull request for net-next: batman-adv 2026-09-30 Simon Wunderlich
2026-09-30 9:45 ` [PATCH net-next 1/9] batman-adv: bla: avoid double free after failed backbone_hash alloc Simon Wunderlich
2026-10-01 10:10 ` netdev-bot+sashiko
2026-10-02 15:59 ` Sven Eckelmann
2026-10-06 0:50 ` patchwork-bot+netdevbpf
2026-09-30 9:45 ` [PATCH net-next 2/9] batman-adv: tt: clarify kernel-doc for batadv_tt_global_purge_local Simon Wunderlich
2026-09-30 9:45 ` [PATCH net-next 3/9] batman-adv: tt: clarify responsibility for roam flag during removal Simon Wunderlich
2026-10-01 10:10 ` netdev-bot+sashiko
2026-10-02 16:05 ` Sven Eckelmann
2026-09-30 9:45 ` [PATCH net-next 4/9] batman-adv: tt: soften kernel-doc for batadv_tt_local_remove_now() Simon Wunderlich
2026-09-30 9:45 ` [PATCH net-next 5/9] batman-adv: tt: only queue local del event after successful unlink Simon Wunderlich
2026-10-01 10:10 ` netdev-bot+sashiko
2026-10-02 16:35 ` Sven Eckelmann
[not found] ` <20261001095518.932241F000FF@smtp.kernel.org>
2026-10-02 16:24 ` Sven Eckelmann
2026-09-30 9:45 ` Simon Wunderlich [this message]
2026-10-01 10:10 ` [PATCH net-next 6/9] batman-adv: tt: queue local DEL event under bucket lock netdev-bot+sashiko
2026-10-02 17:49 ` Sven Eckelmann
2026-09-30 9:45 ` [PATCH net-next 7/9] batman-adv: tt: queue local DEL event before marking entry as pending Simon Wunderlich
2026-10-01 10:10 ` netdev-bot+sashiko
2026-10-02 20:05 ` Sven Eckelmann
2026-09-30 9:45 ` [PATCH net-next 8/9] batman-adv: tt: reject VLAN/TT entries before reaching size limit Simon Wunderlich
2026-10-01 10:10 ` netdev-bot+sashiko
2026-10-02 22:05 ` Sven Eckelmann
2026-09-30 9:45 ` [PATCH net-next 9/9] batman-adv: use assign_bit() where applicable Simon Wunderlich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260930094558.3723766-7-sw@simonwunderlich.de \
--to=sw@simonwunderlich.de \
--cc=b.a.t.m.a.n@lists.open-mesh.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sashiko-bot@kernel.org \
--cc=sven@narfation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox