mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 03:24:19 +02:00
Merge branch 'net-mana-fix-null-dereferences-during-teardown-after-attach-failure'
Dipayaan Roy says: ==================== net: mana: Fix NULL dereferences during teardown after attach failure When mana_attach() fails (e.g. during queue allocation), the error cleanup frees apc->tx_qp and apc->rxqs and sets them to NULL. Multiple subsequent teardown paths can then dereference these NULL pointers, causing kernel panics. Patch 1 adds NULL guards in the low-level teardown functions (mana_fence_rqs, mana_destroy_vport, mana_dealloc_queues) so they are safe to call regardless of queue initialization state. This covers all callers: mana_remove(), mana_change_mtu() recovery, and internal error paths in mana_alloc_queues(). Patch 2 adds an early exit in mana_detach() for already-detached ports, making it safe for non-close callers. This allows the queue reset handler to safely retry mana_attach() without redundant teardown. ==================== Link: https://patch.msgid.link/20260525081129.1230035-1-dipayanroy@linux.microsoft.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
ab4ac5a93b
|
|
@ -1727,6 +1727,9 @@ static void mana_fence_rqs(struct mana_port_context *apc)
|
|||
struct mana_rxq *rxq;
|
||||
int err;
|
||||
|
||||
if (!apc->rxqs)
|
||||
return;
|
||||
|
||||
for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) {
|
||||
rxq = apc->rxqs[rxq_idx];
|
||||
err = mana_fence_rq(apc, rxq);
|
||||
|
|
@ -2858,13 +2861,16 @@ static void mana_destroy_vport(struct mana_port_context *apc)
|
|||
struct mana_rxq *rxq;
|
||||
u32 rxq_idx;
|
||||
|
||||
for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) {
|
||||
rxq = apc->rxqs[rxq_idx];
|
||||
if (!rxq)
|
||||
continue;
|
||||
if (apc->rxqs) {
|
||||
|
||||
mana_destroy_rxq(apc, rxq, true);
|
||||
apc->rxqs[rxq_idx] = NULL;
|
||||
for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) {
|
||||
rxq = apc->rxqs[rxq_idx];
|
||||
if (!rxq)
|
||||
continue;
|
||||
|
||||
mana_destroy_rxq(apc, rxq, true);
|
||||
apc->rxqs[rxq_idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mana_destroy_txq(apc);
|
||||
|
|
@ -3269,7 +3275,8 @@ static int mana_dealloc_queues(struct net_device *ndev)
|
|||
if (apc->port_is_up)
|
||||
return -EINVAL;
|
||||
|
||||
mana_chn_setxdp(apc, NULL);
|
||||
if (apc->rxqs)
|
||||
mana_chn_setxdp(apc, NULL);
|
||||
|
||||
if (gd->gdma_context->is_pf && !apc->ac->bm_hostmode)
|
||||
mana_pf_deregister_filter(apc);
|
||||
|
|
@ -3287,33 +3294,38 @@ static int mana_dealloc_queues(struct net_device *ndev)
|
|||
* number of queues.
|
||||
*/
|
||||
|
||||
for (i = 0; i < apc->num_queues; i++) {
|
||||
txq = &apc->tx_qp[i].txq;
|
||||
tsleep = 1000;
|
||||
while (atomic_read(&txq->pending_sends) > 0 &&
|
||||
time_before(jiffies, timeout)) {
|
||||
usleep_range(tsleep, tsleep + 1000);
|
||||
tsleep <<= 1;
|
||||
}
|
||||
if (atomic_read(&txq->pending_sends)) {
|
||||
err = pcie_flr(to_pci_dev(gd->gdma_context->dev));
|
||||
if (err) {
|
||||
netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n",
|
||||
err, atomic_read(&txq->pending_sends),
|
||||
txq->gdma_txq_id);
|
||||
if (apc->tx_qp) {
|
||||
for (i = 0; i < apc->num_queues; i++) {
|
||||
txq = &apc->tx_qp[i].txq;
|
||||
tsleep = 1000;
|
||||
while (atomic_read(&txq->pending_sends) > 0 &&
|
||||
time_before(jiffies, timeout)) {
|
||||
usleep_range(tsleep, tsleep + 1000);
|
||||
tsleep <<= 1;
|
||||
}
|
||||
break;
|
||||
if (atomic_read(&txq->pending_sends)) {
|
||||
err =
|
||||
pcie_flr(to_pci_dev(gd->gdma_context->dev));
|
||||
if (err) {
|
||||
netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n",
|
||||
err,
|
||||
atomic_read(&txq->pending_sends),
|
||||
txq->gdma_txq_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < apc->num_queues; i++) {
|
||||
txq = &apc->tx_qp[i].txq;
|
||||
while ((skb = skb_dequeue(&txq->pending_skbs))) {
|
||||
mana_unmap_skb(skb, apc);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
atomic_set(&txq->pending_sends, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < apc->num_queues; i++) {
|
||||
txq = &apc->tx_qp[i].txq;
|
||||
while ((skb = skb_dequeue(&txq->pending_skbs))) {
|
||||
mana_unmap_skb(skb, apc);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
atomic_set(&txq->pending_sends, 0);
|
||||
}
|
||||
/* We're 100% sure the queues can no longer be woken up, because
|
||||
* we're sure now mana_poll_tx_cq() can't be running.
|
||||
*/
|
||||
|
|
@ -3338,6 +3350,12 @@ int mana_detach(struct net_device *ndev, bool from_close)
|
|||
|
||||
ASSERT_RTNL();
|
||||
|
||||
/* If already detached (indicates detach succeeded but attach failed
|
||||
* previously). Now skip mana detach and just retry mana_attach.
|
||||
*/
|
||||
if (!from_close && !netif_device_present(ndev))
|
||||
return 0;
|
||||
|
||||
apc->port_st_save = apc->port_is_up;
|
||||
apc->port_is_up = false;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user