B.A.T.M.A.N Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH batadv] batman-adv: mark functions inheriting critical sections
@ 2026-10-15  7:08 Sven Eckelmann
       [not found] ` <sashiko-outbox-172395@kernel.org>
  0 siblings, 1 reply; 2+ messages in thread
From: Sven Eckelmann @ 2026-10-15  7:08 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Sven Eckelmann

Various functions are not taking a lock themselves but are expecting the
caller to take care of holding the lock/RCU critical section. These are a
perfect use case for Compiler-Based Context Analysis.

For now, just mark these functions as preparation for __guarded_by().

Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
The __guarded_by and also need following line at the beginning of
net/batman-adv/Makefile before it is possible to enable
`CONFIG_WARN_CONTEXT_ANALYSIS=y` with clang-23

CONTEXT_ANALYSIS := y

But I am not sure at the moment how to correctly handle some of the corner
cases of __guarded_by and thus didn't submit this part (yet).
---
 net/batman-adv/bat_iv_ogm.c        |  3 +++
 net/batman-adv/bat_v.c             |  2 ++
 net/batman-adv/bat_v_ogm.c         |  4 ++++
 net/batman-adv/fragmentation.c     |  1 +
 net/batman-adv/fragmentation.h     |  1 +
 net/batman-adv/gateway_client.c    |  1 +
 net/batman-adv/multicast.c         | 14 ++++++++++++++
 net/batman-adv/translation-table.c |  4 ++++
 net/batman-adv/tvlv.c              |  3 +++
 9 files changed, 33 insertions(+)

diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 85e99506..2ff2e446 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -893,6 +893,7 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface)
  * @hard_iface: interface whose ogm buffer should be transmitted
  */
 static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
+	__must_hold(&hard_iface->bat_iv.ogm_buff_mutex)
 {
 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
 	struct batadv_ogm_buf *ogm_buff = &hard_iface->bat_iv.ogm_buff;
@@ -2105,6 +2106,7 @@ batadv_iv_ogm_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 			      struct batadv_priv *bat_priv,
 			      struct batadv_hard_iface *if_outgoing,
 			      struct batadv_orig_node *orig_node, int *sub_s)
+	__must_hold_shared(RCU)
 {
 	struct batadv_neigh_node *neigh_node_best;
 	struct batadv_neigh_node *neigh_node;
@@ -2331,6 +2333,7 @@ batadv_iv_ogm_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
 				struct batadv_priv *bat_priv,
 				struct batadv_hard_iface *hard_iface,
 				int *idx_s)
+	__must_hold_shared(RCU)
 {
 	struct batadv_hardif_neigh_node *hardif_neigh;
 	int idx = 0;
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
index 596889b3..9aea526d 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -210,6 +210,7 @@ batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq,
 			   struct batadv_priv *bat_priv,
 			   struct batadv_hard_iface *hard_iface,
 			   int *idx_s)
+	__must_hold_shared(RCU)
 {
 	struct batadv_hardif_neigh_node *hardif_neigh;
 	int idx = 0;
@@ -365,6 +366,7 @@ batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 			 struct batadv_priv *bat_priv,
 			 struct batadv_hard_iface *if_outgoing,
 			 struct batadv_orig_node *orig_node, int *sub_s)
+	__must_hold_shared(RCU)
 {
 	struct batadv_neigh_node *neigh_node_best;
 	struct batadv_neigh_node *neigh_node;
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 70846c99..1427f055 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -162,6 +162,7 @@ static unsigned int batadv_v_ogm_len(struct sk_buff *skb)
  */
 static bool batadv_v_ogm_queue_left(struct sk_buff *skb,
 				    struct batadv_hard_iface *hard_iface)
+	__must_hold(&hard_iface->bat_v.aggr_list.lock)
 {
 	unsigned int max = min_t(unsigned int, hard_iface->net_dev->mtu,
 				 BATADV_MAX_AGGREGATION_BYTES);
@@ -181,6 +182,7 @@ static bool batadv_v_ogm_queue_left(struct sk_buff *skb,
  * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
  */
 static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
+	__must_hold(&hard_iface->bat_v.aggr_list.lock)
 {
 	lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
 
@@ -200,6 +202,7 @@ static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
  * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
  */
 static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
+	__must_hold(&hard_iface->bat_v.aggr_list.lock)
 {
 	unsigned int aggr_len = hard_iface->bat_v.aggr_len;
 	struct sk_buff *skb_aggr;
@@ -268,6 +271,7 @@ static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
  * @bat_priv: the bat priv with all the mesh interface information
  */
 static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
+	__must_hold(&bat_priv->bat_v.ogm_buff_mutex)
 {
 	struct batadv_ogm2_packet *ogm_packet;
 	struct batadv_hard_iface *hard_iface;
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c
index 493af309..ac0478ed 100644
--- a/net/batman-adv/fragmentation.c
+++ b/net/batman-adv/fragmentation.c
@@ -107,6 +107,7 @@ static size_t batadv_frag_size_limit(void)
  */
 static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain,
 				   u16 seqno)
+	__must_hold(&chain->lock)
 {
 	lockdep_assert_held(&chain->lock);
 
diff --git a/net/batman-adv/fragmentation.h b/net/batman-adv/fragmentation.h
index 51e28102..0b687fd2 100644
--- a/net/batman-adv/fragmentation.h
+++ b/net/batman-adv/fragmentation.h
@@ -35,6 +35,7 @@ int batadv_frag_send_packet(struct sk_buff *skb,
  */
 static inline bool
 batadv_frag_check_entry(struct batadv_frag_table_entry *frags_entry)
+	__must_hold(&frags_entry->lock)
 {
 	if (!hlist_empty(&frags_entry->fragment_list) &&
 	    batadv_has_timed_out(frags_entry->timestamp, BATADV_FRAG_TIMEOUT))
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index e6e97c04..51234e4f 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -333,6 +333,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv,
 static void batadv_gw_node_add(struct batadv_priv *bat_priv,
 			       struct batadv_orig_node *orig_node,
 			       struct batadv_tvlv_gateway_data *gateway)
+	__must_hold(&bat_priv->gw.list_lock)
 {
 	struct batadv_gw_node *gw_node;
 
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 22dd28d5..6ebab4eb 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -108,6 +108,7 @@ static struct net_device *batadv_mcast_get_bridge(struct net_device *mesh_iface)
  * Return: BATADV_NO_FLAGS if present, BATADV_MCAST_WANT_NO_RTR4 otherwise.
  */
 static u8 batadv_mcast_mla_rtr_flags_meshif_get_ipv4(struct net_device *dev)
+	__must_hold_shared(RCU)
 {
 	struct in_device *in_dev = __in_dev_get_rcu(dev);
 
@@ -130,6 +131,7 @@ static u8 batadv_mcast_mla_rtr_flags_meshif_get_ipv4(struct net_device *dev)
  */
 #if IS_ENABLED(CONFIG_IPV6_MROUTE)
 static u8 batadv_mcast_mla_rtr_flags_meshif_get_ipv6(struct net_device *dev)
+	__must_hold_shared(RCU)
 {
 	struct inet6_dev *in6_dev = __in6_dev_get(dev);
 
@@ -683,6 +685,7 @@ static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
  */
 static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
 					struct hlist_head *mcast_list)
+	__must_hold(&bat_priv->mcast.mla_lock)
 {
 	struct batadv_hw_addr *mcast_entry;
 	struct hlist_node *tmp;
@@ -713,6 +716,7 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
  */
 static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
 				    struct hlist_head *mcast_list)
+	__must_hold(&bat_priv->mcast.mla_lock)
 {
 	struct batadv_hw_addr *mcast_entry;
 	struct hlist_node *tmp;
@@ -761,6 +765,7 @@ static void
 batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
 			 struct batadv_mcast_querier_state *old_state,
 			 struct batadv_mcast_querier_state *new_state)
+	__must_hold(&bat_priv->mcast.mla_lock)
 {
 	if (!old_state->exists && new_state->exists)
 		batadv_info(bat_priv->mesh_iface, "%s Querier appeared\n",
@@ -806,6 +811,7 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
 static void
 batadv_mcast_bridge_log(struct batadv_priv *bat_priv,
 			struct batadv_mcast_mla_flags *new_flags)
+	__must_hold(&bat_priv->mcast.mla_lock)
 {
 	struct batadv_mcast_mla_flags *old_flags = &bat_priv->mcast.mla_flags;
 
@@ -835,6 +841,7 @@ batadv_mcast_bridge_log(struct batadv_priv *bat_priv,
  * should be used to notify userspace about the change.
  */
 static void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags)
+	__must_hold(&bat_priv->mcast.mla_lock)
 {
 	bool old_enabled = bat_priv->mcast.mla_flags.enabled;
 	u8 old_flags = bat_priv->mcast.mla_flags.tvlv_flags;
@@ -870,6 +877,7 @@ static void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags)
 static void
 batadv_mcast_mla_flags_update(struct batadv_priv *bat_priv,
 			      struct batadv_mcast_mla_flags *flags)
+	__must_hold(&bat_priv->mcast.mla_lock)
 {
 	struct batadv_tvlv_mcast_data mcast_data;
 
@@ -1612,6 +1620,7 @@ int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
 static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
 					     struct batadv_orig_node *orig,
 					     u8 mcast_flags)
+	__must_hold(&orig->mcast_handler_lock)
 {
 	struct hlist_head *head = &bat_priv->mcast.want_all_unsnoopables_list;
 	struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node;
@@ -1657,6 +1666,7 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
 static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig,
 					  u8 mcast_flags)
+	__must_hold(&orig->mcast_handler_lock)
 {
 	struct hlist_head *head = &bat_priv->mcast.want_all_ipv4_list;
 	struct hlist_node *node = &orig->mcast_want_all_ipv4_node;
@@ -1702,6 +1712,7 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
 static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig,
 					  u8 mcast_flags)
+	__must_hold(&orig->mcast_handler_lock)
 {
 	struct hlist_head *head = &bat_priv->mcast.want_all_ipv6_list;
 	struct hlist_node *node = &orig->mcast_want_all_ipv6_node;
@@ -1747,6 +1758,7 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
 static void batadv_mcast_want_rtr4_update(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig,
 					  u8 mcast_flags)
+	__must_hold(&orig->mcast_handler_lock)
 {
 	struct hlist_head *head = &bat_priv->mcast.want_all_rtr4_list;
 	struct hlist_node *node = &orig->mcast_want_all_rtr4_node;
@@ -1792,6 +1804,7 @@ static void batadv_mcast_want_rtr4_update(struct batadv_priv *bat_priv,
 static void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig,
 					  u8 mcast_flags)
+	__must_hold(&orig->mcast_handler_lock)
 {
 	struct hlist_head *head = &bat_priv->mcast.want_all_rtr6_list;
 	struct hlist_node *node = &orig->mcast_want_all_rtr6_node;
@@ -1835,6 +1848,7 @@ static void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv,
 static void batadv_mcast_have_mc_ptype_update(struct batadv_priv *bat_priv,
 					      struct batadv_orig_node *orig,
 					      u8 mcast_flags)
+	__must_hold(&orig->mcast_handler_lock)
 {
 	lockdep_assert_held(&orig->mcast_handler_lock);
 
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index e46040fd..2b9e9fd2 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -2357,6 +2357,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
 static struct batadv_tt_orig_list_entry *
 batadv_transtable_best_orig(struct batadv_priv *bat_priv,
 			    struct batadv_tt_global_entry *tt_global_entry)
+	__must_hold_shared(RCU)
 {
 	struct batadv_tt_orig_list_entry *best_entry = NULL;
 	struct batadv_algo_ops *bao = bat_priv->algo_ops;
@@ -2470,6 +2471,7 @@ static int
 batadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 			    struct batadv_priv *bat_priv,
 			    struct batadv_tt_common_entry *common, int *sub_s)
+	__must_hold_shared(RCU)
 {
 	struct batadv_tt_orig_list_entry *orig_entry;
 	struct batadv_tt_orig_list_entry *best_entry;
@@ -2610,6 +2612,7 @@ int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb)
 static void
 _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
 				 struct batadv_tt_orig_list_entry *orig_entry)
+	__must_hold(&tt_global_entry->list_lock)
 {
 	lockdep_assert_held(&tt_global_entry->list_lock);
 
@@ -4464,6 +4467,7 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
  * Caller must hold tt->commit_lock.
  */
 static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
+	__must_hold(&bat_priv->tt.commit_lock)
 {
 	lockdep_assert_held(&bat_priv->tt.commit_lock);
 
diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c
index 93492d39..d1e402e2 100644
--- a/net/batman-adv/tvlv.c
+++ b/net/batman-adv/tvlv.c
@@ -134,6 +134,7 @@ static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv)
  */
 static struct batadv_tvlv_container *
 batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
+	__must_hold(&bat_priv->tvlv.container_list_lock)
 {
 	struct batadv_tvlv_container *tvlv = NULL;
 	struct batadv_tvlv_container *tvlv_tmp;
@@ -166,6 +167,7 @@ batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
  * Return: size of all currently registered tvlv containers in bytes.
  */
 static size_t batadv_tvlv_container_list_size(struct batadv_priv *bat_priv)
+	__must_hold(&bat_priv->tvlv.container_list_lock)
 {
 	struct batadv_tvlv_container *tvlv;
 	size_t tvlv_len = 0;
@@ -191,6 +193,7 @@ static size_t batadv_tvlv_container_list_size(struct batadv_priv *bat_priv)
  */
 static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv,
 					 struct batadv_tvlv_container *tvlv)
+	__must_hold(&bat_priv->tvlv.container_list_lock)
 {
 	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
 

---
base-commit: 0eaac0f4187bc9b69b41d90998fd7b93ab07e53e
change-id: 20261015-must_hold-92c4ef54c668

Best regards,
--  
Sven Eckelmann <sven@narfation.org>


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH batadv] batman-adv: mark functions inheriting critical sections
       [not found] ` <sashiko-outbox-172395@kernel.org>
@ 2026-10-15  7:26   ` Sven Eckelmann
  0 siblings, 0 replies; 2+ messages in thread
From: Sven Eckelmann @ 2026-10-15  7:26 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: marek.lindner, sw, antonio, b.a.t.m.a.n

[-- Attachment #1: Type: text/plain, Size: 1829 bytes --]

On Thursday, 15 October 2026 09:22:30 CEST sashiko-bot@kernel.org wrote:
[...]
> [Severity: Low]
> Does adding this capability annotation break the type signature when passed
> as a function pointer?
> 
> In net/batman-adv/originator.c, batadv_frag_check_entry() is passed as the
> check_cb argument to batadv_frag_purge_orig():
> 
> 			batadv_frag_purge_orig(orig_node,
> 					       batadv_frag_check_entry);
> 
> Because the check_cb function pointer definition lacks the corresponding
> capability annotation, this creates a capability type mismatch that leads to
> a static analysis warning or error during context analysis.

No, it doesn't in my tests.

> 
> [ ... ]
> 
> > diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
> > index 22dd28d5e1abc..6ebab4eb1382e 100644
> > --- a/net/batman-adv/multicast.c
> > +++ b/net/batman-adv/multicast.c
> > @@ -683,6 +685,7 @@ static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
> >   */
> >  static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
> >  					struct hlist_head *mcast_list)
> > +	__must_hold(&bat_priv->mcast.mla_lock)
> >  {
> 
> [Severity: Low]
> Is it possible this annotation is violated during teardown?
> 
> In batadv_mcast_free(), the code intentionally skips acquiring mla_lock
> because it relies on implicit serialization after the worker is canceled:
> 
> 	/* safely calling outside of worker, as worker was canceled above */
> 	batadv_mcast_mla_tt_retract(bat_priv, NULL);
> 
> However, batadv_mcast_mla_tt_retract() is now strictly annotated to require
> the lock, which will cause a build warning or error when compiled with
> CONFIG_WARN_CONTEXT_ANALYSIS=y. Is this one of the corner cases preventing
> the enablement of CONTEXT_ANALYSIS := y?

Yes, it is one one of the corner cases.

Regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-15  7:26 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15  7:08 [PATCH batadv] batman-adv: mark functions inheriting critical sections Sven Eckelmann
     [not found] ` <sashiko-outbox-172395@kernel.org>
2026-10-15  7:26   ` Sven Eckelmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox