On 5/13/26 18:50, Gregory Price wrote:
> 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);

Nothing too crazy here, however, the question is which of these values we
actually want to guarantee that we will provide them with unchanged semantics in
the future ... I guess anything we already expose to user space is alright
(because it effectively already must remain mostly unchanged I assume).

-- 
Cheers,

David

Reply via email to