Skip to content

Commit

Permalink
bridge: update sysfs link names if port device names have changed
Browse files Browse the repository at this point in the history
Links for each port are created in sysfs using the device
name, but this could be changed after being added to the
bridge.

As well as being unable to remove interfaces after this
occurs (because userspace tools don't recognise the new
name, and the kernel won't recognise the old name), adding
another interface with the old name to the bridge will
cause an error trying to create the sysfs link.

This fixes the problem by listening for NETDEV_CHANGENAME
notifications and renaming the link.

https://bugzilla.kernel.org/show_bug.cgi?id=12743

Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
nomis authored and davem330 committed May 16, 2010
1 parent 28a16c9 commit e0f4375
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 6 deletions.
1 change: 1 addition & 0 deletions fs/sysfs/symlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,4 @@ const struct inode_operations sysfs_symlink_inode_operations = {

EXPORT_SYMBOL_GPL(sysfs_create_link);
EXPORT_SYMBOL_GPL(sysfs_remove_link);
EXPORT_SYMBOL_GPL(sysfs_rename_link);
2 changes: 1 addition & 1 deletion net/bridge/br_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ 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);
sysfs_remove_link(br->ifobj, p->sysfs_name);

dev_set_promiscuity(dev, -1);

Expand Down
7 changes: 7 additions & 0 deletions net/bridge/br_notify.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
struct net_device *dev = ptr;
struct net_bridge_port *p = dev->br_port;
struct net_bridge *br;
int err;

/* not a port of a bridge */
if (p == NULL)
Expand Down Expand Up @@ -83,6 +84,12 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
br_del_if(br, dev);
break;

case NETDEV_CHANGENAME:
err = br_sysfs_renameif(p);
if (err)
return notifier_from_errno(err);
break;

case NETDEV_PRE_TYPE_CHANGE:
/* Forbid underlaying device to change its type. */
return NOTIFY_BAD;
Expand Down
6 changes: 6 additions & 0 deletions net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ struct net_bridge_port
struct hlist_head mglist;
struct hlist_node rlist;
#endif

#ifdef CONFIG_SYSFS
char sysfs_name[IFNAMSIZ];
#endif
};

struct br_cpu_netstats {
Expand Down Expand Up @@ -480,6 +484,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
/* br_sysfs_if.c */
extern const struct sysfs_ops brport_sysfs_ops;
extern int br_sysfs_addif(struct net_bridge_port *p);
extern int br_sysfs_renameif(struct net_bridge_port *p);

/* br_sysfs_br.c */
extern int br_sysfs_addbr(struct net_device *dev);
Expand All @@ -488,6 +493,7 @@ extern void br_sysfs_delbr(struct net_device *dev);
#else

#define br_sysfs_addif(p) (0)
#define br_sysfs_renameif(p) (0)
#define br_sysfs_addbr(dev) (0)
#define br_sysfs_delbr(dev) do { } while(0)
#endif /* CONFIG_SYSFS */
Expand Down
32 changes: 27 additions & 5 deletions net/bridge/br_sysfs_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ const struct sysfs_ops brport_sysfs_ops = {
/*
* Add sysfs entries to ethernet device added to a bridge.
* Creates a brport subdirectory with bridge attributes.
* Puts symlink in bridge's brport subdirectory
* Puts symlink in bridge's brif subdirectory
*/
int br_sysfs_addif(struct net_bridge_port *p)
{
Expand All @@ -257,15 +257,37 @@ int br_sysfs_addif(struct net_bridge_port *p)
err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
SYSFS_BRIDGE_PORT_LINK);
if (err)
goto out2;
return err;

for (a = brport_attrs; *a; ++a) {
err = sysfs_create_file(&p->kobj, &((*a)->attr));
if (err)
goto out2;
return err;
}

err = sysfs_create_link(br->ifobj, &p->kobj, p->dev->name);
out2:
strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
}

/* Rename bridge's brif symlink */
int br_sysfs_renameif(struct net_bridge_port *p)
{
struct net_bridge *br = p->br;
int err;

/* If a rename fails, the rollback will cause another
* rename call with the existing name.
*/
if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ))
return 0;

err = sysfs_rename_link(br->ifobj, &p->kobj,
p->sysfs_name, p->dev->name);
if (err)
netdev_notice(br->dev, "unable to rename link %s to %s",
p->sysfs_name, p->dev->name);
else
strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);

return err;
}

0 comments on commit e0f4375

Please sign in to comment.