Subject: + mm-memcg-enable-memcg-oom-killer-only-for-user-faults.patch added to -mm tree To: hannes@xxxxxxxxxxx,azurit@xxxxxxxx,kamezawa.hiroyu@xxxxxxxxxxxxxx,kosaki.motohiro@xxxxxxxxxxxxxx,mhocko@xxxxxxx,rientjes@xxxxxxxxxx From: akpm@xxxxxxxxxxxxxxxxxxxx Date: Mon, 05 Aug 2013 15:05:58 -0700 The patch titled Subject: mm: memcg: enable memcg OOM killer only for user faults has been added to the -mm tree. Its filename is mm-memcg-enable-memcg-oom-killer-only-for-user-faults.patch This patch should soon appear at http://ozlabs.org/~akpm/mmots/broken-out/mm-memcg-enable-memcg-oom-killer-only-for-user-faults.patch and later at http://ozlabs.org/~akpm/mmotm/broken-out/mm-memcg-enable-memcg-oom-killer-only-for-user-faults.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Johannes Weiner <hannes@xxxxxxxxxxx> Subject: mm: memcg: enable memcg OOM killer only for user faults System calls and kernel faults (uaccess, gup) can handle an out of memory situation gracefully and just return -ENOMEM. Enable the memcg OOM killer only for user faults, where it's really the only option available. Signed-off-by: Johannes Weiner <hannes@xxxxxxxxxxx> Acked-by: Michal Hocko <mhocko@xxxxxxx> Cc: David Rientjes <rientjes@xxxxxxxxxx> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@xxxxxxxxxxxxxx> Cc: azurIt <azurit@xxxxxxxx> Cc: KOSAKI Motohiro <kosaki.motohiro@xxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- include/linux/memcontrol.h | 44 +++++++++++++++++++++++++++++++++++ include/linux/sched.h | 3 ++ mm/filemap.c | 11 +++++++- mm/memcontrol.c | 2 - mm/memory.c | 40 +++++++++++++++++++++++-------- 5 files changed, 88 insertions(+), 12 deletions(-) diff -puN include/linux/memcontrol.h~mm-memcg-enable-memcg-oom-killer-only-for-user-faults include/linux/memcontrol.h --- a/include/linux/memcontrol.h~mm-memcg-enable-memcg-oom-killer-only-for-user-faults +++ a/include/linux/memcontrol.h @@ -151,6 +151,37 @@ extern void mem_cgroup_print_oom_info(st extern void mem_cgroup_replace_page_cache(struct page *oldpage, struct page *newpage); +/** + * mem_cgroup_toggle_oom - toggle the memcg OOM killer for the current task + * @new: true to enable, false to disable + * + * Toggle whether a failed memcg charge should invoke the OOM killer + * or just return -ENOMEM. Returns the previous toggle state. + */ +static inline bool mem_cgroup_toggle_oom(bool new) +{ + bool old; + + old = current->memcg_oom.may_oom; + current->memcg_oom.may_oom = new; + + return old; +} + +static inline void mem_cgroup_enable_oom(void) +{ + bool old = mem_cgroup_toggle_oom(true); + + WARN_ON(old == true); +} + +static inline void mem_cgroup_disable_oom(void) +{ + bool old = mem_cgroup_toggle_oom(false); + + WARN_ON(old == false); +} + #ifdef CONFIG_MEMCG_SWAP extern int do_swap_account; #endif @@ -382,6 +413,19 @@ static inline void mem_cgroup_end_update { } +static inline bool mem_cgroup_toggle_oom(bool new) +{ + return false; +} + +static inline void mem_cgroup_enable_oom(void) +{ +} + +static inline void mem_cgroup_disable_oom(void) +{ +} + static inline void mem_cgroup_inc_page_stat(struct page *page, enum mem_cgroup_page_stat_item idx) { diff -puN include/linux/sched.h~mm-memcg-enable-memcg-oom-killer-only-for-user-faults include/linux/sched.h --- a/include/linux/sched.h~mm-memcg-enable-memcg-oom-killer-only-for-user-faults +++ a/include/linux/sched.h @@ -1399,6 +1399,9 @@ struct task_struct { unsigned long memsw_nr_pages; /* uncharged mem+swap usage */ } memcg_batch; unsigned int memcg_kmem_skip_account; + struct memcg_oom_info { + unsigned int may_oom:1; + } memcg_oom; #endif #ifdef CONFIG_UPROBES struct uprobe_task *utask; diff -puN mm/filemap.c~mm-memcg-enable-memcg-oom-killer-only-for-user-faults mm/filemap.c --- a/mm/filemap.c~mm-memcg-enable-memcg-oom-killer-only-for-user-faults +++ a/mm/filemap.c @@ -1616,6 +1616,7 @@ int filemap_fault(struct vm_area_struct struct inode *inode = mapping->host; pgoff_t offset = vmf->pgoff; struct page *page; + bool memcg_oom; pgoff_t size; int ret = 0; @@ -1624,7 +1625,11 @@ int filemap_fault(struct vm_area_struct return VM_FAULT_SIGBUS; /* - * Do we have something in the page cache already? + * Do we have something in the page cache already? Either + * way, try readahead, but disable the memcg OOM killer for it + * as readahead is optional and no errors are propagated up + * the fault stack. The OOM killer is enabled while trying to + * instantiate the faulting page individually below. */ page = find_get_page(mapping, offset); if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) { @@ -1632,10 +1637,14 @@ int filemap_fault(struct vm_area_struct * We found the page, so try async readahead before * waiting for the lock. */ + memcg_oom = mem_cgroup_toggle_oom(false); do_async_mmap_readahead(vma, ra, file, page, offset); + mem_cgroup_toggle_oom(memcg_oom); } else if (!page) { /* No page in the page cache at all */ + memcg_oom = mem_cgroup_toggle_oom(false); do_sync_mmap_readahead(vma, ra, file, offset); + mem_cgroup_toggle_oom(memcg_oom); count_vm_event(PGMAJFAULT); mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); ret = VM_FAULT_MAJOR; diff -puN mm/memcontrol.c~mm-memcg-enable-memcg-oom-killer-only-for-user-faults mm/memcontrol.c --- a/mm/memcontrol.c~mm-memcg-enable-memcg-oom-killer-only-for-user-faults +++ a/mm/memcontrol.c @@ -2478,7 +2478,7 @@ static int mem_cgroup_do_charge(struct m return CHARGE_RETRY; /* If we don't need to call oom-killer at el, return immediately */ - if (!oom_check) + if (!oom_check || !current->memcg_oom.may_oom) return CHARGE_NOMEM; /* check OOM */ if (!mem_cgroup_handle_oom(mem_over_limit, gfp_mask, get_order(csize))) diff -puN mm/memory.c~mm-memcg-enable-memcg-oom-killer-only-for-user-faults mm/memory.c --- a/mm/memory.c~mm-memcg-enable-memcg-oom-killer-only-for-user-faults +++ a/mm/memory.c @@ -3752,22 +3752,14 @@ unlock: /* * By the time we get here, we already hold the mm semaphore */ -int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long address, unsigned int flags) +static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, unsigned int flags) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; - __set_current_state(TASK_RUNNING); - - count_vm_event(PGFAULT); - mem_cgroup_count_vm_event(mm, PGFAULT); - - /* do counter updates before entering really critical section. */ - check_sync_rss_stat(current); - if (unlikely(is_vm_hugetlb_page(vma))) return hugetlb_fault(mm, vma, address, flags); @@ -3851,6 +3843,34 @@ retry: return handle_pte_fault(mm, vma, address, pte, pmd, flags); } +int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, unsigned int flags) +{ + int ret; + + __set_current_state(TASK_RUNNING); + + count_vm_event(PGFAULT); + mem_cgroup_count_vm_event(mm, PGFAULT); + + /* do counter updates before entering really critical section. */ + check_sync_rss_stat(current); + + /* + * Enable the memcg OOM handling for faults triggered in user + * space. Kernel faults are handled more gracefully. + */ + if (flags & FAULT_FLAG_USER) + mem_cgroup_enable_oom(); + + ret = __handle_mm_fault(mm, vma, address, flags); + + if (flags & FAULT_FLAG_USER) + mem_cgroup_disable_oom(); + + return ret; +} + #ifndef __PAGETABLE_PUD_FOLDED /* * Allocate page upper directory. _ Patches currently in -mm which might be from hannes@xxxxxxxxxxx are memcg-dont-initialize-kmem-cache-destroying-work-for-root-caches.patch mm-kill-one-if-loop-in-__free_pages_bootmem.patch mm-vmscan-fix-numa-reclaim-balance-problem-in-kswapd.patch mm-page_alloc-rearrange-watermark-checking-in-get_page_from_freelist.patch mm-page_alloc-fair-zone-allocator-policy.patch mm-revert-page-writebackc-subtract-min_free_kbytes-from-dirtyable-memory.patch memcg-remove-redundant-code-in-mem_cgroup_force_empty_write.patch memcg-vmscan-integrate-soft-reclaim-tighter-with-zone-shrinking-code.patch memcg-get-rid-of-soft-limit-tree-infrastructure.patch vmscan-memcg-do-softlimit-reclaim-also-for-targeted-reclaim.patch memcg-enhance-memcg-iterator-to-support-predicates.patch memcg-track-children-in-soft-limit-excess-to-improve-soft-limit.patch memcg-vmscan-do-not-attempt-soft-limit-reclaim-if-it-would-not-scan-anything.patch memcg-track-all-children-over-limit-in-the-root.patch memcg-vmscan-do-not-fall-into-reclaim-all-pass-too-quickly.patch arch-mm-remove-obsolete-init-oom-protection.patch arch-mm-do-not-invoke-oom-killer-on-kernel-fault-oom.patch arch-mm-pass-userspace-fault-flag-to-generic-fault-handler.patch x86-finish-user-fault-error-path-with-fatal-signal.patch mm-memcg-enable-memcg-oom-killer-only-for-user-faults.patch mm-memcg-rework-and-document-oom-waiting-and-wakeup.patch mm-memcg-do-not-trap-chargers-with-full-callstack-on-oom.patch swap-add-a-simple-detector-for-inappropriate-swapin-readahead-fix.patch debugging-keep-track-of-page-owners-fix-2-fix-fix-fix.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html