Message ID | 20220210041345.321216-2-colin.foster@in-advantage.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | use bulk reads for ocelot statistics | expand |
On Wed, Feb 09, 2022 at 08:13:41PM -0800, Colin Foster wrote: > 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. > > Signed-off-by: Colin Foster <colin.foster@in-advantage.com> > Fixes: a556c76adc052 ("net: mscc: Add initial Ocelot switch support") > Reported-by: Vladimir Oltean <olteanv@gmail.com> I reported this using vladimir.oltean@nxp.com btw. Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> If you hurry and resend this against the "net" tree, you might catch this week's pull request, since the last one was on Feb 3->4: https://patchwork.kernel.org/project/netdevbpf/patch/20220204000428.2889873-1-kuba@kernel.org/ Then "net" will be merged into "net-next" probably the next day or so, and you can resend patches 2-5 towards "net-next". > --- > drivers/net/ethernet/mscc/ocelot.c | 11 +++++++---- > 1 file changed, 7 insertions(+), 4 deletions(-) > > diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c > index 455293aa6343..6933dff1dd37 100644 > --- a/drivers/net/ethernet/mscc/ocelot.c > +++ b/drivers/net/ethernet/mscc/ocelot.c > @@ -1737,12 +1737,11 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data) > } > EXPORT_SYMBOL(ocelot_get_strings); > > +/* Caller must hold &ocelot->stats_lock */ > static void ocelot_update_stats(struct ocelot *ocelot) > { > int i, j; > > - mutex_lock(&ocelot->stats_lock); > - > for (i = 0; i < ocelot->num_phys_ports; i++) { > /* Configure the port to read the stats from */ > ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(i), SYS_STAT_CFG); > @@ -1761,8 +1760,6 @@ static void ocelot_update_stats(struct ocelot *ocelot) > ~(u64)U32_MAX) + val; > } > } > - > - mutex_unlock(&ocelot->stats_lock); > } > > static void ocelot_check_stats_work(struct work_struct *work) > @@ -1771,7 +1768,9 @@ static void ocelot_check_stats_work(struct work_struct *work) > struct ocelot *ocelot = container_of(del_work, struct ocelot, > stats_work); > > + mutex_lock(&ocelot->stats_lock); > ocelot_update_stats(ocelot); > + mutex_unlock(&ocelot->stats_lock); > > queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work, > OCELOT_STATS_CHECK_DELAY); > @@ -1781,12 +1780,16 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data) > { > int i; > > + mutex_lock(&ocelot->stats_lock); > + > /* check and update now */ > ocelot_update_stats(ocelot); > > /* Copy all counters */ > for (i = 0; i < ocelot->num_stats; i++) > *data++ = ocelot->stats[port * ocelot->num_stats + i]; > + > + mutex_unlock(&ocelot->stats_lock); > } > EXPORT_SYMBOL(ocelot_get_ethtool_stats); > > -- > 2.25.1 >
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 455293aa6343..6933dff1dd37 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1737,12 +1737,11 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data) } EXPORT_SYMBOL(ocelot_get_strings); +/* Caller must hold &ocelot->stats_lock */ static void ocelot_update_stats(struct ocelot *ocelot) { int i, j; - mutex_lock(&ocelot->stats_lock); - for (i = 0; i < ocelot->num_phys_ports; i++) { /* Configure the port to read the stats from */ ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(i), SYS_STAT_CFG); @@ -1761,8 +1760,6 @@ static void ocelot_update_stats(struct ocelot *ocelot) ~(u64)U32_MAX) + val; } } - - mutex_unlock(&ocelot->stats_lock); } static void ocelot_check_stats_work(struct work_struct *work) @@ -1771,7 +1768,9 @@ static void ocelot_check_stats_work(struct work_struct *work) struct ocelot *ocelot = container_of(del_work, struct ocelot, stats_work); + mutex_lock(&ocelot->stats_lock); ocelot_update_stats(ocelot); + mutex_unlock(&ocelot->stats_lock); queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work, OCELOT_STATS_CHECK_DELAY); @@ -1781,12 +1780,16 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data) { int i; + mutex_lock(&ocelot->stats_lock); + /* check and update now */ ocelot_update_stats(ocelot); /* Copy all counters */ for (i = 0; i < ocelot->num_stats; i++) *data++ = ocelot->stats[port * ocelot->num_stats + i]; + + mutex_unlock(&ocelot->stats_lock); } EXPORT_SYMBOL(ocelot_get_ethtool_stats);
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. Signed-off-by: Colin Foster <colin.foster@in-advantage.com> Fixes: a556c76adc052 ("net: mscc: Add initial Ocelot switch support") Reported-by: Vladimir Oltean <olteanv@gmail.com> --- drivers/net/ethernet/mscc/ocelot.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)