From: Yuyang Huang Date: Fri, 5 Jun 2026 01:43:17 +0000 (+0900) Subject: ipv4: igmp: annotate data-races around in_dev->mc_count X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1719841cab55d9da92b2e55b6e0c701e10201467;p=thirdparty%2Flinux.git ipv4: igmp: annotate data-races around in_dev->mc_count /proc/net/igmp walks the multicast list for IPv4 interfaces locklessly under RCU and prints state->in_dev->mc_count. Concurrently, device init/destruction and multicast join/leave paths update the count under the RTNL lock. Fix this intentional lockless snapshot by annotating the read with READ_ONCE() and the updates with WRITE_ONCE(). Signed-off-by: Yuyang Huang Reviewed-by: Ido Schimmel Link: https://patch.msgid.link/20260605014318.3890804-2-yuyanghuang@google.com Signed-off-by: Paolo Abeni --- diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index f2aca659b29c..fd0faf042fa6 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1566,7 +1566,7 @@ static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr, #endif im->next_rcu = in_dev->mc_list; - in_dev->mc_count++; + WRITE_ONCE(in_dev->mc_count, in_dev->mc_count + 1); rcu_assign_pointer(in_dev->mc_list, im); ip_mc_hash_add(in_dev, im); @@ -1790,7 +1790,8 @@ void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp) if (new_users == 0) { ip_mc_hash_remove(in_dev, i); *ip = i->next_rcu; - in_dev->mc_count--; + WRITE_ONCE(in_dev->mc_count, + in_dev->mc_count - 1); __igmp_group_dropped(i, gfp); inet_ifmcaddr_notify(in_dev->dev, i, RTM_DELMULTICAST); @@ -1922,7 +1923,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev) while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) { in_dev->mc_list = i->next_rcu; - in_dev->mc_count--; + WRITE_ONCE(in_dev->mc_count, in_dev->mc_count - 1); ip_mc_clear_src(i); ip_ma_put(i); } @@ -2974,7 +2975,9 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v) if (rcu_access_pointer(state->in_dev->mc_list) == im) { seq_printf(seq, "%d\t%-10s: %5d %7s\n", - state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier); + state->dev->ifindex, state->dev->name, + READ_ONCE(state->in_dev->mc_count), + querier); } delta = im->timer.expires - jiffies;