* [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes
@ 2026-08-29 6:18 Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 01/20] batman-adv: tt: remove only the entry which was looked up from the hash Sven Eckelmann
` (19 more replies)
0 siblings, 20 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
There were a couple of sashiko reports regarding the
batadv-next-pullrequest-20260728 PR. I went through the TT code and tried
to handle them and at the same time already predict what else sashiko might
report as next. I needed to change the batadv_tt_local_remove() hash
interaction as preparation for the related NEW flag (and counter) handling.
And the netdev maintainers rejected this approach (for now). I had to
re-add the atomic_t code parts back in this patchset. But since the netdev
maintainers didn't like the atomic_t implementation, everything was changed
to atomic_t with the help of scoped_guard() or spin_(un)lock_bh (when the
routine used "goto").
This version of the patchset also includes the cleanups and swithches to
scoped_guards (when appropriate). The original cover letter was:
While working on the flag protection changes, it became apparent that the
current code is hard to maintain. Too many gotos with large sections which
are hard to crasp; because it is unclear how these sections are interact.
To simplify everything, sections which are handling a single task are
extracted in separate functions. This makes it cleared what the input and
output of each "section" are.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
Changes in v5:
- keep all batadv_tt_flags_get changes to "batman-adv: tt: use protected flag modifications"
- remove to non-RCU iterator in batadv_tt_local_transition_new() after
switching to locked iteration
- remove RFC patch prefix
- integrate the cleanup patches which depend on this patchset
- Link to v4: https://patch.msgid.link/20260806-tt-fixes-v4-0-c2fc871fe807@narfation.org
Changes in v4:
- fix setting of BATADV_TT_CLIENT_ROAM batadv_tt_local_add_roam()
- move the roam_at setting in batadv_tt_global_del_roaming() before the
setting of the flag
- don't unset BATADV_TT_CLIENT_NEW when avoiding the
batadv_tt_local_size_dec() - it is simply not needed
- new patch: fix lock precondition for batadv_tt_local_size_inc() and
document it
- clean up mini-helpers to avoid goto. precondition for using scoped_guard
- switch routines with goto's from scoped_guard to spin_(un)lock_bh
- Link to v3: https://patch.msgid.link/20260805-tt-fixes-v3-0-25b00b558470@narfation.org
Changes in v3:
- switched to spinlock_bh due to rejection atomic_t by netdev (and
potentially easier code)
- switch back to RFC
- Link to v2: https://patch.msgid.link/20260804-tt-fixes-v2-0-487c48fc7fc4@narfation.org
Changes in v2:
- rebase on main
- add "batman-adv: tt: use atomic flag modifications" and "batman-adv: tt:
simplify NEW flag transition code" because they are reverted on main
- add patch to extract the roam "add" code in a separate function
- make the "simplify NEW flag transition code" patch independent of atomic_t code
- Link to v1: https://patch.msgid.link/20260730-tt-fixes-v1-0-64e9e525d555@narfation.org
To: b.a.t.m.a.n@lists.open-mesh.org
---
Sven Eckelmann (20):
batman-adv: tt: remove only the entry which was looked up from the hash
batman-adv: tt: extract code handling a roam on add
batman-adv: tt: simplify NEW flag transition code
batman-adv: tt: drop unnecessary cleanup goto in helpers
batman-adv: tt: use protected flag modifications
batman-adv: tt: transition NEW local entries only under lock
batman-adv: tt: don't uncount never committed clients on pending purge
batman-adv: tt: decrement count for committed client on local_remove
batman-adv: tt: look up wifi state of incoming interface in helper
batman-adv: tt: extract allocation of new local entries
batman-adv: tt: replace forward gotos in batadv_tt_local_add()
batman-adv: tt: extract refresh of existing local entries
batman-adv: tt: extract update of dynamic client flags
batman-adv: tt: extract allocation of new global entries
batman-adv: tt: extract merging of flags into existing global entries
batman-adv: tt: replace add_orig_entry goto in batadv_tt_global_add()
batman-adv: tt: extract removal of the superseded local entry
batman-adv: tt: extract marking of a removed local entry
batman-adv: tt: extract immediate purge of a local entry
batman-adv: tt: drop the cleanup label from batadv_tt_local_remove()
net/batman-adv/translation-table.c | 1100 ++++++++++++++++++++++++------------
net/batman-adv/types.h | 8 +-
2 files changed, 736 insertions(+), 372 deletions(-)
---
base-commit: f3c33e7fcb7e88cc099b783faf26f0494b774571
change-id: 20260730-tt-fixes-fca2b722ebbd
Best regards,
--
Sven Eckelmann <sven@narfation.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH batadv v5 01/20] batman-adv: tt: remove only the entry which was looked up from the hash
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 02/20] batman-adv: tt: extract code handling a roam on add Sven Eckelmann
` (18 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
batadv_hash_remove() searches a bucket with a compare callback and unlinks
the first matching entry. batadv_compare_tt() matches any entry for the
same MAC address and VLAN, not the object which was passed in, and the
callers in batadv_tt_local_remove() and batadv_tt_global_free() are not
serialized against the rest of the translation table in any way.
So when the looked up entry was already unlinked by another context and a
new entry for the same client was added in the meantime, these two
functions unlink that new entry instead.
Add batadv_compare_tt_entry(), which matches the very object which is
searched for, and use it for both removals. Nothing is unlinked when the
entry is gone already, batadv_hash_remove() then simply returns NULL and
only the reference of the calling context is dropped.
As a side effect the returned hlist_node can no longer belong to a
different object, so both functions can operate on the entry they were
given.
Fixes: af912d77181f ("batman-adv: protect tt_local_entry from concurrent delete events")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 38 ++++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 4f47c97b..af40ff81 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -136,6 +136,26 @@ static bool batadv_compare_tt(const struct hlist_node *node, const void *data2)
return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
}
+/**
+ * batadv_compare_tt_entry() - check if a hash node is a specific TT entry
+ * @node: the list element pointer of the TT entry stored in the bucket
+ * @data2: pointer to the tt_common_entry which is looked for
+ *
+ * Unlike batadv_compare_tt(), this only matches the very object which is
+ * passed as @data2 and not just any entry for the same TT client. It is meant
+ * for batadv_hash_remove() callers which must not unlink an entry they did not
+ * look up themselves.
+ *
+ * Return: true if @node belongs to @data2, false otherwise
+ */
+static bool batadv_compare_tt_entry(const struct hlist_node *node,
+ const void *data2)
+{
+ const struct batadv_tt_common_entry *tt = data2;
+
+ return node == &tt->hash_entry;
+}
+
/**
* batadv_choose_tt() - return the index of the tt entry in the hash table
* @data: pointer to the tt_common_entry object to map
@@ -628,7 +648,6 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
struct batadv_tt_global_entry *tt_global,
const char *message)
{
- struct batadv_tt_global_entry *tt_removed_entry;
struct hlist_node *tt_removed_node;
batadv_dbg(BATADV_DBG_TT, bat_priv,
@@ -636,18 +655,16 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
tt_global->common.addr,
batadv_print_vid(tt_global->common.vid), message);
+ /* remove exactly this object when still present in hash */
tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash,
- batadv_compare_tt,
+ batadv_compare_tt_entry,
batadv_choose_tt,
&tt_global->common);
if (!tt_removed_node)
return;
/* drop reference of remove hash entry */
- tt_removed_entry = hlist_entry(tt_removed_node,
- struct batadv_tt_global_entry,
- common.hash_entry);
- batadv_tt_global_entry_put(tt_removed_entry);
+ batadv_tt_global_entry_put(tt_global);
}
/**
@@ -1345,7 +1362,6 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
unsigned short vid, const char *message,
bool roaming)
{
- struct batadv_tt_local_entry *tt_removed_entry;
struct batadv_tt_local_entry *tt_local_entry;
struct hlist_node *tt_removed_node;
u16 curr_flags = BATADV_NO_FLAGS;
@@ -1378,18 +1394,16 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
*/
batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
+ /* remove exactly this object when still present in hash */
tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash,
- batadv_compare_tt,
+ batadv_compare_tt_entry,
batadv_choose_tt,
&tt_local_entry->common);
if (!tt_removed_node)
goto out;
/* drop reference of remove hash entry */
- tt_removed_entry = hlist_entry(tt_removed_node,
- struct batadv_tt_local_entry,
- common.hash_entry);
- batadv_tt_local_entry_put(tt_removed_entry);
+ batadv_tt_local_entry_put(tt_local_entry);
out:
batadv_tt_local_entry_put(tt_local_entry);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 02/20] batman-adv: tt: extract code handling a roam on add
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 01/20] batman-adv: tt: remove only the entry which was looked up from the hash Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 03/20] batman-adv: tt: simplify NEW flag transition code Sven Eckelmann
` (17 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The code for handling the roaming of clients is mostly self contained but
embedded in the already too large batadv_tt_local_add function. The
maintainability can be improved by keeping it in an separate function.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 71 ++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 26 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index af40ff81..2a1d8963 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -667,6 +667,50 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
batadv_tt_global_entry_put(tt_global);
}
+/**
+ * batadv_tt_local_add_roam() - handle roamed clients during batadv_tt_local_add()
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tt_global: the global TT entry
+ * @roamed_back: whether @tt_global roamed back
+ */
+static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
+ struct batadv_tt_global_entry *tt_global,
+ bool roamed_back)
+{
+ struct batadv_tt_orig_list_entry *orig_entry;
+ struct hlist_head *head;
+
+ if (!tt_global)
+ return;
+
+ /* Check whether it is a roaming, but don't do anything if the roaming
+ * process has already been handled
+ */
+ if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
+ return;
+
+ /* These node are probably going to update their tt table */
+ head = &tt_global->orig_list;
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(orig_entry, head, list) {
+ batadv_send_roam_adv(bat_priv, tt_global->common.addr,
+ tt_global->common.vid,
+ orig_entry->orig_node);
+ }
+ rcu_read_unlock();
+
+ if (roamed_back) {
+ batadv_tt_global_free(bat_priv, tt_global,
+ "Roaming canceled");
+ } else {
+ /* The global entry has to be marked as ROAMING and
+ * has to be kept for consistency purpose
+ */
+ tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
+ tt_global->roam_at = jiffies;
+ }
+}
+
/**
* batadv_tt_local_add() - add a new client to the local table or update an
* existing client
@@ -685,14 +729,12 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
{
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_tt_global_entry *tt_global = NULL;
- struct batadv_tt_orig_list_entry *orig_entry;
struct batadv_tt_local_entry *tt_local;
struct net *net = dev_net(mesh_iface);
struct net_device *in_dev = NULL;
struct batadv_meshif_vlan *vlan;
bool roamed_back = false;
bool iif_is_wifi = false;
- struct hlist_head *head;
int packet_size_max;
bool ret = false;
u8 remote_flags;
@@ -811,30 +853,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
check_roaming:
- /* Check whether it is a roaming, but don't do anything if the roaming
- * process has already been handled
- */
- if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
- /* These node are probably going to update their tt table */
- head = &tt_global->orig_list;
- rcu_read_lock();
- hlist_for_each_entry_rcu(orig_entry, head, list) {
- batadv_send_roam_adv(bat_priv, tt_global->common.addr,
- tt_global->common.vid,
- orig_entry->orig_node);
- }
- rcu_read_unlock();
- if (roamed_back) {
- batadv_tt_global_free(bat_priv, tt_global,
- "Roaming canceled");
- } else {
- /* The global entry has to be marked as ROAMING and
- * has to be kept for consistency purpose
- */
- tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
- tt_global->roam_at = jiffies;
- }
- }
+ batadv_tt_local_add_roam(bat_priv, tt_global, roamed_back);
/* store the current remote flags before altering them. This helps
* understanding is flags are changing or not
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 03/20] batman-adv: tt: simplify NEW flag transition code
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 01/20] batman-adv: tt: remove only the entry which was looked up from the hash Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 02/20] batman-adv: tt: extract code handling a roam on add Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 04/20] batman-adv: tt: drop unnecessary cleanup goto in helpers Sven Eckelmann
` (16 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The function batadv_tt_local_set_flags() implements support for various
flags and to set/unset them. It is also possible to decide whether this
change should increase the TT size or not.
But in reality, this function is only used to transition tt local entries
from the NEW state and count these entries. Remove the rest of the code to
simplify the function.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 26 +++++++-------------------
1 file changed, 7 insertions(+), 19 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 2a1d8963..5f0f7fb6 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -3868,15 +3868,11 @@ void batadv_tt_free(struct batadv_priv *bat_priv)
}
/**
- * batadv_tt_local_set_flags() - set or unset the specified flags on the local
- * table and possibly count them in the TT size
+ * batadv_tt_local_transition_new() - unset the NEW flag on the local
+ * table and count them in the TT size
* @bat_priv: the bat priv with all the mesh interface information
- * @flags: the flag to switch
- * @enable: whether to set or unset the flag
- * @count: whether to increase the TT size by the number of changed entries
*/
-static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
- bool enable, bool count)
+static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)
{
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
struct batadv_tt_common_entry *tt_common_entry;
@@ -3892,19 +3888,11 @@ static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common_entry,
head, hash_entry) {
- if (enable) {
- if ((tt_common_entry->flags & flags) == flags)
- continue;
- tt_common_entry->flags |= flags;
- } else {
- if (!(tt_common_entry->flags & flags))
- continue;
- tt_common_entry->flags &= ~flags;
- }
-
- if (!count)
+ if (!(tt_common_entry->flags & BATADV_TT_CLIENT_NEW))
continue;
+ tt_common_entry->flags &= ~BATADV_TT_CLIENT_NEW;
+
batadv_tt_local_size_inc(bat_priv,
tt_common_entry->vid);
}
@@ -3977,7 +3965,7 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
return;
}
- batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
+ batadv_tt_local_transition_new(bat_priv);
batadv_tt_local_purge_pending_clients(bat_priv);
batadv_tt_local_update_crc(bat_priv);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 04/20] batman-adv: tt: drop unnecessary cleanup goto in helpers
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (2 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 03/20] batman-adv: tt: simplify NEW flag transition code Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 05/20] batman-adv: tt: use protected flag modifications Sven Eckelmann
` (15 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
To use scoped_guard(), it is not allowed to use goto in the same routine.
These goto's should only be used for cleanups but are not necessary of
minimal helpers like batadv_is_my_client(),
batadv_tt_global_client_is_roaming() and
batadv_tt_local_client_is_roaming(). Removing the goto's is actually making
these functions more readable.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 5f0f7fb6..2dcee14d 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -3597,19 +3597,18 @@ bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
unsigned short vid)
{
struct batadv_tt_local_entry *tt_local_entry;
- bool ret = false;
+ bool ret;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
- goto out;
+ return false;
+
/* Check if the client has been logically deleted (but is kept for
* consistency purpose)
*/
- if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
- (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
- goto out;
- ret = true;
-out:
+ ret = !((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
+ (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM));
+
batadv_tt_local_entry_put(tt_local_entry);
return ret;
}
@@ -4135,15 +4134,15 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
struct batadv_tt_global_entry *tt_global_entry;
- bool ret = false;
+ bool ret;
tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
if (!tt_global_entry)
- goto out;
+ return false;
ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_global_entry_put(tt_global_entry);
-out:
+
return ret;
}
@@ -4161,15 +4160,15 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
struct batadv_tt_local_entry *tt_local_entry;
- bool ret = false;
+ bool ret;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
- goto out;
+ return false;
ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_local_entry_put(tt_local_entry);
-out:
+
return ret;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 05/20] batman-adv: tt: use protected flag modifications
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (3 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 04/20] batman-adv: tt: drop unnecessary cleanup goto in helpers Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 06/20] batman-adv: tt: transition NEW local entries only under lock Sven Eckelmann
` (14 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The flags of translation table entries are modified in various places using
RMW operations like:
* read flags + add flag + store
* read flags + remove flag + store
These were done without making sure that no other context is doing a
similar operation at the same time. If another context does modify the
flags then it could happen that a store of the flag modifications is simply
lost. This problem can usually be fixed at a later point when the flags are
tried to be adjusted again.
To reduce the time the wrong flags are used, it is better to use a TT entry
specific spinlock when accessing the u16.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 339 ++++++++++++++++++++++++++-----------
net/batman-adv/types.h | 8 +-
2 files changed, 245 insertions(+), 102 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 2dcee14d..0513f899 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -13,6 +13,7 @@
#include <linux/build_bug.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
+#include <linux/cleanup.h>
#include <linux/compiler.h>
#include <linux/container_of.h>
#include <linux/crc32.h>
@@ -486,6 +487,22 @@ batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)
kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
}
+/**
+ * batadv_tt_flags_get() - get a snapshot of the flags of a TT entry
+ * @common: tt local & tt global common data
+ *
+ * Return: the flags of the TT entry as observed under its flags_lock.
+ */
+static u16 batadv_tt_flags_get(struct batadv_tt_common_entry *common)
+{
+ u16 flags;
+
+ scoped_guard(spinlock_bh, &common->flags_lock)
+ flags = common->flags;
+
+ return flags;
+}
+
/**
* batadv_tt_local_event() - store a local TT event (ADD/DEL)
* @bat_priv: the bat priv with all the mesh interface information
@@ -498,23 +515,25 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
{
struct batadv_tt_common_entry *common = &tt_local_entry->common;
struct batadv_tt_change_node *tt_change_node;
- u8 flags = common->flags | event_flags;
struct batadv_tt_change_node *entry;
struct batadv_tt_change_node *safe;
bool del_op_requested;
bool del_op_entry;
size_t changes;
+ u8 flags;
tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);
if (!tt_change_node)
return;
- tt_change_node->change.flags = flags;
memset(tt_change_node->change.reserved, 0,
sizeof(tt_change_node->change.reserved));
ether_addr_copy(tt_change_node->change.addr, common->addr);
tt_change_node->change.vid = htons(common->vid);
+ flags = batadv_tt_flags_get(common) | event_flags;
+
+ tt_change_node->change.flags = flags;
del_op_requested = flags & BATADV_TT_CLIENT_DEL;
/* check for ADD+DEL, DEL+ADD, ADD+ADD or DEL+DEL events */
@@ -686,8 +705,23 @@ static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
/* Check whether it is a roaming, but don't do anything if the roaming
* process has already been handled
*/
- if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
- return;
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
+ return;
+
+ if (!roamed_back) {
+ /* The global entry has to be marked as ROAMING and has to be
+ * kept for consistency purpose.
+ *
+ * batadv_tt_global_to_purge() evaluates roam_at as soon as it
+ * observes BATADV_TT_CLIENT_ROAM, so the timeout has to be
+ * stamped before the flag is published. Otherwise the entry can
+ * be deleted right away as "Roaming timeout".
+ */
+ tt_global->roam_at = jiffies;
+ tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
+ }
+ }
/* These node are probably going to update their tt table */
head = &tt_global->orig_list;
@@ -699,16 +733,8 @@ static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
}
rcu_read_unlock();
- if (roamed_back) {
- batadv_tt_global_free(bat_priv, tt_global,
- "Roaming canceled");
- } else {
- /* The global entry has to be marked as ROAMING and
- * has to be kept for consistency purpose
- */
- tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
- tt_global->roam_at = jiffies;
- }
+ if (roamed_back)
+ batadv_tt_global_free(bat_priv, tt_global, "Roaming canceled");
}
/**
@@ -741,6 +767,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
int hash_added;
int table_size;
u32 match_mark;
+ bool modified;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(net, ifindex);
@@ -758,6 +785,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
if (tt_local) {
tt_local->last_seen = jiffies;
+
+ spin_lock_bh(&tt_local->common.flags_lock);
if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
batadv_dbg(BATADV_DBG_TT, bat_priv,
"Re-adding pending client %pM (vid: %d)\n",
@@ -768,6 +797,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
* flag can be reset like it was never enqueued
*/
tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
+ spin_unlock_bh(&tt_local->common.flags_lock);
+
goto add_event;
}
@@ -783,6 +814,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
roamed_back = true;
}
+ spin_unlock_bh(&tt_local->common.flags_lock);
+
goto check_roaming;
}
@@ -818,18 +851,21 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
(u8)atomic_read(&bat_priv->tt.vn));
ether_addr_copy(tt_local->common.addr, addr);
+ tt_local->common.vid = vid;
+ kref_init(&tt_local->common.refcount);
+ tt_local->last_seen = jiffies;
+ tt_local->common.added_at = tt_local->last_seen;
+ tt_local->vlan = vlan;
+ spin_lock_init(&tt_local->common.flags_lock);
+
+ spin_lock_bh(&tt_local->common.flags_lock);
/* The local entry has to be marked as NEW to avoid to send it in
* a full table response going out before the next ttvn increment
* (consistency check)
*/
tt_local->common.flags = BATADV_TT_CLIENT_NEW;
- tt_local->common.vid = vid;
if (iif_is_wifi)
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
- kref_init(&tt_local->common.refcount);
- tt_local->last_seen = jiffies;
- tt_local->common.added_at = tt_local->last_seen;
- tt_local->vlan = vlan;
/* the batman interface mac and multicast addresses should never be
* purged
@@ -837,6 +873,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
if (batadv_compare_eth(addr, mesh_iface->dev_addr) ||
is_multicast_ether_addr(addr))
tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
+ spin_unlock_bh(&tt_local->common.flags_lock);
kref_get(&tt_local->common.refcount);
hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
@@ -855,6 +892,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
check_roaming:
batadv_tt_local_add_roam(bat_priv, tt_global, roamed_back);
+ spin_lock_bh(&tt_local->common.flags_lock);
/* store the current remote flags before altering them. This helps
* understanding is flags are changing or not
*/
@@ -876,10 +914,13 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
else
tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
+ modified = remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK);
+ spin_unlock_bh(&tt_local->common.flags_lock);
+
/* if any "dynamic" flag has been modified, resend an ADD event for this
* entry so that all the nodes can get the new flags
*/
- if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
+ if (modified)
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
ret = true;
@@ -1204,6 +1245,7 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
struct batadv_meshif_vlan *vlan;
unsigned int last_seen_msecs;
void *hdr;
+ u16 flags;
u32 crc;
local = container_of(common, struct batadv_tt_local_entry, common);
@@ -1225,13 +1267,15 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
genl_dump_check_consistent(cb, hdr);
+ flags = batadv_tt_flags_get(common);
+
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
- nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
+ nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, flags))
goto nla_put_failure;
- if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) &&
+ if (!(flags & BATADV_TT_CLIENT_NOPURGE) &&
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))
goto nla_put_failure;
@@ -1338,7 +1382,7 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
}
/**
- * batadv_tt_local_set_pending() - mark a local TT entry as pending removal
+ * batadv_tt_local_set_pending_event() - trigger events for TT pending removal
* @bat_priv: the bat priv with all the mesh interface information
* @tt_local_entry: local TT entry to mark
* @flags: TT change flags to announce together with the pending removal
@@ -1349,18 +1393,12 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
* so that a consistency-check response can still be answered.
*/
static void
-batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
- struct batadv_tt_local_entry *tt_local_entry,
- u16 flags, const char *message)
+batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
+ struct batadv_tt_local_entry *tt_local_entry,
+ u16 flags, const char *message)
{
batadv_tt_local_event(bat_priv, tt_local_entry, flags);
- /* The local client has to be marked as "pending to be removed" but has
- * to be kept in the table in order to send it in a full table
- * response issued before the net ttvn increment (consistency check)
- */
- tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
-
batadv_dbg(BATADV_DBG_TT, bat_priv,
"Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
tt_local_entry->common.addr,
@@ -1384,12 +1422,14 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
struct batadv_tt_local_entry *tt_local_entry;
struct hlist_node *tt_removed_node;
u16 curr_flags = BATADV_NO_FLAGS;
+ bool pending = false;
u16 flags;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
goto out;
+ spin_lock_bh(&tt_local_entry->common.flags_lock);
curr_flags = tt_local_entry->common.flags;
flags = BATADV_TT_CLIENT_DEL;
@@ -1404,10 +1444,17 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
}
if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
- batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
- message);
+ tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
+ pending = true;
+ }
+ spin_unlock_bh(&tt_local_entry->common.flags_lock);
+
+ if (pending) {
+ batadv_tt_local_set_pending_event(bat_priv, tt_local_entry, flags,
+ message);
goto out;
}
+
/* if this client has been added right now, it is possible to
* immediately purge it
*/
@@ -1447,21 +1494,37 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
hash_entry) {
+ bool cont = false;
+
tt_local_entry = container_of(tt_common_entry,
struct batadv_tt_local_entry,
common);
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
+
+ scoped_guard(spinlock_bh, &tt_local_entry->common.flags_lock) {
+ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) {
+ cont = true;
+ break;
+ }
+
+ /* entry already marked for deletion */
+ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) {
+ cont = true;
+ break;
+ }
+
+ if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) {
+ cont = true;
+ break;
+ }
+
+ tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
+ }
+
+ if (cont)
continue;
- /* entry already marked for deletion */
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
- continue;
-
- if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
- continue;
-
- batadv_tt_local_set_pending(bat_priv, tt_local_entry,
- BATADV_TT_CLIENT_DEL, "timed out");
+ batadv_tt_local_set_pending_event(bat_priv, tt_local_entry,
+ BATADV_TT_CLIENT_DEL, "timed out");
}
}
@@ -1667,8 +1730,10 @@ batadv_tt_global_sync_flags(struct batadv_tt_global_entry *tt_global)
flags |= orig_entry->flags;
rcu_read_unlock();
- flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
- tt_global->common.flags = flags;
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
+ tt_global->common.flags = flags;
+ }
}
/**
@@ -1750,8 +1815,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry;
struct batadv_tt_common_entry *common;
bool ret = false;
+ u16 global_flags;
u16 local_flags;
int hash_added;
+ bool delete;
/* ignore global entries from backbone nodes */
if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
@@ -1764,9 +1831,11 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* for a roaming advertisement instead of manually messing up the global
* table
*/
- if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
- !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
- goto out;
+ if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry) {
+ local_flags = batadv_tt_flags_get(&tt_local_entry->common);
+ if (!(local_flags & BATADV_TT_CLIENT_NEW))
+ goto out;
+ }
if (!tt_global_entry) {
tt_global_entry = kmem_cache_zalloc(batadv_tg_cache,
@@ -1777,9 +1846,13 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
common = &tt_global_entry->common;
ether_addr_copy(common->addr, tt_addr);
common->vid = vid;
+ spin_lock_init(&common->flags_lock);
- if (!is_multicast_ether_addr(common->addr))
+ if (!is_multicast_ether_addr(common->addr)) {
+ spin_lock_bh(&common->flags_lock);
common->flags = flags & (~BATADV_TT_SYNC_MASK);
+ spin_unlock_bh(&common->flags_lock);
+ }
tt_global_entry->roam_at = 0;
/* node must store current time in case of roaming. This is
@@ -1819,8 +1892,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* originator list and add the new one orig_entry
*/
if (flags & BATADV_TT_CLIENT_TEMP) {
- if (!(common->flags & BATADV_TT_CLIENT_TEMP))
+ global_flags = batadv_tt_flags_get(common);
+ if (!(global_flags & BATADV_TT_CLIENT_TEMP))
goto out;
+
if (batadv_tt_global_entry_has_orig(tt_global_entry,
orig_node, NULL))
goto out_remove;
@@ -1828,6 +1903,9 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
goto add_orig_entry;
}
+ delete = false;
+
+ spin_lock_bh(&common->flags_lock);
/* if the client was temporary added before receiving the first
* OGM announcing it, we have to clear the TEMP flag. Also,
* remove the previous temporary orig node and re-add it
@@ -1835,7 +1913,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* is a non-temporary entry is preferred.
*/
if (common->flags & BATADV_TT_CLIENT_TEMP) {
- batadv_tt_global_del_orig_list(tt_global_entry);
+ delete = true;
common->flags &= ~BATADV_TT_CLIENT_TEMP;
}
@@ -1854,10 +1932,14 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* new one.
*/
if (common->flags & BATADV_TT_CLIENT_ROAM) {
- batadv_tt_global_del_orig_list(tt_global_entry);
- common->flags &= ~BATADV_TT_CLIENT_ROAM;
+ delete = true;
tt_global_entry->roam_at = 0;
+ common->flags &= ~BATADV_TT_CLIENT_ROAM;
}
+ spin_unlock_bh(&common->flags_lock);
+
+ if (delete)
+ batadv_tt_global_del_orig_list(tt_global_entry);
}
add_orig_entry:
/* add the new orig_entry (if needed) or update it */
@@ -1881,6 +1963,8 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
"global tt received",
flags & BATADV_TT_CLIENT_ROAM);
+
+ spin_lock_bh(&tt_global_entry->common.flags_lock);
tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
if (!(flags & BATADV_TT_CLIENT_ROAM))
@@ -1888,6 +1972,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* roaming state anymore.
*/
tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
+ spin_unlock_bh(&tt_global_entry->common.flags_lock);
out:
batadv_tt_global_entry_put(tt_global_entry);
@@ -1957,9 +2042,9 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
struct batadv_tt_orig_list_entry *orig,
bool best)
{
- u16 flags = (common->flags & (~BATADV_TT_SYNC_MASK)) | orig->flags;
struct batadv_orig_node_vlan *vlan;
u8 last_ttvn;
+ u16 flags;
void *hdr;
u32 crc;
@@ -1978,6 +2063,7 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
if (!hdr)
return -ENOBUFS;
+ flags = (batadv_tt_flags_get(common) & (~BATADV_TT_SYNC_MASK)) | orig->flags;
last_ttvn = READ_ONCE(orig->orig_node->last_ttvn);
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
@@ -2266,8 +2352,9 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
if (last_entry) {
/* its the last one, mark for roaming. */
- tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
tt_global_entry->roam_at = jiffies;
+ scoped_guard(spinlock_bh, &tt_global_entry->common.flags_lock)
+ tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
} else {
/* there is another entry, we can simply delete this
* one and can still use the other one.
@@ -2416,16 +2503,18 @@ static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
bool purge = false;
- if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
- batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
- purge = true;
- *msg = "Roaming timeout\n";
- }
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
+ batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
+ purge = true;
+ *msg = "Roaming timeout\n";
+ }
- if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
- batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
- purge = true;
- *msg = "Temporary client timeout\n";
+ if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
+ batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
+ purge = true;
+ *msg = "Temporary client timeout\n";
+ }
}
return purge;
@@ -2534,13 +2623,19 @@ static bool
_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
struct batadv_tt_global_entry *tt_global_entry)
{
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
- tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
+ u16 global_flags;
+ u16 local_flags;
+
+ global_flags = batadv_tt_flags_get(&tt_global_entry->common);
+ local_flags = batadv_tt_flags_get(&tt_local_entry->common);
+
+ if (local_flags & BATADV_TT_CLIENT_WIFI &&
+ global_flags & BATADV_TT_CLIENT_WIFI)
return true;
/* check if the two clients are marked as isolated */
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
- tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
+ if (local_flags & BATADV_TT_CLIENT_ISOLA &&
+ global_flags & BATADV_TT_CLIENT_ISOLA)
return true;
return false;
@@ -2569,11 +2664,15 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry = NULL;
struct batadv_tt_orig_list_entry *best_entry;
struct batadv_orig_node *orig_node = NULL;
+ u16 flags;
if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
- if (!tt_local_entry ||
- (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
+ if (!tt_local_entry)
+ goto out;
+
+ flags = batadv_tt_flags_get(&tt_local_entry->common);
+ if (flags & BATADV_TT_CLIENT_PENDING)
goto out;
}
@@ -2648,6 +2747,8 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
+ u16 tt_flags;
+
tt_global = container_of(tt_common,
struct batadv_tt_global_entry,
common);
@@ -2657,18 +2758,21 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
if (tt_common->vid != vid)
continue;
+ tt_flags = batadv_tt_flags_get(tt_common);
+
/* Roaming clients are in the global table for
* consistency only. They don't have to be
* taken into account while computing the
* global crc
*/
- if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
+ if (tt_flags & BATADV_TT_CLIENT_ROAM)
continue;
+
/* Temporary clients have not been announced yet, so
* they have to be skipped while computing the global
* crc
*/
- if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
+ if (tt_flags & BATADV_TT_CLIENT_TEMP)
continue;
/* find out if this global entry is announced by this
@@ -2728,18 +2832,24 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
+ u16 tt_flags;
+
/* compute the CRC only for entries belonging to the
* VLAN identified by vid
*/
if (tt_common->vid != vid)
continue;
+ tt_flags = batadv_tt_flags_get(tt_common);
+
/* not yet committed clients have not to be taken into
* account while computing the CRC
*/
- if (tt_common->flags & BATADV_TT_CLIENT_NEW)
+ if (tt_flags & BATADV_TT_CLIENT_NEW)
continue;
+ flags = tt_flags & BATADV_TT_SYNC_MASK;
+
/* use network order to read the VID: this ensures that
* every node reads the bytes in the same order.
*/
@@ -2749,7 +2859,6 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
/* compute the CRC on flags that have to be kept in sync
* among nodes
*/
- flags = tt_common->flags & BATADV_TT_SYNC_MASK;
crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
@@ -2907,17 +3016,19 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,
*
* Return: true if the entry is a valid, false otherwise.
*/
-static bool batadv_tt_local_valid(const void *entry_ptr,
+static bool batadv_tt_local_valid(void *entry_ptr,
const void *data_ptr,
u8 *flags)
{
- const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+ struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+ u16 tt_flags;
- if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
+ tt_flags = batadv_tt_flags_get(tt_common_entry);
+ if (tt_flags & BATADV_TT_CLIENT_NEW)
return false;
if (flags)
- *flags = tt_common_entry->flags;
+ *flags = tt_flags;
return true;
}
@@ -2934,16 +3045,18 @@ static bool batadv_tt_local_valid(const void *entry_ptr,
*
* Return: true if the entry is a valid, false otherwise.
*/
-static bool batadv_tt_global_valid(const void *entry_ptr,
+static bool batadv_tt_global_valid(void *entry_ptr,
const void *data_ptr,
u8 *flags)
{
- const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
- const struct batadv_tt_global_entry *tt_global_entry;
+ struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
const struct batadv_orig_node *orig_node = data_ptr;
+ struct batadv_tt_global_entry *tt_global_entry;
+ u16 tt_flags;
- if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
- tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
+ tt_flags = batadv_tt_flags_get(tt_common_entry);
+ if (tt_flags & BATADV_TT_CLIENT_ROAM ||
+ tt_flags & BATADV_TT_CLIENT_TEMP)
return false;
tt_global_entry = container_of(tt_common_entry,
@@ -2972,7 +3085,7 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
struct batadv_hashtable *hash,
void *tvlv_buff, u16 tt_len,
- bool (*valid_cb)(const void *,
+ bool (*valid_cb)(void *,
const void *,
u8 *flags),
void *cb_data)
@@ -3597,17 +3710,20 @@ bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
unsigned short vid)
{
struct batadv_tt_local_entry *tt_local_entry;
+ u16 tt_flags;
bool ret;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
return false;
+ tt_flags = batadv_tt_flags_get(&tt_local_entry->common);
+
/* Check if the client has been logically deleted (but is kept for
* consistency purpose)
*/
- ret = !((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
- (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM));
+ ret = !((tt_flags & BATADV_TT_CLIENT_PENDING) ||
+ (tt_flags & BATADV_TT_CLIENT_ROAM));
batadv_tt_local_entry_put(tt_local_entry);
return ret;
@@ -3887,10 +4003,19 @@ static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common_entry,
head, hash_entry) {
- if (!(tt_common_entry->flags & BATADV_TT_CLIENT_NEW))
- continue;
+ bool cont = false;
- tt_common_entry->flags &= ~BATADV_TT_CLIENT_NEW;
+ scoped_guard(spinlock_bh, &tt_common_entry->flags_lock) {
+ if (!(tt_common_entry->flags & BATADV_TT_CLIENT_NEW)) {
+ cont = true;
+ break;
+ }
+
+ tt_common_entry->flags &= ~BATADV_TT_CLIENT_NEW;
+ }
+
+ if (cont)
+ continue;
batadv_tt_local_size_inc(bat_priv,
tt_common_entry->vid);
@@ -3927,16 +4052,26 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_common, node_tmp, head,
hash_entry) {
- if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
+ bool cont = false;
+
+ scoped_guard(spinlock_bh, &tt_common->flags_lock) {
+ if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) {
+ cont = true;
+ break;
+ }
+
+ batadv_dbg(BATADV_DBG_TT, bat_priv,
+ "Deleting local tt entry (%pM, vid: %d): pending\n",
+ tt_common->addr,
+ batadv_print_vid(tt_common->vid));
+
+ batadv_tt_local_size_dec(bat_priv, tt_common->vid);
+ hlist_del_rcu(&tt_common->hash_entry);
+ }
+
+ if (cont)
continue;
- batadv_dbg(BATADV_DBG_TT, bat_priv,
- "Deleting local tt entry (%pM, vid: %d): pending\n",
- tt_common->addr,
- batadv_print_vid(tt_common->vid));
-
- batadv_tt_local_size_dec(bat_priv, tt_common->vid);
- hlist_del_rcu(&tt_common->hash_entry);
tt_local = container_of(tt_common,
struct batadv_tt_local_entry,
common);
@@ -4140,7 +4275,8 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
if (!tt_global_entry)
return false;
- ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
+ ret = batadv_tt_flags_get(&tt_global_entry->common) & BATADV_TT_CLIENT_ROAM;
+
batadv_tt_global_entry_put(tt_global_entry);
return ret;
@@ -4166,7 +4302,8 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
if (!tt_local_entry)
return false;
- ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
+ ret = batadv_tt_flags_get(&tt_local_entry->common) & BATADV_TT_CLIENT_ROAM;
+
batadv_tt_local_entry_put(tt_local_entry);
return ret;
@@ -4477,7 +4614,7 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
if (!tt)
return false;
- ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
+ ret = batadv_tt_flags_get(&tt->common) & BATADV_TT_CLIENT_ISOLA;
batadv_tt_global_entry_put(tt);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 9bdc5a3e..142169be 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1851,12 +1851,18 @@ struct batadv_tt_common_entry {
*/
struct hlist_node hash_entry;
- /** @flags: various state handling flags (see batadv_tt_client_flags) */
+ /**
+ * @flags: various state handling flags (see batadv_tt_client_flags),
+ * protected by @flags_lock
+ */
u16 flags;
/** @added_at: timestamp used for purging stale tt common entries */
unsigned long added_at;
+ /** @flags_lock: protect modifications of @flags */
+ spinlock_t flags_lock;
+
/** @refcount: number of contexts the object is used */
struct kref refcount;
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 06/20] batman-adv: tt: transition NEW local entries only under lock
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (4 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 05/20] batman-adv: tt: use protected flag modifications Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 07/20] batman-adv: tt: don't uncount never committed clients on pending purge Sven Eckelmann
` (13 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The batadv_tt_local_size_inc() must never be called for an entry which was
already removed from the list. Otherwise the removal from the hash cannot
correctly determine if the batadv_tt_local_size_dec() needs to be called or
not.
This assumption is broken by the use of rcu_read_lock() in
batadv_tt_local_transition_new() because it might still see entries in the
list which were already removed by a different context from the list. If it
then increments the size counter, nothing will reduce the counter again.
Simply because the removal (responsible for the decrement) already
happened.
Over the whole time, the actual hash list spinlock must be held when
transitioning NEW local entries to avoid list manipulations.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 0513f899..431d1b7f 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -382,6 +382,10 @@ static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
* given vid
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
+ *
+ * It must only be called when removing the NEW flag of a
+ * batadv_tt_local_entry while it is still part of the bat_priv->tt.local_hash.
+ * It must therefore be checked under the specific list_locks[i].
*/
static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
unsigned short vid)
@@ -3989,6 +3993,7 @@ void batadv_tt_free(struct batadv_priv *bat_priv)
*/
static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)
{
+ spinlock_t *list_lock; /* protects write access to the hash lists */
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
struct batadv_tt_common_entry *tt_common_entry;
struct hlist_head *head;
@@ -3999,10 +4004,10 @@ static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
- rcu_read_lock();
- hlist_for_each_entry_rcu(tt_common_entry,
- head, hash_entry) {
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry(tt_common_entry, head, hash_entry) {
bool cont = false;
scoped_guard(spinlock_bh, &tt_common_entry->flags_lock) {
@@ -4020,7 +4025,7 @@ static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)
batadv_tt_local_size_inc(bat_priv,
tt_common_entry->vid);
}
- rcu_read_unlock();
+ spin_unlock_bh(list_lock);
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 07/20] batman-adv: tt: don't uncount never committed clients on pending purge
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (5 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 06/20] batman-adv: tt: transition NEW local entries only under lock Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 08/20] batman-adv: tt: decrement count for committed client on local_remove Sven Eckelmann
` (12 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
batadv_tt_local_purge_pending_clients() decreases vlan->tt.num_entries for
every entry it unlinks, but an entry which still carries
BATADV_TT_CLIENT_NEW was never counted by batadv_tt_local_transition_new().
batadv_tt_local_resize_to_mtu() calls batadv_tt_local_purge() and
batadv_tt_local_purge_pending_clients() directly, without committing in
between, and it halves its timeout down towards zero. Once the timeout is
short enough, batadv_tt_local_purge_list() marks even freshly added clients
as pending. And each of them decreases a counter it never increased.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 431d1b7f..ee4e3594 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -398,6 +398,10 @@ static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
* given vid
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
+ *
+ * It must only be called after a batadv_tt_local_entry without NEW flag
+ * was removed from bat_priv->tt.local_hash (under under the specific
+ * list_locks[i]).
*/
static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
unsigned short vid)
@@ -4070,8 +4074,13 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
tt_common->addr,
batadv_print_vid(tt_common->vid));
- batadv_tt_local_size_dec(bat_priv, tt_common->vid);
hlist_del_rcu(&tt_common->hash_entry);
+
+ /* An entry which still carries BATADV_TT_CLIENT_NEW was
+ * never counted and must not be uncounted here.
+ */
+ if (!(tt_common->flags & BATADV_TT_CLIENT_NEW))
+ batadv_tt_local_size_dec(bat_priv, tt_common->vid);
}
if (cont)
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 08/20] batman-adv: tt: decrement count for committed client on local_remove
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (6 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 07/20] batman-adv: tt: don't uncount never committed clients on pending purge Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 09/20] batman-adv: tt: look up wifi state of incoming interface in helper Sven Eckelmann
` (11 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
Local TT entries which have the BATADV_TT_CLIENT_NEW no longer set are
committed. The batadv_tt_local_size_inc() was called for them and thus the
batadv_tt_local_size_dec() has to be called also when
batadv_tt_local_remove() is called for them when the BATADV_TT_CLIENT_NEW
wasn't consumed in the remove path.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index ee4e3594..63948ee2 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1476,6 +1476,13 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
if (!tt_removed_node)
goto out;
+ /* batadv_tt_local_transition_new() may have committed the entry and
+ * thus counted it in the local table size since the BATADV_TT_CLIENT_NEW
+ * check above.
+ */
+ if (!(batadv_tt_flags_get(&tt_local_entry->common) & BATADV_TT_CLIENT_NEW))
+ batadv_tt_local_size_dec(bat_priv, tt_local_entry->common.vid);
+
/* drop reference of remove hash entry */
batadv_tt_local_entry_put(tt_local_entry);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 09/20] batman-adv: tt: look up wifi state of incoming interface in helper
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (7 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 08/20] batman-adv: tt: decrement count for committed client on local_remove Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 10/20] batman-adv: tt: extract allocation of new local entries Sven Eckelmann
` (10 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
batadv_tt_local_add() only needs to know whether the client was seen on a
wifi interface. But it kept the net_device reference of the incoming
interface alive until its own cleanup section, together with a "net" and an
"in_dev" variable which are of no interest to the rest of the function.
Move the lookup to a small helper which acquires and releases the
net_device reference itself.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 41 +++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 63948ee2..d040c0d3 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -41,6 +41,7 @@
#include <linux/string.h>
#include <linux/workqueue.h>
#include <net/genetlink.h>
+#include <net/net_namespace.h>
#include <net/netlink.h>
#include <uapi/linux/batadv_packet.h>
#include <uapi/linux/batman_adv.h>
@@ -745,6 +746,32 @@ static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
batadv_tt_global_free(bat_priv, tt_global, "Roaming canceled");
}
+/**
+ * batadv_tt_iif_is_wifi() - check whether a client is connected via wifi
+ * @net: namespace to search the incoming interface in
+ * @ifindex: index of the interface where the client is connected to
+ *
+ * Return: true if @ifindex refers to a wifi interface, false otherwise (which
+ * includes the case of an unknown or missing incoming interface).
+ */
+static bool batadv_tt_iif_is_wifi(struct net *net, int ifindex)
+{
+ struct net_device *in_dev;
+ u32 wifi_flags;
+
+ if (ifindex == BATADV_NULL_IFINDEX)
+ return false;
+
+ in_dev = dev_get_by_index(net, ifindex);
+ if (!in_dev)
+ return false;
+
+ wifi_flags = batadv_netdev_get_wifi_flags(in_dev);
+ dev_put(in_dev);
+
+ return batadv_is_wifi(wifi_flags);
+}
+
/**
* batadv_tt_local_add() - add a new client to the local table or update an
* existing client
@@ -764,12 +791,10 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_tt_global_entry *tt_global = NULL;
struct batadv_tt_local_entry *tt_local;
- struct net *net = dev_net(mesh_iface);
- struct net_device *in_dev = NULL;
struct batadv_meshif_vlan *vlan;
bool roamed_back = false;
- bool iif_is_wifi = false;
int packet_size_max;
+ bool iif_is_wifi;
bool ret = false;
u8 remote_flags;
int hash_added;
@@ -777,14 +802,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
u32 match_mark;
bool modified;
- if (ifindex != BATADV_NULL_IFINDEX)
- in_dev = dev_get_by_index(net, ifindex);
-
- if (in_dev) {
- u32 wifi_flags = batadv_netdev_get_wifi_flags(in_dev);
-
- iif_is_wifi = batadv_is_wifi(wifi_flags);
- }
+ iif_is_wifi = batadv_tt_iif_is_wifi(dev_net(mesh_iface), ifindex);
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
@@ -933,7 +951,6 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
ret = true;
out:
- dev_put(in_dev);
batadv_tt_local_entry_put(tt_local);
batadv_tt_global_entry_put(tt_global);
return ret;
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 10/20] batman-adv: tt: extract allocation of new local entries
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (8 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 09/20] batman-adv: tt: look up wifi state of incoming interface in helper Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 11/20] batman-adv: tt: replace forward gotos in batadv_tt_local_add() Sven Eckelmann
` (9 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The code which allocates and initializes a brand new local TT entry makes
up more than a third of batadv_tt_local_add(). It only shares the addr, vid
and iif_is_wifi parameters with the rest of the function.
Move it to batadv_tt_local_create(), which returns the fully initialized
entry. The error paths become plain returns.
The insertion into bat_priv->tt.local_hash intentionally stays in
batadv_tt_local_add(), keeping the extra reference for the hash next to the
error handling which has to drop it again.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 135 ++++++++++++++++++++++---------------
1 file changed, 79 insertions(+), 56 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index d040c0d3..8726bbba 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -772,6 +772,84 @@ static bool batadv_tt_iif_is_wifi(struct net *net, int ifindex)
return batadv_is_wifi(wifi_flags);
}
+/**
+ * batadv_tt_local_create() - allocate and initialize a local TT entry
+ * @mesh_iface: netdev struct of the mesh interface
+ * @addr: the mac address of the client to add
+ * @vid: VLAN identifier
+ * @iif_is_wifi: whether the client is connected via a wifi interface
+ *
+ * The returned entry is not yet part of bat_priv->tt.local_hash. It is marked
+ * as BATADV_TT_CLIENT_NEW to avoid sending it in a full table response going
+ * out before the next ttvn increment (consistency check).
+ *
+ * Return: the new entry with an initialized reference counter on success, NULL
+ * otherwise.
+ */
+static struct batadv_tt_local_entry *
+batadv_tt_local_create(struct net_device *mesh_iface, const u8 *addr,
+ unsigned short vid, bool iif_is_wifi)
+{
+ struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
+ struct batadv_tt_local_entry *tt_local;
+ struct batadv_meshif_vlan *vlan;
+ int packet_size_max;
+ int table_size;
+
+ /* Ignore the client if we cannot send it in a full table response. */
+ table_size = batadv_tt_local_table_transmit_size(bat_priv);
+ table_size += batadv_tt_len(1);
+ packet_size_max = READ_ONCE(bat_priv->packet_size_max);
+ if (table_size > packet_size_max) {
+ net_ratelimited_function(batadv_info, mesh_iface,
+ "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
+ table_size, packet_size_max, addr);
+ return NULL;
+ }
+
+ tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);
+ if (!tt_local)
+ return NULL;
+
+ /* increase the refcounter of the related vlan */
+ vlan = batadv_meshif_vlan_get(bat_priv, vid);
+ if (!vlan) {
+ net_ratelimited_function(batadv_info, mesh_iface,
+ "adding TT local entry %pM to non-existent VLAN %d\n",
+ addr, batadv_print_vid(vid));
+ kmem_cache_free(batadv_tl_cache, tt_local);
+ return NULL;
+ }
+
+ batadv_dbg(BATADV_DBG_TT, bat_priv,
+ "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
+ addr, batadv_print_vid(vid),
+ (u8)atomic_read(&bat_priv->tt.vn));
+
+ ether_addr_copy(tt_local->common.addr, addr);
+ tt_local->common.vid = vid;
+ kref_init(&tt_local->common.refcount);
+ tt_local->last_seen = jiffies;
+ tt_local->common.added_at = tt_local->last_seen;
+ tt_local->vlan = vlan;
+ spin_lock_init(&tt_local->common.flags_lock);
+
+ scoped_guard(spinlock_bh, &tt_local->common.flags_lock) {
+ tt_local->common.flags = BATADV_TT_CLIENT_NEW;
+ if (iif_is_wifi)
+ tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
+
+ /* the batman interface mac and multicast addresses should never
+ * be purged
+ */
+ if (batadv_compare_eth(addr, mesh_iface->dev_addr) ||
+ is_multicast_ether_addr(addr))
+ tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
+ }
+
+ return tt_local;
+}
+
/**
* batadv_tt_local_add() - add a new client to the local table or update an
* existing client
@@ -791,14 +869,11 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_tt_global_entry *tt_global = NULL;
struct batadv_tt_local_entry *tt_local;
- struct batadv_meshif_vlan *vlan;
bool roamed_back = false;
- int packet_size_max;
bool iif_is_wifi;
bool ret = false;
u8 remote_flags;
int hash_added;
- int table_size;
u32 match_mark;
bool modified;
@@ -845,62 +920,10 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
goto check_roaming;
}
- /* Ignore the client if we cannot send it in a full table response. */
- table_size = batadv_tt_local_table_transmit_size(bat_priv);
- table_size += batadv_tt_len(1);
- packet_size_max = READ_ONCE(bat_priv->packet_size_max);
- if (table_size > packet_size_max) {
- net_ratelimited_function(batadv_info, mesh_iface,
- "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
- table_size, packet_size_max, addr);
- goto out;
- }
-
- tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);
+ tt_local = batadv_tt_local_create(mesh_iface, addr, vid, iif_is_wifi);
if (!tt_local)
goto out;
- /* increase the refcounter of the related vlan */
- vlan = batadv_meshif_vlan_get(bat_priv, vid);
- if (!vlan) {
- net_ratelimited_function(batadv_info, mesh_iface,
- "adding TT local entry %pM to non-existent VLAN %d\n",
- addr, batadv_print_vid(vid));
- kmem_cache_free(batadv_tl_cache, tt_local);
- tt_local = NULL;
- goto out;
- }
-
- batadv_dbg(BATADV_DBG_TT, bat_priv,
- "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
- addr, batadv_print_vid(vid),
- (u8)atomic_read(&bat_priv->tt.vn));
-
- ether_addr_copy(tt_local->common.addr, addr);
- tt_local->common.vid = vid;
- kref_init(&tt_local->common.refcount);
- tt_local->last_seen = jiffies;
- tt_local->common.added_at = tt_local->last_seen;
- tt_local->vlan = vlan;
- spin_lock_init(&tt_local->common.flags_lock);
-
- spin_lock_bh(&tt_local->common.flags_lock);
- /* The local entry has to be marked as NEW to avoid to send it in
- * a full table response going out before the next ttvn increment
- * (consistency check)
- */
- tt_local->common.flags = BATADV_TT_CLIENT_NEW;
- if (iif_is_wifi)
- tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
-
- /* the batman interface mac and multicast addresses should never be
- * purged
- */
- if (batadv_compare_eth(addr, mesh_iface->dev_addr) ||
- is_multicast_ether_addr(addr))
- tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
- spin_unlock_bh(&tt_local->common.flags_lock);
-
kref_get(&tt_local->common.refcount);
hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
batadv_choose_tt, &tt_local->common,
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 11/20] batman-adv: tt: replace forward gotos in batadv_tt_local_add()
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (9 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 10/20] batman-adv: tt: extract allocation of new local entries Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 12/20] batman-adv: tt: extract refresh of existing local entries Sven Eckelmann
` (8 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
batadv_tt_local_add() used two labels in the middle of the function to
express which parts of the common tail have to be executed: "add_event" to
announce a (re-)added client and "check_roaming" to skip that announcement.
Jumping forward into the middle of a function makes it hard to see which
path ends up sending an ADD event. Especially since the PENDING branch
reached "add_event" while the branch right below it reached "check_roaming"
instead.
Express the same in an "added" variable and turn the two client cases into
a plain if/else. The PENDING check returned early before the ROAM check
could run, so it becomes an "else if".
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 47 ++++++++++++++++++--------------------
1 file changed, 22 insertions(+), 25 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 8726bbba..5405be65 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -870,6 +870,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
struct batadv_tt_global_entry *tt_global = NULL;
struct batadv_tt_local_entry *tt_local;
bool roamed_back = false;
+ bool added = false;
bool iif_is_wifi;
bool ret = false;
u8 remote_flags;
@@ -898,12 +899,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
* flag can be reset like it was never enqueued
*/
tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
- spin_unlock_bh(&tt_local->common.flags_lock);
-
- goto add_event;
- }
-
- if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
+ added = true;
+ } else if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
batadv_dbg(BATADV_DBG_TT, bat_priv,
"Roaming client %pM (vid: %d) came back to its original location\n",
addr, batadv_print_vid(vid));
@@ -916,29 +913,29 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
roamed_back = true;
}
spin_unlock_bh(&tt_local->common.flags_lock);
+ } else {
+ tt_local = batadv_tt_local_create(mesh_iface, addr, vid, iif_is_wifi);
+ if (!tt_local)
+ goto out;
- goto check_roaming;
+ kref_get(&tt_local->common.refcount);
+ hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
+ batadv_choose_tt, &tt_local->common,
+ &tt_local->common.hash_entry);
+
+ if (unlikely(hash_added != 0)) {
+ /* remove the reference for the hash */
+ batadv_tt_local_entry_put(tt_local);
+ goto out;
+ }
+
+ added = true;
}
- tt_local = batadv_tt_local_create(mesh_iface, addr, vid, iif_is_wifi);
- if (!tt_local)
- goto out;
+ /* announce the (re-)added client to the mesh */
+ if (added)
+ batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
- kref_get(&tt_local->common.refcount);
- hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
- batadv_choose_tt, &tt_local->common,
- &tt_local->common.hash_entry);
-
- if (unlikely(hash_added != 0)) {
- /* remove the reference for the hash */
- batadv_tt_local_entry_put(tt_local);
- goto out;
- }
-
-add_event:
- batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
-
-check_roaming:
batadv_tt_local_add_roam(bat_priv, tt_global, roamed_back);
spin_lock_bh(&tt_local->common.flags_lock);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 12/20] batman-adv: tt: extract refresh of existing local entries
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (10 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 11/20] batman-adv: tt: replace forward gotos in batadv_tt_local_add() Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 13/20] batman-adv: tt: extract update of dynamic client flags Sven Eckelmann
` (7 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The handling of a client which is already part of the local translation
table is independent from the rest of batadv_tt_local_add(): it only
refreshes last_seen and evaluates the PENDING and ROAM flags of the entry
which was just looked up.
Move it to batadv_tt_local_add_existing(). It reports via its return value
whether the client has to be announced to the mesh again and whether the
client roamed back to its original location.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 78 +++++++++++++++++++++++++-------------
1 file changed, 51 insertions(+), 27 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 5405be65..ca9956be 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -772,6 +772,55 @@ static bool batadv_tt_iif_is_wifi(struct net *net, int ifindex)
return batadv_is_wifi(wifi_flags);
}
+/**
+ * batadv_tt_local_add_existing() - refresh an already known local TT entry
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tt_local: the local TT entry which was found in the local table
+ * @roamed_back: set to true when the client returned to its original location
+ *
+ * Return: true when the client has to be announced to the mesh again, false
+ * otherwise.
+ */
+static bool batadv_tt_local_add_existing(struct batadv_priv *bat_priv,
+ struct batadv_tt_local_entry *tt_local,
+ bool *roamed_back)
+{
+ struct batadv_tt_common_entry *common = &tt_local->common;
+
+ tt_local->last_seen = jiffies;
+
+ scoped_guard(spinlock_bh, &common->flags_lock) {
+ if (common->flags & BATADV_TT_CLIENT_PENDING) {
+ batadv_dbg(BATADV_DBG_TT, bat_priv,
+ "Re-adding pending client %pM (vid: %d)\n",
+ common->addr, batadv_print_vid(common->vid));
+ /* whatever the reason why the PENDING flag was set,
+ * this is a client which was enqueued to be removed in
+ * this orig_interval. Since it popped up again, the
+ * flag can be reset like it was never enqueued
+ */
+ common->flags &= ~BATADV_TT_CLIENT_PENDING;
+
+ return true;
+ }
+
+ if (common->flags & BATADV_TT_CLIENT_ROAM) {
+ batadv_dbg(BATADV_DBG_TT, bat_priv,
+ "Roaming client %pM (vid: %d) came back to its original location\n",
+ common->addr, batadv_print_vid(common->vid));
+ /* the ROAM flag is set because this client roamed away
+ * and the node got a roaming_advertisement message. Now
+ * that the client popped up again at its original
+ * location such flag can be unset
+ */
+ common->flags &= ~BATADV_TT_CLIENT_ROAM;
+ *roamed_back = true;
+ }
+ }
+
+ return false;
+}
+
/**
* batadv_tt_local_create() - allocate and initialize a local TT entry
* @mesh_iface: netdev struct of the mesh interface
@@ -886,33 +935,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
if (tt_local) {
- tt_local->last_seen = jiffies;
-
- spin_lock_bh(&tt_local->common.flags_lock);
- if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
- batadv_dbg(BATADV_DBG_TT, bat_priv,
- "Re-adding pending client %pM (vid: %d)\n",
- addr, batadv_print_vid(vid));
- /* whatever the reason why the PENDING flag was set,
- * this is a client which was enqueued to be removed in
- * this orig_interval. Since it popped up again, the
- * flag can be reset like it was never enqueued
- */
- tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
- added = true;
- } else if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
- batadv_dbg(BATADV_DBG_TT, bat_priv,
- "Roaming client %pM (vid: %d) came back to its original location\n",
- addr, batadv_print_vid(vid));
- /* the ROAM flag is set because this client roamed away
- * and the node got a roaming_advertisement message. Now
- * that the client popped up again at its original
- * location such flag can be unset
- */
- tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
- roamed_back = true;
- }
- spin_unlock_bh(&tt_local->common.flags_lock);
+ added = batadv_tt_local_add_existing(bat_priv, tt_local,
+ &roamed_back);
} else {
tt_local = batadv_tt_local_create(mesh_iface, addr, vid, iif_is_wifi);
if (!tt_local)
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 13/20] batman-adv: tt: extract update of dynamic client flags
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (11 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 12/20] batman-adv: tt: extract refresh of existing local entries Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 14/20] batman-adv: tt: extract allocation of new global entries Sven Eckelmann
` (6 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The WIFI and ISOLA flags are re-evaluated on every batadv_tt_local_add()
call, no matter whether a new entry was created or an existing one was
refreshed. It is mostly isolated from the rest of the
batadv_tt_local_add().
Move it to batadv_tt_local_update_flags(). To allow the caller to trigger
the queuing of ADD events, it returns whether one of the flags announced to
the other nodes actually changed.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 79 ++++++++++++++++++++++++--------------
1 file changed, 50 insertions(+), 29 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index ca9956be..ba2a5188 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -899,6 +899,55 @@ batadv_tt_local_create(struct net_device *mesh_iface, const u8 *addr,
return tt_local;
}
+/**
+ * batadv_tt_local_update_flags() - update the dynamic flags of a local entry
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tt_local: the local TT entry to update
+ * @iif_is_wifi: whether the client is connected via a wifi interface
+ * @mark: the value contained in the skb->mark field of the received packet (if
+ * any)
+ *
+ * Return: true if a flag announced to the other nodes was modified, false
+ * otherwise.
+ */
+static bool
+batadv_tt_local_update_flags(struct batadv_priv *bat_priv,
+ struct batadv_tt_local_entry *tt_local,
+ bool iif_is_wifi, u32 mark)
+{
+ struct batadv_tt_common_entry *common = &tt_local->common;
+ u8 remote_flags;
+ u32 match_mark;
+ bool modified;
+
+ scoped_guard(spinlock_bh, &common->flags_lock) {
+ /* store the current remote flags before altering them. This
+ * helps understanding is flags are changing or not
+ */
+ remote_flags = common->flags & BATADV_TT_REMOTE_MASK;
+
+ if (iif_is_wifi)
+ common->flags |= BATADV_TT_CLIENT_WIFI;
+ else
+ common->flags &= ~BATADV_TT_CLIENT_WIFI;
+
+ /* check the mark in the skb: if it's equal to the configured
+ * isolation_mark, it means the packet is coming from an
+ * isolated non-mesh client
+ */
+ match_mark = (mark & bat_priv->isolation_mark_mask);
+ if (bat_priv->isolation_mark_mask &&
+ match_mark == bat_priv->isolation_mark)
+ common->flags |= BATADV_TT_CLIENT_ISOLA;
+ else
+ common->flags &= ~BATADV_TT_CLIENT_ISOLA;
+
+ modified = remote_flags ^ (common->flags & BATADV_TT_REMOTE_MASK);
+ }
+
+ return modified;
+}
+
/**
* batadv_tt_local_add() - add a new client to the local table or update an
* existing client
@@ -922,10 +971,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
bool added = false;
bool iif_is_wifi;
bool ret = false;
- u8 remote_flags;
int hash_added;
- u32 match_mark;
- bool modified;
iif_is_wifi = batadv_tt_iif_is_wifi(dev_net(mesh_iface), ifindex);
@@ -962,35 +1008,10 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
batadv_tt_local_add_roam(bat_priv, tt_global, roamed_back);
- spin_lock_bh(&tt_local->common.flags_lock);
- /* store the current remote flags before altering them. This helps
- * understanding is flags are changing or not
- */
- remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
-
- if (iif_is_wifi)
- tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
- else
- tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
-
- /* check the mark in the skb: if it's equal to the configured
- * isolation_mark, it means the packet is coming from an isolated
- * non-mesh client
- */
- match_mark = (mark & bat_priv->isolation_mark_mask);
- if (bat_priv->isolation_mark_mask &&
- match_mark == bat_priv->isolation_mark)
- tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
- else
- tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
-
- modified = remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK);
- spin_unlock_bh(&tt_local->common.flags_lock);
-
/* if any "dynamic" flag has been modified, resend an ADD event for this
* entry so that all the nodes can get the new flags
*/
- if (modified)
+ if (batadv_tt_local_update_flags(bat_priv, tt_local, iif_is_wifi, mark))
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
ret = true;
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 14/20] batman-adv: tt: extract allocation of new global entries
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (12 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 13/20] batman-adv: tt: extract update of dynamic client flags Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 15/20] batman-adv: tt: extract merging of flags into existing " Sven Eckelmann
` (5 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The code which allocates and initializes a brand new global TT entry makes
up a third of batadv_tt_global_add() and only needs the tt_addr, vid and
flags arguments. It is also the only part of the "new entry" branch which
does not deal with the global hash.
Move it to batadv_tt_global_create() and let it return the initialized
entry.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 76 +++++++++++++++++++++++++-------------
1 file changed, 51 insertions(+), 25 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index ba2a5188..d9055d07 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1884,6 +1884,56 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
spin_unlock_bh(&tt_global->list_lock);
}
+/**
+ * batadv_tt_global_create() - allocate and initialize a global TT entry
+ * @tt_addr: the mac address of the non-mesh client
+ * @vid: VLAN identifier
+ * @flags: TT flags that have to be set for this non-mesh client
+ *
+ * The returned entry is not yet part of bat_priv->tt.global_hash and has an
+ * empty originator list.
+ *
+ * Return: the new entry with an initialized reference counter on success, NULL
+ * otherwise.
+ */
+static struct batadv_tt_global_entry *
+batadv_tt_global_create(const unsigned char *tt_addr, unsigned short vid,
+ u16 flags)
+{
+ struct batadv_tt_global_entry *tt_global_entry;
+ struct batadv_tt_common_entry *common;
+
+ tt_global_entry = kmem_cache_zalloc(batadv_tg_cache, GFP_ATOMIC);
+ if (!tt_global_entry)
+ return NULL;
+
+ common = &tt_global_entry->common;
+ ether_addr_copy(common->addr, tt_addr);
+ common->vid = vid;
+ spin_lock_init(&common->flags_lock);
+
+ if (!is_multicast_ether_addr(common->addr)) {
+ scoped_guard(spinlock_bh, &common->flags_lock)
+ common->flags = flags & (~BATADV_TT_SYNC_MASK);
+ }
+
+ tt_global_entry->roam_at = 0;
+ /* node must store current time in case of roaming. This is
+ * needed to purge this entry out on timeout (if nobody claims
+ * it)
+ */
+ if (flags & BATADV_TT_CLIENT_ROAM)
+ tt_global_entry->roam_at = jiffies;
+ kref_init(&common->refcount);
+ common->added_at = jiffies;
+
+ INIT_HLIST_HEAD(&tt_global_entry->orig_list);
+ atomic_set(&tt_global_entry->orig_list_count, 0);
+ spin_lock_init(&tt_global_entry->list_lock);
+
+ return tt_global_entry;
+}
+
/**
* batadv_tt_global_add() - add a new TT global entry or update an existing one
* @bat_priv: the bat priv with all the mesh interface information
@@ -1935,35 +1985,11 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
}
if (!tt_global_entry) {
- tt_global_entry = kmem_cache_zalloc(batadv_tg_cache,
- GFP_ATOMIC);
+ tt_global_entry = batadv_tt_global_create(tt_addr, vid, flags);
if (!tt_global_entry)
goto out;
common = &tt_global_entry->common;
- ether_addr_copy(common->addr, tt_addr);
- common->vid = vid;
- spin_lock_init(&common->flags_lock);
-
- if (!is_multicast_ether_addr(common->addr)) {
- spin_lock_bh(&common->flags_lock);
- common->flags = flags & (~BATADV_TT_SYNC_MASK);
- spin_unlock_bh(&common->flags_lock);
- }
-
- tt_global_entry->roam_at = 0;
- /* node must store current time in case of roaming. This is
- * needed to purge this entry out on timeout (if nobody claims
- * it)
- */
- if (flags & BATADV_TT_CLIENT_ROAM)
- tt_global_entry->roam_at = jiffies;
- kref_init(&common->refcount);
- common->added_at = jiffies;
-
- INIT_HLIST_HEAD(&tt_global_entry->orig_list);
- atomic_set(&tt_global_entry->orig_list_count, 0);
- spin_lock_init(&tt_global_entry->list_lock);
kref_get(&common->refcount);
hash_added = batadv_hash_add(bat_priv->tt.global_hash,
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 15/20] batman-adv: tt: extract merging of flags into existing global entries
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (13 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 14/20] batman-adv: tt: extract allocation of new global entries Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 16/20] batman-adv: tt: replace add_orig_entry goto in batadv_tt_global_add() Sven Eckelmann
` (4 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
When an already known global TT entry is announced again, its flags have to
be merged with the announced ones. Two of the merge steps also decide
whether the originator list has to be purged before the announced
originator is added.
Move this to batadv_tt_global_merge_flags() and let it report via its
return value whether the originator list has to be purged.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 87 +++++++++++++++++++++++---------------
1 file changed, 52 insertions(+), 35 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index d9055d07..71d9fcf6 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1884,6 +1884,57 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
spin_unlock_bh(&tt_global->list_lock);
}
+/**
+ * batadv_tt_global_merge_flags() - merge announced flags into a global TT entry
+ * @tt_global_entry: the global TT entry to update
+ * @flags: TT flags announced for this non-mesh client
+ *
+ * Return: true if the originator list of @tt_global_entry has to be purged
+ * before the announced originator is added, false otherwise.
+ */
+static bool
+batadv_tt_global_merge_flags(struct batadv_tt_global_entry *tt_global_entry,
+ u16 flags)
+{
+ struct batadv_tt_common_entry *common = &tt_global_entry->common;
+ bool delete = false;
+
+ scoped_guard(spinlock_bh, &common->flags_lock) {
+ /* if the client was temporary added before receiving the first
+ * OGM announcing it, we have to clear the TEMP flag. Also,
+ * remove the previous temporary orig node and re-add it
+ * if required. If the orig entry changed, the new one which
+ * is a non-temporary entry is preferred.
+ */
+ if (common->flags & BATADV_TT_CLIENT_TEMP) {
+ delete = true;
+ common->flags &= ~BATADV_TT_CLIENT_TEMP;
+ }
+
+ /* the change can carry possible "attribute" flags like the
+ * TT_CLIENT_TEMP, therefore they have to be copied in the
+ * client entry
+ */
+ if (!is_multicast_ether_addr(common->addr))
+ common->flags |= flags & (~BATADV_TT_SYNC_MASK);
+
+ /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
+ * one originator left in the list and we previously received a
+ * delete + roaming change for this originator.
+ *
+ * We should first delete the old originator before adding the
+ * new one.
+ */
+ if (common->flags & BATADV_TT_CLIENT_ROAM) {
+ delete = true;
+ tt_global_entry->roam_at = 0;
+ common->flags &= ~BATADV_TT_CLIENT_ROAM;
+ }
+ }
+
+ return delete;
+}
+
/**
* batadv_tt_global_create() - allocate and initialize a global TT entry
* @tt_addr: the mac address of the non-mesh client
@@ -2026,41 +2077,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
goto add_orig_entry;
}
- delete = false;
-
- spin_lock_bh(&common->flags_lock);
- /* if the client was temporary added before receiving the first
- * OGM announcing it, we have to clear the TEMP flag. Also,
- * remove the previous temporary orig node and re-add it
- * if required. If the orig entry changed, the new one which
- * is a non-temporary entry is preferred.
- */
- if (common->flags & BATADV_TT_CLIENT_TEMP) {
- delete = true;
- common->flags &= ~BATADV_TT_CLIENT_TEMP;
- }
-
- /* the change can carry possible "attribute" flags like the
- * TT_CLIENT_TEMP, therefore they have to be copied in the
- * client entry
- */
- if (!is_multicast_ether_addr(common->addr))
- common->flags |= flags & (~BATADV_TT_SYNC_MASK);
-
- /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
- * one originator left in the list and we previously received a
- * delete + roaming change for this originator.
- *
- * We should first delete the old originator before adding the
- * new one.
- */
- if (common->flags & BATADV_TT_CLIENT_ROAM) {
- delete = true;
- tt_global_entry->roam_at = 0;
- common->flags &= ~BATADV_TT_CLIENT_ROAM;
- }
- spin_unlock_bh(&common->flags_lock);
-
+ delete = batadv_tt_global_merge_flags(tt_global_entry, flags);
if (delete)
batadv_tt_global_del_orig_list(tt_global_entry);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 16/20] batman-adv: tt: replace add_orig_entry goto in batadv_tt_global_add()
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (14 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 15/20] batman-adv: tt: extract merging of flags into existing " Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 17/20] batman-adv: tt: extract removal of the superseded local entry Sven Eckelmann
` (3 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The "add_orig_entry" label was only used to skip the flag merging of the
non-temporary path. Which means that the code jumping to it and the code
below it are the two halves of an if/else.
Both halves now only decide whether the originator list has to be purged,
so turn them into an if/else and purge the list at a single place.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 71d9fcf6..17a92ff4 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -2073,15 +2073,16 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
if (batadv_tt_global_entry_has_orig(tt_global_entry,
orig_node, NULL))
goto out_remove;
- batadv_tt_global_del_orig_list(tt_global_entry);
- goto add_orig_entry;
+
+ delete = true;
+ } else {
+ delete = batadv_tt_global_merge_flags(tt_global_entry, flags);
}
- delete = batadv_tt_global_merge_flags(tt_global_entry, flags);
if (delete)
batadv_tt_global_del_orig_list(tt_global_entry);
}
-add_orig_entry:
+
/* add the new orig_entry (if needed) or update it */
batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn,
flags & BATADV_TT_SYNC_MASK);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 17/20] batman-adv: tt: extract removal of the superseded local entry
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (15 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 16/20] batman-adv: tt: replace add_orig_entry goto in batadv_tt_global_add() Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 18/20] batman-adv: tt: extract marking of a removed " Sven Eckelmann
` (2 subsequent siblings)
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
A client which was announced by another originator is no longer a local
client. The code which drops it from the local table and takes over its
WIFI flag is the second cleanup stage of batadv_tt_global_add() and needed
its own goto to skip over the multicast case.
Move it to batadv_tt_global_purge_local().
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 61 +++++++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 20 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 17a92ff4..4a166791 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1884,6 +1884,46 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
spin_unlock_bh(&tt_global->list_lock);
}
+/**
+ * batadv_tt_global_purge_local() - drop the local entry of an announced client
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tt_global_entry: the global TT entry of the announced client
+ * @flags: TT flags announced for this non-mesh client
+ *
+ * A client which is announced by another originator is no longer a local
+ * client. Remove it from the local table and take over the WIFI flag it was
+ * tracked with.
+ */
+static void
+batadv_tt_global_purge_local(struct batadv_priv *bat_priv,
+ struct batadv_tt_global_entry *tt_global_entry,
+ u16 flags)
+{
+ struct batadv_tt_common_entry *common = &tt_global_entry->common;
+ u16 local_flags;
+
+ /* Do not remove multicast addresses from the local hash on
+ * global additions
+ */
+ if (is_multicast_ether_addr(common->addr))
+ return;
+
+ /* remove address from local hash if present */
+ local_flags = batadv_tt_local_remove(bat_priv, common->addr, common->vid,
+ "global tt received",
+ flags & BATADV_TT_CLIENT_ROAM);
+
+ scoped_guard(spinlock_bh, &common->flags_lock) {
+ common->flags |= local_flags & BATADV_TT_CLIENT_WIFI;
+
+ if (!(flags & BATADV_TT_CLIENT_ROAM))
+ /* this is a normal global add. Therefore the client is
+ * not in a roaming state anymore.
+ */
+ common->flags &= ~BATADV_TT_CLIENT_ROAM;
+ }
+}
+
/**
* batadv_tt_global_merge_flags() - merge announced flags into a global TT entry
* @tt_global_entry: the global TT entry to update
@@ -2094,26 +2134,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
ret = true;
out_remove:
- /* Do not remove multicast addresses from the local hash on
- * global additions
- */
- if (is_multicast_ether_addr(tt_addr))
- goto out;
-
- /* remove address from local hash if present */
- local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
- "global tt received",
- flags & BATADV_TT_CLIENT_ROAM);
-
- spin_lock_bh(&tt_global_entry->common.flags_lock);
- tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
-
- if (!(flags & BATADV_TT_CLIENT_ROAM))
- /* this is a normal global add. Therefore the client is not in a
- * roaming state anymore.
- */
- tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
- spin_unlock_bh(&tt_global_entry->common.flags_lock);
+ batadv_tt_global_purge_local(bat_priv, tt_global_entry, flags);
out:
batadv_tt_global_entry_put(tt_global_entry);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 18/20] batman-adv: tt: extract marking of a removed local entry
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (16 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 17/20] batman-adv: tt: extract removal of the superseded local entry Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 19/20] batman-adv: tt: extract immediate purge of a " Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 20/20] batman-adv: tt: drop the cleanup label from batadv_tt_local_remove() Sven Eckelmann
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
The first locked section of batadv_tt_local_remove() does three things at
once
* it snapshots the flags for the return value
* it marks the client as ROAMed
* it decides whether the entry has to survive until the next ttvn increment
But this complex locked section is in the middle of the function and cannot
be written as scoped_guard() due to goto's in this routine.
Move it to batadv_tt_local_mark_removed() and report the decision via its
return value. But leave the batadv_tt_local_set_pending_event() flag
assembly outside the function because it has no locking requirements.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 48 +++++++++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 4a166791..52c7cb90 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1495,6 +1495,38 @@ batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
batadv_print_vid(tt_local_entry->common.vid), message);
}
+/**
+ * batadv_tt_local_mark_removed() - mark a local entry as removed
+ * @tt_local_entry: local TT entry to mark
+ * @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
+ *
+ * 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)
+{
+ struct batadv_tt_common_entry *common = &tt_local_entry->common;
+ bool pending = false;
+
+ scoped_guard(spinlock_bh, &common->flags_lock) {
+ *curr_flags = common->flags;
+
+ /* mark the local client as ROAMed */
+ if (roaming)
+ common->flags |= BATADV_TT_CLIENT_ROAM;
+
+ if (!(common->flags & BATADV_TT_CLIENT_NEW)) {
+ common->flags |= BATADV_TT_CLIENT_PENDING;
+ pending = true;
+ }
+ }
+
+ return pending;
+}
+
/**
* batadv_tt_local_remove() - logically remove an entry from the local table
* @bat_priv: the bat priv with all the mesh interface information
@@ -1519,26 +1551,16 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
if (!tt_local_entry)
goto out;
- spin_lock_bh(&tt_local_entry->common.flags_lock);
- curr_flags = tt_local_entry->common.flags;
-
flags = BATADV_TT_CLIENT_DEL;
/* if this global entry addition is due to a roaming, the node has to
* mark the local entry as "roamed" in order to correctly reroute
* packets later
*/
- if (roaming) {
+ if (roaming)
flags |= BATADV_TT_CLIENT_ROAM;
- /* mark the local client as ROAMed */
- tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
- }
-
- if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
- tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
- pending = true;
- }
- spin_unlock_bh(&tt_local_entry->common.flags_lock);
+ pending = batadv_tt_local_mark_removed(tt_local_entry, roaming,
+ &curr_flags);
if (pending) {
batadv_tt_local_set_pending_event(bat_priv, tt_local_entry, flags,
message);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 19/20] batman-adv: tt: extract immediate purge of a local entry
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (17 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 18/20] batman-adv: tt: extract marking of a removed " Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 20/20] batman-adv: tt: drop the cleanup label from batadv_tt_local_remove() Sven Eckelmann
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
A client which was added after the last ttvn increment was never announced
and can be dropped from the local table right away. The code doing so is
the second half of batadv_tt_local_remove() and needed a goto to skip the
accounting when the entry was already gone from the hash.
Move it to batadv_tt_local_remove_now().
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 57 +++++++++++++++++++++++++-------------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 52c7cb90..fecf1930 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1527,6 +1527,42 @@ batadv_tt_local_mark_removed(struct batadv_tt_local_entry *tt_local_entry,
return pending;
}
+/**
+ * batadv_tt_local_remove_now() - purge a local entry which was never announced
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tt_local_entry: local TT entry to purge
+ *
+ * A client which was added right after the last ttvn increment was never sent
+ * to the other nodes. It can therefore be dropped from the local table without
+ * waiting for the next ttvn increment.
+ */
+static void
+batadv_tt_local_remove_now(struct batadv_priv *bat_priv,
+ struct batadv_tt_local_entry *tt_local_entry)
+{
+ struct batadv_tt_common_entry *common = &tt_local_entry->common;
+ struct hlist_node *tt_removed_node;
+
+ batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
+
+ /* remove exactly this object when still present in hash */
+ tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash,
+ batadv_compare_tt_entry,
+ batadv_choose_tt, common);
+ if (!tt_removed_node)
+ return;
+
+ /* batadv_tt_local_transition_new() may have committed the entry and
+ * thus counted it in the local table size since the
+ * BATADV_TT_CLIENT_NEW check in batadv_tt_local_mark_removed().
+ */
+ if (!(batadv_tt_flags_get(common) & BATADV_TT_CLIENT_NEW))
+ batadv_tt_local_size_dec(bat_priv, common->vid);
+
+ /* drop reference of remove hash entry */
+ batadv_tt_local_entry_put(tt_local_entry);
+}
+
/**
* batadv_tt_local_remove() - logically remove an entry from the local table
* @bat_priv: the bat priv with all the mesh interface information
@@ -1542,7 +1578,6 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
bool roaming)
{
struct batadv_tt_local_entry *tt_local_entry;
- struct hlist_node *tt_removed_node;
u16 curr_flags = BATADV_NO_FLAGS;
bool pending = false;
u16 flags;
@@ -1570,25 +1605,7 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
/* if this client has been added right now, it is possible to
* immediately purge it
*/
- batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
-
- /* remove exactly this object when still present in hash */
- tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash,
- batadv_compare_tt_entry,
- batadv_choose_tt,
- &tt_local_entry->common);
- if (!tt_removed_node)
- goto out;
-
- /* batadv_tt_local_transition_new() may have committed the entry and
- * thus counted it in the local table size since the BATADV_TT_CLIENT_NEW
- * check above.
- */
- if (!(batadv_tt_flags_get(&tt_local_entry->common) & BATADV_TT_CLIENT_NEW))
- batadv_tt_local_size_dec(bat_priv, tt_local_entry->common.vid);
-
- /* drop reference of remove hash entry */
- batadv_tt_local_entry_put(tt_local_entry);
+ batadv_tt_local_remove_now(bat_priv, tt_local_entry);
out:
batadv_tt_local_entry_put(tt_local_entry);
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH batadv v5 20/20] batman-adv: tt: drop the cleanup label from batadv_tt_local_remove()
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
` (18 preceding siblings ...)
2026-08-29 6:18 ` [PATCH batadv v5 19/20] batman-adv: tt: extract immediate purge of a " Sven Eckelmann
@ 2026-08-29 6:18 ` Sven Eckelmann
19 siblings, 0 replies; 21+ messages in thread
From: Sven Eckelmann @ 2026-08-29 6:18 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Sven Eckelmann
With both locked sections moved to their own helpers, the only thing left
in the cleanup section is the reference of the looked up entry. The "out"
label is therefore only reached with a valid entry, except for the lookup
failure at the very beginning.
Return BATADV_NO_FLAGS directly when there is no entry and let the two
remaining cases be an if/else.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
net/batman-adv/translation-table.c | 26 ++++++++++----------------
1 file changed, 10 insertions(+), 16 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index fecf1930..e8ec2b6c 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1578,13 +1578,12 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
bool roaming)
{
struct batadv_tt_local_entry *tt_local_entry;
- u16 curr_flags = BATADV_NO_FLAGS;
- bool pending = false;
+ u16 curr_flags;
u16 flags;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
- goto out;
+ return BATADV_NO_FLAGS;
flags = BATADV_TT_CLIENT_DEL;
/* if this global entry addition is due to a roaming, the node has to
@@ -1594,20 +1593,15 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
if (roaming)
flags |= BATADV_TT_CLIENT_ROAM;
- pending = batadv_tt_local_mark_removed(tt_local_entry, roaming,
- &curr_flags);
- if (pending) {
- batadv_tt_local_set_pending_event(bat_priv, tt_local_entry, flags,
- message);
- goto out;
- }
+ if (batadv_tt_local_mark_removed(tt_local_entry, roaming, &curr_flags))
+ 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
+ */
+ batadv_tt_local_remove_now(bat_priv, tt_local_entry);
- /* if this client has been added right now, it is possible to
- * immediately purge it
- */
- batadv_tt_local_remove_now(bat_priv, tt_local_entry);
-
-out:
batadv_tt_local_entry_put(tt_local_entry);
return curr_flags;
--
2.47.3
^ permalink raw reply related [flat|nested] 21+ messages in thread
end of thread, other threads:[~2026-08-29 6:29 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-29 6:18 [PATCH batadv v5 00/20] batman-adv: tt: atomic sashiko fixes Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 01/20] batman-adv: tt: remove only the entry which was looked up from the hash Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 02/20] batman-adv: tt: extract code handling a roam on add Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 03/20] batman-adv: tt: simplify NEW flag transition code Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 04/20] batman-adv: tt: drop unnecessary cleanup goto in helpers Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 05/20] batman-adv: tt: use protected flag modifications Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 06/20] batman-adv: tt: transition NEW local entries only under lock Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 07/20] batman-adv: tt: don't uncount never committed clients on pending purge Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 08/20] batman-adv: tt: decrement count for committed client on local_remove Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 09/20] batman-adv: tt: look up wifi state of incoming interface in helper Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 10/20] batman-adv: tt: extract allocation of new local entries Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 11/20] batman-adv: tt: replace forward gotos in batadv_tt_local_add() Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 12/20] batman-adv: tt: extract refresh of existing local entries Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 13/20] batman-adv: tt: extract update of dynamic client flags Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 14/20] batman-adv: tt: extract allocation of new global entries Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 15/20] batman-adv: tt: extract merging of flags into existing " Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 16/20] batman-adv: tt: replace add_orig_entry goto in batadv_tt_global_add() Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 17/20] batman-adv: tt: extract removal of the superseded local entry Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 18/20] batman-adv: tt: extract marking of a removed " Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 19/20] batman-adv: tt: extract immediate purge of a " Sven Eckelmann
2026-08-29 6:18 ` [PATCH batadv v5 20/20] batman-adv: tt: drop the cleanup label from batadv_tt_local_remove() Sven Eckelmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox