From bab1deea308afcf9200837d6ac20aefe92972efb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 9 Feb 2006 17:10:12 -0800 Subject: [PATCH] [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 Signed-off-by: David S. Miller --- net/bridge/br_if.c | 77 ++++++++++++++++++++++++++++------------ net/bridge/br_private.h | 5 +-- net/bridge/br_sysfs_if.c | 50 ++------------------------ 3 files changed, 59 insertions(+), 73 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 70b7ef9172..7fa3a5a997 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -106,6 +106,20 @@ done: rtnl_unlock(); } +static void release_nbp(struct kobject *kobj) +{ + struct net_bridge_port *p + = container_of(kobj, struct net_bridge_port, kobj); + kfree(p); +} + +static struct kobj_type brport_ktype = { +#ifdef CONFIG_SYSFS + .sysfs_ops = &brport_sysfs_ops, +#endif + .release = release_nbp, +}; + static void destroy_nbp(struct net_bridge_port *p) { struct net_device *dev = p->dev; @@ -114,7 +128,7 @@ static void destroy_nbp(struct net_bridge_port *p) p->dev = NULL; dev_put(dev); - br_sysfs_freeif(p); + kobject_put(&p->kobj); } static void destroy_nbp_rcu(struct rcu_head *head) @@ -138,6 +152,8 @@ static void del_nbp(struct net_bridge_port *p) struct net_bridge *br = p->br; struct net_device *dev = p->dev; + sysfs_remove_link(&br->ifobj, dev->name); + dev_set_promiscuity(dev, -1); cancel_delayed_work(&p->carrier_check); @@ -152,6 +168,8 @@ static void del_nbp(struct net_bridge_port *p) rcu_assign_pointer(dev->br_port, NULL); + kobject_del(&p->kobj); + call_rcu(&p->rcu, destroy_nbp_rcu); } @@ -161,7 +179,6 @@ static void del_br(struct net_bridge *br) struct net_bridge_port *p, *n; list_for_each_entry_safe(p, n, &br->port_list, list) { - br_sysfs_removeif(p); del_nbp(p); } @@ -261,6 +278,11 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, INIT_WORK(&p->carrier_check, port_carrier_check, dev); kobject_init(&p->kobj); + kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); + p->kobj.ktype = &brport_ktype; + p->kobj.parent = &(dev->class_dev.kobj); + p->kobj.kset = NULL; + return p; } @@ -388,31 +410,43 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (dev->br_port != NULL) return -EBUSY; - if (IS_ERR(p = new_nbp(br, dev))) + p = new_nbp(br, dev); + if (IS_ERR(p)) return PTR_ERR(p); - if ((err = br_fdb_insert(br, p, dev->dev_addr))) - destroy_nbp(p); - - else if ((err = br_sysfs_addif(p))) - del_nbp(p); - else { - rcu_assign_pointer(dev->br_port, p); - dev_set_promiscuity(dev, 1); + err = kobject_add(&p->kobj); + if (err) + goto err0; - list_add_rcu(&p->list, &br->port_list); + err = br_fdb_insert(br, p, dev->dev_addr); + if (err) + goto err1; - spin_lock_bh(&br->lock); - br_stp_recalculate_bridge_id(br); - br_features_recompute(br); - if ((br->dev->flags & IFF_UP) - && (dev->flags & IFF_UP) && netif_carrier_ok(dev)) - br_stp_enable_port(p); - spin_unlock_bh(&br->lock); + err = br_sysfs_addif(p); + if (err) + goto err2; - dev_set_mtu(br->dev, br_min_mtu(br)); - } + rcu_assign_pointer(dev->br_port, p); + dev_set_promiscuity(dev, 1); + + list_add_rcu(&p->list, &br->port_list); + + spin_lock_bh(&br->lock); + br_stp_recalculate_bridge_id(br); + br_features_recompute(br); + schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); + spin_unlock_bh(&br->lock); + + dev_set_mtu(br->dev, br_min_mtu(br)); + kobject_uevent(&p->kobj, KOBJ_ADD); + return 0; +err2: + br_fdb_delete_by_port(br, p); +err1: + kobject_del(&p->kobj); +err0: + kobject_put(&p->kobj); return err; } @@ -424,7 +458,6 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) if (!p || p->br != br) return -EINVAL; - br_sysfs_removeif(p); del_nbp(p); spin_lock_bh(&br->lock); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c5bd631ffc..8f10e09f25 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); #ifdef CONFIG_SYSFS /* br_sysfs_if.c */ +extern struct sysfs_ops brport_sysfs_ops; extern int br_sysfs_addif(struct net_bridge_port *p); -extern void br_sysfs_removeif(struct net_bridge_port *p); -extern void br_sysfs_freeif(struct net_bridge_port *p); /* br_sysfs_br.c */ extern int br_sysfs_addbr(struct net_device *dev); @@ -243,8 +242,6 @@ extern void br_sysfs_delbr(struct net_device *dev); #else #define br_sysfs_addif(p) (0) -#define br_sysfs_removeif(p) do { } while(0) -#define br_sysfs_freeif(p) kfree(p) #define br_sysfs_addbr(dev) (0) #define br_sysfs_delbr(dev) do { } while(0) #endif /* CONFIG_SYSFS */ diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 0ac0355d16..c51c9e42ae 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, return ret; } -/* called from kobject_put when port ref count goes to zero. */ -static void brport_release(struct kobject *kobj) -{ - kfree(container_of(kobj, struct net_bridge_port, kobj)); -} - -static struct sysfs_ops brport_sysfs_ops = { +struct sysfs_ops brport_sysfs_ops = { .show = brport_show, .store = brport_store, }; -static struct kobj_type brport_ktype = { - .sysfs_ops = &brport_sysfs_ops, - .release = brport_release, -}; - - /* * Add sysfs entries to ethernet device added to a bridge. * Creates a brport subdirectory with bridge attributes. @@ -223,17 +211,6 @@ int br_sysfs_addif(struct net_bridge_port *p) struct brport_attribute **a; int err; - ASSERT_RTNL(); - - kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); - p->kobj.ktype = &brport_ktype; - p->kobj.parent = &(p->dev->class_dev.kobj); - p->kobj.kset = NULL; - - err = kobject_add(&p->kobj); - if(err) - goto out1; - err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj, SYSFS_BRIDGE_PORT_LINK); if (err) @@ -245,28 +222,7 @@ int br_sysfs_addif(struct net_bridge_port *p) goto out2; } - err = sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name); - if (err) - goto out2; - - kobject_uevent(&p->kobj, KOBJ_ADD); - return 0; - out2: - kobject_del(&p->kobj); - out1: + err= sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name); +out2: return err; } - -void br_sysfs_removeif(struct net_bridge_port *p) -{ - pr_debug("br_sysfs_removeif\n"); - sysfs_remove_link(&p->br->ifobj, p->dev->name); - kobject_uevent(&p->kobj, KOBJ_REMOVE); - kobject_del(&p->kobj); -} - -void br_sysfs_freeif(struct net_bridge_port *p) -{ - pr_debug("br_sysfs_freeif\n"); - kobject_put(&p->kobj); -} -- 2.39.5