[PATCH 04/16] NTB: ntb_transport: Stop QP work before freeing a queue

Koichiro Den <[email protected]>
Newsgroups dev.linux.lists.ntb,org.kernel.vger.linux-kernel,org.kernel.vger.netdev
Message-ID <[email protected]>
ntb_transport_link_down() clears client_ready, but asynchronous QP work
can outlive that transition. This leaves three teardown races:

  1. Queued link_work can mark the QP active again and schedule RX
     processing.
  2. A per-QP MSI can schedule RX processing after client link-down.
  3. link_cleanup can run while ntb_transport_free_queue() releases queue
     state and can rearm link_work. RX processing can also queue another
     cleanup while it is being drained.

Gate link_work and the MSI handler with client_ready. Before releasing
queue resources, drain link_cleanup and link_work. After stopping RX
processing, drain link_cleanup once more, then link_work because cleanup
can rearm it.

Fixes: fce8a7bb5b4b ("PCI-Express Non-Transparent Bridge Support")
Signed-off-by: Koichiro Den <[email protected]>
---
 drivers/ntb/ntb_transport.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 044d8b5747fc..4afad4489772 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -653,7 +653,8 @@ static irqreturn_t ntb_transport_isr(int irq, void *dev)
 {
 	struct ntb_transport_qp *qp = dev;
 
-	tasklet_schedule(&qp->rxc_db_work);
+	if (qp->client_ready)
+		tasklet_schedule(&qp->rxc_db_work);
 
 	return IRQ_HANDLED;
 }
@@ -1133,6 +1134,9 @@ static void ntb_qp_link_work(struct work_struct *work)
 	struct ntb_transport_ctx *nt = qp->transport;
 	int val;
 
+	if (!qp->client_ready)
+		return;
+
 	WARN_ON(!nt->link_is_up);
 
 	val = ntb_spad_read(nt->ndev, QP_LINKS);
@@ -2182,6 +2186,8 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 
 	pdev = qp->ndev->pdev;
 
+	cancel_work_sync(&qp->link_cleanup);
+	cancel_delayed_work_sync(&qp->link_work);
 	qp->active = false;
 
 	if (qp->tx_offload_thread) {
@@ -2229,6 +2235,8 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 	ntb_db_set_mask(qp->ndev, qp_bit);
 	tasklet_kill(&qp->rxc_db_work);
 
+	/* Catch cleanup queued while draining RX processing. */
+	cancel_work_sync(&qp->link_cleanup);
 	cancel_delayed_work_sync(&qp->link_work);
 
 	qp->cb_data = NULL;
-- 
2.51.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.