@@ -1799,32 +1799,54 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
1799
1799
iml -> next = inet -> mc_list ;
1800
1800
iml -> sflist = NULL ;
1801
1801
iml -> sfmode = MCAST_EXCLUDE ;
1802
- inet -> mc_list = iml ;
1802
+ rcu_assign_pointer ( inet -> mc_list , iml ) ;
1803
1803
ip_mc_inc_group (in_dev , addr );
1804
1804
err = 0 ;
1805
1805
done :
1806
1806
rtnl_unlock ();
1807
1807
return err ;
1808
1808
}
1809
1809
1810
+ static void ip_sf_socklist_reclaim (struct rcu_head * rp )
1811
+ {
1812
+ struct ip_sf_socklist * psf ;
1813
+
1814
+ psf = container_of (rp , struct ip_sf_socklist , rcu );
1815
+ /* sk_omem_alloc should have been decreased by the caller*/
1816
+ kfree (psf );
1817
+ }
1818
+
1810
1819
static int ip_mc_leave_src (struct sock * sk , struct ip_mc_socklist * iml ,
1811
1820
struct in_device * in_dev )
1812
1821
{
1822
+ struct ip_sf_socklist * psf = iml -> sflist ;
1813
1823
int err ;
1814
1824
1815
- if (iml -> sflist == NULL ) {
1825
+ if (psf == NULL ) {
1816
1826
/* any-source empty exclude case */
1817
1827
return ip_mc_del_src (in_dev , & iml -> multi .imr_multiaddr .s_addr ,
1818
1828
iml -> sfmode , 0 , NULL , 0 );
1819
1829
}
1820
1830
err = ip_mc_del_src (in_dev , & iml -> multi .imr_multiaddr .s_addr ,
1821
- iml -> sfmode , iml -> sflist -> sl_count ,
1822
- iml -> sflist -> sl_addr , 0 );
1823
- sock_kfree_s (sk , iml -> sflist , IP_SFLSIZE (iml -> sflist -> sl_max ));
1824
- iml -> sflist = NULL ;
1831
+ iml -> sfmode , psf -> sl_count , psf -> sl_addr , 0 );
1832
+ rcu_assign_pointer (iml -> sflist , NULL );
1833
+ /* decrease mem now to avoid the memleak warning */
1834
+ atomic_sub (IP_SFLSIZE (psf -> sl_max ), & sk -> sk_omem_alloc );
1835
+ call_rcu (& psf -> rcu , ip_sf_socklist_reclaim );
1825
1836
return err ;
1826
1837
}
1827
1838
1839
+
1840
+ static void ip_mc_socklist_reclaim (struct rcu_head * rp )
1841
+ {
1842
+ struct ip_mc_socklist * iml ;
1843
+
1844
+ iml = container_of (rp , struct ip_mc_socklist , rcu );
1845
+ /* sk_omem_alloc should have been decreased by the caller*/
1846
+ kfree (iml );
1847
+ }
1848
+
1849
+
1828
1850
/*
1829
1851
* Ask a socket to leave a group.
1830
1852
*/
@@ -1854,12 +1876,14 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
1854
1876
1855
1877
(void ) ip_mc_leave_src (sk , iml , in_dev );
1856
1878
1857
- * imlp = iml -> next ;
1879
+ rcu_assign_pointer ( * imlp , iml -> next ) ;
1858
1880
1859
1881
if (in_dev )
1860
1882
ip_mc_dec_group (in_dev , group );
1861
1883
rtnl_unlock ();
1862
- sock_kfree_s (sk , iml , sizeof (* iml ));
1884
+ /* decrease mem now to avoid the memleak warning */
1885
+ atomic_sub (sizeof (* iml ), & sk -> sk_omem_alloc );
1886
+ call_rcu (& iml -> rcu , ip_mc_socklist_reclaim );
1863
1887
return 0 ;
1864
1888
}
1865
1889
if (!in_dev )
@@ -1974,9 +1998,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
1974
1998
if (psl ) {
1975
1999
for (i = 0 ; i < psl -> sl_count ; i ++ )
1976
2000
newpsl -> sl_addr [i ] = psl -> sl_addr [i ];
1977
- sock_kfree_s (sk , psl , IP_SFLSIZE (psl -> sl_max ));
2001
+ /* decrease mem now to avoid the memleak warning */
2002
+ atomic_sub (IP_SFLSIZE (psl -> sl_max ), & sk -> sk_omem_alloc );
2003
+ call_rcu (& psl -> rcu , ip_sf_socklist_reclaim );
1978
2004
}
1979
- pmc -> sflist = psl = newpsl ;
2005
+ rcu_assign_pointer (pmc -> sflist , newpsl );
2006
+ psl = newpsl ;
1980
2007
}
1981
2008
rv = 1 ; /* > 0 for insert logic below if sl_count is 0 */
1982
2009
for (i = 0 ; i < psl -> sl_count ; i ++ ) {
@@ -2072,11 +2099,13 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
2072
2099
if (psl ) {
2073
2100
(void ) ip_mc_del_src (in_dev , & msf -> imsf_multiaddr , pmc -> sfmode ,
2074
2101
psl -> sl_count , psl -> sl_addr , 0 );
2075
- sock_kfree_s (sk , psl , IP_SFLSIZE (psl -> sl_max ));
2102
+ /* decrease mem now to avoid the memleak warning */
2103
+ atomic_sub (IP_SFLSIZE (psl -> sl_max ), & sk -> sk_omem_alloc );
2104
+ call_rcu (& psl -> rcu , ip_sf_socklist_reclaim );
2076
2105
} else
2077
2106
(void ) ip_mc_del_src (in_dev , & msf -> imsf_multiaddr , pmc -> sfmode ,
2078
2107
0 , NULL , 0 );
2079
- pmc -> sflist = newpsl ;
2108
+ rcu_assign_pointer ( pmc -> sflist , newpsl ) ;
2080
2109
pmc -> sfmode = msf -> imsf_fmode ;
2081
2110
err = 0 ;
2082
2111
done :
@@ -2209,30 +2238,40 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
2209
2238
struct ip_mc_socklist * pmc ;
2210
2239
struct ip_sf_socklist * psl ;
2211
2240
int i ;
2241
+ int ret ;
2212
2242
2243
+ ret = 1 ;
2213
2244
if (!ipv4_is_multicast (loc_addr ))
2214
- return 1 ;
2245
+ goto out ;
2215
2246
2216
- for (pmc = inet -> mc_list ; pmc ; pmc = pmc -> next ) {
2247
+ rcu_read_lock ();
2248
+ for (pmc = rcu_dereference (inet -> mc_list ); pmc ; pmc = rcu_dereference (pmc -> next )) {
2217
2249
if (pmc -> multi .imr_multiaddr .s_addr == loc_addr &&
2218
2250
pmc -> multi .imr_ifindex == dif )
2219
2251
break ;
2220
2252
}
2253
+ ret = inet -> mc_all ;
2221
2254
if (!pmc )
2222
- return inet -> mc_all ;
2255
+ goto unlock ;
2223
2256
psl = pmc -> sflist ;
2257
+ ret = (pmc -> sfmode == MCAST_EXCLUDE );
2224
2258
if (!psl )
2225
- return pmc -> sfmode == MCAST_EXCLUDE ;
2259
+ goto unlock ;
2226
2260
2227
2261
for (i = 0 ; i < psl -> sl_count ; i ++ ) {
2228
2262
if (psl -> sl_addr [i ] == rmt_addr )
2229
2263
break ;
2230
2264
}
2265
+ ret = 0 ;
2231
2266
if (pmc -> sfmode == MCAST_INCLUDE && i >= psl -> sl_count )
2232
- return 0 ;
2267
+ goto unlock ;
2233
2268
if (pmc -> sfmode == MCAST_EXCLUDE && i < psl -> sl_count )
2234
- return 0 ;
2235
- return 1 ;
2269
+ goto unlock ;
2270
+ ret = 1 ;
2271
+ unlock :
2272
+ rcu_read_unlock ();
2273
+ out :
2274
+ return ret ;
2236
2275
}
2237
2276
2238
2277
/*
@@ -2251,15 +2290,17 @@ void ip_mc_drop_socket(struct sock *sk)
2251
2290
rtnl_lock ();
2252
2291
while ((iml = inet -> mc_list ) != NULL ) {
2253
2292
struct in_device * in_dev ;
2254
- inet -> mc_list = iml -> next ;
2293
+ rcu_assign_pointer ( inet -> mc_list , iml -> next ) ;
2255
2294
2256
2295
in_dev = inetdev_by_index (net , iml -> multi .imr_ifindex );
2257
2296
(void ) ip_mc_leave_src (sk , iml , in_dev );
2258
2297
if (in_dev != NULL ) {
2259
2298
ip_mc_dec_group (in_dev , iml -> multi .imr_multiaddr .s_addr );
2260
2299
in_dev_put (in_dev );
2261
2300
}
2262
- sock_kfree_s (sk , iml , sizeof (* iml ));
2301
+ /* decrease mem now to avoid the memleak warning */
2302
+ atomic_sub (sizeof (* iml ), & sk -> sk_omem_alloc );
2303
+ call_rcu (& iml -> rcu , ip_mc_socklist_reclaim );
2263
2304
}
2264
2305
rtnl_unlock ();
2265
2306
}
0 commit comments