From: xu xin <xu.xin16@zte.com.cn> mainline inclusion from mainline-v6.6-rc1 commit 6080d19f07043ade61094d0f58b14c05e1694a39 category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/10169 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- As the number of ksm zero pages is not included in ksm_merging_pages per process when enabling use_zero_pages, it's unclear of how many actual pages are merged by KSM. To let users accurately estimate their memory demands when unsharing KSM zero-pages, it's necessary to show KSM zero- pages per process. In addition, it help users to know the actual KSM profit because KSM-placed zero pages are also benefit from KSM. since unsharing zero pages placed by KSM accurately is achieved, then tracking empty pages merging and unmerging is not a difficult thing any longer. Since we already have /proc/<pid>/ksm_stat, just add the information of 'ksm_zero_pages' in it. Link: https://lkml.kernel.org/r/20230613030938.185993-1-yang.yang29@zte.com.cn Signed-off-by: xu xin <xu.xin16@zte.com.cn> Acked-by: David Hildenbrand <david@redhat.com> Reviewed-by: Xiaokai Ran <ran.xiaokai@zte.com.cn> Reviewed-by: Yang Yang <yang.yang29@zte.com.cn> Cc: Claudio Imbrenda <imbrenda@linux.ibm.com> Cc: Xuexin Jiang <jiang.xuexin@zte.com.cn> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Conflicts: include/linux/mm_types.h mm/khugepaged.c mm/memory.c Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- fs/proc/base.c | 1 + include/linux/ksm.h | 8 +++++--- include/linux/mm_types.h | 11 ++++++++++- mm/khugepaged.c | 2 +- mm/ksm.c | 1 + mm/memory.c | 4 ++-- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 64d471fa99b3..80ceb036bae2 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3065,6 +3065,7 @@ static int proc_pid_ksm_stat(struct seq_file *m, struct pid_namespace *ns, mm = get_task_mm(task); if (mm) { seq_printf(m, "ksm_rmap_items %lu\n", mm->ksm_rmap_items); + seq_printf(m, "ksm_zero_pages %lu\n", mm->ksm_zero_pages); seq_printf(m, "ksm_merging_pages %lu\n", mm->ksm_merging_pages); seq_printf(m, "ksm_process_profit %ld\n", ksm_process_profit(mm)); mmput(mm); diff --git a/include/linux/ksm.h b/include/linux/ksm.h index 9a01f2a406a6..f2a83a2676cb 100644 --- a/include/linux/ksm.h +++ b/include/linux/ksm.h @@ -37,10 +37,12 @@ void __ksm_exit(struct mm_struct *mm); extern unsigned long ksm_zero_pages; -static inline void ksm_might_unmap_zero_page(pte_t pte) +static inline void ksm_might_unmap_zero_page(struct mm_struct *mm, pte_t pte) { - if (is_ksm_zero_pte(pte)) + if (is_ksm_zero_pte(pte)) { ksm_zero_pages--; + mm->ksm_zero_pages--; + } } static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm) @@ -105,7 +107,7 @@ static inline void ksm_exit(struct mm_struct *mm) { } -static inline void ksm_might_unmap_zero_page(pte_t pte) +static inline void ksm_might_unmap_zero_page(struct mm_struct *mm, pte_t pte) { } diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 2db486c0ee5b..5d7de361db2a 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -567,7 +567,7 @@ struct mm_struct { #if defined(CONFIG_KSM) && !defined(__GENKSYMS__) /* * Represent how many pages of this process are involved in KSM - * merging. + * merging (not including ksm_zero_pages). */ unsigned long ksm_merging_pages; #else @@ -583,7 +583,16 @@ struct mm_struct { #else KABI_RESERVE(5) #endif + +#if defined(CONFIG_KSM) && !defined(__GENKSYMS__) + /* + * Represent how many empty pages are merged with kernel zero + * pages when enabling KSM use_zero_pages. + */ + unsigned long ksm_zero_pages; +#else KABI_RESERVE(6) +#endif KABI_RESERVE(7) KABI_RESERVE(8) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index e98b755dc0d1..37c5768b6ac8 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -674,7 +674,7 @@ static void __collapse_huge_page_copy(pte_t *pte, struct page *page, */ pte_clear(vma->vm_mm, address, _pte); spin_unlock(ptl); - ksm_might_unmap_zero_page(pteval); + ksm_might_unmap_zero_page(vma->vm_mm, pteval); } } else { src_page = pte_page(pteval); diff --git a/mm/ksm.c b/mm/ksm.c index 0cddf1b8cd05..5938de557780 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -1239,6 +1239,7 @@ static int replace_page(struct vm_area_struct *vma, struct page *page, */ newpte = pte_mkdirty(pte_mkspecial(pfn_pte(page_to_pfn(kpage), vma->vm_page_prot))); ksm_zero_pages++; + mm->ksm_zero_pages++; /* * We're replacing an anonymous page with a zero page, which is * not anonymous. We need to do proper accounting otherwise we diff --git a/mm/memory.c b/mm/memory.c index acdf8907becb..209439e02647 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1106,7 +1106,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, tlb->fullmm); tlb_remove_tlb_entry(tlb, pte, addr); if (unlikely(!page)) { - ksm_might_unmap_zero_page(ptent); + ksm_might_unmap_zero_page(mm, ptent); continue; } @@ -2518,7 +2518,7 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf) reliable_page_counter(new_page, mm, 1); } } else { - ksm_might_unmap_zero_page(vmf->orig_pte); + ksm_might_unmap_zero_page(mm, vmf->orig_pte); inc_mm_counter_fast(mm, MM_ANONPAGES); reliable_page_counter(new_page, mm, 1); } -- 2.43.0