Re: [PATCH] vmstat: don't auto expand the sysfs files

From: David Rientjes
Date: Thu Dec 14 2023 - 12:52:17 EST


On Mon, 11 Dec 2023, Pasha Tatashin wrote:

> Whenever a new fields are added one of the following: node_stat_item
> numa_stat_item zone_stat_item, the /sys/devices/system/node/nodeX/vmstat
> files are auto expanded.
>
> This is a problem, as sysfs files should be only one value per file.

Does this patch address the one-value-per-file issue? (I think that ship
has sailed for vmstat.)

/sys/devices/system/node/nodeX/vmstat has been documented as a stable ABI
in Linux for 13 years.

That said, the contents of the file has not been documented so I assume
it's "whatever stats make sense for the current implementation of the
Linux VM".

> Also, once a field is exported via vmstat it is hard to remove it as
> there could be user applications that rely on this field. This is why
> we still cary "nr_unstable 0" in /proc/vmstat that is not used.
>

Implementations change over time, so this would be expected.

I'm assuming, but perhaps incorrectly, that userspace won't crash if
nr_unstable just don't appear anymore. That whoever is using it would
just assume that it's zero if it doesn't appear.

So I think we need to answer the question of: are the *contents* of files
like vmstat that are heavily dependent on implementation level details
really part of a stable ABI that people can expect will carry on forever?

> Also, since vmstat is auto-expanded the fields are not documented, so
> users do not know whether they are counted in bytes/kilobytes/pages,
> and the exact meaning of these fields.
>

I think that's actually intended since there can also be ones that are
event counters. I don't think any fields in vmstat are intended to be
long-term sacred stable ABIs.

