diff options
author | stephen hemminger <shemminger@vyatta.com> | 2010-04-27 07:13:11 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-27 12:53:24 -0700 |
commit | dcdca2c49bb6328bbc7cd8d73434c308b5dd0df2 (patch) | |
tree | a9cbb45b1cd4cffae2279f18989c5a40887a1b72 | |
parent | 7180f7751d5a1b6f1ef40285b5e928970cdd5306 (diff) | |
download | op-kernel-dev-dcdca2c49bb6328bbc7cd8d73434c308b5dd0df2.zip op-kernel-dev-dcdca2c49bb6328bbc7cd8d73434c308b5dd0df2.tar.gz |
bridge: multicast router list manipulation
I prefer that the hlist be only accessed through the hlist macro
objects. Explicit twiddling of links (especially with RCU) exposes
the code to future bugs.
Compile tested only.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/bridge/br_multicast.c | 30 |
1 files changed, 15 insertions, 15 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 2048ef0..fcba313 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1042,21 +1042,21 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, static void br_multicast_add_router(struct net_bridge *br, struct net_bridge_port *port) { - struct hlist_node *p; - struct hlist_node **h; - - for (h = &br->router_list.first; - (p = *h) && - (unsigned long)container_of(p, struct net_bridge_port, rlist) > - (unsigned long)port; - h = &p->next) - ; - - port->rlist.pprev = h; - port->rlist.next = p; - rcu_assign_pointer(*h, &port->rlist); - if (p) - p->pprev = &port->rlist.next; + struct net_bridge_port *p; + struct hlist_node *n, *last = NULL; + + hlist_for_each_entry(p, n, &br->router_list, rlist) { + if ((unsigned long) port >= (unsigned long) p) { + hlist_add_before_rcu(n, &port->rlist); + return; + } + last = n; + } + + if (last) + hlist_add_after_rcu(last, &port->rlist); + else + hlist_add_head_rcu(&port->rlist, &br->router_list); } static void br_multicast_mark_router(struct net_bridge *br, |