diff options
Diffstat (limited to 'net/ipv4/igmp.c')
-rw-r--r-- | net/ipv4/igmp.c | 225 |
1 files changed, 105 insertions, 120 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 3c53c2d89e3b..0f0e0f0279b8 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -149,11 +149,17 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc); | |||
149 | static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | 149 | static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, |
150 | int sfcount, __be32 *psfsrc, int delta); | 150 | int sfcount, __be32 *psfsrc, int delta); |
151 | 151 | ||
152 | |||
153 | static void ip_mc_list_reclaim(struct rcu_head *head) | ||
154 | { | ||
155 | kfree(container_of(head, struct ip_mc_list, rcu)); | ||
156 | } | ||
157 | |||
152 | static void ip_ma_put(struct ip_mc_list *im) | 158 | static void ip_ma_put(struct ip_mc_list *im) |
153 | { | 159 | { |
154 | if (atomic_dec_and_test(&im->refcnt)) { | 160 | if (atomic_dec_and_test(&im->refcnt)) { |
155 | in_dev_put(im->interface); | 161 | in_dev_put(im->interface); |
156 | kfree(im); | 162 | call_rcu(&im->rcu, ip_mc_list_reclaim); |
157 | } | 163 | } |
158 | } | 164 | } |
159 | 165 | ||
@@ -163,7 +169,7 @@ static void ip_ma_put(struct ip_mc_list *im) | |||
163 | * Timer management | 169 | * Timer management |
164 | */ | 170 | */ |
165 | 171 | ||
166 | static __inline__ void igmp_stop_timer(struct ip_mc_list *im) | 172 | static void igmp_stop_timer(struct ip_mc_list *im) |
167 | { | 173 | { |
168 | spin_lock_bh(&im->lock); | 174 | spin_lock_bh(&im->lock); |
169 | if (del_timer(&im->timer)) | 175 | if (del_timer(&im->timer)) |
@@ -496,14 +502,24 @@ empty_source: | |||
496 | return skb; | 502 | return skb; |
497 | } | 503 | } |
498 | 504 | ||
505 | #define for_each_pmc_rcu(in_dev, pmc) \ | ||
506 | for (pmc = rcu_dereference(in_dev->mc_list); \ | ||
507 | pmc != NULL; \ | ||
508 | pmc = rcu_dereference(pmc->next_rcu)) | ||
509 | |||
510 | #define for_each_pmc_rtnl(in_dev, pmc) \ | ||
511 | for (pmc = rtnl_dereference(in_dev->mc_list); \ | ||
512 | pmc != NULL; \ | ||
513 | pmc = rtnl_dereference(pmc->next_rcu)) | ||
514 | |||
499 | static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) | 515 | static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) |
500 | { | 516 | { |
501 | struct sk_buff *skb = NULL; | 517 | struct sk_buff *skb = NULL; |
502 | int type; | 518 | int type; |
503 | 519 | ||
504 | if (!pmc) { | 520 | if (!pmc) { |
505 | read_lock(&in_dev->mc_list_lock); | 521 | rcu_read_lock(); |
506 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 522 | for_each_pmc_rcu(in_dev, pmc) { |
507 | if (pmc->multiaddr == IGMP_ALL_HOSTS) | 523 | if (pmc->multiaddr == IGMP_ALL_HOSTS) |
508 | continue; | 524 | continue; |
509 | spin_lock_bh(&pmc->lock); | 525 | spin_lock_bh(&pmc->lock); |
@@ -514,7 +530,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) | |||
514 | skb = add_grec(skb, pmc, type, 0, 0); | 530 | skb = add_grec(skb, pmc, type, 0, 0); |
515 | spin_unlock_bh(&pmc->lock); | 531 | spin_unlock_bh(&pmc->lock); |
516 | } | 532 | } |
517 | read_unlock(&in_dev->mc_list_lock); | 533 | rcu_read_unlock(); |
518 | } else { | 534 | } else { |
519 | spin_lock_bh(&pmc->lock); | 535 | spin_lock_bh(&pmc->lock); |
520 | if (pmc->sfcount[MCAST_EXCLUDE]) | 536 | if (pmc->sfcount[MCAST_EXCLUDE]) |
@@ -556,7 +572,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) | |||
556 | struct sk_buff *skb = NULL; | 572 | struct sk_buff *skb = NULL; |
557 | int type, dtype; | 573 | int type, dtype; |
558 | 574 | ||
559 | read_lock(&in_dev->mc_list_lock); | 575 | rcu_read_lock(); |
560 | spin_lock_bh(&in_dev->mc_tomb_lock); | 576 | spin_lock_bh(&in_dev->mc_tomb_lock); |
561 | 577 | ||
562 | /* deleted MCA's */ | 578 | /* deleted MCA's */ |
@@ -593,7 +609,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) | |||
593 | spin_unlock_bh(&in_dev->mc_tomb_lock); | 609 | spin_unlock_bh(&in_dev->mc_tomb_lock); |
594 | 610 | ||
595 | /* change recs */ | 611 | /* change recs */ |
596 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 612 | for_each_pmc_rcu(in_dev, pmc) { |
597 | spin_lock_bh(&pmc->lock); | 613 | spin_lock_bh(&pmc->lock); |
598 | if (pmc->sfcount[MCAST_EXCLUDE]) { | 614 | if (pmc->sfcount[MCAST_EXCLUDE]) { |
599 | type = IGMPV3_BLOCK_OLD_SOURCES; | 615 | type = IGMPV3_BLOCK_OLD_SOURCES; |
@@ -616,7 +632,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) | |||
616 | } | 632 | } |
617 | spin_unlock_bh(&pmc->lock); | 633 | spin_unlock_bh(&pmc->lock); |
618 | } | 634 | } |
619 | read_unlock(&in_dev->mc_list_lock); | 635 | rcu_read_unlock(); |
620 | 636 | ||
621 | if (!skb) | 637 | if (!skb) |
622 | return; | 638 | return; |
@@ -813,14 +829,14 @@ static void igmp_heard_report(struct in_device *in_dev, __be32 group) | |||
813 | if (group == IGMP_ALL_HOSTS) | 829 | if (group == IGMP_ALL_HOSTS) |
814 | return; | 830 | return; |
815 | 831 | ||
816 | read_lock(&in_dev->mc_list_lock); | 832 | rcu_read_lock(); |
817 | for (im=in_dev->mc_list; im!=NULL; im=im->next) { | 833 | for_each_pmc_rcu(in_dev, im) { |
818 | if (im->multiaddr == group) { | 834 | if (im->multiaddr == group) { |
819 | igmp_stop_timer(im); | 835 | igmp_stop_timer(im); |
820 | break; | 836 | break; |
821 | } | 837 | } |
822 | } | 838 | } |
823 | read_unlock(&in_dev->mc_list_lock); | 839 | rcu_read_unlock(); |
824 | } | 840 | } |
825 | 841 | ||
826 | static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | 842 | static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, |
@@ -906,8 +922,8 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
906 | * - Use the igmp->igmp_code field as the maximum | 922 | * - Use the igmp->igmp_code field as the maximum |
907 | * delay possible | 923 | * delay possible |
908 | */ | 924 | */ |
909 | read_lock(&in_dev->mc_list_lock); | 925 | rcu_read_lock(); |
910 | for (im=in_dev->mc_list; im!=NULL; im=im->next) { | 926 | for_each_pmc_rcu(in_dev, im) { |
911 | int changed; | 927 | int changed; |
912 | 928 | ||
913 | if (group && group != im->multiaddr) | 929 | if (group && group != im->multiaddr) |
@@ -925,7 +941,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
925 | if (changed) | 941 | if (changed) |
926 | igmp_mod_timer(im, max_delay); | 942 | igmp_mod_timer(im, max_delay); |
927 | } | 943 | } |
928 | read_unlock(&in_dev->mc_list_lock); | 944 | rcu_read_unlock(); |
929 | } | 945 | } |
930 | 946 | ||
931 | /* called in rcu_read_lock() section */ | 947 | /* called in rcu_read_lock() section */ |
@@ -961,7 +977,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
961 | case IGMP_HOST_MEMBERSHIP_REPORT: | 977 | case IGMP_HOST_MEMBERSHIP_REPORT: |
962 | case IGMPV2_HOST_MEMBERSHIP_REPORT: | 978 | case IGMPV2_HOST_MEMBERSHIP_REPORT: |
963 | /* Is it our report looped back? */ | 979 | /* Is it our report looped back? */ |
964 | if (skb_rtable(skb)->fl.iif == 0) | 980 | if (rt_is_output_route(skb_rtable(skb))) |
965 | break; | 981 | break; |
966 | /* don't rely on MC router hearing unicast reports */ | 982 | /* don't rely on MC router hearing unicast reports */ |
967 | if (skb->pkt_type == PACKET_MULTICAST || | 983 | if (skb->pkt_type == PACKET_MULTICAST || |
@@ -1110,8 +1126,8 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) | |||
1110 | kfree(pmc); | 1126 | kfree(pmc); |
1111 | } | 1127 | } |
1112 | /* clear dead sources, too */ | 1128 | /* clear dead sources, too */ |
1113 | read_lock(&in_dev->mc_list_lock); | 1129 | rcu_read_lock(); |
1114 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 1130 | for_each_pmc_rcu(in_dev, pmc) { |
1115 | struct ip_sf_list *psf, *psf_next; | 1131 | struct ip_sf_list *psf, *psf_next; |
1116 | 1132 | ||
1117 | spin_lock_bh(&pmc->lock); | 1133 | spin_lock_bh(&pmc->lock); |
@@ -1123,7 +1139,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) | |||
1123 | kfree(psf); | 1139 | kfree(psf); |
1124 | } | 1140 | } |
1125 | } | 1141 | } |
1126 | read_unlock(&in_dev->mc_list_lock); | 1142 | rcu_read_unlock(); |
1127 | } | 1143 | } |
1128 | #endif | 1144 | #endif |
1129 | 1145 | ||
@@ -1209,7 +1225,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
1209 | 1225 | ||
1210 | ASSERT_RTNL(); | 1226 | ASSERT_RTNL(); |
1211 | 1227 | ||
1212 | for (im=in_dev->mc_list; im; im=im->next) { | 1228 | for_each_pmc_rtnl(in_dev, im) { |
1213 | if (im->multiaddr == addr) { | 1229 | if (im->multiaddr == addr) { |
1214 | im->users++; | 1230 | im->users++; |
1215 | ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0); | 1231 | ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0); |
@@ -1217,7 +1233,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
1217 | } | 1233 | } |
1218 | } | 1234 | } |
1219 | 1235 | ||
1220 | im = kmalloc(sizeof(*im), GFP_KERNEL); | 1236 | im = kzalloc(sizeof(*im), GFP_KERNEL); |
1221 | if (!im) | 1237 | if (!im) |
1222 | goto out; | 1238 | goto out; |
1223 | 1239 | ||
@@ -1227,26 +1243,18 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
1227 | im->multiaddr = addr; | 1243 | im->multiaddr = addr; |
1228 | /* initial mode is (EX, empty) */ | 1244 | /* initial mode is (EX, empty) */ |
1229 | im->sfmode = MCAST_EXCLUDE; | 1245 | im->sfmode = MCAST_EXCLUDE; |
1230 | im->sfcount[MCAST_INCLUDE] = 0; | ||
1231 | im->sfcount[MCAST_EXCLUDE] = 1; | 1246 | im->sfcount[MCAST_EXCLUDE] = 1; |
1232 | im->sources = NULL; | ||
1233 | im->tomb = NULL; | ||
1234 | im->crcount = 0; | ||
1235 | atomic_set(&im->refcnt, 1); | 1247 | atomic_set(&im->refcnt, 1); |
1236 | spin_lock_init(&im->lock); | 1248 | spin_lock_init(&im->lock); |
1237 | #ifdef CONFIG_IP_MULTICAST | 1249 | #ifdef CONFIG_IP_MULTICAST |
1238 | im->tm_running = 0; | ||
1239 | setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im); | 1250 | setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im); |
1240 | im->unsolicit_count = IGMP_Unsolicited_Report_Count; | 1251 | im->unsolicit_count = IGMP_Unsolicited_Report_Count; |
1241 | im->reporter = 0; | ||
1242 | im->gsquery = 0; | ||
1243 | #endif | 1252 | #endif |
1244 | im->loaded = 0; | 1253 | |
1245 | write_lock_bh(&in_dev->mc_list_lock); | 1254 | im->next_rcu = in_dev->mc_list; |
1246 | im->next = in_dev->mc_list; | ||
1247 | in_dev->mc_list = im; | ||
1248 | in_dev->mc_count++; | 1255 | in_dev->mc_count++; |
1249 | write_unlock_bh(&in_dev->mc_list_lock); | 1256 | rcu_assign_pointer(in_dev->mc_list, im); |
1257 | |||
1250 | #ifdef CONFIG_IP_MULTICAST | 1258 | #ifdef CONFIG_IP_MULTICAST |
1251 | igmpv3_del_delrec(in_dev, im->multiaddr); | 1259 | igmpv3_del_delrec(in_dev, im->multiaddr); |
1252 | #endif | 1260 | #endif |
@@ -1287,17 +1295,18 @@ EXPORT_SYMBOL(ip_mc_rejoin_group); | |||
1287 | 1295 | ||
1288 | void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) | 1296 | void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) |
1289 | { | 1297 | { |
1290 | struct ip_mc_list *i, **ip; | 1298 | struct ip_mc_list *i; |
1299 | struct ip_mc_list __rcu **ip; | ||
1291 | 1300 | ||
1292 | ASSERT_RTNL(); | 1301 | ASSERT_RTNL(); |
1293 | 1302 | ||
1294 | for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { | 1303 | for (ip = &in_dev->mc_list; |
1304 | (i = rtnl_dereference(*ip)) != NULL; | ||
1305 | ip = &i->next_rcu) { | ||
1295 | if (i->multiaddr == addr) { | 1306 | if (i->multiaddr == addr) { |
1296 | if (--i->users == 0) { | 1307 | if (--i->users == 0) { |
1297 | write_lock_bh(&in_dev->mc_list_lock); | 1308 | *ip = i->next_rcu; |
1298 | *ip = i->next; | ||
1299 | in_dev->mc_count--; | 1309 | in_dev->mc_count--; |
1300 | write_unlock_bh(&in_dev->mc_list_lock); | ||
1301 | igmp_group_dropped(i); | 1310 | igmp_group_dropped(i); |
1302 | 1311 | ||
1303 | if (!in_dev->dead) | 1312 | if (!in_dev->dead) |
@@ -1316,34 +1325,34 @@ EXPORT_SYMBOL(ip_mc_dec_group); | |||
1316 | 1325 | ||
1317 | void ip_mc_unmap(struct in_device *in_dev) | 1326 | void ip_mc_unmap(struct in_device *in_dev) |
1318 | { | 1327 | { |
1319 | struct ip_mc_list *i; | 1328 | struct ip_mc_list *pmc; |
1320 | 1329 | ||
1321 | ASSERT_RTNL(); | 1330 | ASSERT_RTNL(); |
1322 | 1331 | ||
1323 | for (i = in_dev->mc_list; i; i = i->next) | 1332 | for_each_pmc_rtnl(in_dev, pmc) |
1324 | igmp_group_dropped(i); | 1333 | igmp_group_dropped(pmc); |
1325 | } | 1334 | } |
1326 | 1335 | ||
1327 | void ip_mc_remap(struct in_device *in_dev) | 1336 | void ip_mc_remap(struct in_device *in_dev) |
1328 | { | 1337 | { |
1329 | struct ip_mc_list *i; | 1338 | struct ip_mc_list *pmc; |
1330 | 1339 | ||
1331 | ASSERT_RTNL(); | 1340 | ASSERT_RTNL(); |
1332 | 1341 | ||
1333 | for (i = in_dev->mc_list; i; i = i->next) | 1342 | for_each_pmc_rtnl(in_dev, pmc) |
1334 | igmp_group_added(i); | 1343 | igmp_group_added(pmc); |
1335 | } | 1344 | } |
1336 | 1345 | ||
1337 | /* Device going down */ | 1346 | /* Device going down */ |
1338 | 1347 | ||
1339 | void ip_mc_down(struct in_device *in_dev) | 1348 | void ip_mc_down(struct in_device *in_dev) |
1340 | { | 1349 | { |
1341 | struct ip_mc_list *i; | 1350 | struct ip_mc_list *pmc; |
1342 | 1351 | ||
1343 | ASSERT_RTNL(); | 1352 | ASSERT_RTNL(); |
1344 | 1353 | ||
1345 | for (i=in_dev->mc_list; i; i=i->next) | 1354 | for_each_pmc_rtnl(in_dev, pmc) |
1346 | igmp_group_dropped(i); | 1355 | igmp_group_dropped(pmc); |
1347 | 1356 | ||
1348 | #ifdef CONFIG_IP_MULTICAST | 1357 | #ifdef CONFIG_IP_MULTICAST |
1349 | in_dev->mr_ifc_count = 0; | 1358 | in_dev->mr_ifc_count = 0; |
@@ -1374,7 +1383,6 @@ void ip_mc_init_dev(struct in_device *in_dev) | |||
1374 | in_dev->mr_qrv = IGMP_Unsolicited_Report_Count; | 1383 | in_dev->mr_qrv = IGMP_Unsolicited_Report_Count; |
1375 | #endif | 1384 | #endif |
1376 | 1385 | ||
1377 | rwlock_init(&in_dev->mc_list_lock); | ||
1378 | spin_lock_init(&in_dev->mc_tomb_lock); | 1386 | spin_lock_init(&in_dev->mc_tomb_lock); |
1379 | } | 1387 | } |
1380 | 1388 | ||
@@ -1382,14 +1390,14 @@ void ip_mc_init_dev(struct in_device *in_dev) | |||
1382 | 1390 | ||
1383 | void ip_mc_up(struct in_device *in_dev) | 1391 | void ip_mc_up(struct in_device *in_dev) |
1384 | { | 1392 | { |
1385 | struct ip_mc_list *i; | 1393 | struct ip_mc_list *pmc; |
1386 | 1394 | ||
1387 | ASSERT_RTNL(); | 1395 | ASSERT_RTNL(); |
1388 | 1396 | ||
1389 | ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); | 1397 | ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); |
1390 | 1398 | ||
1391 | for (i=in_dev->mc_list; i; i=i->next) | 1399 | for_each_pmc_rtnl(in_dev, pmc) |
1392 | igmp_group_added(i); | 1400 | igmp_group_added(pmc); |
1393 | } | 1401 | } |
1394 | 1402 | ||
1395 | /* | 1403 | /* |
@@ -1405,17 +1413,13 @@ void ip_mc_destroy_dev(struct in_device *in_dev) | |||
1405 | /* Deactivate timers */ | 1413 | /* Deactivate timers */ |
1406 | ip_mc_down(in_dev); | 1414 | ip_mc_down(in_dev); |
1407 | 1415 | ||
1408 | write_lock_bh(&in_dev->mc_list_lock); | 1416 | while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) { |
1409 | while ((i = in_dev->mc_list) != NULL) { | 1417 | in_dev->mc_list = i->next_rcu; |
1410 | in_dev->mc_list = i->next; | ||
1411 | in_dev->mc_count--; | 1418 | in_dev->mc_count--; |
1412 | write_unlock_bh(&in_dev->mc_list_lock); | 1419 | |
1413 | igmp_group_dropped(i); | 1420 | igmp_group_dropped(i); |
1414 | ip_ma_put(i); | 1421 | ip_ma_put(i); |
1415 | |||
1416 | write_lock_bh(&in_dev->mc_list_lock); | ||
1417 | } | 1422 | } |
1418 | write_unlock_bh(&in_dev->mc_list_lock); | ||
1419 | } | 1423 | } |
1420 | 1424 | ||
1421 | /* RTNL is locked */ | 1425 | /* RTNL is locked */ |
@@ -1513,18 +1517,18 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
1513 | 1517 | ||
1514 | if (!in_dev) | 1518 | if (!in_dev) |
1515 | return -ENODEV; | 1519 | return -ENODEV; |
1516 | read_lock(&in_dev->mc_list_lock); | 1520 | rcu_read_lock(); |
1517 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 1521 | for_each_pmc_rcu(in_dev, pmc) { |
1518 | if (*pmca == pmc->multiaddr) | 1522 | if (*pmca == pmc->multiaddr) |
1519 | break; | 1523 | break; |
1520 | } | 1524 | } |
1521 | if (!pmc) { | 1525 | if (!pmc) { |
1522 | /* MCA not found?? bug */ | 1526 | /* MCA not found?? bug */ |
1523 | read_unlock(&in_dev->mc_list_lock); | 1527 | rcu_read_unlock(); |
1524 | return -ESRCH; | 1528 | return -ESRCH; |
1525 | } | 1529 | } |
1526 | spin_lock_bh(&pmc->lock); | 1530 | spin_lock_bh(&pmc->lock); |
1527 | read_unlock(&in_dev->mc_list_lock); | 1531 | rcu_read_unlock(); |
1528 | #ifdef CONFIG_IP_MULTICAST | 1532 | #ifdef CONFIG_IP_MULTICAST |
1529 | sf_markstate(pmc); | 1533 | sf_markstate(pmc); |
1530 | #endif | 1534 | #endif |
@@ -1685,18 +1689,18 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
1685 | 1689 | ||
1686 | if (!in_dev) | 1690 | if (!in_dev) |
1687 | return -ENODEV; | 1691 | return -ENODEV; |
1688 | read_lock(&in_dev->mc_list_lock); | 1692 | rcu_read_lock(); |
1689 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 1693 | for_each_pmc_rcu(in_dev, pmc) { |
1690 | if (*pmca == pmc->multiaddr) | 1694 | if (*pmca == pmc->multiaddr) |
1691 | break; | 1695 | break; |
1692 | } | 1696 | } |
1693 | if (!pmc) { | 1697 | if (!pmc) { |
1694 | /* MCA not found?? bug */ | 1698 | /* MCA not found?? bug */ |
1695 | read_unlock(&in_dev->mc_list_lock); | 1699 | rcu_read_unlock(); |
1696 | return -ESRCH; | 1700 | return -ESRCH; |
1697 | } | 1701 | } |
1698 | spin_lock_bh(&pmc->lock); | 1702 | spin_lock_bh(&pmc->lock); |
1699 | read_unlock(&in_dev->mc_list_lock); | 1703 | rcu_read_unlock(); |
1700 | 1704 | ||
1701 | #ifdef CONFIG_IP_MULTICAST | 1705 | #ifdef CONFIG_IP_MULTICAST |
1702 | sf_markstate(pmc); | 1706 | sf_markstate(pmc); |
@@ -1793,7 +1797,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
1793 | 1797 | ||
1794 | err = -EADDRINUSE; | 1798 | err = -EADDRINUSE; |
1795 | ifindex = imr->imr_ifindex; | 1799 | ifindex = imr->imr_ifindex; |
1796 | for (i = inet->mc_list; i; i = i->next) { | 1800 | for_each_pmc_rtnl(inet, i) { |
1797 | if (i->multi.imr_multiaddr.s_addr == addr && | 1801 | if (i->multi.imr_multiaddr.s_addr == addr && |
1798 | i->multi.imr_ifindex == ifindex) | 1802 | i->multi.imr_ifindex == ifindex) |
1799 | goto done; | 1803 | goto done; |
@@ -1807,7 +1811,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
1807 | goto done; | 1811 | goto done; |
1808 | 1812 | ||
1809 | memcpy(&iml->multi, imr, sizeof(*imr)); | 1813 | memcpy(&iml->multi, imr, sizeof(*imr)); |
1810 | iml->next = inet->mc_list; | 1814 | iml->next_rcu = inet->mc_list; |
1811 | iml->sflist = NULL; | 1815 | iml->sflist = NULL; |
1812 | iml->sfmode = MCAST_EXCLUDE; | 1816 | iml->sfmode = MCAST_EXCLUDE; |
1813 | rcu_assign_pointer(inet->mc_list, iml); | 1817 | rcu_assign_pointer(inet->mc_list, iml); |
@@ -1821,17 +1825,14 @@ EXPORT_SYMBOL(ip_mc_join_group); | |||
1821 | 1825 | ||
1822 | static void ip_sf_socklist_reclaim(struct rcu_head *rp) | 1826 | static void ip_sf_socklist_reclaim(struct rcu_head *rp) |
1823 | { | 1827 | { |
1824 | struct ip_sf_socklist *psf; | 1828 | kfree(container_of(rp, struct ip_sf_socklist, rcu)); |
1825 | |||
1826 | psf = container_of(rp, struct ip_sf_socklist, rcu); | ||
1827 | /* sk_omem_alloc should have been decreased by the caller*/ | 1829 | /* sk_omem_alloc should have been decreased by the caller*/ |
1828 | kfree(psf); | ||
1829 | } | 1830 | } |
1830 | 1831 | ||
1831 | static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, | 1832 | static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, |
1832 | struct in_device *in_dev) | 1833 | struct in_device *in_dev) |
1833 | { | 1834 | { |
1834 | struct ip_sf_socklist *psf = iml->sflist; | 1835 | struct ip_sf_socklist *psf = rtnl_dereference(iml->sflist); |
1835 | int err; | 1836 | int err; |
1836 | 1837 | ||
1837 | if (psf == NULL) { | 1838 | if (psf == NULL) { |
@@ -1851,11 +1852,8 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, | |||
1851 | 1852 | ||
1852 | static void ip_mc_socklist_reclaim(struct rcu_head *rp) | 1853 | static void ip_mc_socklist_reclaim(struct rcu_head *rp) |
1853 | { | 1854 | { |
1854 | struct ip_mc_socklist *iml; | 1855 | kfree(container_of(rp, struct ip_mc_socklist, rcu)); |
1855 | |||
1856 | iml = container_of(rp, struct ip_mc_socklist, rcu); | ||
1857 | /* sk_omem_alloc should have been decreased by the caller*/ | 1856 | /* sk_omem_alloc should have been decreased by the caller*/ |
1858 | kfree(iml); | ||
1859 | } | 1857 | } |
1860 | 1858 | ||
1861 | 1859 | ||
@@ -1866,7 +1864,8 @@ static void ip_mc_socklist_reclaim(struct rcu_head *rp) | |||
1866 | int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | 1864 | int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) |
1867 | { | 1865 | { |
1868 | struct inet_sock *inet = inet_sk(sk); | 1866 | struct inet_sock *inet = inet_sk(sk); |
1869 | struct ip_mc_socklist *iml, **imlp; | 1867 | struct ip_mc_socklist *iml; |
1868 | struct ip_mc_socklist __rcu **imlp; | ||
1870 | struct in_device *in_dev; | 1869 | struct in_device *in_dev; |
1871 | struct net *net = sock_net(sk); | 1870 | struct net *net = sock_net(sk); |
1872 | __be32 group = imr->imr_multiaddr.s_addr; | 1871 | __be32 group = imr->imr_multiaddr.s_addr; |
@@ -1876,7 +1875,9 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
1876 | rtnl_lock(); | 1875 | rtnl_lock(); |
1877 | in_dev = ip_mc_find_dev(net, imr); | 1876 | in_dev = ip_mc_find_dev(net, imr); |
1878 | ifindex = imr->imr_ifindex; | 1877 | ifindex = imr->imr_ifindex; |
1879 | for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) { | 1878 | for (imlp = &inet->mc_list; |
1879 | (iml = rtnl_dereference(*imlp)) != NULL; | ||
1880 | imlp = &iml->next_rcu) { | ||
1880 | if (iml->multi.imr_multiaddr.s_addr != group) | 1881 | if (iml->multi.imr_multiaddr.s_addr != group) |
1881 | continue; | 1882 | continue; |
1882 | if (ifindex) { | 1883 | if (ifindex) { |
@@ -1888,7 +1889,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
1888 | 1889 | ||
1889 | (void) ip_mc_leave_src(sk, iml, in_dev); | 1890 | (void) ip_mc_leave_src(sk, iml, in_dev); |
1890 | 1891 | ||
1891 | rcu_assign_pointer(*imlp, iml->next); | 1892 | *imlp = iml->next_rcu; |
1892 | 1893 | ||
1893 | if (in_dev) | 1894 | if (in_dev) |
1894 | ip_mc_dec_group(in_dev, group); | 1895 | ip_mc_dec_group(in_dev, group); |
@@ -1934,7 +1935,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
1934 | } | 1935 | } |
1935 | err = -EADDRNOTAVAIL; | 1936 | err = -EADDRNOTAVAIL; |
1936 | 1937 | ||
1937 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 1938 | for_each_pmc_rtnl(inet, pmc) { |
1938 | if ((pmc->multi.imr_multiaddr.s_addr == | 1939 | if ((pmc->multi.imr_multiaddr.s_addr == |
1939 | imr.imr_multiaddr.s_addr) && | 1940 | imr.imr_multiaddr.s_addr) && |
1940 | (pmc->multi.imr_ifindex == imr.imr_ifindex)) | 1941 | (pmc->multi.imr_ifindex == imr.imr_ifindex)) |
@@ -1958,7 +1959,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
1958 | pmc->sfmode = omode; | 1959 | pmc->sfmode = omode; |
1959 | } | 1960 | } |
1960 | 1961 | ||
1961 | psl = pmc->sflist; | 1962 | psl = rtnl_dereference(pmc->sflist); |
1962 | if (!add) { | 1963 | if (!add) { |
1963 | if (!psl) | 1964 | if (!psl) |
1964 | goto done; /* err = -EADDRNOTAVAIL */ | 1965 | goto done; /* err = -EADDRNOTAVAIL */ |
@@ -2077,7 +2078,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
2077 | goto done; | 2078 | goto done; |
2078 | } | 2079 | } |
2079 | 2080 | ||
2080 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 2081 | for_each_pmc_rtnl(inet, pmc) { |
2081 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && | 2082 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && |
2082 | pmc->multi.imr_ifindex == imr.imr_ifindex) | 2083 | pmc->multi.imr_ifindex == imr.imr_ifindex) |
2083 | break; | 2084 | break; |
@@ -2107,7 +2108,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
2107 | (void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr, | 2108 | (void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr, |
2108 | msf->imsf_fmode, 0, NULL, 0); | 2109 | msf->imsf_fmode, 0, NULL, 0); |
2109 | } | 2110 | } |
2110 | psl = pmc->sflist; | 2111 | psl = rtnl_dereference(pmc->sflist); |
2111 | if (psl) { | 2112 | if (psl) { |
2112 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, | 2113 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, |
2113 | psl->sl_count, psl->sl_addr, 0); | 2114 | psl->sl_count, psl->sl_addr, 0); |
@@ -2155,7 +2156,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
2155 | } | 2156 | } |
2156 | err = -EADDRNOTAVAIL; | 2157 | err = -EADDRNOTAVAIL; |
2157 | 2158 | ||
2158 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 2159 | for_each_pmc_rtnl(inet, pmc) { |
2159 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && | 2160 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && |
2160 | pmc->multi.imr_ifindex == imr.imr_ifindex) | 2161 | pmc->multi.imr_ifindex == imr.imr_ifindex) |
2161 | break; | 2162 | break; |
@@ -2163,7 +2164,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
2163 | if (!pmc) /* must have a prior join */ | 2164 | if (!pmc) /* must have a prior join */ |
2164 | goto done; | 2165 | goto done; |
2165 | msf->imsf_fmode = pmc->sfmode; | 2166 | msf->imsf_fmode = pmc->sfmode; |
2166 | psl = pmc->sflist; | 2167 | psl = rtnl_dereference(pmc->sflist); |
2167 | rtnl_unlock(); | 2168 | rtnl_unlock(); |
2168 | if (!psl) { | 2169 | if (!psl) { |
2169 | len = 0; | 2170 | len = 0; |
@@ -2208,7 +2209,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
2208 | 2209 | ||
2209 | err = -EADDRNOTAVAIL; | 2210 | err = -EADDRNOTAVAIL; |
2210 | 2211 | ||
2211 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 2212 | for_each_pmc_rtnl(inet, pmc) { |
2212 | if (pmc->multi.imr_multiaddr.s_addr == addr && | 2213 | if (pmc->multi.imr_multiaddr.s_addr == addr && |
2213 | pmc->multi.imr_ifindex == gsf->gf_interface) | 2214 | pmc->multi.imr_ifindex == gsf->gf_interface) |
2214 | break; | 2215 | break; |
@@ -2216,7 +2217,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
2216 | if (!pmc) /* must have a prior join */ | 2217 | if (!pmc) /* must have a prior join */ |
2217 | goto done; | 2218 | goto done; |
2218 | gsf->gf_fmode = pmc->sfmode; | 2219 | gsf->gf_fmode = pmc->sfmode; |
2219 | psl = pmc->sflist; | 2220 | psl = rtnl_dereference(pmc->sflist); |
2220 | rtnl_unlock(); | 2221 | rtnl_unlock(); |
2221 | count = psl ? psl->sl_count : 0; | 2222 | count = psl ? psl->sl_count : 0; |
2222 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; | 2223 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; |
@@ -2257,7 +2258,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | |||
2257 | goto out; | 2258 | goto out; |
2258 | 2259 | ||
2259 | rcu_read_lock(); | 2260 | rcu_read_lock(); |
2260 | for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) { | 2261 | for_each_pmc_rcu(inet, pmc) { |
2261 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && | 2262 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && |
2262 | pmc->multi.imr_ifindex == dif) | 2263 | pmc->multi.imr_ifindex == dif) |
2263 | break; | 2264 | break; |
@@ -2265,7 +2266,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | |||
2265 | ret = inet->mc_all; | 2266 | ret = inet->mc_all; |
2266 | if (!pmc) | 2267 | if (!pmc) |
2267 | goto unlock; | 2268 | goto unlock; |
2268 | psl = pmc->sflist; | 2269 | psl = rcu_dereference(pmc->sflist); |
2269 | ret = (pmc->sfmode == MCAST_EXCLUDE); | 2270 | ret = (pmc->sfmode == MCAST_EXCLUDE); |
2270 | if (!psl) | 2271 | if (!psl) |
2271 | goto unlock; | 2272 | goto unlock; |
@@ -2300,10 +2301,10 @@ void ip_mc_drop_socket(struct sock *sk) | |||
2300 | return; | 2301 | return; |
2301 | 2302 | ||
2302 | rtnl_lock(); | 2303 | rtnl_lock(); |
2303 | while ((iml = inet->mc_list) != NULL) { | 2304 | while ((iml = rtnl_dereference(inet->mc_list)) != NULL) { |
2304 | struct in_device *in_dev; | 2305 | struct in_device *in_dev; |
2305 | rcu_assign_pointer(inet->mc_list, iml->next); | ||
2306 | 2306 | ||
2307 | inet->mc_list = iml->next_rcu; | ||
2307 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); | 2308 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); |
2308 | (void) ip_mc_leave_src(sk, iml, in_dev); | 2309 | (void) ip_mc_leave_src(sk, iml, in_dev); |
2309 | if (in_dev != NULL) | 2310 | if (in_dev != NULL) |
@@ -2321,8 +2322,8 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p | |||
2321 | struct ip_sf_list *psf; | 2322 | struct ip_sf_list *psf; |
2322 | int rv = 0; | 2323 | int rv = 0; |
2323 | 2324 | ||
2324 | read_lock(&in_dev->mc_list_lock); | 2325 | rcu_read_lock(); |
2325 | for (im=in_dev->mc_list; im; im=im->next) { | 2326 | for_each_pmc_rcu(in_dev, im) { |
2326 | if (im->multiaddr == mc_addr) | 2327 | if (im->multiaddr == mc_addr) |
2327 | break; | 2328 | break; |
2328 | } | 2329 | } |
@@ -2343,7 +2344,7 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p | |||
2343 | } else | 2344 | } else |
2344 | rv = 1; /* unspecified source; tentatively allow */ | 2345 | rv = 1; /* unspecified source; tentatively allow */ |
2345 | } | 2346 | } |
2346 | read_unlock(&in_dev->mc_list_lock); | 2347 | rcu_read_unlock(); |
2347 | return rv; | 2348 | return rv; |
2348 | } | 2349 | } |
2349 | 2350 | ||
@@ -2369,13 +2370,11 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) | |||
2369 | in_dev = __in_dev_get_rcu(state->dev); | 2370 | in_dev = __in_dev_get_rcu(state->dev); |
2370 | if (!in_dev) | 2371 | if (!in_dev) |
2371 | continue; | 2372 | continue; |
2372 | read_lock(&in_dev->mc_list_lock); | 2373 | im = rcu_dereference(in_dev->mc_list); |
2373 | im = in_dev->mc_list; | ||
2374 | if (im) { | 2374 | if (im) { |
2375 | state->in_dev = in_dev; | 2375 | state->in_dev = in_dev; |
2376 | break; | 2376 | break; |
2377 | } | 2377 | } |
2378 | read_unlock(&in_dev->mc_list_lock); | ||
2379 | } | 2378 | } |
2380 | return im; | 2379 | return im; |
2381 | } | 2380 | } |
@@ -2383,11 +2382,9 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) | |||
2383 | static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im) | 2382 | static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im) |
2384 | { | 2383 | { |
2385 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); | 2384 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); |
2386 | im = im->next; | ||
2387 | while (!im) { | ||
2388 | if (likely(state->in_dev != NULL)) | ||
2389 | read_unlock(&state->in_dev->mc_list_lock); | ||
2390 | 2385 | ||
2386 | im = rcu_dereference(im->next_rcu); | ||
2387 | while (!im) { | ||
2391 | state->dev = next_net_device_rcu(state->dev); | 2388 | state->dev = next_net_device_rcu(state->dev); |
2392 | if (!state->dev) { | 2389 | if (!state->dev) { |
2393 | state->in_dev = NULL; | 2390 | state->in_dev = NULL; |
@@ -2396,8 +2393,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li | |||
2396 | state->in_dev = __in_dev_get_rcu(state->dev); | 2393 | state->in_dev = __in_dev_get_rcu(state->dev); |
2397 | if (!state->in_dev) | 2394 | if (!state->in_dev) |
2398 | continue; | 2395 | continue; |
2399 | read_lock(&state->in_dev->mc_list_lock); | 2396 | im = rcu_dereference(state->in_dev->mc_list); |
2400 | im = state->in_dev->mc_list; | ||
2401 | } | 2397 | } |
2402 | return im; | 2398 | return im; |
2403 | } | 2399 | } |
@@ -2433,10 +2429,8 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v) | |||
2433 | __releases(rcu) | 2429 | __releases(rcu) |
2434 | { | 2430 | { |
2435 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); | 2431 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); |
2436 | if (likely(state->in_dev != NULL)) { | 2432 | |
2437 | read_unlock(&state->in_dev->mc_list_lock); | 2433 | state->in_dev = NULL; |
2438 | state->in_dev = NULL; | ||
2439 | } | ||
2440 | state->dev = NULL; | 2434 | state->dev = NULL; |
2441 | rcu_read_unlock(); | 2435 | rcu_read_unlock(); |
2442 | } | 2436 | } |
@@ -2458,7 +2452,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v) | |||
2458 | querier = "NONE"; | 2452 | querier = "NONE"; |
2459 | #endif | 2453 | #endif |
2460 | 2454 | ||
2461 | if (state->in_dev->mc_list == im) { | 2455 | if (rcu_dereference(state->in_dev->mc_list) == im) { |
2462 | seq_printf(seq, "%d\t%-10s: %5d %7s\n", | 2456 | seq_printf(seq, "%d\t%-10s: %5d %7s\n", |
2463 | state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier); | 2457 | state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier); |
2464 | } | 2458 | } |
@@ -2517,8 +2511,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) | |||
2517 | idev = __in_dev_get_rcu(state->dev); | 2511 | idev = __in_dev_get_rcu(state->dev); |
2518 | if (unlikely(idev == NULL)) | 2512 | if (unlikely(idev == NULL)) |
2519 | continue; | 2513 | continue; |
2520 | read_lock(&idev->mc_list_lock); | 2514 | im = rcu_dereference(idev->mc_list); |
2521 | im = idev->mc_list; | ||
2522 | if (likely(im != NULL)) { | 2515 | if (likely(im != NULL)) { |
2523 | spin_lock_bh(&im->lock); | 2516 | spin_lock_bh(&im->lock); |
2524 | psf = im->sources; | 2517 | psf = im->sources; |
@@ -2529,7 +2522,6 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) | |||
2529 | } | 2522 | } |
2530 | spin_unlock_bh(&im->lock); | 2523 | spin_unlock_bh(&im->lock); |
2531 | } | 2524 | } |
2532 | read_unlock(&idev->mc_list_lock); | ||
2533 | } | 2525 | } |
2534 | return psf; | 2526 | return psf; |
2535 | } | 2527 | } |
@@ -2543,9 +2535,6 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l | |||
2543 | spin_unlock_bh(&state->im->lock); | 2535 | spin_unlock_bh(&state->im->lock); |
2544 | state->im = state->im->next; | 2536 | state->im = state->im->next; |
2545 | while (!state->im) { | 2537 | while (!state->im) { |
2546 | if (likely(state->idev != NULL)) | ||
2547 | read_unlock(&state->idev->mc_list_lock); | ||
2548 | |||
2549 | state->dev = next_net_device_rcu(state->dev); | 2538 | state->dev = next_net_device_rcu(state->dev); |
2550 | if (!state->dev) { | 2539 | if (!state->dev) { |
2551 | state->idev = NULL; | 2540 | state->idev = NULL; |
@@ -2554,8 +2543,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l | |||
2554 | state->idev = __in_dev_get_rcu(state->dev); | 2543 | state->idev = __in_dev_get_rcu(state->dev); |
2555 | if (!state->idev) | 2544 | if (!state->idev) |
2556 | continue; | 2545 | continue; |
2557 | read_lock(&state->idev->mc_list_lock); | 2546 | state->im = rcu_dereference(state->idev->mc_list); |
2558 | state->im = state->idev->mc_list; | ||
2559 | } | 2547 | } |
2560 | if (!state->im) | 2548 | if (!state->im) |
2561 | break; | 2549 | break; |
@@ -2601,10 +2589,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) | |||
2601 | spin_unlock_bh(&state->im->lock); | 2589 | spin_unlock_bh(&state->im->lock); |
2602 | state->im = NULL; | 2590 | state->im = NULL; |
2603 | } | 2591 | } |
2604 | if (likely(state->idev != NULL)) { | 2592 | state->idev = NULL; |
2605 | read_unlock(&state->idev->mc_list_lock); | ||
2606 | state->idev = NULL; | ||
2607 | } | ||
2608 | state->dev = NULL; | 2593 | state->dev = NULL; |
2609 | rcu_read_unlock(); | 2594 | rcu_read_unlock(); |
2610 | } | 2595 | } |