aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-02-09 20:10:12 -0500
committerDavid S. Miller <davem@davemloft.net>2006-02-09 20:10:12 -0500
commitbab1deea308afcf9200837d6ac20aefe92972efb (patch)
treebcf3d6ecb431b7b94cdd2a68e12b97abe3c2ebba /net/bridge
parent5dce971acf2ae20c80d5e9d1f6bbf17376870911 (diff)
[BRIDGE]: fix error handling for add interface to bridge
Refactor how the bridge code interacts with kobject system. It should still use kobjects even if not using sysfs. Fix the error unwind handling in br_add_if. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_if.c77
-rw-r--r--net/bridge/br_private.h5
-rw-r--r--net/bridge/br_sysfs_if.c50
3 files changed, 59 insertions, 73 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 70b7ef917234..7fa3a5a9971f 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -106,6 +106,20 @@ done:
106 rtnl_unlock(); 106 rtnl_unlock();
107} 107}
108 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
109static void destroy_nbp(struct net_bridge_port *p) 123static void destroy_nbp(struct net_bridge_port *p)
110{ 124{
111 struct net_device *dev = p->dev; 125 struct net_device *dev = p->dev;
@@ -114,7 +128,7 @@ static void destroy_nbp(struct net_bridge_port *p)
114 p->dev = NULL; 128 p->dev = NULL;
115 dev_put(dev); 129 dev_put(dev);
116 130
117 br_sysfs_freeif(p); 131 kobject_put(&p->kobj);
118} 132}
119 133
120static void destroy_nbp_rcu(struct rcu_head *head) 134static void destroy_nbp_rcu(struct rcu_head *head)
@@ -138,6 +152,8 @@ static void del_nbp(struct net_bridge_port *p)
138 struct net_bridge *br = p->br; 152 struct net_bridge *br = p->br;
139 struct net_device *dev = p->dev; 153 struct net_device *dev = p->dev;
140 154
155 sysfs_remove_link(&br->ifobj, dev->name);
156
141 dev_set_promiscuity(dev, -1); 157 dev_set_promiscuity(dev, -1);
142 158
143 cancel_delayed_work(&p->carrier_check); 159 cancel_delayed_work(&p->carrier_check);
@@ -152,6 +168,8 @@ static void del_nbp(struct net_bridge_port *p)
152 168
153 rcu_assign_pointer(dev->br_port, NULL); 169 rcu_assign_pointer(dev->br_port, NULL);
154 170
171 kobject_del(&p->kobj);
172
155 call_rcu(&p->rcu, destroy_nbp_rcu); 173 call_rcu(&p->rcu, destroy_nbp_rcu);
156} 174}
157 175
@@ -161,7 +179,6 @@ static void del_br(struct net_bridge *br)
161 struct net_bridge_port *p, *n; 179 struct net_bridge_port *p, *n;
162 180
163 list_for_each_entry_safe(p, n, &br->port_list, list) { 181 list_for_each_entry_safe(p, n, &br->port_list, list) {
164 br_sysfs_removeif(p);
165 del_nbp(p); 182 del_nbp(p);
166 } 183 }
167 184
@@ -261,6 +278,11 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
261 INIT_WORK(&p->carrier_check, port_carrier_check, dev); 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,31 +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 rcu_assign_pointer(dev->br_port, p);
401 dev_set_promiscuity(dev, 1);
402 420
403 list_add_rcu(&p->list, &br->port_list); 421 err = br_fdb_insert(br, p, dev->dev_addr);
422 if (err)
423 goto err1;
404 424
405 spin_lock_bh(&br->lock); 425 err = br_sysfs_addif(p);
406 br_stp_recalculate_bridge_id(br); 426 if (err)
407 br_features_recompute(br); 427 goto err2;
408 if ((br->dev->flags & IFF_UP)
409 && (dev->flags & IFF_UP) && netif_carrier_ok(dev))
410 br_stp_enable_port(p);
411 spin_unlock_bh(&br->lock);
412 428
413 dev_set_mtu(br->dev, br_min_mtu(br)); 429 rcu_assign_pointer(dev->br_port, p);
414 } 430 dev_set_promiscuity(dev, 1);
431
432 list_add_rcu(&p->list, &br->port_list);
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);
415 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);
416 return err; 450 return err;
417} 451}
418 452
@@ -424,7 +458,6 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
424 if (!p || p->br != br) 458 if (!p || p->br != br)
425 return -EINVAL; 459 return -EINVAL;
426 460
427 br_sysfs_removeif(p);
428 del_nbp(p); 461 del_nbp(p);
429 462
430 spin_lock_bh(&br->lock); 463 spin_lock_bh(&br->lock);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c5bd631ffcd5..8f10e09f251b 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -232,9 +232,8 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
232 232
233#ifdef CONFIG_SYSFS 233#ifdef CONFIG_SYSFS
234/* br_sysfs_if.c */ 234/* br_sysfs_if.c */
235extern struct sysfs_ops brport_sysfs_ops;
235extern int br_sysfs_addif(struct net_bridge_port *p); 236extern int br_sysfs_addif(struct net_bridge_port *p);
236extern void br_sysfs_removeif(struct net_bridge_port *p);
237extern void br_sysfs_freeif(struct net_bridge_port *p);
238 237
239/* br_sysfs_br.c */ 238/* br_sysfs_br.c */
240extern int br_sysfs_addbr(struct net_device *dev); 239extern int br_sysfs_addbr(struct net_device *dev);
@@ -243,8 +242,6 @@ extern void br_sysfs_delbr(struct net_device *dev);
243#else 242#else
244 243
245#define br_sysfs_addif(p) (0) 244#define br_sysfs_addif(p) (0)
246#define br_sysfs_removeif(p) do { } while(0)
247#define br_sysfs_freeif(p) kfree(p)
248#define br_sysfs_addbr(dev) (0) 245#define br_sysfs_addbr(dev) (0)
249#define br_sysfs_delbr(dev) do { } while(0) 246#define br_sysfs_delbr(dev) do { } while(0)
250#endif /* CONFIG_SYSFS */ 247#endif /* CONFIG_SYSFS */
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 0ac0355d16dd..c51c9e42aeb3 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -195,23 +195,11 @@ static ssize_t brport_store(struct kobject * kobj,
195 return ret; 195 return ret;
196} 196}
197 197
198/* called from kobject_put when port ref count goes to zero. */ 198struct sysfs_ops brport_sysfs_ops = {
199static void brport_release(struct kobject *kobj)
200{
201 kfree(container_of(kobj, struct net_bridge_port, kobj));
202}
203
204static struct sysfs_ops brport_sysfs_ops = {
205 .show = brport_show, 199 .show = brport_show,
206 .store = brport_store, 200 .store = brport_store,
207}; 201};
208 202
209static struct kobj_type brport_ktype = {
210 .sysfs_ops = &brport_sysfs_ops,
211 .release = brport_release,
212};
213
214
215/* 203/*
216 * Add sysfs entries to ethernet device added to a bridge. 204 * Add sysfs entries to ethernet device added to a bridge.
217 * Creates a brport subdirectory with bridge attributes. 205 * Creates a brport subdirectory with bridge attributes.
@@ -223,17 +211,6 @@ int br_sysfs_addif(struct net_bridge_port *p)
223 struct brport_attribute **a; 211 struct brport_attribute **a;
224 int err; 212 int err;
225 213
226 ASSERT_RTNL();
227
228 kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
229 p->kobj.ktype = &brport_ktype;
230 p->kobj.parent = &(p->dev->class_dev.kobj);
231 p->kobj.kset = NULL;
232
233 err = kobject_add(&p->kobj);
234 if(err)
235 goto out1;
236
237 err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj, 214 err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj,
238 SYSFS_BRIDGE_PORT_LINK); 215 SYSFS_BRIDGE_PORT_LINK);
239 if (err) 216 if (err)
@@ -245,28 +222,7 @@ int br_sysfs_addif(struct net_bridge_port *p)
245 goto out2; 222 goto out2;
246 } 223 }
247 224
248 err = sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name); 225 err= sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name);
249 if (err) 226out2:
250 goto out2;
251
252 kobject_uevent(&p->kobj, KOBJ_ADD);
253 return 0;
254 out2:
255 kobject_del(&p->kobj);
256 out1:
257 return err; 227 return err;
258} 228}
259
260void br_sysfs_removeif(struct net_bridge_port *p)
261{
262 pr_debug("br_sysfs_removeif\n");
263 sysfs_remove_link(&p->br->ifobj, p->dev->name);
264 kobject_uevent(&p->kobj, KOBJ_REMOVE);
265 kobject_del(&p->kobj);
266}
267
268void br_sysfs_freeif(struct net_bridge_port *p)
269{
270 pr_debug("br_sysfs_freeif\n");
271 kobject_put(&p->kobj);
272}