diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-11-15 01:38:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-11-15 14:13:16 -0500 |
commit | e80516880019aa1f7c5c410276edfea9575ec89f (patch) | |
tree | b17f51f56ef97e5a366f2f5bc3020935d8eb5def /net/bridge | |
parent | 8a22c99a80b0926585cfcbcc423ee2c49c1fd820 (diff) |
bridge: add RCU annotation to bridge multicast table
Add modern __rcu annotatations to bridge multicast table.
Use newer hlist macros to avoid direct access to hlist internals.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_forward.c | 4 | ||||
-rw-r--r-- | net/bridge/br_multicast.c | 78 | ||||
-rw-r--r-- | net/bridge/br_private.h | 6 |
3 files changed, 56 insertions, 32 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index cbfe87f0f34a..2bd11ec6d166 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -223,7 +223,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, | |||
223 | struct net_bridge_port_group *p; | 223 | struct net_bridge_port_group *p; |
224 | struct hlist_node *rp; | 224 | struct hlist_node *rp; |
225 | 225 | ||
226 | rp = rcu_dereference(br->router_list.first); | 226 | rp = rcu_dereference(hlist_first_rcu(&br->router_list)); |
227 | p = mdst ? rcu_dereference(mdst->ports) : NULL; | 227 | p = mdst ? rcu_dereference(mdst->ports) : NULL; |
228 | while (p || rp) { | 228 | while (p || rp) { |
229 | struct net_bridge_port *port, *lport, *rport; | 229 | struct net_bridge_port *port, *lport, *rport; |
@@ -242,7 +242,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, | |||
242 | if ((unsigned long)lport >= (unsigned long)port) | 242 | if ((unsigned long)lport >= (unsigned long)port) |
243 | p = rcu_dereference(p->next); | 243 | p = rcu_dereference(p->next); |
244 | if ((unsigned long)rport >= (unsigned long)port) | 244 | if ((unsigned long)rport >= (unsigned long)port) |
245 | rp = rcu_dereference(rp->next); | 245 | rp = rcu_dereference(hlist_next_rcu(rp)); |
246 | } | 246 | } |
247 | 247 | ||
248 | if (!prev) | 248 | if (!prev) |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index eb5b256ffc88..326e599f83fb 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -33,6 +33,9 @@ | |||
33 | 33 | ||
34 | #include "br_private.h" | 34 | #include "br_private.h" |
35 | 35 | ||
36 | #define mlock_dereference(X, br) \ | ||
37 | rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) | ||
38 | |||
36 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 39 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
37 | static inline int ipv6_is_local_multicast(const struct in6_addr *addr) | 40 | static inline int ipv6_is_local_multicast(const struct in6_addr *addr) |
38 | { | 41 | { |
@@ -135,7 +138,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get( | |||
135 | struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, | 138 | struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, |
136 | struct sk_buff *skb) | 139 | struct sk_buff *skb) |
137 | { | 140 | { |
138 | struct net_bridge_mdb_htable *mdb = br->mdb; | 141 | struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb); |
139 | struct br_ip ip; | 142 | struct br_ip ip; |
140 | 143 | ||
141 | if (br->multicast_disabled) | 144 | if (br->multicast_disabled) |
@@ -235,7 +238,8 @@ static void br_multicast_group_expired(unsigned long data) | |||
235 | if (mp->ports) | 238 | if (mp->ports) |
236 | goto out; | 239 | goto out; |
237 | 240 | ||
238 | mdb = br->mdb; | 241 | mdb = mlock_dereference(br->mdb, br); |
242 | |||
239 | hlist_del_rcu(&mp->hlist[mdb->ver]); | 243 | hlist_del_rcu(&mp->hlist[mdb->ver]); |
240 | mdb->size--; | 244 | mdb->size--; |
241 | 245 | ||
@@ -249,16 +253,20 @@ out: | |||
249 | static void br_multicast_del_pg(struct net_bridge *br, | 253 | static void br_multicast_del_pg(struct net_bridge *br, |
250 | struct net_bridge_port_group *pg) | 254 | struct net_bridge_port_group *pg) |
251 | { | 255 | { |
252 | struct net_bridge_mdb_htable *mdb = br->mdb; | 256 | struct net_bridge_mdb_htable *mdb; |
253 | struct net_bridge_mdb_entry *mp; | 257 | struct net_bridge_mdb_entry *mp; |
254 | struct net_bridge_port_group *p; | 258 | struct net_bridge_port_group *p; |
255 | struct net_bridge_port_group **pp; | 259 | struct net_bridge_port_group __rcu **pp; |
260 | |||
261 | mdb = mlock_dereference(br->mdb, br); | ||
256 | 262 | ||
257 | mp = br_mdb_ip_get(mdb, &pg->addr); | 263 | mp = br_mdb_ip_get(mdb, &pg->addr); |
258 | if (WARN_ON(!mp)) | 264 | if (WARN_ON(!mp)) |
259 | return; | 265 | return; |
260 | 266 | ||
261 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 267 | for (pp = &mp->ports; |
268 | (p = mlock_dereference(*pp, br)) != NULL; | ||
269 | pp = &p->next) { | ||
262 | if (p != pg) | 270 | if (p != pg) |
263 | continue; | 271 | continue; |
264 | 272 | ||
@@ -294,10 +302,10 @@ out: | |||
294 | spin_unlock(&br->multicast_lock); | 302 | spin_unlock(&br->multicast_lock); |
295 | } | 303 | } |
296 | 304 | ||
297 | static int br_mdb_rehash(struct net_bridge_mdb_htable **mdbp, int max, | 305 | static int br_mdb_rehash(struct net_bridge_mdb_htable __rcu **mdbp, int max, |
298 | int elasticity) | 306 | int elasticity) |
299 | { | 307 | { |
300 | struct net_bridge_mdb_htable *old = *mdbp; | 308 | struct net_bridge_mdb_htable *old = rcu_dereference_protected(*mdbp, 1); |
301 | struct net_bridge_mdb_htable *mdb; | 309 | struct net_bridge_mdb_htable *mdb; |
302 | int err; | 310 | int err; |
303 | 311 | ||
@@ -569,7 +577,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group( | |||
569 | struct net_bridge *br, struct net_bridge_port *port, | 577 | struct net_bridge *br, struct net_bridge_port *port, |
570 | struct br_ip *group, int hash) | 578 | struct br_ip *group, int hash) |
571 | { | 579 | { |
572 | struct net_bridge_mdb_htable *mdb = br->mdb; | 580 | struct net_bridge_mdb_htable *mdb; |
573 | struct net_bridge_mdb_entry *mp; | 581 | struct net_bridge_mdb_entry *mp; |
574 | struct hlist_node *p; | 582 | struct hlist_node *p; |
575 | unsigned count = 0; | 583 | unsigned count = 0; |
@@ -577,6 +585,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group( | |||
577 | int elasticity; | 585 | int elasticity; |
578 | int err; | 586 | int err; |
579 | 587 | ||
588 | mdb = rcu_dereference_protected(br->mdb, 1); | ||
580 | hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { | 589 | hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { |
581 | count++; | 590 | count++; |
582 | if (unlikely(br_ip_equal(group, &mp->addr))) | 591 | if (unlikely(br_ip_equal(group, &mp->addr))) |
@@ -642,10 +651,11 @@ static struct net_bridge_mdb_entry *br_multicast_new_group( | |||
642 | struct net_bridge *br, struct net_bridge_port *port, | 651 | struct net_bridge *br, struct net_bridge_port *port, |
643 | struct br_ip *group) | 652 | struct br_ip *group) |
644 | { | 653 | { |
645 | struct net_bridge_mdb_htable *mdb = br->mdb; | 654 | struct net_bridge_mdb_htable *mdb; |
646 | struct net_bridge_mdb_entry *mp; | 655 | struct net_bridge_mdb_entry *mp; |
647 | int hash; | 656 | int hash; |
648 | 657 | ||
658 | mdb = rcu_dereference_protected(br->mdb, 1); | ||
649 | if (!mdb) { | 659 | if (!mdb) { |
650 | if (br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0)) | 660 | if (br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0)) |
651 | return NULL; | 661 | return NULL; |
@@ -660,7 +670,7 @@ static struct net_bridge_mdb_entry *br_multicast_new_group( | |||
660 | 670 | ||
661 | case -EAGAIN: | 671 | case -EAGAIN: |
662 | rehash: | 672 | rehash: |
663 | mdb = br->mdb; | 673 | mdb = rcu_dereference_protected(br->mdb, 1); |
664 | hash = br_ip_hash(mdb, group); | 674 | hash = br_ip_hash(mdb, group); |
665 | break; | 675 | break; |
666 | 676 | ||
@@ -692,7 +702,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
692 | { | 702 | { |
693 | struct net_bridge_mdb_entry *mp; | 703 | struct net_bridge_mdb_entry *mp; |
694 | struct net_bridge_port_group *p; | 704 | struct net_bridge_port_group *p; |
695 | struct net_bridge_port_group **pp; | 705 | struct net_bridge_port_group __rcu **pp; |
696 | unsigned long now = jiffies; | 706 | unsigned long now = jiffies; |
697 | int err; | 707 | int err; |
698 | 708 | ||
@@ -712,7 +722,9 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
712 | goto out; | 722 | goto out; |
713 | } | 723 | } |
714 | 724 | ||
715 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 725 | for (pp = &mp->ports; |
726 | (p = mlock_dereference(*pp, br)) != NULL; | ||
727 | pp = &p->next) { | ||
716 | if (p->port == port) | 728 | if (p->port == port) |
717 | goto found; | 729 | goto found; |
718 | if ((unsigned long)p->port < (unsigned long)port) | 730 | if ((unsigned long)p->port < (unsigned long)port) |
@@ -1106,7 +1118,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1106 | struct net_bridge_mdb_entry *mp; | 1118 | struct net_bridge_mdb_entry *mp; |
1107 | struct igmpv3_query *ih3; | 1119 | struct igmpv3_query *ih3; |
1108 | struct net_bridge_port_group *p; | 1120 | struct net_bridge_port_group *p; |
1109 | struct net_bridge_port_group **pp; | 1121 | struct net_bridge_port_group __rcu **pp; |
1110 | unsigned long max_delay; | 1122 | unsigned long max_delay; |
1111 | unsigned long now = jiffies; | 1123 | unsigned long now = jiffies; |
1112 | __be32 group; | 1124 | __be32 group; |
@@ -1145,7 +1157,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1145 | if (!group) | 1157 | if (!group) |
1146 | goto out; | 1158 | goto out; |
1147 | 1159 | ||
1148 | mp = br_mdb_ip4_get(br->mdb, group); | 1160 | mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group); |
1149 | if (!mp) | 1161 | if (!mp) |
1150 | goto out; | 1162 | goto out; |
1151 | 1163 | ||
@@ -1157,7 +1169,9 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1157 | try_to_del_timer_sync(&mp->timer) >= 0)) | 1169 | try_to_del_timer_sync(&mp->timer) >= 0)) |
1158 | mod_timer(&mp->timer, now + max_delay); | 1170 | mod_timer(&mp->timer, now + max_delay); |
1159 | 1171 | ||
1160 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 1172 | for (pp = &mp->ports; |
1173 | (p = mlock_dereference(*pp, br)) != NULL; | ||
1174 | pp = &p->next) { | ||
1161 | if (timer_pending(&p->timer) ? | 1175 | if (timer_pending(&p->timer) ? |
1162 | time_after(p->timer.expires, now + max_delay) : | 1176 | time_after(p->timer.expires, now + max_delay) : |
1163 | try_to_del_timer_sync(&p->timer) >= 0) | 1177 | try_to_del_timer_sync(&p->timer) >= 0) |
@@ -1178,7 +1192,8 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1178 | struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); | 1192 | struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); |
1179 | struct net_bridge_mdb_entry *mp; | 1193 | struct net_bridge_mdb_entry *mp; |
1180 | struct mld2_query *mld2q; | 1194 | struct mld2_query *mld2q; |
1181 | struct net_bridge_port_group *p, **pp; | 1195 | struct net_bridge_port_group *p; |
1196 | struct net_bridge_port_group __rcu **pp; | ||
1182 | unsigned long max_delay; | 1197 | unsigned long max_delay; |
1183 | unsigned long now = jiffies; | 1198 | unsigned long now = jiffies; |
1184 | struct in6_addr *group = NULL; | 1199 | struct in6_addr *group = NULL; |
@@ -1214,7 +1229,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1214 | if (!group) | 1229 | if (!group) |
1215 | goto out; | 1230 | goto out; |
1216 | 1231 | ||
1217 | mp = br_mdb_ip6_get(br->mdb, group); | 1232 | mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group); |
1218 | if (!mp) | 1233 | if (!mp) |
1219 | goto out; | 1234 | goto out; |
1220 | 1235 | ||
@@ -1225,7 +1240,9 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1225 | try_to_del_timer_sync(&mp->timer) >= 0)) | 1240 | try_to_del_timer_sync(&mp->timer) >= 0)) |
1226 | mod_timer(&mp->timer, now + max_delay); | 1241 | mod_timer(&mp->timer, now + max_delay); |
1227 | 1242 | ||
1228 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 1243 | for (pp = &mp->ports; |
1244 | (p = mlock_dereference(*pp, br)) != NULL; | ||
1245 | pp = &p->next) { | ||
1229 | if (timer_pending(&p->timer) ? | 1246 | if (timer_pending(&p->timer) ? |
1230 | time_after(p->timer.expires, now + max_delay) : | 1247 | time_after(p->timer.expires, now + max_delay) : |
1231 | try_to_del_timer_sync(&p->timer) >= 0) | 1248 | try_to_del_timer_sync(&p->timer) >= 0) |
@@ -1254,7 +1271,7 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1254 | timer_pending(&br->multicast_querier_timer)) | 1271 | timer_pending(&br->multicast_querier_timer)) |
1255 | goto out; | 1272 | goto out; |
1256 | 1273 | ||
1257 | mdb = br->mdb; | 1274 | mdb = mlock_dereference(br->mdb, br); |
1258 | mp = br_mdb_ip_get(mdb, group); | 1275 | mp = br_mdb_ip_get(mdb, group); |
1259 | if (!mp) | 1276 | if (!mp) |
1260 | goto out; | 1277 | goto out; |
@@ -1277,7 +1294,9 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1277 | goto out; | 1294 | goto out; |
1278 | } | 1295 | } |
1279 | 1296 | ||
1280 | for (p = mp->ports; p; p = p->next) { | 1297 | for (p = mlock_dereference(mp->ports, br); |
1298 | p != NULL; | ||
1299 | p = mlock_dereference(p->next, br)) { | ||
1281 | if (p->port != port) | 1300 | if (p->port != port) |
1282 | continue; | 1301 | continue; |
1283 | 1302 | ||
@@ -1625,7 +1644,7 @@ void br_multicast_stop(struct net_bridge *br) | |||
1625 | del_timer_sync(&br->multicast_query_timer); | 1644 | del_timer_sync(&br->multicast_query_timer); |
1626 | 1645 | ||
1627 | spin_lock_bh(&br->multicast_lock); | 1646 | spin_lock_bh(&br->multicast_lock); |
1628 | mdb = br->mdb; | 1647 | mdb = mlock_dereference(br->mdb, br); |
1629 | if (!mdb) | 1648 | if (!mdb) |
1630 | goto out; | 1649 | goto out; |
1631 | 1650 | ||
@@ -1729,6 +1748,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1729 | { | 1748 | { |
1730 | struct net_bridge_port *port; | 1749 | struct net_bridge_port *port; |
1731 | int err = 0; | 1750 | int err = 0; |
1751 | struct net_bridge_mdb_htable *mdb; | ||
1732 | 1752 | ||
1733 | spin_lock(&br->multicast_lock); | 1753 | spin_lock(&br->multicast_lock); |
1734 | if (br->multicast_disabled == !val) | 1754 | if (br->multicast_disabled == !val) |
@@ -1741,15 +1761,16 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1741 | if (!netif_running(br->dev)) | 1761 | if (!netif_running(br->dev)) |
1742 | goto unlock; | 1762 | goto unlock; |
1743 | 1763 | ||
1744 | if (br->mdb) { | 1764 | mdb = mlock_dereference(br->mdb, br); |
1745 | if (br->mdb->old) { | 1765 | if (mdb) { |
1766 | if (mdb->old) { | ||
1746 | err = -EEXIST; | 1767 | err = -EEXIST; |
1747 | rollback: | 1768 | rollback: |
1748 | br->multicast_disabled = !!val; | 1769 | br->multicast_disabled = !!val; |
1749 | goto unlock; | 1770 | goto unlock; |
1750 | } | 1771 | } |
1751 | 1772 | ||
1752 | err = br_mdb_rehash(&br->mdb, br->mdb->max, | 1773 | err = br_mdb_rehash(&br->mdb, mdb->max, |
1753 | br->hash_elasticity); | 1774 | br->hash_elasticity); |
1754 | if (err) | 1775 | if (err) |
1755 | goto rollback; | 1776 | goto rollback; |
@@ -1774,6 +1795,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1774 | { | 1795 | { |
1775 | int err = -ENOENT; | 1796 | int err = -ENOENT; |
1776 | u32 old; | 1797 | u32 old; |
1798 | struct net_bridge_mdb_htable *mdb; | ||
1777 | 1799 | ||
1778 | spin_lock(&br->multicast_lock); | 1800 | spin_lock(&br->multicast_lock); |
1779 | if (!netif_running(br->dev)) | 1801 | if (!netif_running(br->dev)) |
@@ -1782,7 +1804,9 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1782 | err = -EINVAL; | 1804 | err = -EINVAL; |
1783 | if (!is_power_of_2(val)) | 1805 | if (!is_power_of_2(val)) |
1784 | goto unlock; | 1806 | goto unlock; |
1785 | if (br->mdb && val < br->mdb->size) | 1807 | |
1808 | mdb = mlock_dereference(br->mdb, br); | ||
1809 | if (mdb && val < mdb->size) | ||
1786 | goto unlock; | 1810 | goto unlock; |
1787 | 1811 | ||
1788 | err = 0; | 1812 | err = 0; |
@@ -1790,8 +1814,8 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1790 | old = br->hash_max; | 1814 | old = br->hash_max; |
1791 | br->hash_max = val; | 1815 | br->hash_max = val; |
1792 | 1816 | ||
1793 | if (br->mdb) { | 1817 | if (mdb) { |
1794 | if (br->mdb->old) { | 1818 | if (mdb->old) { |
1795 | err = -EEXIST; | 1819 | err = -EEXIST; |
1796 | rollback: | 1820 | rollback: |
1797 | br->hash_max = old; | 1821 | br->hash_max = old; |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 75c90edaf7db..b862071bf601 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -72,7 +72,7 @@ struct net_bridge_fdb_entry | |||
72 | 72 | ||
73 | struct net_bridge_port_group { | 73 | struct net_bridge_port_group { |
74 | struct net_bridge_port *port; | 74 | struct net_bridge_port *port; |
75 | struct net_bridge_port_group *next; | 75 | struct net_bridge_port_group __rcu *next; |
76 | struct hlist_node mglist; | 76 | struct hlist_node mglist; |
77 | struct rcu_head rcu; | 77 | struct rcu_head rcu; |
78 | struct timer_list timer; | 78 | struct timer_list timer; |
@@ -86,7 +86,7 @@ struct net_bridge_mdb_entry | |||
86 | struct hlist_node hlist[2]; | 86 | struct hlist_node hlist[2]; |
87 | struct hlist_node mglist; | 87 | struct hlist_node mglist; |
88 | struct net_bridge *br; | 88 | struct net_bridge *br; |
89 | struct net_bridge_port_group *ports; | 89 | struct net_bridge_port_group __rcu *ports; |
90 | struct rcu_head rcu; | 90 | struct rcu_head rcu; |
91 | struct timer_list timer; | 91 | struct timer_list timer; |
92 | struct timer_list query_timer; | 92 | struct timer_list query_timer; |
@@ -227,7 +227,7 @@ struct net_bridge | |||
227 | unsigned long multicast_startup_query_interval; | 227 | unsigned long multicast_startup_query_interval; |
228 | 228 | ||
229 | spinlock_t multicast_lock; | 229 | spinlock_t multicast_lock; |
230 | struct net_bridge_mdb_htable *mdb; | 230 | struct net_bridge_mdb_htable __rcu *mdb; |
231 | struct hlist_head router_list; | 231 | struct hlist_head router_list; |
232 | struct hlist_head mglist; | 232 | struct hlist_head mglist; |
233 | 233 | ||