All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Anderson <sean.anderson@linux.dev>
To: Maxime Chevallier <maxime.chevallier@bootlin.com>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>,
	Claudiu Beznea <claudiu.beznea@tuxon.dev>,
	netdev@vger.kernel.org, Eric Dumazet <edumazet@google.com>,
	Paolo Abeni <pabeni@redhat.com>,
	linux-kernel@vger.kernel.org,
	"David S . Miller" <davem@davemloft.net>,
	Andrew Lunn <andrew+netdev@lunn.ch>,
	Jakub Kicinski <kuba@kernel.org>
Subject: Re: [PATCH net] net: cadence: macb: Synchronize stats calculations
Date: Thu, 20 Feb 2025 11:02:07 -0500	[thread overview]
Message-ID: <451aca38-3b58-46c8-b6ce-6460f0504314@linux.dev> (raw)
In-Reply-To: <20250219094851.0419759f@2a02-8440-d103-5c0b-874f-3af8-c06f-cd89.rev.sfr.net>

On 2/19/25 03:48, Maxime Chevallier wrote:
> Hello Sean,
> 
> On Tue, 18 Feb 2025 14:50:36 -0500
> Sean Anderson <sean.anderson@linux.dev> wrote:
> 
>> Stats calculations involve a RMW to add the stat update to the existing
>> value. This is currently not protected by any synchronization mechanism,
>> so data races are possible. Add a spinlock to protect the update. The
>> reader side could be protected using u64_stats, but we would still need
>> a spinlock for the update side anyway. And we always do an update
>> immediately before reading the stats anyway.
>> 
>> Fixes: 89e5785fc8a6 ("[PATCH] Atmel MACB ethernet driver")
>> Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
>> ---
>> 
>>  drivers/net/ethernet/cadence/macb.h      |  2 ++
>>  drivers/net/ethernet/cadence/macb_main.c | 12 ++++++++++--
>>  2 files changed, 12 insertions(+), 2 deletions(-)
>> 
>> diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
>> index 5740c98d8c9f..2847278d9cd4 100644
>> --- a/drivers/net/ethernet/cadence/macb.h
>> +++ b/drivers/net/ethernet/cadence/macb.h
>> @@ -1279,6 +1279,8 @@ struct macb {
>>  	struct clk		*rx_clk;
>>  	struct clk		*tsu_clk;
>>  	struct net_device	*dev;
>> +	/* Protects hw_stats and ethtool_stats */
>> +	spinlock_t		stats_lock;
>>  	union {
>>  		struct macb_stats	macb;
>>  		struct gem_stats	gem;
>> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
>> index 48496209fb16..990a3863c6e1 100644
>> --- a/drivers/net/ethernet/cadence/macb_main.c
>> +++ b/drivers/net/ethernet/cadence/macb_main.c
>> @@ -1978,10 +1978,12 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
>>  
>>  		if (status & MACB_BIT(ISR_ROVR)) {
>>  			/* We missed at least one packet */
>> +			spin_lock(&bp->stats_lock);
>>  			if (macb_is_gem(bp))
>>  				bp->hw_stats.gem.rx_overruns++;
>>  			else
>>  				bp->hw_stats.macb.rx_overruns++;
>> +			spin_unlock(&bp->stats_lock);
>>  
>>  			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>>  				queue_writel(queue, ISR, MACB_BIT(ISR_ROVR));
>> @@ -3102,6 +3104,7 @@ static struct net_device_stats *gem_get_stats(struct macb *bp)
>>  	if (!netif_running(bp->dev))
>>  		return nstat;
>>  
>> +	spin_lock(&bp->stats_lock);
>>  	gem_update_stats(bp);
>>  
>>  	nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors +
>> @@ -3131,6 +3134,7 @@ static struct net_device_stats *gem_get_stats(struct macb *bp)
>>  	nstat->tx_aborted_errors = hwstat->tx_excessive_collisions;
>>  	nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors;
>>  	nstat->tx_fifo_errors = hwstat->tx_underrun;
>> +	spin_unlock(&bp->stats_lock);
>>  
>>  	return nstat;
>>  }
>> @@ -3138,12 +3142,13 @@ static struct net_device_stats *gem_get_stats(struct macb *bp)
>>  static void gem_get_ethtool_stats(struct net_device *dev,
>>  				  struct ethtool_stats *stats, u64 *data)
>>  {
>> -	struct macb *bp;
>> +	struct macb *bp = netdev_priv(dev);
>>  
>> -	bp = netdev_priv(dev);
>> +	spin_lock(&bp->stats_lock);
> 
> Sorry if I missed something, but as you're using that lock within the
> macb_interrupt(), shouldn't it be a spin_lock_irqsave() for all the
> callsites that aren't in irq context ?
> 
> You would risk a deadlock otherwise.

Yeah, looks like I missed this. Although I tested on a kernel with
lockdep enabled, and I thought that was supposed to catch this sort of
thing. Will send a v2.

--Sean

  reply	other threads:[~2025-02-20 16:02 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-18 19:50 [PATCH net] net: cadence: macb: Synchronize stats calculations Sean Anderson
2025-02-19  8:48 ` Maxime Chevallier
2025-02-20 16:02   ` Sean Anderson [this message]
2025-02-20 19:48     ` Andrew Lunn
2025-02-20 20:02       ` Sean Anderson

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=451aca38-3b58-46c8-b6ce-6460f0504314@linux.dev \
    --to=sean.anderson@linux.dev \
    --cc=andrew+netdev@lunn.ch \
    --cc=claudiu.beznea@tuxon.dev \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maxime.chevallier@bootlin.com \
    --cc=netdev@vger.kernel.org \
    --cc=nicolas.ferre@microchip.com \
    --cc=pabeni@redhat.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.