| From c01fda35bd82f7e154c3783a01a15bfadd8860e9 Mon Sep 17 00:00:00 2001 |
| From: Kaike Wan <kaike.wan@intel.com> |
| Date: Thu, 19 Dec 2019 16:19:41 -0500 |
| Subject: [PATCH] IB/hfi1: Don't cancel unused work item |
| |
| commit ca9033ba69c7e3477f207df69867b2ea969197c8 upstream. |
| |
| In the iowait structure, two iowait_work entries were included to queue a |
| given object: one for normal IB operations, and the other for TID RDMA |
| operations. For non-TID RDMA operations, the iowait_work structure for TID |
| RDMA is initialized to contain a NULL function (not used). When the QP is |
| reset, the function iowait_cancel_work will be called to cancel any |
| pending work. The problem is that this function will call |
| cancel_work_sync() for both iowait_work entries, even though the one for |
| TID RDMA is not used at all. Eventually, the call cascades to |
| __flush_work(), wherein a WARN_ON will be triggered due to the fact that |
| work->func is NULL. |
| |
| The WARN_ON was introduced in commit 4d43d395fed1 ("workqueue: Try to |
| catch flush_work() without INIT_WORK().") |
| |
| This patch fixes the issue by making sure that a work function is present |
| for TID RDMA before calling cancel_work_sync in iowait_cancel_work. |
| |
| Fixes: 4d43d395fed1 ("workqueue: Try to catch flush_work() without INIT_WORK().") |
| Fixes: 5da0fc9dbf89 ("IB/hfi1: Prepare resource waits for dual leg") |
| Link: https://lore.kernel.org/r/20191219211941.58387.39883.stgit@awfm-01.aw.intel.com |
| Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com> |
| Signed-off-by: Kaike Wan <kaike.wan@intel.com> |
| Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com> |
| Signed-off-by: Jason Gunthorpe <jgg@mellanox.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/infiniband/hw/hfi1/iowait.c b/drivers/infiniband/hw/hfi1/iowait.c |
| index adb4a1ba921b..5836fe7b2817 100644 |
| --- a/drivers/infiniband/hw/hfi1/iowait.c |
| +++ b/drivers/infiniband/hw/hfi1/iowait.c |
| @@ -81,7 +81,9 @@ void iowait_init(struct iowait *wait, u32 tx_limit, |
| void iowait_cancel_work(struct iowait *w) |
| { |
| cancel_work_sync(&iowait_get_ib_work(w)->iowork); |
| - cancel_work_sync(&iowait_get_tid_work(w)->iowork); |
| + /* Make sure that the iowork for TID RDMA is used */ |
| + if (iowait_get_tid_work(w)->iowork.func) |
| + cancel_work_sync(&iowait_get_tid_work(w)->iowork); |
| } |
| |
| /** |
| -- |
| 2.7.4 |
| |