- 简述内核在理想情况下页面分配器(page allocator)是如何分配出连续物理页面的?
使用alloc_pages()函数分配连续的物理页面,分配的页面个数只能是2的整数次幂,传入两个参数,第一个参数为分配掩码,第二个是分配阶数。
- 在页面分配器中,如何从分配掩码中确定哪些zone分配内存
alloc_pages()函数会调用gfp_zone(),该函数根据分配掩码计算出zoneidx并填入alloc_context结构体的.high_zoneidx成员。根据这个zoneidx来确认zone。
static inline enum zone_type gfp_zone(gfp_t flags)
{
enum zone_type z;
int bit = (__force int) (flags & GFP_ZONEMASK);
z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) &
((1 << GFP_ZONES_SHIFT) - 1);
VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
return z;
}
- 页面分配器时按照什么方向来扫描zone的?
首先扫描函数为for_next_zone_zonelist_nodemask。
#define for_next_zone_zonelist_nodemask(zone, z, highidx, nodemask)
for (zone = z->zone;
zone;
z = next_zones_zonelist(++z, highidx, nodemask),
zone = zonelist_zone(z))
有两种zone类型,ZONE_HIGHMEM和ZONE_NORMAL两种,ZONE_HIGHMEM编号为1,ZONE_NORMAL编号为0。
_zonerefs[0]->zone_index=1
_zonerefs[1]->zone_index=0
在分配物理页面时会优先考虑ZONE_HIGHMEM,再分配ZONE_NORMAL。
首先从给定的zoneidx开始扫描,就是alloc_context结构体中的high_zoneidx成员,以分配掩码GFP_KERNEL为例,计算出的high_zoneidx为0,即_zonerefs[0],而这个节点的第一个zone是ZONE_HIGHMEM,其zone编号zone_index为1.也就是说在next_zones_zonelist运行的时候,++z,最终函数会返回ZONE_NORMAL(因为只会循环一次,扫描_zonerefs[1])。遍历ZONE_NORMAL这一个zone。
- 为用户进程分配物理内存,分配掩码应该选择哪个
GFP_USER或者GFP_HIGHUSER