内存管理-80-PAGE_REPORTING-6.1


一、page report 简介

CONFIG_PAGE_REPORTING —— 空闲页报告机制

1. 一句话总结

Page Reporting 让虚拟机(Guest)告诉宿主机(Host)"哪些物理页我不用了",Host 可以回收这些页面的物理内存给其他虚拟机或自身使用,实现内存超分(overcommit)。

2. 存在意义

在虚拟化环境中:

┌──────────────── Host ────────────────────────┐
│                                              │
│  物理内存 64GB                                │
│                                              │
│  ┌─── VM1 ───┐  ┌─── VM2 ───┐  ┌── VM3 ──┐   │
│  │ 分配 16GB  │  │ 分配 16GB  │  │分配 16GB│   │
│  │ 实际用 8GB │  │ 实际用 12GB│  │实际用 4GB│   │
│  │ 空闲 8GB ↓ │  │ 空闲 4GB  │  │空闲 12GB │   │
│  └───────────┘  └───────────┘  └─────────┘   │
│                                              │
│  问题:VM1 和 VM3 空闲的 20GB,Host 不知道!     │
│  Host 认为 48GB 都被使用了,无法分给新 VM        │
└──────────────────────────────────────────────┘

没有 Page Reporting 时: Guest 释放了内存(free 回 buddy),但 Host 不知道。Host 的 hypervisor 仍为这些页面保留物理内存映射。

有 Page Reporting 时: Guest 释放页面后主动告诉 Host "这些页面我不用了",Host 可以:
(1) 解除这些页面的物理内存映射(释放 Host 的 RAM);
(2) 将这些 RAM 分配给其他 VM 或 Host 进程;
(3) 当 Guest 再次访问这些页面时,Host 按需重新分配(zero-fill fault);


3. 工作原理

3.1 Guest 内核:

__free_one_page(page, ...) 释放页面到 buddy
  └── page_reporting_notify_free(order)     <-- 通知 reporting 子系统
       └── 标记有新的空闲高阶页面可报告

page_reporting_process() 后台工作:
  ├── 扫描 buddy free_list 中 >= 阈值 order 的页面
  ├── 将这些页面从 free_list 临时取出
  ├── 组成一个 scatter-gather list
  ├── 调用 report 回调 --> virtio-balloon / 其他 backend
  │     └── 告诉 Host "这些 GPA(Guest Physical Address) 页面我不用了"
  ├── Host 处理(解除映射/标记为可回收)
  └── 将页面放回 buddy free_list(标记为 "reported")

3.2 与 Balloon 的区别

---------------------------------------------------------------------------------------------------
特性                Balloon(virtio-balloon)            Page Reporting
---------------------------------------------------------------------------------------------------
方向                Host 要求 Guest 交还内存             Guest 主动告知空闲页
Guest 开销          需要实际"充气"占用 Guest 内存         无开销,只报告 buddy 上本就空闲的页面
恢复速度            需要"放气"操作                        Guest 重新分配时自动触发 page fault
粒度                逐页控制                            批量报告高阶空闲块
适用场景            动态调整 VM 内存大小                  透明地回收 Guest 不用的内存
对 Guest 的侵入     有(实际减少 Guest 可用内存)            无(只报告已经空闲的)
---------------------------------------------------------------------------------------------------


4. 核心代码路径

4.1 通知入口(__free_one_page 末尾)

//mm/page_alloc.c — __free_one_page
done_merging:
    add_to_free_list(page, zone, order, migratetype);

    /* 通知 page reporting:有新的空闲高阶页面 */
    if (!(fpi_flags & FPI_SKIP_REPORT_NOTIFY))
        page_reporting_notify_free(order);

4.2 通知实现

//mm/page_reporting.c
void page_reporting_notify_free(unsigned int order)
{
    /* 只报告 >= 阈值 order 的页面(默认 pageblock_order,避免报告碎片), 实测是 11,恒关闭的 */
    if (order >= page_reporting_order)
        schedule_delayed_work(&reporting_work, ...);
}

4.3 报告工作函数

static void page_reporting_process(struct work_struct *work)
{
    for_each_populated_zone(zone) {
        for (order = page_reporting_order; order < MAX_ORDER; order++) {
            for (mt = 0; mt < MIGRATE_TYPES; mt++) {
                /* 从 free_list 取出未报告的页面 */
                page = get_unreported_pages(zone, order, mt);
                /* 组成 scatterlist 批量报告 */
                sg_set_page(&sgl[i], page, PAGE_SIZE << order, 0);
            }
        }
        /* 调用后端驱动的 report 回调 */
        reporting_dev->report(reporting_dev, sgl, nents);
        /* 将页面标记为 "reported" 后放回 free_list */
        put_reported_pages(zone, sgl, nents);
    }
}

