Skip to content

Commit

Permalink
mm/ksm: unmerge and clear VM_MERGEABLE when setting PR_SET_MEMORY_MER…
Browse files Browse the repository at this point in the history
…GE=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/[email protected]
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: David Hildenbrand <[email protected]>
Acked-by: Stefan Roesch <[email protected]>
Cc: Christian Borntraeger <[email protected]>
Cc: Claudio Imbrenda <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Janosch Frank <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Rik van Riel <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: Vasily Gorbik <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
  • Loading branch information
davidhildenbrand authored and akpm00 committed May 3, 2023
1 parent 70307b0 commit 24139c0
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 9 deletions.
1 change: 1 addition & 0 deletions include/linux/ksm.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ int ksm_madvise(struct vm_area_struct *vma, unsigned long start,

void ksm_add_vma(struct vm_area_struct *vma);
int ksm_enable_merge_any(struct mm_struct *mm);
int ksm_disable_merge_any(struct mm_struct *mm);

int __ksm_enter(struct mm_struct *mm);
void __ksm_exit(struct mm_struct *mm);
Expand Down
12 changes: 3 additions & 9 deletions kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -2695,16 +2695,10 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
if (mmap_write_lock_killable(me->mm))
return -EINTR;

if (arg2) {
if (arg2)
error = ksm_enable_merge_any(me->mm);
} else {
/*
* TODO: we might want disable KSM on all VMAs and
* trigger unsharing to completely disable KSM.
*/
clear_bit(MMF_VM_MERGE_ANY, &me->mm->flags);
error = 0;
}
else
error = ksm_disable_merge_any(me->mm);
mmap_write_unlock(me->mm);
break;
case PR_GET_MEMORY_MERGE:
Expand Down
59 changes: 59 additions & 0 deletions mm/ksm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2520,6 +2520,22 @@ static void __ksm_add_vma(struct vm_area_struct *vma)
vm_flags_set(vma, VM_MERGEABLE);
}

static int __ksm_del_vma(struct vm_area_struct *vma)
{
int err;

if (!(vma->vm_flags & VM_MERGEABLE))
return 0;

if (vma->anon_vma) {
err = unmerge_ksm_pages(vma, vma->vm_start, vma->vm_end);
if (err)
return err;
}

vm_flags_clear(vma, VM_MERGEABLE);
return 0;
}
/**
* ksm_add_vma - Mark vma as mergeable if compatible
*
Expand All @@ -2542,6 +2558,20 @@ static void ksm_add_vmas(struct mm_struct *mm)
__ksm_add_vma(vma);
}

static int ksm_del_vmas(struct mm_struct *mm)
{
struct vm_area_struct *vma;
int err;

VMA_ITERATOR(vmi, mm, 0);
for_each_vma(vmi, vma) {
err = __ksm_del_vma(vma);
if (err)
return err;
}
return 0;
}

/**
* ksm_enable_merge_any - Add mm to mm ksm list and enable merging on all
* compatible VMA's
Expand Down Expand Up @@ -2569,6 +2599,35 @@ int ksm_enable_merge_any(struct mm_struct *mm)
return 0;
}

/**
* ksm_disable_merge_any - Disable merging on all compatible VMA's of the mm,
* previously enabled via ksm_enable_merge_any().
*
* Disabling merging implies unmerging any merged pages, like setting
* MADV_UNMERGEABLE would. If unmerging fails, the whole operation fails and
* merging on all compatible VMA's remains enabled.
*
* @mm: Pointer to mm
*
* Returns 0 on success, otherwise error code
*/
int ksm_disable_merge_any(struct mm_struct *mm)
{
int err;

if (!test_bit(MMF_VM_MERGE_ANY, &mm->flags))
return 0;

err = ksm_del_vmas(mm);
if (err) {
ksm_add_vmas(mm);
return err;
}

clear_bit(MMF_VM_MERGE_ANY, &mm->flags);
return 0;
}

int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
unsigned long end, int advice, unsigned long *vm_flags)
{
Expand Down

0 comments on commit 24139c0

Please sign in to comment.