> Modify the code that the new fields do not auto-expand the vmstat in
> sysfs. The new fields can still be exported via their own files in
> sysfs, and be properly documents.
>
> vmstat values are named using vmstat_text[] array, which contains names
> for zone_stat, numa_stat, node_stat, lru_list, writeback_stat,
> vm_event.
>
> Change vmstat_text[] to be an array of structs that contain two values:
> name, and flags. The new flags field contains information whether to
> show stat value in vmstat files in sysfs (VMSTAT_SHOW_SYSFS), and in
> procfs (VMSTAT_SHOW_PROCFS). The comment above VMSTAT_SHOW_SYSFS
> documents that this flag should not be used for new stat values when
> they are added.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
> ---
> drivers/base/node.c | 34 ++--
> include/linux/vmstat.h | 48 ++++--
> mm/vmstat.c | 377 +++++++++++++++++++++--------------------
> 3 files changed, 244 insertions(+), 215 deletions(-)
>
> Examples of the projects that are currently under review and that add new
> fields to the one of the vmstat items:
>
> [1] mm: report per-page metadata information
> https://lore.kernel.org/all/20231205223118.3575485-1-souravpanda@xxxxxxxxxx
>
> [2] IOMMU memory observability
> https://lore.kernel.org/all/20231130201504.2322355-1-pasha.tatashin@xxxxxxxxxx
>
> Greg KH has been requesting for these files not to grow:
> https://lore.kernel.org/all/2023120731-deception-handmade-8d49@gregkh
>
> diff --git a/drivers/base/node.c b/drivers/base/node.c
> index 493d533f8375..f139d7ab58f5 100644
> --- a/drivers/base/node.c
> +++ b/drivers/base/node.c
> @@ -520,26 +520,34 @@ static ssize_t node_read_vmstat(struct device *dev,
> int i;
> int len = 0;
>
> - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
> - len += sysfs_emit_at(buf, len, "%s %lu\n",
> - zone_stat_name(i),
> - sum_zone_node_page_state(nid, i));
> + for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
> + if (vmstat_text[ZONE_STAT_NAME_IDX(i)].flags & VMSTAT_SHOW_SYSFS) {
> + len += sysfs_emit_at(buf, len, "%s %lu\n",
> + zone_stat_name(i),
> + sum_zone_node_page_state(nid, i));
> + }
> + }
>
> #ifdef CONFIG_NUMA
> fold_vm_numa_events();
> - for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++)
> - len += sysfs_emit_at(buf, len, "%s %lu\n",
> - numa_stat_name(i),
> - sum_zone_numa_event_state(nid, i));
> + for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++) {
> + if (vmstat_text[NUMA_STAT_NAME_IDX(i)].flags & VMSTAT_SHOW_SYSFS) {
> + len += sysfs_emit_at(buf, len, "%s %lu\n",
> + numa_stat_name(i),
> + sum_zone_numa_event_state(nid, i));
> + }
> + }
>
> #endif
> for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
> - unsigned long pages = node_page_state_pages(pgdat, i);
> + if (vmstat_text[NODE_STAT_NAME_IDX(i)].flags & VMSTAT_SHOW_SYSFS) {
> + unsigned long pages = node_page_state_pages(pgdat, i);
>
> - if (vmstat_item_print_in_thp(i))
> - pages /= HPAGE_PMD_NR;
> - len += sysfs_emit_at(buf, len, "%s %lu\n", node_stat_name(i),
> - pages);
> + if (vmstat_item_print_in_thp(i))
> + pages /= HPAGE_PMD_NR;
> + len += sysfs_emit_at(buf, len, "%s %lu\n", node_stat_name(i),
> + pages);
> + }
> }
>
> return len;
> diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
> index fed855bae6d8..2dd46daf69aa 100644
> --- a/include/linux/vmstat.h
> +++ b/include/linux/vmstat.h
> @@ -495,26 +495,44 @@ static inline void __mod_zone_freepage_state(struct zone *zone, int nr_pages,
> __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages);
> }
>
> -extern const char * const vmstat_text[];
>
> +/*
> + * Show this stat in /sys/devices/system/node/nodeX/vmstat
> + * IMPORTANT: Don't use this flag for new stats, as the right way to output only
> + * one stat per file in sysfs. Instead, add new individual sysfs files for new
> + * stats, and document them in Documentation/ABI/TYPE/sysfs-new_field_name.
> + */
> +#define VMSTAT_SHOW_SYSFS BIT(0)
> +
> +/* Show this stat in /proc/vmstat */
> +#define VMSTAT_SHOW_PROCFS BIT(1)
> +
> +struct vmstat_text {
> + const char *name;
> + char flags;
> +};
> +
> +extern const struct vmstat_text vmstat_text[];
> +
> +#define ZONE_STAT_NAME_IDX(item) ((int)(item))
> static inline const char *zone_stat_name(enum zone_stat_item item)
> {
> - return vmstat_text[item];
> + return vmstat_text[ZONE_STAT_NAME_IDX(item)].name;
> }
>
> #ifdef CONFIG_NUMA
> +#define NUMA_STAT_NAME_IDX(item) (NR_VM_ZONE_STAT_ITEMS + (int)(item))
> static inline const char *numa_stat_name(enum numa_stat_item item)
> {
> - return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
> - item];
> + return vmstat_text[NUMA_STAT_NAME_IDX(item)].name;
> }
> #endif /* CONFIG_NUMA */
>
> +#define NODE_STAT_NAME_IDX(item) (NR_VM_NUMA_EVENT_ITEMS + \
> + NR_VM_ZONE_STAT_ITEMS + (int)(item))
> static inline const char *node_stat_name(enum node_stat_item item)
> {
> - return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
> - NR_VM_NUMA_EVENT_ITEMS +
> - item];
> + return vmstat_text[NODE_STAT_NAME_IDX(item)].name;
> }
>
> static inline const char *lru_list_name(enum lru_list lru)
> @@ -522,22 +540,20 @@ static inline const char *lru_list_name(enum lru_list lru)
> return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
> }
>
> +#define WRITEBACK_STAT_NAME_IDX(item) (NR_VM_NODE_STAT_ITEMS + \
> + NR_VM_NUMA_EVENT_ITEMS + NR_VM_ZONE_STAT_ITEMS + (int)(item))
> static inline const char *writeback_stat_name(enum writeback_stat_item item)
> {
> - return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
> - NR_VM_NUMA_EVENT_ITEMS +
> - NR_VM_NODE_STAT_ITEMS +
> - item];
> + return vmstat_text[WRITEBACK_STAT_NAME_IDX(item)].name;
> }
>
> #if defined(CONFIG_VM_EVENT_COUNTERS) || defined(CONFIG_MEMCG)
> +#define VM_EVENT_NAME_IDX(item) (NR_VM_WRITEBACK_STAT_ITEMS + \
> + NR_VM_NODE_STAT_ITEMS + NR_VM_NUMA_EVENT_ITEMS + \
> + NR_VM_ZONE_STAT_ITEMS + (int)(item))
> static inline const char *vm_event_name(enum vm_event_item item)
> {
> - return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
> - NR_VM_NUMA_EVENT_ITEMS +
> - NR_VM_NODE_STAT_ITEMS +
> - NR_VM_WRITEBACK_STAT_ITEMS +
> - item];
> + return vmstat_text[VM_EVENT_NAME_IDX(item)].name;
> }
> #endif /* CONFIG_VM_EVENT_COUNTERS || CONFIG_MEMCG */
>
> diff --git a/mm/vmstat.c b/mm/vmstat.c
> index 359460deb377..691d8c90b4ac 100644
> --- a/mm/vmstat.c
> +++ b/mm/vmstat.c
> @@ -1142,278 +1142,281 @@ int fragmentation_index(struct zone *zone, unsigned int order)
> #if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || \
> defined(CONFIG_NUMA) || defined(CONFIG_MEMCG)
> #ifdef CONFIG_ZONE_DMA
> -#define TEXT_FOR_DMA(xx) xx "_dma",
> +#define TEXT_FOR_DMA(xx) {xx "_dma", VMSTAT_SHOW_PROCFS},
> #else
> #define TEXT_FOR_DMA(xx)
> #endif
>
> #ifdef CONFIG_ZONE_DMA32
> -#define TEXT_FOR_DMA32(xx) xx "_dma32",
> +#define TEXT_FOR_DMA32(xx) {xx "_dma32", VMSTAT_SHOW_PROCFS},
> #else
> #define TEXT_FOR_DMA32(xx)
> #endif
>
> #ifdef CONFIG_HIGHMEM
> -#define TEXT_FOR_HIGHMEM(xx) xx "_high",
> +#define TEXT_FOR_HIGHMEM(xx) {xx "_high", VMSTAT_SHOW_PROCFS},
> #else
> #define TEXT_FOR_HIGHMEM(xx)
> #endif
>
> #ifdef CONFIG_ZONE_DEVICE
> -#define TEXT_FOR_DEVICE(xx) xx "_device",
> +#define TEXT_FOR_DEVICE(xx) {xx "_device", VMSTAT_SHOW_PROCFS},
> #else
> #define TEXT_FOR_DEVICE(xx)
> #endif
>
> -#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
> - TEXT_FOR_HIGHMEM(xx) xx "_movable", \
> - TEXT_FOR_DEVICE(xx)
> +#define TEXT_FOR_NORMAL(xx) {xx "_normal", VMSTAT_SHOW_PROCFS},
> +#define TEXT_FOR_MOVABLE(xx) {xx "_movable", VMSTAT_SHOW_PROCFS},
>
> -const char * const vmstat_text[] = {
> +#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) \
> + TEXT_FOR_NORMAL(xx) TEXT_FOR_HIGHMEM(xx) TEXT_FOR_MOVABLE(xx) \
> + TEXT_FOR_DEVICE(xx)
> +
> +const struct vmstat_text vmstat_text[] = {
> /* enum zone_stat_item counters */
> - "nr_free_pages",
> - "nr_zone_inactive_anon",
> - "nr_zone_active_anon",
> - "nr_zone_inactive_file",
> - "nr_zone_active_file",
> - "nr_zone_unevictable",
> - "nr_zone_write_pending",
> - "nr_mlock",
> - "nr_bounce",
> + {"nr_free_pages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_zone_inactive_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_zone_active_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_zone_inactive_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_zone_active_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_zone_unevictable", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_zone_write_pending", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_mlock", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_bounce", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #if IS_ENABLED(CONFIG_ZSMALLOC)
> - "nr_zspages",
> + {"nr_zspages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #endif
> - "nr_free_cma",
> + {"nr_free_cma", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #ifdef CONFIG_UNACCEPTED_MEMORY
> - "nr_unaccepted",
> + {"nr_unaccepted", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #endif
>
> /* enum numa_stat_item counters */
> #ifdef CONFIG_NUMA
> - "numa_hit",
> - "numa_miss",
> - "numa_foreign",
> - "numa_interleave",
> - "numa_local",
> - "numa_other",
> + {"numa_hit", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"numa_miss", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"numa_foreign", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"numa_interleave", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"numa_local", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"numa_other", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #endif
> -
> /* enum node_stat_item counters */
> - "nr_inactive_anon",
> - "nr_active_anon",
> - "nr_inactive_file",
> - "nr_active_file",
> - "nr_unevictable",
> - "nr_slab_reclaimable",
> - "nr_slab_unreclaimable",
> - "nr_isolated_anon",
> - "nr_isolated_file",
> - "workingset_nodes",
> - "workingset_refault_anon",
> - "workingset_refault_file",
> - "workingset_activate_anon",
> - "workingset_activate_file",
> - "workingset_restore_anon",
> - "workingset_restore_file",
> - "workingset_nodereclaim",
> - "nr_anon_pages",
> - "nr_mapped",
> - "nr_file_pages",
> - "nr_dirty",
> - "nr_writeback",
> - "nr_writeback_temp",
> - "nr_shmem",
> - "nr_shmem_hugepages",
> - "nr_shmem_pmdmapped",
> - "nr_file_hugepages",
> - "nr_file_pmdmapped",
> - "nr_anon_transparent_hugepages",
> - "nr_vmscan_write",
> - "nr_vmscan_immediate_reclaim",
> - "nr_dirtied",
> - "nr_written",
> - "nr_throttled_written",
> - "nr_kernel_misc_reclaimable",
> - "nr_foll_pin_acquired",
> - "nr_foll_pin_released",
> - "nr_kernel_stack",
> + {"nr_inactive_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_active_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_inactive_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_active_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_unevictable", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_slab_reclaimable", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_slab_unreclaimable", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_isolated_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_isolated_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_nodes", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_refault_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_refault_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_activate_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_activate_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_restore_anon", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_restore_file", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"workingset_nodereclaim", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_anon_pages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_mapped", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_file_pages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_dirty", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_writeback", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_writeback_temp", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_shmem", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_shmem_hugepages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_shmem_pmdmapped", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_file_hugepages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_file_pmdmapped", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_anon_transparent_hugepages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_vmscan_write", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_vmscan_immediate_reclaim", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_dirtied", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_written", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_throttled_written", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_kernel_misc_reclaimable", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_foll_pin_acquired", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_foll_pin_released", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_kernel_stack", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #if IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
> - "nr_shadow_call_stack",
> + {"nr_shadow_call_stack", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #endif
> - "nr_page_table_pages",
> - "nr_sec_page_table_pages",
> + {"nr_page_table_pages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"nr_sec_page_table_pages", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #ifdef CONFIG_SWAP
> - "nr_swapcached",
> + {"nr_swapcached", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #endif
> #ifdef CONFIG_NUMA_BALANCING
> - "pgpromote_success",
> - "pgpromote_candidate",
> + {"pgpromote_success", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> + {"pgpromote_candidate", VMSTAT_SHOW_PROCFS | VMSTAT_SHOW_SYSFS},
> #endif
>
> /* enum writeback_stat_item counters */
> - "nr_dirty_threshold",
> - "nr_dirty_background_threshold",
> + {"nr_dirty_threshold", VMSTAT_SHOW_PROCFS},
> + {"nr_dirty_background_threshold", VMSTAT_SHOW_PROCFS},
>
> #if defined(CONFIG_VM_EVENT_COUNTERS) || defined(CONFIG_MEMCG)
> /* enum vm_event_item counters */
> - "pgpgin",
> - "pgpgout",
> - "pswpin",
> - "pswpout",
> + {"pgpgin", VMSTAT_SHOW_PROCFS},
> + {"pgpgout", VMSTAT_SHOW_PROCFS},
> + {"pswpin", VMSTAT_SHOW_PROCFS},
> + {"pswpout", VMSTAT_SHOW_PROCFS},
>
> TEXTS_FOR_ZONES("pgalloc")
> TEXTS_FOR_ZONES("allocstall")
> TEXTS_FOR_ZONES("pgskip")
>
> - "pgfree",
> - "pgactivate",
> - "pgdeactivate",
> - "pglazyfree",
> -
> - "pgfault",
> - "pgmajfault",
> - "pglazyfreed",
> -
> - "pgrefill",
> - "pgreuse",
> - "pgsteal_kswapd",
> - "pgsteal_direct",
> - "pgsteal_khugepaged",
> - "pgdemote_kswapd",
> - "pgdemote_direct",
> - "pgdemote_khugepaged",
> - "pgscan_kswapd",
> - "pgscan_direct",
> - "pgscan_khugepaged",
> - "pgscan_direct_throttle",
> - "pgscan_anon",
> - "pgscan_file",
> - "pgsteal_anon",
> - "pgsteal_file",
> + {"pgfree", VMSTAT_SHOW_PROCFS},
> + {"pgactivate", VMSTAT_SHOW_PROCFS},
> + {"pgdeactivate", VMSTAT_SHOW_PROCFS},
> + {"pglazyfree", VMSTAT_SHOW_PROCFS},
> +
> + {"pgfault", VMSTAT_SHOW_PROCFS},
> + {"pgmajfault", VMSTAT_SHOW_PROCFS},
> + {"pglazyfreed", VMSTAT_SHOW_PROCFS},
> +
> + {"pgrefill", VMSTAT_SHOW_PROCFS},
> + {"pgreuse", VMSTAT_SHOW_PROCFS},
> + {"pgsteal_kswapd", VMSTAT_SHOW_PROCFS},
> + {"pgsteal_direct", VMSTAT_SHOW_PROCFS},
> + {"pgsteal_khugepaged", VMSTAT_SHOW_PROCFS},
> + {"pgdemote_kswapd", VMSTAT_SHOW_PROCFS},
> + {"pgdemote_direct", VMSTAT_SHOW_PROCFS},
> + {"pgdemote_khugepaged", VMSTAT_SHOW_PROCFS},
> + {"pgscan_kswapd", VMSTAT_SHOW_PROCFS},
> + {"pgscan_direct", VMSTAT_SHOW_PROCFS},
> + {"pgscan_khugepaged", VMSTAT_SHOW_PROCFS},
> + {"pgscan_direct_throttle", VMSTAT_SHOW_PROCFS},
> + {"pgscan_anon", VMSTAT_SHOW_PROCFS},
> + {"pgscan_file", VMSTAT_SHOW_PROCFS},
> + {"pgsteal_anon", VMSTAT_SHOW_PROCFS},
> + {"pgsteal_file", VMSTAT_SHOW_PROCFS},
>
> #ifdef CONFIG_NUMA
> - "zone_reclaim_failed",
> + {"zone_reclaim_failed", VMSTAT_SHOW_PROCFS},
> #endif
> - "pginodesteal",
> - "slabs_scanned",
> - "kswapd_inodesteal",
> - "kswapd_low_wmark_hit_quickly",
> - "kswapd_high_wmark_hit_quickly",
> - "pageoutrun",
> + {"pginodesteal", VMSTAT_SHOW_PROCFS},
> + {"slabs_scanned", VMSTAT_SHOW_PROCFS},
> + {"kswapd_inodesteal", VMSTAT_SHOW_PROCFS},
> + {"kswapd_low_wmark_hit_quickly", VMSTAT_SHOW_PROCFS},
> + {"kswapd_high_wmark_hit_quickly", VMSTAT_SHOW_PROCFS},
> + {"pageoutrun", VMSTAT_SHOW_PROCFS},
>
> - "pgrotated",
> + {"pgrotated", VMSTAT_SHOW_PROCFS},
>
> - "drop_pagecache",
> - "drop_slab",
> - "oom_kill",
> + {"drop_pagecache", VMSTAT_SHOW_PROCFS},
> + {"drop_slab", VMSTAT_SHOW_PROCFS},
> + {"oom_kill", VMSTAT_SHOW_PROCFS},
>
> #ifdef CONFIG_NUMA_BALANCING
> - "numa_pte_updates",
> - "numa_huge_pte_updates",
> - "numa_hint_faults",
> - "numa_hint_faults_local",
> - "numa_pages_migrated",
> + {"numa_pte_updates", VMSTAT_SHOW_PROCFS},
> + {"numa_huge_pte_updates", VMSTAT_SHOW_PROCFS},
> + {"numa_hint_faults", VMSTAT_SHOW_PROCFS},
> + {"numa_hint_faults_local", VMSTAT_SHOW_PROCFS},
> + {"numa_pages_migrated", VMSTAT_SHOW_PROCFS},
> #endif
> #ifdef CONFIG_MIGRATION
> - "pgmigrate_success",
> - "pgmigrate_fail",
> - "thp_migration_success",
> - "thp_migration_fail",
> - "thp_migration_split",
> + {"pgmigrate_success", VMSTAT_SHOW_PROCFS},
> + {"pgmigrate_fail", VMSTAT_SHOW_PROCFS},
> + {"thp_migration_success", VMSTAT_SHOW_PROCFS},
> + {"thp_migration_fail", VMSTAT_SHOW_PROCFS},
> + {"thp_migration_split", VMSTAT_SHOW_PROCFS},
> #endif
> #ifdef CONFIG_COMPACTION
> - "compact_migrate_scanned",
> - "compact_free_scanned",
> - "compact_isolated",
> - "compact_stall",
> - "compact_fail",
> - "compact_success",
> - "compact_daemon_wake",
> - "compact_daemon_migrate_scanned",
> - "compact_daemon_free_scanned",
> + {"compact_migrate_scanned", VMSTAT_SHOW_PROCFS},
> + {"compact_free_scanned", VMSTAT_SHOW_PROCFS},
> + {"compact_isolated", VMSTAT_SHOW_PROCFS},
> + {"compact_stall", VMSTAT_SHOW_PROCFS},
> + {"compact_fail", VMSTAT_SHOW_PROCFS},
> + {"compact_success", VMSTAT_SHOW_PROCFS},
> + {"compact_daemon_wake", VMSTAT_SHOW_PROCFS},
> + {"compact_daemon_migrate_scanned", VMSTAT_SHOW_PROCFS},
> + {"compact_daemon_free_scanned", VMSTAT_SHOW_PROCFS},
> #endif
>
> #ifdef CONFIG_HUGETLB_PAGE
> - "htlb_buddy_alloc_success",
> - "htlb_buddy_alloc_fail",
> + {"htlb_buddy_alloc_success", VMSTAT_SHOW_PROCFS},
> + {"htlb_buddy_alloc_fail", VMSTAT_SHOW_PROCFS},
> #endif
> #ifdef CONFIG_CMA
> - "cma_alloc_success",
> - "cma_alloc_fail",
> + {"cma_alloc_success", VMSTAT_SHOW_PROCFS},
> + {"cma_alloc_fail", VMSTAT_SHOW_PROCFS},
> #endif
> - "unevictable_pgs_culled",
> - "unevictable_pgs_scanned",
> - "unevictable_pgs_rescued",
> - "unevictable_pgs_mlocked",
> - "unevictable_pgs_munlocked",
> - "unevictable_pgs_cleared",
> - "unevictable_pgs_stranded",
> + {"unevictable_pgs_culled", VMSTAT_SHOW_PROCFS},
> + {"unevictable_pgs_scanned", VMSTAT_SHOW_PROCFS},
> + {"unevictable_pgs_rescued", VMSTAT_SHOW_PROCFS},
> + {"unevictable_pgs_mlocked", VMSTAT_SHOW_PROCFS},
> + {"unevictable_pgs_munlocked", VMSTAT_SHOW_PROCFS},
> + {"unevictable_pgs_cleared", VMSTAT_SHOW_PROCFS},
> + {"unevictable_pgs_stranded", VMSTAT_SHOW_PROCFS},
>
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> - "thp_fault_alloc",
> - "thp_fault_fallback",
> - "thp_fault_fallback_charge",
> - "thp_collapse_alloc",
> - "thp_collapse_alloc_failed",
> - "thp_file_alloc",
> - "thp_file_fallback",
> - "thp_file_fallback_charge",
> - "thp_file_mapped",
> - "thp_split_page",
> - "thp_split_page_failed",
> - "thp_deferred_split_page",
> - "thp_split_pmd",
> - "thp_scan_exceed_none_pte",
> - "thp_scan_exceed_swap_pte",
> - "thp_scan_exceed_share_pte",
> + {"thp_fault_alloc", VMSTAT_SHOW_PROCFS},
> + {"thp_fault_fallback", VMSTAT_SHOW_PROCFS},
> + {"thp_fault_fallback_charge", VMSTAT_SHOW_PROCFS},
> + {"thp_collapse_alloc", VMSTAT_SHOW_PROCFS},
> + {"thp_collapse_alloc_failed", VMSTAT_SHOW_PROCFS},
> + {"thp_file_alloc", VMSTAT_SHOW_PROCFS},
> + {"thp_file_fallback", VMSTAT_SHOW_PROCFS},
> + {"thp_file_fallback_charge", VMSTAT_SHOW_PROCFS},
> + {"thp_file_mapped", VMSTAT_SHOW_PROCFS},
> + {"thp_split_page", VMSTAT_SHOW_PROCFS},
> + {"thp_split_page_failed", VMSTAT_SHOW_PROCFS},
> + {"thp_deferred_split_page", VMSTAT_SHOW_PROCFS},
> + {"thp_split_pmd", VMSTAT_SHOW_PROCFS},
> + {"thp_scan_exceed_none_pte", VMSTAT_SHOW_PROCFS},
> + {"thp_scan_exceed_swap_pte", VMSTAT_SHOW_PROCFS},
> + {"thp_scan_exceed_share_pte", VMSTAT_SHOW_PROCFS},
> #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
> - "thp_split_pud",
> + {"thp_split_pud", VMSTAT_SHOW_PROCFS},
> #endif
> - "thp_zero_page_alloc",
> - "thp_zero_page_alloc_failed",
> - "thp_swpout",
> - "thp_swpout_fallback",
> + {"thp_zero_page_alloc", VMSTAT_SHOW_PROCFS},
> + {"thp_zero_page_alloc_failed", VMSTAT_SHOW_PROCFS},
> + {"thp_swpout", VMSTAT_SHOW_PROCFS},
> + {"thp_swpout_fallback", VMSTAT_SHOW_PROCFS},
> #endif
> #ifdef CONFIG_MEMORY_BALLOON
> - "balloon_inflate",
> - "balloon_deflate",
> + {"balloon_inflate", VMSTAT_SHOW_PROCFS},
> + {"balloon_deflate", VMSTAT_SHOW_PROCFS},
> #ifdef CONFIG_BALLOON_COMPACTION
> - "balloon_migrate",
> + {"balloon_migrate", VMSTAT_SHOW_PROCFS},
> #endif
> #endif /* CONFIG_MEMORY_BALLOON */
> #ifdef CONFIG_DEBUG_TLBFLUSH
> - "nr_tlb_remote_flush",
> - "nr_tlb_remote_flush_received",
> - "nr_tlb_local_flush_all",
> - "nr_tlb_local_flush_one",
> + {"nr_tlb_remote_flush", VMSTAT_SHOW_PROCFS},
> + {"nr_tlb_remote_flush_received", VMSTAT_SHOW_PROCFS},
> + {"nr_tlb_local_flush_all", VMSTAT_SHOW_PROCFS},
> + {"nr_tlb_local_flush_one", VMSTAT_SHOW_PROCFS},
> #endif /* CONFIG_DEBUG_TLBFLUSH */
>
> #ifdef CONFIG_SWAP
> - "swap_ra",
> - "swap_ra_hit",
> + {"swap_ra", VMSTAT_SHOW_PROCFS},
> + {"swap_ra_hit", VMSTAT_SHOW_PROCFS},
> #ifdef CONFIG_KSM
> - "ksm_swpin_copy",
> + {"ksm_swpin_copy", VMSTAT_SHOW_PROCFS},
> #endif
> #endif
> #ifdef CONFIG_KSM
> - "cow_ksm",
> + {"cow_ksm", VMSTAT_SHOW_PROCFS},
> #endif
> #ifdef CONFIG_ZSWAP
> - "zswpin",
> - "zswpout",
> + {"zswpin", VMSTAT_SHOW_PROCFS},
> + {"zswpout", VMSTAT_SHOW_PROCFS},
> #endif
> #ifdef CONFIG_X86
> - "direct_map_level2_splits",
> - "direct_map_level3_splits",
> + {"direct_map_level2_splits", VMSTAT_SHOW_PROCFS},
> + {"direct_map_level3_splits", VMSTAT_SHOW_PROCFS},
> #endif
> #ifdef CONFIG_PER_VMA_LOCK_STATS
> - "vma_lock_success",
> - "vma_lock_abort",
> - "vma_lock_retry",
> - "vma_lock_miss",
> + {"vma_lock_success", VMSTAT_SHOW_PROCFS},
> + {"vma_lock_abort", VMSTAT_SHOW_PROCFS},
> + {"vma_lock_retry", VMSTAT_SHOW_PROCFS},
> + {"vma_lock_miss", VMSTAT_SHOW_PROCFS},
> #endif
> #endif /* CONFIG_VM_EVENT_COUNTERS || CONFIG_MEMCG */
> };
> +
> #endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA || CONFIG_MEMCG */
>
> #if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)) || \
> @@ -1845,9 +1848,11 @@ static int vmstat_show(struct seq_file *m, void *arg)
> unsigned long *l = arg;
> unsigned long off = l - (unsigned long *)m->private;
>
> - seq_puts(m, vmstat_text[off]);
> - seq_put_decimal_ull(m, " ", *l);
> - seq_putc(m, '\n');
> + if (vmstat_text[off].flags & VMSTAT_SHOW_PROCFS) {
> + seq_puts(m, vmstat_text[off].name);
> + seq_put_decimal_ull(m, " ", *l);
> + seq_putc(m, '\n');
> + }
>
> if (off == NR_VMSTAT_ITEMS - 1) {
> /*
> --
> 2.43.0.472.g3155946c3a-goog
>
>
>