Skip to content

Commit 7fbf679

Browse files
colin-foster-in-advantagekuba-moo
authored andcommitted
net: mscc: ocelot: fix mutex lock error during ethtool stats read
An ongoing workqueue populates the stats buffer. At the same time, a user might query the statistics. While writing to the buffer is mutex-locked, reading from the buffer wasn't. This could lead to buggy reads by ethtool. This patch fixes the former blamed commit, but the bug was introduced in the latter. Signed-off-by: Colin Foster <[email protected]> Fixes: 1e1caa9 ("ocelot: Clean up stats update deferred work") Fixes: a556c76 ("net: mscc: Add initial Ocelot switch support") Reported-by: Vladimir Oltean <[email protected]> Reviewed-by: Vladimir Oltean <[email protected]> Link: https://lore.kernel.org/all/[email protected]/ Signed-off-by: Jakub Kicinski <[email protected]>
1 parent c4416f5 commit 7fbf679

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

drivers/net/ethernet/mscc/ocelot.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,12 +1745,11 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
17451745
}
17461746
EXPORT_SYMBOL(ocelot_get_strings);
17471747

1748+
/* Caller must hold &ocelot->stats_lock */
17481749
static void ocelot_update_stats(struct ocelot *ocelot)
17491750
{
17501751
int i, j;
17511752

1752-
mutex_lock(&ocelot->stats_lock);
1753-
17541753
for (i = 0; i < ocelot->num_phys_ports; i++) {
17551754
/* Configure the port to read the stats from */
17561755
ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(i), SYS_STAT_CFG);
@@ -1769,8 +1768,6 @@ static void ocelot_update_stats(struct ocelot *ocelot)
17691768
~(u64)U32_MAX) + val;
17701769
}
17711770
}
1772-
1773-
mutex_unlock(&ocelot->stats_lock);
17741771
}
17751772

17761773
static void ocelot_check_stats_work(struct work_struct *work)
@@ -1779,7 +1776,9 @@ static void ocelot_check_stats_work(struct work_struct *work)
17791776
struct ocelot *ocelot = container_of(del_work, struct ocelot,
17801777
stats_work);
17811778

1779+
mutex_lock(&ocelot->stats_lock);
17821780
ocelot_update_stats(ocelot);
1781+
mutex_unlock(&ocelot->stats_lock);
17831782

17841783
queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
17851784
OCELOT_STATS_CHECK_DELAY);
@@ -1789,12 +1788,16 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
17891788
{
17901789
int i;
17911790

1791+
mutex_lock(&ocelot->stats_lock);
1792+
17921793
/* check and update now */
17931794
ocelot_update_stats(ocelot);
17941795

17951796
/* Copy all counters */
17961797
for (i = 0; i < ocelot->num_stats; i++)
17971798
*data++ = ocelot->stats[port * ocelot->num_stats + i];
1799+
1800+
mutex_unlock(&ocelot->stats_lock);
17981801
}
17991802
EXPORT_SYMBOL(ocelot_get_ethtool_stats);
18001803

0 commit comments

Comments
 (0)