Commit 36e36b51 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Hideaki Yoshifuji

[BRIDGE]: Use RCU for port table.

parent b2da2b35
...@@ -320,6 +320,21 @@ static inline void list_splice_init(struct list_head *list, ...@@ -320,6 +320,21 @@ static inline void list_splice_init(struct list_head *list,
for (pos = (head)->next, n = pos->next; pos != (head); \ for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
/**
* list_for_each_entry_rcu - iterate over rcu list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_rcu(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member), \
({ smp_read_barrier_depends(); 0;}), \
prefetch(pos->member.next))
/* /*
* Double linked lists with a single pointer list head. * Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is * Mostly useful for hash tables where the two pointer list head is
......
...@@ -74,27 +74,20 @@ static int __br_dev_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -74,27 +74,20 @@ static int __br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct net_bridge *br;
int ret; int ret;
br = dev->priv; rcu_read_lock();
read_lock(&br->lock);
ret = __br_dev_xmit(skb, dev); ret = __br_dev_xmit(skb, dev);
read_unlock(&br->lock); rcu_read_unlock();
return ret; return ret;
} }
static int br_dev_open(struct net_device *dev) static int br_dev_open(struct net_device *dev)
{ {
struct net_bridge *br;
netif_start_queue(dev); netif_start_queue(dev);
br = dev->priv; br_stp_enable_bridge(dev->priv);
write_lock(&br->lock);
br_stp_enable_bridge(br);
write_unlock(&br->lock);
return 0; return 0;
} }
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
#include <linux/netfilter_bridge.h> #include <linux/netfilter_bridge.h>
#include "br_private.h" #include "br_private.h"
static inline int should_deliver(struct net_bridge_port *p, struct sk_buff *skb) static inline int should_deliver(const struct net_bridge_port *p,
const struct sk_buff *skb)
{ {
if (skb->dev == p->dev || if (skb->dev == p->dev ||
p->state != BR_STATE_FORWARDING) p->state != BR_STATE_FORWARDING)
...@@ -52,7 +53,7 @@ int br_forward_finish(struct sk_buff *skb) ...@@ -52,7 +53,7 @@ int br_forward_finish(struct sk_buff *skb)
return 0; return 0;
} }
static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb) static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{ {
skb->dev = to->dev; skb->dev = to->dev;
#ifdef CONFIG_NETFILTER_DEBUG #ifdef CONFIG_NETFILTER_DEBUG
...@@ -62,7 +63,7 @@ static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb) ...@@ -62,7 +63,7 @@ static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
br_forward_finish); br_forward_finish);
} }
static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb) static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{ {
struct net_device *indev; struct net_device *indev;
...@@ -73,8 +74,8 @@ static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb) ...@@ -73,8 +74,8 @@ static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb)
br_forward_finish); br_forward_finish);
} }
/* called under bridge lock */ /* called with rcu_read_lock */
void br_deliver(struct net_bridge_port *to, struct sk_buff *skb) void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{ {
if (should_deliver(to, skb)) { if (should_deliver(to, skb)) {
__br_deliver(to, skb); __br_deliver(to, skb);
...@@ -84,8 +85,8 @@ void br_deliver(struct net_bridge_port *to, struct sk_buff *skb) ...@@ -84,8 +85,8 @@ void br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
} }
/* called under bridge lock */ /* called with rcu_read_lock */
void br_forward(struct net_bridge_port *to, struct sk_buff *skb) void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{ {
if (should_deliver(to, skb)) { if (should_deliver(to, skb)) {
__br_forward(to, skb); __br_forward(to, skb);
...@@ -97,7 +98,8 @@ void br_forward(struct net_bridge_port *to, struct sk_buff *skb) ...@@ -97,7 +98,8 @@ void br_forward(struct net_bridge_port *to, struct sk_buff *skb)
/* called under bridge lock */ /* called under bridge lock */
static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone, static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
void (*__packet_hook)(struct net_bridge_port *p, struct sk_buff *skb)) void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb))
{ {
struct net_bridge_port *p; struct net_bridge_port *p;
struct net_bridge_port *prev; struct net_bridge_port *prev;
...@@ -115,7 +117,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone, ...@@ -115,7 +117,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
prev = NULL; prev = NULL;
list_for_each_entry(p, &br->port_list, list) { list_for_each_entry_rcu(p, &br->port_list, list) {
if (should_deliver(p, skb)) { if (should_deliver(p, skb)) {
if (prev != NULL) { if (prev != NULL) {
struct sk_buff *skb2; struct sk_buff *skb2;
...@@ -141,7 +143,8 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone, ...@@ -141,7 +143,8 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
kfree_skb(skb); kfree_skb(skb);
} }
/* called under bridge lock */
/* called with rcu_read_lock */
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone) void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
{ {
br_flood(br, skb, clone, __br_deliver); br_flood(br, skb, clone, __br_deliver);
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/brlock.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "br_private.h" #include "br_private.h"
...@@ -38,7 +37,14 @@ static int br_initial_port_cost(struct net_device *dev) ...@@ -38,7 +37,14 @@ static int br_initial_port_cost(struct net_device *dev)
return 100; return 100;
} }
/* called under BR_NETPROTO_LOCK and bridge lock */ static void destroy_nbp(void *arg)
{
struct net_bridge_port *p = arg;
dev_put(p->dev);
kfree(p);
}
/* called under bridge lock */
static void del_nbp(struct net_bridge_port *p) static void del_nbp(struct net_bridge_port *p)
{ {
struct net_device *dev = p->dev; struct net_device *dev = p->dev;
...@@ -48,24 +54,22 @@ static void del_nbp(struct net_bridge_port *p) ...@@ -48,24 +54,22 @@ static void del_nbp(struct net_bridge_port *p)
dev_set_promiscuity(dev, -1); dev_set_promiscuity(dev, -1);
dev->br_port = NULL; dev->br_port = NULL;
list_del(&p->list); list_del_rcu(&p->list);
br_fdb_delete_by_port(p->br, p); br_fdb_delete_by_port(p->br, p);
kfree(p);
dev_put(dev); call_rcu(&p->rcu, destroy_nbp, p);
} }
static void del_ifs(struct net_bridge *br) static void del_ifs(struct net_bridge *br)
{ {
struct list_head *p, *n; struct list_head *p, *n;
br_write_lock_bh(BR_NETPROTO_LOCK); spin_lock_bh(&br->lock);
write_lock(&br->lock);
list_for_each_safe(p, n, &br->port_list) { list_for_each_safe(p, n, &br->port_list) {
del_nbp(list_entry(p, struct net_bridge_port, list)); del_nbp(list_entry(p, struct net_bridge_port, list));
} }
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
br_write_unlock_bh(BR_NETPROTO_LOCK);
} }
static struct net_bridge *new_nb(const char *name) static struct net_bridge *new_nb(const char *name)
...@@ -87,7 +91,7 @@ static struct net_bridge *new_nb(const char *name) ...@@ -87,7 +91,7 @@ static struct net_bridge *new_nb(const char *name)
ether_setup(dev); ether_setup(dev);
br_dev_setup(dev); br_dev_setup(dev);
br->lock = RW_LOCK_UNLOCKED; br->lock = SPIN_LOCK_UNLOCKED;
INIT_LIST_HEAD(&br->port_list); INIT_LIST_HEAD(&br->port_list);
br->hash_lock = RW_LOCK_UNLOCKED; br->hash_lock = RW_LOCK_UNLOCKED;
...@@ -145,7 +149,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device ...@@ -145,7 +149,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device
br_init_port(p); br_init_port(p);
p->state = BR_STATE_DISABLED; p->state = BR_STATE_DISABLED;
list_add(&p->list, &br->port_list); list_add_rcu(&p->list, &br->port_list);
return p; return p;
} }
...@@ -207,9 +211,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) ...@@ -207,9 +211,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
return -ELOOP; return -ELOOP;
dev_hold(dev); dev_hold(dev);
write_lock_bh(&br->lock); spin_lock_bh(&br->lock);
if ((p = new_nbp(br, dev)) == NULL) { if ((p = new_nbp(br, dev)) == NULL) {
write_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
dev_put(dev); dev_put(dev);
return -EXFULL; return -EXFULL;
} }
...@@ -220,7 +224,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) ...@@ -220,7 +224,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
br_fdb_insert(br, p, dev->dev_addr, 1); br_fdb_insert(br, p, dev->dev_addr, 1);
if ((br->dev.flags & IFF_UP) && (dev->flags & IFF_UP)) if ((br->dev.flags & IFF_UP) && (dev->flags & IFF_UP))
br_stp_enable_port(p); br_stp_enable_port(p);
write_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
return 0; return 0;
} }
...@@ -230,16 +234,14 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) ...@@ -230,16 +234,14 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
struct net_bridge_port *p; struct net_bridge_port *p;
int retval = 0; int retval = 0;
br_write_lock_bh(BR_NETPROTO_LOCK); spin_lock_bh(&br->lock);
write_lock(&br->lock);
if ((p = dev->br_port) == NULL || p->br != br) if ((p = dev->br_port) == NULL || p->br != br)
retval = -EINVAL; retval = -EINVAL;
else { else {
del_nbp(p); del_nbp(p);
br_stp_recalculate_bridge_id(br); br_stp_recalculate_bridge_id(br);
} }
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
br_write_unlock_bh(BR_NETPROTO_LOCK);
return retval; return retval;
} }
...@@ -263,11 +265,11 @@ void br_get_port_ifindices(struct net_bridge *br, int *ifindices) ...@@ -263,11 +265,11 @@ void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
{ {
struct net_bridge_port *p; struct net_bridge_port *p;
read_lock(&br->lock); rcu_read_lock();
list_for_each_entry(p, &br->port_list, list) { list_for_each_entry_rcu(p, &br->port_list, list) {
ifindices[p->port_no] = p->dev->ifindex; ifindices[p->port_no] = p->dev->ifindex;
} }
read_unlock(&br->lock); rcu_read_unlock();
} }
......
...@@ -59,15 +59,16 @@ int br_handle_frame_finish(struct sk_buff *skb) ...@@ -59,15 +59,16 @@ int br_handle_frame_finish(struct sk_buff *skb)
dest = skb->mac.ethernet->h_dest; dest = skb->mac.ethernet->h_dest;
rcu_read_lock();
p = skb->dev->br_port; p = skb->dev->br_port;
if (p == NULL) smp_read_barrier_depends();
goto err_nolock;
br = p->br; if (p == NULL || p->state == BR_STATE_DISABLED) {
read_lock(&br->lock); kfree(skb);
if (skb->dev->br_port == NULL) goto out;
goto err; }
br = p->br;
passedup = 0; passedup = 0;
if (br->dev.flags & IFF_PROMISC) { if (br->dev.flags & IFF_PROMISC) {
struct sk_buff *skb2; struct sk_buff *skb2;
...@@ -105,35 +106,20 @@ int br_handle_frame_finish(struct sk_buff *skb) ...@@ -105,35 +106,20 @@ int br_handle_frame_finish(struct sk_buff *skb)
br_flood_forward(br, skb, 0); br_flood_forward(br, skb, 0);
out: out:
read_unlock(&br->lock); rcu_read_unlock();
return 0;
err:
read_unlock(&br->lock);
err_nolock:
kfree_skb(skb);
return 0; return 0;
} }
int br_handle_frame(struct sk_buff *skb) int br_handle_frame(struct sk_buff *skb)
{ {
struct net_bridge *br;
unsigned char *dest; unsigned char *dest;
struct net_bridge_port *p; struct net_bridge_port *p;
dest = skb->mac.ethernet->h_dest; dest = skb->mac.ethernet->h_dest;
rcu_read_lock();
p = skb->dev->br_port; p = skb->dev->br_port;
if (p == NULL) if (p == NULL || p->state == BR_STATE_DISABLED)
goto err_nolock;
br = p->br;
read_lock(&br->lock);
if (skb->dev->br_port == NULL)
goto err;
if (!(br->dev.flags & IFF_UP) ||
p->state == BR_STATE_DISABLED)
goto err; goto err;
if (skb->mac.ethernet->h_source[0] & 1) if (skb->mac.ethernet->h_source[0] & 1)
...@@ -141,34 +127,30 @@ int br_handle_frame(struct sk_buff *skb) ...@@ -141,34 +127,30 @@ int br_handle_frame(struct sk_buff *skb)
if (p->state == BR_STATE_LEARNING || if (p->state == BR_STATE_LEARNING ||
p->state == BR_STATE_FORWARDING) p->state == BR_STATE_FORWARDING)
br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0); br_fdb_insert(p->br, p, skb->mac.ethernet->h_source, 0);
if (br->stp_enabled && if (p->br->stp_enabled &&
!memcmp(dest, bridge_ula, 5) && !memcmp(dest, bridge_ula, 5) &&
!(dest[5] & 0xF0)) !(dest[5] & 0xF0)) {
goto handle_special_frame; if (!dest[5])
br_stp_handle_bpdu(skb);
goto err;
}
if (p->state == BR_STATE_FORWARDING) { if (p->state == BR_STATE_FORWARDING) {
if (br_should_route_hook && br_should_route_hook(&skb)) { if (br_should_route_hook && br_should_route_hook(&skb)) {
read_unlock(&br->lock); rcu_read_unlock();
return -1; return -1;
} }
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish); br_handle_frame_finish);
read_unlock(&br->lock); rcu_read_unlock();
return 0; return 0;
} }
err: err:
read_unlock(&br->lock); rcu_read_unlock();
err_nolock:
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
handle_special_frame:
read_unlock(&br->lock);
if (!dest[5])
br_stp_handle_bpdu(skb);
goto err_nolock;
} }
...@@ -68,8 +68,8 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -68,8 +68,8 @@ static int br_ioctl_device(struct net_bridge *br,
{ {
struct __bridge_info b; struct __bridge_info b;
read_lock(&br->lock);
memset(&b, 0, sizeof(struct __bridge_info)); memset(&b, 0, sizeof(struct __bridge_info));
rcu_read_lock();
memcpy(&b.designated_root, &br->designated_root, 8); memcpy(&b.designated_root, &br->designated_root, 8);
memcpy(&b.bridge_id, &br->bridge_id, 8); memcpy(&b.bridge_id, &br->bridge_id, 8);
b.root_path_cost = br->root_path_cost; b.root_path_cost = br->root_path_cost;
...@@ -89,7 +89,7 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -89,7 +89,7 @@ static int br_ioctl_device(struct net_bridge *br,
b.tcn_timer_value = timer_residue(&br->tcn_timer); b.tcn_timer_value = timer_residue(&br->tcn_timer);
b.topology_change_timer_value = timer_residue(&br->topology_change_timer); b.topology_change_timer_value = timer_residue(&br->topology_change_timer);
b.gc_timer_value = timer_residue(&br->gc_timer); b.gc_timer_value = timer_residue(&br->gc_timer);
read_unlock(&br->lock); rcu_read_unlock();
if (copy_to_user((void *)arg0, &b, sizeof(b))) if (copy_to_user((void *)arg0, &b, sizeof(b)))
return -EFAULT; return -EFAULT;
...@@ -116,27 +116,27 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -116,27 +116,27 @@ static int br_ioctl_device(struct net_bridge *br,
} }
case BRCTL_SET_BRIDGE_FORWARD_DELAY: case BRCTL_SET_BRIDGE_FORWARD_DELAY:
write_lock(&br->lock); spin_lock_bh(&br->lock);
br->bridge_forward_delay = user_to_ticks(arg0); br->bridge_forward_delay = user_to_ticks(arg0);
if (br_is_root_bridge(br)) if (br_is_root_bridge(br))
br->forward_delay = br->bridge_forward_delay; br->forward_delay = br->bridge_forward_delay;
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
return 0; return 0;
case BRCTL_SET_BRIDGE_HELLO_TIME: case BRCTL_SET_BRIDGE_HELLO_TIME:
write_lock(&br->lock); spin_lock_bh(&br->lock);
br->bridge_hello_time = user_to_ticks(arg0); br->bridge_hello_time = user_to_ticks(arg0);
if (br_is_root_bridge(br)) if (br_is_root_bridge(br))
br->hello_time = br->bridge_hello_time; br->hello_time = br->bridge_hello_time;
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
return 0; return 0;
case BRCTL_SET_BRIDGE_MAX_AGE: case BRCTL_SET_BRIDGE_MAX_AGE:
write_lock(&br->lock); spin_lock_bh(&br->lock);
br->bridge_max_age = user_to_ticks(arg0); br->bridge_max_age = user_to_ticks(arg0);
if (br_is_root_bridge(br)) if (br_is_root_bridge(br))
br->max_age = br->bridge_max_age; br->max_age = br->bridge_max_age;
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
return 0; return 0;
case BRCTL_SET_AGEING_TIME: case BRCTL_SET_AGEING_TIME:
...@@ -152,9 +152,9 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -152,9 +152,9 @@ static int br_ioctl_device(struct net_bridge *br,
struct __port_info p; struct __port_info p;
struct net_bridge_port *pt; struct net_bridge_port *pt;
read_lock(&br->lock); rcu_read_lock();
if ((pt = br_get_port(br, arg1)) == NULL) { if ((pt = br_get_port(br, arg1)) == NULL) {
read_unlock(&br->lock); rcu_read_unlock();
return -EINVAL; return -EINVAL;
} }
...@@ -172,7 +172,7 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -172,7 +172,7 @@ static int br_ioctl_device(struct net_bridge *br,
p.forward_delay_timer_value = timer_residue(&pt->forward_delay_timer); p.forward_delay_timer_value = timer_residue(&pt->forward_delay_timer);
p.hold_timer_value = timer_residue(&pt->hold_timer); p.hold_timer_value = timer_residue(&pt->hold_timer);
read_unlock(&br->lock); rcu_read_unlock();
if (copy_to_user((void *)arg0, &p, sizeof(p))) if (copy_to_user((void *)arg0, &p, sizeof(p)))
return -EFAULT; return -EFAULT;
...@@ -185,9 +185,9 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -185,9 +185,9 @@ static int br_ioctl_device(struct net_bridge *br,
return 0; return 0;
case BRCTL_SET_BRIDGE_PRIORITY: case BRCTL_SET_BRIDGE_PRIORITY:
write_lock(&br->lock); spin_lock_bh(&br->lock);
br_stp_set_bridge_priority(br, arg0); br_stp_set_bridge_priority(br, arg0);
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
return 0; return 0;
case BRCTL_SET_PORT_PRIORITY: case BRCTL_SET_PORT_PRIORITY:
...@@ -195,12 +195,12 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -195,12 +195,12 @@ static int br_ioctl_device(struct net_bridge *br,
struct net_bridge_port *p; struct net_bridge_port *p;
int ret = 0; int ret = 0;
write_lock(&br->lock); spin_lock_bh(&br->lock);
if ((p = br_get_port(br, arg0)) == NULL) if ((p = br_get_port(br, arg0)) == NULL)
ret = -EINVAL; ret = -EINVAL;
else else
br_stp_set_port_priority(p, arg1); br_stp_set_port_priority(p, arg1);
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
return ret; return ret;
} }
...@@ -209,12 +209,12 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -209,12 +209,12 @@ static int br_ioctl_device(struct net_bridge *br,
struct net_bridge_port *p; struct net_bridge_port *p;
int ret = 0; int ret = 0;
write_lock(&br->lock); spin_lock_bh(&br->lock);
if ((p = br_get_port(br, arg0)) == NULL) if ((p = br_get_port(br, arg0)) == NULL)
ret = -EINVAL; ret = -EINVAL;
else else
br_stp_set_path_cost(p, arg1); br_stp_set_path_cost(p, arg1);
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
return ret; return ret;
} }
......
...@@ -41,10 +41,10 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v ...@@ -41,10 +41,10 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
switch (event) switch (event)
{ {
case NETDEV_CHANGEADDR: case NETDEV_CHANGEADDR:
write_lock_bh(&br->lock); spin_lock_bh(&br->lock);
br_fdb_changeaddr(p, dev->dev_addr); br_fdb_changeaddr(p, dev->dev_addr);
br_stp_recalculate_bridge_id(br); br_stp_recalculate_bridge_id(br);
write_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
break; break;
case NETDEV_GOING_DOWN: case NETDEV_GOING_DOWN:
...@@ -53,17 +53,17 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v ...@@ -53,17 +53,17 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
case NETDEV_DOWN: case NETDEV_DOWN:
if (br->dev.flags & IFF_UP) { if (br->dev.flags & IFF_UP) {
write_lock_bh(&br->lock); spin_lock_bh(&br->lock);
br_stp_disable_port(p); br_stp_disable_port(p);
write_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
} }
break; break;
case NETDEV_UP: case NETDEV_UP:
if (!(br->dev.flags & IFF_UP)) { if (!(br->dev.flags & IFF_UP)) {
write_lock_bh(&br->lock); spin_lock_bh(&br->lock);
br_stp_enable_port(p); br_stp_enable_port(p);
write_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
} }
break; break;
......
...@@ -75,11 +75,13 @@ struct net_bridge_port ...@@ -75,11 +75,13 @@ struct net_bridge_port
struct br_timer forward_delay_timer; struct br_timer forward_delay_timer;
struct br_timer hold_timer; struct br_timer hold_timer;
struct br_timer message_age_timer; struct br_timer message_age_timer;
struct rcu_head rcu;
}; };
struct net_bridge struct net_bridge
{ {
rwlock_t lock; spinlock_t lock;
struct list_head port_list; struct list_head port_list;
struct net_device dev; struct net_device dev;
struct net_device_stats statistics; struct net_device_stats statistics;
...@@ -137,10 +139,10 @@ extern void br_fdb_insert(struct net_bridge *br, ...@@ -137,10 +139,10 @@ extern void br_fdb_insert(struct net_bridge *br,
int is_local); int is_local);
/* br_forward.c */ /* br_forward.c */
extern void br_deliver(struct net_bridge_port *to, extern void br_deliver(const struct net_bridge_port *to,
struct sk_buff *skb); struct sk_buff *skb);
extern int br_dev_queue_push_xmit(struct sk_buff *skb); extern int br_dev_queue_push_xmit(struct sk_buff *skb);
extern void br_forward(struct net_bridge_port *to, extern void br_forward(const struct net_bridge_port *to,
struct sk_buff *skb); struct sk_buff *skb);
extern int br_forward_finish(struct sk_buff *skb); extern int br_forward_finish(struct sk_buff *skb);
extern void br_flood_deliver(struct net_bridge *br, extern void br_flood_deliver(struct net_bridge *br,
......
...@@ -143,7 +143,7 @@ void br_stp_handle_bpdu(struct sk_buff *skb) ...@@ -143,7 +143,7 @@ void br_stp_handle_bpdu(struct sk_buff *skb)
p = skb->dev->br_port; p = skb->dev->br_port;
br = p->br; br = p->br;
write_lock_bh(&br->lock); spin_lock_bh(&br->lock);
if (p->state == BR_STATE_DISABLED if (p->state == BR_STATE_DISABLED
|| !(br->dev.flags & IFF_UP) || !(br->dev.flags & IFF_UP)
|| !br->stp_enabled || !br->stp_enabled
...@@ -192,5 +192,5 @@ void br_stp_handle_bpdu(struct sk_buff *skb) ...@@ -192,5 +192,5 @@ void br_stp_handle_bpdu(struct sk_buff *skb)
goto out; goto out;
} }
out: out:
write_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
} }
...@@ -44,6 +44,7 @@ void br_stp_enable_bridge(struct net_bridge *br) ...@@ -44,6 +44,7 @@ void br_stp_enable_bridge(struct net_bridge *br)
struct net_bridge_port *p; struct net_bridge_port *p;
struct timer_list *timer = &br->tick; struct timer_list *timer = &br->tick;
spin_lock_bh(&br->lock);
init_timer(timer); init_timer(timer);
timer->data = (unsigned long) br; timer->data = (unsigned long) br;
timer->function = br_tick; timer->function = br_tick;
...@@ -59,6 +60,7 @@ void br_stp_enable_bridge(struct net_bridge *br) ...@@ -59,6 +60,7 @@ void br_stp_enable_bridge(struct net_bridge *br)
} }
br_timer_set(&br->gc_timer, jiffies); br_timer_set(&br->gc_timer, jiffies);
spin_unlock_bh(&br->lock);
} }
/* NO locks held */ /* NO locks held */
...@@ -66,7 +68,7 @@ void br_stp_disable_bridge(struct net_bridge *br) ...@@ -66,7 +68,7 @@ void br_stp_disable_bridge(struct net_bridge *br)
{ {
struct net_bridge_port *p; struct net_bridge_port *p;
write_lock(&br->lock); spin_lock_bh(&br->lock);
br->topology_change = 0; br->topology_change = 0;
br->topology_change_detected = 0; br->topology_change_detected = 0;
br_timer_clear(&br->hello_timer); br_timer_clear(&br->hello_timer);
...@@ -79,7 +81,7 @@ void br_stp_disable_bridge(struct net_bridge *br) ...@@ -79,7 +81,7 @@ void br_stp_disable_bridge(struct net_bridge *br)
if (p->state != BR_STATE_DISABLED) if (p->state != BR_STATE_DISABLED)
br_stp_disable_port(p); br_stp_disable_port(p);
} }
write_unlock(&br->lock); spin_unlock_bh(&br->lock);
del_timer_sync(&br->tick); del_timer_sync(&br->tick);
} }
......
...@@ -169,10 +169,10 @@ void br_tick(unsigned long __data) ...@@ -169,10 +169,10 @@ void br_tick(unsigned long __data)
{ {
struct net_bridge *br = (struct net_bridge *)__data; struct net_bridge *br = (struct net_bridge *)__data;
read_lock(&br->lock); if (spin_trylock_bh(&br->lock)) {
br_check_timers(br); br_check_timers(br);
read_unlock(&br->lock); spin_unlock_bh(&br->lock);
}
br->tick.expires = jiffies + 1; br->tick.expires = jiffies + 1;
add_timer(&br->tick); add_timer(&br->tick);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment