Commit fc766e4c4965915ab52a1d1fa3c7a7b3e7bc07f0
Committed by
David S. Miller
1 parent
e4a7b93bd5
Exists in
master
and in
7 other branches
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>
Showing 8 changed files with 127 additions and 88 deletions Side-by-side Diff
include/linux/netdevice.h
... | ... | @@ -951,7 +951,7 @@ |
951 | 951 | #endif |
952 | 952 | void *atalk_ptr; /* AppleTalk link */ |
953 | 953 | struct in_device __rcu *ip_ptr; /* IPv4 specific data */ |
954 | - void *dn_ptr; /* DECnet specific data */ | |
954 | + struct dn_dev __rcu *dn_ptr; /* DECnet specific data */ | |
955 | 955 | struct inet6_dev __rcu *ip6_ptr; /* IPv6 specific data */ |
956 | 956 | void *ec_ptr; /* Econet specific data */ |
957 | 957 | void *ax25_ptr; /* AX.25 specific data */ |
include/net/dn_dev.h
... | ... | @@ -5,13 +5,14 @@ |
5 | 5 | struct dn_dev; |
6 | 6 | |
7 | 7 | struct dn_ifaddr { |
8 | - struct dn_ifaddr *ifa_next; | |
8 | + struct dn_ifaddr __rcu *ifa_next; | |
9 | 9 | struct dn_dev *ifa_dev; |
10 | 10 | __le16 ifa_local; |
11 | 11 | __le16 ifa_address; |
12 | 12 | __u8 ifa_flags; |
13 | 13 | __u8 ifa_scope; |
14 | 14 | char ifa_label[IFNAMSIZ]; |
15 | + struct rcu_head rcu; | |
15 | 16 | }; |
16 | 17 | |
17 | 18 | #define DN_DEV_S_RU 0 /* Run - working normally */ |
... | ... | @@ -83,7 +84,7 @@ |
83 | 84 | |
84 | 85 | |
85 | 86 | struct dn_dev { |
86 | - struct dn_ifaddr *ifa_list; | |
87 | + struct dn_ifaddr __rcu *ifa_list; | |
87 | 88 | struct net_device *dev; |
88 | 89 | struct dn_dev_parms parms; |
89 | 90 | char use_long; |
90 | 91 | |
91 | 92 | |
92 | 93 | |
93 | 94 | |
... | ... | @@ -171,19 +172,27 @@ |
171 | 172 | |
172 | 173 | static inline int dn_dev_islocal(struct net_device *dev, __le16 addr) |
173 | 174 | { |
174 | - struct dn_dev *dn_db = dev->dn_ptr; | |
175 | + struct dn_dev *dn_db; | |
175 | 176 | struct dn_ifaddr *ifa; |
177 | + int res = 0; | |
176 | 178 | |
179 | + rcu_read_lock(); | |
180 | + dn_db = rcu_dereference(dev->dn_ptr); | |
177 | 181 | if (dn_db == NULL) { |
178 | 182 | printk(KERN_DEBUG "dn_dev_islocal: Called for non DECnet device\n"); |
179 | - return 0; | |
183 | + goto out; | |
180 | 184 | } |
181 | 185 | |
182 | - for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) | |
183 | - if ((addr ^ ifa->ifa_local) == 0) | |
184 | - return 1; | |
185 | - | |
186 | - return 0; | |
186 | + for (ifa = rcu_dereference(dn_db->ifa_list); | |
187 | + ifa != NULL; | |
188 | + ifa = rcu_dereference(ifa->ifa_next)) | |
189 | + if ((addr ^ ifa->ifa_local) == 0) { | |
190 | + res = 1; | |
191 | + break; | |
192 | + } | |
193 | +out: | |
194 | + rcu_read_unlock(); | |
195 | + return res; | |
187 | 196 | } |
188 | 197 | |
189 | 198 | #endif /* _NET_DN_DEV_H */ |
include/net/dst.h
... | ... | @@ -94,10 +94,10 @@ |
94 | 94 | int __use; |
95 | 95 | unsigned long lastuse; |
96 | 96 | union { |
97 | - struct dst_entry *next; | |
98 | - struct rtable __rcu *rt_next; | |
99 | - struct rt6_info *rt6_next; | |
100 | - struct dn_route *dn_next; | |
97 | + struct dst_entry *next; | |
98 | + struct rtable __rcu *rt_next; | |
99 | + struct rt6_info *rt6_next; | |
100 | + struct dn_route __rcu *dn_next; | |
101 | 101 | }; |
102 | 102 | }; |
103 | 103 |
net/decnet/af_decnet.c
... | ... | @@ -1848,7 +1848,7 @@ |
1848 | 1848 | { |
1849 | 1849 | unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER; |
1850 | 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 | 1852 | mtu -= LL_RESERVED_SPACE(dev); |
1853 | 1853 | if (dn_db->use_long) |
1854 | 1854 | mtu -= 21; |
net/decnet/dn_dev.c
... | ... | @@ -267,7 +267,7 @@ |
267 | 267 | if (table->extra1 == NULL) |
268 | 268 | return -EINVAL; |
269 | 269 | |
270 | - dn_db = dev->dn_ptr; | |
270 | + dn_db = rcu_dereference_raw(dev->dn_ptr); | |
271 | 271 | old = dn_db->parms.forwarding; |
272 | 272 | |
273 | 273 | err = proc_dointvec(table, write, buffer, lenp, ppos); |
274 | 274 | |
275 | 275 | |
276 | 276 | |
... | ... | @@ -332,14 +332,19 @@ |
332 | 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 | 348 | unsigned char mac_addr[6]; |
344 | 349 | struct net_device *dev = dn_db->dev; |
345 | 350 | |
... | ... | @@ -373,7 +378,9 @@ |
373 | 378 | ASSERT_RTNL(); |
374 | 379 | |
375 | 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 | 384 | if (ifa1->ifa_local == ifa->ifa_local) |
378 | 385 | return -EEXIST; |
379 | 386 | } |
... | ... | @@ -386,7 +393,7 @@ |
386 | 393 | } |
387 | 394 | |
388 | 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 | 398 | dn_ifaddr_notify(RTM_NEWADDR, ifa); |
392 | 399 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); |
... | ... | @@ -396,7 +403,7 @@ |
396 | 403 | |
397 | 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 | 407 | int rv; |
401 | 408 | |
402 | 409 | if (dn_db == NULL) { |
... | ... | @@ -425,7 +432,8 @@ |
425 | 432 | struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr; |
426 | 433 | struct dn_dev *dn_db; |
427 | 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 | 437 | int ret = 0; |
430 | 438 | |
431 | 439 | if (copy_from_user(ifr, arg, DN_IFREQ_SIZE)) |
... | ... | @@ -454,8 +462,10 @@ |
454 | 462 | goto done; |
455 | 463 | } |
456 | 464 | |
457 | - if ((dn_db = dev->dn_ptr) != NULL) { | |
458 | - for (ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) | |
465 | + if ((dn_db = rtnl_dereference(dev->dn_ptr)) != NULL) { | |
466 | + for (ifap = &dn_db->ifa_list; | |
467 | + (ifa = rtnl_dereference(*ifap)) != NULL; | |
468 | + ifap = &ifa->ifa_next) | |
459 | 469 | if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0) |
460 | 470 | break; |
461 | 471 | } |
... | ... | @@ -558,7 +568,7 @@ |
558 | 568 | |
559 | 569 | dev = __dev_get_by_index(&init_net, ifindex); |
560 | 570 | if (dev) |
561 | - dn_dev = dev->dn_ptr; | |
571 | + dn_dev = rtnl_dereference(dev->dn_ptr); | |
562 | 572 | |
563 | 573 | return dn_dev; |
564 | 574 | } |
... | ... | @@ -576,7 +586,8 @@ |
576 | 586 | struct nlattr *tb[IFA_MAX+1]; |
577 | 587 | struct dn_dev *dn_db; |
578 | 588 | struct ifaddrmsg *ifm; |
579 | - struct dn_ifaddr *ifa, **ifap; | |
589 | + struct dn_ifaddr *ifa; | |
590 | + struct dn_ifaddr __rcu **ifap; | |
580 | 591 | int err = -EINVAL; |
581 | 592 | |
582 | 593 | if (!net_eq(net, &init_net)) |
... | ... | @@ -592,7 +603,9 @@ |
592 | 603 | goto errout; |
593 | 604 | |
594 | 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 | 609 | if (tb[IFA_LOCAL] && |
597 | 610 | nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2)) |
598 | 611 | continue; |
... | ... | @@ -632,7 +645,7 @@ |
632 | 645 | if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL) |
633 | 646 | return -ENODEV; |
634 | 647 | |
635 | - if ((dn_db = dev->dn_ptr) == NULL) { | |
648 | + if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) { | |
636 | 649 | dn_db = dn_dev_create(dev, &err); |
637 | 650 | if (!dn_db) |
638 | 651 | return err; |
639 | 652 | |
... | ... | @@ -748,11 +761,11 @@ |
748 | 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 | 765 | goto cont; |
753 | 766 | |
754 | - for (ifa = dn_db->ifa_list, dn_idx = 0; ifa; | |
755 | - ifa = ifa->ifa_next, dn_idx++) { | |
767 | + for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa; | |
768 | + ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) { | |
756 | 769 | if (dn_idx < skip_naddr) |
757 | 770 | continue; |
758 | 771 | |
759 | 772 | |
760 | 773 | |
761 | 774 | |
762 | 775 | |
... | ... | @@ -773,21 +786,22 @@ |
773 | 786 | |
774 | 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 | 790 | struct dn_ifaddr *ifa; |
778 | 791 | int rv = -ENODEV; |
779 | 792 | |
793 | + rcu_read_lock(); | |
794 | + dn_db = rcu_dereference(dev->dn_ptr); | |
780 | 795 | if (dn_db == NULL) |
781 | 796 | goto out; |
782 | 797 | |
783 | - rtnl_lock(); | |
784 | - ifa = dn_db->ifa_list; | |
798 | + ifa = rcu_dereference(dn_db->ifa_list); | |
785 | 799 | if (ifa != NULL) { |
786 | 800 | *addr = ifa->ifa_local; |
787 | 801 | rv = 0; |
788 | 802 | } |
789 | - rtnl_unlock(); | |
790 | 803 | out: |
804 | + rcu_read_unlock(); | |
791 | 805 | return rv; |
792 | 806 | } |
793 | 807 | |
... | ... | @@ -823,7 +837,7 @@ |
823 | 837 | struct endnode_hello_message *msg; |
824 | 838 | struct sk_buff *skb = NULL; |
825 | 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 | 842 | if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL) |
829 | 843 | return; |
... | ... | @@ -889,7 +903,7 @@ |
889 | 903 | static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) |
890 | 904 | { |
891 | 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 | 907 | struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; |
894 | 908 | struct sk_buff *skb; |
895 | 909 | size_t size; |
... | ... | @@ -960,7 +974,7 @@ |
960 | 974 | |
961 | 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 | 979 | if (dn_db->parms.forwarding == 0) |
966 | 980 | dn_send_endnode_hello(dev, ifa); |
... | ... | @@ -998,7 +1012,7 @@ |
998 | 1012 | |
999 | 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 | 1017 | if (dn_db->parms.forwarding == 0) |
1004 | 1018 | dev_mc_add(dev, dn_rt_all_end_mcast); |
... | ... | @@ -1012,7 +1026,7 @@ |
1012 | 1026 | |
1013 | 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 | 1031 | if (dn_db->parms.forwarding == 0) |
1018 | 1032 | dev_mc_del(dev, dn_rt_all_end_mcast); |
1019 | 1033 | |
1020 | 1034 | |
... | ... | @@ -1025,12 +1039,16 @@ |
1025 | 1039 | static void dn_dev_timer_func(unsigned long arg) |
1026 | 1040 | { |
1027 | 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 | 1043 | struct dn_ifaddr *ifa; |
1030 | 1044 | |
1045 | + rcu_read_lock(); | |
1046 | + dn_db = rcu_dereference(dev->dn_ptr); | |
1031 | 1047 | if (dn_db->t3 <= dn_db->parms.t2) { |
1032 | 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 | 1052 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) |
1035 | 1053 | dn_db->parms.timer3(dev, ifa); |
1036 | 1054 | } |
1037 | 1055 | |
... | ... | @@ -1039,13 +1057,13 @@ |
1039 | 1057 | } else { |
1040 | 1058 | dn_db->t3 -= dn_db->parms.t2; |
1041 | 1059 | } |
1042 | - | |
1060 | + rcu_read_unlock(); | |
1043 | 1061 | dn_dev_set_timer(dev); |
1044 | 1062 | } |
1045 | 1063 | |
1046 | 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 | 1068 | if (dn_db->parms.t2 > dn_db->parms.t3) |
1051 | 1069 | dn_db->parms.t2 = dn_db->parms.t3; |
... | ... | @@ -1077,8 +1095,8 @@ |
1077 | 1095 | return NULL; |
1078 | 1096 | |
1079 | 1097 | memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms)); |
1080 | - smp_wmb(); | |
1081 | - dev->dn_ptr = dn_db; | |
1098 | + | |
1099 | + rcu_assign_pointer(dev->dn_ptr, dn_db); | |
1082 | 1100 | dn_db->dev = dev; |
1083 | 1101 | init_timer(&dn_db->timer); |
1084 | 1102 | |
... | ... | @@ -1086,7 +1104,7 @@ |
1086 | 1104 | |
1087 | 1105 | dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); |
1088 | 1106 | if (!dn_db->neigh_parms) { |
1089 | - dev->dn_ptr = NULL; | |
1107 | + rcu_assign_pointer(dev->dn_ptr, NULL); | |
1090 | 1108 | kfree(dn_db); |
1091 | 1109 | return NULL; |
1092 | 1110 | } |
... | ... | @@ -1125,7 +1143,7 @@ |
1125 | 1143 | struct dn_ifaddr *ifa; |
1126 | 1144 | __le16 addr = decnet_address; |
1127 | 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 | 1148 | if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) |
1131 | 1149 | return; |
... | ... | @@ -1176,7 +1194,7 @@ |
1176 | 1194 | |
1177 | 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 | 1199 | if (dn_db == NULL) |
1182 | 1200 | return; |
1183 | 1201 | |
... | ... | @@ -1204,13 +1222,13 @@ |
1204 | 1222 | |
1205 | 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 | 1226 | struct dn_ifaddr *ifa; |
1209 | 1227 | |
1210 | 1228 | if (dn_db == NULL) |
1211 | 1229 | return; |
1212 | 1230 | |
1213 | - while((ifa = dn_db->ifa_list) != NULL) { | |
1231 | + while ((ifa = rtnl_dereference(dn_db->ifa_list)) != NULL) { | |
1214 | 1232 | dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0); |
1215 | 1233 | dn_dev_free_ifa(ifa); |
1216 | 1234 | } |
... | ... | @@ -1270,7 +1288,7 @@ |
1270 | 1288 | } |
1271 | 1289 | |
1272 | 1290 | static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) |
1273 | - __acquires(rcu) | |
1291 | + __acquires(RCU) | |
1274 | 1292 | { |
1275 | 1293 | int i; |
1276 | 1294 | struct net_device *dev; |
... | ... | @@ -1313,7 +1331,7 @@ |
1313 | 1331 | } |
1314 | 1332 | |
1315 | 1333 | static void dn_dev_seq_stop(struct seq_file *seq, void *v) |
1316 | - __releases(rcu) | |
1334 | + __releases(RCU) | |
1317 | 1335 | { |
1318 | 1336 | rcu_read_unlock(); |
1319 | 1337 | } |
... | ... | @@ -1340,7 +1358,7 @@ |
1340 | 1358 | struct net_device *dev = v; |
1341 | 1359 | char peer_buf[DN_ASCBUF_LEN]; |
1342 | 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 | 1363 | seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" |
1346 | 1364 | " %04hu %03d %02x %-10s %-7s %-7s\n", |
net/decnet/dn_fib.c
... | ... | @@ -610,10 +610,12 @@ |
610 | 610 | /* Scan device list */ |
611 | 611 | rcu_read_lock(); |
612 | 612 | for_each_netdev_rcu(&init_net, dev) { |
613 | - dn_db = dev->dn_ptr; | |
613 | + dn_db = rcu_dereference(dev->dn_ptr); | |
614 | 614 | if (dn_db == NULL) |
615 | 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 | 619 | if (ifa2->ifa_local == ifa->ifa_local) { |
618 | 620 | found_it = 1; |
619 | 621 | break; |
net/decnet/dn_neigh.c
net/decnet/dn_route.c
... | ... | @@ -93,7 +93,7 @@ |
93 | 93 | |
94 | 94 | struct dn_rt_hash_bucket |
95 | 95 | { |
96 | - struct dn_route *chain; | |
96 | + struct dn_route __rcu *chain; | |
97 | 97 | spinlock_t lock; |
98 | 98 | }; |
99 | 99 | |
100 | 100 | |
101 | 101 | |
... | ... | @@ -157,15 +157,17 @@ |
157 | 157 | static void dn_dst_check_expire(unsigned long dummy) |
158 | 158 | { |
159 | 159 | int i; |
160 | - struct dn_route *rt, **rtp; | |
160 | + struct dn_route *rt; | |
161 | + struct dn_route __rcu **rtp; | |
161 | 162 | unsigned long now = jiffies; |
162 | 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 | 166 | rtp = &dn_rt_hash_table[i].chain; |
166 | 167 | |
167 | 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 | 171 | if (atomic_read(&rt->dst.__refcnt) || |
170 | 172 | (now - rt->dst.lastuse) < expire) { |
171 | 173 | rtp = &rt->dst.dn_next; |
172 | 174 | |
173 | 175 | |
... | ... | @@ -186,17 +188,19 @@ |
186 | 188 | |
187 | 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 | 193 | int i; |
191 | 194 | unsigned long now = jiffies; |
192 | 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 | 199 | spin_lock_bh(&dn_rt_hash_table[i].lock); |
197 | 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 | 204 | if (atomic_read(&rt->dst.__refcnt) || |
201 | 205 | (now - rt->dst.lastuse) < expire) { |
202 | 206 | rtp = &rt->dst.dn_next; |
... | ... | @@ -227,7 +231,7 @@ |
227 | 231 | { |
228 | 232 | u32 min_mtu = 230; |
229 | 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 | 236 | if (dn && dn->use_long == 0) |
233 | 237 | min_mtu -= 6; |
234 | 238 | |
... | ... | @@ -277,13 +281,15 @@ |
277 | 281 | |
278 | 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 | 286 | unsigned long now = jiffies; |
282 | 287 | |
283 | 288 | rthp = &dn_rt_hash_table[hash].chain; |
284 | 289 | |
285 | 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 | 293 | if (compare_keys(&rth->fl, &rt->fl)) { |
288 | 294 | /* Put it first */ |
289 | 295 | *rthp = rth->dst.dn_next; |
290 | 296 | |
291 | 297 | |
... | ... | @@ -315,15 +321,15 @@ |
315 | 321 | int i; |
316 | 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 | 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 | 328 | goto nothing_to_declare; |
323 | 329 | |
324 | - for(; rt; rt=next) { | |
325 | - next = rt->dst.dn_next; | |
326 | - rt->dst.dn_next = NULL; | |
330 | + for(; rt; rt = next) { | |
331 | + next = rcu_dereference_raw(rt->dst.dn_next); | |
332 | + RCU_INIT_POINTER(rt->dst.dn_next, NULL); | |
327 | 333 | dst_free((struct dst_entry *)rt); |
328 | 334 | } |
329 | 335 | |
330 | 336 | |
331 | 337 | |
... | ... | @@ -458,15 +464,16 @@ |
458 | 464 | */ |
459 | 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 | 468 | int err; |
463 | 469 | |
464 | 470 | if ((err = dn_route_input(skb)) == 0) |
465 | 471 | return dst_input(skb); |
466 | 472 | |
473 | + cb = DN_SKB_CB(skb); | |
467 | 474 | if (decnet_debug_level & 4) { |
468 | 475 | char *devname = skb->dev ? skb->dev->name : "???"; |
469 | - struct dn_skb_cb *cb = DN_SKB_CB(skb); | |
476 | + | |
470 | 477 | printk(KERN_DEBUG |
471 | 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 | 479 | (int)cb->rt_flags, devname, skb->len, |
... | ... | @@ -573,7 +580,7 @@ |
573 | 580 | struct dn_skb_cb *cb; |
574 | 581 | unsigned char flags = 0; |
575 | 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 | 584 | unsigned char padlen = 0; |
578 | 585 | |
579 | 586 | if (!net_eq(dev_net(dev), &init_net)) |
... | ... | @@ -728,7 +735,7 @@ |
728 | 735 | { |
729 | 736 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
730 | 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 | 739 | struct dn_route *rt; |
733 | 740 | struct neighbour *neigh = dst->neighbour; |
734 | 741 | int header_len; |
735 | 742 | |
... | ... | @@ -835,13 +842,16 @@ |
835 | 842 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) |
836 | 843 | { |
837 | 844 | __le16 saddr = 0; |
838 | - struct dn_dev *dn_db = dev->dn_ptr; | |
845 | + struct dn_dev *dn_db; | |
839 | 846 | struct dn_ifaddr *ifa; |
840 | 847 | int best_match = 0; |
841 | 848 | int ret; |
842 | 849 | |
843 | - read_lock(&dev_base_lock); | |
844 | - for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { | |
850 | + rcu_read_lock(); | |
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 | 855 | if (ifa->ifa_scope > scope) |
846 | 856 | continue; |
847 | 857 | if (!daddr) { |
... | ... | @@ -854,7 +864,7 @@ |
854 | 864 | if (best_match == 0) |
855 | 865 | saddr = ifa->ifa_local; |
856 | 866 | } |
857 | - read_unlock(&dev_base_lock); | |
867 | + rcu_read_unlock(); | |
858 | 868 | |
859 | 869 | return saddr; |
860 | 870 | } |
... | ... | @@ -1020,7 +1030,7 @@ |
1020 | 1030 | err = -ENODEV; |
1021 | 1031 | if (dev_out == NULL) |
1022 | 1032 | goto out; |
1023 | - dn_db = dev_out->dn_ptr; | |
1033 | + dn_db = rcu_dereference_raw(dev_out->dn_ptr); | |
1024 | 1034 | /* Possible improvement - check all devices for local addr */ |
1025 | 1035 | if (dn_dev_islocal(dev_out, fl.fld_dst)) { |
1026 | 1036 | dev_put(dev_out); |
... | ... | @@ -1233,7 +1243,7 @@ |
1233 | 1243 | |
1234 | 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 | 1247 | goto out; |
1238 | 1248 | |
1239 | 1249 | /* Zero source addresses are not allowed */ |
1240 | 1250 | |
1241 | 1251 | |
... | ... | @@ -1677,15 +1687,15 @@ |
1677 | 1687 | { |
1678 | 1688 | struct dn_rt_cache_iter_state *s = seq->private; |
1679 | 1689 | |
1680 | - rt = rt->dst.dn_next; | |
1681 | - while(!rt) { | |
1690 | + rt = rcu_dereference_bh(rt->dst.dn_next); | |
1691 | + while (!rt) { | |
1682 | 1692 | rcu_read_unlock_bh(); |
1683 | 1693 | if (--s->bucket < 0) |
1684 | 1694 | break; |
1685 | 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 | 1701 | static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) |