Netdev List
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: sw@simonwunderlich.de
Cc: netdev@vger.kernel.org, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
	b.a.t.m.a.n@lists.open-mesh.org, sven@narfation.org,
	sashiko-bot@kernel.org
Subject: Re: [PATCH net-next 7/9] batman-adv: tt: queue local DEL event before marking entry as pending
Date: Thu, 01 Oct 2026 10:10:30 +0000	[thread overview]
Message-ID: <179084943057.434549.7181634875043920373@kernel.org> (raw)
In-Reply-To: <20260930094558.3723766-8-sw@simonwunderlich.de>

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.

Critical: 0 · High: 1 · Medium: 0 · Low: 1

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [High] The fix covers only one ordering of the set_pending vs. re-add
  race.
- [Low] Stale locking rationale in the new kernel-doc.

--

batman-adv: tt: queue local DEL event before marking entry as pending

This patch restores the original order in batadv_tt_local_set_pending(),
so the DEL change is queued before BATADV_TT_CLIENT_PENDING is set. It
also moves the NEW check, the event queuing and the PENDING update into a
single flags_lock critical section. The goal is to stop a concurrent
batadv_tt_local_add_existing() from leaving the PENDING state and the
queued changes out of sync, which corrupts the TT CRC on neighbour nodes.

> diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
> index c229c51cafa72..481dc6afaaba1 100644
> --- a/net/batman-adv/translation-table.c
> +++ b/net/batman-adv/translation-table.c

[ ... ]

> @@ -1420,28 +1433,37 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
>  }
>  
>  /**
> - * batadv_tt_local_set_pending_event() - trigger events for TT pending removal
> + * batadv_tt_local_set_pending() - mark local TT entry as pending removal
>   * @bat_priv: the bat priv with all the mesh interface information
> - * @tt_local_entry: local TT entry which was marked as BATADV_TT_CLIENT_PENDING
> + * @tt_local_entry: local TT entry to mark as BATADV_TT_CLIENT_PENDING
>   * @flags: TT change flags to announce together with the pending removal
>   * @message: debug message describing the reason for the change
>   *
> - * Schedule the TT change announcement for the entry. The caller must already
> - * have added BATADV_TT_CLIENT_PENDING to the @tt_local_entry and must hold the
> - * hash bucket list_lock of @tt_local_entry since setting the flag.
> + * Schedule the TT change announcement and set BATADV_TT_CLIENT_PENDING on the
> + * entry. The entry is kept in the local table until the next TTVN increment
> + * so that a consistency-check response can still be answered.
> + *
> + * Next to the flags_lock of the entry, the caller must hold the hash bucket
> + * list_lock of @tt_local_entry. Otherwise
> + * batadv_tt_local_purge_pending_clients() could remove the entry before its
> + * change was queued.

[Severity: Low]
Is this rationale still accurate after the reordering?

With this patch, batadv_tt_local_set_pending() queues the event and then
sets BATADV_TT_CLIENT_PENDING, and both happen inside one
common->flags_lock section:

    __batadv_tt_local_event(bat_priv, common, common->flags | flags);
    common->flags |= BATADV_TT_CLIENT_PENDING;

batadv_tt_local_purge_pending_clients() only acts on PENDING after
reading it under the same flags_lock:

    scoped_guard(spinlock_bh, &tt_common->flags_lock) {
        if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) {

So it looks like purge_pending_clients() cannot see PENDING before the
change is queued, whether or not list_lock is held.

The updated batadv_tt_local_mark_removed() kernel-doc has the same
problem. It still gives the old order ("marked as
BATADV_TT_CLIENT_PENDING and the (roamed) DEL change is queued"). It also
adds a claim that list_lock prevents batadv_tt_local_transition_new() from
clearing BATADV_TT_CLIENT_NEW after it was checked. As far as I can tell,
that protection comes from the NEW check and set_pending() sharing one
flags_lock scoped_guard. The commit message says the same thing.

Could both comments name the single flags_lock section, together with the
queue-then-mark order, as the invariant? A later change could otherwise
move __batadv_tt_local_event() out of the flags_lock section while keeping
list_lock, and bring back the ADD/DEL misordering this patch fixes.

>   */
>  static void
> -batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
> -				  struct batadv_tt_local_entry *tt_local_entry,
> -				  u16 flags, const char *message)
> +batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
> +			    struct batadv_tt_local_entry *tt_local_entry,
> +			    u16 flags, const char *message)
> +	__must_hold(&tt_local_entry->common.flags_lock)
>  {
> +	struct batadv_tt_common_entry *common = &tt_local_entry->common;
>  	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
>  	u32 i;
>  
> -	i = batadv_choose_tt(&tt_local_entry->common, hash->size);
> +	i = batadv_choose_tt(common, hash->size);
>  	lockdep_assert_held(&hash->list_locks[i]);
> +	lockdep_assert_held(&common->flags_lock);
>  
> -	batadv_tt_local_event(bat_priv, tt_local_entry, flags);
> +	__batadv_tt_local_event(bat_priv, common, common->flags | flags);
> +	common->flags |= BATADV_TT_CLIENT_PENDING;

[Severity: High]
Does this close only one ordering of the race with the re-add path?

The add side still changes the flags and queues the ADD in two separate
steps. batadv_tt_local_add_existing() clears PENDING inside a flags_lock
scoped_guard and returns. batadv_tt_local_add() then queues the ADD after
that lock is dropped:

    if (added)
        batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
    ...
    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);

