diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-08-20 13:43:26 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-08-20 13:43:27 -0700 |
| commit | 52ffb39e710db4b08cb0434741b96a9baf1a1934 (patch) | |
| tree | c99bd625d4d53a54255d91b0de330a9c77885edd | |
| parent | 8197c180052fe5ee644e91b31d98328bea8a31ed (diff) | |
| parent | a4f2387db6f1cc2f03abba7f3a6807ad61e26ff7 (diff) | |
Merge branch 'net-ntb_netdev-fix-tx-completion-and-error-handling'
Koichiro Den says:
====================
net: ntb_netdev: Fix TX completion and error handling
This small series fixes several TX buffer ownership and queue handling
bugs in ntb_netdev and ntb_transport.
Patch 4 first appeared in my "NTB: Add direct TX/RX using PCI endpoint
DMA" series. Sashiko later reported the same pre-existing leak while
reviewing another series, so I moved the fix here. See:
https://lore.kernel.org/r/20260815032932.151F11F000E9@smtp.kernel.org/
The ntb_transport fixes affect buffer ownership and queue handling in
ntb_netdev, the only in-tree ntb_transport_client implementation, so the
patches need to go in together. I am targeting the net tree for the
series.
====================
Link: https://patch.msgid.link/20260817053519.4135287-1-den@valinux.co.jp
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ntb_netdev.c | 27 | ||||
| -rw-r--r-- | drivers/ntb/ntb_transport.c | 38 |
2 files changed, 37 insertions, 28 deletions
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index 029a4a532a10..02b35cf53a62 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -199,8 +199,10 @@ static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev, static int ntb_netdev_maybe_stop_tx(struct net_device *ndev, struct ntb_netdev_queue *q, int size) { - if (__netif_subqueue_stopped(ndev, q->qid) || - (ntb_transport_tx_free_entry(q->qp) >= size)) + if (__netif_subqueue_stopped(ndev, q->qid)) + return -EBUSY; + + if (ntb_transport_tx_free_entry(q->qp) >= size) return 0; return __ntb_netdev_maybe_stop_tx(ndev, q, size); @@ -256,21 +258,30 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb, q = &dev->queues[qid]; - ntb_netdev_maybe_stop_tx(ndev, q, tx_stop); + if (unlikely(ntb_netdev_maybe_stop_tx(ndev, q, tx_stop))) + return NETDEV_TX_BUSY; rc = ntb_transport_tx_enqueue(q->qp, skb, skb->data, skb->len); - if (rc) - goto err; + if (rc) { + if (rc == -EAGAIN || rc == -EBUSY) { + netif_stop_subqueue(ndev, q->qid); + mod_timer(&q->tx_timer, + jiffies + usecs_to_jiffies(tx_time)); + return NETDEV_TX_BUSY; + } + + goto drop; + } /* check for next submit */ ntb_netdev_maybe_stop_tx(ndev, q, tx_stop); return NETDEV_TX_OK; -err: +drop: + dev_kfree_skb_any(skb); ndev->stats.tx_dropped++; - ndev->stats.tx_errors++; - return NETDEV_TX_BUSY; + return NETDEV_TX_OK; } static void ntb_netdev_tx_timer(struct timer_list *t) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index f59f926d4bfa..f9caa1a653c5 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1719,9 +1719,16 @@ static void ntb_transport_rxc_db(unsigned long data) static void ntb_tx_copy_callback(void *data, const struct dmaengine_result *res) { + struct ntb_payload_header __iomem *hdr; struct ntb_queue_entry *entry = data; - struct ntb_transport_qp *qp = entry->qp; - struct ntb_payload_header __iomem *hdr = entry->tx_hdr; + struct ntb_transport_qp *qp; + unsigned int len; + void *cb_data; + + qp = entry->qp; + hdr = entry->tx_hdr; + cb_data = entry->cb_data; + len = entry->len; /* we need to check DMA results if we are using DMA */ if (res) { @@ -1768,15 +1775,13 @@ static void ntb_tx_copy_callback(void *data, * "link down" or similar. Since no payload is being sent in these * cases, there is nothing to add to the completion queue. */ - if (entry->len > 0) { - qp->tx_bytes += entry->len; - - if (qp->tx_handler) - qp->tx_handler(qp, qp->cb_data, entry->cb_data, - entry->len); - } + if (len > 0) + qp->tx_bytes += len; ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry, &qp->tx_free_q); + + if (len > 0 && qp->tx_handler) + qp->tx_handler(qp, qp->cb_data, cb_data, len); } static void ntb_memcpy_tx_on_stack(struct ntb_queue_entry *entry, void __iomem *offset) @@ -1950,15 +1955,6 @@ static int ntb_process_tx(struct ntb_transport_qp *qp, return -EAGAIN; } - if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) { - if (qp->tx_handler) - qp->tx_handler(qp, qp->cb_data, NULL, -EIO); - - ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry, - &qp->tx_free_q); - return 0; - } - ntb_async_tx(qp, entry); qp->tx_pkts++; @@ -2348,9 +2344,11 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, if (!qp || !len) return -EINVAL; - /* If the qp link is down already, just ignore. */ if (!qp->link_is_up) - return 0; + return -ENOLINK; + + if (len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) + return -EMSGSIZE; entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); if (!entry) { |
