aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2009-06-16 18:32:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:47:40 -0400
commit7f33d49a2ed546e01f7b1d0607661810f2421859 (patch)
tree8b05ac7ec2cd123efb266ecaa1bf0bd1487158f8
parent75927af8bcb940dad4fe281713d526cb520869ff (diff)
mm, PM/Freezer: Disable OOM killer when tasks are frozen
Currently, the following scenario appears to be possible in theory: * Tasks are frozen for hibernation or suspend. * Free pages are almost exhausted. * Certain piece of code in the suspend code path attempts to allocate some memory using GFP_KERNEL and allocation order less than or equal to PAGE_ALLOC_COSTLY_ORDER. * __alloc_pages_internal() cannot find a free page so it invokes the OOM killer. * The OOM killer attempts to kill a task, but the task is frozen, so it doesn't die immediately. * __alloc_pages_internal() jumps to 'restart', unsuccessfully tries to find a free page and invokes the OOM killer. * No progress can be made. Although it is now hard to trigger during hibernation due to the memory shrinking carried out by the hibernation code, it is theoretically possible to trigger during suspend after the memory shrinking has been removed from that code path. Moreover, since memory allocations are going to be used for the hibernation memory shrinking, it will be even more likely to happen during hibernation. To prevent it from happening, introduce the oom_killer_disabled switch that will cause __alloc_pages_internal() to fail in the situations in which the OOM killer would have been called and make the freezer set this switch after tasks have been successfully frozen. [akpm@linux-foundation.org: be nicer to the namespace] Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Fengguang Wu <fengguang.wu@gmail.com> Cc: David Rientjes <rientjes@google.com> Acked-by: Pavel Machek <pavel@ucw.cz> Cc: Mel Gorman <mel@csn.ul.ie> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/gfp.h12
-rw-r--r--kernel/power/process.c5
-rw-r--r--mm/page_alloc.c4
3 files changed, 21 insertions, 0 deletions
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 4efa33088a82..06b7e8cc80ac 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -243,4 +243,16 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
243void drain_all_pages(void); 243void drain_all_pages(void);
244void drain_local_pages(void *dummy); 244void drain_local_pages(void *dummy);
245 245
246extern bool oom_killer_disabled;
247
248static inline void oom_killer_disable(void)
249{
250 oom_killer_disabled = true;
251}
252
253static inline void oom_killer_enable(void)
254{
255 oom_killer_disabled = false;
256}
257
246#endif /* __LINUX_GFP_H */ 258#endif /* __LINUX_GFP_H */
diff --git a/kernel/power/process.c b/kernel/power/process.c
index ca634019497a..da2072d73811 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -117,9 +117,12 @@ int freeze_processes(void)
117 if (error) 117 if (error)
118 goto Exit; 118 goto Exit;
119 printk("done."); 119 printk("done.");
120
121 oom_killer_disable();
120 Exit: 122 Exit:
121 BUG_ON(in_atomic()); 123 BUG_ON(in_atomic());
122 printk("\n"); 124 printk("\n");
125
123 return error; 126 return error;
124} 127}
125 128
@@ -145,6 +148,8 @@ static void thaw_tasks(bool nosig_only)
145 148
146void thaw_processes(void) 149void thaw_processes(void)
147{ 150{
151 oom_killer_enable();
152
148 printk("Restarting tasks ... "); 153 printk("Restarting tasks ... ");
149 thaw_tasks(true); 154 thaw_tasks(true);
150 thaw_tasks(false); 155 thaw_tasks(false);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 61290ea721c8..5b09488d0f55 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -178,6 +178,8 @@ static void set_pageblock_migratetype(struct page *page, int migratetype)
178 PB_migrate, PB_migrate_end); 178 PB_migrate, PB_migrate_end);
179} 179}
180 180
181bool oom_killer_disabled __read_mostly;
182
181#ifdef CONFIG_DEBUG_VM 183#ifdef CONFIG_DEBUG_VM
182static int page_outside_zone_boundaries(struct zone *zone, struct page *page) 184static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
183{ 185{
@@ -1769,6 +1771,8 @@ rebalance:
1769 */ 1771 */
1770 if (!did_some_progress) { 1772 if (!did_some_progress) {
1771 if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) { 1773 if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
1774 if (oom_killer_disabled)
1775 goto nopage;
1772 page = __alloc_pages_may_oom(gfp_mask, order, 1776 page = __alloc_pages_may_oom(gfp_mask, order,
1773 zonelist, high_zoneidx, 1777 zonelist, high_zoneidx,
1774 nodemask, preferred_zone, 1778 nodemask, preferred_zone,