Commit 351ceedb authored by David Hildenbrand's avatar David Hildenbrand Committed by Ma Wupeng
Browse files

mm/ksm: unmerge and clear VM_MERGEABLE when setting PR_SET_MEMORY_MERGE=0

mainline inclusion
from mainline-v6.4-rc1
commit 24139c07
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I72R0B
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=24139c07f413ef4b555482c758343d71392a19bc

----------------------------------------------------------------------

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: default avatarDavid Hildenbrand <david@redhat.com>
Acked-by: default avatarStefan 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Conflicts:
	mm/ksm.c
Signed-off-by: default avatarNanyong Sun <sunnanyong@huawei.com>
parent a098d41e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,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);
+3 −9
Original line number Diff line number Diff line
@@ -2538,16 +2538,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:
+59 −0
Original line number Diff line number Diff line
@@ -2489,6 +2489,23 @@ static void __ksm_add_vma(struct vm_area_struct *vma)
	}
}

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;
	}

	mmap_assert_write_locked(vma->vm_mm);
	vma->vm_flags &= ~VM_MERGEABLE;
	return 0;
}
/**
 * ksm_add_vma - Mark vma as mergeable if compatible
 *
@@ -2510,6 +2527,19 @@ 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;

	for (vma = mm->mmap; vma; vma = vma->vm_next) {
		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
@@ -2537,6 +2567,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)
{