The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Simon Horman <horms@kernel.org>
To: fanwu01@zju.edu.cn
Cc: Simon Horman <horms@kernel.org>,
	netdev@vger.kernel.org, shenjian15@huawei.com,
	salil.mehta@huawei.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: Re: [PATCH] net: hip04: quiesce tx coalesce timer before teardown
Date: Thu,  9 Jul 2026 13:43:10 +0100	[thread overview]
Message-ID: <20260709124309.1557255-2-horms@kernel.org> (raw)
In-Reply-To: <20260703050133.2445155-1-fanwu01@zju.edu.cn>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
net: hip04: quiesce tx coalesce timer before teardown

This patch fixes race conditions with the tx_coalesce_timer by properly
canceling it during device stop and remove. It also serializes device
restarts in the tx timeout handler using rtnl_lock().

> diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
> index 18376bcc718a2..cb9b01c79ee6e 100644
> --- a/drivers/net/ethernet/hisilicon/hip04_eth.c
> +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c

[ ... ]

> @@ -761,6 +762,13 @@ static int hip04_mac_stop(struct net_device *ndev)
>  
>  	napi_disable(&priv->napi);
>  	netif_stop_queue(ndev);

[Severity: High]
This is a pre-existing issue, but does netif_stop_queue() adequately protect
against concurrent transmission here?

Since netif_stop_queue() only changes the queue state flag without waiting for
an active ndo_start_xmit callback to finish (unlike netif_tx_disable()), could
this allow the subsequent hip04_tx_reclaim() call to corrupt the TX ring or
cause invalid DMA mappings if a transmission is actively running?

> +
> +	/* Cancel the TX-coalesce timer after the arming paths (xmit via the
> +	 * queue, rx poll via NAPI) are disabled, so a pending tx_done()
> +	 * (which dereferences priv) is drained before the device is freed.
> +	 */
> +	hrtimer_cancel(&priv->tx_coalesce_timer);

[Severity: High]
This is a pre-existing issue, but is it possible for the softirq to re-arm
the timer after hrtimer_cancel() is called?

In hip04_rx_poll(), the NAPI ownership is released via napi_complete_done()
before the timer is armed:

hip04_rx_poll() {
    ...
    napi_complete_done(napi, rx);
done:
    if (rx < budget && tx_remaining)
        hip04_start_tx_timer(priv);
}

If the teardown thread cancels the timer and frees the private structure
while the softirq is preempted just after napi_complete_done(), could this
result in a use-after-free when hip04_start_tx_timer() is eventually executed?

> +
>  	hip04_mac_disable(ndev);
>  	hip04_tx_reclaim(ndev, true);

[Severity: High]
This is a pre-existing issue, but is there missing hardware synchronization
between disabling the MAC and reclaiming the TX ring?

hip04_mac_disable() disables the MAC using a relaxed MMIO write without
polling for an idle state.

Since the very next call is hip04_tx_reclaim() which unmaps buffers and
modifies descriptor memory, could this cause silent data corruption or IOMMU
page faults if the MAC is still actively processing packets in the background?

[ ... ]

> @@ -791,8 +799,15 @@ static void hip04_tx_timeout_task(struct work_struct *work)
>  	struct hip04_priv *priv;
>  
>  	priv = container_of(work, struct hip04_priv, tx_timeout_task);
> +
> +	rtnl_lock();
> +	if (!netif_running(priv->ndev))
> +		goto out;
> +
>  	hip04_mac_stop(priv->ndev);
>  	hip04_mac_open(priv->ndev);

[Severity: High]
This is a pre-existing issue, but what happens if hip04_mac_open() fails
during this restart?

If dma_map_single() fails inside hip04_mac_open(), it returns -EIO without
enabling NAPI. Because this return value is ignored here, the device remains
broken and NAPI is left disabled (with the SCHED bit set).

Will this cause a hard lockup later when hip04_mac_stop() spins forever in
napi_disable() waiting for the SCHED bit to clear?

> +out:
> +	rtnl_unlock();
>  }
>  

[ ... ]

> @@ -1029,10 +1044,15 @@ static void hip04_remove(struct platform_device *pdev)
>  	if (priv->phy)
>  		phy_disconnect(priv->phy);
>  
> -	hip04_free_ring(ndev, d);
>  	unregister_netdev(ndev);

[Severity: High]
This is a pre-existing issue, but does calling phy_disconnect() before
unregister_netdev() cause a use-after-free and WARN?

phy_disconnect() halts and detaches the PHY, dropping its reference count.
The subsequent call to unregister_netdev() invokes hip04_mac_stop(), which
unconditionally calls phy_stop().

Could calling phy_stop() on a detached and potentially freed PHY device
pointer cause a crash?

> -	of_node_put(priv->phy_node);
>  	cancel_work_sync(&priv->tx_timeout_task);
> +	hrtimer_cancel(&priv->tx_coalesce_timer);
> +	/* Free the rings only after the interface is stopped (.ndo_stop via
> +	 * unregister_netdev) and the work/timer are drained; the TX/NAPI
> +	 * paths touch them while the device is up.
> +	 */
> +	hip04_free_ring(ndev, d);

[Severity: High]
This is a pre-existing issue, but does hip04_free_ring() safely handle
allocation failures?

During probe, if allocating the TX descriptor ring fails, priv->tx_desc
remains NULL, and the error path calls hip04_free_ring().

Since hip04_free_ring() unconditionally calls dma_free_coherent() on
priv->tx_desc, could this cause a kernel panic on architectures that trap
virtual-to-physical translations on NULL?

> +	of_node_put(priv->phy_node);
>  	free_netdev(ndev);

[Severity: High]
This is a pre-existing issue, but does explicitly freeing the netdev here
create a use-after-free race with the interrupt handler?

The driver requests its interrupt in hip04_mac_probe() using
devm_request_irq(), meaning the IRQ is only freed during devres cleanup after
hip04_remove() completely finishes.

If an interrupt fires between free_netdev() and the devres cleanup,
hip04_mac_interrupt() will cast dev_id to the freed ndev pointer, which seems
like it would lead to a use-after-free crash.

>  }
>  

[ ... ]

Regarding the RX polling path in hip04_rx_poll():

[Severity: High]
This is a pre-existing issue, but does a failure in build_skb() cause a memory
and DMA mapping leak?

Looking at hip04_rx_poll():

    if (unlikely(!skb)) {
        net_dbg_ratelimited("build_skb failed\n");
        goto refill;
    }
    ...
refill:
    ...
    priv->rx_buf[priv->rx_head] = buf;
    priv->rx_phys[priv->rx_head] = phys;

If build_skb() fails, the code jumps directly to the refill label, completely
bypassing the dma_unmap_single() call for the original buffer. It then
allocates and maps a new buffer, overwriting the array entries.

Could this permanently leak the original buffer and its DMA mapping,
eventually leading to an OOM crash under memory pressure?

  reply	other threads:[~2026-07-09 12:48 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-03  5:01 [PATCH] net: hip04: quiesce tx coalesce timer before teardown Fan Wu
2026-07-09 12:43 ` Simon Horman [this message]
2026-07-11  5:34   ` Fan Wu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260709124309.1557255-2-horms@kernel.org \
    --to=horms@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=fanwu01@zju.edu.cn \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=salil.mehta@huawei.com \
    --cc=shenjian15@huawei.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox