[PATCH net-next] ipv4: igmp: annotate data-races around im->users

From: Yuyang Huang

Date: Thu May 21 2026 - 05:52:59 EST


/proc/net/igmp walks IPv4 multicast memberships under RCU and
prints im->users without holding RTNL, while multicast join and leave
paths update the field while holding RTNL. Annotate this intentional
lockless snapshot with READ_ONCE() and the matching writers with
WRITE_ONCE().

Signed-off-by: Yuyang Huang <sigefriedhyy@xxxxxxxxx>
---
net/ipv4/igmp.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 27d120183779..f2aca659b29c 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1541,7 +1541,7 @@ static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
}

if (im) {
- im->users++;
+ WRITE_ONCE(im->users, im->users + 1);
ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0);
goto out;
}
@@ -1550,7 +1550,7 @@ static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
if (!im)
goto out;

- im->users = 1;
+ WRITE_ONCE(im->users, 1);
im->interface = in_dev;
in_dev_hold(in_dev);
im->multiaddr = addr;
@@ -1784,7 +1784,10 @@ void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
(i = rtnl_dereference(*ip)) != NULL;
ip = &i->next_rcu) {
if (i->multiaddr == addr) {
- if (--i->users == 0) {
+ int new_users = i->users - 1;
+
+ WRITE_ONCE(i->users, new_users);
+ if (new_users == 0) {
ip_mc_hash_remove(in_dev, i);
*ip = i->next_rcu;
in_dev->mc_count--;
@@ -2977,7 +2980,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
delta = im->timer.expires - jiffies;
seq_printf(seq,
"\t\t\t\t%08X %5d %d:%08lX\t\t%d\n",
- im->multiaddr, im->users,
+ im->multiaddr, READ_ONCE(im->users),
im->tm_running,
im->tm_running ? jiffies_delta_to_clock_t(delta) : 0,
im->reporter);
--
2.43.0