aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r--net/bridge/br_if.c94
1 files changed, 64 insertions, 30 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index da687c8dc6ff..7fa3a5a9971f 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -79,9 +79,14 @@ static int port_cost(struct net_device *dev)
79 */ 79 */
80static void port_carrier_check(void *arg) 80static void port_carrier_check(void *arg)
81{ 81{
82 struct net_bridge_port *p = arg; 82 struct net_device *dev = arg;
83 struct net_bridge_port *p;
83 84
84 rtnl_lock(); 85 rtnl_lock();
86 p = dev->br_port;
87 if (!p)
88 goto done;
89
85 if (netif_carrier_ok(p->dev)) { 90 if (netif_carrier_ok(p->dev)) {
86 u32 cost = port_cost(p->dev); 91 u32 cost = port_cost(p->dev);
87 92
@@ -97,19 +102,33 @@ static void port_carrier_check(void *arg)
97 br_stp_disable_port(p); 102 br_stp_disable_port(p);
98 spin_unlock_bh(&p->br->lock); 103 spin_unlock_bh(&p->br->lock);
99 } 104 }
105done:
100 rtnl_unlock(); 106 rtnl_unlock();
101} 107}
102 108
109static void release_nbp(struct kobject *kobj)
110{
111 struct net_bridge_port *p
112 = container_of(kobj, struct net_bridge_port, kobj);
113 kfree(p);
114}
115
116static struct kobj_type brport_ktype = {
117#ifdef CONFIG_SYSFS
118 .sysfs_ops = &brport_sysfs_ops,
119#endif
120 .release = release_nbp,
121};
122
103static void destroy_nbp(struct net_bridge_port *p) 123static void destroy_nbp(struct net_bridge_port *p)
104{ 124{
105 struct net_device *dev = p->dev; 125 struct net_device *dev = p->dev;
106 126
107 dev->br_port = NULL;
108 p->br = NULL; 127 p->br = NULL;
109 p->dev = NULL; 128 p->dev = NULL;
110 dev_put(dev); 129 dev_put(dev);
111 130
112 br_sysfs_freeif(p); 131 kobject_put(&p->kobj);
113} 132}
114 133
115static void destroy_nbp_rcu(struct rcu_head *head) 134static void destroy_nbp_rcu(struct rcu_head *head)
@@ -133,24 +152,24 @@ static void del_nbp(struct net_bridge_port *p)
133 struct net_bridge *br = p->br; 152 struct net_bridge *br = p->br;
134 struct net_device *dev = p->dev; 153 struct net_device *dev = p->dev;
135 154
136 /* Race between RTNL notify and RCU callback */ 155 sysfs_remove_link(&br->ifobj, dev->name);
137 if (p->deleted)
138 return;
139 156
140 dev_set_promiscuity(dev, -1); 157 dev_set_promiscuity(dev, -1);
141 158
142 cancel_delayed_work(&p->carrier_check); 159 cancel_delayed_work(&p->carrier_check);
143 flush_scheduled_work();
144 160
145 spin_lock_bh(&br->lock); 161 spin_lock_bh(&br->lock);
146 br_stp_disable_port(p); 162 br_stp_disable_port(p);
147 p->deleted = 1;
148 spin_unlock_bh(&br->lock); 163 spin_unlock_bh(&br->lock);
149 164
150 br_fdb_delete_by_port(br, p); 165 br_fdb_delete_by_port(br, p);
151 166
152 list_del_rcu(&p->list); 167 list_del_rcu(&p->list);
153 168
169 rcu_assign_pointer(dev->br_port, NULL);
170
171 kobject_del(&p->kobj);
172
154 call_rcu(&p->rcu, destroy_nbp_rcu); 173 call_rcu(&p->rcu, destroy_nbp_rcu);
155} 174}
156 175
@@ -160,7 +179,6 @@ static void del_br(struct net_bridge *br)
160 struct net_bridge_port *p, *n; 179 struct net_bridge_port *p, *n;
161 180
162 list_for_each_entry_safe(p, n, &br->port_list, list) { 181 list_for_each_entry_safe(p, n, &br->port_list, list) {
163 br_sysfs_removeif(p);
164 del_nbp(p); 182 del_nbp(p);
165 } 183 }
166 184
@@ -254,13 +272,17 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
254 p->dev = dev; 272 p->dev = dev;
255 p->path_cost = port_cost(dev); 273 p->path_cost = port_cost(dev);
256 p->priority = 0x8000 >> BR_PORT_BITS; 274 p->priority = 0x8000 >> BR_PORT_BITS;
257 dev->br_port = p;
258 p->port_no = index; 275 p->port_no = index;
259 br_init_port(p); 276 br_init_port(p);
260 p->state = BR_STATE_DISABLED; 277 p->state = BR_STATE_DISABLED;
261 INIT_WORK(&p->carrier_check, port_carrier_check, p); 278 INIT_WORK(&p->carrier_check, port_carrier_check, dev);
262 kobject_init(&p->kobj); 279 kobject_init(&p->kobj);
263 280
281 kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
282 p->kobj.ktype = &brport_ktype;
283 p->kobj.parent = &(dev->class_dev.kobj);
284 p->kobj.kset = NULL;
285
264 return p; 286 return p;
265} 287}
266 288
@@ -388,30 +410,43 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
388 if (dev->br_port != NULL) 410 if (dev->br_port != NULL)
389 return -EBUSY; 411 return -EBUSY;
390 412
391 if (IS_ERR(p = new_nbp(br, dev))) 413 p = new_nbp(br, dev);
414 if (IS_ERR(p))
392 return PTR_ERR(p); 415 return PTR_ERR(p);
393 416
394 if ((err = br_fdb_insert(br, p, dev->dev_addr))) 417 err = kobject_add(&p->kobj);
395 destroy_nbp(p); 418 if (err)
396 419 goto err0;
397 else if ((err = br_sysfs_addif(p)))
398 del_nbp(p);
399 else {
400 dev_set_promiscuity(dev, 1);
401 420
402 list_add_rcu(&p->list, &br->port_list); 421 err = br_fdb_insert(br, p, dev->dev_addr);
422 if (err)
423 goto err1;
403 424
404 spin_lock_bh(&br->lock); 425 err = br_sysfs_addif(p);
405 br_stp_recalculate_bridge_id(br); 426 if (err)
406 br_features_recompute(br); 427 goto err2;
407 if ((br->dev->flags & IFF_UP)
408 && (dev->flags & IFF_UP) && netif_carrier_ok(dev))
409 br_stp_enable_port(p);
410 spin_unlock_bh(&br->lock);
411 428
412 dev_set_mtu(br->dev, br_min_mtu(br)); 429 rcu_assign_pointer(dev->br_port, p);
413 } 430 dev_set_promiscuity(dev, 1);
431
432 list_add_rcu(&p->list, &br->port_list);
414 433
434 spin_lock_bh(&br->lock);
435 br_stp_recalculate_bridge_id(br);
436 br_features_recompute(br);
437 schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE);
438 spin_unlock_bh(&br->lock);
439
440 dev_set_mtu(br->dev, br_min_mtu(br));
441 kobject_uevent(&p->kobj, KOBJ_ADD);
442
443 return 0;
444err2:
445 br_fdb_delete_by_port(br, p);
446err1:
447 kobject_del(&p->kobj);
448err0:
449 kobject_put(&p->kobj);
415 return err; 450 return err;
416} 451}
417 452
@@ -423,7 +458,6 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
423 if (!p || p->br != br) 458 if (!p || p->br != br)
424 return -EINVAL; 459 return -EINVAL;
425 460
426 br_sysfs_removeif(p);
427 del_nbp(p); 461 del_nbp(p);
428 462
429 spin_lock_bh(&br->lock); 463 spin_lock_bh(&br->lock);