virtio-devices: balloon: add Linux extended statistics tags

Add support for balloon stats tags 10-15, which are Linux kernel
extensions reporting VM memory pressure metrics: OOM kills, allocation
stalls, async/direct page scans, and async/direct page reclaims.

Also downgrade the balloon statistics API request log and the unknown
stats tag warning to debug level to reduce log noise.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Davíð Steinn Geirsson 2026-03-22 12:18:40 +00:00
parent 6ce557ced8
commit 7933f33fa9
3 changed files with 58 additions and 3 deletions

View file

@ -86,6 +86,13 @@ const VIRTIO_BALLOON_S_AVAIL: u16 = 6;
const VIRTIO_BALLOON_S_CACHES: u16 = 7;
const VIRTIO_BALLOON_S_HTLB_PGALLOC: u16 = 8;
const VIRTIO_BALLOON_S_HTLB_PGFAIL: u16 = 9;
// Linux kernel extensions (not yet in the virtio spec).
const VIRTIO_BALLOON_S_OOM_KILL: u16 = 10;
const VIRTIO_BALLOON_S_ALLOC_STALL: u16 = 11;
const VIRTIO_BALLOON_S_ASYNC_SCAN: u16 = 12;
const VIRTIO_BALLOON_S_DIRECT_SCAN: u16 = 13;
const VIRTIO_BALLOON_S_ASYNC_RECLAIM: u16 = 14;
const VIRTIO_BALLOON_S_DIRECT_RECLAIM: u16 = 15;
#[derive(Error, Debug)]
pub enum Error {
@ -201,6 +208,18 @@ pub struct BalloonStatistics {
pub hugetlb_allocations: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hugetlb_failures: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub oom_kills: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub alloc_stalls: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub async_scans: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub direct_scans: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub async_reclaims: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub direct_reclaims: Option<u64>,
}
pub struct BalloonStatsState {
@ -445,8 +464,14 @@ impl BalloonEpollHandler {
VIRTIO_BALLOON_S_CACHES => stats.disk_caches = Some(val),
VIRTIO_BALLOON_S_HTLB_PGALLOC => stats.hugetlb_allocations = Some(val),
VIRTIO_BALLOON_S_HTLB_PGFAIL => stats.hugetlb_failures = Some(val),
VIRTIO_BALLOON_S_OOM_KILL => stats.oom_kills = Some(val),
VIRTIO_BALLOON_S_ALLOC_STALL => stats.alloc_stalls = Some(val),
VIRTIO_BALLOON_S_ASYNC_SCAN => stats.async_scans = Some(val),
VIRTIO_BALLOON_S_DIRECT_SCAN => stats.direct_scans = Some(val),
VIRTIO_BALLOON_S_ASYNC_RECLAIM => stats.async_reclaims = Some(val),
VIRTIO_BALLOON_S_DIRECT_RECLAIM => stats.direct_reclaims = Some(val),
_ => {
log::warn!("Unknown balloon stats tag: {tag}");
log::debug!("Unknown balloon stats tag: {tag}");
}
}
offset += entry_size as u64;

View file

@ -36,7 +36,7 @@ pub mod http;
use std::io;
use std::sync::mpsc::{RecvError, SendError, Sender, channel};
use log::info;
use log::{debug, info};
use micro_http::Body;
use serde::{Deserialize, Serialize};
use thiserror::Error;
@ -895,7 +895,7 @@ impl ApiAction for VmBalloonStatistics {
fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest {
Box::new(move |vmm| {
info!("API request event: VmBalloonStatistics");
debug!("API request event: VmBalloonStatistics");
let response = vmm
.vm_balloon_statistics()
.map_err(ApiError::VmBalloonStatistics)

View file

@ -1102,6 +1102,36 @@ components:
type: integer
format: int64
nullable: true
oom_kills:
description: Number of OOM killer invocations
type: integer
format: int64
nullable: true
alloc_stalls:
description: Number of memory allocation stalls
type: integer
format: int64
nullable: true
async_scans:
description: Amount of memory scanned asynchronously by kswapd (pages)
type: integer
format: int64
nullable: true
direct_scans:
description: Amount of memory scanned by direct reclaim (pages)
type: integer
format: int64
nullable: true
async_reclaims:
description: Amount of memory reclaimed asynchronously by kswapd (pages)
type: integer
format: int64
nullable: true
direct_reclaims:
description: Amount of memory reclaimed by direct reclaim (pages)
type: integer
format: int64
nullable: true
balloon_actual_bytes:
description: Current balloon size in bytes (guest-confirmed)
type: integer