IB/ipoib: Add rtnl_link_ops support
Add rtnl_link_ops to IPoIB, with the first usage being child device
create/delete through them. Childs devices are now either legacy ones,
created/deleted through the ipoib sysfs entries, or RTNL ones.
Adding support for RTNL childs involved refactoring of ipoib_vlan_add
which is now used by both the sysfs and the link_ops code.
Also, added ndo_uninit entry to support calling unregister_netdevice_queue
from the rtnl dellink entry. This required removal of calls to
ipoib_dev_cleanup from the driver in flows which use unregister_netdevice,
since the networking core will invoke ipoib_uninit which does exactly that.
Signed-off-by: Erez Shitrit <erezsh@mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index d7e9740..238bbf9 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -49,47 +49,11 @@
}
static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
-int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
+int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
+ u16 pkey, int type)
{
- struct ipoib_dev_priv *ppriv, *priv;
- char intf_name[IFNAMSIZ];
int result;
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- ppriv = netdev_priv(pdev);
-
- if (!rtnl_trylock())
- return restart_syscall();
- mutex_lock(&ppriv->vlan_mutex);
-
- /*
- * First ensure this isn't a duplicate. We check the parent device and
- * then all of the child interfaces to make sure the Pkey doesn't match.
- */
- if (ppriv->pkey == pkey) {
- result = -ENOTUNIQ;
- priv = NULL;
- goto err;
- }
-
- list_for_each_entry(priv, &ppriv->child_intfs, list) {
- if (priv->pkey == pkey) {
- result = -ENOTUNIQ;
- priv = NULL;
- goto err;
- }
- }
-
- snprintf(intf_name, sizeof intf_name, "%s.%04x",
- ppriv->dev->name, pkey);
- priv = ipoib_intf_alloc(intf_name);
- if (!priv) {
- result = -ENOMEM;
- goto err;
- }
-
priv->max_ib_mtu = ppriv->max_ib_mtu;
/* MTU will be reset when mcast join happens */
priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu);
@@ -134,14 +98,13 @@
if (device_create_file(&priv->dev->dev, &dev_attr_parent))
goto sysfs_failed;
+ priv->child_type = type;
list_add_tail(&priv->list, &ppriv->child_intfs);
- mutex_unlock(&ppriv->vlan_mutex);
- rtnl_unlock();
-
return 0;
sysfs_failed:
+ result = -ENOMEM;
ipoib_delete_debug_files(priv->dev);
unregister_netdevice(priv->dev);
@@ -149,11 +112,60 @@
ipoib_dev_cleanup(priv->dev);
err:
+ return result;
+}
+
+int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
+{
+ struct ipoib_dev_priv *ppriv, *priv;
+ char intf_name[IFNAMSIZ];
+ struct ipoib_dev_priv *tpriv;
+ int result;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ ppriv = netdev_priv(pdev);
+
+ snprintf(intf_name, sizeof intf_name, "%s.%04x",
+ ppriv->dev->name, pkey);
+ priv = ipoib_intf_alloc(intf_name);
+ if (!priv)
+ return -ENOMEM;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ mutex_lock(&ppriv->vlan_mutex);
+
+ /*
+ * First ensure this isn't a duplicate. We check the parent device and
+ * then all of the legacy child interfaces to make sure the Pkey
+ * doesn't match.
+ */
+ if (ppriv->pkey == pkey) {
+ result = -ENOTUNIQ;
+ goto out;
+ }
+
+ list_for_each_entry(tpriv, &ppriv->child_intfs, list) {
+ if (tpriv->pkey == pkey &&
+ tpriv->child_type == IPOIB_LEGACY_CHILD) {
+ result = -ENOTUNIQ;
+ goto out;
+ }
+ }
+
+ result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
+
+out:
mutex_unlock(&ppriv->vlan_mutex);
- rtnl_unlock();
- if (priv)
+
+ if (result)
free_netdev(priv->dev);
+ rtnl_unlock();
+
return result;
}
@@ -171,9 +183,9 @@
return restart_syscall();
mutex_lock(&ppriv->vlan_mutex);
list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
- if (priv->pkey == pkey) {
+ if (priv->pkey == pkey &&
+ priv->child_type == IPOIB_LEGACY_CHILD) {
unregister_netdevice(priv->dev);
- ipoib_dev_cleanup(priv->dev);
list_del(&priv->list);
dev = priv->dev;
break;