--- x/include/rdma/rdma_cm.h +++ y/include/rdma/rdma_cm.h @@ -167,6 +167,7 @@ struct rdma_cm_id *rdma_create_user_id(r * asynchronous operations associated with the id. */ void rdma_destroy_id(struct rdma_cm_id *id); +void rdma_destroy_id_wq(struct rdma_cm_id *id); /** * rdma_restrict_node_type - Restrict an RDMA identifier to specific --- x/net/rds/ib.c +++ y/net/rds/ib.c @@ -486,7 +486,7 @@ static int rds_ib_laddr_check_cm(struct cm_id->device ? cm_id->device->node_type : -1); out: - rdma_destroy_id(cm_id); + rdma_destroy_id_wq(cm_id); return ret; } --- x/drivers/infiniband/core/cma_priv.h +++ y/drivers/infiniband/core/cma_priv.h @@ -110,6 +110,7 @@ struct rdma_id_private { */ struct rdma_restrack_entry res; struct rdma_ucm_ece ece; + struct work_struct destroy_work; }; #if IS_ENABLED(CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS) --- x/drivers/infiniband/core/cma.c +++ y/drivers/infiniband/core/cma.c @@ -2126,6 +2126,25 @@ void rdma_destroy_id(struct rdma_cm_id * } EXPORT_SYMBOL(rdma_destroy_id); +static void destroy_id_work(struct work_struct *work) +{ + struct rdma_id_private *id_priv = + container_of(work, struct rdma_id_private, destroy_work); + + mutex_lock(&id_priv->handler_mutex); + destroy_id_handler_unlock(id_priv); +} + +void rdma_destroy_id_wq(struct rdma_cm_id *id) +{ + struct rdma_id_private *id_priv = + container_of(id, struct rdma_id_private, id); + + INIT_WORK(&id_priv->destroy_work, destroy_id_work); + queue_work(cma_wq, &id_priv->destroy_work); +} +EXPORT_SYMBOL(rdma_destroy_id_wq); + static int cma_rep_recv(struct rdma_id_private *id_priv) { int ret;