Skip to content

Commit 24139c0

Browse files
davidhildenbrandakpm00
authored andcommitted
mm/ksm: unmerge and clear VM_MERGEABLE when setting PR_SET_MEMORY_MERGE=0
Patch series "mm/ksm: improve PR_SET_MEMORY_MERGE=0 handling and cleanup disabling KSM", v2. (1) Make PR_SET_MEMORY_MERGE=0 unmerge pages like setting MADV_UNMERGEABLE does, (2) add a selftest for it and (3) factor out disabling of KSM from s390/gmap code. This patch (of 3): Let's unmerge any KSM pages when setting PR_SET_MEMORY_MERGE=0, and clear the VM_MERGEABLE flag from all VMAs -- just like KSM would. Of course, only do that if we previously set PR_SET_MEMORY_MERGE=1. Link: https://lkml.kernel.org/r/20230422205420.30372-1-david@redhat.com Link: https://lkml.kernel.org/r/20230422205420.30372-2-david@redhat.com Signed-off-by: David Hildenbrand <david@redhat.com> Acked-by: Stefan Roesch <shr@devkernel.io> Cc: Christian Borntraeger <borntraeger@linux.ibm.com> Cc: Claudio Imbrenda <imbrenda@linux.ibm.com> Cc: Heiko Carstens <hca@linux.ibm.com> Cc: Janosch Frank <frankja@linux.ibm.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Rik van Riel <riel@surriel.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Sven Schnelle <svens@linux.ibm.com> Cc: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 70307b0 commit 24139c0

3 files changed

Lines changed: 63 additions & 9 deletions

File tree

include/linux/ksm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
2121

2222
void ksm_add_vma(struct vm_area_struct *vma);
2323
int ksm_enable_merge_any(struct mm_struct *mm);
24+
int ksm_disable_merge_any(struct mm_struct *mm);
2425

2526
int __ksm_enter(struct mm_struct *mm);
2627
void __ksm_exit(struct mm_struct *mm);

kernel/sys.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,16 +2695,10 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
26952695
if (mmap_write_lock_killable(me->mm))
26962696
return -EINTR;
26972697

2698-
if (arg2) {
2698+
if (arg2)
26992699
error = ksm_enable_merge_any(me->mm);
2700-
} else {
2701-
/*
2702-
* TODO: we might want disable KSM on all VMAs and
2703-
* trigger unsharing to completely disable KSM.
2704-
*/
2705-
clear_bit(MMF_VM_MERGE_ANY, &me->mm->flags);
2706-
error = 0;
2707-
}
2700+
else
2701+
error = ksm_disable_merge_any(me->mm);
27082702
mmap_write_unlock(me->mm);
27092703
break;
27102704
case PR_GET_MEMORY_MERGE:

mm/ksm.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2520,6 +2520,22 @@ static void __ksm_add_vma(struct vm_area_struct *vma)
25202520
vm_flags_set(vma, VM_MERGEABLE);
25212521
}
25222522

2523+
static int __ksm_del_vma(struct vm_area_struct *vma)
2524+
{
2525+
int err;
2526+
2527+
if (!(vma->vm_flags & VM_MERGEABLE))
2528+
return 0;
2529+
2530+
if (vma->anon_vma) {
2531+
err = unmerge_ksm_pages(vma, vma->vm_start, vma->vm_end);
2532+
if (err)
2533+
return err;
2534+
}
2535+
2536+
vm_flags_clear(vma, VM_MERGEABLE);
2537+
return 0;
2538+
}
25232539
/**
25242540
* ksm_add_vma - Mark vma as mergeable if compatible
25252541
*
@@ -2542,6 +2558,20 @@ static void ksm_add_vmas(struct mm_struct *mm)
25422558
__ksm_add_vma(vma);
25432559
}
25442560

2561+
static int ksm_del_vmas(struct mm_struct *mm)
2562+
{
2563+
struct vm_area_struct *vma;
2564+
int err;
2565+
2566+
VMA_ITERATOR(vmi, mm, 0);
2567+
for_each_vma(vmi, vma) {
2568+
err = __ksm_del_vma(vma);
2569+
if (err)
2570+
return err;
2571+
}
2572+
return 0;
2573+
}
2574+
25452575
/**
25462576
* ksm_enable_merge_any - Add mm to mm ksm list and enable merging on all
25472577
* compatible VMA's
@@ -2569,6 +2599,35 @@ int ksm_enable_merge_any(struct mm_struct *mm)
25692599
return 0;
25702600
}
25712601

2602+
/**
2603+
* ksm_disable_merge_any - Disable merging on all compatible VMA's of the mm,
2604+
* previously enabled via ksm_enable_merge_any().
2605+
*
2606+
* Disabling merging implies unmerging any merged pages, like setting
2607+
* MADV_UNMERGEABLE would. If unmerging fails, the whole operation fails and
2608+
* merging on all compatible VMA's remains enabled.
2609+
*
2610+
* @mm: Pointer to mm
2611+
*
2612+
* Returns 0 on success, otherwise error code
2613+
*/
2614+
int ksm_disable_merge_any(struct mm_struct *mm)
2615+
{
2616+
int err;
2617+
2618+
if (!test_bit(MMF_VM_MERGE_ANY, &mm->flags))
2619+
return 0;
2620+
2621+
err = ksm_del_vmas(mm);
2622+
if (err) {
2623+
ksm_add_vmas(mm);
2624+
return err;
2625+
}
2626+
2627+
clear_bit(MMF_VM_MERGE_ANY, &mm->flags);
2628+
return 0;
2629+
}
2630+
25722631
int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
25732632
unsigned long end, int advice, unsigned long *vm_flags)
25742633
{

0 commit comments

Comments
 (0)