This patch allows drivers to optionally include struct rcu_head in their private object data structs and have rdma-core use kfree_rcu to free the objects. The offsets of the rcu_heads are stored in fields in struct ib_device_ops and a macro RDMA_KFREE_RCU is introduced which calls (an open coded) kfree_rcu instead of kfree if the value is non- zero. Currently the supported object types are AH, QP and MW. Signed-off-by: Bob Pearson <rpearsonhpe@xxxxxxxxx> --- drivers/infiniband/core/uverbs_main.c | 2 +- drivers/infiniband/core/verbs.c | 6 +++--- include/rdma/ib_verbs.h | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 7c9c79c13941..50497e550f18 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -112,7 +112,7 @@ int uverbs_dealloc_mw(struct ib_mw *mw) return ret; atomic_dec(&pd->usecnt); - kfree(mw); + RDMA_KFREE_RCU(mw); return ret; } diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index b99b3cc283b6..a49ae8c52c66 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -982,7 +982,7 @@ int rdma_destroy_ah_user(struct ib_ah *ah, u32 flags, struct ib_udata *udata) if (sgid_attr) rdma_put_gid_attr(sgid_attr); - kfree(ah); + RDMA_KFREE_RCU(ah); return ret; } EXPORT_SYMBOL(rdma_destroy_ah_user); @@ -1970,7 +1970,7 @@ int ib_close_qp(struct ib_qp *qp) atomic_dec(&real_qp->usecnt); if (qp->qp_sec) ib_close_shared_qp_security(qp->qp_sec); - kfree(qp); + RDMA_KFREE_RCU(qp); return 0; } @@ -2041,7 +2041,7 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata) ib_destroy_qp_security_end(sec); rdma_restrack_del(&qp->res); - kfree(qp); + RDMA_KFREE_RCU(qp); return ret; } EXPORT_SYMBOL(ib_destroy_qp_user); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 1e7774ac808f..616e9e54a733 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2684,8 +2684,32 @@ struct ib_device_ops { DECLARE_RDMA_OBJ_SIZE(ib_srq); DECLARE_RDMA_OBJ_SIZE(ib_ucontext); DECLARE_RDMA_OBJ_SIZE(ib_xrcd); + + /* if non-zero holds offset of rcu_head in object */ + ssize_t rcu_offset_ah; + ssize_t rcu_offset_qp; + ssize_t rcu_offset_mw; + }; +/* drivers may optionally use rcu locking on verbs objects + * by including struct rcu_head in their private data and + * setting rcu_offset_xx in the ib_driver_ops struct where + * xx is one of ah, qp or mw. + */ +static inline void __rdma_kfree_rcu(void *obj, ssize_t rcu_offset) +{ + if (rcu_offset) + kvfree_call_rcu((struct rcu_head *)((u8 *)obj + rcu_offset), + obj); + else + kfree(obj); +} + +/* obj must be one of ah, qp, or mw */ +#define RDMA_KFREE_RCU(obj) __rdma_kfree_rcu(obj, \ + obj->device->ops.rcu_offset_##obj) + struct ib_core_device { /* device must be the first element in structure until, * union of ib_core_device and device exists in ib_device. -- 2.39.2