Re: [PATCH] rdma: fix self-deadlock in dtr_cma_event_handler calling rdma_destroy_id
Philipp Reisner <[email protected]> Fri, 5 Jun 2026 15:26:56 +0200
| Newsgroups | dev.linux.lists.drbd-dev |
|---|---|
| Message-ID | <CADGDV=WgH8dXJt+mwqMjFfjLWThSgqiOkiEDokysrGcg2sFDKw@mail.gmail.com> |
Merged. Thanks! On Thu, May 28, 2026 at 5:24=E2=80=AFAM zhengbing.huang <[email protected]> wrote: > > deadlock stack: > [<0>] rdma_destroy_id+0x24/0x48 [rdma_cm] > [<0>] __dtr_destroy_cm+0x118/0x160 [drbd_transport_rdma] > [<0>] dtr_remove_cm_from_path+0xf4/0x100 [drbd_transport_rdma] > [<0>] dtr_cma_retry_connect+0x24/0xa0 [drbd_transport_rdma] > [<0>] dtr_cma_event_handler+0x2fc/0x788 [drbd_transport_rdma] > [<0>] cma_cm_event_handler+0x38/0xf0 [rdma_cm] > [<0>] cma_ib_handler+0xa0/0x2c8 [rdma_cm] > [<0>] cm_process_work+0x30/0x278 [ib_cm] > [<0>] cm_queue_work_unlock+0x80/0x160 [ib_cm] > [<0>] cm_rej_handler+0xf4/0x288 [ib_cm] > [<0>] cm_work_handler+0x108/0x420 [ib_cm] > > dtr_cma_event_handler() is called from the IB CM workqueue which holds > handler_mutex. On error events (REJECTED, CONNECT_ERROR, etc.) it > called dtr_cma_retry_connect() -> dtr_remove_cm_from_path() -> > kref_put(dtr_destroy_cm), which drops the path->cm ref. When that was > the last kref, __dtr_destroy_cm() -> rdma_destroy_id() tried to lock > handler_mutex again, causing self-deadlock. > > Fix by taking a shield kref before dtr_cma_retry_connect(), so the > kref_put inside dtr_remove_cm_from_path() never reaches zero. The > shield ref is then released at function exit via dtr_destroy_cm_keep_id > (which does not call rdma_destroy_id). In the connecting case, the > shield ref is dropped explicitly while refcount is still >=3D 2, so > dtr_destroy_cm is not invoked either. > > Signed-off-by: zhengbing.huang <[email protected]> > --- > drbd/drbd_transport_rdma.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/drbd/drbd_transport_rdma.c b/drbd/drbd_transport_rdma.c > index 9099fee93..e513339a7 100644 > --- a/drbd/drbd_transport_rdma.c > +++ b/drbd/drbd_transport_rdma.c > @@ -1313,11 +1313,13 @@ static int dtr_cma_event_handler(struct rdma_cm_i= d *cm_id, struct rdma_cm_event > // pr_info("event =3D %d, status =3D %d\n", event->event,= event->status); > set_bit(DSB_ERROR, &cm->state); > > + /* shield ref: prevent the last kref put calling rdma_des= troy_id() here */ > + kref_get(&cm->kref); > dtr_cma_retry_connect(cm->path, cm); > connecting =3D test_and_clear_bit(DSB_CONNECTING, &cm->st= ate) || > test_and_clear_bit(DSB_CONNECT_REQ, &cm->state); > - if (!connecting) > - return 0; /* keep ref; __dtr_disconnect_path() wo= n */ > + if (connecting) > + kref_put(&cm->kref, dtr_destroy_cm); > break; > > case RDMA_CM_EVENT_DISCONNECTED: > -- > 2.43.0 >