batadv_tt_local_set_pending() can run in that window from the RX path:

batadv_tt_global_add()->batadv_tt_global_purge_local()->
  batadv_tt_local_remove()->batadv_tt_local_mark_removed()->
    batadv_tt_local_set_pending()

Here is one interleaving, starting with DEL#1 already queued and PENDING
set:

  CPU1 (TX)                         CPU0 (RX)
  batadv_tt_local_add()
    batadv_tt_local_add_existing()
      flags &= ~PENDING;
                                    batadv_tt_local_mark_removed()
                                      batadv_tt_local_set_pending()
                                        DEL|ROAM merged into DEL#1
                                        flags |= PENDING;
    batadv_tt_local_event(NO_FLAGS)
      ADD cancels DEL#1

There is a similar case with no earlier DEL. batadv_tt_local_update_flags()
returns true on CPU1, CPU0 queues a new DEL and sets PENDING, and then the
ADD from CPU1 cancels that DEL through the DEL+ADD case in
__batadv_tt_local_event().

Either way, the entry would be left PENDING with no DEL queued. At the
next commit, batadv_tt_local_purge_pending_clients() would remove it
locally, but neighbours would never receive a DEL.

Wouldn't that give the same CRC mismatch and full table request that the
commit message describes? Would the ADD also need to be queued inside the
flags_lock section that clears PENDING or updates the flags?

>  
>  	batadv_dbg(BATADV_DBG_TT, bat_priv,
>  		   "Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
> @@ -1460,7 +1482,8 @@ batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
>   * An already announced entry is marked as BATADV_TT_CLIENT_PENDING and the
>   * (roamed) DEL change is queued. Both happen under the hash bucket list_lock
>   * of the entry to prevent concurrent batadv_tt_local_purge_pending_clients()
> - * from removing the entry.
> + * from removing the entry and batadv_tt_local_transition_new() from clearing
> + * BATADV_TT_CLIENT_NEW after it was checked.

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260930094558.3723766-2-sw%40simonwunderlich.de

  reply	other threads:[~2026-10-01 10:10 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-30  9:45 [PATCH net-next 0/9] pull request for net-next: batman-adv 2026-09-30 Simon Wunderlich
2026-09-30  9:45 ` [PATCH net-next 1/9] batman-adv: bla: avoid double free after failed backbone_hash alloc Simon Wunderlich
2026-10-01 10:10   ` netdev-bot+sashiko
2026-10-02 15:59     ` Sven Eckelmann
2026-10-06  0:50   ` patchwork-bot+netdevbpf
2026-09-30  9:45 ` [PATCH net-next 2/9] batman-adv: tt: clarify kernel-doc for batadv_tt_global_purge_local Simon Wunderlich
2026-09-30  9:45 ` [PATCH net-next 3/9] batman-adv: tt: clarify responsibility for roam flag during removal Simon Wunderlich
2026-10-01 10:10   ` netdev-bot+sashiko
2026-10-02 16:05     ` Sven Eckelmann
2026-09-30  9:45 ` [PATCH net-next 4/9] batman-adv: tt: soften kernel-doc for batadv_tt_local_remove_now() Simon Wunderlich
2026-09-30  9:45 ` [PATCH net-next 5/9] batman-adv: tt: only queue local del event after successful unlink Simon Wunderlich
2026-10-01 10:10   ` netdev-bot+sashiko
2026-10-02 16:35     ` Sven Eckelmann
     [not found]   ` <20261001095518.932241F000FF@smtp.kernel.org>
2026-10-02 16:24     ` Sven Eckelmann
2026-09-30  9:45 ` [PATCH net-next 6/9] batman-adv: tt: queue local DEL event under bucket lock Simon Wunderlich
2026-10-01 10:10   ` netdev-bot+sashiko
2026-10-02 17:49     ` Sven Eckelmann
2026-09-30  9:45 ` [PATCH net-next 7/9] batman-adv: tt: queue local DEL event before marking entry as pending Simon Wunderlich
2026-10-01 10:10   ` netdev-bot+sashiko [this message]
2026-10-02 20:05     ` Sven Eckelmann
2026-09-30  9:45 ` [PATCH net-next 8/9] batman-adv: tt: reject VLAN/TT entries before reaching size limit Simon Wunderlich
2026-10-01 10:10   ` netdev-bot+sashiko
2026-10-02 22:05     ` Sven Eckelmann
2026-09-30  9:45 ` [PATCH net-next 9/9] batman-adv: use assign_bit() where applicable Simon Wunderlich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=179084943057.434549.7181634875043920373@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=b.a.t.m.a.n@lists.open-mesh.org \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sashiko-bot@kernel.org \
    --cc=sven@narfation.org \
    --cc=sw@simonwunderlich.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox