/*简单来说就是如果小块没空间了,就从大块上分配,然后把大块碎裂为n个小块。
然后把其余的小块放到相应分配阶的free_area中。
参数的含义如下 :
zone: 管理区
page: 要归还内存的起始内框 page
index: 在管理区中的序号
low: 欲分配的内框大小
high: 已经分配的内框大小
area: 空闲区
*/
static inline struct page *
expand(struct zone *zone, struct page *page,
unsigned long index, int low, int high, struct free_area *area)
{
// 求得总的内框个数
unsigned long size = 1 << high;
while (high > low) {
area--;
high--;
size >>= 1;
BUG_ON(bad_range(zone, &page[size]));
/*
page[size]:参数传进来的是page*,对于连续为2的high阶的页来说,这也可以看作是元素为page的数组指针
size是1<<high 然后>>1,就是说这个page的数组原来有2^high个元素, page[size]指向第2^high/2个元素,即指向了数组的
中间元素。
这里还要留意分裂后的页是如何并入到下一个分配阶的frea_area中的。是将这个page数组中高的那一半的第一个页(
即 page[size])的lru指针加入到area->free_list[]队列中。
*/
list_add(&page[size].lru, &area->free_list);
// 更正空闲区的页框位图
//1
MARK_USED(index + size, high, area);
}
return page;
}
1 在书中,该处还有两个操作,一个是将area->nr_free++,一个是set_page_order(&page[size],high);
这里可以看出来,我们分配一个N阶的连续页,所得到的只是该连续页中第一个页的指针,即该连续页的
指针,一个指针指向的是多少阶的连续页是通过p[0]->private来指示的。
联想:借此复习一下空闲列表的初始化过程:zone_init_free_lists
static void __meminit zone_init_free_lists(struct zone *zone)
{
int order, t;
for_each_migratetype_order(order, t) {
INIT_LIST_HEAD(&zone->free_area[order].free_list[t]);//free_list是队列头,将指向某个页的lru。
zone->free_area[order].nr_free = 0;
}
}