diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 15 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 95 |
2 files changed, 57 insertions, 53 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ea6b9043a5e7..a6e789172727 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -5064,19 +5064,16 @@ static void bond_set_lockdep_class(struct net_device *dev) | |||
5064 | int bond_create(const char *name) | 5064 | int bond_create(const char *name) |
5065 | { | 5065 | { |
5066 | struct net_device *bond_dev; | 5066 | struct net_device *bond_dev; |
5067 | struct bonding *bond; | ||
5068 | int res; | 5067 | int res; |
5069 | 5068 | ||
5070 | rtnl_lock(); | 5069 | rtnl_lock(); |
5071 | /* Check to see if the bond already exists. */ | 5070 | /* Check to see if the bond already exists. */ |
5072 | if (name) { | 5071 | /* FIXME: pass netns from caller */ |
5073 | list_for_each_entry(bond, &bond_dev_list, bond_list) | 5072 | if (name && __dev_get_by_name(&init_net, name)) { |
5074 | if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { | 5073 | pr_err(DRV_NAME ": cannot add bond %s; already exists\n", |
5075 | pr_err(DRV_NAME ": cannot add bond %s;" | 5074 | name); |
5076 | " it already exists\n", name); | 5075 | res = -EEXIST; |
5077 | res = -EPERM; | 5076 | goto out_rtnl; |
5078 | goto out_rtnl; | ||
5079 | } | ||
5080 | } | 5077 | } |
5081 | 5078 | ||
5082 | bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", | 5079 | bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index e3fb7f515150..395f3b160a75 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -68,6 +68,17 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) | |||
68 | return res; | 68 | return res; |
69 | } | 69 | } |
70 | 70 | ||
71 | static struct net_device *bond_get_by_name(const char *ifname) | ||
72 | { | ||
73 | struct bonding *bond; | ||
74 | |||
75 | list_for_each_entry(bond, &bond_dev_list, bond_list) { | ||
76 | if (strncmp(bond->dev->name, ifname, IFNAMSIZ) == 0) | ||
77 | return bond->dev; | ||
78 | } | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
71 | /* | 82 | /* |
72 | * "store" function for the bond_masters attribute. This is what | 83 | * "store" function for the bond_masters attribute. This is what |
73 | * creates and deletes entire bonds. | 84 | * creates and deletes entire bonds. |
@@ -82,7 +93,6 @@ static ssize_t bonding_store_bonds(struct class *cls, | |||
82 | char command[IFNAMSIZ + 1] = {0, }; | 93 | char command[IFNAMSIZ + 1] = {0, }; |
83 | char *ifname; | 94 | char *ifname; |
84 | int rv, res = count; | 95 | int rv, res = count; |
85 | struct bonding *bond; | ||
86 | 96 | ||
87 | sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ | 97 | sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ |
88 | ifname = command + 1; | 98 | ifname = command + 1; |
@@ -98,41 +108,35 @@ static ssize_t bonding_store_bonds(struct class *cls, | |||
98 | pr_info(DRV_NAME ": Bond creation failed.\n"); | 108 | pr_info(DRV_NAME ": Bond creation failed.\n"); |
99 | res = rv; | 109 | res = rv; |
100 | } | 110 | } |
101 | goto out; | 111 | } else if (command[0] == '-') { |
102 | } | 112 | struct net_device *bond_dev; |
103 | 113 | ||
104 | if (command[0] == '-') { | ||
105 | rtnl_lock(); | 114 | rtnl_lock(); |
115 | bond_dev = bond_get_by_name(ifname); | ||
116 | if (bond_dev) { | ||
117 | pr_info(DRV_NAME ": %s is being deleted...\n", | ||
118 | ifname); | ||
119 | unregister_netdevice(bond_dev); | ||
120 | } else { | ||
121 | pr_err(DRV_NAME ": unable to delete non-existent %s\n", | ||
122 | ifname); | ||
123 | res = -ENODEV; | ||
124 | } | ||
125 | rtnl_unlock(); | ||
126 | } else | ||
127 | goto err_no_cmd; | ||
106 | 128 | ||
107 | list_for_each_entry(bond, &bond_dev_list, bond_list) | 129 | /* Always return either count or an error. If you return 0, you'll |
108 | if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { | 130 | * get called forever, which is bad. |
109 | pr_info(DRV_NAME | 131 | */ |
110 | ": %s is being deleted...\n", | 132 | return res; |
111 | bond->dev->name); | ||
112 | unregister_netdevice(bond->dev); | ||
113 | goto out_unlock; | ||
114 | } | ||
115 | |||
116 | pr_err(DRV_NAME | ||
117 | ": unable to delete non-existent bond %s\n", ifname); | ||
118 | res = -ENODEV; | ||
119 | goto out_unlock; | ||
120 | } | ||
121 | 133 | ||
122 | err_no_cmd: | 134 | err_no_cmd: |
123 | pr_err(DRV_NAME ": no command found in bonding_masters." | 135 | pr_err(DRV_NAME ": no command found in bonding_masters." |
124 | " Use +ifname or -ifname.\n"); | 136 | " Use +ifname or -ifname.\n"); |
125 | return -EPERM; | 137 | return -EPERM; |
126 | |||
127 | out_unlock: | ||
128 | rtnl_unlock(); | ||
129 | |||
130 | /* Always return either count or an error. If you return 0, you'll | ||
131 | * get called forever, which is bad. | ||
132 | */ | ||
133 | out: | ||
134 | return res; | ||
135 | } | 138 | } |
139 | |||
136 | /* class attribute for bond_masters file. This ends up in /sys/class/net */ | 140 | /* class attribute for bond_masters file. This ends up in /sys/class/net */ |
137 | static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO, | 141 | static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO, |
138 | bonding_show_bonds, bonding_store_bonds); | 142 | bonding_show_bonds, bonding_store_bonds); |
@@ -233,29 +237,16 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
233 | 237 | ||
234 | /* Got a slave name in ifname. Is it already in the list? */ | 238 | /* Got a slave name in ifname. Is it already in the list? */ |
235 | found = 0; | 239 | found = 0; |
236 | read_lock(&bond->lock); | ||
237 | bond_for_each_slave(bond, slave, i) | ||
238 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | ||
239 | pr_err(DRV_NAME | ||
240 | ": %s: Interface %s is already enslaved!\n", | ||
241 | bond->dev->name, ifname); | ||
242 | ret = -EPERM; | ||
243 | read_unlock(&bond->lock); | ||
244 | goto out; | ||
245 | } | ||
246 | 240 | ||
247 | read_unlock(&bond->lock); | 241 | /* FIXME: get netns from sysfs object */ |
248 | pr_info(DRV_NAME ": %s: Adding slave %s.\n", | 242 | dev = __dev_get_by_name(&init_net, ifname); |
249 | bond->dev->name, ifname); | ||
250 | dev = dev_get_by_name(&init_net, ifname); | ||
251 | if (!dev) { | 243 | if (!dev) { |
252 | pr_info(DRV_NAME | 244 | pr_info(DRV_NAME |
253 | ": %s: Interface %s does not exist!\n", | 245 | ": %s: Interface %s does not exist!\n", |
254 | bond->dev->name, ifname); | 246 | bond->dev->name, ifname); |
255 | ret = -EPERM; | 247 | ret = -ENODEV; |
256 | goto out; | 248 | goto out; |
257 | } else | 249 | } |
258 | dev_put(dev); | ||
259 | 250 | ||
260 | if (dev->flags & IFF_UP) { | 251 | if (dev->flags & IFF_UP) { |
261 | pr_err(DRV_NAME | 252 | pr_err(DRV_NAME |
@@ -265,6 +256,22 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
265 | ret = -EPERM; | 256 | ret = -EPERM; |
266 | goto out; | 257 | goto out; |
267 | } | 258 | } |
259 | |||
260 | read_lock(&bond->lock); | ||
261 | bond_for_each_slave(bond, slave, i) | ||
262 | if (slave->dev == dev) { | ||
263 | pr_err(DRV_NAME | ||
264 | ": %s: Interface %s is already enslaved!\n", | ||
265 | bond->dev->name, ifname); | ||
266 | ret = -EPERM; | ||
267 | read_unlock(&bond->lock); | ||
268 | goto out; | ||
269 | } | ||
270 | read_unlock(&bond->lock); | ||
271 | |||
272 | pr_info(DRV_NAME ": %s: Adding slave %s.\n", | ||
273 | bond->dev->name, ifname); | ||
274 | |||
268 | /* If this is the first slave, then we need to set | 275 | /* If this is the first slave, then we need to set |
269 | the master's hardware address to be the same as the | 276 | the master's hardware address to be the same as the |
270 | slave's. */ | 277 | slave's. */ |