[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>
This commit is contained in:
Stephen Hemminger 2006-02-09 17:10:12 -08:00 committed by David S. Miller
parent 5dce971acf
commit bab1deea30
3 changed files with 59 additions and 73 deletions

View File

@ -106,6 +106,20 @@ done:
rtnl_unlock(); 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) static void destroy_nbp(struct net_bridge_port *p)
{ {
struct net_device *dev = p->dev; struct net_device *dev = p->dev;
@ -114,7 +128,7 @@ static void destroy_nbp(struct net_bridge_port *p)
p->dev = NULL; p->dev = NULL;
dev_put(dev); dev_put(dev);
br_sysfs_freeif(p); kobject_put(&p->kobj);
} }
static void destroy_nbp_rcu(struct rcu_head *head) 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_bridge *br = p->br;
struct net_device *dev = p->dev; struct net_device *dev = p->dev;
sysfs_remove_link(&br->ifobj, dev->name);
dev_set_promiscuity(dev, -1); dev_set_promiscuity(dev, -1);
cancel_delayed_work(&p->carrier_check); 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); rcu_assign_pointer(dev->br_port, NULL);
kobject_del(&p->kobj);
call_rcu(&p->rcu, destroy_nbp_rcu); 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; struct net_bridge_port *p, *n;
list_for_each_entry_safe(p, n, &br->port_list, list) { list_for_each_entry_safe(p, n, &br->port_list, list) {
br_sysfs_removeif(p);
del_nbp(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); INIT_WORK(&p->carrier_check, port_carrier_check, dev);
kobject_init(&p->kobj); 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; return p;
} }
@ -388,31 +410,43 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
if (dev->br_port != NULL) if (dev->br_port != NULL)
return -EBUSY; return -EBUSY;
if (IS_ERR(p = new_nbp(br, dev))) p = new_nbp(br, dev);
if (IS_ERR(p))
return PTR_ERR(p); return PTR_ERR(p);
if ((err = br_fdb_insert(br, p, dev->dev_addr))) err = kobject_add(&p->kobj);
destroy_nbp(p); if (err)
goto err0;
else if ((err = br_sysfs_addif(p)))
del_nbp(p);
else {
rcu_assign_pointer(dev->br_port, p);
dev_set_promiscuity(dev, 1);
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); err = br_sysfs_addif(p);
br_stp_recalculate_bridge_id(br); if (err)
br_features_recompute(br); goto err2;
if ((br->dev->flags & IFF_UP)
&& (dev->flags & IFF_UP) && netif_carrier_ok(dev))
br_stp_enable_port(p);
spin_unlock_bh(&br->lock);
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; return err;
} }
@ -424,7 +458,6 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
if (!p || p->br != br) if (!p || p->br != br)
return -EINVAL; return -EINVAL;
br_sysfs_removeif(p);
del_nbp(p); del_nbp(p);
spin_lock_bh(&br->lock); spin_lock_bh(&br->lock);

View File

@ -232,9 +232,8 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
/* br_sysfs_if.c */ /* br_sysfs_if.c */
extern struct sysfs_ops brport_sysfs_ops;
extern int br_sysfs_addif(struct net_bridge_port *p); 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 */ /* br_sysfs_br.c */
extern int br_sysfs_addbr(struct net_device *dev); extern int br_sysfs_addbr(struct net_device *dev);
@ -243,8 +242,6 @@ extern void br_sysfs_delbr(struct net_device *dev);
#else #else
#define br_sysfs_addif(p) (0) #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_addbr(dev) (0)
#define br_sysfs_delbr(dev) do { } while(0) #define br_sysfs_delbr(dev) do { } while(0)
#endif /* CONFIG_SYSFS */ #endif /* CONFIG_SYSFS */

View File

@ -195,23 +195,11 @@ static ssize_t brport_store(struct kobject * kobj,
return ret; return ret;
} }
/* called from kobject_put when port ref count goes to zero. */ struct sysfs_ops brport_sysfs_ops = {
static void brport_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct net_bridge_port, kobj));
}
static struct sysfs_ops brport_sysfs_ops = {
.show = brport_show, .show = brport_show,
.store = brport_store, .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. * Add sysfs entries to ethernet device added to a bridge.
* Creates a brport subdirectory with bridge attributes. * Creates a brport subdirectory with bridge attributes.
@ -223,17 +211,6 @@ int br_sysfs_addif(struct net_bridge_port *p)
struct brport_attribute **a; struct brport_attribute **a;
int err; 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, err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj,
SYSFS_BRIDGE_PORT_LINK); SYSFS_BRIDGE_PORT_LINK);
if (err) if (err)
@ -245,28 +222,7 @@ int br_sysfs_addif(struct net_bridge_port *p)
goto out2; goto out2;
} }
err = sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name); err= sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name);
if (err) out2:
goto out2;
kobject_uevent(&p->kobj, KOBJ_ADD);
return 0;
out2:
kobject_del(&p->kobj);
out1:
return err; 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);
}