[PATCH rdma-next 4/7] RDMA/core: Introduce a helper function to change net namespace of rdma device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Parav Pandit <parav@xxxxxxxxxxxx>

Introduce a helper function that changes rdma device's net namespace
which performs mini unregistration and registration sequence to have
device visible only in assigned namespace.

Currently changing device net namespace is supported for those devices
which support disassociating a device from the user space application.
Without which application might have valid reference attached to it.

Also if the device has its own port specific sysfs files, changing net
namespace is unsupported. Once the port_uninit callback is implemented
in near future, this limitation will be removed as well.

Also modify ib_unregister_device() to sync with namespace change
routine, so that both cannot work on a device at the same time.

Signed-off-by: Parav Pandit <parav@xxxxxxxxxxxx>
Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx>
---
 drivers/infiniband/core/core_priv.h |   2 +
 drivers/infiniband/core/device.c    | 106 +++++++++++++++++++++++++---
 include/rdma/ib_verbs.h             |   2 +
 3 files changed, 102 insertions(+), 8 deletions(-)

diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index 7dc6f814f387..ae4d65359fa7 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -360,4 +360,6 @@ int ib_setup_port_attrs(struct ib_core_device *coredev,
 
 void ib_device_cache_update(struct ib_device *device);
 void ib_gid_table_cleanup_one(struct ib_device *device);
+
+int ib_dev_change_net_ns(struct ib_device *device, struct net *net);
 #endif /* _CORE_PRIV_H */
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 3ccab52ab243..3758426c8717 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -150,8 +150,7 @@ static int ib_device_check_mandatory(struct ib_device *device)
 bool rdma_dev_access_netns(const struct ib_device *device,
 			   const struct net *net)
 {
-	return (device->netns_shared ||
-		net_eq(rdma_coredev_net(&device->coredev), net));
+	return (device->netns_shared || net_eq(rdma_dev_net(device), net));
 }
 EXPORT_SYMBOL(rdma_dev_access_netns);
 
@@ -227,7 +226,13 @@ int ib_device_rename(struct ib_device *ibdev, const char *name)
 			goto out;
 		}
 	}
-
+	/* If device got unregistered while changing net namespace,
+	 * avoid renaming such device.
+	 */
+	if (ibdev->reg_state != IB_DEV_REGISTERED) {
+		ret = -ENODEV;
+		goto out;
+	}
 	ret = device_rename(&ibdev->dev, name);
 	if (ret)
 		goto out;
@@ -762,11 +767,12 @@ void ib_unregister_device(struct ib_device *device)
 
 	mutex_lock(&ib_device_mutex);
 
-	unregister_remove_clients(device);
-
-	rdma_compatdev_remove(device);
-	ib_device_unregister_sysfs(device);
-	ib_device_unregister_rdmacg(device);
+	if (device->reg_state == IB_DEV_REGISTERED) {
+		unregister_remove_clients(device);
+		rdma_compatdev_remove(device);
+		ib_device_unregister_sysfs(device);
+		ib_device_unregister_rdmacg(device);
+	}
 
 	mutex_unlock(&ib_device_mutex);
 
@@ -781,6 +787,90 @@ void ib_unregister_device(struct ib_device *device)
 }
 EXPORT_SYMBOL(ib_unregister_device);
 
+static int _ib_dev_change_net_ns(struct ib_device *device, struct net *net)
+{
+	int ret = -EINVAL;
+
+	if (net_eq(rdma_dev_net(device), net))
+		return 0;
+
+	/*
+	 * Currently supported only for those providers which supports
+	 * disassociation and those which doesn't do port specific sysfs
+	 * init. Once a port_cleanup infrastructure is implemented, this
+	 * limitation will be removed.
+	 */
+	if (!device->ops.disassociate_ucontext || device->ops.port_init)
+		return -EOPNOTSUPP;
+
+	unregister_remove_clients(device);
+	rdma_compatdev_remove(device);
+	ib_device_unregister_rdmacg(device);
+
+	ib_gid_table_cleanup_one(device);
+	free_client_contexts(device);
+	device->reg_state = IB_DEV_UNREGISTERED;
+
+	device->netns_shared = 0;
+	rdma_coredev_net_set(&device->coredev, net);
+
+	rdma_roce_rescan_device(device);
+	ib_device_cache_update(device);
+
+	ret = ib_device_register_rdmacg(device);
+	if (ret) {
+		dev_warn(&device->dev,
+			 "Couldn't register device with rdma cgroup\n");
+		goto out;
+	}
+
+	/* Rename sysfs tree in new namespace */
+	ret = device_rename(&device->dev, device->name);
+	if (ret) {
+		dev_warn(&device->dev, "Couldn't rename device\n");
+		goto cg_cleanup;
+	}
+	device->reg_state = IB_DEV_REGISTERED;
+
+	register_add_clients(device);
+	return 0;
+
+cg_cleanup:
+	ib_device_unregister_rdmacg(device);
+out:
+	return ret;
+}
+
+int ib_dev_change_net_ns(struct ib_device *device, struct net *net)
+{
+	int ret;
+
+	mutex_lock(&ib_device_mutex);
+	/* Perform unregistration, registration sequence under a lock.
+	 * This ensures that such rdma device doesn't get removed or renamed
+	 * while it is moving to different net namespace.
+	 */
+	ret = _ib_dev_change_net_ns(device, net);
+	mutex_unlock(&ib_device_mutex);
+	return ret;
+}
+
+/**
+ * rdma_dev_net - Return net namespace of the ib device
+ * @dev:	Pointer to ib_device whose net namespace to read
+ * rdma_dev_net() returns the net namespace of the rdma device.
+ * This API is usable only to those ULPs which register with the core using
+ * using ib_register_client() API. This ensures that ib_clients have access
+ * to stable net namespace of rdma device without a complex locking scheme.
+ * This API should not be used by the provider drivers, as provider drivers
+ * are not yet made aware of the rdma device's net namespace movement changes.
+ */
+struct net *rdma_dev_net(const struct ib_device *dev)
+{
+	return rdma_coredev_net(&dev->coredev);
+}
+EXPORT_SYMBOL(rdma_dev_net);
+
 /**
  * ib_register_client - Register an IB client
  * @client:Client to register
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 934f7031dd2f..ce6784710ad5 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -4274,4 +4274,6 @@ static inline struct ib_device *rdma_device_to_ibdev(struct device *device)
 
 bool rdma_dev_access_netns(const struct ib_device *device,
 			   const struct net *net);
+
+struct net *rdma_dev_net(const struct ib_device *dev);
 #endif /* IB_VERBS_H */
-- 
2.19.1




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux