[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>
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 70b7ef9..7fa3a5a 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -106,6 +106,20 @@
 	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 @@
 	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 @@
 	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 @@
 
 	rcu_assign_pointer(dev->br_port, NULL);
 
+	kobject_del(&p->kobj);
+
 	call_rcu(&p->rcu, destroy_nbp_rcu);
 }
 
@@ -161,7 +179,6 @@
 	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 @@
 	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 @@
 	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 @@
 	if (!p || p->br != br) 
 		return -EINVAL;
 
-	br_sysfs_removeif(p);
 	del_nbp(p);
 
 	spin_lock_bh(&br->lock);