Linux内核打印页属性的接口

在Linux内核中,打印内存页(struct page)属性的常用接口是 dump_page() 函数。该函数能够输出页的详细信息,包括页帧号(PFN)、标志位、映射信息、引用计数等,非常适合调试和分析。

1. dump_page() 接口

  • 功能:打印 struct page 的详细信息到内核日志(通过 dmesg 查看)。
  • 函数原型
    1
    void dump_page(struct page *page, const char *msg);
  • 参数
    • page:目标页的 struct page 指针。
    • msg:自定义信息,用于标识输出内容。
  • 用法示例
    1
    2
    struct page *page = virt_to_page(vaddr);  // 通过虚拟地址获取页
    dump_page(page, "Debugging page info");

2. 手动访问页属性

若需要自定义输出,可直接访问 struct page 的字段或使用内核提供的辅助宏:

  • 常用字段/宏

    1
    2
    3
    4
    printk("Page flags: 0x%lx\n", page->flags);       // 页标志位
    printk("Mapping: %px\n", page->mapping); // 关联的地址映射
    printk("Reference count: %d\n", page_count(page)); // 引用计数
    printk("Dirty? %s\n", PageDirty(page) ? "Yes" : "No"); // 是否脏页
  • 标志位检查宏

    • PageLocked(page): 页是否被锁定。
    • PageDirty(page): 页是否为脏页。
    • PageAnon(page): 是否匿名页。
    • PageSwapBacked(page): 是否有交换支持。

3. 示例内核模块

以下模块演示如何打印首个页帧的信息(注意:实际中需确保页有效):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>

static int __init my_init(void) {
struct page *page;
// 示例:获取 PFN=0 的页(可能不适用所有环境)
page = pfn_to_page(0);
if (page) {
dump_page(page, "Example page dump:");
printk("Reference count: %d\n", page_count(page));
}
return 0;
}

static void __exit my_exit(void) {}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

4. 注意事项

  • 内核版本差异struct page 结构可能随内核版本变化,建议使用官方宏(如 page_count())而非直接访问字段。
  • 安全性:确保目标页有效且未被释放,避免内核崩溃。
  • 调试输出:通过 dmesg 查看输出,使用 CONFIG_DEBUG_VM 配置可启用更详细的内存调试信息。

5. 页表遍历(扩展场景)

若需打印虚拟地址对应的页属性(如页表项标志),可使用页表遍历接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <linux/mm.h>
#include <linux/pagewalk.h>

static int pte_callback(pte_t *pte, unsigned long addr, void *private) {
if (pte_present(*pte)) {
printk("PTE flags: 0x%lx\n", pte_val(*pte) & _PAGE_FLAGS_MASK);
}
return 0;
}

void walk_vma_page_table(struct vm_area_struct *vma) {
struct mm_walk walk = {};
walk.vma = vma;
walk.mm = vma->vm_mm;
walk.pte_entry = pte_callback;
walk_page_range(vma->vm_start, vma->vm_end, &walk);
}

总结

  • 快速调试:直接使用 dump_page() 输出完整页信息。
  • 自定义需求:通过 struct page 字段或辅助宏获取特定属性。
  • 页表属性:结合页表遍历接口检查 PTE 标志。

通过上述方法,您可以在内核开发或调试中有效分析内存页的状态和属性。