diff options
| author | Jonathan Corbet <[email protected]> | 2016-12-27 12:53:44 -0700 | 
|---|---|---|
| committer | Jonathan Corbet <[email protected]> | 2016-12-27 12:53:44 -0700 | 
| commit | 54ab6db0909061ab7ee07233d3cab86d29f86e6c (patch) | |
| tree | a7650ab5c0fa3a6a3841de8e8693041b3e009054 /mm/page_alloc.c | |
| parent | 217e2bfab22e740227df09f22165e834cddd8a3b (diff) | |
| parent | 7ce7d89f48834cefece7804d38fc5d85382edf77 (diff) | |
Merge tag 'v4.10-rc1' into docs-next
Linux 4.10-rc1
Diffstat (limited to 'mm/page_alloc.c')
| -rw-r--r-- | mm/page_alloc.c | 144 | 
1 files changed, 98 insertions, 46 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 072d791dce2d..2c6d5f64feca 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2058,8 +2058,12 @@ out_unlock:   * potentially hurts the reliability of high-order allocations when under   * intense memory pressure but failed atomic allocations should be easier   * to recover from than an OOM. + * + * If @force is true, try to unreserve a pageblock even though highatomic + * pageblock is exhausted.   */ -static void unreserve_highatomic_pageblock(const struct alloc_context *ac) +static bool unreserve_highatomic_pageblock(const struct alloc_context *ac, +						bool force)  {  	struct zonelist *zonelist = ac->zonelist;  	unsigned long flags; @@ -2067,11 +2071,16 @@ static void unreserve_highatomic_pageblock(const struct alloc_context *ac)  	struct zone *zone;  	struct page *page;  	int order; +	bool ret;  	for_each_zone_zonelist_nodemask(zone, z, zonelist, ac->high_zoneidx,  								ac->nodemask) { -		/* Preserve at least one pageblock */ -		if (zone->nr_reserved_highatomic <= pageblock_nr_pages) +		/* +		 * Preserve at least one pageblock unless memory pressure +		 * is really high. +		 */ +		if (!force && zone->nr_reserved_highatomic <= +					pageblock_nr_pages)  			continue;  		spin_lock_irqsave(&zone->lock, flags); @@ -2085,13 +2094,25 @@ static void unreserve_highatomic_pageblock(const struct alloc_context *ac)  				continue;  			/* -			 * It should never happen but changes to locking could -			 * inadvertently allow a per-cpu drain to add pages -			 * to MIGRATE_HIGHATOMIC while unreserving so be safe -			 * and watch for underflows. +			 * In page freeing path, migratetype change is racy so +			 * we can counter several free pages in a pageblock +			 * in this loop althoug we changed the pageblock type +			 * from highatomic to ac->migratetype. So we should +			 * adjust the count once.  			 */ -			zone->nr_reserved_highatomic -= min(pageblock_nr_pages, -				zone->nr_reserved_highatomic); +			if (get_pageblock_migratetype(page) == +							MIGRATE_HIGHATOMIC) { +				/* +				 * It should never happen but changes to +				 * locking could inadvertently allow a per-cpu +				 * drain to add pages to MIGRATE_HIGHATOMIC +				 * while unreserving so be safe and watch for +				 * underflows. +				 */ +				zone->nr_reserved_highatomic -= min( +						pageblock_nr_pages, +						zone->nr_reserved_highatomic); +			}  			/*  			 * Convert to ac->migratetype and avoid the normal @@ -2103,12 +2124,16 @@ static void unreserve_highatomic_pageblock(const struct alloc_context *ac)  			 * may increase.  			 */  			set_pageblock_migratetype(page, ac->migratetype); -			move_freepages_block(zone, page, ac->migratetype); -			spin_unlock_irqrestore(&zone->lock, flags); -			return; +			ret = move_freepages_block(zone, page, ac->migratetype); +			if (ret) { +				spin_unlock_irqrestore(&zone->lock, flags); +				return ret; +			}  		}  		spin_unlock_irqrestore(&zone->lock, flags);  	} + +	return false;  }  /* Remove an element from the buddy allocator from the fallback list */ @@ -2133,7 +2158,8 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype)  		page = list_first_entry(&area->free_list[fallback_mt],  						struct page, lru); -		if (can_steal) +		if (can_steal && +			get_pageblock_migratetype(page) != MIGRATE_HIGHATOMIC)  			steal_suitable_fallback(zone, page, start_migratetype);  		/* Remove the page from the freelists */ @@ -2192,7 +2218,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,  			unsigned long count, struct list_head *list,  			int migratetype, bool cold)  { -	int i; +	int i, alloced = 0;  	spin_lock(&zone->lock);  	for (i = 0; i < count; ++i) { @@ -2217,13 +2243,21 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,  		else  			list_add_tail(&page->lru, list);  		list = &page->lru; +		alloced++;  		if (is_migrate_cma(get_pcppage_migratetype(page)))  			__mod_zone_page_state(zone, NR_FREE_CMA_PAGES,  					      -(1 << order));  	} + +	/* +	 * i pages were removed from the buddy list even if some leak due +	 * to check_pcp_refill failing so adjust NR_FREE_PAGES based +	 * on i. Do not confuse with 'alloced' which is the number of +	 * pages added to the pcp list. +	 */  	__mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));  	spin_unlock(&zone->lock); -	return i; +	return alloced;  }  #ifdef CONFIG_NUMA @@ -2534,7 +2568,8 @@ int __isolate_free_page(struct page *page, unsigned int order)  		struct page *endpage = page + (1 << order) - 1;  		for (; page < endpage; page += pageblock_nr_pages) {  			int mt = get_pageblock_migratetype(page); -			if (!is_migrate_isolate(mt) && !is_migrate_cma(mt)) +			if (!is_migrate_isolate(mt) && !is_migrate_cma(mt) +				&& mt != MIGRATE_HIGHATOMIC)  				set_pageblock_migratetype(page,  							  MIGRATE_MOVABLE);  		} @@ -3305,7 +3340,7 @@ retry:  	 * Shrink them them and try again  	 */  	if (!page && !drained) { -		unreserve_highatomic_pageblock(ac); +		unreserve_highatomic_pageblock(ac, false);  		drain_all_pages(NULL);  		drained = true;  		goto retry; @@ -3422,8 +3457,10 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,  	 * Make sure we converge to OOM if we cannot make any progress  	 * several times in the row.  	 */ -	if (*no_progress_loops > MAX_RECLAIM_RETRIES) -		return false; +	if (*no_progress_loops > MAX_RECLAIM_RETRIES) { +		/* Before OOM, exhaust highatomic_reserve */ +		return unreserve_highatomic_pageblock(ac, true); +	}  	/*  	 * Keep reclaiming pages while there is a chance this will lead @@ -3658,7 +3695,7 @@ retry:  	/* Make sure we know about allocations which stall for too long */  	if (time_after(jiffies, alloc_start + stall_timeout)) {  		warn_alloc(gfp_mask, -			"page alloction stalls for %ums, order:%u\n", +			"page allocation stalls for %ums, order:%u",  			jiffies_to_msecs(jiffies-alloc_start), order);  		stall_timeout += 10 * HZ;  	} @@ -3888,6 +3925,20 @@ static struct page *__page_frag_refill(struct page_frag_cache *nc,  	return page;  } +void __page_frag_drain(struct page *page, unsigned int order, +		       unsigned int count) +{ +	VM_BUG_ON_PAGE(page_ref_count(page) == 0, page); + +	if (page_ref_sub_and_test(page, count)) { +		if (order == 0) +			free_hot_cold_page(page, false); +		else +			__free_pages_ok(page, order); +	} +} +EXPORT_SYMBOL(__page_frag_drain); +  void *__alloc_page_frag(struct page_frag_cache *nc,  			unsigned int fragsz, gfp_t gfp_mask)  { @@ -6399,8 +6450,8 @@ unsigned long free_reserved_area(void *start, void *end, int poison, char *s)  	}  	if (pages && s) -		pr_info("Freeing %s memory: %ldK (%p - %p)\n", -			s, pages << (PAGE_SHIFT - 10), start, end); +		pr_info("Freeing %s memory: %ldK\n", +			s, pages << (PAGE_SHIFT - 10));  	return pages;  } @@ -6491,38 +6542,39 @@ void __init free_area_init(unsigned long *zones_size)  			__pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL);  } -static int page_alloc_cpu_notify(struct notifier_block *self, -				 unsigned long action, void *hcpu) +static int page_alloc_cpu_dead(unsigned int cpu)  { -	int cpu = (unsigned long)hcpu; -	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { -		lru_add_drain_cpu(cpu); -		drain_pages(cpu); +	lru_add_drain_cpu(cpu); +	drain_pages(cpu); -		/* -		 * Spill the event counters of the dead processor -		 * into the current processors event counters. -		 * This artificially elevates the count of the current -		 * processor. -		 */ -		vm_events_fold_cpu(cpu); +	/* +	 * Spill the event counters of the dead processor +	 * into the current processors event counters. +	 * This artificially elevates the count of the current +	 * processor. +	 */ +	vm_events_fold_cpu(cpu); -		/* -		 * Zero the differential counters of the dead processor -		 * so that the vm statistics are consistent. -		 * -		 * This is only okay since the processor is dead and cannot -		 * race with what we are doing. -		 */ -		cpu_vm_stats_fold(cpu); -	} -	return NOTIFY_OK; +	/* +	 * Zero the differential counters of the dead processor +	 * so that the vm statistics are consistent. +	 * +	 * This is only okay since the processor is dead and cannot +	 * race with what we are doing. +	 */ +	cpu_vm_stats_fold(cpu); +	return 0;  }  void __init page_alloc_init(void)  { -	hotcpu_notifier(page_alloc_cpu_notify, 0); +	int ret; + +	ret = cpuhp_setup_state_nocalls(CPUHP_PAGE_ALLOC_DEAD, +					"mm/page_alloc:dead", NULL, +					page_alloc_cpu_dead); +	WARN_ON(ret < 0);  }  /*  |