diff options
Diffstat (limited to 'mm/memory-failure.c')
| -rw-r--r-- | mm/memory-failure.c | 36 | 
1 files changed, 22 insertions, 14 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 6c5899b9034..108c52fa60f 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -781,16 +781,16 @@ static struct page_state {  	{ compound,	compound,	"huge",		me_huge_page },  #endif -	{ sc|dirty,	sc|dirty,	"swapcache",	me_swapcache_dirty }, -	{ sc|dirty,	sc,		"swapcache",	me_swapcache_clean }, +	{ sc|dirty,	sc|dirty,	"dirty swapcache",	me_swapcache_dirty }, +	{ sc|dirty,	sc,		"clean swapcache",	me_swapcache_clean }, -	{ unevict|dirty, unevict|dirty,	"unevictable LRU", me_pagecache_dirty}, -	{ unevict,	unevict,	"unevictable LRU", me_pagecache_clean}, +	{ unevict|dirty, unevict|dirty,	"dirty unevictable LRU", me_pagecache_dirty }, +	{ unevict,	unevict,	"clean unevictable LRU", me_pagecache_clean }, -	{ mlock|dirty,	mlock|dirty,	"mlocked LRU",	me_pagecache_dirty }, -	{ mlock,	mlock,		"mlocked LRU",	me_pagecache_clean }, +	{ mlock|dirty,	mlock|dirty,	"dirty mlocked LRU",	me_pagecache_dirty }, +	{ mlock,	mlock,		"clean mlocked LRU",	me_pagecache_clean }, -	{ lru|dirty,	lru|dirty,	"LRU",		me_pagecache_dirty }, +	{ lru|dirty,	lru|dirty,	"dirty LRU",	me_pagecache_dirty },  	{ lru|dirty,	lru,		"clean LRU",	me_pagecache_clean },  	/* @@ -812,14 +812,14 @@ static struct page_state {  #undef slab  #undef reserved +/* + * "Dirty/Clean" indication is not 100% accurate due to the possibility of + * setting PG_dirty outside page lock. See also comment above set_page_dirty(). + */  static void action_result(unsigned long pfn, char *msg, int result)  { -	struct page *page = pfn_to_page(pfn); - -	printk(KERN_ERR "MCE %#lx: %s%s page recovery: %s\n", -		pfn, -		PageDirty(page) ? "dirty " : "", -		msg, action_name[result]); +	pr_err("MCE %#lx: %s page recovery: %s\n", +		pfn, msg, action_name[result]);  }  static int page_action(struct page_state *ps, struct page *p, @@ -1385,7 +1385,7 @@ static int get_any_page(struct page *p, unsigned long pfn, int flags)  	 * Isolate the page, so that it doesn't get reallocated if it  	 * was free.  	 */ -	set_migratetype_isolate(p); +	set_migratetype_isolate(p, true);  	/*  	 * When the target page is a free hugepage, just remove it  	 * from free hugepage list. @@ -1476,9 +1476,17 @@ int soft_offline_page(struct page *page, int flags)  {  	int ret;  	unsigned long pfn = page_to_pfn(page); +	struct page *hpage = compound_trans_head(page);  	if (PageHuge(page))  		return soft_offline_huge_page(page, flags); +	if (PageTransHuge(hpage)) { +		if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) { +			pr_info("soft offline: %#lx: failed to split THP\n", +				pfn); +			return -EBUSY; +		} +	}  	ret = get_any_page(page, pfn, flags);  	if (ret < 0)  |