aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Arlott <simon@fire.lp0.eu>2010-05-10 05:31:11 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-16 02:10:15 -0400
commite0f43752a942b7be1bc06b9fd74e20ae337c1cca (patch)
tree892d0fbc2ecae39f2e5c4a7b711cbb988c8dc3f1
parent28a16c97963d3bc36a2c192859f6d8025ef2967a (diff)
bridge: update sysfs link names if port device names have changed
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>
-rw-r--r--fs/sysfs/symlink.c1
-rw-r--r--net/bridge/br_if.c2
-rw-r--r--net/bridge/br_notify.c7
-rw-r--r--net/bridge/br_private.h6
-rw-r--r--net/bridge/br_sysfs_if.c32
5 files changed, 42 insertions, 6 deletions
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index b93ec51fa7ac..942f239a2132 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -261,3 +261,4 @@ const struct inode_operations sysfs_symlink_inode_operations = {
261 261
262EXPORT_SYMBOL_GPL(sysfs_create_link); 262EXPORT_SYMBOL_GPL(sysfs_create_link);
263EXPORT_SYMBOL_GPL(sysfs_remove_link); 263EXPORT_SYMBOL_GPL(sysfs_remove_link);
264EXPORT_SYMBOL_GPL(sysfs_rename_link);
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 45f3f8871149..f25e3c92bd72 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -133,7 +133,7 @@ static void del_nbp(struct net_bridge_port *p)
133 struct net_bridge *br = p->br; 133 struct net_bridge *br = p->br;
134 struct net_device *dev = p->dev; 134 struct net_device *dev = p->dev;
135 135
136 sysfs_remove_link(br->ifobj, dev->name); 136 sysfs_remove_link(br->ifobj, p->sysfs_name);
137 137
138 dev_set_promiscuity(dev, -1); 138 dev_set_promiscuity(dev, -1);
139 139
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 1413b72acc7f..717e1fd6133c 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -34,6 +34,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
34 struct net_device *dev = ptr; 34 struct net_device *dev = ptr;
35 struct net_bridge_port *p = dev->br_port; 35 struct net_bridge_port *p = dev->br_port;
36 struct net_bridge *br; 36 struct net_bridge *br;
37 int err;
37 38
38 /* not a port of a bridge */ 39 /* not a port of a bridge */
39 if (p == NULL) 40 if (p == NULL)
@@ -83,6 +84,12 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
83 br_del_if(br, dev); 84 br_del_if(br, dev);
84 break; 85 break;
85 86
87 case NETDEV_CHANGENAME:
88 err = br_sysfs_renameif(p);
89 if (err)
90 return notifier_from_errno(err);
91 break;
92
86 case NETDEV_PRE_TYPE_CHANGE: 93 case NETDEV_PRE_TYPE_CHANGE:
87 /* Forbid underlaying device to change its type. */ 94 /* Forbid underlaying device to change its type. */
88 return NOTIFY_BAD; 95 return NOTIFY_BAD;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 79a13d1c2573..0f4a74bc6a9b 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -139,6 +139,10 @@ struct net_bridge_port
139 struct hlist_head mglist; 139 struct hlist_head mglist;
140 struct hlist_node rlist; 140 struct hlist_node rlist;
141#endif 141#endif
142
143#ifdef CONFIG_SYSFS
144 char sysfs_name[IFNAMSIZ];
145#endif
142}; 146};
143 147
144struct br_cpu_netstats { 148struct br_cpu_netstats {
@@ -480,6 +484,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
480/* br_sysfs_if.c */ 484/* br_sysfs_if.c */
481extern const struct sysfs_ops brport_sysfs_ops; 485extern const struct sysfs_ops brport_sysfs_ops;
482extern int br_sysfs_addif(struct net_bridge_port *p); 486extern int br_sysfs_addif(struct net_bridge_port *p);
487extern int br_sysfs_renameif(struct net_bridge_port *p);
483 488
484/* br_sysfs_br.c */ 489/* br_sysfs_br.c */
485extern int br_sysfs_addbr(struct net_device *dev); 490extern int br_sysfs_addbr(struct net_device *dev);
@@ -488,6 +493,7 @@ extern void br_sysfs_delbr(struct net_device *dev);
488#else 493#else
489 494
490#define br_sysfs_addif(p) (0) 495#define br_sysfs_addif(p) (0)
496#define br_sysfs_renameif(p) (0)
491#define br_sysfs_addbr(dev) (0) 497#define br_sysfs_addbr(dev) (0)
492#define br_sysfs_delbr(dev) do { } while(0) 498#define br_sysfs_delbr(dev) do { } while(0)
493#endif /* CONFIG_SYSFS */ 499#endif /* CONFIG_SYSFS */
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 0b9916489d6b..fd5799c9bc8d 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -246,7 +246,7 @@ const struct sysfs_ops brport_sysfs_ops = {
246/* 246/*
247 * Add sysfs entries to ethernet device added to a bridge. 247 * Add sysfs entries to ethernet device added to a bridge.
248 * Creates a brport subdirectory with bridge attributes. 248 * Creates a brport subdirectory with bridge attributes.
249 * Puts symlink in bridge's brport subdirectory 249 * Puts symlink in bridge's brif subdirectory
250 */ 250 */
251int br_sysfs_addif(struct net_bridge_port *p) 251int br_sysfs_addif(struct net_bridge_port *p)
252{ 252{
@@ -257,15 +257,37 @@ int br_sysfs_addif(struct net_bridge_port *p)
257 err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj, 257 err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
258 SYSFS_BRIDGE_PORT_LINK); 258 SYSFS_BRIDGE_PORT_LINK);
259 if (err) 259 if (err)
260 goto out2; 260 return err;
261 261
262 for (a = brport_attrs; *a; ++a) { 262 for (a = brport_attrs; *a; ++a) {
263 err = sysfs_create_file(&p->kobj, &((*a)->attr)); 263 err = sysfs_create_file(&p->kobj, &((*a)->attr));
264 if (err) 264 if (err)
265 goto out2; 265 return err;
266 } 266 }
267 267
268 err = sysfs_create_link(br->ifobj, &p->kobj, p->dev->name); 268 strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
269out2: 269 return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
270}
271
272/* Rename bridge's brif symlink */
273int br_sysfs_renameif(struct net_bridge_port *p)
274{
275 struct net_bridge *br = p->br;
276 int err;
277
278 /* If a rename fails, the rollback will cause another
279 * rename call with the existing name.
280 */
281 if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ))
282 return 0;
283
284 err = sysfs_rename_link(br->ifobj, &p->kobj,
285 p->sysfs_name, p->dev->name);
286 if (err)
287 netdev_notice(br->dev, "unable to rename link %s to %s",
288 p->sysfs_name, p->dev->name);
289 else
290 strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
291
270 return err; 292 return err;
271} 293}