diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-10-28 23:09:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-11-08 16:50:08 -0500 |
commit | fc766e4c4965915ab52a1d1fa3c7a7b3e7bc07f0 (patch) | |
tree | d45160f52eea37d4e5149d511c3c577bef253801 /net/decnet | |
parent | e4a7b93bd5d84e1e79917d024d17d745d190fc9a (diff) |
decnet: RCU conversion and get rid of dev_base_lock
While tracking dev_base_lock users, I found decnet used it in
dnet_select_source(), but for a wrong purpose:
Writers only hold RTNL, not dev_base_lock, so readers must use RCU if
they cannot use RTNL.
Adds an rcu_head in struct dn_ifaddr and handle proper RCU management.
Adds __rcu annotation in dn_route as well.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Acked-by: Steven Whitehouse <swhiteho@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/decnet')
-rw-r--r-- | net/decnet/af_decnet.c | 2 | ||||
-rw-r--r-- | net/decnet/dn_dev.c | 100 | ||||
-rw-r--r-- | net/decnet/dn_fib.c | 6 | ||||
-rw-r--r-- | net/decnet/dn_neigh.c | 2 | ||||
-rw-r--r-- | net/decnet/dn_route.c | 68 |
5 files changed, 104 insertions, 74 deletions
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index d6b93d19790f..18b8a2cbdf77 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c | |||
@@ -1848,7 +1848,7 @@ unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu) | |||
1848 | { | 1848 | { |
1849 | unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER; | 1849 | unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER; |
1850 | if (dev) { | 1850 | if (dev) { |
1851 | struct dn_dev *dn_db = dev->dn_ptr; | 1851 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1852 | mtu -= LL_RESERVED_SPACE(dev); | 1852 | mtu -= LL_RESERVED_SPACE(dev); |
1853 | if (dn_db->use_long) | 1853 | if (dn_db->use_long) |
1854 | mtu -= 21; | 1854 | mtu -= 21; |
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 4c409b46aa35..0ba15633c418 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
@@ -267,7 +267,7 @@ static int dn_forwarding_proc(ctl_table *table, int write, | |||
267 | if (table->extra1 == NULL) | 267 | if (table->extra1 == NULL) |
268 | return -EINVAL; | 268 | return -EINVAL; |
269 | 269 | ||
270 | dn_db = dev->dn_ptr; | 270 | dn_db = rcu_dereference_raw(dev->dn_ptr); |
271 | old = dn_db->parms.forwarding; | 271 | old = dn_db->parms.forwarding; |
272 | 272 | ||
273 | err = proc_dointvec(table, write, buffer, lenp, ppos); | 273 | err = proc_dointvec(table, write, buffer, lenp, ppos); |
@@ -332,14 +332,19 @@ static struct dn_ifaddr *dn_dev_alloc_ifa(void) | |||
332 | return ifa; | 332 | return ifa; |
333 | } | 333 | } |
334 | 334 | ||
335 | static __inline__ void dn_dev_free_ifa(struct dn_ifaddr *ifa) | 335 | static void dn_dev_free_ifa_rcu(struct rcu_head *head) |
336 | { | 336 | { |
337 | kfree(ifa); | 337 | kfree(container_of(head, struct dn_ifaddr, rcu)); |
338 | } | 338 | } |
339 | 339 | ||
340 | static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy) | 340 | static void dn_dev_free_ifa(struct dn_ifaddr *ifa) |
341 | { | 341 | { |
342 | struct dn_ifaddr *ifa1 = *ifap; | 342 | call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu); |
343 | } | ||
344 | |||
345 | static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy) | ||
346 | { | ||
347 | struct dn_ifaddr *ifa1 = rtnl_dereference(*ifap); | ||
343 | unsigned char mac_addr[6]; | 348 | unsigned char mac_addr[6]; |
344 | struct net_device *dev = dn_db->dev; | 349 | struct net_device *dev = dn_db->dev; |
345 | 350 | ||
@@ -373,7 +378,9 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
373 | ASSERT_RTNL(); | 378 | ASSERT_RTNL(); |
374 | 379 | ||
375 | /* Check for duplicates */ | 380 | /* Check for duplicates */ |
376 | for(ifa1 = dn_db->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { | 381 | for (ifa1 = rtnl_dereference(dn_db->ifa_list); |
382 | ifa1 != NULL; | ||
383 | ifa1 = rtnl_dereference(ifa1->ifa_next)) { | ||
377 | if (ifa1->ifa_local == ifa->ifa_local) | 384 | if (ifa1->ifa_local == ifa->ifa_local) |
378 | return -EEXIST; | 385 | return -EEXIST; |
379 | } | 386 | } |
@@ -386,7 +393,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
386 | } | 393 | } |
387 | 394 | ||
388 | ifa->ifa_next = dn_db->ifa_list; | 395 | ifa->ifa_next = dn_db->ifa_list; |
389 | dn_db->ifa_list = ifa; | 396 | rcu_assign_pointer(dn_db->ifa_list, ifa); |
390 | 397 | ||
391 | dn_ifaddr_notify(RTM_NEWADDR, ifa); | 398 | dn_ifaddr_notify(RTM_NEWADDR, ifa); |
392 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); | 399 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); |
@@ -396,7 +403,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
396 | 403 | ||
397 | static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa) | 404 | static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa) |
398 | { | 405 | { |
399 | struct dn_dev *dn_db = dev->dn_ptr; | 406 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
400 | int rv; | 407 | int rv; |
401 | 408 | ||
402 | if (dn_db == NULL) { | 409 | if (dn_db == NULL) { |
@@ -425,7 +432,8 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) | |||
425 | struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr; | 432 | struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr; |
426 | struct dn_dev *dn_db; | 433 | struct dn_dev *dn_db; |
427 | struct net_device *dev; | 434 | struct net_device *dev; |
428 | struct dn_ifaddr *ifa = NULL, **ifap = NULL; | 435 | struct dn_ifaddr *ifa = NULL; |
436 | struct dn_ifaddr __rcu **ifap = NULL; | ||
429 | int ret = 0; | 437 | int ret = 0; |
430 | 438 | ||
431 | if (copy_from_user(ifr, arg, DN_IFREQ_SIZE)) | 439 | if (copy_from_user(ifr, arg, DN_IFREQ_SIZE)) |
@@ -454,8 +462,10 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) | |||
454 | goto done; | 462 | goto done; |
455 | } | 463 | } |
456 | 464 | ||
457 | if ((dn_db = dev->dn_ptr) != NULL) { | 465 | if ((dn_db = rtnl_dereference(dev->dn_ptr)) != NULL) { |
458 | for (ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) | 466 | for (ifap = &dn_db->ifa_list; |
467 | (ifa = rtnl_dereference(*ifap)) != NULL; | ||
468 | ifap = &ifa->ifa_next) | ||
459 | if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0) | 469 | if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0) |
460 | break; | 470 | break; |
461 | } | 471 | } |
@@ -558,7 +568,7 @@ static struct dn_dev *dn_dev_by_index(int ifindex) | |||
558 | 568 | ||
559 | dev = __dev_get_by_index(&init_net, ifindex); | 569 | dev = __dev_get_by_index(&init_net, ifindex); |
560 | if (dev) | 570 | if (dev) |
561 | dn_dev = dev->dn_ptr; | 571 | dn_dev = rtnl_dereference(dev->dn_ptr); |
562 | 572 | ||
563 | return dn_dev; | 573 | return dn_dev; |
564 | } | 574 | } |
@@ -576,7 +586,8 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
576 | struct nlattr *tb[IFA_MAX+1]; | 586 | struct nlattr *tb[IFA_MAX+1]; |
577 | struct dn_dev *dn_db; | 587 | struct dn_dev *dn_db; |
578 | struct ifaddrmsg *ifm; | 588 | struct ifaddrmsg *ifm; |
579 | struct dn_ifaddr *ifa, **ifap; | 589 | struct dn_ifaddr *ifa; |
590 | struct dn_ifaddr __rcu **ifap; | ||
580 | int err = -EINVAL; | 591 | int err = -EINVAL; |
581 | 592 | ||
582 | if (!net_eq(net, &init_net)) | 593 | if (!net_eq(net, &init_net)) |
@@ -592,7 +603,9 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
592 | goto errout; | 603 | goto errout; |
593 | 604 | ||
594 | err = -EADDRNOTAVAIL; | 605 | err = -EADDRNOTAVAIL; |
595 | for (ifap = &dn_db->ifa_list; (ifa = *ifap); ifap = &ifa->ifa_next) { | 606 | for (ifap = &dn_db->ifa_list; |
607 | (ifa = rtnl_dereference(*ifap)) != NULL; | ||
608 | ifap = &ifa->ifa_next) { | ||
596 | if (tb[IFA_LOCAL] && | 609 | if (tb[IFA_LOCAL] && |
597 | nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2)) | 610 | nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2)) |
598 | continue; | 611 | continue; |
@@ -632,7 +645,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
632 | if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL) | 645 | if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL) |
633 | return -ENODEV; | 646 | return -ENODEV; |
634 | 647 | ||
635 | if ((dn_db = dev->dn_ptr) == NULL) { | 648 | if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) { |
636 | dn_db = dn_dev_create(dev, &err); | 649 | dn_db = dn_dev_create(dev, &err); |
637 | if (!dn_db) | 650 | if (!dn_db) |
638 | return err; | 651 | return err; |
@@ -748,11 +761,11 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
748 | skip_naddr = 0; | 761 | skip_naddr = 0; |
749 | } | 762 | } |
750 | 763 | ||
751 | if ((dn_db = dev->dn_ptr) == NULL) | 764 | if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) |
752 | goto cont; | 765 | goto cont; |
753 | 766 | ||
754 | for (ifa = dn_db->ifa_list, dn_idx = 0; ifa; | 767 | for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa; |
755 | ifa = ifa->ifa_next, dn_idx++) { | 768 | ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) { |
756 | if (dn_idx < skip_naddr) | 769 | if (dn_idx < skip_naddr) |
757 | continue; | 770 | continue; |
758 | 771 | ||
@@ -773,21 +786,22 @@ done: | |||
773 | 786 | ||
774 | static int dn_dev_get_first(struct net_device *dev, __le16 *addr) | 787 | static int dn_dev_get_first(struct net_device *dev, __le16 *addr) |
775 | { | 788 | { |
776 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 789 | struct dn_dev *dn_db; |
777 | struct dn_ifaddr *ifa; | 790 | struct dn_ifaddr *ifa; |
778 | int rv = -ENODEV; | 791 | int rv = -ENODEV; |
779 | 792 | ||
793 | rcu_read_lock(); | ||
794 | dn_db = rcu_dereference(dev->dn_ptr); | ||
780 | if (dn_db == NULL) | 795 | if (dn_db == NULL) |
781 | goto out; | 796 | goto out; |
782 | 797 | ||
783 | rtnl_lock(); | 798 | ifa = rcu_dereference(dn_db->ifa_list); |
784 | ifa = dn_db->ifa_list; | ||
785 | if (ifa != NULL) { | 799 | if (ifa != NULL) { |
786 | *addr = ifa->ifa_local; | 800 | *addr = ifa->ifa_local; |
787 | rv = 0; | 801 | rv = 0; |
788 | } | 802 | } |
789 | rtnl_unlock(); | ||
790 | out: | 803 | out: |
804 | rcu_read_unlock(); | ||
791 | return rv; | 805 | return rv; |
792 | } | 806 | } |
793 | 807 | ||
@@ -823,7 +837,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
823 | struct endnode_hello_message *msg; | 837 | struct endnode_hello_message *msg; |
824 | struct sk_buff *skb = NULL; | 838 | struct sk_buff *skb = NULL; |
825 | __le16 *pktlen; | 839 | __le16 *pktlen; |
826 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 840 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
827 | 841 | ||
828 | if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL) | 842 | if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL) |
829 | return; | 843 | return; |
@@ -889,7 +903,7 @@ static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn | |||
889 | static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) | 903 | static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) |
890 | { | 904 | { |
891 | int n; | 905 | int n; |
892 | struct dn_dev *dn_db = dev->dn_ptr; | 906 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
893 | struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; | 907 | struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; |
894 | struct sk_buff *skb; | 908 | struct sk_buff *skb; |
895 | size_t size; | 909 | size_t size; |
@@ -960,7 +974,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
960 | 974 | ||
961 | static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa) | 975 | static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa) |
962 | { | 976 | { |
963 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 977 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
964 | 978 | ||
965 | if (dn_db->parms.forwarding == 0) | 979 | if (dn_db->parms.forwarding == 0) |
966 | dn_send_endnode_hello(dev, ifa); | 980 | dn_send_endnode_hello(dev, ifa); |
@@ -998,7 +1012,7 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
998 | 1012 | ||
999 | static int dn_eth_up(struct net_device *dev) | 1013 | static int dn_eth_up(struct net_device *dev) |
1000 | { | 1014 | { |
1001 | struct dn_dev *dn_db = dev->dn_ptr; | 1015 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1002 | 1016 | ||
1003 | if (dn_db->parms.forwarding == 0) | 1017 | if (dn_db->parms.forwarding == 0) |
1004 | dev_mc_add(dev, dn_rt_all_end_mcast); | 1018 | dev_mc_add(dev, dn_rt_all_end_mcast); |
@@ -1012,7 +1026,7 @@ static int dn_eth_up(struct net_device *dev) | |||
1012 | 1026 | ||
1013 | static void dn_eth_down(struct net_device *dev) | 1027 | static void dn_eth_down(struct net_device *dev) |
1014 | { | 1028 | { |
1015 | struct dn_dev *dn_db = dev->dn_ptr; | 1029 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1016 | 1030 | ||
1017 | if (dn_db->parms.forwarding == 0) | 1031 | if (dn_db->parms.forwarding == 0) |
1018 | dev_mc_del(dev, dn_rt_all_end_mcast); | 1032 | dev_mc_del(dev, dn_rt_all_end_mcast); |
@@ -1025,12 +1039,16 @@ static void dn_dev_set_timer(struct net_device *dev); | |||
1025 | static void dn_dev_timer_func(unsigned long arg) | 1039 | static void dn_dev_timer_func(unsigned long arg) |
1026 | { | 1040 | { |
1027 | struct net_device *dev = (struct net_device *)arg; | 1041 | struct net_device *dev = (struct net_device *)arg; |
1028 | struct dn_dev *dn_db = dev->dn_ptr; | 1042 | struct dn_dev *dn_db; |
1029 | struct dn_ifaddr *ifa; | 1043 | struct dn_ifaddr *ifa; |
1030 | 1044 | ||
1045 | rcu_read_lock(); | ||
1046 | dn_db = rcu_dereference(dev->dn_ptr); | ||
1031 | if (dn_db->t3 <= dn_db->parms.t2) { | 1047 | if (dn_db->t3 <= dn_db->parms.t2) { |
1032 | if (dn_db->parms.timer3) { | 1048 | if (dn_db->parms.timer3) { |
1033 | for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { | 1049 | for (ifa = rcu_dereference(dn_db->ifa_list); |
1050 | ifa; | ||
1051 | ifa = rcu_dereference(ifa->ifa_next)) { | ||
1034 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) | 1052 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) |
1035 | dn_db->parms.timer3(dev, ifa); | 1053 | dn_db->parms.timer3(dev, ifa); |
1036 | } | 1054 | } |
@@ -1039,13 +1057,13 @@ static void dn_dev_timer_func(unsigned long arg) | |||
1039 | } else { | 1057 | } else { |
1040 | dn_db->t3 -= dn_db->parms.t2; | 1058 | dn_db->t3 -= dn_db->parms.t2; |
1041 | } | 1059 | } |
1042 | 1060 | rcu_read_unlock(); | |
1043 | dn_dev_set_timer(dev); | 1061 | dn_dev_set_timer(dev); |
1044 | } | 1062 | } |
1045 | 1063 | ||
1046 | static void dn_dev_set_timer(struct net_device *dev) | 1064 | static void dn_dev_set_timer(struct net_device *dev) |
1047 | { | 1065 | { |
1048 | struct dn_dev *dn_db = dev->dn_ptr; | 1066 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1049 | 1067 | ||
1050 | if (dn_db->parms.t2 > dn_db->parms.t3) | 1068 | if (dn_db->parms.t2 > dn_db->parms.t3) |
1051 | dn_db->parms.t2 = dn_db->parms.t3; | 1069 | dn_db->parms.t2 = dn_db->parms.t3; |
@@ -1077,8 +1095,8 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err) | |||
1077 | return NULL; | 1095 | return NULL; |
1078 | 1096 | ||
1079 | memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms)); | 1097 | memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms)); |
1080 | smp_wmb(); | 1098 | |
1081 | dev->dn_ptr = dn_db; | 1099 | rcu_assign_pointer(dev->dn_ptr, dn_db); |
1082 | dn_db->dev = dev; | 1100 | dn_db->dev = dev; |
1083 | init_timer(&dn_db->timer); | 1101 | init_timer(&dn_db->timer); |
1084 | 1102 | ||
@@ -1086,7 +1104,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err) | |||
1086 | 1104 | ||
1087 | dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); | 1105 | dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); |
1088 | if (!dn_db->neigh_parms) { | 1106 | if (!dn_db->neigh_parms) { |
1089 | dev->dn_ptr = NULL; | 1107 | rcu_assign_pointer(dev->dn_ptr, NULL); |
1090 | kfree(dn_db); | 1108 | kfree(dn_db); |
1091 | return NULL; | 1109 | return NULL; |
1092 | } | 1110 | } |
@@ -1125,7 +1143,7 @@ void dn_dev_up(struct net_device *dev) | |||
1125 | struct dn_ifaddr *ifa; | 1143 | struct dn_ifaddr *ifa; |
1126 | __le16 addr = decnet_address; | 1144 | __le16 addr = decnet_address; |
1127 | int maybe_default = 0; | 1145 | int maybe_default = 0; |
1128 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 1146 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
1129 | 1147 | ||
1130 | if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) | 1148 | if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) |
1131 | return; | 1149 | return; |
@@ -1176,7 +1194,7 @@ void dn_dev_up(struct net_device *dev) | |||
1176 | 1194 | ||
1177 | static void dn_dev_delete(struct net_device *dev) | 1195 | static void dn_dev_delete(struct net_device *dev) |
1178 | { | 1196 | { |
1179 | struct dn_dev *dn_db = dev->dn_ptr; | 1197 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
1180 | 1198 | ||
1181 | if (dn_db == NULL) | 1199 | if (dn_db == NULL) |
1182 | return; | 1200 | return; |
@@ -1204,13 +1222,13 @@ static void dn_dev_delete(struct net_device *dev) | |||
1204 | 1222 | ||
1205 | void dn_dev_down(struct net_device *dev) | 1223 | void dn_dev_down(struct net_device *dev) |
1206 | { | 1224 | { |
1207 | struct dn_dev *dn_db = dev->dn_ptr; | 1225 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
1208 | struct dn_ifaddr *ifa; | 1226 | struct dn_ifaddr *ifa; |
1209 | 1227 | ||
1210 | if (dn_db == NULL) | 1228 | if (dn_db == NULL) |
1211 | return; | 1229 | return; |
1212 | 1230 | ||
1213 | while((ifa = dn_db->ifa_list) != NULL) { | 1231 | while ((ifa = rtnl_dereference(dn_db->ifa_list)) != NULL) { |
1214 | dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0); | 1232 | dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0); |
1215 | dn_dev_free_ifa(ifa); | 1233 | dn_dev_free_ifa(ifa); |
1216 | } | 1234 | } |
@@ -1270,7 +1288,7 @@ static inline int is_dn_dev(struct net_device *dev) | |||
1270 | } | 1288 | } |
1271 | 1289 | ||
1272 | static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) | 1290 | static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) |
1273 | __acquires(rcu) | 1291 | __acquires(RCU) |
1274 | { | 1292 | { |
1275 | int i; | 1293 | int i; |
1276 | struct net_device *dev; | 1294 | struct net_device *dev; |
@@ -1313,7 +1331,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1313 | } | 1331 | } |
1314 | 1332 | ||
1315 | static void dn_dev_seq_stop(struct seq_file *seq, void *v) | 1333 | static void dn_dev_seq_stop(struct seq_file *seq, void *v) |
1316 | __releases(rcu) | 1334 | __releases(RCU) |
1317 | { | 1335 | { |
1318 | rcu_read_unlock(); | 1336 | rcu_read_unlock(); |
1319 | } | 1337 | } |
@@ -1340,7 +1358,7 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v) | |||
1340 | struct net_device *dev = v; | 1358 | struct net_device *dev = v; |
1341 | char peer_buf[DN_ASCBUF_LEN]; | 1359 | char peer_buf[DN_ASCBUF_LEN]; |
1342 | char router_buf[DN_ASCBUF_LEN]; | 1360 | char router_buf[DN_ASCBUF_LEN]; |
1343 | struct dn_dev *dn_db = dev->dn_ptr; | 1361 | struct dn_dev *dn_db = rcu_dereference(dev->dn_ptr); |
1344 | 1362 | ||
1345 | seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" | 1363 | seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" |
1346 | " %04hu %03d %02x %-10s %-7s %-7s\n", | 1364 | " %04hu %03d %02x %-10s %-7s %-7s\n", |
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 4ab96c15166d..0ef0a81bcd72 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c | |||
@@ -610,10 +610,12 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) | |||
610 | /* Scan device list */ | 610 | /* Scan device list */ |
611 | rcu_read_lock(); | 611 | rcu_read_lock(); |
612 | for_each_netdev_rcu(&init_net, dev) { | 612 | for_each_netdev_rcu(&init_net, dev) { |
613 | dn_db = dev->dn_ptr; | 613 | dn_db = rcu_dereference(dev->dn_ptr); |
614 | if (dn_db == NULL) | 614 | if (dn_db == NULL) |
615 | continue; | 615 | continue; |
616 | for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) { | 616 | for (ifa2 = rcu_dereference(dn_db->ifa_list); |
617 | ifa2 != NULL; | ||
618 | ifa2 = rcu_dereference(ifa2->ifa_next)) { | ||
617 | if (ifa2->ifa_local == ifa->ifa_local) { | 619 | if (ifa2->ifa_local == ifa->ifa_local) { |
618 | found_it = 1; | 620 | found_it = 1; |
619 | break; | 621 | break; |
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index a085dbcf5c7f..602dade7e9a3 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c | |||
@@ -391,7 +391,7 @@ int dn_neigh_router_hello(struct sk_buff *skb) | |||
391 | write_lock(&neigh->lock); | 391 | write_lock(&neigh->lock); |
392 | 392 | ||
393 | neigh->used = jiffies; | 393 | neigh->used = jiffies; |
394 | dn_db = (struct dn_dev *)neigh->dev->dn_ptr; | 394 | dn_db = rcu_dereference(neigh->dev->dn_ptr); |
395 | 395 | ||
396 | if (!(neigh->nud_state & NUD_PERMANENT)) { | 396 | if (!(neigh->nud_state & NUD_PERMANENT)) { |
397 | neigh->updated = jiffies; | 397 | neigh->updated = jiffies; |
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index df0f3e54ff8a..94a9eb1d313e 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c | |||
@@ -93,7 +93,7 @@ | |||
93 | 93 | ||
94 | struct dn_rt_hash_bucket | 94 | struct dn_rt_hash_bucket |
95 | { | 95 | { |
96 | struct dn_route *chain; | 96 | struct dn_route __rcu *chain; |
97 | spinlock_t lock; | 97 | spinlock_t lock; |
98 | }; | 98 | }; |
99 | 99 | ||
@@ -157,15 +157,17 @@ static inline void dnrt_drop(struct dn_route *rt) | |||
157 | static void dn_dst_check_expire(unsigned long dummy) | 157 | static void dn_dst_check_expire(unsigned long dummy) |
158 | { | 158 | { |
159 | int i; | 159 | int i; |
160 | struct dn_route *rt, **rtp; | 160 | struct dn_route *rt; |
161 | struct dn_route __rcu **rtp; | ||
161 | unsigned long now = jiffies; | 162 | unsigned long now = jiffies; |
162 | unsigned long expire = 120 * HZ; | 163 | unsigned long expire = 120 * HZ; |
163 | 164 | ||
164 | for(i = 0; i <= dn_rt_hash_mask; i++) { | 165 | for (i = 0; i <= dn_rt_hash_mask; i++) { |
165 | rtp = &dn_rt_hash_table[i].chain; | 166 | rtp = &dn_rt_hash_table[i].chain; |
166 | 167 | ||
167 | spin_lock(&dn_rt_hash_table[i].lock); | 168 | spin_lock(&dn_rt_hash_table[i].lock); |
168 | while((rt=*rtp) != NULL) { | 169 | while ((rt = rcu_dereference_protected(*rtp, |
170 | lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) { | ||
169 | if (atomic_read(&rt->dst.__refcnt) || | 171 | if (atomic_read(&rt->dst.__refcnt) || |
170 | (now - rt->dst.lastuse) < expire) { | 172 | (now - rt->dst.lastuse) < expire) { |
171 | rtp = &rt->dst.dn_next; | 173 | rtp = &rt->dst.dn_next; |
@@ -186,17 +188,19 @@ static void dn_dst_check_expire(unsigned long dummy) | |||
186 | 188 | ||
187 | static int dn_dst_gc(struct dst_ops *ops) | 189 | static int dn_dst_gc(struct dst_ops *ops) |
188 | { | 190 | { |
189 | struct dn_route *rt, **rtp; | 191 | struct dn_route *rt; |
192 | struct dn_route __rcu **rtp; | ||
190 | int i; | 193 | int i; |
191 | unsigned long now = jiffies; | 194 | unsigned long now = jiffies; |
192 | unsigned long expire = 10 * HZ; | 195 | unsigned long expire = 10 * HZ; |
193 | 196 | ||
194 | for(i = 0; i <= dn_rt_hash_mask; i++) { | 197 | for (i = 0; i <= dn_rt_hash_mask; i++) { |
195 | 198 | ||
196 | spin_lock_bh(&dn_rt_hash_table[i].lock); | 199 | spin_lock_bh(&dn_rt_hash_table[i].lock); |
197 | rtp = &dn_rt_hash_table[i].chain; | 200 | rtp = &dn_rt_hash_table[i].chain; |
198 | 201 | ||
199 | while((rt=*rtp) != NULL) { | 202 | while ((rt = rcu_dereference_protected(*rtp, |
203 | lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) { | ||
200 | if (atomic_read(&rt->dst.__refcnt) || | 204 | if (atomic_read(&rt->dst.__refcnt) || |
201 | (now - rt->dst.lastuse) < expire) { | 205 | (now - rt->dst.lastuse) < expire) { |
202 | rtp = &rt->dst.dn_next; | 206 | rtp = &rt->dst.dn_next; |
@@ -227,7 +231,7 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
227 | { | 231 | { |
228 | u32 min_mtu = 230; | 232 | u32 min_mtu = 230; |
229 | struct dn_dev *dn = dst->neighbour ? | 233 | struct dn_dev *dn = dst->neighbour ? |
230 | (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL; | 234 | rcu_dereference_raw(dst->neighbour->dev->dn_ptr) : NULL; |
231 | 235 | ||
232 | if (dn && dn->use_long == 0) | 236 | if (dn && dn->use_long == 0) |
233 | min_mtu -= 6; | 237 | min_mtu -= 6; |
@@ -277,13 +281,15 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) | |||
277 | 281 | ||
278 | static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) | 282 | static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) |
279 | { | 283 | { |
280 | struct dn_route *rth, **rthp; | 284 | struct dn_route *rth; |
285 | struct dn_route __rcu **rthp; | ||
281 | unsigned long now = jiffies; | 286 | unsigned long now = jiffies; |
282 | 287 | ||
283 | rthp = &dn_rt_hash_table[hash].chain; | 288 | rthp = &dn_rt_hash_table[hash].chain; |
284 | 289 | ||
285 | spin_lock_bh(&dn_rt_hash_table[hash].lock); | 290 | spin_lock_bh(&dn_rt_hash_table[hash].lock); |
286 | while((rth = *rthp) != NULL) { | 291 | while ((rth = rcu_dereference_protected(*rthp, |
292 | lockdep_is_held(&dn_rt_hash_table[hash].lock))) != NULL) { | ||
287 | if (compare_keys(&rth->fl, &rt->fl)) { | 293 | if (compare_keys(&rth->fl, &rt->fl)) { |
288 | /* Put it first */ | 294 | /* Put it first */ |
289 | *rthp = rth->dst.dn_next; | 295 | *rthp = rth->dst.dn_next; |
@@ -315,15 +321,15 @@ static void dn_run_flush(unsigned long dummy) | |||
315 | int i; | 321 | int i; |
316 | struct dn_route *rt, *next; | 322 | struct dn_route *rt, *next; |
317 | 323 | ||
318 | for(i = 0; i < dn_rt_hash_mask; i++) { | 324 | for (i = 0; i < dn_rt_hash_mask; i++) { |
319 | spin_lock_bh(&dn_rt_hash_table[i].lock); | 325 | spin_lock_bh(&dn_rt_hash_table[i].lock); |
320 | 326 | ||
321 | if ((rt = xchg(&dn_rt_hash_table[i].chain, NULL)) == NULL) | 327 | if ((rt = xchg((struct dn_route **)&dn_rt_hash_table[i].chain, NULL)) == NULL) |
322 | goto nothing_to_declare; | 328 | goto nothing_to_declare; |
323 | 329 | ||
324 | for(; rt; rt=next) { | 330 | for(; rt; rt = next) { |
325 | next = rt->dst.dn_next; | 331 | next = rcu_dereference_raw(rt->dst.dn_next); |
326 | rt->dst.dn_next = NULL; | 332 | RCU_INIT_POINTER(rt->dst.dn_next, NULL); |
327 | dst_free((struct dst_entry *)rt); | 333 | dst_free((struct dst_entry *)rt); |
328 | } | 334 | } |
329 | 335 | ||
@@ -458,15 +464,16 @@ static int dn_return_long(struct sk_buff *skb) | |||
458 | */ | 464 | */ |
459 | static int dn_route_rx_packet(struct sk_buff *skb) | 465 | static int dn_route_rx_packet(struct sk_buff *skb) |
460 | { | 466 | { |
461 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 467 | struct dn_skb_cb *cb; |
462 | int err; | 468 | int err; |
463 | 469 | ||
464 | if ((err = dn_route_input(skb)) == 0) | 470 | if ((err = dn_route_input(skb)) == 0) |
465 | return dst_input(skb); | 471 | return dst_input(skb); |
466 | 472 | ||
473 | cb = DN_SKB_CB(skb); | ||
467 | if (decnet_debug_level & 4) { | 474 | if (decnet_debug_level & 4) { |
468 | char *devname = skb->dev ? skb->dev->name : "???"; | 475 | char *devname = skb->dev ? skb->dev->name : "???"; |
469 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 476 | |
470 | printk(KERN_DEBUG | 477 | printk(KERN_DEBUG |
471 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", | 478 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", |
472 | (int)cb->rt_flags, devname, skb->len, | 479 | (int)cb->rt_flags, devname, skb->len, |
@@ -573,7 +580,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type | |||
573 | struct dn_skb_cb *cb; | 580 | struct dn_skb_cb *cb; |
574 | unsigned char flags = 0; | 581 | unsigned char flags = 0; |
575 | __u16 len = le16_to_cpu(*(__le16 *)skb->data); | 582 | __u16 len = le16_to_cpu(*(__le16 *)skb->data); |
576 | struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; | 583 | struct dn_dev *dn = rcu_dereference(dev->dn_ptr); |
577 | unsigned char padlen = 0; | 584 | unsigned char padlen = 0; |
578 | 585 | ||
579 | if (!net_eq(dev_net(dev), &init_net)) | 586 | if (!net_eq(dev_net(dev), &init_net)) |
@@ -728,7 +735,7 @@ static int dn_forward(struct sk_buff *skb) | |||
728 | { | 735 | { |
729 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 736 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
730 | struct dst_entry *dst = skb_dst(skb); | 737 | struct dst_entry *dst = skb_dst(skb); |
731 | struct dn_dev *dn_db = dst->dev->dn_ptr; | 738 | struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr); |
732 | struct dn_route *rt; | 739 | struct dn_route *rt; |
733 | struct neighbour *neigh = dst->neighbour; | 740 | struct neighbour *neigh = dst->neighbour; |
734 | int header_len; | 741 | int header_len; |
@@ -835,13 +842,16 @@ static inline int dn_match_addr(__le16 addr1, __le16 addr2) | |||
835 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) | 842 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) |
836 | { | 843 | { |
837 | __le16 saddr = 0; | 844 | __le16 saddr = 0; |
838 | struct dn_dev *dn_db = dev->dn_ptr; | 845 | struct dn_dev *dn_db; |
839 | struct dn_ifaddr *ifa; | 846 | struct dn_ifaddr *ifa; |
840 | int best_match = 0; | 847 | int best_match = 0; |
841 | int ret; | 848 | int ret; |
842 | 849 | ||
843 | read_lock(&dev_base_lock); | 850 | rcu_read_lock(); |
844 | for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { | 851 | dn_db = rcu_dereference(dev->dn_ptr); |
852 | for (ifa = rcu_dereference(dn_db->ifa_list); | ||
853 | ifa != NULL; | ||
854 | ifa = rcu_dereference(ifa->ifa_next)) { | ||
845 | if (ifa->ifa_scope > scope) | 855 | if (ifa->ifa_scope > scope) |
846 | continue; | 856 | continue; |
847 | if (!daddr) { | 857 | if (!daddr) { |
@@ -854,7 +864,7 @@ static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int | |||
854 | if (best_match == 0) | 864 | if (best_match == 0) |
855 | saddr = ifa->ifa_local; | 865 | saddr = ifa->ifa_local; |
856 | } | 866 | } |
857 | read_unlock(&dev_base_lock); | 867 | rcu_read_unlock(); |
858 | 868 | ||
859 | return saddr; | 869 | return saddr; |
860 | } | 870 | } |
@@ -1020,7 +1030,7 @@ source_ok: | |||
1020 | err = -ENODEV; | 1030 | err = -ENODEV; |
1021 | if (dev_out == NULL) | 1031 | if (dev_out == NULL) |
1022 | goto out; | 1032 | goto out; |
1023 | dn_db = dev_out->dn_ptr; | 1033 | dn_db = rcu_dereference_raw(dev_out->dn_ptr); |
1024 | /* Possible improvement - check all devices for local addr */ | 1034 | /* Possible improvement - check all devices for local addr */ |
1025 | if (dn_dev_islocal(dev_out, fl.fld_dst)) { | 1035 | if (dn_dev_islocal(dev_out, fl.fld_dst)) { |
1026 | dev_put(dev_out); | 1036 | dev_put(dev_out); |
@@ -1233,7 +1243,7 @@ static int dn_route_input_slow(struct sk_buff *skb) | |||
1233 | 1243 | ||
1234 | dev_hold(in_dev); | 1244 | dev_hold(in_dev); |
1235 | 1245 | ||
1236 | if ((dn_db = in_dev->dn_ptr) == NULL) | 1246 | if ((dn_db = rcu_dereference(in_dev->dn_ptr)) == NULL) |
1237 | goto out; | 1247 | goto out; |
1238 | 1248 | ||
1239 | /* Zero source addresses are not allowed */ | 1249 | /* Zero source addresses are not allowed */ |
@@ -1677,15 +1687,15 @@ static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_rou | |||
1677 | { | 1687 | { |
1678 | struct dn_rt_cache_iter_state *s = seq->private; | 1688 | struct dn_rt_cache_iter_state *s = seq->private; |
1679 | 1689 | ||
1680 | rt = rt->dst.dn_next; | 1690 | rt = rcu_dereference_bh(rt->dst.dn_next); |
1681 | while(!rt) { | 1691 | while (!rt) { |
1682 | rcu_read_unlock_bh(); | 1692 | rcu_read_unlock_bh(); |
1683 | if (--s->bucket < 0) | 1693 | if (--s->bucket < 0) |
1684 | break; | 1694 | break; |
1685 | rcu_read_lock_bh(); | 1695 | rcu_read_lock_bh(); |
1686 | rt = dn_rt_hash_table[s->bucket].chain; | 1696 | rt = rcu_dereference_bh(dn_rt_hash_table[s->bucket].chain); |
1687 | } | 1697 | } |
1688 | return rcu_dereference_bh(rt); | 1698 | return rt; |
1689 | } | 1699 | } |
1690 | 1700 | ||
1691 | static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) | 1701 | static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) |