oom: various fixes and improvements for 2.6.18-rc2
Subsystems (4)
cover oom: various fixes and improvements for 2.6.18-rc2
These are some various OOM killer fixes that I have accumulated. Some of the more important ones are in SLES10, and were developed in response to issues coming up in stress testing.
The other small fixes haven't been widely tested, but they're issues I spotted when working in this area.
Comments?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/9 oom: use unreclaimable info
__alloc_pages currently starts shooting if page reclaim has failed to free up swap_cluster_max pages in one run through the priorities. This is not always a good indicator on its own, so make use of the all_unreclaimable logic as
well: don't consider going OOM until all zones we're interested in are unreclaimable.
mm/vmscan.c +8 -0
@@ -62,6 +62,8 @@ struct scan_control {int swap_cluster_max;int swappiness; + +int all_unreclaimable; };/*
@@ -925,6 +927,7 @@ static unsigned long shrink_zones(int prunsigned long nr_reclaimed =0 ;int i; + sc->all_unreclaimable =1 ;for (i =0 ; zones[i] !=NULL ; i++) {struct zone *zone = zones[i];
@@ -941,6 +944,8 @@ static unsigned long shrink_zones(int prif (zone->all_unreclaimable && priority !=DEF_PRIORITY )continue ;/* Let kswapd poll it */ + sc->all_unreclaimable =0 ; + nr_reclaimed +=shrink_zone (priority, zone, sc); }return nr_reclaimed;
@@ -1021,6 +1026,9 @@ unsigned long try_to_free_pages(struct zif (sc.nr_scanned && priority <DEF_PRIORITY -2 )blk_congestion_wait (WRITE ,HZ /10 ); } +/* top priority shrink_caches still had more to do? don't OOM, then */ +if (!sc.all_unreclaimable) + ret =1 ; out:for (i =0 ; zones[i] !=0 ; i++) {struct zone *zone = zones[i];
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/9 oom: reclaim_mapped on oom
In reply to Nick PigginPotentially it takes several scans of the lru lists before we can even start reclaiming pages.
mapped pages, with young ptes can take 2 passes on the active list + one on the inactive list. But reclaim_mapped may not always kick in instantly, so it could take even more than that.
Raise the threshold for marking a zone as all_unreclaimable from a factor of 4 time the pages in the zone to 6. Introduce a mechanism to force reclaim_mapped if we've reached a factor 3 and still haven't made progress.
Previously, a customer doing stress testing was able to easily OOM the box after using only a small fraction of its swap (~100MB). After the patches, it would only OOM after having used up all swap (~800MB).
mm/vmscan.c +10 -1
@@ -697,6 +697,11 @@ done:return nr_reclaimed; } +static inline int zone_is_near_oom (struct zone *zone) +{ +return zone->pages_scanned >= (zone->nr_active + zone->nr_inactive)*3 ; +} +/* * This moves pages from the active list to the inactive list. *
@@ -732,6 +737,9 @@ static void shrink_active_list(unsignedlong distress;long swap_tendency; +if (zone_is_near_oom (zone)) + goto force_reclaim_mapped; +/* * `distress' is a measure of how much trouble we're having * reclaiming pages. 0 -> no problems. 100 -> great trouble.
@@ -767,6 +775,7 @@ static void shrink_active_list(unsigned* memory onto the inactive list. */ if (swap_tendency >=100 ) +force_reclaim_mapped: reclaim_mapped =1 ; }
@@ -1161,7 +1170,7 @@ scan:if (zone->all_unreclaimable)continue ;if (nr_slab ==0 && zone->pages_scanned >= - (zone->nr_active + zone->nr_inactive) *4 ) + (zone->nr_active + zone->nr_inactive) *6 ) zone->all_unreclaimable =1 ;/* * If we've done a decent amount of scanning and
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/9 cpuset: oom panic fix
In reply to Nick Piggincpuset_excl_nodes_overlap always returns 0 if current is exiting. This caused customer's systems to panic in the OOM killer when processes were having trouble getting memory for the final put_user in mm_release. Even though there were lots of processes to kill.
Change to returning 0 in this case. This achieves parity with !CONFIG_CPUSETS case, and was observed to fix the problem.
kernel/cpuset.c +1 -1
@@ -2369,7 +2369,7 @@ EXPORT_SYMBOL_GPL(cpuset_mem_spread_nodeint cpuset_excl_nodes_overlap (const struct task_struct *p) {const struct cpuset *cs1, *cs2;/* my and p's cpuset ancestors */ -int overlap =0 ;/* do cpusets overlap? */ +int overlap =1 ;/* do cpusets overlap? */ task_lock (current);if (current->flags &PF_EXITING ) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/9] cpuset: oom panic fix
Quoted 9 lines · Nick Piggin
cpuset_excl_nodes_overlapalways returns 0 if current is exiting. This caused customer's systems to panic in the OOM killer when processes were having trouble getting memory for the finalput_userinmm_release. Even though there were lots of processes to kill.Change to returning 0 in this case. This achieves parity with !CONFIG_CPUSETS case, and was observed to fix the problem.
Signed-off-by Nick Piggin <[email protected]>
I forgot to mention, I think this one was also Acked-by: Paul Jackson. CCing him...
Quoted 6 lines
Index:
linux-2.6/kernel/cpuset.c
===================================================================
kernel/cpuset.c EXPORT_SYMBOL_GPL(cpuset_mem_spread_node · line 2375
Quoted 8 lines
kernel/cpuset.c +1
-1@@ -2369,7 +2369,7 @@ EXPORT_SYMBOL_GPL(cpuset_mem_spread_nodeint cpuset_excl_nodes_overlap (const struct task_struct *p) {const struct cpuset *cs1, *cs2;/* my and p's cpuset ancestors */ -int overlap =0 ;/* do cpusets overlap? */ +int overlap =1 ;/* do cpusets overlap? */ task_lock (current);if (current->flags &PF_EXITING ) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/9] cpuset: oom panic fix
In reply to Nick PigginQuoted 1 line · Nick
Change to returning 0 in this case.
I think that comment is a typo, and should be instead:
Quoted 1 line
Change to returning 1 in this case.
Other than that nit:
I haven't actually seen a test case in hand for this one, but it sure seems like "the right thing to do (tm)", and I understand Nick has seen it fix a real problem.
Signature · 9 lines
I won't rest till it's the best ...
Programmer, Linux Scalability
Paul Jackson <[email protected]> 1.925.600.0401
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>PATCH 4/9 oom: cpuset hint
In reply to Nick Piggincpuset_excl_nodes_overlap does not always indicate that killing a task will not free any memory we for us. For example, we may be asking for an allocation from _anywhere_ in the machine, or the task in question may be pinning memory that is outside its cpuset. Fix this by just causing cpuset_excl_nodes_overlap to reduce the badness rather than disallow it.
mm/oom_kill.c +8 -3
@@ -127,6 +127,14 @@ unsigned long badness(struct task_struct points /=4 ;/* +* If p's nodes don't overlap ours, it may still help to kill p +* because p may have allocated or otherwise mapped memory on +* this node before. However it will be less likely. +*/ +if (!cpuset_excl_nodes_overlap (p)) + points /=8 ; + +/* * Adjust the score by oomkilladj. */ if (p->oomkilladj) {
@@ -196,9 +204,6 @@ static struct task_struct *select_bad_prcontinue ;if (p->oomkilladj ==OOM_DISABLE )continue ; -/* If p's nodes don't overlap ours, it won't help to kill p. */ -if (!cpuset_excl_nodes_overlap (p)) -continue ;/* * This is in the process of releasing memory so wait for it
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 4/9] oom: cpuset hint
I don't have a test case for this in hand, but
it sure makes sense.
Signature · 9 lines
I won't rest till it's the best ...
Programmer, Linux Scalability
Paul Jackson <[email protected]> 1.925.600.0401
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>PATCH 5/9 oom: handle current exiting
In reply to Nick PigginIf current *is* exiting, it should actually be allowed to access reserved memory rather than OOM kill something else. Can't do this via a straight check in page_alloc.c because that would allow multiple tasks to use up reserves. Instead cause current to OOM-kill itself which will mark it as TIF_MEMDIE.
The current procedure of simply aborting the OOM-kill if a task is exiting can lead to OOM deadlocks.
In the case of killing a PF_EXITING task, don't make a lot of noise about it. This becomes more important in future patches, where we can "kill" OOM_DISABLE tasks.
mm/oom_kill.c +31 -4
@@ -208,11 +208,26 @@ static struct task_struct *select_bad_pr/* * This is in the process of releasing memory so wait for it * to finish before killing some other task by mistake. +* +* However, if p is the current task, we allow the 'kill' to +* go ahead if it is exiting: this will simply set TIF_MEMDIE, +* which will allow it to gain access to memory reserves in +* the process of exiting and releasing its resources. +* Otherwise we could get an OOM deadlock. */ releasing =test_tsk_thread_flag (p,TIF_MEMDIE ) || p->flags &PF_EXITING ; -if (releasing && !(p->flags &PF_DEAD )) +if (releasing) { +/* PF_DEAD tasks have already released their mm */ +if (p->flags &PF_DEAD ) +continue ; +if (p->flags &PF_EXITING && p == current) { + chosen = p; + *ppoints =ULONG_MAX ; +break ; + }return ERR_PTR (-1UL ); + }if (p->flags &PF_SWAPOFF )return p;
@@ -246,8 +261,11 @@ static void __oom_kill_task(struct task_return ; }task_unlock (p); -printk (KERN_ERR "%s: Killed process %d (%s).\n" , + +if (message) { +printk (KERN_ERR "%s: Killed process %d (%s).\n" , message, p->pid, p->comm); + }/* * We give our sacrificial lamb high priority and access to
@@ -298,8 +316,17 @@ static int oom_kill_process(struct task_struct task_struct *c;struct list_head *tsk; -printk (KERN_ERR "Out of Memory: Kill process %d (%s) score %li and " -"children.\n" , p->pid, p->comm, points); +/* +* If the task is already exiting, don't alarm the sysadmin or kill +* its children or threads, just set TIF_MEMDIE so it can die quickly +*/ +if (p->flags &PF_EXITING ) { +__oom_kill_task (p,NULL ); +return 0 ; + } + +printk (KERN_ERR "Out of Memory: Kill process %d (%s) score %li" +" and children.\n" , p->pid, p->comm, points);/* Try to kill a child first */ list_for_each (tsk, &p->children) { c = list_entry(tsk, struct task_struct, sibling);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 6/9 oom: handle oom_disable exiting
In reply to Nick PigginHaving the oomkilladj == OOM_DISABLE check before the releasing check means that oomkilladj == OOM_DISABLE tasks exiting will not stop the OOM killer.
Moving the test down will give the desired behaviour. Also: it will allow them to "OOM-kill" themselves if they are exiting. As per the previous patch, this is required to prevent OOM killer deadlocks (and they don't actually get killed, because they're already exiting -- they're simply allowed access to memory reserves).
mm/oom_kill.c +2 -2
@@ -202,8 +202,6 @@ static struct task_struct *select_bad_pr/* skip the init task with pid == 1 */ if (p->pid ==1 )continue ; -if (p->oomkilladj ==OOM_DISABLE ) -continue ;/* * This is in the process of releasing memory so wait for it
@@ -228,6 +226,8 @@ static struct task_struct *select_bad_pr }return ERR_PTR (-1UL ); } +if (p->oomkilladj ==OOM_DISABLE ) +continue ;if (p->flags &PF_SWAPOFF )return p;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 7/9 oom: swapoff tasks tweak
In reply to Nick PigginPF_SWAPOFF processes currently cause select_bad_process to return straight away. Instead, give them high priority, so we will kill them first, however we also first ensure no parallel OOM kills are happening at the same time.
mm/oom_kill.c +6 -2
@@ -58,6 +58,12 @@ unsigned long badness(struct task_struct }/* +* swapoff can easily use up all memory, so kill those first. +*/ +if (p->flags &PF_SWAPOFF ) +return ULONG_MAX ; + +/* * The memory size of the process is the basis for the badness. */ points = mm->total_vm;
@@ -228,8 +234,6 @@ static struct task_struct *select_bad_pr }if (p->oomkilladj ==OOM_DISABLE )continue ; -if (p->flags &PF_SWAPOFF ) -return p; points =badness (p, uptime.tv_sec);if (points > *ppoints || !chosen) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 8/9 oom: kthread infinite loop fix
In reply to Nick PigginSkip kernel threads, rather than having them return 0 from badness. Theoretically, badness might truncate all results to 0, thus a kernel thread might be picked first, causing an infinite loop.
mm/oom_kill.c +3 -0
@@ -205,6 +205,9 @@ static struct task_struct *select_bad_prunsigned long points;int releasing; +/* skip kernel threads */ +if (!p->mm) +continue ;/* skip the init task with pid == 1 */ if (p->pid ==1 )continue ;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 9/9 oom: more printk
In reply to Nick PigginPrint the name of the task invoking the OOM killer. Could make debugging easier.
mm/oom_kill.c +3 -2
@@ -359,8 +359,9 @@ void out_of_memory(struct zonelist *zoneunsigned long points =0 ;if (printk_ratelimit ()) { -printk ("oom-killer: gfp_mask=0x%x, order=%d\n" , - gfp_mask, order); +printk (KERN_WARNING "%s invoked oom-killer: " +"gfp_mask=0x%x, order=%d, oomkilladj=%d\n" , + current->comm, gfp_mask, order, current->oomkilladj);dump_stack ();show_mem (); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · On Fri, 28 Jul 2006 09:20:44 +0200 (CEST) Nick Piggin <[email protected]> wrote:
These are some various OOM killer fixes that I have accumulated. Some of the more important ones are in SLES10, and were developed in response to issues coming up in stress testing.
The other small fixes haven't been widely tested, but they're issues I spotted when working in this area.
Comments?
They all look good to me (although I haven't grappled with the cpuset ones yet).
The "oom: reclaim_mapped on oom" one is kinda funny. Back in 2.5.early I decided that we were probably donig too much scanning before declaring oom so I randomly reduced it by a factor of, iirc, four. Under the assumption that someone would start hitting early ooms and would get in there and tune it for real. It took five years ;)
Which of these patches have been well-tested and which are the more speculative ones?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Andrew Morton
Quoted 4 lines · On Fri, 28 Jul 2006 09:20:44 +0200 (CEST) Nick Piggin <[email protected]> wrote:
These are some various OOM killer fixes that I have accumulated. Some of the more important ones are in SLES10, and were developed in response to issues coming up in stress testing.
Quoted 7 lines
Quoted 4 lines
The other small fixes haven't been widely tested, but they're issues I spotted when working in this area.
Comments?
They all look good to me (although I haven't grappled with the cpuset ones yet).
OK.
Quoted 6 lines
The "oom:
reclaim_mappedon oom" one is kinda funny. Back in 2.5.early I decided that we were probably donig too much scanning before declaring oom so I randomly reduced it by a factor of, iirc, four. Under the assumption that someone would start hitting early ooms and would get in there and tune it for real. It took five years ;)
Well, I guess it *can* make the machine less responsive during OOM, but I guess it is probably reasonable to trade "OOM throughput" for a system that is more conservative about killing tasks.
The workload involved was semi-realistic I guess, involving apache/mysql servers in a hypervisor guest. The after patch 1, it was still killing early, and with patch 2 it seemed to be the minimum required to get it to use up all swap first.
Quoted 3 lines
Which of these patches have been well-tested and which are the more speculative ones?
1,2,3 are in SLES10, and tested/confirmed to fix things. The others I guess are more edge cases, but I hope that together they can make things a little more robust.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>