Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/alpha/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -490,3 +490,4 @@
558 common process_mrelease sys_process_mrelease
559 common futex_waitv sys_futex_waitv
560 common set_mempolicy_home_node sys_ni_syscall
561 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/arm/tools/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
2 changes: 1 addition & 1 deletion arch/arm64/include/asm/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)
#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)

#define __NR_compat_syscalls 451
#define __NR_compat_syscalls 452
#endif

#define __ARCH_WANT_SYS_CLONE
Expand Down
2 changes: 2 additions & 0 deletions arch/arm64/include/asm/unistd32.h
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,8 @@ __SYSCALL(__NR_process_mrelease, sys_process_mrelease)
__SYSCALL(__NR_futex_waitv, sys_futex_waitv)
#define __NR_set_mempolicy_home_node 450
__SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)
#define __NR_pmadv_ksm 451
__SYSCALL(__NR_pmadv_ksm, sys_pmadv_ksm)

/*
* Please add new compat syscalls above this comment and update
Expand Down
1 change: 1 addition & 0 deletions arch/ia64/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/m68k/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/microblaze/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -456,3 +456,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/mips/kernel/syscalls/syscall_n32.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -389,3 +389,4 @@
448 n32 process_mrelease sys_process_mrelease
449 n32 futex_waitv sys_futex_waitv
450 n32 set_mempolicy_home_node sys_set_mempolicy_home_node
451 n32 pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/mips/kernel/syscalls/syscall_n64.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,4 @@
448 n64 process_mrelease sys_process_mrelease
449 n64 futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 n64 pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/mips/kernel/syscalls/syscall_o32.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -438,3 +438,4 @@
448 o32 process_mrelease sys_process_mrelease
449 o32 futex_waitv sys_futex_waitv
450 o32 set_mempolicy_home_node sys_set_mempolicy_home_node
451 o32 pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/parisc/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/powerpc/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -537,3 +537,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 nospu set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/s390/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -453,3 +453,4 @@
448 common process_mrelease sys_process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/sh/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -453,3 +453,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/sparc/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -496,3 +496,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/x86/entry/syscalls/syscall_32.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,4 @@
448 i386 process_mrelease sys_process_mrelease
449 i386 futex_waitv sys_futex_waitv
450 i386 set_mempolicy_home_node sys_set_mempolicy_home_node
451 i386 pmadv_ksm sys_pmadv_ksm
1 change: 1 addition & 0 deletions arch/x86/entry/syscalls/syscall_64.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm

#
# Due to a historical design error, certain syscalls are numbered differently
Expand Down
1 change: 1 addition & 0 deletions arch/xtensa/kernel/syscalls/syscall.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,4 @@
448 common process_mrelease sys_process_mrelease
449 common futex_waitv sys_futex_waitv
450 common set_mempolicy_home_node sys_set_mempolicy_home_node
451 common pmadv_ksm sys_pmadv_ksm
4 changes: 4 additions & 0 deletions include/linux/ksm.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include <linux/sched/coredump.h>

#ifdef CONFIG_KSM
int ksm_madvise_merge(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long *vm_flags);
int ksm_madvise_unmerge(struct vm_area_struct *vma, unsigned long start,
unsigned long end, unsigned long *vm_flags);
int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
unsigned long end, int advice, unsigned long *vm_flags);
int __ksm_enter(struct mm_struct *mm);
Expand Down
1 change: 1 addition & 0 deletions include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,7 @@ asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior);
asmlinkage long sys_process_madvise(int pidfd, const struct iovec __user *vec,
size_t vlen, int behavior, unsigned int flags);
asmlinkage long sys_process_mrelease(int pidfd, unsigned int flags);
asmlinkage long sys_pmadv_ksm(int pidfd, int behavior, unsigned int flags);
asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
unsigned long prot, unsigned long pgoff,
unsigned long flags);
Expand Down
5 changes: 4 additions & 1 deletion include/uapi/asm-generic/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,11 @@ __SYSCALL(__NR_futex_waitv, sys_futex_waitv)
#define __NR_set_mempolicy_home_node 450
__SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node)

#define __NR_pmadv_ksm 451
__SYSCALL(__NR_pmadv_ksm, sys_pmadv_ksm)

#undef __NR_syscalls
#define __NR_syscalls 451
#define __NR_syscalls 452

/*
* 32 bit systems traditionally used different
Expand Down
1 change: 1 addition & 0 deletions kernel/sys_ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ COND_SYSCALL(mincore);
COND_SYSCALL(madvise);
COND_SYSCALL(process_madvise);
COND_SYSCALL(process_mrelease);
COND_SYSCALL(pmadv_ksm);
COND_SYSCALL(remap_file_pages);
COND_SYSCALL(mbind);
COND_SYSCALL(get_mempolicy);
Expand Down
88 changes: 56 additions & 32 deletions mm/ksm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2438,54 +2438,78 @@ static int ksm_scan_thread(void *nothing)
return 0;
}

int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
unsigned long end, int advice, unsigned long *vm_flags)
int ksm_madvise_merge(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long *vm_flags)
{
struct mm_struct *mm = vma->vm_mm;
int err;

switch (advice) {
case MADV_MERGEABLE:
/*
* Be somewhat over-protective for now!
*/
if (*vm_flags & (VM_MERGEABLE | VM_SHARED | VM_MAYSHARE |
VM_PFNMAP | VM_IO | VM_DONTEXPAND |
VM_HUGETLB | VM_MIXEDMAP))
return 0; /* just ignore the advice */
/*
* Be somewhat over-protective for now!
*/
if (*vm_flags & (VM_MERGEABLE | VM_SHARED | VM_MAYSHARE |
VM_PFNMAP | VM_IO | VM_DONTEXPAND |
VM_HUGETLB | VM_MIXEDMAP))
return 0; /* just ignore the advice */

