Skip to content

Commit

Permalink
[BRIDGE]: fix error handling for add interface to bridge
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stephen Hemminger authored and David S. Miller committed Feb 10, 2006
1 parent 5dce971 commit bab1dee
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 73 deletions.
77 changes: 55 additions & 22 deletions net/bridge/br_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ static void port_carrier_check(void *arg)
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;
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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);
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
Expand Down
5 changes: 1 addition & 4 deletions net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 */
Expand Down
50 changes: 3 additions & 47 deletions net/bridge/br_sysfs_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
Expand All @@ -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);
}

0 comments on commit bab1dee

Please sign in to comment.