The memory stat is not done in real time, it have some gap with real value. In CPU-less NUMA node, the values of MemTotal and MemFree can be nearly equal, the gap may cause MemFree bigger than MemTotal, it leads MemUsed is negative which print as a large positive number. cat /sys/devices/system/node/node17/meminfo Node 17 MemTotal: 4194304 kB Node 17 MemFree: 4195552 kB Node 17 MemUsed: 18446744073709550368 kB Node 17 Active: 52 kB Node 17 Inactive: 320 kB Node 17 Active(anon): 0 kB Node 17 Inactive(anon): 0 kB Node 17 Active(file): 52 kB Node 17 Inactive(file): 320 kB Node 17 Unevictable: 0 kB Node 17 Mlocked: 0 kB Node 17 Dirty: 0 kB Node 17 Writeback: 0 kB Node 17 FilePages: 372 kB Node 17 Mapped: 320 kB Node 17 AnonPages: 0 kB Node 17 Shmem: 0 kB Node 17 KernelStack: 0 kB Node 17 PageTables: 0 kB Node 17 NFS_Unstable: 0 kB Node 17 Bounce: 0 kB Node 17 WritebackTmp: 0 kB Node 17 KReclaimable: 0 kB Node 17 Slab: 0 kB Node 17 SReclaimable: 0 kB Node 17 SUnreclaim: 0 kB Node 17 AnonHugePages: 79872 kB Node 17 ShmemHugePages: 0 kB Node 17 ShmemPmdMapped: 0 kB Node 17 FileHugePages: 0 kB Node 17 FilePmdMapped: 0 kB Node 17 HugePages_Total: 0 Node 17 HugePages_Free: 0 Node 17 HugePages_Surp: 0 To avoid this exception by refreshing vm_stat, when MemFree is bigger than MemTotal. Signed-off-by: Yang Yingliang --- include/linux/vmstat.h | 1 + mm/show_mem.c | 10 ++++++++++ mm/vmstat.c | 15 ++++++++++----- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index 3c9c266cf782..6a7d2f3757b0 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -259,6 +259,7 @@ extern unsigned long node_page_state(struct pglist_data *pgdat, enum node_stat_item item); extern unsigned long node_page_state_pages(struct pglist_data *pgdat, enum node_stat_item item); +extern int refresh_node_page_state(void); extern void fold_vm_numa_events(void); #else #define sum_zone_node_page_state(node, item) global_zone_page_state(item) diff --git a/mm/show_mem.c b/mm/show_mem.c index 43aca5a2ac99..dc8d2b6056d3 100644 --- a/mm/show_mem.c +++ b/mm/show_mem.c @@ -106,6 +106,16 @@ void si_meminfo_node(struct sysinfo *val, int nid) val->totalram = managed_pages; val->sharedram = node_page_state(pgdat, NR_SHMEM); val->freeram = sum_zone_node_page_state(nid, NR_FREE_PAGES); + if (val->freeram > val->totalram) { + int err = refresh_node_page_state(); + if (err) + val->freeram = val->totalram; + else + val->freeram = sum_zone_node_page_state(nid, NR_FREE_PAGES); + + if (val->freeram > val->totalram) + val->freeram = val->totalram; + } val->totalhigh = managed_highpages; val->freehigh = free_highpages; val->mem_unit = PAGE_SIZE; diff --git a/mm/vmstat.c b/mm/vmstat.c index f534972f517d..96a2e03ec83e 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -881,6 +881,11 @@ static bool refresh_cpu_vm_stats(bool do_pagesets) return changed; } +static void refresh_vm_stats(struct work_struct *work) +{ + refresh_cpu_vm_stats(true); +} + /* * Fold the data for an offline cpu into the global array. * There cannot be any access by the offline cpu and therefore @@ -1024,6 +1029,11 @@ unsigned long node_page_state(struct pglist_data *pgdat, return node_page_state_pages(pgdat, item); } + +int refresh_node_page_state(void) +{ + return schedule_on_each_cpu(refresh_vm_stats); +} #endif /* @@ -1970,11 +1980,6 @@ static int sysctl_stat_interval __read_mostly = HZ; static int vmstat_late_init_done; #ifdef CONFIG_PROC_FS -static void refresh_vm_stats(struct work_struct *work) -{ - refresh_cpu_vm_stats(true); -} - static int vmstat_refresh(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { -- 2.25.1