906 lines · 23.7 KB · C
RawDownload
/* * linux/mm/compaction.c * * Memory compaction for the reduction of external fragmentation. Note that * this heavily depends upon page migration to do all the real heavy * lifting * * Copyright IBM Corp. 2007-2010 Mel Gorman <mel@csn.ul.ie> */#include <linux/swap.h>#include <linux/migrate.h>#include <linux/compaction.h>#include <linux/mm_inline.h>#include <linux/backing-dev.h>#include <linux/sysctl.h>#include <linux/sysfs.h>#include "internal.h" #if defined CONFIG_COMPACTION || defined CONFIG_CMA #define CREATE_TRACE_POINTS#include <trace/events/compaction.h> static unsigned long release_freepages(struct list_head *freelist){	struct page *page, *next;	unsigned long count = 0; 	list_for_each_entry_safe(page, next, freelist, lru) {		list_del(&page->lru);		__free_page(page);		count++;	} 	return count;} static void map_pages(struct list_head *list){	struct page *page; 	list_for_each_entry(page, list, lru) {		arch_alloc_page(page, 0);		kernel_map_pages(page, 1, 1);	}} static inline bool migrate_async_suitable(int migratetype){	return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE;} /* * Isolate free pages onto a private freelist. Caller must hold zone->lock. * If @strict is true, will abort returning 0 on any invalid PFNs or non-free * pages inside of the pageblock (even though it may still end up isolating * some pages). */static unsigned long isolate_freepages_block(unsigned long blockpfn,				unsigned long end_pfn,				struct list_head *freelist,				bool strict){	int nr_scanned = 0, total_isolated = 0;	struct page *cursor; 	cursor = pfn_to_page(blockpfn); 	/* Isolate free pages. This assumes the block is valid */	for (; blockpfn < end_pfn; blockpfn++, cursor++) {		int isolated, i;		struct page *page = cursor; 		if (!pfn_valid_within(blockpfn)) {			if (strict)				return 0;			continue;		}		nr_scanned++; 		if (!PageBuddy(page)) {			if (strict)				return 0;			continue;		} 		/* Found a free page, break it into order-0 pages */		isolated = split_free_page(page);		if (!isolated && strict)			return 0;		total_isolated += isolated;		for (i = 0; i < isolated; i++) {			list_add(&page->lru, freelist);			page++;		} 		/* If a page was split, advance to the end of it */		if (isolated) {			blockpfn += isolated - 1;			cursor += isolated - 1;		}	} 	trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);	return total_isolated;} /** * isolate_freepages_range() - isolate free pages. * @start_pfn: The first PFN to start isolating. * @end_pfn:   The one-past-last PFN. * * Non-free pages, invalid PFNs, or zone boundaries within the * [start_pfn, end_pfn) range are considered errors, cause function to * undo its actions and return zero. * * Otherwise, function returns one-past-the-last PFN of isolated page * (which may be greater then end_pfn if end fell in a middle of * a free page). */unsigned longisolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn){	unsigned long isolated, pfn, block_end_pfn, flags;	struct zone *zone = NULL;	LIST_HEAD(freelist); 	if (pfn_valid(start_pfn))		zone = page_zone(pfn_to_page(start_pfn)); 	for (pfn = start_pfn; pfn < end_pfn; pfn += isolated) {		if (!pfn_valid(pfn) || zone != page_zone(pfn_to_page(pfn)))			break; 		/*		 * On subsequent iterations ALIGN() is actually not needed,		 * but we keep it that we not to complicate the code.		 */		block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);		block_end_pfn = min(block_end_pfn, end_pfn); 		spin_lock_irqsave(&zone->lock, flags);		isolated = isolate_freepages_block(pfn, block_end_pfn,						   &freelist, true);		spin_unlock_irqrestore(&zone->lock, flags); 		/*		 * In strict mode, isolate_freepages_block() returns 0 if		 * there are any holes in the block (ie. invalid PFNs or		 * non-free pages).		 */		if (!isolated)			break; 		/*		 * If we managed to isolate pages, it is always (1 << n) *		 * pageblock_nr_pages for some non-negative n.  (Max order		 * page may span two pageblocks).		 */	} 	/* split_free_page does not map the pages */	map_pages(&freelist); 	if (pfn < end_pfn) {		/* Loop terminated early, cleanup. */		release_freepages(&freelist);		return 0;	} 	/* We don't use freelists for anything. */	return pfn;} /* Update the number of anon and file isolated pages in the zone */static void acct_isolated(struct zone *zone, struct compact_control *cc){	struct page *page;	unsigned int count[2] = { 0, }; 	list_for_each_entry(page, &cc->migratepages, lru)		count[!!page_is_file_cache(page)]++; 	__mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);	__mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);} /* Similar to reclaim, but different enough that they don't share logic */static bool too_many_isolated(struct zone *zone){	unsigned long active, inactive, isolated; 	inactive = zone_page_state(zone, NR_INACTIVE_FILE) +					zone_page_state(zone, NR_INACTIVE_ANON);	active = zone_page_state(zone, NR_ACTIVE_FILE) +					zone_page_state(zone, NR_ACTIVE_ANON);	isolated = zone_page_state(zone, NR_ISOLATED_FILE) +					zone_page_state(zone, NR_ISOLATED_ANON); 	return isolated > (inactive + active) / 2;} /** * isolate_migratepages_range() - isolate all migrate-able pages in range. * @zone:	Zone pages are in. * @cc:		Compaction control structure. * @low_pfn:	The first PFN of the range. * @end_pfn:	The one-past-the-last PFN of the range. * * Isolate all pages that can be migrated from the range specified by * [low_pfn, end_pfn).  Returns zero if there is a fatal signal * pending), otherwise PFN of the first page that was not scanned * (which may be both less, equal to or more then end_pfn). * * Assumes that cc->migratepages is empty and cc->nr_migratepages is * zero. * * Apart from cc->migratepages and cc->nr_migratetypes this function * does not modify any cc's fields, in particular it does not modify * (or read for that matter) cc->migrate_pfn. */unsigned longisolate_migratepages_range(struct zone *zone, struct compact_control *cc,			   unsigned long low_pfn, unsigned long end_pfn){	unsigned long last_pageblock_nr = 0, pageblock_nr;	unsigned long nr_scanned = 0, nr_isolated = 0;	struct list_head *migratelist = &cc->migratepages;	isolate_mode_t mode = 0;	struct lruvec *lruvec; 	/*	 * Ensure that there are not too many pages isolated from the LRU	 * list by either parallel reclaimers or compaction. If there are,	 * delay for some time until fewer pages are isolated	 */	while (unlikely(too_many_isolated(zone))) {		/* async migration should just abort */		if (!cc->sync)			return 0; 		congestion_wait(BLK_RW_ASYNC, HZ/10); 		if (fatal_signal_pending(current))			return 0;	} 	/* Time to isolate some pages for migration */	cond_resched();	spin_lock_irq(&zone->lru_lock);	for (; low_pfn < end_pfn; low_pfn++) {		struct page *page;		bool locked = true; 		/* give a chance to irqs before checking need_resched() */		if (!((low_pfn+1) % SWAP_CLUSTER_MAX)) {			spin_unlock_irq(&zone->lru_lock);			locked = false;		}		if (need_resched() || spin_is_contended(&zone->lru_lock)) {			if (locked)				spin_unlock_irq(&zone->lru_lock);			cond_resched();			spin_lock_irq(&zone->lru_lock);			if (fatal_signal_pending(current))				break;		} else if (!locked)			spin_lock_irq(&zone->lru_lock); 		/*		 * migrate_pfn does not necessarily start aligned to a		 * pageblock. Ensure that pfn_valid is called when moving		 * into a new MAX_ORDER_NR_PAGES range in case of large		 * memory holes within the zone		 */		if ((low_pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) {			if (!pfn_valid(low_pfn)) {				low_pfn += MAX_ORDER_NR_PAGES - 1;				continue;			}		} 		if (!pfn_valid_within(low_pfn))			continue;		nr_scanned++; 		/*		 * Get the page and ensure the page is within the same zone.		 * See the comment in isolate_freepages about overlapping		 * nodes. It is deliberate that the new zone lock is not taken		 * as memory compaction should not move pages between nodes.		 */		page = pfn_to_page(low_pfn);		if (page_zone(page) != zone)			continue; 		/* Skip if free */		if (PageBuddy(page))			continue; 		/*		 * For async migration, also only scan in MOVABLE blocks. Async		 * migration is optimistic to see if the minimum amount of work		 * satisfies the allocation		 */		pageblock_nr = low_pfn >> pageblock_order;		if (!cc->sync && last_pageblock_nr != pageblock_nr &&		    !migrate_async_suitable(get_pageblock_migratetype(page))) {			low_pfn += pageblock_nr_pages;			low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;			last_pageblock_nr = pageblock_nr;			continue;		} 		if (!PageLRU(page))			continue; 		/*		 * PageLRU is set, and lru_lock excludes isolation,		 * splitting and collapsing (collapsing has already		 * happened if PageLRU is set).		 */		if (PageTransHuge(page)) {			low_pfn += (1 << compound_order(page)) - 1;			continue;		} 		if (!cc->sync)			mode |= ISOLATE_ASYNC_MIGRATE; 		lruvec = mem_cgroup_page_lruvec(page, zone); 		/* Try isolate the page */		if (__isolate_lru_page(page, mode) != 0)			continue; 		VM_BUG_ON(PageTransCompound(page)); 		/* Successfully isolated */		del_page_from_lru_list(page, lruvec, page_lru(page));		list_add(&page->lru, migratelist);		cc->nr_migratepages++;		nr_isolated++; 		/* Avoid isolating too much */		if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) {			++low_pfn;			break;		}	} 	acct_isolated(zone, cc); 	spin_unlock_irq(&zone->lru_lock); 	trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated); 	return low_pfn;} #endif /* CONFIG_COMPACTION || CONFIG_CMA */#ifdef CONFIG_COMPACTION /* Returns true if the page is within a block suitable for migration to */static bool suitable_migration_target(struct page *page){ 	int migratetype = get_pageblock_migratetype(page); 	/* Don't interfere with memory hot-remove or the min_free_kbytes blocks */	if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)		return false; 	/* If the page is a large free page, then allow migration */	if (PageBuddy(page) && page_order(page) >= pageblock_order)		return true; 	/* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */	if (migrate_async_suitable(migratetype))		return true; 	/* Otherwise skip the block */	return false;} /* * Based on information in the current compact_control, find blocks * suitable for isolating free pages from and then isolate them. */static void isolate_freepages(struct zone *zone,				struct compact_control *cc){	struct page *page;	unsigned long high_pfn, low_pfn, pfn, zone_end_pfn, end_pfn;	unsigned long flags;	int nr_freepages = cc->nr_freepages;	struct list_head *freelist = &cc->freepages; 	/*	 * Initialise the free scanner. The starting point is where we last	 * scanned from (or the end of the zone if starting). The low point	 * is the end of the pageblock the migration scanner is using.	 */	pfn = cc->free_pfn;	low_pfn = cc->migrate_pfn + pageblock_nr_pages; 	/*	 * Take care that if the migration scanner is at the end of the zone	 * that the free scanner does not accidentally move to the next zone	 * in the next isolation cycle.	 */	high_pfn = min(low_pfn, pfn); 	zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; 	/*	 * Isolate free pages until enough are available to migrate the	 * pages on cc->migratepages. We stop searching if the migrate	 * and free page scanners meet or enough free pages are isolated.	 */	for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages;					pfn -= pageblock_nr_pages) {		unsigned long isolated; 		if (!pfn_valid(pfn))			continue; 		/*		 * Check for overlapping nodes/zones. It's possible on some		 * configurations to have a setup like		 * node0 node1 node0		 * i.e. it's possible that all pages within a zones range of		 * pages do not belong to a single zone.		 */		page = pfn_to_page(pfn);		if (page_zone(page) != zone)			continue; 		/* Check the block is suitable for migration */		if (!suitable_migration_target(page))			continue; 		/*		 * Found a block suitable for isolating free pages from. Now		 * we disabled interrupts, double check things are ok and		 * isolate the pages. This is to minimise the time IRQs		 * are disabled		 */		isolated = 0;		spin_lock_irqsave(&zone->lock, flags);		if (suitable_migration_target(page)) {			end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);			isolated = isolate_freepages_block(pfn, end_pfn,							   freelist, false);			nr_freepages += isolated;		}		spin_unlock_irqrestore(&zone->lock, flags); 		/*		 * Record the highest PFN we isolated pages from. When next		 * looking for free pages, the search will restart here as		 * page migration may have returned some pages to the allocator		 */		if (isolated)			high_pfn = max(high_pfn, pfn);	} 	/* split_free_page does not map the pages */	map_pages(freelist); 	cc->free_pfn = high_pfn;	cc->nr_freepages = nr_freepages;} /* * This is a migrate-callback that "allocates" freepages by taking pages * from the isolated freelists in the block we are migrating to. */static struct page *compaction_alloc(struct page *migratepage,					unsigned long data,					int **result){	struct compact_control *cc = (struct compact_control *)data;	struct page *freepage; 	/* Isolate free pages if necessary */	if (list_empty(&cc->freepages)) {		isolate_freepages(cc->zone, cc); 		if (list_empty(&cc->freepages))			return NULL;	} 	freepage = list_entry(cc->freepages.next, struct page, lru);	list_del(&freepage->lru);	cc->nr_freepages--; 	return freepage;} 

Lines 1–500 of 906.