mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 10:31:33 -04:00
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>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user