阅读 178

alloc_pages的实现浅析

alloc_pages的实现浅析

alloc_pages的使用

struct page *alloc_pages(gft_t gfp, unsigned int order)

alloc_pages定义于 inux/gfp.h 中. 该函数用于分配2^order个 连续 的物理页. 分配失败返回NULL。

alloc_pages的调用链

这里写图片描述

主功能函数

static struct page *get_page_from_freelist(gfp_t gfp_mask, nodemask_t *nodemask, unsigned int order, struct zonelist *zonelist, int high_zoneidx, int alloc_flags,  struct zone *preferred_zone, int migratetype)static inlinestruct page *buffered_rmqueue(struct zone *preferred_zone,
			struct zone *zone, int order, gfp_t gfp_flags,			int migratetype)static struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,						int migratetype)static int rmqueue_bulk(struct zone *zone, unsigned int order, 
			unsigned long count, struct list_head *list,			int migratetype, int cold)

get_page_from_freelist() 遍历整个 zonelist, 如果找到一个watermark满足要求的zone, 就在这个zone上调用 buffered_rmqueue.

struct page *buffered_rmqueue(struct zone *preferred_zone,
			struct zone *zone, int order, gfp_t gfp_flags,			int migratetype){	unsigned long flags;	struct page *page;
	//是否使用cold cache
	int cold = !!(gfp_flags & __GFP_COLD);

again:	//如果要请求页的数量为1
	if (likely(order == 0)) {		struct per_cpu_pages *pcp;
		struct list_head *list;
		//把当前中断状态保存到flags中,然后禁用当前处理器上的中断发送。flags 被直接传递, 而不是通过指针来传递。
		local_irq_save(flags);		//获取本地CPU上的per_cpu_pages结构
		pcp = &this_cpu_ptr(zone->pageset)->pcp;		//获取高速缓冲中页框描述符链表的头指针   
		list = &pcp->lists[migratetype];		//如果链表为空,则向高速缓冲中添加页框
		if (list_empty(list)) {
			pcp->count += rmqueue_bulk(zone, 0,
					pcp->batch, list,
					migratetype, cold);			if (unlikely(list_empty(list)))				goto failed;
		}		if (cold)		// 如果从cold高速缓存中请求页
			page = list_entry(list->prev, struct page, lru);		else
		// 
			page = list_entry(list->next, struct page, lru);		//从LRU链表中删除该页	
		list_del(&page->lru);		//缓存中的页框数减1
		pcp->count--;
	} else {		//保存当前中断状态到flags, 并请求zonelock
		spin_lock_irqsave(&zone->lock, flags);
		page = __rmqueue(zone, order, migratetype);
		spin_unlock(&zone->lock);		if (!page)			goto failed;
		__mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order));
	}

	__count_zone_vm_events(PGALLOC, zone, 1 << order);
	zone_statistics(preferred_zone, zone);
	local_irq_restore(flags);

	VM_BUG_ON(bad_range(zone, page));	if (prep_new_page(page, order, gfp_flags))		goto again;	return page;

failed:
	local_irq_restore(flags);	return NULL;
}
static inlinestruct page *__rmqueue_smallest(struct zone *zone, unsigned int order,						int migratetype)
{
	unsigned int current_order;	struct free_area * area;
	struct page *page;

	//从指定的order开始,寻找一个指向非空free list的free area
	//如果指定的order对应的free area满足要求,则从中返回一个页块
	//否则使用expand进一步处理
	for (current_order = order; current_order < MAX_ORDER; ++current_order) {        //从指定内存区间中获取的起始地址
		area = &(zone->free_area[current_order]);        //判断该空闲区间的指定迁移类型的空闲列表是否为空
        //为空查找下一个块
		if (list_empty(&area->free_list[migratetype]))			continue;
      
		page = list_entry(area->free_list[migratetype].next,
							struct page, lru);        //将该页从LRU链表中删除
		list_del(&page->lru);
		rmv_page_order(page);        //将内存区间的可用页面数减1
		area->nr_free--;		//返回的页块大于请求的页块,将页块的剩余页框分配到其他order的free area
		expand(zone, page, order, current_order, area, migratetype);		return page;
	}	return NULL;
}

假设我们请求分配一个order=2,大小为4的页块,order的最大值是5。 前4个free area都为空。我们从order=5的area得到一个大小为32的页块。所以我们order5的页块分配到order=3和order=4的页块。这时,order2 order3 order4分别得到了大小为4,8和16的页块。
就这样一个32大小的页块被分给了low以上的free area。
这里写图片描述

static inline void expand(struct zone *zone, struct page *page,	int low, int high, struct free_area *area,	int migratetype){	//high为实际分配到的页块的order,此处得到页块的大小
	unsigned long size = 1 << high;	
	while (high > low) {
		area--;
		high--;		//低一级页块的大小为上一级页块大小的1/2
		size >>= 1;
		VM_BUG_ON(bad_range(zone, &page[size]));
		list_add(&page[size].lru, &area->free_list[migratetype]);		//area的可用页块数加一
		area->nr_free++;
		set_page_order(&page[size], high);
	}
}

来源https://www.cnblogs.com/dennis-wong/p/14729447.html

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