diff options
Diffstat (limited to 'mm/vmscan.c')
| -rw-r--r-- | mm/vmscan.c | 111 | 
1 files changed, 83 insertions, 28 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 99b434b674c..2624edcfb42 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -553,7 +553,7 @@ void putback_lru_page(struct page *page)  redo:  	ClearPageUnevictable(page); -	if (page_evictable(page, NULL)) { +	if (page_evictable(page)) {  		/*  		 * For evictable pages, we can use the cache.  		 * In event of a race, worst case is we end up with an @@ -587,7 +587,7 @@ redo:  	 * page is on unevictable list, it never be freed. To avoid that,  	 * check after we added it to the list, again.  	 */ -	if (lru == LRU_UNEVICTABLE && page_evictable(page, NULL)) { +	if (lru == LRU_UNEVICTABLE && page_evictable(page)) {  		if (!isolate_lru_page(page)) {  			put_page(page);  			goto redo; @@ -674,8 +674,10 @@ static enum page_references page_check_references(struct page *page,  static unsigned long shrink_page_list(struct list_head *page_list,  				      struct zone *zone,  				      struct scan_control *sc, +				      enum ttu_flags ttu_flags,  				      unsigned long *ret_nr_dirty, -				      unsigned long *ret_nr_writeback) +				      unsigned long *ret_nr_writeback, +				      bool force_reclaim)  {  	LIST_HEAD(ret_pages);  	LIST_HEAD(free_pages); @@ -689,10 +691,10 @@ static unsigned long shrink_page_list(struct list_head *page_list,  	mem_cgroup_uncharge_start();  	while (!list_empty(page_list)) { -		enum page_references references;  		struct address_space *mapping;  		struct page *page;  		int may_enter_fs; +		enum page_references references = PAGEREF_RECLAIM_CLEAN;  		cond_resched(); @@ -707,7 +709,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,  		sc->nr_scanned++; -		if (unlikely(!page_evictable(page, NULL))) +		if (unlikely(!page_evictable(page)))  			goto cull_mlocked;  		if (!sc->may_unmap && page_mapped(page)) @@ -758,7 +760,9 @@ static unsigned long shrink_page_list(struct list_head *page_list,  			wait_on_page_writeback(page);  		} -		references = page_check_references(page, sc); +		if (!force_reclaim) +			references = page_check_references(page, sc); +  		switch (references) {  		case PAGEREF_ACTIVATE:  			goto activate_locked; @@ -788,7 +792,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,  		 * processes. Try to unmap it here.  		 */  		if (page_mapped(page) && mapping) { -			switch (try_to_unmap(page, TTU_UNMAP)) { +			switch (try_to_unmap(page, ttu_flags)) {  			case SWAP_FAIL:  				goto activate_locked;  			case SWAP_AGAIN: @@ -960,6 +964,33 @@ keep:  	return nr_reclaimed;  } +unsigned long reclaim_clean_pages_from_list(struct zone *zone, +					    struct list_head *page_list) +{ +	struct scan_control sc = { +		.gfp_mask = GFP_KERNEL, +		.priority = DEF_PRIORITY, +		.may_unmap = 1, +	}; +	unsigned long ret, dummy1, dummy2; +	struct page *page, *next; +	LIST_HEAD(clean_pages); + +	list_for_each_entry_safe(page, next, page_list, lru) { +		if (page_is_file_cache(page) && !PageDirty(page)) { +			ClearPageActive(page); +			list_move(&page->lru, &clean_pages); +		} +	} + +	ret = shrink_page_list(&clean_pages, zone, &sc, +				TTU_UNMAP|TTU_IGNORE_ACCESS, +				&dummy1, &dummy2, true); +	list_splice(&clean_pages, page_list); +	__mod_zone_page_state(zone, NR_ISOLATED_FILE, -ret); +	return ret; +} +  /*   * Attempt to remove the specified page from its LRU.  Only take this page   * if it is of the appropriate PageActive status.  Pages which are being @@ -978,8 +1009,8 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)  	if (!PageLRU(page))  		return ret; -	/* Do not give back unevictable pages for compaction */ -	if (PageUnevictable(page)) +	/* Compaction should not handle unevictable pages but CMA can do so */ +	if (PageUnevictable(page) && !(mode & ISOLATE_UNEVICTABLE))  		return ret;  	ret = -EBUSY; @@ -1186,7 +1217,7 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)  		VM_BUG_ON(PageLRU(page));  		list_del(&page->lru); -		if (unlikely(!page_evictable(page, NULL))) { +		if (unlikely(!page_evictable(page))) {  			spin_unlock_irq(&zone->lru_lock);  			putback_lru_page(page);  			spin_lock_irq(&zone->lru_lock); @@ -1278,8 +1309,8 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,  	if (nr_taken == 0)  		return 0; -	nr_reclaimed = shrink_page_list(&page_list, zone, sc, -						&nr_dirty, &nr_writeback); +	nr_reclaimed = shrink_page_list(&page_list, zone, sc, TTU_UNMAP, +					&nr_dirty, &nr_writeback, false);  	spin_lock_irq(&zone->lru_lock); @@ -1439,7 +1470,7 @@ static void shrink_active_list(unsigned long nr_to_scan,  		page = lru_to_page(&l_hold);  		list_del(&page->lru); -		if (unlikely(!page_evictable(page, NULL))) { +		if (unlikely(!page_evictable(page))) {  			putback_lru_page(page);  			continue;  		} @@ -1729,6 +1760,28 @@ static bool in_reclaim_compaction(struct scan_control *sc)  	return false;  } +#ifdef CONFIG_COMPACTION +/* + * If compaction is deferred for sc->order then scale the number of pages + * reclaimed based on the number of consecutive allocation failures + */ +static unsigned long scale_for_compaction(unsigned long pages_for_compaction, +			struct lruvec *lruvec, struct scan_control *sc) +{ +	struct zone *zone = lruvec_zone(lruvec); + +	if (zone->compact_order_failed <= sc->order) +		pages_for_compaction <<= zone->compact_defer_shift; +	return pages_for_compaction; +} +#else +static unsigned long scale_for_compaction(unsigned long pages_for_compaction, +			struct lruvec *lruvec, struct scan_control *sc) +{ +	return pages_for_compaction; +} +#endif +  /*   * Reclaim/compaction is used for high-order allocation requests. It reclaims   * order-0 pages before compacting the zone. should_continue_reclaim() returns @@ -1776,6 +1829,9 @@ static inline bool should_continue_reclaim(struct lruvec *lruvec,  	 * inactive lists are large enough, continue reclaiming  	 */  	pages_for_compaction = (2UL << sc->order); + +	pages_for_compaction = scale_for_compaction(pages_for_compaction, +						    lruvec, sc);  	inactive_lru_pages = get_lru_size(lruvec, LRU_INACTIVE_FILE);  	if (nr_swap_pages > 0)  		inactive_lru_pages += get_lru_size(lruvec, LRU_INACTIVE_ANON); @@ -2839,6 +2895,14 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order, int classzone_idx)  		 */  		set_pgdat_percpu_threshold(pgdat, calculate_normal_threshold); +		/* +		 * Compaction records what page blocks it recently failed to +		 * isolate pages from and skips them in the future scanning. +		 * When kswapd is going to sleep, it is reasonable to assume +		 * that pages and compaction may succeed so reset the cache. +		 */ +		reset_isolation_suitable(pgdat); +  		if (!kthread_should_stop())  			schedule(); @@ -3101,9 +3165,9 @@ int kswapd_run(int nid)  	if (IS_ERR(pgdat->kswapd)) {  		/* failure at boot is fatal */  		BUG_ON(system_state == SYSTEM_BOOTING); -		printk("Failed to start kswapd on node %d\n",nid);  		pgdat->kswapd = NULL; -		ret = -1; +		pr_err("Failed to start kswapd on node %d\n", nid); +		ret = PTR_ERR(pgdat->kswapd);  	}  	return ret;  } @@ -3350,27 +3414,18 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)  /*   * page_evictable - test whether a page is evictable   * @page: the page to test - * @vma: the VMA in which the page is or will be mapped, may be NULL   *   * Test whether page is evictable--i.e., should be placed on active/inactive - * lists vs unevictable list.  The vma argument is !NULL when called from the - * fault path to determine how to instantate a new page. + * lists vs unevictable list.   *   * Reasons page might not be evictable:   * (1) page's mapping marked unevictable   * (2) page is part of an mlocked VMA   *   */ -int page_evictable(struct page *page, struct vm_area_struct *vma) +int page_evictable(struct page *page)  { - -	if (mapping_unevictable(page_mapping(page))) -		return 0; - -	if (PageMlocked(page) || (vma && mlocked_vma_newpage(vma, page))) -		return 0; - -	return 1; +	return !mapping_unevictable(page_mapping(page)) && !PageMlocked(page);  }  #ifdef CONFIG_SHMEM @@ -3408,7 +3463,7 @@ void check_move_unevictable_pages(struct page **pages, int nr_pages)  		if (!PageLRU(page) || !PageUnevictable(page))  			continue; -		if (page_evictable(page, NULL)) { +		if (page_evictable(page)) {  			enum lru_list lru = page_lru_base_type(page);  			VM_BUG_ON(PageActive(page));  |