基础知识点
为什么需要zonelist?
之前bootmem_init初始化的时候,已经初始化了内存节点的zone成员,该成员是一个struct zone数组,存放该内存节点的zone信息。
对于uma系统来说,这已经够了,因为uma系统只有一个本地内存节点,所有zone的信息都存放在本地内存节点的zone成员中。
对于numa系统来说,除了本地内存节点,还可以存在一个或多个远端内存节点,本地内存节点的zone成员并不会存放远端内存节点的zone信息。所以,这里引入zonelist的概念,本地内存节点和远端内存节点的zone统一挂在zonelist链表上。
什么是pageset?
每一个cpu会维护一个boot_pageset成员,这是一个struct per_cpu_pageset结构体,用于描述每个cpu维护的page集合。该函数中只会对pageset做一些最简单的初始化。
代码分析
build_all_zonelists
|----->set_zonelist_order();
| |----->current_zonelist_order = ZONELIST_ORDER_ZONE;
| | 对于uma系统来说,仅存在一个内存节点,所以按zone来排序;对于numa系统来说,可以按node来排序,也可以按zone来排序
|----->build_all_zonelists_init();
| |----->__build_all_zonelists(NULL);
| | |----->pg_data_t *pgdat = NODE_DATA(nid);
| | |----->build_zonelists(pgdat);
| | | |----->zonelist = &pgdat->node_zonelists[ZONELIST_FALLBACK];
| | | |----->j = build_zonelists_node(pgdat, zonelist, 0);
| | | | 遍历该内存节点所有的zone,将所有的zone挂到该内存节点的node_zonelists上去
| | | | |----->zoneref_set_zone(zone, &zonelist->_zonerefs[nr_zones++]);
| | | | |----->return nr_zones;
| | | | | 传进来的nr_zones加上挂到node_zonelists上的zone之后,返回
| | | |----->zonelist->_zonerefs[j].zone = NULL;
| | | |----->zonelist->_zonerefs[j].zone_idx = 0;
| | | | 标记node_zonelists上zone的结束
| | | |----->zonelist->_zonerefs[j].zone = NULL;
| | | |----->zonelist->_zonerefs[j].zone_idx = 0;
| | |----->setup_pageset(&per_cpu(boot_pageset, cpu), 0);
| | | 遍历每一个cpu,初始化其pageset
| | | |----->pageset_init(p);
| | | | |----->pcp->count = 0;
| | | | | page数量初始化为0
| | | | |----->INIT_LIST_HEAD(&pcp->lists[migratetype]);
| | | | | 每一种迁移类型对于一个链表,这里初始化所有迁移类型对应的链表
| | | |----->pageset_set_batch(p, batch);
| | | | |----->pageset_update(&p->pcp, 6 * batch, max(1UL, 1 * batch));
| | | | | |----->pcp->batch = 1;
| | | | | | chunk size初始化为1
| | | | | |----->pcp->high = high;
| | | | | | page上限初始化为0
| | | | | |----->pcp->batch = batch;
| | | | | | chunk size初始化为1