diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-02-22 04:10:18 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-02-26 14:42:59 -0500 |
commit | 269def7c505b4d229f9ad49bf88543d1e605533e (patch) | |
tree | 341377271f16c0def001a876217a8e6f430d75b4 /net/bridge | |
parent | ac062e84d0c177c43549e7fb608152fec218e7fc (diff) |
[BRIDGE]: eliminate workqueue for carrier check
Having a work queue for checking carrier leads to lots of race issues.
Simpler to just get the cost when data structure is created and
update on change.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_if.c | 30 | ||||
-rw-r--r-- | net/bridge/br_notify.c | 25 | ||||
-rw-r--r-- | net/bridge/br_private.h | 4 |
3 files changed, 17 insertions, 42 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index aff6a779c9c8..6845a258408f 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -77,26 +77,15 @@ static int port_cost(struct net_device *dev) | |||
77 | * Called from work queue to allow for calling functions that | 77 | * Called from work queue to allow for calling functions that |
78 | * might sleep (such as speed check), and to debounce. | 78 | * might sleep (such as speed check), and to debounce. |
79 | */ | 79 | */ |
80 | static void port_carrier_check(struct work_struct *work) | 80 | void br_port_carrier_check(struct net_bridge_port *p) |
81 | { | 81 | { |
82 | struct net_bridge_port *p; | 82 | struct net_device *dev = p->dev; |
83 | struct net_device *dev; | 83 | struct net_bridge *br = p->br; |
84 | struct net_bridge *br; | ||
85 | |||
86 | dev = container_of(work, struct net_bridge_port, | ||
87 | carrier_check.work)->dev; | ||
88 | work_release(work); | ||
89 | |||
90 | rtnl_lock(); | ||
91 | p = dev->br_port; | ||
92 | if (!p) | ||
93 | goto done; | ||
94 | br = p->br; | ||
95 | 84 | ||
96 | if (netif_carrier_ok(dev)) | 85 | if (netif_carrier_ok(dev)) |
97 | p->path_cost = port_cost(dev); | 86 | p->path_cost = port_cost(dev); |
98 | 87 | ||
99 | if (br->dev->flags & IFF_UP) { | 88 | if (netif_running(br->dev)) { |
100 | spin_lock_bh(&br->lock); | 89 | spin_lock_bh(&br->lock); |
101 | if (netif_carrier_ok(dev)) { | 90 | if (netif_carrier_ok(dev)) { |
102 | if (p->state == BR_STATE_DISABLED) | 91 | if (p->state == BR_STATE_DISABLED) |
@@ -107,9 +96,6 @@ static void port_carrier_check(struct work_struct *work) | |||
107 | } | 96 | } |
108 | spin_unlock_bh(&br->lock); | 97 | spin_unlock_bh(&br->lock); |
109 | } | 98 | } |
110 | done: | ||
111 | dev_put(dev); | ||
112 | rtnl_unlock(); | ||
113 | } | 99 | } |
114 | 100 | ||
115 | static void release_nbp(struct kobject *kobj) | 101 | static void release_nbp(struct kobject *kobj) |
@@ -162,9 +148,6 @@ static void del_nbp(struct net_bridge_port *p) | |||
162 | 148 | ||
163 | dev_set_promiscuity(dev, -1); | 149 | dev_set_promiscuity(dev, -1); |
164 | 150 | ||
165 | if (cancel_delayed_work(&p->carrier_check)) | ||
166 | dev_put(dev); | ||
167 | |||
168 | spin_lock_bh(&br->lock); | 151 | spin_lock_bh(&br->lock); |
169 | br_stp_disable_port(p); | 152 | br_stp_disable_port(p); |
170 | spin_unlock_bh(&br->lock); | 153 | spin_unlock_bh(&br->lock); |
@@ -282,7 +265,6 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, | |||
282 | p->port_no = index; | 265 | p->port_no = index; |
283 | br_init_port(p); | 266 | br_init_port(p); |
284 | p->state = BR_STATE_DISABLED; | 267 | p->state = BR_STATE_DISABLED; |
285 | INIT_DELAYED_WORK_NAR(&p->carrier_check, port_carrier_check); | ||
286 | br_stp_port_timer_init(p); | 268 | br_stp_port_timer_init(p); |
287 | 269 | ||
288 | kobject_init(&p->kobj); | 270 | kobject_init(&p->kobj); |
@@ -446,12 +428,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
446 | spin_lock_bh(&br->lock); | 428 | spin_lock_bh(&br->lock); |
447 | br_stp_recalculate_bridge_id(br); | 429 | br_stp_recalculate_bridge_id(br); |
448 | br_features_recompute(br); | 430 | br_features_recompute(br); |
449 | if (schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE)) | ||
450 | dev_hold(dev); | ||
451 | |||
452 | spin_unlock_bh(&br->lock); | 431 | spin_unlock_bh(&br->lock); |
453 | 432 | ||
454 | dev_set_mtu(br->dev, br_min_mtu(br)); | 433 | dev_set_mtu(br->dev, br_min_mtu(br)); |
434 | |||
455 | kobject_uevent(&p->kobj, KOBJ_ADD); | 435 | kobject_uevent(&p->kobj, KOBJ_ADD); |
456 | 436 | ||
457 | return 0; | 437 | return 0; |
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 3311c4e30829..37357ed2149b 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c | |||
@@ -42,51 +42,48 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v | |||
42 | 42 | ||
43 | br = p->br; | 43 | br = p->br; |
44 | 44 | ||
45 | spin_lock_bh(&br->lock); | ||
46 | switch (event) { | 45 | switch (event) { |
47 | case NETDEV_CHANGEMTU: | 46 | case NETDEV_CHANGEMTU: |
48 | dev_set_mtu(br->dev, br_min_mtu(br)); | 47 | dev_set_mtu(br->dev, br_min_mtu(br)); |
49 | break; | 48 | break; |
50 | 49 | ||
51 | case NETDEV_CHANGEADDR: | 50 | case NETDEV_CHANGEADDR: |
51 | spin_lock_bh(&br->lock); | ||
52 | br_fdb_changeaddr(p, dev->dev_addr); | 52 | br_fdb_changeaddr(p, dev->dev_addr); |
53 | br_ifinfo_notify(RTM_NEWLINK, p); | 53 | br_ifinfo_notify(RTM_NEWLINK, p); |
54 | br_stp_recalculate_bridge_id(br); | 54 | br_stp_recalculate_bridge_id(br); |
55 | spin_unlock_bh(&br->lock); | ||
55 | break; | 56 | break; |
56 | 57 | ||
57 | case NETDEV_CHANGE: | 58 | case NETDEV_CHANGE: |
58 | if (br->dev->flags & IFF_UP) | 59 | br_port_carrier_check(p); |
59 | if (schedule_delayed_work(&p->carrier_check, | ||
60 | BR_PORT_DEBOUNCE)) | ||
61 | dev_hold(dev); | ||
62 | break; | 60 | break; |
63 | 61 | ||
64 | case NETDEV_FEAT_CHANGE: | 62 | case NETDEV_FEAT_CHANGE: |
65 | if (br->dev->flags & IFF_UP) | 63 | spin_lock_bh(&br->lock); |
64 | if (netif_running(br->dev)) | ||
66 | br_features_recompute(br); | 65 | br_features_recompute(br); |
67 | 66 | spin_unlock_bh(&br->lock); | |
68 | /* could do recursive feature change notification | ||
69 | * but who would care?? | ||
70 | */ | ||
71 | break; | 67 | break; |
72 | 68 | ||
73 | case NETDEV_DOWN: | 69 | case NETDEV_DOWN: |
70 | spin_lock_bh(&br->lock); | ||
74 | if (br->dev->flags & IFF_UP) | 71 | if (br->dev->flags & IFF_UP) |
75 | br_stp_disable_port(p); | 72 | br_stp_disable_port(p); |
73 | spin_unlock_bh(&br->lock); | ||
76 | break; | 74 | break; |
77 | 75 | ||
78 | case NETDEV_UP: | 76 | case NETDEV_UP: |
77 | spin_lock_bh(&br->lock); | ||
79 | if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) | 78 | if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) |
80 | br_stp_enable_port(p); | 79 | br_stp_enable_port(p); |
80 | spin_unlock_bh(&br->lock); | ||
81 | break; | 81 | break; |
82 | 82 | ||
83 | case NETDEV_UNREGISTER: | 83 | case NETDEV_UNREGISTER: |
84 | spin_unlock_bh(&br->lock); | ||
85 | br_del_if(br, dev); | 84 | br_del_if(br, dev); |
86 | goto done; | 85 | break; |
87 | } | 86 | } |
88 | spin_unlock_bh(&br->lock); | ||
89 | 87 | ||
90 | done: | ||
91 | return NOTIFY_DONE; | 88 | return NOTIFY_DONE; |
92 | } | 89 | } |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 16fc47a821e5..cc3f1c99261a 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -26,8 +26,6 @@ | |||
26 | #define BR_PORT_BITS 10 | 26 | #define BR_PORT_BITS 10 |
27 | #define BR_MAX_PORTS (1<<BR_PORT_BITS) | 27 | #define BR_MAX_PORTS (1<<BR_PORT_BITS) |
28 | 28 | ||
29 | #define BR_PORT_DEBOUNCE (HZ/10) | ||
30 | |||
31 | #define BR_VERSION "2.2" | 29 | #define BR_VERSION "2.2" |
32 | 30 | ||
33 | typedef struct bridge_id bridge_id; | 31 | typedef struct bridge_id bridge_id; |
@@ -81,7 +79,6 @@ struct net_bridge_port | |||
81 | struct timer_list hold_timer; | 79 | struct timer_list hold_timer; |
82 | struct timer_list message_age_timer; | 80 | struct timer_list message_age_timer; |
83 | struct kobject kobj; | 81 | struct kobject kobj; |
84 | struct delayed_work carrier_check; | ||
85 | struct rcu_head rcu; | 82 | struct rcu_head rcu; |
86 | }; | 83 | }; |
87 | 84 | ||
@@ -172,6 +169,7 @@ extern void br_flood_forward(struct net_bridge *br, | |||
172 | int clone); | 169 | int clone); |
173 | 170 | ||
174 | /* br_if.c */ | 171 | /* br_if.c */ |
172 | extern void br_port_carrier_check(struct net_bridge_port *p); | ||
175 | extern int br_add_bridge(const char *name); | 173 | extern int br_add_bridge(const char *name); |
176 | extern int br_del_bridge(const char *name); | 174 | extern int br_del_bridge(const char *name); |
177 | extern void br_cleanup_bridges(void); | 175 | extern void br_cleanup_bridges(void); |