⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 page_alloc.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/mm/page_alloc.c * *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds *  Swap reorganised 29.12.95, Stephen Tweedie *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 *  Reshaped it to be a zoned allocator, Ingo Molnar, Red Hat, 1999 *  Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 *  Zone balancing, Kanoj Sarcar, SGI, Jan 2000 */#include <linux/config.h>#include <linux/mm.h>#include <linux/swap.h>#include <linux/swapctl.h>#include <linux/interrupt.h>#include <linux/pagemap.h>#include <linux/bootmem.h>#include <linux/slab.h>#include <linux/compiler.h>int nr_swap_pages;int nr_active_pages;int nr_inactive_pages;struct list_head inactive_list;struct list_head active_list;pg_data_t *pgdat_list;static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };static int zone_balance_ratio[MAX_NR_ZONES] __initdata = { 128, 128, 128, };static int zone_balance_min[MAX_NR_ZONES] __initdata = { 20 , 20, 20, };static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, };/* * Free_page() adds the page to the free lists. This is optimized for * fast normal cases (no error jumps taken normally). * * The way to optimize jumps for gcc-2.2.2 is to: *  - select the "normal" case and put it inside the if () { XXX } *  - no else-statements if you can avoid them * * With the above two rules, you get a straight-line execution path * for the normal case, giving better asm-code. */#define memlist_init(x) INIT_LIST_HEAD(x)#define memlist_add_head list_add#define memlist_add_tail list_add_tail#define memlist_del list_del#define memlist_entry list_entry#define memlist_next(x) ((x)->next)#define memlist_prev(x) ((x)->prev)/* * Temporary debugging check. */#define BAD_RANGE(zone,x) (((zone) != (x)->zone) || (((x)-mem_map) < (zone)->zone_start_mapnr) || (((x)-mem_map) >= (zone)->zone_start_mapnr+(zone)->size))/* * Buddy system. Hairy. You really aren't expected to understand this * * Hint: -mask = 1+~mask */static void FASTCALL(__free_pages_ok (struct page *page, unsigned int order));static void __free_pages_ok (struct page *page, unsigned int order){	unsigned long index, page_idx, mask, flags;	free_area_t *area;	struct page *base;	zone_t *zone;	/* Yes, think what happens when other parts of the kernel take 	 * a reference to a page in order to pin it for io. -ben	 */	if (PageLRU(page))		lru_cache_del(page);	if (page->buffers)		BUG();	if (page->mapping)		BUG();	if (!VALID_PAGE(page))		BUG();	if (PageSwapCache(page))		BUG();	if (PageLocked(page))		BUG();	if (PageLRU(page))		BUG();	if (PageActive(page))		BUG();	page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty));	if (current->flags & PF_FREE_PAGES)		goto local_freelist; back_local_freelist:	zone = page->zone;	mask = (~0UL) << order;	base = zone->zone_mem_map;	page_idx = page - base;	if (page_idx & ~mask)		BUG();	index = page_idx >> (1 + order);	area = zone->free_area + order;	spin_lock_irqsave(&zone->lock, flags);	zone->free_pages -= mask;	while (mask + (1 << (MAX_ORDER-1))) {		struct page *buddy1, *buddy2;		if (area >= zone->free_area + MAX_ORDER)			BUG();		if (!__test_and_change_bit(index, area->map))			/*			 * the buddy page is still allocated.			 */			break;		/*		 * Move the buddy up one level.		 */		buddy1 = base + (page_idx ^ -mask);		buddy2 = base + page_idx;		if (BAD_RANGE(zone,buddy1))			BUG();		if (BAD_RANGE(zone,buddy2))			BUG();		memlist_del(&buddy1->list);		mask <<= 1;		area++;		index >>= 1;		page_idx &= mask;	}	memlist_add_head(&(base + page_idx)->list, &area->free_list);	spin_unlock_irqrestore(&zone->lock, flags);	return; local_freelist:	if (current->nr_local_pages)		goto back_local_freelist;	if (in_interrupt())		goto back_local_freelist;			list_add(&page->list, &current->local_pages);	page->index = order;	current->nr_local_pages++;}#define MARK_USED(index, order, area) \	__change_bit((index) >> (1+(order)), (area)->map)static inline struct page * expand (zone_t *zone, struct page *page,	 unsigned long index, int low, int high, free_area_t * area){	unsigned long size = 1 << high;	while (high > low) {		if (BAD_RANGE(zone,page))			BUG();		area--;		high--;		size >>= 1;		memlist_add_head(&(page)->list, &(area)->free_list);		MARK_USED(index, high, area);		index += size;		page += size;	}	if (BAD_RANGE(zone,page))		BUG();	return page;}static FASTCALL(struct page * rmqueue(zone_t *zone, unsigned int order));static struct page * rmqueue(zone_t *zone, unsigned int order){	free_area_t * area = zone->free_area + order;	unsigned int curr_order = order;	struct list_head *head, *curr;	unsigned long flags;	struct page *page;	spin_lock_irqsave(&zone->lock, flags);	do {		head = &area->free_list;		curr = memlist_next(head);		if (curr != head) {			unsigned int index;			page = memlist_entry(curr, struct page, list);			if (BAD_RANGE(zone,page))				BUG();			memlist_del(curr);			index = page - zone->zone_mem_map;			if (curr_order != MAX_ORDER-1)				MARK_USED(index, curr_order, area);			zone->free_pages -= 1UL << order;			page = expand(zone, page, index, order, curr_order, area);			spin_unlock_irqrestore(&zone->lock, flags);			set_page_count(page, 1);			if (BAD_RANGE(zone,page))				BUG();			if (PageLRU(page))				BUG();			if (PageActive(page))				BUG();			return page;			}		curr_order++;		area++;	} while (curr_order < MAX_ORDER);	spin_unlock_irqrestore(&zone->lock, flags);	return NULL;}#ifndef CONFIG_DISCONTIGMEMstruct page *_alloc_pages(unsigned int gfp_mask, unsigned int order){	return __alloc_pages(gfp_mask, order,		contig_page_data.node_zonelists+(gfp_mask & GFP_ZONEMASK));}#endifstatic struct page * FASTCALL(balance_classzone(zone_t *, unsigned int, unsigned int, int *));static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed){	struct page * page = NULL;	int __freed = 0;	if (!(gfp_mask & __GFP_WAIT))		goto out;	if (in_interrupt())		BUG();	current->allocation_order = order;	current->flags |= PF_MEMALLOC | PF_FREE_PAGES;	__freed = try_to_free_pages(classzone, gfp_mask, order);	current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES);	if (current->nr_local_pages) {		struct list_head * entry, * local_pages;		struct page * tmp;		int nr_pages;		local_pages = &current->local_pages;		if (likely(__freed)) {			/* pick from the last inserted so we're lifo */			entry = local_pages->next;			do {				tmp = list_entry(entry, struct page, list);				if (tmp->index == order && memclass(tmp->zone, classzone)) {					list_del(entry);					current->nr_local_pages--;					set_page_count(tmp, 1);					page = tmp;					if (page->buffers)						BUG();					if (page->mapping)						BUG();					if (!VALID_PAGE(page))						BUG();					if (PageSwapCache(page))						BUG();					if (PageLocked(page))						BUG();					if (PageLRU(page))						BUG();					if (PageActive(page))						BUG();					if (PageDirty(page))						BUG();					break;				}			} while ((entry = entry->next) != local_pages);		}		nr_pages = current->nr_local_pages;		/* free in reverse order so that the global order will be lifo */		while ((entry = local_pages->prev) != local_pages) {			list_del(entry);			tmp = list_entry(entry, struct page, list);			__free_pages_ok(tmp, tmp->index);			if (!nr_pages--)				BUG();		}		current->nr_local_pages = 0;	} out:	*freed = __freed;	return page;}/* * This is the 'heart' of the zoned buddy allocator: */struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist){	unsigned long min;	zone_t **zone, * classzone;	struct page * page;	int freed;	zone = zonelist->zones;	classzone = *zone;	min = 1UL << order;	for (;;) {		zone_t *z = *(zone++);		if (!z)			break;		min += z->pages_low;		if (z->free_pages > min) {			page = rmqueue(z, order);			if (page)				return page;		}	}	classzone->need_balance = 1;	mb();	if (waitqueue_active(&kswapd_wait))		wake_up_interruptible(&kswapd_wait);	zone = zonelist->zones;	min = 1UL << order;	for (;;) {		unsigned long local_min;		zone_t *z = *(zone++);		if (!z)			break;		local_min = z->pages_min;		if (!(gfp_mask & __GFP_WAIT))			local_min >>= 2;		min += local_min;		if (z->free_pages > min) {			page = rmqueue(z, order);			if (page)				return page;		}	}	/* here we're in the low on memory slow path */rebalance:	if (current->flags & (PF_MEMALLOC | PF_MEMDIE)) {		zone = zonelist->zones;		for (;;) {			zone_t *z = *(zone++);			if (!z)				break;			page = rmqueue(z, order);			if (page)				return page;		}		return NULL;	}	/* Atomic allocations - we can't balance anything */	if (!(gfp_mask & __GFP_WAIT))		return NULL;	page = balance_classzone(classzone, gfp_mask, order, &freed);	if (page)		return page;	zone = zonelist->zones;	min = 1UL << order;	for (;;) {		zone_t *z = *(zone++);		if (!z)			break;		min += z->pages_min;		if (z->free_pages > min) {			page = rmqueue(z, order);			if (page)				return page;		}	}	/* Don't let big-order allocations loop */	if (order > 3)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -