diff options
-rw-r--r-- | mm/oom_kill.c | 86 |
1 files changed, 57 insertions, 29 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index fca886d8b5fb..dad13fc41f47 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -631,6 +631,44 @@ void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_mask) | |||
631 | } | 631 | } |
632 | 632 | ||
633 | /* | 633 | /* |
634 | * Try to acquire the oom killer lock for all system zones. Returns zero if a | ||
635 | * parallel oom killing is taking place, otherwise locks all zones and returns | ||
636 | * non-zero. | ||
637 | */ | ||
638 | static int try_set_system_oom(void) | ||
639 | { | ||
640 | struct zone *zone; | ||
641 | int ret = 1; | ||
642 | |||
643 | spin_lock(&zone_scan_lock); | ||
644 | for_each_populated_zone(zone) | ||
645 | if (zone_is_oom_locked(zone)) { | ||
646 | ret = 0; | ||
647 | goto out; | ||
648 | } | ||
649 | for_each_populated_zone(zone) | ||
650 | zone_set_flag(zone, ZONE_OOM_LOCKED); | ||
651 | out: | ||
652 | spin_unlock(&zone_scan_lock); | ||
653 | return ret; | ||
654 | } | ||
655 | |||
656 | /* | ||
657 | * Clears ZONE_OOM_LOCKED for all system zones so that failed allocation | ||
658 | * attempts or page faults may now recall the oom killer, if necessary. | ||
659 | */ | ||
660 | static void clear_system_oom(void) | ||
661 | { | ||
662 | struct zone *zone; | ||
663 | |||
664 | spin_lock(&zone_scan_lock); | ||
665 | for_each_populated_zone(zone) | ||
666 | zone_clear_flag(zone, ZONE_OOM_LOCKED); | ||
667 | spin_unlock(&zone_scan_lock); | ||
668 | } | ||
669 | |||
670 | |||
671 | /* | ||
634 | * Must be called with tasklist_lock held for read. | 672 | * Must be called with tasklist_lock held for read. |
635 | */ | 673 | */ |
636 | static void __out_of_memory(gfp_t gfp_mask, int order, | 674 | static void __out_of_memory(gfp_t gfp_mask, int order, |
@@ -665,33 +703,6 @@ retry: | |||
665 | goto retry; | 703 | goto retry; |
666 | } | 704 | } |
667 | 705 | ||
668 | /* | ||
669 | * pagefault handler calls into here because it is out of memory but | ||
670 | * doesn't know exactly how or why. | ||
671 | */ | ||
672 | void pagefault_out_of_memory(void) | ||
673 | { | ||
674 | unsigned long freed = 0; | ||
675 | |||
676 | blocking_notifier_call_chain(&oom_notify_list, 0, &freed); | ||
677 | if (freed > 0) | ||
678 | /* Got some memory back in the last second. */ | ||
679 | return; | ||
680 | |||
681 | check_panic_on_oom(CONSTRAINT_NONE, 0, 0); | ||
682 | read_lock(&tasklist_lock); | ||
683 | /* unknown gfp_mask and order */ | ||
684 | __out_of_memory(0, 0, CONSTRAINT_NONE, NULL); | ||
685 | read_unlock(&tasklist_lock); | ||
686 | |||
687 | /* | ||
688 | * Give "p" a good chance of killing itself before we | ||
689 | * retry to allocate memory. | ||
690 | */ | ||
691 | if (!test_thread_flag(TIF_MEMDIE)) | ||
692 | schedule_timeout_uninterruptible(1); | ||
693 | } | ||
694 | |||
695 | /** | 706 | /** |
696 | * out_of_memory - kill the "best" process when we run out of memory | 707 | * out_of_memory - kill the "best" process when we run out of memory |
697 | * @zonelist: zonelist pointer | 708 | * @zonelist: zonelist pointer |
@@ -708,7 +719,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | |||
708 | int order, nodemask_t *nodemask) | 719 | int order, nodemask_t *nodemask) |
709 | { | 720 | { |
710 | unsigned long freed = 0; | 721 | unsigned long freed = 0; |
711 | enum oom_constraint constraint; | 722 | enum oom_constraint constraint = CONSTRAINT_NONE; |
712 | 723 | ||
713 | blocking_notifier_call_chain(&oom_notify_list, 0, &freed); | 724 | blocking_notifier_call_chain(&oom_notify_list, 0, &freed); |
714 | if (freed > 0) | 725 | if (freed > 0) |
@@ -729,7 +740,8 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | |||
729 | * Check if there were limitations on the allocation (only relevant for | 740 | * Check if there were limitations on the allocation (only relevant for |
730 | * NUMA) that may require different handling. | 741 | * NUMA) that may require different handling. |
731 | */ | 742 | */ |
732 | constraint = constrained_alloc(zonelist, gfp_mask, nodemask); | 743 | if (zonelist) |
744 | constraint = constrained_alloc(zonelist, gfp_mask, nodemask); | ||
733 | check_panic_on_oom(constraint, gfp_mask, order); | 745 | check_panic_on_oom(constraint, gfp_mask, order); |
734 | read_lock(&tasklist_lock); | 746 | read_lock(&tasklist_lock); |
735 | __out_of_memory(gfp_mask, order, constraint, nodemask); | 747 | __out_of_memory(gfp_mask, order, constraint, nodemask); |
@@ -742,3 +754,19 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, | |||
742 | if (!test_thread_flag(TIF_MEMDIE)) | 754 | if (!test_thread_flag(TIF_MEMDIE)) |
743 | schedule_timeout_uninterruptible(1); | 755 | schedule_timeout_uninterruptible(1); |
744 | } | 756 | } |
757 | |||
758 | /* | ||
759 | * The pagefault handler calls here because it is out of memory, so kill a | ||
760 | * memory-hogging task. If a populated zone has ZONE_OOM_LOCKED set, a parallel | ||
761 | * oom killing is already in progress so do nothing. If a task is found with | ||
762 | * TIF_MEMDIE set, it has been killed so do nothing and allow it to exit. | ||
763 | */ | ||
764 | void pagefault_out_of_memory(void) | ||
765 | { | ||
766 | if (try_set_system_oom()) { | ||
767 | out_of_memory(NULL, 0, 0, NULL); | ||
768 | clear_system_oom(); | ||
769 | } | ||
770 | if (!test_thread_flag(TIF_MEMDIE)) | ||
771 | schedule_timeout_uninterruptible(1); | ||
772 | } | ||