| From 16e905b73d0b2b4cc0dc7cd352974606449c1a15 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 18 Apr 2022 23:33:22 +0800 |
| Subject: RDMA/irdma: Fix deadlock in irdma_cleanup_cm_core() |
| |
| From: Duoming Zhou <duoming@zju.edu.cn> |
| |
| [ Upstream commit 679ab61bf5f5f519377d812afb4fb93634782c74 ] |
| |
| There is a deadlock in irdma_cleanup_cm_core(), which is shown below: |
| |
| (Thread 1) | (Thread 2) |
| | irdma_schedule_cm_timer() |
| irdma_cleanup_cm_core() | add_timer() |
| spin_lock_irqsave() //(1) | (wait a time) |
| ... | irdma_cm_timer_tick() |
| del_timer_sync() | spin_lock_irqsave() //(2) |
| (wait timer to stop) | ... |
| |
| We hold cm_core->ht_lock in position (1) of thread 1 and use |
| del_timer_sync() to wait timer to stop, but timer handler also need |
| cm_core->ht_lock in position (2) of thread 2. As a result, |
| irdma_cleanup_cm_core() will block forever. |
| |
| This patch removes the check of timer_pending() in |
| irdma_cleanup_cm_core(), because the del_timer_sync() function will just |
| return directly if there isn't a pending timer. As a result, the lock is |
| redundant, because there is no resource it could protect. |
| |
| Link: https://lore.kernel.org/r/20220418153322.42524-1-duoming@zju.edu.cn |
| Signed-off-by: Duoming Zhou <duoming@zju.edu.cn> |
| Reviewed-by: Shiraz Saleem <shiraz.saleem@intel.com> |
| Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/infiniband/hw/irdma/cm.c | 7 +------ |
| 1 file changed, 1 insertion(+), 6 deletions(-) |
| |
| diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c |
| index 082a3ddb0fa3..632f65e53b63 100644 |
| --- a/drivers/infiniband/hw/irdma/cm.c |
| +++ b/drivers/infiniband/hw/irdma/cm.c |
| @@ -3242,15 +3242,10 @@ enum irdma_status_code irdma_setup_cm_core(struct irdma_device *iwdev, |
| */ |
| void irdma_cleanup_cm_core(struct irdma_cm_core *cm_core) |
| { |
| - unsigned long flags; |
| - |
| if (!cm_core) |
| return; |
| |
| - spin_lock_irqsave(&cm_core->ht_lock, flags); |
| - if (timer_pending(&cm_core->tcp_timer)) |
| - del_timer_sync(&cm_core->tcp_timer); |
| - spin_unlock_irqrestore(&cm_core->ht_lock, flags); |
| + del_timer_sync(&cm_core->tcp_timer); |
| |
| destroy_workqueue(cm_core->event_wq); |
| cm_core->dev->ws_reset(&cm_core->iwdev->vsi); |
| -- |
| 2.35.1 |
| |