1222 lines · 32.5 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 <linux/balloon_compaction.h>#include <linux/page-isolation.h>#include "internal.h" #ifdef CONFIG_COMPACTIONstatic inline void count_compact_event(enum vm_event_item item){	count_vm_event(item);} static inline void count_compact_events(enum vm_event_item item, long delta){	count_vm_events(item, delta);}#else#define count_compact_event(item) do { } while (0)#define count_compact_events(item, delta) do { } while (0)#endif #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;} #ifdef CONFIG_COMPACTION/* Returns true if the pageblock should be scanned for pages to isolate. */static inline bool isolation_suitable(struct compact_control *cc,					struct page *page){	if (cc->ignore_skip_hint)		return true; 	return !get_pageblock_skip(page);} /* * This function is called to clear all cached information on pageblocks that * should be skipped for page isolation when the migrate and free page scanner * meet. */static void __reset_isolation_suitable(struct zone *zone){	unsigned long start_pfn = zone->zone_start_pfn;	unsigned long end_pfn = zone_end_pfn(zone);	unsigned long pfn; 	zone->compact_cached_migrate_pfn = start_pfn;	zone->compact_cached_free_pfn = end_pfn;	zone->compact_blockskip_flush = false; 	/* Walk the zone and mark every pageblock as suitable for isolation */	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {		struct page *page; 		cond_resched(); 		if (!pfn_valid(pfn))			continue; 		page = pfn_to_page(pfn);		if (zone != page_zone(page))			continue; 		clear_pageblock_skip(page);	}} void reset_isolation_suitable(pg_data_t *pgdat){	int zoneid; 	for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {		struct zone *zone = &pgdat->node_zones[zoneid];		if (!populated_zone(zone))			continue; 		/* Only flush if a full compaction finished recently */		if (zone->compact_blockskip_flush)			__reset_isolation_suitable(zone);	}} /* * If no pages were isolated then mark this pageblock to be skipped in the * future. The information is later cleared by __reset_isolation_suitable(). */static void update_pageblock_skip(struct compact_control *cc,			struct page *page, unsigned long nr_isolated,			bool migrate_scanner){	struct zone *zone = cc->zone; 	if (cc->ignore_skip_hint)		return; 	if (!page)		return; 	if (!nr_isolated) {		unsigned long pfn = page_to_pfn(page);		set_pageblock_skip(page); 		/* Update where compaction should restart */		if (migrate_scanner) {			if (!cc->finished_update_migrate &&			    pfn > zone->compact_cached_migrate_pfn)				zone->compact_cached_migrate_pfn = pfn;		} else {			if (!cc->finished_update_free &&			    pfn < zone->compact_cached_free_pfn)				zone->compact_cached_free_pfn = pfn;		}	}}#elsestatic inline bool isolation_suitable(struct compact_control *cc,					struct page *page){	return true;} static void update_pageblock_skip(struct compact_control *cc,			struct page *page, unsigned long nr_isolated,			bool migrate_scanner){}#endif /* CONFIG_COMPACTION */ static inline bool should_release_lock(spinlock_t *lock){	return need_resched() || spin_is_contended(lock);} /* * Compaction requires the taking of some coarse locks that are potentially * very heavily contended. Check if the process needs to be scheduled or * if the lock is contended. For async compaction, back out in the event * if contention is severe. For sync compaction, schedule. * * Returns true if the lock is held. * Returns false if the lock is released and compaction should abort */static bool compact_checklock_irqsave(spinlock_t *lock, unsigned long *flags,				      bool locked, struct compact_control *cc){	if (should_release_lock(lock)) {		if (locked) {			spin_unlock_irqrestore(lock, *flags);			locked = false;		} 		/* async aborts if taking too long or contended */		if (!cc->sync) {			cc->contended = true;			return false;		} 		cond_resched();	} 	if (!locked)		spin_lock_irqsave(lock, *flags);	return true;} static inline bool compact_trylock_irqsave(spinlock_t *lock,			unsigned long *flags, struct compact_control *cc){	return compact_checklock_irqsave(lock, flags, false, cc);} /* 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_RESERVE)		return false; 	if (is_migrate_isolate(migratetype))		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;} /* * Isolate free pages onto a private freelist. 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(struct compact_control *cc,				unsigned long blockpfn,				unsigned long end_pfn,				struct list_head *freelist,				bool strict){	int nr_scanned = 0, total_isolated = 0;	struct page *cursor, *valid_page = NULL;	unsigned long nr_strict_required = end_pfn - blockpfn;	unsigned long flags;	bool locked = false; 	cursor = pfn_to_page(blockpfn); 	/* Isolate free pages. */	for (; blockpfn < end_pfn; blockpfn++, cursor++) {		int isolated, i;		struct page *page = cursor; 		nr_scanned++;		if (!pfn_valid_within(blockpfn))			continue;		if (!valid_page)			valid_page = page;		if (!PageBuddy(page))			continue; 		/*		 * The zone lock must be held to isolate freepages.		 * Unfortunately this is a very coarse lock and can be		 * heavily contended if there are parallel allocations		 * or parallel compactions. For async compaction do not		 * spin on the lock and we acquire the lock as late as		 * possible.		 */		locked = compact_checklock_irqsave(&cc->zone->lock, &flags,								locked, cc);		if (!locked)			break; 		/* Recheck this is a suitable migration target under lock */		if (!strict && !suitable_migration_target(page))			break; 		/* Recheck this is a buddy page under lock */		if (!PageBuddy(page))			continue; 		/* Found a free page, break it into order-0 pages */		isolated = split_free_page(page);		if (!isolated && strict)			break;		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); 	/*	 * If strict isolation is requested by CMA then check that all the	 * pages requested were isolated. If there were any failures, 0 is	 * returned and CMA will fail.	 */	if (strict && nr_strict_required > total_isolated)		total_isolated = 0; 	if (locked)		spin_unlock_irqrestore(&cc->zone->lock, flags); 	/* Update the pageblock-skip if the whole pageblock was scanned */	if (blockpfn == end_pfn)		update_pageblock_skip(cc, valid_page, total_isolated, false); 	count_compact_events(COMPACTFREE_SCANNED, nr_scanned);	if (total_isolated)		count_compact_events(COMPACTISOLATED, 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(struct compact_control *cc,			unsigned long start_pfn, unsigned long end_pfn){	unsigned long isolated, pfn, block_end_pfn;	LIST_HEAD(freelist); 	for (pfn = start_pfn; pfn < end_pfn; pfn += isolated) {		if (!pfn_valid(pfn) || cc->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); 		isolated = isolate_freepages_block(cc, pfn, block_end_pfn,						   &freelist, true); 		/*		 * 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, bool locked, 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)]++; 	/* If locked we can use the interrupt unsafe versions */	if (locked) {		__mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);		__mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);	} else {		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. * @unevictable: true if it allows to isolate unevictable pages * * 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, bool unevictable){	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;	unsigned long flags;	bool locked = false;	struct page *page = NULL, *valid_page = NULL; 	/*	 * 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();	for (; low_pfn < end_pfn; low_pfn++) {		/* give a chance to irqs before checking need_resched() */		if (locked && !((low_pfn+1) % SWAP_CLUSTER_MAX)) {			if (should_release_lock(&zone->lru_lock)) {				spin_unlock_irqrestore(&zone->lru_lock, flags);				locked = false;			}		} 		/*		 * 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;			}

Lines 1–500 of 1222.