@@ -803,10 +803,17 @@ static void igmp_gq_timer_expire(struct timer_list *t)
803
803
static void igmp_ifc_timer_expire (struct timer_list * t )
804
804
{
805
805
struct in_device * in_dev = from_timer (in_dev , t , mr_ifc_timer );
806
+ u8 mr_ifc_count ;
806
807
807
808
igmpv3_send_cr (in_dev );
808
- if (in_dev -> mr_ifc_count ) {
809
- in_dev -> mr_ifc_count -- ;
809
+ restart :
810
+ mr_ifc_count = READ_ONCE (in_dev -> mr_ifc_count );
811
+
812
+ if (mr_ifc_count ) {
813
+ if (cmpxchg (& in_dev -> mr_ifc_count ,
814
+ mr_ifc_count ,
815
+ mr_ifc_count - 1 ) != mr_ifc_count )
816
+ goto restart ;
810
817
igmp_ifc_start_timer (in_dev ,
811
818
unsolicited_report_interval (in_dev ));
812
819
}
@@ -818,7 +825,7 @@ static void igmp_ifc_event(struct in_device *in_dev)
818
825
struct net * net = dev_net (in_dev -> dev );
819
826
if (IGMP_V1_SEEN (in_dev ) || IGMP_V2_SEEN (in_dev ))
820
827
return ;
821
- in_dev -> mr_ifc_count = in_dev -> mr_qrv ?: net -> ipv4 .sysctl_igmp_qrv ;
828
+ WRITE_ONCE ( in_dev -> mr_ifc_count , in_dev -> mr_qrv ?: net -> ipv4 .sysctl_igmp_qrv ) ;
822
829
igmp_ifc_start_timer (in_dev , 1 );
823
830
}
824
831
@@ -957,7 +964,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
957
964
in_dev -> mr_qri ;
958
965
}
959
966
/* cancel the interface change timer */
960
- in_dev -> mr_ifc_count = 0 ;
967
+ WRITE_ONCE ( in_dev -> mr_ifc_count , 0 ) ;
961
968
if (del_timer (& in_dev -> mr_ifc_timer ))
962
969
__in_dev_put (in_dev );
963
970
/* clear deleted report items */
@@ -1724,7 +1731,7 @@ void ip_mc_down(struct in_device *in_dev)
1724
1731
igmp_group_dropped (pmc );
1725
1732
1726
1733
#ifdef CONFIG_IP_MULTICAST
1727
- in_dev -> mr_ifc_count = 0 ;
1734
+ WRITE_ONCE ( in_dev -> mr_ifc_count , 0 ) ;
1728
1735
if (del_timer (& in_dev -> mr_ifc_timer ))
1729
1736
__in_dev_put (in_dev );
1730
1737
in_dev -> mr_gq_running = 0 ;
@@ -1941,7 +1948,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
1941
1948
pmc -> sfmode = MCAST_INCLUDE ;
1942
1949
#ifdef CONFIG_IP_MULTICAST
1943
1950
pmc -> crcount = in_dev -> mr_qrv ?: net -> ipv4 .sysctl_igmp_qrv ;
1944
- in_dev -> mr_ifc_count = pmc -> crcount ;
1951
+ WRITE_ONCE ( in_dev -> mr_ifc_count , pmc -> crcount ) ;
1945
1952
for (psf = pmc -> sources ; psf ; psf = psf -> sf_next )
1946
1953
psf -> sf_crcount = 0 ;
1947
1954
igmp_ifc_event (pmc -> interface );
@@ -2120,7 +2127,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
2120
2127
/* else no filters; keep old mode for reports */
2121
2128
2122
2129
pmc -> crcount = in_dev -> mr_qrv ?: net -> ipv4 .sysctl_igmp_qrv ;
2123
- in_dev -> mr_ifc_count = pmc -> crcount ;
2130
+ WRITE_ONCE ( in_dev -> mr_ifc_count , pmc -> crcount ) ;
2124
2131
for (psf = pmc -> sources ; psf ; psf = psf -> sf_next )
2125
2132
psf -> sf_crcount = 0 ;
2126
2133
igmp_ifc_event (in_dev );
0 commit comments