diff mbox

[for-next,02/10] IB/mlx5: Support IB device's callback for getting its netdev

Message ID 561A64E9.1070906@mellanox.com (mailing list archive)
State Accepted
Headers show

Commit Message

Matan Barak Oct. 11, 2015, 1:32 p.m. UTC
On 8/20/2015 7:46 PM, Achiad Shochat wrote:
> For Eth ports only.
> Maintain a net device pointer in mlx5_ib_device and update it
> upon NETDEV_REGISTER and NETDEV_UNREGISTER events if the
> net-device and IB device have the same PCI parent device.
> Implement the get_netdev callback to return this net device.
>
> Signed-off-by: Achiad Shochat <achiad@mellanox.com>
> ---
>   drivers/infiniband/hw/mlx5/main.c    | 64 +++++++++++++++++++++++++++++++++++-
>   drivers/infiniband/hw/mlx5/mlx5_ib.h | 10 ++++++
>   2 files changed, 73 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
> index 8540e00..5a176d7 100644
> --- a/drivers/infiniband/hw/mlx5/main.c
> +++ b/drivers/infiniband/hw/mlx5/main.c
> @@ -85,6 +85,41 @@ mlx5_ib_port_link_layer(struct ib_device *device, u8 port_num)
>   	return mlx5_port_type_cap_to_rdma_ll(port_type_cap);
>   }
>
> +static int mlx5_netdev_event(struct notifier_block *this,
> +			     unsigned long event, void *ptr)
> +{
> +	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
> +	struct mlx5_ib_dev *ibdev = container_of(this, struct mlx5_ib_dev,
> +						 roce.nb);
> +
> +	if ((event != NETDEV_UNREGISTER) && (event != NETDEV_REGISTER))
> +		return NOTIFY_DONE;
> +
> +	write_lock(&ibdev->roce.netdev_lock);
> +	if (ndev->dev.parent == &ibdev->mdev->pdev->dev)
> +		ibdev->roce.netdev = (event == NETDEV_UNREGISTER) ? NULL : ndev;
> +	write_unlock(&ibdev->roce.netdev_lock);
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct net_device *mlx5_ib_get_netdev(struct ib_device *device,
> +					     u8 port_num)
> +{
> +	struct mlx5_ib_dev *ibdev = to_mdev(device);
> +	struct net_device *ndev;
> +
> +	/* Ensure ndev does not disappear before we invoke dev_hold()
> +	 */
> +	read_lock(&ibdev->roce.netdev_lock);
> +	ndev = ibdev->roce.netdev;
> +	if (ndev)
> +		dev_hold(ndev);
> +	read_unlock(&ibdev->roce.netdev_lock);
> +
> +	return ndev;
> +}
> +
>   static int mlx5_use_mad_ifc(struct mlx5_ib_dev *dev)
>   {
>   	return !dev->mdev->issi;
> @@ -1398,6 +1433,18 @@ static int mlx5_port_immutable(struct ib_device *ibdev, u8 port_num,
>   	return 0;
>   }
>
> +static int mlx5_enable_roce(struct mlx5_ib_dev *dev)
> +{
> +	rwlock_init(&dev->roce.netdev_lock);
> +	dev->roce.nb.notifier_call = mlx5_netdev_event;
> +	return register_netdevice_notifier(&dev->roce.nb);
> +}
> +
> +static void mlx5_disable_roce(struct mlx5_ib_dev *dev)
> +{
> +	unregister_netdevice_notifier(&dev->roce.nb);
> +}
> +
>   static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
>   {
>   	struct mlx5_ib_dev *dev;
> @@ -1471,6 +1518,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
>   	dev->ib_dev.query_device	= mlx5_ib_query_device;
>   	dev->ib_dev.query_port		= mlx5_ib_query_port;
>   	dev->ib_dev.get_link_layer	= mlx5_ib_port_link_layer;
> +	if (ll == IB_LINK_LAYER_ETHERNET)
> +		dev->ib_dev.get_netdev	= mlx5_ib_get_netdev;
>   	dev->ib_dev.query_gid		= mlx5_ib_query_gid;
>   	dev->ib_dev.query_pkey		= mlx5_ib_query_pkey;
>   	dev->ib_dev.modify_device	= mlx5_ib_modify_device;
> @@ -1530,9 +1579,15 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
>
>   	mutex_init(&dev->cap_mask_mutex);
>
> +	if (ll == IB_LINK_LAYER_ETHERNET) {
> +		err = mlx5_enable_roce(dev);
> +		if (err)
> +			goto err_dealloc;
> +	}
> +
>   	err = create_dev_resources(&dev->devr);
>   	if (err)
> -		goto err_dealloc;
> +		goto err_disable_roce;
>
>   	err = mlx5_ib_odp_init_one(dev);
>   	if (err)
> @@ -1569,6 +1624,10 @@ err_odp:
>   err_rsrc:
>   	destroy_dev_resources(&dev->devr);
>
> +err_disable_roce:
> +	if (ll == IB_LINK_LAYER_ETHERNET)
> +		mlx5_disable_roce(dev);
> +
>   err_dealloc:
>   	ib_dealloc_device((struct ib_device *)dev);
>
> @@ -1578,11 +1637,14 @@ err_dealloc:
>   static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context)
>   {
>   	struct mlx5_ib_dev *dev = context;
> +	enum rdma_link_layer ll = mlx5_ib_port_link_layer(&dev->ib_dev, 1);
>
>   	ib_unregister_device(&dev->ib_dev);
>   	destroy_umrc_res(dev);
>   	mlx5_ib_odp_remove_one(dev);
>   	destroy_dev_resources(&dev->devr);
> +	if (ll == IB_LINK_LAYER_ETHERNET)
> +		mlx5_disable_roce(dev);
>   	ib_dealloc_device(&dev->ib_dev);
>   }
>
> diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
> index 7cae098..81df6d4 100644
> --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
> +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
> @@ -418,9 +418,19 @@ struct mlx5_ib_resources {
>   	struct ib_srq	*s1;
>   };
>
> +struct mlx5_roce {
> +	/* Protect mlx5_ib_get_netdev from invoking dev_hold() with a NULL
> +	 * netdev pointer
> +	 */
> +	rwlock_t		netdev_lock;
> +	struct net_device	*netdev;
> +	struct notifier_block	nb;
> +};
> +
>   struct mlx5_ib_dev {
>   	struct ib_device		ib_dev;
>   	struct mlx5_core_dev		*mdev;
> +	struct mlx5_roce		roce;
>   	MLX5_DECLARE_DOORBELL_LOCK(uar_lock);
>   	int				num_ports;
>   	/* serialize update of capability mask
>

Hi,

We've found a bug in this patch - the rwlock is used before it's 
initialized. Here is a quick fix to this patch. If you prefer, we could
re-spin this series.

 From f6a851452016dcb5a4513bf195857c4e4ec4969a Mon Sep 17 00:00:00 2001
From: Achiad Shochat <achiad@mellanox.com>
Date: Thu, 17 Sep 2015 13:01:47 +0300
Subject: [PATCH for-next] IB/mlx5: Avoid using un-initialized rwlock

Upon IB device creation, we try to acquire the rwlock protecting net
device before it was initialized.

The flow is:
mlx5_ib_add()->get_port_caps()->mlx5_ib_query_port()->
mlx5_query_port_roce()->mlx5_ib_get_netdev()

So we moved the rwlock initialization to be before invoking
get_port_caps().

Fixes: 6583d240c73d ('IB/mlx5: Support IB device's callback for getting
	its netdev')
Signed-off-by: Achiad Shochat <achiad@mellanox.com>
---
  drivers/infiniband/hw/mlx5/main.c | 16 ++++++++--------
  1 file changed, 8 insertions(+), 8 deletions(-)
diff mbox

Patch

diff --git a/drivers/infiniband/hw/mlx5/main.c 
b/drivers/infiniband/hw/mlx5/main.c
index e8d2d01..8ad647e 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -1611,9 +1611,15 @@  static void *mlx5_ib_add(struct mlx5_core_dev *mdev)

  	dev->mdev = mdev;

+	if (ll == IB_LINK_LAYER_ETHERNET) {
+		err = mlx5_enable_roce(dev);
+		if (err)
+			goto err_dealloc;
+	}
+
  	err = get_port_caps(dev);
  	if (err)
-		goto err_dealloc;
+		goto err_disable_roce;

  	if (mlx5_use_mad_ifc(dev))
  		get_ext_port_caps(dev);
@@ -1718,16 +1724,10 @@  static void *mlx5_ib_add(struct mlx5_core_dev *mdev)

  	err = init_node_data(dev);
  	if (err)
-		goto err_dealloc;
+		goto err_disable_roce;

  	mutex_init(&dev->cap_mask_mutex);

-	if (ll == IB_LINK_LAYER_ETHERNET) {
-		err = mlx5_enable_roce(dev);
-		if (err)
-			goto err_dealloc;
-	}
-
  	err = create_dev_resources(&dev->devr);
  	if (err)
  		goto err_disable_roce;