1 | /* |
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. |
3 | * |
4 | * This software is available to you under a choice of one of two |
5 | * licenses. You may choose to be licensed under the terms of the GNU |
6 | * General Public License (GPL) Version 2, available from the file |
7 | * COPYING in the main directory of this source tree, or the |
8 | * OpenIB.org BSD license below: |
9 | * |
10 | * Redistribution and use in source and binary forms, with or |
11 | * without modification, are permitted provided that the following |
12 | * conditions are met: |
13 | * |
14 | * - Redistributions of source code must retain the above |
15 | * copyright notice, this list of conditions and the following |
16 | * disclaimer. |
17 | * |
18 | * - Redistributions in binary form must reproduce the above |
19 | * copyright notice, this list of conditions and the following |
20 | * disclaimer in the documentation and/or other materials |
21 | * provided with the distribution. |
22 | * |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
30 | * SOFTWARE. |
31 | */ |
32 | |
33 | #include <linux/sched/signal.h> |
34 | |
35 | #include <linux/init.h> |
36 | #include <linux/seq_file.h> |
37 | |
38 | #include <linux/uaccess.h> |
39 | |
40 | #include "ipoib.h" |
41 | |
42 | static ssize_t parent_show(struct device *d, struct device_attribute *attr, |
43 | char *buf) |
44 | { |
45 | struct net_device *dev = to_net_dev(d); |
46 | struct ipoib_dev_priv *priv = ipoib_priv(dev); |
47 | |
48 | return sysfs_emit(buf, fmt: "%s\n" , priv->parent->name); |
49 | } |
50 | static DEVICE_ATTR_RO(parent); |
51 | |
52 | static bool is_child_unique(struct ipoib_dev_priv *ppriv, |
53 | struct ipoib_dev_priv *priv) |
54 | { |
55 | struct ipoib_dev_priv *tpriv; |
56 | |
57 | ASSERT_RTNL(); |
58 | |
59 | /* |
60 | * Since the legacy sysfs interface uses pkey for deletion it cannot |
61 | * support more than one interface with the same pkey, it creates |
62 | * ambiguity. The RTNL interface deletes using the netdev so it does |
63 | * not have a problem to support duplicated pkeys. |
64 | */ |
65 | if (priv->child_type != IPOIB_LEGACY_CHILD) |
66 | return true; |
67 | |
68 | /* |
69 | * First ensure this isn't a duplicate. We check the parent device and |
70 | * then all of the legacy child interfaces to make sure the Pkey |
71 | * doesn't match. |
72 | */ |
73 | if (ppriv->pkey == priv->pkey) |
74 | return false; |
75 | |
76 | list_for_each_entry(tpriv, &ppriv->child_intfs, list) { |
77 | if (tpriv->pkey == priv->pkey && |
78 | tpriv->child_type == IPOIB_LEGACY_CHILD) |
79 | return false; |
80 | } |
81 | |
82 | return true; |
83 | } |
84 | |
85 | /* |
86 | * NOTE: If this function fails then the priv->dev will remain valid, however |
87 | * priv will have been freed and must not be touched by caller in the error |
88 | * case. |
89 | * |
90 | * If (ndev->reg_state == NETREG_UNINITIALIZED) then it is up to the caller to |
91 | * free the net_device (just as rtnl_newlink does) otherwise the net_device |
92 | * will be freed when the rtnl is unlocked. |
93 | */ |
94 | int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, |
95 | u16 pkey, int type) |
96 | { |
97 | struct net_device *ndev = priv->dev; |
98 | int result; |
99 | struct rdma_netdev *rn = netdev_priv(dev: ndev); |
100 | |
101 | ASSERT_RTNL(); |
102 | |
103 | /* |
104 | * We do not need to touch priv if register_netdevice fails, so just |
105 | * always use this flow. |
106 | */ |
107 | ndev->priv_destructor = ipoib_intf_free; |
108 | |
109 | /* |
110 | * Racing with unregister of the parent must be prevented by the |
111 | * caller. |
112 | */ |
113 | WARN_ON(ppriv->dev->reg_state != NETREG_REGISTERED); |
114 | |
115 | if (pkey == 0 || pkey == 0x8000) { |
116 | result = -EINVAL; |
117 | goto out_early; |
118 | } |
119 | |
120 | rn->mtu = priv->mcast_mtu; |
121 | |
122 | priv->parent = ppriv->dev; |
123 | priv->pkey = pkey; |
124 | priv->child_type = type; |
125 | |
126 | if (!is_child_unique(ppriv, priv)) { |
127 | result = -ENOTUNIQ; |
128 | goto out_early; |
129 | } |
130 | |
131 | result = register_netdevice(dev: ndev); |
132 | if (result) { |
133 | ipoib_warn(priv, "failed to initialize; error %i" , result); |
134 | |
135 | /* |
136 | * register_netdevice sometimes calls priv_destructor, |
137 | * sometimes not. Make sure it was done. |
138 | */ |
139 | goto out_early; |
140 | } |
141 | |
142 | /* RTNL childs don't need proprietary sysfs entries */ |
143 | if (type == IPOIB_LEGACY_CHILD) { |
144 | if (ipoib_cm_add_mode_attr(dev: ndev)) |
145 | goto sysfs_failed; |
146 | if (ipoib_add_pkey_attr(dev: ndev)) |
147 | goto sysfs_failed; |
148 | if (ipoib_add_umcast_attr(dev: ndev)) |
149 | goto sysfs_failed; |
150 | |
151 | if (device_create_file(device: &ndev->dev, entry: &dev_attr_parent)) |
152 | goto sysfs_failed; |
153 | } |
154 | |
155 | return 0; |
156 | |
157 | sysfs_failed: |
158 | unregister_netdevice(dev: priv->dev); |
159 | return -ENOMEM; |
160 | |
161 | out_early: |
162 | if (ndev->priv_destructor) |
163 | ndev->priv_destructor(ndev); |
164 | return result; |
165 | } |
166 | |
167 | int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) |
168 | { |
169 | struct ipoib_dev_priv *ppriv, *priv; |
170 | char intf_name[IFNAMSIZ]; |
171 | struct net_device *ndev; |
172 | int result; |
173 | |
174 | if (!capable(CAP_NET_ADMIN)) |
175 | return -EPERM; |
176 | |
177 | if (!rtnl_trylock()) |
178 | return restart_syscall(); |
179 | |
180 | if (pdev->reg_state != NETREG_REGISTERED) { |
181 | rtnl_unlock(); |
182 | return -EPERM; |
183 | } |
184 | |
185 | ppriv = ipoib_priv(dev: pdev); |
186 | |
187 | snprintf(buf: intf_name, size: sizeof(intf_name), fmt: "%s.%04x" , |
188 | ppriv->dev->name, pkey); |
189 | |
190 | ndev = ipoib_intf_alloc(hca: ppriv->ca, port: ppriv->port, format: intf_name); |
191 | if (IS_ERR(ptr: ndev)) { |
192 | result = PTR_ERR(ptr: ndev); |
193 | goto out; |
194 | } |
195 | priv = ipoib_priv(dev: ndev); |
196 | |
197 | ndev->rtnl_link_ops = ipoib_get_link_ops(); |
198 | |
199 | result = __ipoib_vlan_add(ppriv, priv, pkey, type: IPOIB_LEGACY_CHILD); |
200 | |
201 | if (result && ndev->reg_state == NETREG_UNINITIALIZED) |
202 | free_netdev(dev: ndev); |
203 | |
204 | out: |
205 | rtnl_unlock(); |
206 | |
207 | return result; |
208 | } |
209 | |
210 | struct ipoib_vlan_delete_work { |
211 | struct work_struct work; |
212 | struct net_device *dev; |
213 | }; |
214 | |
215 | /* |
216 | * sysfs callbacks of a netdevice cannot obtain the rtnl lock as |
217 | * unregister_netdev ultimately deletes the sysfs files while holding the rtnl |
218 | * lock. This deadlocks the system. |
219 | * |
220 | * A callback can use rtnl_trylock to avoid the deadlock but it cannot call |
221 | * unregister_netdev as that internally takes and releases the rtnl_lock. So |
222 | * instead we find the netdev to unregister and then do the actual unregister |
223 | * from the global work queue where we can obtain the rtnl_lock safely. |
224 | */ |
225 | static void ipoib_vlan_delete_task(struct work_struct *work) |
226 | { |
227 | struct ipoib_vlan_delete_work *pwork = |
228 | container_of(work, struct ipoib_vlan_delete_work, work); |
229 | struct net_device *dev = pwork->dev; |
230 | |
231 | rtnl_lock(); |
232 | |
233 | /* Unregistering tasks can race with another task or parent removal */ |
234 | if (dev->reg_state == NETREG_REGISTERED) { |
235 | struct ipoib_dev_priv *priv = ipoib_priv(dev); |
236 | struct ipoib_dev_priv *ppriv = ipoib_priv(dev: priv->parent); |
237 | |
238 | ipoib_dbg(ppriv, "delete child vlan %s\n" , dev->name); |
239 | unregister_netdevice(dev); |
240 | } |
241 | |
242 | rtnl_unlock(); |
243 | |
244 | kfree(objp: pwork); |
245 | } |
246 | |
247 | int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) |
248 | { |
249 | struct ipoib_dev_priv *ppriv, *priv, *tpriv; |
250 | int rc; |
251 | |
252 | if (!capable(CAP_NET_ADMIN)) |
253 | return -EPERM; |
254 | |
255 | if (!rtnl_trylock()) |
256 | return restart_syscall(); |
257 | |
258 | if (pdev->reg_state != NETREG_REGISTERED) { |
259 | rtnl_unlock(); |
260 | return -EPERM; |
261 | } |
262 | |
263 | ppriv = ipoib_priv(dev: pdev); |
264 | |
265 | rc = -ENODEV; |
266 | list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { |
267 | if (priv->pkey == pkey && |
268 | priv->child_type == IPOIB_LEGACY_CHILD) { |
269 | struct ipoib_vlan_delete_work *work; |
270 | |
271 | work = kmalloc(size: sizeof(*work), GFP_KERNEL); |
272 | if (!work) { |
273 | rc = -ENOMEM; |
274 | goto out; |
275 | } |
276 | |
277 | down_write(sem: &ppriv->vlan_rwsem); |
278 | list_del_init(entry: &priv->list); |
279 | up_write(sem: &ppriv->vlan_rwsem); |
280 | work->dev = priv->dev; |
281 | INIT_WORK(&work->work, ipoib_vlan_delete_task); |
282 | queue_work(wq: ipoib_workqueue, work: &work->work); |
283 | |
284 | rc = 0; |
285 | break; |
286 | } |
287 | } |
288 | |
289 | out: |
290 | rtnl_unlock(); |
291 | |
292 | return rc; |
293 | } |
294 | |