[Devel] [PATCH RHEL10 COMMIT] fs/fuse kio: zero cs_stats accumulators on each seqlock retry

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 15 13:43:02 MSK 2026


The commit is pushed to "branch-rh10-6.12.0-211.16.1.12.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.16.1.el10
------>
commit e3508247b74d6c6c8a1cf9dc2058a45a6b9d18b4
Author: Konstantin Khorenko <khorenko at virtuozzo.com>
Date:   Wed Jun 3 23:57:17 2026 +0200

    fs/fuse kio: zero cs_stats accumulators on each seqlock retry
    
    do_show_cs_stats() sums the per-cpu latency/rate counters into the
    on-stack accumulators inside a read_seqretry() loop:
      iolat, netlat, read_ops_rate, write_ops_rate, sync_ops_rate.
    
    The accumulators were initialised only once, before the loop.
    
    If a writer (pcs_cs_update_stat() / pcs_cs_stat_up(), both under
    write_seqlock(&cs->stat.seqlock)) runs concurrently, read_seqretry()
    re-executes the loop body, summing every per-cpu counter a second time
    on top of the already-populated structs - producing over-counted values
    in the cs_stats output.
    
    Zero the accumulators at the top of each pass so a retry starts clean,
    and remove the initialization in the header as redundant.
    
    Fixes: d3a72ba5c1ae ("fs/fuse kio: implement cs_stats statistics info")
    https://virtuozzo.atlassian.net/browse/VSTOR-132310
    Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
    
    Feature: vStorage
---
 fs/fuse/kio/pcs/fuse_stat.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/fs/fuse/kio/pcs/fuse_stat.c b/fs/fuse/kio/pcs/fuse_stat.c
index 447e4a617655..41bb9c71af90 100644
--- a/fs/fuse/kio/pcs/fuse_stat.c
+++ b/fs/fuse/kio/pcs/fuse_stat.c
@@ -331,15 +331,25 @@ static int do_show_cs_stats(struct pcs_cs *cs, void *ctx)
 	struct seq_file *m = ctx;
 	int rpc_state = cs->rpc ? cs->rpc->state : PCS_RPC_UNCONN;
 	unsigned int in_flight_avg = cs->in_flight_avg;
-	struct fuse_lat_stat iolat = {}, netlat = {};
-	struct pcs_perf_rate_cnt read_ops_rate = {}, write_ops_rate = {},
-				 sync_ops_rate = {};
+	struct fuse_lat_stat iolat, netlat;
+	struct pcs_perf_rate_cnt read_ops_rate, write_ops_rate, sync_ops_rate;
 	unsigned seq;
 
 	do {
 		int cpu;
 
 		seq = read_seqbegin(&cs->stat.seqlock);
+		/*
+		 * read_seqretry() may re-run this loop if a writer updated the
+		 * stats meanwhile; zero the accumulators on every pass so a
+		 * retry does not sum the per-cpu counters on top of the values
+		 * already gathered by the previous (aborted) pass.
+		 */
+		memset(&iolat, 0, sizeof(iolat));
+		memset(&netlat, 0, sizeof(netlat));
+		memset(&read_ops_rate, 0, sizeof(read_ops_rate));
+		memset(&write_ops_rate, 0, sizeof(write_ops_rate));
+		memset(&sync_ops_rate, 0, sizeof(sync_ops_rate));
 		for_each_possible_cpu(cpu) {
 			struct fuse_lat_stat *pcpu_iolat, *pcpu_netlat;
 			struct pcs_perf_rate_cnt *pcpu_read_rate,


More information about the Devel mailing list