From: Leon Romanovsky <leon@kernel.org> Date: 2021-04-05 05:50:08
From: Leon Romanovsky <leonro@nvidia.com>
Hi,
This series adds new callback to check if ib client is supported/not_supported.
Such general callback allows us to save memory footprint by not starting
on devices that not going to work on them anyway.
Thanks
Parav Pandit (8):
RDMA/core: Check if client supports IB device or not
RDMA/cma: Skip device which doesn't support CM
IB/cm: Skip device which doesn't support IB CM
IB/core: Skip device which doesn't have necessary capabilities
IB/IPoIB: Skip device which doesn't have InfiniBand port
IB/opa_vnic: Move to client_supported callback
net/smc: Move to client_supported callback
net/rds: Move to client_supported callback
drivers/infiniband/core/cm.c | 15 +++++++++++++-
drivers/infiniband/core/cma.c | 15 +++++++++++++-
drivers/infiniband/core/device.c | 3 +++
drivers/infiniband/core/multicast.c | 15 +++++++++++++-
drivers/infiniband/core/sa_query.c | 15 +++++++++++++-
drivers/infiniband/ulp/ipoib/ipoib_main.c | 13 ++++++++++++
.../infiniband/ulp/opa_vnic/opa_vnic_vema.c | 4 +---
include/rdma/ib_verbs.h | 9 +++++++++
net/rds/ib.c | 20 ++++++++++++-------
net/smc/smc_ib.c | 9 ++++++---
10 files changed, 101 insertions(+), 17 deletions(-)
--
2.30.2
From: Leon Romanovsky <leon@kernel.org> Date: 2021-04-05 05:50:11
From: Parav Pandit <redacted>
A switchdev RDMA device do not support IB CM. When such device is added
to the RDMA CM's device list, when application invokes rdma_listen(),
cma attempts to listen to such device, however it has IB CM attribute
disabled.
Due to this, rdma_listen() call fails to listen for other non
switchdev devices as well.
A below error message can be seen.
infiniband mlx5_0: RDMA CMA: cma_listen_on_dev, error -38
A failing call flow is below.
rdma_listen()
cma_listen_on_all()
cma_listen_on_dev()
_cma_attach_to_dev()
rdma_listen() <- fails on a specific switchdev device
Hence, when a IB device doesn't support IB CM or IW CM, avoid adding
such device to the cma list.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
drivers/infiniband/core/cma.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
From: Leon Romanovsky <leon@kernel.org> Date: 2021-04-05 05:50:16
From: Parav Pandit <redacted>
There are at least 3 types of RDMA devices which do not support IB CM.
They are
(1) A (eswitch) switchdev RDMA device,
(2) iWARP device and
(3) RDMA device without a RoCE capability
Hence, avoid IB CM initialization for such devices.
This saves 8Kbytes of memory for eswitch device consist of 512 ports and
also avoids unnecessary initialization for all above 3 types of devices.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
drivers/infiniband/core/cm.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
From: Leon Romanovsky <leon@kernel.org> Date: 2021-04-05 05:50:18
From: Parav Pandit <redacted>
RDMA devices are of different transport(iWarp, IB, RoCE) and have
different attributes.
Not all clients are interested in all type of devices.
Implement a generic callback that each IB client can implement to decide
if client add() or remove() should be done by the IB core or not for a
given IB device, client combination.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
drivers/infiniband/core/device.c | 3 +++
include/rdma/ib_verbs.h | 9 +++++++++
2 files changed, 12 insertions(+)
From: Leon Romanovsky <leon@kernel.org> Date: 2021-04-05 05:50:37
From: Parav Pandit <redacted>
If device doesn't have multicast capability, avoid client registration
for it. This saves 16Kbytes of memory for a RDMA device consist of 128
ports.
If device doesn't support subnet administration, avoid client
registration for it. This saves 8Kbytes of memory for a RDMA device
consist of 128 ports.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
drivers/infiniband/core/multicast.c | 15 ++++++++++++++-
drivers/infiniband/core/sa_query.c | 15 ++++++++++++++-
2 files changed, 28 insertions(+), 2 deletions(-)
From: Leon Romanovsky <leon@kernel.org> Date: 2021-04-05 05:50:41
From: Parav Pandit <redacted>
Use newly introduced client_supported() callback to avoid client
additional if the RDMA device is not of IB type or if it doesn't
support device memory extensions.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
net/rds/ib.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
@@ -125,18 +125,23 @@ void rds_ib_dev_put(struct rds_ib_device *rds_ibdev)queue_work(rds_wq,&rds_ibdev->free_work);}-staticintrds_ib_add_one(structib_device*device)+staticboolrds_client_supported(structib_device*device){-structrds_ib_device*rds_ibdev;-intret;-/* Only handle IB (no iWARP) devices */if(device->node_type!=RDMA_NODE_IB_CA)-return-EOPNOTSUPP;+returnfalse;/* Device must support FRWR */if(!(device->attrs.device_cap_flags&IB_DEVICE_MEM_MGT_EXTENSIONS))-return-EOPNOTSUPP;+returnfalse;++returntrue;+}++staticintrds_ib_add_one(structib_device*device)+{+structrds_ib_device*rds_ibdev;+intret;rds_ibdev=kzalloc_node(sizeof(structrds_ib_device),GFP_KERNEL,ibdev_to_node(device));
From: Gal Pressman <hidden> Date: 2021-04-05 06:21:20
On 05/04/2021 8:49, Leon Romanovsky wrote:
quoted hunk
From: Parav Pandit <redacted>
RDMA devices are of different transport(iWarp, IB, RoCE) and have
different attributes.
Not all clients are interested in all type of devices.
Implement a generic callback that each IB client can implement to decide
if client add() or remove() should be done by the IB core or not for a
given IB device, client combination.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
drivers/infiniband/core/device.c | 3 +++
include/rdma/ib_verbs.h | 9 +++++++++
2 files changed, 12 insertions(+)
From: Leon Romanovsky <leon@kernel.org> Date: 2021-04-05 08:47:00
On Mon, Apr 05, 2021 at 09:20:32AM +0300, Gal Pressman wrote:
On 05/04/2021 8:49, Leon Romanovsky wrote:
quoted
From: Parav Pandit <redacted>
RDMA devices are of different transport(iWarp, IB, RoCE) and have
different attributes.
Not all clients are interested in all type of devices.
Implement a generic callback that each IB client can implement to decide
if client add() or remove() should be done by the IB core or not for a
given IB device, client combination.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
drivers/infiniband/core/device.c | 3 +++
include/rdma/ib_verbs.h | 9 +++++++++
2 files changed, 12 insertions(+)
@@ -691,6 +691,9 @@ static int add_client_context(struct ib_device *device,if(!device->kverbs_provider&&!client->no_kverbs_req)return0;+if(client->is_supported&&!client->is_supported(device))+return0;
Isn't it better to remove the kverbs_provider flag (from previous if statement)
and unify it with this generic support check?
I thought about it, but didn't find it worth. The kverbs_provider needs
to be provided by device and all ULPs except uverbs will have the same check.
Thanks
On Apr 4, 2021, at 10:50 PM, Leon Romanovsky [off-list ref] wrote:
From: Parav Pandit <redacted>
Use newly introduced client_supported() callback to avoid client
additional if the RDMA device is not of IB type or if it doesn't
support device memory extensions.
Signed-off-by: Parav Pandit <redacted>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
---
net/rds/ib.c | 20 +++++++++++++———
Looks fine by me.
Acked-by: Santosh Shilimkar <redacted>
This is already done though:
for (i = 0; i <= e - s; ++i) {
spin_lock_init(&sa_dev->port[i].ah_lock);
if (!rdma_cap_ib_sa(device, i + 1))
continue;
[..]
if (!count) {
ret = -EOPNOTSUPP;
goto free;
Why does it need to be duplicated? The other patches are all basically
like that too.
The add_one function should return -EOPNOTSUPP if it doesn't want to
run on this device and any supported checks should just be at the
front - this is how things work right now
Jason
It is but, ib_sa_device() allocates ib_sa_device worth of struct for each port without checking the rdma_cap_ib_sa().
This results into allocating 40 * 512 = 20480 rounded of to power of 2 to 32K bytes of memory for the rdma device with 512 ports.
Other modules are also similarly wasting such memory.
for (i = 0; i <= e - s; ++i) {
spin_lock_init(&sa_dev->port[i].ah_lock);
if (!rdma_cap_ib_sa(device, i + 1))
continue;
[..]
if (!count) {
ret = -EOPNOTSUPP;
goto free;
Why does it need to be duplicated? The other patches are all basically like
that too.
The add_one function should return -EOPNOTSUPP if it doesn't want to run
on this device and any supported checks should just be at the front - this is
how things work right now
I am ok to fold this check at the beginning of add callback.
When 512 to 1K RoCE devices are used, they do not have SA, CM, CMA etc caps on and all the client needs to go through refcnt + xa + sem and unroll them.
Is_supported() routine helps to cut down all of it. I didn't calculate the usec saved with it.
Please let me know.
It is but, ib_sa_device() allocates ib_sa_device worth of struct for
each port without checking the rdma_cap_ib_sa(). This results into
allocating 40 * 512 = 20480 rounded of to power of 2 to 32K bytes of
memory for the rdma device with 512 ports. Other modules are also
similarly wasting such memory.
If it returns EOPNOTUPP then the remove is never called so if it
allocated memory and left it allocated then it is leaking memory.
If you are saying 32k bytes of temporary allocation matters during
device startup then it needs benchmarks and a use case.
quoted
The add_one function should return -EOPNOTSUPP if it doesn't want to run
on this device and any supported checks should just be at the front - this is
how things work right now
I am ok to fold this check at the beginning of add callback. When
512 to 1K RoCE devices are used, they do not have SA, CM, CMA etc
caps on and all the client needs to go through refcnt + xa + sem and
unroll them. Is_supported() routine helps to cut down all of it. I
didn't calculate the usec saved with it.
If that is the reason then explain in the cover letter and provide
benchmarks
Jason
It is but, ib_sa_device() allocates ib_sa_device worth of struct for
each port without checking the rdma_cap_ib_sa(). This results into
allocating 40 * 512 = 20480 rounded of to power of 2 to 32K bytes of
memory for the rdma device with 512 ports. Other modules are also
similarly wasting such memory.
If it returns EOPNOTUPP then the remove is never called so if it allocated
memory and left it allocated then it is leaking memory.
I probably confused you. There is no leak today because add_one allocates memory, and later on when SA/CM etc per port cap is not present, it is unused left there which is freed on remove_one().
Returning EOPNOTUPP is fine at start of add_one() before allocation.
If you are saying 32k bytes of temporary allocation matters during device
startup then it needs benchmarks and a use case.
Use case is clear and explained in commit logs, i.e. to not allocate the memory which is never used.
quoted
quoted
The add_one function should return -EOPNOTSUPP if it doesn't want to
run on this device and any supported checks should just be at the
front - this is how things work right now
quoted
I am ok to fold this check at the beginning of add callback. When
512 to 1K RoCE devices are used, they do not have SA, CM, CMA etc caps
on and all the client needs to go through refcnt + xa + sem and unroll
them. Is_supported() routine helps to cut down all of it. I didn't
calculate the usec saved with it.
If that is the reason then explain in the cover letter and provide benchmarks
I doubt it will be significant but I will do a benchmark.
From: Jason Gunthorpe <jgg@nvidia.com> Date: 2021-04-08 12:16:11
On Wed, Apr 07, 2021 at 03:44:35PM +0000, Parav Pandit wrote:
quoted
If it returns EOPNOTUPP then the remove is never called so if it allocated
memory and left it allocated then it is leaking memory.
I probably confused you. There is no leak today because add_one
allocates memory, and later on when SA/CM etc per port cap is not
present, it is unused left there which is freed on remove_one().
Returning EOPNOTUPP is fine at start of add_one() before allocation.
Most of ULPs are OK, eg umad does:
umad_dev = kzalloc(struct_size(umad_dev, ports, e - s + 1), GFP_KERNEL);
if (!umad_dev)
return -ENOMEM;
for (i = s; i <= e; ++i) {
if (!rdma_cap_ib_mad(device, i))
continue;
if (!count) {
ret = -EOPNOTSUPP;
goto free;
free:
/* balances kref_init */
ib_umad_dev_put(umad_dev);
It looks like only cm.c and cma.c need fixing, just fix those two.
The CM using ULPs have a different issue though..
Jason
From: Jason Gunthorpe <jgg@nvidia.com>
Sent: Thursday, April 8, 2021 5:46 PM
On Wed, Apr 07, 2021 at 03:44:35PM +0000, Parav Pandit wrote:
quoted
quoted
If it returns EOPNOTUPP then the remove is never called so if it
allocated memory and left it allocated then it is leaking memory.
I probably confused you. There is no leak today because add_one
allocates memory, and later on when SA/CM etc per port cap is not
present, it is unused left there which is freed on remove_one().
Returning EOPNOTUPP is fine at start of add_one() before allocation.
Most of ULPs are OK, eg umad does:
umad_dev = kzalloc(struct_size(umad_dev, ports, e - s + 1),
GFP_KERNEL);
if (!umad_dev)
return -ENOMEM;
for (i = s; i <= e; ++i) {
if (!rdma_cap_ib_mad(device, i))
continue;
if (!count) {
ret = -EOPNOTSUPP;
goto free;
free:
/* balances kref_init */
ib_umad_dev_put(umad_dev);
It looks like only cm.c and cma.c need fixing, just fix those two.
Only cma.c needs a fixing. cm.c also reports EOPNOTSUPP.
I will send the simplified fix through Leon.