[PATCH 3/5] mm/vmstat: use cmpxchg loop in cpu_vm_stats_fold

From: Marcelo Tosatti
Date: Wed Feb 01 2023 - 14:53:23 EST


In preparation to switch vmstat shepherd to flush
per-CPU counters remotely, use a cmpxchg loop
instead of a pair of read/write instructions.

Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx>

Index: linux-vmstat-remote/mm/vmstat.c
===================================================================
--- linux-vmstat-remote.orig/mm/vmstat.c
+++ linux-vmstat-remote/mm/vmstat.c
@@ -885,7 +885,7 @@ static int refresh_cpu_vm_stats(void)
}

/*
- * Fold the data for an offline cpu into the global array.
+ * Fold the data for a cpu into the global array.
* There cannot be any access by the offline cpu and therefore
* synchronization is simplified.
*/
@@ -906,8 +906,9 @@ void cpu_vm_stats_fold(int cpu)
if (pzstats->vm_stat_diff[i]) {
int v;

- v = pzstats->vm_stat_diff[i];
- pzstats->vm_stat_diff[i] = 0;
+ do {
+ v = pzstats->vm_stat_diff[i];
+ } while (cmpxchg(&pzstats->vm_stat_diff[i], v, 0) != v);
atomic_long_add(v, &zone->vm_stat[i]);
global_zone_diff[i] += v;
}
@@ -917,8 +918,9 @@ void cpu_vm_stats_fold(int cpu)
if (pzstats->vm_numa_event[i]) {
unsigned long v;

- v = pzstats->vm_numa_event[i];
- pzstats->vm_numa_event[i] = 0;
+ do {
+ v = pzstats->vm_numa_event[i];
+ } while (cmpxchg(&pzstats->vm_numa_event[i], v, 0) != v);
zone_numa_event_add(v, zone, i);
}
}
@@ -934,8 +936,9 @@ void cpu_vm_stats_fold(int cpu)
if (p->vm_node_stat_diff[i]) {
int v;

- v = p->vm_node_stat_diff[i];
- p->vm_node_stat_diff[i] = 0;
+ do {
+ v = p->vm_node_stat_diff[i];
+ } while (cmpxchg(&p->vm_node_stat_diff[i], v, 0) != v);
atomic_long_add(v, &pgdat->vm_stat[i]);
global_node_diff[i] += v;
}