struct page的flags布局

page->flags 虽然只占 8 个字节,但 64 个 bit 位里存了较多的信息,且受若干配置选项的影响,比如内存模型、zone 数量、node 数量等,有必要简单梳理一下。从下面内核源码的注释可以看到,page->flags 的布局一共分为 5 种情况,第2、4种格式只是多了一个 LAST_CPUID 域,可以暂且不看,同时 FLAGS 域相对比较固定,也可以暂且不看,这里需要分析 SECTION、NODE、ZONE 域的去留问题。

内核中对 page->flags 布局的描述:

/*
 * page->flags layout:
 *
 * There are five possibilities for how page->flags get laid out.  The first
 * pair is for the normal case without sparsemem. The second pair is for
 * sparsemem when there is plenty of space for node and section information.
 * The last is when there is insufficient space in page->flags and a separate
 * lookup is necessary.
 *
 * No sparsemem or sparsemem vmemmap: |       NODE     | ZONE |             ... | FLAGS |
 *      " plus space for last_cpupid: |       NODE     | ZONE | LAST_CPUPID ... | FLAGS |
 * classic sparse with space for node:| SECTION | NODE | ZONE |             ... | FLAGS |
 *      " plus space for last_cpupid: | SECTION | NODE | ZONE | LAST_CPUPID ... | FLAGS |
 * classic sparse no space for node:  | SECTION |     ZONE    | ... | FLAGS |
 */

第 1 种格式分为两种情况:

情况一:非稀疏型内存模型

稀疏型内存模型将整个物理地址空间划分成多个区段(section),每个区段由一个 mem_section 描述,因此在 page->flags 中需要存储该页所属的 section_id,但在非稀疏型内存模型中没有 mem_section,所以 page->flags 中不需要存储 section_id。

情况二:vmemmap 稀疏型内存模型

在 sparsemem vmemmap 模型中,page 和 pfn 一一对应,由 page 可以得到 pfn,由 pfn 可以得到 section_id,因此 page->flags 中也不需要存储 section_id。

第 3 种格式:常规稀疏型内存模型

page->flags 需要存储 section_id,同时也存储了 node 和 zone 信息。

第 5 种格式:常规稀疏型内存模型

page->flags 需要存储 section_id 和 zone 信息,但没有空间用来存储 node 信息,因此,在这种情况下存在一个 section_to_node_table[ ] 全局数组,它存储了 section_id 和 node_id 的对应关系,在获取 page 的 node_id 时,先得到 page 的 section_id,再由上述数组查找到 node_id。

section_to_node_table[ ] 数组定义:

#ifdef NODE_NOT_IN_PAGE_FLAGS
/*
 * If we did not store the node number in the page then we have to
 * do a lookup in the section_to_node_table in order to find which
 * node the page belongs to.
 */
#if MAX_NUMNODES <= 256
static u8 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned;
#else
static u16 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned;
#endif
 
int page_to_nid(const struct page *page)
{
    return section_to_node_table[page_to_section(page)];
}
EXPORT_SYMBOL(page_to_nid);
 
static void set_section_nid(unsigned long section_nr, int nid)
{
    section_to_node_table[section_nr] = nid;
}
#else /* !NODE_NOT_IN_PAGE_FLAGS */
static inline void set_section_nid(unsigned long section_nr, int nid)
{
}
#endif

不管是哪种格式,ZONE 域和 FLAGS 域始终是保留的。zone、node、section 信息是在页初始化的时候设置的,其中 zone 信息在 free_area_init_core() 函数中设置完成后不再改变。

pages->flags 的初始化:

static inline void set_page_links(struct page *page, enum zone_type zone,
    unsigned long node, unsigned long pfn)
{                          
    set_page_zone(page, zone);
    set_page_node(page, node);
#ifdef SECTION_IN_PAGE_FLAGS
    set_page_section(page, pfn_to_section_nr(pfn));
#endif                     
}        

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值