[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1514718983-466-3-git-send-email-denisd@mellanox.com>
Date: Sun, 31 Dec 2017 13:16:23 +0200
From: Denis Drozdov <denisd@...lanox.com>
To: davem@...emloft.net
Cc: jgg@...pe.ca, dledford@...hat.com, leonro@...lanox.com,
linux-rdma@...r.kernel.org, netdev@...r.kernel.org,
Denis Drozdov <denisd@...lanox.com>
Subject: [PATCH net 2/2] IB/ipoib: Fix netlink support in IPoIB
IPoIB netlink support was broken by commit cd565b4b51e5
("IB/IPoIB: Support acceleration options callbacks"),
that added flow which allocates netdev rdma structures
after netlink object is already created. Such situation leads
to crash in __ipoib_device_add, once trying to reuse netlink
device.
This commit restores the netlink support.
Fixes: cd565b4b51e5 ("IB/IPoIB: Support acceleration options callbacks")
Reviewed-by: Erez Shitrit <erezsh@...lanox.com>
Reviewed-by: Leon Romanovsky <leonro@...lanox.com>
Reviewed-by: Saeed Mahameed <saeedm@...lanox.com>
Signed-off-by: Denis Drozdov <denisd@...lanox.com>
---
drivers/infiniband/ulp/ipoib/ipoib.h | 2 ++
drivers/infiniband/ulp/ipoib/ipoib_main.c | 23 +++++++++--------
drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 38 +++++++++++++++++++++++++---
drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 20 ++++-----------
4 files changed, 54 insertions(+), 29 deletions(-)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 8033a00..aa7a02f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -607,6 +607,8 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
void ipoib_set_ethtool_ops(struct net_device *dev);
void ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca);
+void ipoib_free_rdma_netdev(struct net_device *dev);
+
#define IPOIB_FLAGS_RC 0x80
#define IPOIB_FLAGS_UC 0x40
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 71a66a7..63c9584 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -2041,6 +2041,14 @@ struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port,
return NULL;
}
+void ipoib_free_rdma_netdev(struct net_device *dev)
+{
+ struct rdma_netdev *rn = netdev_priv(dev);
+
+ rn->free_rdma_netdev(dev);
+ kfree(ipoib_priv(dev));
+}
+
static ssize_t show_pkey(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2222,7 +2230,6 @@ static struct net_device *ipoib_add_port(const char *format,
{
struct ipoib_dev_priv *priv;
struct ib_port_attr attr;
- struct rdma_netdev *rn;
int result = -ENOMEM;
priv = ipoib_intf_alloc(hca, port, format);
@@ -2322,9 +2329,7 @@ static struct net_device *ipoib_add_port(const char *format,
ipoib_dev_cleanup(priv->dev);
device_init_failed:
- rn = netdev_priv(priv->dev);
- rn->free_rdma_netdev(priv->dev);
- kfree(priv);
+ ipoib_free_rdma_netdev(priv->dev);
alloc_mem_failed:
return ERR_PTR(result);
@@ -2397,13 +2402,9 @@ static void ipoib_remove_one(struct ib_device *device, void *client_data)
parent_rn->free_rdma_netdev(priv->dev);
- list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
- struct rdma_netdev *child_rn;
-
- child_rn = netdev_priv(cpriv->dev);
- child_rn->free_rdma_netdev(cpriv->dev);
- kfree(cpriv);
- }
+ list_for_each_entry_safe(cpriv, tcpriv,
+ &priv->child_intfs, list)
+ ipoib_free_rdma_netdev(cpriv->dev);
kfree(priv);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
index 3e44087..1fff706 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
@@ -93,12 +93,38 @@ static int ipoib_changelink(struct net_device *dev, struct nlattr *tb[],
return ret;
}
+static struct net_device *ipoib_alloc_link(struct net *src_net,
+ const char *dev_name,
+ struct nlattr *tb[])
+{
+ struct net_device *pdev;
+ struct ipoib_dev_priv *ppriv, *priv;
+
+ if (!tb[IFLA_LINK])
+ return ERR_PTR(-EINVAL);
+
+ ASSERT_RTNL();
+ pdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
+ if (!pdev || pdev->type != ARPHRD_INFINIBAND)
+ return ERR_PTR(-ENODEV);
+
+ ppriv = ipoib_priv(pdev);
+
+ priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, dev_name);
+ if (!priv) {
+ ipoib_warn(ppriv, "failed to allocate pkey device\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return priv->dev;
+}
+
static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[],
struct netlink_ext_ack *extack)
{
struct net_device *pdev;
- struct ipoib_dev_priv *ppriv;
+ struct ipoib_dev_priv *ppriv, *priv;
u16 child_pkey;
int err;
@@ -131,11 +157,15 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
*/
child_pkey |= 0x8000;
- err = __ipoib_vlan_add(ppriv, ipoib_priv(dev),
- child_pkey, IPOIB_RTNL_CHILD);
+ down_write(&ppriv->vlan_rwsem);
+
+ priv = ipoib_priv(dev);
+ err = __ipoib_vlan_add(ppriv, priv, child_pkey, IPOIB_RTNL_CHILD);
+ up_write(&ppriv->vlan_rwsem);
if (!err && data)
err = ipoib_changelink(dev, tb, data, extack);
+
return err;
}
@@ -170,6 +200,8 @@ static size_t ipoib_get_size(const struct net_device *dev)
.dellink = ipoib_unregister_child_dev,
.get_size = ipoib_get_size,
.fill_info = ipoib_fill_info,
+ .alloc_link = ipoib_alloc_link,
+ .free_link = ipoib_free_rdma_netdev
};
int __init ipoib_netlink_init(void)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 55a9b71..3ebf6de 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -162,29 +162,23 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
result = -ENOTUNIQ;
goto out;
}
-
list_for_each_entry(tpriv, &ppriv->child_intfs, list) {
if (tpriv->pkey == pkey &&
- tpriv->child_type == IPOIB_LEGACY_CHILD) {
+ (tpriv->child_type == IPOIB_LEGACY_CHILD ||
+ tpriv->child_type == IPOIB_RTNL_CHILD)) {
result = -ENOTUNIQ;
goto out;
}
}
result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
-
out:
up_write(&ppriv->vlan_rwsem);
rtnl_unlock();
mutex_unlock(&ppriv->sysfs_mutex);
- if (result && priv) {
- struct rdma_netdev *rn;
-
- rn = netdev_priv(priv->dev);
- rn->free_rdma_netdev(priv->dev);
- kfree(priv);
- }
+ if (result && priv)
+ ipoib_free_rdma_netdev(priv->dev);
return result;
}
@@ -235,11 +229,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
mutex_unlock(&ppriv->sysfs_mutex);
if (dev) {
- struct rdma_netdev *rn;
-
- rn = netdev_priv(dev);
- rn->free_rdma_netdev(priv->dev);
- kfree(priv);
+ ipoib_free_rdma_netdev(dev);
return 0;
}
--
1.8.3.1
Powered by blists - more mailing lists