diff options
Diffstat (limited to 'debian/patches-rt/net-stats-Read-the-statistics-in-___gnet_stats_copy_.patch')
-rw-r--r-- | debian/patches-rt/net-stats-Read-the-statistics-in-___gnet_stats_copy_.patch | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/debian/patches-rt/net-stats-Read-the-statistics-in-___gnet_stats_copy_.patch b/debian/patches-rt/net-stats-Read-the-statistics-in-___gnet_stats_copy_.patch new file mode 100644 index 000000000..b43ea9f32 --- /dev/null +++ b/debian/patches-rt/net-stats-Read-the-statistics-in-___gnet_stats_copy_.patch @@ -0,0 +1,90 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Thu, 21 Oct 2021 11:59:19 +0200 +Subject: [PATCH] net: stats: Read the statistics in ___gnet_stats_copy_basic() + instead of adding. +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.15/older/patches-5.15.3-rt21.tar.xz + +Since the rework, the statistics code always adds up the byte and packet +value(s). On 32bit architectures a seqcount_t is used in +gnet_stats_basic_sync to ensure that the 64bit values are not modified +during the read since two 32bit loads are required. The usage of a +seqcount_t requires a lock to ensure that only one writer is active at a +time. This lock leads to disabled preemption during the update. + +The lack of disabling preemption is now creating a warning as reported +by Naresh since the query done by gnet_stats_copy_basic() is in +preemptible context. + +For ___gnet_stats_copy_basic() there is no need to disable preemption +since the update is performed on stack and can't be modified by another +writer. Instead of disabling preemption, to avoid the warning, +simply create a read function to just read the values and return as u64. + +Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org> +Fixes: 67c9e6270f301 ("net: sched: Protect Qdisc::bstats with u64_stats") +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Link: https://lore.kernel.org/r/20211021095919.bi3szpt3c2kcoiso@linutronix.de +--- + net/core/gen_stats.c | 43 +++++++++++++++++++++++++++++++++++++------ + 1 file changed, 37 insertions(+), 6 deletions(-) + +--- a/net/core/gen_stats.c ++++ b/net/core/gen_stats.c +@@ -171,20 +171,51 @@ void gnet_stats_add_basic(struct gnet_st + } + EXPORT_SYMBOL(gnet_stats_add_basic); + ++static void gnet_stats_read_basic(u64 *ret_bytes, u64 *ret_packets, ++ struct gnet_stats_basic_sync __percpu *cpu, ++ struct gnet_stats_basic_sync *b, bool running) ++{ ++ unsigned int start; ++ ++ if (cpu) { ++ u64 t_bytes = 0, t_packets = 0; ++ int i; ++ ++ for_each_possible_cpu(i) { ++ struct gnet_stats_basic_sync *bcpu = per_cpu_ptr(cpu, i); ++ unsigned int start; ++ u64 bytes, packets; ++ ++ do { ++ start = u64_stats_fetch_begin_irq(&bcpu->syncp); ++ bytes = u64_stats_read(&bcpu->bytes); ++ packets = u64_stats_read(&bcpu->packets); ++ } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); ++ ++ t_bytes += bytes; ++ t_packets += packets; ++ } ++ *ret_bytes = t_bytes; ++ *ret_packets = t_packets; ++ return; ++ } ++ do { ++ if (running) ++ start = u64_stats_fetch_begin_irq(&b->syncp); ++ *ret_bytes = u64_stats_read(&b->bytes); ++ *ret_packets = u64_stats_read(&b->packets); ++ } while (running && u64_stats_fetch_retry_irq(&b->syncp, start)); ++} ++ + static int + ___gnet_stats_copy_basic(struct gnet_dump *d, + struct gnet_stats_basic_sync __percpu *cpu, + struct gnet_stats_basic_sync *b, + int type, bool running) + { +- struct gnet_stats_basic_sync bstats; + u64 bstats_bytes, bstats_packets; + +- gnet_stats_basic_sync_init(&bstats); +- gnet_stats_add_basic(&bstats, cpu, b, running); +- +- bstats_bytes = u64_stats_read(&bstats.bytes); +- bstats_packets = u64_stats_read(&bstats.packets); ++ gnet_stats_read_basic(&bstats_bytes, &bstats_packets, cpu, b, running); + + if (d->compat_tc_stats && type == TCA_STATS_BASIC) { + d->tc_stats.bytes = bstats_bytes; |