if (vma_is_dax(vma))
return 0;
if (vma_is_dax(vma))
return 0;

#ifdef VM_SAO
if (*vm_flags & VM_SAO)
return 0;
#endif
#ifdef VM_SPARC_ADI
if (*vm_flags & VM_SPARC_ADI)
return 0;
if (*vm_flags & VM_SPARC_ADI)
return 0;
#endif

if (!test_bit(MMF_VM_MERGEABLE, &mm->flags)) {
err = __ksm_enter(mm);
if (err)
return err;
}
if (!test_bit(MMF_VM_MERGEABLE, &mm->flags)) {
err = __ksm_enter(mm);
if (err)
return err;
}

*vm_flags |= VM_MERGEABLE;
break;
*vm_flags |= VM_MERGEABLE;

case MADV_UNMERGEABLE:
if (!(*vm_flags & VM_MERGEABLE))
return 0; /* just ignore the advice */
return 0;
}

if (vma->anon_vma) {
err = unmerge_ksm_pages(vma, start, end);
if (err)
return err;
}
int ksm_madvise_unmerge(struct vm_area_struct *vma, unsigned long start,
unsigned long end, unsigned long *vm_flags)
{
int err;

if (!(*vm_flags & VM_MERGEABLE))
return 0; /* just ignore the advice */

if (vma->anon_vma) {
err = unmerge_ksm_pages(vma, start, end);
if (err)
return err;
}

*vm_flags &= ~VM_MERGEABLE;
*vm_flags &= ~VM_MERGEABLE;

return 0;
}

int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
unsigned long end, int advice, unsigned long *vm_flags)
{
struct mm_struct *mm = vma->vm_mm;
int err;

switch (advice) {
case MADV_MERGEABLE:
err = ksm_madvise_merge(mm, vma, vm_flags);
if (err)
return err;
break;

case MADV_UNMERGEABLE:
err = ksm_madvise_unmerge(vma, start, end, vm_flags);
if (err)
return err;
break;
}

Expand Down
113 changes: 113 additions & 0 deletions mm/madvise.c
Original file line number Diff line number Diff line change
Expand Up @@ -1512,3 +1512,116 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec,
out:
return ret;
}

SYSCALL_DEFINE3(pmadv_ksm, int, pidfd, int, behaviour, unsigned int, flags)
{
#ifdef CONFIG_KSM
ssize_t ret;
struct pid *pid;
struct task_struct *task;
struct mm_struct *mm;
unsigned int f_flags;
struct vm_area_struct *vma;
struct vma_iterator vmi;

if (flags != 0) {
ret = -EINVAL;
goto out;
}

switch (behaviour) {
case MADV_MERGEABLE:
case MADV_UNMERGEABLE:
break;
default:
ret = -EINVAL;
goto out;
break;
}

pid = pidfd_get_pid(pidfd, &f_flags);
if (IS_ERR(pid)) {
ret = PTR_ERR(pid);
goto out;
}

task = get_pid_task(pid, PIDTYPE_PID);
if (!task) {
ret = -ESRCH;
goto put_pid;
}

/* Require PTRACE_MODE_READ to avoid leaking ASLR metadata. */
mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
if (IS_ERR_OR_NULL(mm)) {
ret = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH;
goto release_task;
}

/* Require CAP_SYS_NICE for influencing process performance. */
if (!capable(CAP_SYS_NICE)) {
ret = -EPERM;
goto release_mm;
}

if (mmap_write_lock_killable(mm)) {
ret = -EINTR;
goto release_mm;
}

vma_iter_init(&vmi, mm, 0);
for_each_vma(vmi, vma) {
switch (behaviour) {
case MADV_MERGEABLE:
ret = ksm_madvise_merge(vma->vm_mm, vma, &vma->vm_flags);
break;
case MADV_UNMERGEABLE:
ret = ksm_madvise_unmerge(vma, vma->vm_start, vma->vm_end, &vma->vm_flags);
break;
default:
/* look, ma, no brain */
break;
}
if (ret)
break;
}

mmap_write_unlock(mm);

release_mm:
mmput(mm);
release_task:
put_task_struct(task);
put_pid:
put_pid(pid);
out:
return ret;
#else /* CONFIG_KSM */
return -ENOSYS;
#endif /* CONFIG_KSM */
}

#ifdef CONFIG_KSM
static ssize_t ksm_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%u\n", __NR_pmadv_ksm);
}
static struct kobj_attribute pmadv_ksm_attr = __ATTR_RO(ksm);

static struct attribute *pmadv_sysfs_attrs[] = {
&pmadv_ksm_attr.attr,
NULL,
};

static const struct attribute_group pmadv_sysfs_attr_group = {
.attrs = pmadv_sysfs_attrs,
.name = "pmadv",
};

static int __init pmadv_sysfs_init(void)
{
return sysfs_create_group(kernel_kobj, &pmadv_sysfs_attr_group);
}
subsys_initcall(pmadv_sysfs_init);
#endif /* CONFIG_KSM */