Loading fs/proc/task_mmu.c +64 −7 Original line number Diff line number Diff line Loading @@ -1648,15 +1648,17 @@ const struct file_operations proc_pagemap_operations = { static int reclaim_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) { struct vm_area_struct *vma = walk->private; struct reclaim_param *rp = walk->private; struct vm_area_struct *vma = rp->vma; pte_t *pte, ptent; spinlock_t *ptl; struct page *page; LIST_HEAD(page_list); int isolated; int reclaimed; split_huge_pmd(vma, addr, pmd); if (pmd_trans_unstable(pmd)) if (pmd_trans_unstable(pmd) || !rp->nr_to_reclaim) return 0; cont: isolated = 0; Loading @@ -1677,12 +1679,18 @@ static int reclaim_pte_range(pmd_t *pmd, unsigned long addr, inc_node_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); isolated++; if (isolated >= SWAP_CLUSTER_MAX) rp->nr_scanned++; if ((isolated >= SWAP_CLUSTER_MAX) || !rp->nr_to_reclaim) break; } pte_unmap_unlock(pte - 1, ptl); reclaim_pages_from_list(&page_list, vma); if (addr != end) reclaimed = reclaim_pages_from_list(&page_list, vma); rp->nr_reclaimed += reclaimed; rp->nr_to_reclaim -= reclaimed; if (rp->nr_to_reclaim < 0) rp->nr_to_reclaim = 0; if (rp->nr_to_reclaim && (addr != end)) goto cont; cond_resched(); Loading @@ -1696,6 +1704,50 @@ enum reclaim_type { RECLAIM_RANGE, }; struct reclaim_param reclaim_task_anon(struct task_struct *task, int nr_to_reclaim) { struct mm_struct *mm; struct vm_area_struct *vma; struct mm_walk reclaim_walk = {}; struct reclaim_param rp = { .nr_to_reclaim = nr_to_reclaim, }; get_task_struct(task); mm = get_task_mm(task); if (!mm) goto out; reclaim_walk.mm = mm; reclaim_walk.pmd_entry = reclaim_pte_range; reclaim_walk.private = &rp; down_read(&mm->mmap_sem); for (vma = mm->mmap; vma; vma = vma->vm_next) { if (is_vm_hugetlb_page(vma)) continue; if (vma->vm_file) continue; if (!rp.nr_to_reclaim) break; rp.vma = vma; walk_page_range(vma->vm_start, vma->vm_end, &reclaim_walk); } flush_tlb_mm(mm); up_read(&mm->mmap_sem); mmput(mm); out: put_task_struct(task); return rp; } static ssize_t reclaim_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { Loading @@ -1708,6 +1760,7 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, struct mm_walk reclaim_walk = {}; unsigned long start = 0; unsigned long end = 0; struct reclaim_param rp; memset(buffer, 0, sizeof(buffer)); if (count > sizeof(buffer) - 1) Loading Loading @@ -1770,6 +1823,10 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, reclaim_walk.mm = mm; reclaim_walk.pmd_entry = reclaim_pte_range; rp.nr_to_reclaim = INT_MAX; rp.nr_reclaimed = 0; reclaim_walk.private = &rp; down_read(&mm->mmap_sem); if (type == RECLAIM_RANGE) { vma = find_vma(mm, start); Loading @@ -1779,7 +1836,7 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, if (is_vm_hugetlb_page(vma)) continue; reclaim_walk.private = vma; rp.vma = vma; walk_page_range(max(vma->vm_start, start), min(vma->vm_end, end), &reclaim_walk); Loading @@ -1796,7 +1853,7 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, if (type == RECLAIM_FILE && !vma->vm_file) continue; reclaim_walk.private = vma; rp.vma = vma; walk_page_range(vma->vm_start, vma->vm_end, &reclaim_walk); } Loading include/linux/mm.h +14 −0 Original line number Diff line number Diff line Loading @@ -2749,5 +2749,19 @@ static inline void setup_nr_node_ids(void) {} extern int want_old_faultaround_pte; #ifdef CONFIG_PROCESS_RECLAIM struct reclaim_param { struct vm_area_struct *vma; /* Number of pages scanned */ int nr_scanned; /* max pages to reclaim */ int nr_to_reclaim; /* pages reclaimed */ int nr_reclaimed; }; extern struct reclaim_param reclaim_task_anon(struct task_struct *task, int nr_to_reclaim); #endif #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ include/linux/vmpressure.h +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ struct vmpressure { unsigned long tree_scanned; unsigned long tree_reclaimed; unsigned long stall; /* The lock is used to keep the scanned/reclaimed above in sync. */ struct spinlock sr_lock; Loading include/trace/events/process_reclaim.h 0 → 100644 +85 −0 Original line number Diff line number Diff line /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #undef TRACE_SYSTEM #define TRACE_SYSTEM process_reclaim #if !defined(_TRACE_EVENT_PROCESSRECLAIM_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_EVENT_PROCESSRECLAIM_H #include <linux/tracepoint.h> #include <linux/types.h> #include <linux/sched.h> TRACE_EVENT(process_reclaim, TP_PROTO(int tasksize, short oom_score_adj, int nr_scanned, int nr_reclaimed, int per_swap_size, int total_sz, int nr_to_reclaim), TP_ARGS(tasksize, oom_score_adj, nr_scanned, nr_reclaimed, per_swap_size, total_sz, nr_to_reclaim), TP_STRUCT__entry( __field(int, tasksize) __field(short, oom_score_adj) __field(int, nr_scanned) __field(int, nr_reclaimed) __field(int, per_swap_size) __field(int, total_sz) __field(int, nr_to_reclaim) ), TP_fast_assign( __entry->tasksize = tasksize; __entry->oom_score_adj = oom_score_adj; __entry->nr_scanned = nr_scanned; __entry->nr_reclaimed = nr_reclaimed; __entry->per_swap_size = per_swap_size; __entry->total_sz = total_sz; __entry->nr_to_reclaim = nr_to_reclaim; ), TP_printk("%d, %hd, %d, %d, %d, %d, %d", __entry->tasksize, __entry->oom_score_adj, __entry->nr_scanned, __entry->nr_reclaimed, __entry->per_swap_size, __entry->total_sz, __entry->nr_to_reclaim) ); TRACE_EVENT(process_reclaim_eff, TP_PROTO(int efficiency, int reclaim_avg_efficiency), TP_ARGS(efficiency, reclaim_avg_efficiency), TP_STRUCT__entry( __field(int, efficiency) __field(int, reclaim_avg_efficiency) ), TP_fast_assign( __entry->efficiency = efficiency; __entry->reclaim_avg_efficiency = reclaim_avg_efficiency; ), TP_printk("%d, %d", __entry->efficiency, __entry->reclaim_avg_efficiency) ); #endif #include <trace/define_trace.h> mm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -104,3 +104,4 @@ obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_HMM) += hmm.o obj-$(CONFIG_PROCESS_RECLAIM) += process_reclaim.o Loading
fs/proc/task_mmu.c +64 −7 Original line number Diff line number Diff line Loading @@ -1648,15 +1648,17 @@ const struct file_operations proc_pagemap_operations = { static int reclaim_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) { struct vm_area_struct *vma = walk->private; struct reclaim_param *rp = walk->private; struct vm_area_struct *vma = rp->vma; pte_t *pte, ptent; spinlock_t *ptl; struct page *page; LIST_HEAD(page_list); int isolated; int reclaimed; split_huge_pmd(vma, addr, pmd); if (pmd_trans_unstable(pmd)) if (pmd_trans_unstable(pmd) || !rp->nr_to_reclaim) return 0; cont: isolated = 0; Loading @@ -1677,12 +1679,18 @@ static int reclaim_pte_range(pmd_t *pmd, unsigned long addr, inc_node_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); isolated++; if (isolated >= SWAP_CLUSTER_MAX) rp->nr_scanned++; if ((isolated >= SWAP_CLUSTER_MAX) || !rp->nr_to_reclaim) break; } pte_unmap_unlock(pte - 1, ptl); reclaim_pages_from_list(&page_list, vma); if (addr != end) reclaimed = reclaim_pages_from_list(&page_list, vma); rp->nr_reclaimed += reclaimed; rp->nr_to_reclaim -= reclaimed; if (rp->nr_to_reclaim < 0) rp->nr_to_reclaim = 0; if (rp->nr_to_reclaim && (addr != end)) goto cont; cond_resched(); Loading @@ -1696,6 +1704,50 @@ enum reclaim_type { RECLAIM_RANGE, }; struct reclaim_param reclaim_task_anon(struct task_struct *task, int nr_to_reclaim) { struct mm_struct *mm; struct vm_area_struct *vma; struct mm_walk reclaim_walk = {}; struct reclaim_param rp = { .nr_to_reclaim = nr_to_reclaim, }; get_task_struct(task); mm = get_task_mm(task); if (!mm) goto out; reclaim_walk.mm = mm; reclaim_walk.pmd_entry = reclaim_pte_range; reclaim_walk.private = &rp; down_read(&mm->mmap_sem); for (vma = mm->mmap; vma; vma = vma->vm_next) { if (is_vm_hugetlb_page(vma)) continue; if (vma->vm_file) continue; if (!rp.nr_to_reclaim) break; rp.vma = vma; walk_page_range(vma->vm_start, vma->vm_end, &reclaim_walk); } flush_tlb_mm(mm); up_read(&mm->mmap_sem); mmput(mm); out: put_task_struct(task); return rp; } static ssize_t reclaim_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { Loading @@ -1708,6 +1760,7 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, struct mm_walk reclaim_walk = {}; unsigned long start = 0; unsigned long end = 0; struct reclaim_param rp; memset(buffer, 0, sizeof(buffer)); if (count > sizeof(buffer) - 1) Loading Loading @@ -1770,6 +1823,10 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, reclaim_walk.mm = mm; reclaim_walk.pmd_entry = reclaim_pte_range; rp.nr_to_reclaim = INT_MAX; rp.nr_reclaimed = 0; reclaim_walk.private = &rp; down_read(&mm->mmap_sem); if (type == RECLAIM_RANGE) { vma = find_vma(mm, start); Loading @@ -1779,7 +1836,7 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, if (is_vm_hugetlb_page(vma)) continue; reclaim_walk.private = vma; rp.vma = vma; walk_page_range(max(vma->vm_start, start), min(vma->vm_end, end), &reclaim_walk); Loading @@ -1796,7 +1853,7 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, if (type == RECLAIM_FILE && !vma->vm_file) continue; reclaim_walk.private = vma; rp.vma = vma; walk_page_range(vma->vm_start, vma->vm_end, &reclaim_walk); } Loading
include/linux/mm.h +14 −0 Original line number Diff line number Diff line Loading @@ -2749,5 +2749,19 @@ static inline void setup_nr_node_ids(void) {} extern int want_old_faultaround_pte; #ifdef CONFIG_PROCESS_RECLAIM struct reclaim_param { struct vm_area_struct *vma; /* Number of pages scanned */ int nr_scanned; /* max pages to reclaim */ int nr_to_reclaim; /* pages reclaimed */ int nr_reclaimed; }; extern struct reclaim_param reclaim_task_anon(struct task_struct *task, int nr_to_reclaim); #endif #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */
include/linux/vmpressure.h +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ struct vmpressure { unsigned long tree_scanned; unsigned long tree_reclaimed; unsigned long stall; /* The lock is used to keep the scanned/reclaimed above in sync. */ struct spinlock sr_lock; Loading
include/trace/events/process_reclaim.h 0 → 100644 +85 −0 Original line number Diff line number Diff line /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #undef TRACE_SYSTEM #define TRACE_SYSTEM process_reclaim #if !defined(_TRACE_EVENT_PROCESSRECLAIM_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_EVENT_PROCESSRECLAIM_H #include <linux/tracepoint.h> #include <linux/types.h> #include <linux/sched.h> TRACE_EVENT(process_reclaim, TP_PROTO(int tasksize, short oom_score_adj, int nr_scanned, int nr_reclaimed, int per_swap_size, int total_sz, int nr_to_reclaim), TP_ARGS(tasksize, oom_score_adj, nr_scanned, nr_reclaimed, per_swap_size, total_sz, nr_to_reclaim), TP_STRUCT__entry( __field(int, tasksize) __field(short, oom_score_adj) __field(int, nr_scanned) __field(int, nr_reclaimed) __field(int, per_swap_size) __field(int, total_sz) __field(int, nr_to_reclaim) ), TP_fast_assign( __entry->tasksize = tasksize; __entry->oom_score_adj = oom_score_adj; __entry->nr_scanned = nr_scanned; __entry->nr_reclaimed = nr_reclaimed; __entry->per_swap_size = per_swap_size; __entry->total_sz = total_sz; __entry->nr_to_reclaim = nr_to_reclaim; ), TP_printk("%d, %hd, %d, %d, %d, %d, %d", __entry->tasksize, __entry->oom_score_adj, __entry->nr_scanned, __entry->nr_reclaimed, __entry->per_swap_size, __entry->total_sz, __entry->nr_to_reclaim) ); TRACE_EVENT(process_reclaim_eff, TP_PROTO(int efficiency, int reclaim_avg_efficiency), TP_ARGS(efficiency, reclaim_avg_efficiency), TP_STRUCT__entry( __field(int, efficiency) __field(int, reclaim_avg_efficiency) ), TP_fast_assign( __entry->efficiency = efficiency; __entry->reclaim_avg_efficiency = reclaim_avg_efficiency; ), TP_printk("%d, %d", __entry->efficiency, __entry->reclaim_avg_efficiency) ); #endif #include <trace/define_trace.h>
mm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -104,3 +104,4 @@ obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_HMM) += hmm.o obj-$(CONFIG_PROCESS_RECLAIM) += process_reclaim.o