4.4 后端注册(virtio-balloon 为例)

//drivers/virtio/virtio_balloon.c
static int virtballoon_free_page_report(struct page_reporting_dev_info *prdev, struct scatterlist *sg, unsigned int nents)
{
    /* 通过 virtio 队列告诉 Host 这些 Guest Physical Addresses 空闲了 */
    virtqueue_add_inbuf(vq, sg, nents, ...);
    virtqueue_kick(vq);
    /* Host 收到后可以解除这些 GPA 对应的 HPA 映射 */
    wait_for_host_ack();
    return 0;
}

/* 注册 */
page_reporting_register(&vb->pr_dev_info);


5. 如何使用

5.1 在 Guest 内核中开启

CONFIG_PAGE_REPORTING=y

这是一个框架,本身不做任何事。需要后端驱动注册 report 回调。

5.2 后端驱动

(1) virtio-balloon(QEMU/KVM 环境):CONFIG_VIRTIO_BALLOON=y + QEMU 开启 free-page-reporting=on;
(2) Hyper-V balloon:Windows Host 环境;
(3) 自定义后端:任何驱动都可以调用 page_reporting_register() 注册;

5.3 QEMU 启动参数示例

qemu-system-aarch64 ... \
    -device virtio-balloon-pci,free-page-reporting=on

Guest 内核中的调优:

# 查看/修改最小报告 order(默认 = pageblock_order = 910), 只有 >= 这个 order 的空闲块才会被报告
cat /sys/kernel/mm/page_reporting/page_reporting_order

# 大 order 报告更高效(一次报告 2MB),但小 order 可以回收更多碎片内存.


6. 总结

----------------------------------------------------------------------------------------------
维度            说明
----------------------------------------------------------------------------------------------
功能            Guest 向 Host 报告空闲物理页面
目标            让 Host 回收 Guest 不用的内存,实现内存超分
适用环境        虚拟化(KVM/QEMU、Hyper-V 等)
裸机上           无效果(无后端注册时零开销)
后端            virtio-balloon、hv-balloon 等
报告阈值        只报告高阶空闲块(>= pageblock_order),避免碎片页面的低效报告
----------------------------------------------------------------------------------------------

对 Guest 的影响 透明——页面仍在 buddy free_list 上,Guest 可以随时再分配


二、功能只是 Linux Guest + Linux Hypervisor 才能使用吗

1. 概述

Page Reporting 不限定 Hypervisor 类型。框架本身是 Linux Guest 内核内部的通用机制,不关心 Hypervisor 是 Linux/QNX/Nebula 还是其他任何东西。

但它需要一个后端驱动把空闲页信息传递给 Hypervisor。目前 Linux 主线内核中只有 virtio-balloon 和 hv_balloon 两个后端——这两个分别对接 KVM/QEMU 和 Hyper-V 的协议。


2. QNX / Nebula(闭源)能否使用

取决于 Hypervisor 侧是否提供了接收空闲页通知的接口。

---------------------------------------------------------------------------------------------------------------------------------
情况                                                                能否使用
---------------------------------------------------------------------------------------------------------------------------------
Nebula 实现了 virtio-balloon 设备(带 free-page-reporting 特性)    ✅ 直接可用,Linux Guest 的 virtio-balloon 驱动自动对接
Nebula 有自定义的 hypercall/共享内存通道但没有 virtio-balloon        需要编写自定义后端驱动注册到 page_reporting 框架
Nebula 完全没有提供此类接口                                            ❌ 无法使用
---------------------------------------------------------------------------------------------------------------------------------

闭源本身不是障碍——Page Reporting 的后端驱动运行在 Linux Guest 内核中(开源侧),只要知道 Hypervisor 的通信协议(hypercall 号、共享内存地址、消息格式)就能编写驱动。关键是 Hypervisor 侧必须有能力接收通知并做出"回收物理页"的动作。

从内核源码中 Nebula 相关模块(virtio_vsock、virtio_blk、virtio_net 等)来看,Nebula 确实实现了 virtio 设备框架。如果它也实现了 virtio-balloon 设备并支持 VIRTIO_BALLOON_F_FREE_PAGE_HINT 特性位,那 Page Reporting 就能开箱即用。建议直接在 Guest 中检查:

# 有没有 virtio-balloon 设备--实测两个都没有
ls /sys/bus/virtio/devices/ | grep balloon
# 或
dmesg | grep -i balloon

 

posted on 2026-08-24 11:41  Hello-World3  阅读(6)  评论(0)    收藏  举报

导航