内存管理-5-物理内存数据结构-3-struct page
基于msm-5.4
一、struct page简介
物理页帧,系统中的每个物理页面都有一个与之关联的 struct page,用于跟踪我们当前正在使用该页面的用途。请注意,我们无法跟踪哪些任务正在使用页面,但如果它是页面缓存页面,rmap 结构可以告诉我们谁在映射它。
如果您使用 alloc_pages() 分配页面,则可以将 struct page 中的部分空间用于自己的目的。主联合中的五个字(40B)可用,但第一个字的位 0 除外,必须保持清0。许多用户使用此字来存储指向保证对齐的对象的指针。如果您使用与 page->mapping
相同的存储,则必须在释放页面之前将其恢复为 NULL。
如果您的页面不会映射到用户空间,您也可以使用 mapcount 联合中的四个字节,但必须在释放它之前调用 page_mapcount_reset()。
如果要使用 refcount 字段,则必须以其他 CPU 临时增加然后减少 refcount 的方式使用它,而不会导致问题。从 alloc_pages() 接收页面时,refcount 将为正数。
如果分配 order > 0 的页面,则可以使用每个子页面中的某些字段,但之后可能需要恢复它们的值。
SLUB 使用 cmpxchg_double() 原子更新其空闲列表和计数器。这要求空闲列表和计数器相邻且双字8字节对齐。 我们将所有结构页面对齐到双字边界,
并确保“空闲列表”在结构内对齐。
page结构里面有很多union类型,因为page可以用来表示不同类型的物理内存。
page cache: 页缓存,磁盘在去读写的时候在内存中会有一个缓存,叫页缓存。平时申请的匿名页,也会使用page cache类型表示。
page_pool:
slab:
Tail pages:
Second tail page:
Page table:
系统在初始化的时候,对于每一个物理页帧,都会定义一个 struct page 结构去表示它。比如有一千个页帧,就要定义一千个page结构体,这些page结构体也会存放在内存中,使用 vmemmap 指针指向这个区域。此时物理页帧号pfn和page结构之间就存在了一一对应的关系,因为两者都是线性排列的。
#define __pfn_to_page(pfn) (vmemmap + (pfn)) //返回指针 #define __page_to_pfn(page) (unsigned long)((page) - vmemmap) //参数page是指针
//注:pfn = paddr >> PAGE_SHIFT
1.1 struct page 在内存管理中扮演的角色:
struct page 是物理内存页的元数据载体,其核心作用是为内核提供统一管理物理内存页的基础结构。每个物理页帧(Page Frame)对应一个 struct page 实例,通过它内核可以追踪页的状态、属性及关联信息。
struct page 记录页的物理属性(如是否空闲、脏页、锁定状态等); 系统所有 struct page 组成全局数组 mem_map, 通过页帧号(PFN)可直接索引到对应页的元数据。它在内存回收、LRU链表、反向映射、页缓存与文件映射。
二、成员介绍
//include/linux/mm_types.h struct page { unsigned long flags; /* 此union结构是40B */ union { /* Page cache and anonymous pages 40B */ struct { struct list_head lru; struct address_space *mapping; pgoff_t index; unsigned long private; }; /* page_pool used by netstack 8B */ struct { dma_addr_t dma_addr; }; /* slab, slob and slub 40B */ struct { union { struct list_head slab_list; /* Partial pages */ struct { struct page *next; int pages; int pobjects; }; }; struct kmem_cache *slab_cache; void *freelist; union { void *s_mem; unsigned long counters; struct { unsigned inuse:16; unsigned objects:15; unsigned frozen:1; }; }; }; /* Tail pages of compound page 16B */ struct { unsigned long compound_head; /* First tail page only */ unsigned char compound_dtor; unsigned char compound_order; atomic_t compound_mapcount; }; /* Second tail page of compound page 32B */ struct { unsigned long _compound_pad_1; unsigned long _compound_pad_2; struct list_head deferred_list; }; /* Page table pages 40B */ struct { unsigned long _pt_pad_1; pgtable_t pmd_huge_pte; unsigned long _pt_pad_2; union { struct mm_struct *pt_mm; atomic_t pt_frag_refcount; }; spinlock_t *ptl; }; /* ZONE_DEVICE pages 16B */ struct { struct dev_pagemap *pgmap; void *zone_device_data; }; /* 16B */ struct rcu_head rcu_head; }; /* 4B */ union { atomic_t _mapcount; unsigned int page_type; unsigned int active; int units; }; atomic_t _refcount; struct mem_cgroup *mem_cgroup; //CONFIG_MEMCG int _last_cpupid; } __aligned(2 * sizeof(unsigned long));
__init_single_page() 中在初始化一个page结构之前,先将其清0.
成员介绍:
flags:
set_page_zone()中表明bit63表示此page属于哪个zone,由 set_page_links() 可知,当前配置下,node_id 和 section_id 都没保存在这个flags中。
mapping:
利用指针总是4的整数倍这个特性,成员 mapping 的最低两位用来作为页映射标志,最低位 PAGE_MAPPING_ANON 表示匿名页。如果物理页是匿名页,page.mapping = (struct anon_vma 的地址 | PAGE_MAPPING ANON)。如果物理页是文件页 page.mapping 指向结构体 address_space。
index:
页面的pageblock的迁移类型的缓存值,在将页面放入 pcplist 时使用。在大多数情况下,用于在从 pcplist 释放时避免页面块迁移类型查找. 使用见 get_pcppage_migratetype();
它是在映射里面的偏移,单位是页。如果是匿名映射,那么 index 是物理页对应的虚拟页在虚拟内存区域中的页偏移,如果是文件映射那么 index 是物理页存储的数据在文件中的页偏移。
_mapcount:
是映射计数,反映物理页被映射到多少个虚拟内存区域。初始值是 -1, 加上1以后才是真实的映射计数,建议使用内联函数 page_mapcount() 获取页的映射计数。
三、辅助函数
1. 获取page对应的zone、node、section
//include/linux/mm.h static inline struct zone *page_zone(const struct page *page) { return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)]; } static inline pg_data_t *page_pgdat(const struct page *page) { return NODE_DATA(page_to_nid(page)); } static inline unsigned long page_to_section(const struct page *page) { return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK; //64 0 }
四、其它相关
1. __mm_zero_struct_page() 中有对 struct page 的大小进行检查,必须是 56, 64, 72, 80 这几个大小,否则在编译时报错。
2. page有一组debug trace
trace_page_ref_{set/mod/mod_and_test/mod_and_return/mod_unless/freeze/unfreeze}, 使用见 debug_page_ref.c
posted on 2026-04-02 10:41 Hello-World3 阅读(4) 评论(0) 收藏 举报
浙公网安备 33010602011771号