When doing proactive ballooning to reduce the size of a guest, some additional vmstat information is useful in deciding how much pressure to exert on the VM and when the VM starts experiencing undesirable behavior (memory and io pressure).
Add 11 new statistics tags to the existing balloon stats virtqueue for improved balloon sizing decisions. Old hosts ignore unknown tags, so no feature negotiation is required. New memory composition stats (bytes): S_DIRTY: dirty pages awaiting writeback S_WRITEBACK: pages under active writeback S_ANON: anonymous pages (for balloon ceiling calculation) S_INACTIVE_FILE: inactive file LRU (safely reclaimable subset of cache) S_SLAB_RECLAIM: reclaimable slab memory New workingset stats (counts): S_WS_REFAULT_A: anon workingset refaults S_WS_REFAULT_F: file workingset refaults New PSI stats (microseconds, cumulative): S_PSI_MEM_SOME: memory pressure (some stalled) S_PSI_MEM_FULL: memory pressure (all stalled) S_PSI_IO_SOME: IO pressure (some stalled) S_PSI_IO_FULL: IO pressure (all stalled) Export psi_system for module builds (CONFIG_VIRTIO_BALLOON=m with CONFIG_PSI=y). Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Gregory Price <[email protected]> --- drivers/virtio/virtio_balloon.c | 33 +++++++++++++++++++++++++++++ include/uapi/linux/virtio_balloon.h | 26 +++++++++++++++++++++-- kernel/sched/psi.c | 1 + 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index f6c2dff33f8a..8fa33aec4ce7 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -18,6 +18,8 @@ #include <linux/wait.h> #include <linux/mm.h> #include <linux/page_reporting.h> +#include <linux/vmstat.h> +#include <linux/psi.h> /* * Balloon device works in 4K page units. So each page is pointed to by @@ -414,6 +416,37 @@ static unsigned int update_balloon_stats(struct virtio_balloon *vb) update_stat(vb, idx++, VIRTIO_BALLOON_S_CACHES, pages_to_bytes(caches)); + update_stat(vb, idx++, VIRTIO_BALLOON_S_DIRTY, + pages_to_bytes(global_node_page_state(NR_FILE_DIRTY))); + update_stat(vb, idx++, VIRTIO_BALLOON_S_WRITEBACK, + pages_to_bytes(global_node_page_state(NR_WRITEBACK))); + update_stat(vb, idx++, VIRTIO_BALLOON_S_ANON, + pages_to_bytes(global_node_page_state(NR_ANON_MAPPED))); + update_stat(vb, idx++, VIRTIO_BALLOON_S_INACTIVE_FILE, + pages_to_bytes(global_node_page_state(NR_INACTIVE_FILE))); + update_stat(vb, idx++, VIRTIO_BALLOON_S_SLAB_RECLAIM, + pages_to_bytes( + global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B))); + update_stat(vb, idx++, VIRTIO_BALLOON_S_WS_REFAULT_A, + global_node_page_state(WORKINGSET_REFAULT_ANON)); + update_stat(vb, idx++, VIRTIO_BALLOON_S_WS_REFAULT_F, + global_node_page_state(WORKINGSET_REFAULT_FILE)); + +#ifdef CONFIG_PSI + update_stat(vb, idx++, VIRTIO_BALLOON_S_PSI_MEM_SOME, + div_u64(psi_system.total[PSI_AVGS][PSI_MEM_SOME], + NSEC_PER_USEC)); + update_stat(vb, idx++, VIRTIO_BALLOON_S_PSI_MEM_FULL, + div_u64(psi_system.total[PSI_AVGS][PSI_MEM_FULL], + NSEC_PER_USEC)); + update_stat(vb, idx++, VIRTIO_BALLOON_S_PSI_IO_SOME, + div_u64(psi_system.total[PSI_AVGS][PSI_IO_SOME], + NSEC_PER_USEC)); + update_stat(vb, idx++, VIRTIO_BALLOON_S_PSI_IO_FULL, + div_u64(psi_system.total[PSI_AVGS][PSI_IO_FULL], + NSEC_PER_USEC)); +#endif + return idx; } diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h index ee35a372805d..37ec8a8466c4 100644 --- a/include/uapi/linux/virtio_balloon.h +++ b/include/uapi/linux/virtio_balloon.h @@ -77,7 +77,18 @@ struct virtio_balloon_config { #define VIRTIO_BALLOON_S_DIRECT_SCAN 13 /* Amount of memory scanned directly */ #define VIRTIO_BALLOON_S_ASYNC_RECLAIM 14 /* Amount of memory reclaimed asynchronously */ #define VIRTIO_BALLOON_S_DIRECT_RECLAIM 15 /* Amount of memory reclaimed directly */ -#define VIRTIO_BALLOON_S_NR 16 +#define VIRTIO_BALLOON_S_DIRTY 16 /* Dirty pages (bytes) */ +#define VIRTIO_BALLOON_S_WRITEBACK 17 /* Pages under writeback (bytes) */ +#define VIRTIO_BALLOON_S_ANON 18 /* Anonymous pages (bytes) */ +#define VIRTIO_BALLOON_S_INACTIVE_FILE 19 /* Inactive file LRU pages (bytes) */ +#define VIRTIO_BALLOON_S_SLAB_RECLAIM 20 /* Reclaimable slab (bytes) */ +#define VIRTIO_BALLOON_S_WS_REFAULT_A 21 /* Workingset refaults anon (count) */ +#define VIRTIO_BALLOON_S_WS_REFAULT_F 22 /* Workingset refaults file (count) */ +#define VIRTIO_BALLOON_S_PSI_MEM_SOME 23 /* PSI memory some total (us) */ +#define VIRTIO_BALLOON_S_PSI_MEM_FULL 24 /* PSI memory full total (us) */ +#define VIRTIO_BALLOON_S_PSI_IO_SOME 25 /* PSI IO some total (us) */ +#define VIRTIO_BALLOON_S_PSI_IO_FULL 26 /* PSI IO full total (us) */ +#define VIRTIO_BALLOON_S_NR 27 #define VIRTIO_BALLOON_S_NAMES_WITH_PREFIX(VIRTIO_BALLOON_S_NAMES_prefix) { \ VIRTIO_BALLOON_S_NAMES_prefix "swap-in", \ @@ -95,7 +106,18 @@ struct virtio_balloon_config { VIRTIO_BALLOON_S_NAMES_prefix "async-scans", \ VIRTIO_BALLOON_S_NAMES_prefix "direct-scans", \ VIRTIO_BALLOON_S_NAMES_prefix "async-reclaims", \ - VIRTIO_BALLOON_S_NAMES_prefix "direct-reclaims" \ + VIRTIO_BALLOON_S_NAMES_prefix "direct-reclaims", \ + VIRTIO_BALLOON_S_NAMES_prefix "dirty", \ + VIRTIO_BALLOON_S_NAMES_prefix "writeback", \ + VIRTIO_BALLOON_S_NAMES_prefix "anon-pages", \ + VIRTIO_BALLOON_S_NAMES_prefix "inactive-file", \ + VIRTIO_BALLOON_S_NAMES_prefix "slab-reclaimable", \ + VIRTIO_BALLOON_S_NAMES_prefix "ws-refault-anon", \ + VIRTIO_BALLOON_S_NAMES_prefix "ws-refault-file", \ + VIRTIO_BALLOON_S_NAMES_prefix "psi-mem-some-us", \ + VIRTIO_BALLOON_S_NAMES_prefix "psi-mem-full-us", \ + VIRTIO_BALLOON_S_NAMES_prefix "psi-io-some-us", \ + VIRTIO_BALLOON_S_NAMES_prefix "psi-io-full-us" \ } #define VIRTIO_BALLOON_S_NAMES VIRTIO_BALLOON_S_NAMES_WITH_PREFIX("") diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index d9c9d9480a45..8ab3aa1c4ef5 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -175,6 +175,7 @@ static DEFINE_PER_CPU(struct psi_group_cpu, system_group_pcpu); struct psi_group psi_system = { .pcpu = &system_group_pcpu, }; +EXPORT_SYMBOL_GPL(psi_system); static DEFINE_PER_CPU(seqcount_t, psi_seq) = SEQCNT_ZERO(psi_seq); -- 2.54.0

