Skip to content

Commit 929bea7

Browse files
kosakitorvalds
authored andcommitted
vmscan: all_unreclaimable() use zone->all_unreclaimable as a name
all_unreclaimable check in direct reclaim has been introduced at 2.6.19 by following commit. 2006 Sep 25; commit 408d854; oom: use unreclaimable info And it went through strange history. firstly, following commit broke the logic unintentionally. 2008 Apr 29; commit a41f24e; page allocator: smarter retry of costly-order allocations Two years later, I've found obvious meaningless code fragment and restored original intention by following commit. 2010 Jun 04; commit bb21c7c; vmscan: fix do_try_to_free_pages() return value when priority==0 But, the logic didn't works when 32bit highmem system goes hibernation and Minchan slightly changed the algorithm and fixed it . 2010 Sep 22: commit d190836: vmscan: check all_unreclaimable in direct reclaim path But, recently, Andrey Vagin found the new corner case. Look, struct zone { .. int all_unreclaimable; .. unsigned long pages_scanned; .. } zone->all_unreclaimable and zone->pages_scanned are neigher atomic variables nor protected by lock. Therefore zones can become a state of zone->page_scanned=0 and zone->all_unreclaimable=1. In this case, current all_unreclaimable() return false even though zone->all_unreclaimabe=1. This resulted in the kernel hanging up when executing a loop of the form 1. fork 2. mmap 3. touch memory 4. read memory 5. munmmap as described in http://www.gossamer-threads.com/lists/linux/kernel/1348725#1348725 Is this ignorable minor issue? No. Unfortunately, x86 has very small dma zone and it become zone->all_unreclamble=1 easily. and if it become all_unreclaimable=1, it never restore all_unreclaimable=0. Why? if all_unreclaimable=1, vmscan only try DEF_PRIORITY reclaim and a-few-lru-pages>>DEF_PRIORITY always makes 0. that mean no page scan at all! Eventually, oom-killer never works on such systems. That said, we can't use zone->pages_scanned for this purpose. This patch restore all_unreclaimable() use zone->all_unreclaimable as old. and in addition, to add oom_killer_disabled check to avoid reintroduce the issue of commit d190836 ("vmscan: check all_unreclaimable in direct reclaim path"). Reported-by: Andrey Vagin <[email protected]> Signed-off-by: KOSAKI Motohiro <[email protected]> Cc: Nick Piggin <[email protected]> Reviewed-by: Minchan Kim <[email protected]> Reviewed-by: KAMEZAWA Hiroyuki <[email protected]> Acked-by: David Rientjes <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent fe936df commit 929bea7

File tree

1 file changed

+13
-11
lines changed

1 file changed

+13
-11
lines changed

mm/vmscan.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <linux/memcontrol.h>
4242
#include <linux/delayacct.h>
4343
#include <linux/sysctl.h>
44+
#include <linux/oom.h>
4445

4546
#include <asm/tlbflush.h>
4647
#include <asm/div64.h>
@@ -1988,31 +1989,24 @@ static bool zone_reclaimable(struct zone *zone)
19881989
return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
19891990
}
19901991

1991-
/*
1992-
* As hibernation is going on, kswapd is freezed so that it can't mark
1993-
* the zone into all_unreclaimable. It can't handle OOM during hibernation.
1994-
* So let's check zone's unreclaimable in direct reclaim as well as kswapd.
1995-
*/
1992+
/* All zones in zonelist are unreclaimable? */
19961993
static bool all_unreclaimable(struct zonelist *zonelist,
19971994
struct scan_control *sc)
19981995
{
19991996
struct zoneref *z;
20001997
struct zone *zone;
2001-
bool all_unreclaimable = true;
20021998

20031999
for_each_zone_zonelist_nodemask(zone, z, zonelist,
20042000
gfp_zone(sc->gfp_mask), sc->nodemask) {
20052001
if (!populated_zone(zone))
20062002
continue;
20072003
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
20082004
continue;
2009-
if (zone_reclaimable(zone)) {
2010-
all_unreclaimable = false;
2011-
break;
2012-
}
2005+
if (!zone->all_unreclaimable)
2006+
return false;
20132007
}
20142008

2015-
return all_unreclaimable;
2009+
return true;
20162010
}
20172011

20182012
/*
@@ -2108,6 +2102,14 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
21082102
if (sc->nr_reclaimed)
21092103
return sc->nr_reclaimed;
21102104

2105+
/*
2106+
* As hibernation is going on, kswapd is freezed so that it can't mark
2107+
* the zone into all_unreclaimable. Thus bypassing all_unreclaimable
2108+
* check.
2109+
*/
2110+
if (oom_killer_disabled)
2111+
return 0;
2112+
21112113
/* top priority shrink_zones still had more to do? don't OOM, then */
21122114
if (scanning_global_lru(sc) && !all_unreclaimable(zonelist, sc))
21132115
return 1;

0 commit comments

Comments
 (0)