Re: [RFC 5/7] mm: introduce external memory hinting API
From: Christian Brauner
Date: Tue May 21 2019 - 05:03:43 EST
Cc: Jann and Oleg too
On Mon, May 20, 2019 at 12:52:52PM +0900, Minchan Kim wrote:
> There is some usecase that centralized userspace daemon want to give
> a memory hint like MADV_[COOL|COLD] to other process. Android's
> ActivityManagerService is one of them.
>
> It's similar in spirit to madvise(MADV_WONTNEED), but the information
> required to make the reclaim decision is not known to the app. Instead,
> it is known to the centralized userspace daemon(ActivityManagerService),
> and that daemon must be able to initiate reclaim on its own without
> any app involvement.
>
> To solve the issue, this patch introduces new syscall process_madvise(2)
> which works based on pidfd so it could give a hint to the exeternal
> process.
>
> int process_madvise(int pidfd, void *addr, size_t length, int advise);
>
> All advises madvise provides can be supported in process_madvise, too.
> Since it could affect other process's address range, only privileged
> process(CAP_SYS_PTRACE) or something else(e.g., being the same UID)
> gives it the right to ptrrace the process could use it successfully.
>
> Please suggest better idea if you have other idea about the permission.
>
> * from v1r1
> * use ptrace capability - surenb, dancol
>
> Signed-off-by: Minchan Kim <minchan@xxxxxxxxxx>
> ---
> arch/x86/entry/syscalls/syscall_32.tbl | 1 +
> arch/x86/entry/syscalls/syscall_64.tbl | 1 +
> include/linux/proc_fs.h | 1 +
> include/linux/syscalls.h | 2 ++
> include/uapi/asm-generic/unistd.h | 2 ++
> kernel/signal.c | 2 +-
> kernel/sys_ni.c | 1 +
> mm/madvise.c | 45 ++++++++++++++++++++++++++
> 8 files changed, 54 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
> index 4cd5f982b1e5..5b9dd55d6b57 100644
> --- a/arch/x86/entry/syscalls/syscall_32.tbl
> +++ b/arch/x86/entry/syscalls/syscall_32.tbl
> @@ -438,3 +438,4 @@
> 425 i386 io_uring_setup sys_io_uring_setup __ia32_sys_io_uring_setup
> 426 i386 io_uring_enter sys_io_uring_enter __ia32_sys_io_uring_enter
> 427 i386 io_uring_register sys_io_uring_register __ia32_sys_io_uring_register
> +428 i386 process_madvise sys_process_madvise __ia32_sys_process_madvise
> diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
> index 64ca0d06259a..0e5ee78161c9 100644
> --- a/arch/x86/entry/syscalls/syscall_64.tbl
> +++ b/arch/x86/entry/syscalls/syscall_64.tbl
> @@ -355,6 +355,7 @@
> 425 common io_uring_setup __x64_sys_io_uring_setup
> 426 common io_uring_enter __x64_sys_io_uring_enter
> 427 common io_uring_register __x64_sys_io_uring_register
> +428 common process_madvise __x64_sys_process_madvise
>
> #
> # x32-specific system call numbers start at 512 to avoid cache impact
> diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
> index 52a283ba0465..f8545d7c5218 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -122,6 +122,7 @@ static inline struct pid *tgid_pidfd_to_pid(const struct file *file)
>
> #endif /* CONFIG_PROC_FS */
>
> +extern struct pid *pidfd_to_pid(const struct file *file);
> struct net;
>
> static inline struct proc_dir_entry *proc_net_mkdir(
> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
> index e2870fe1be5b..21c6c9a62006 100644
> --- a/include/linux/syscalls.h
> +++ b/include/linux/syscalls.h
> @@ -872,6 +872,8 @@ asmlinkage long sys_munlockall(void);
> asmlinkage long sys_mincore(unsigned long start, size_t len,
> unsigned char __user * vec);
> asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior);
> +asmlinkage long sys_process_madvise(int pid_fd, unsigned long start,
> + size_t len, int behavior);
> asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
> unsigned long prot, unsigned long pgoff,
> unsigned long flags);
> diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
> index dee7292e1df6..7ee82ce04620 100644
> --- a/include/uapi/asm-generic/unistd.h
> +++ b/include/uapi/asm-generic/unistd.h
> @@ -832,6 +832,8 @@ __SYSCALL(__NR_io_uring_setup, sys_io_uring_setup)
> __SYSCALL(__NR_io_uring_enter, sys_io_uring_enter)
> #define __NR_io_uring_register 427
> __SYSCALL(__NR_io_uring_register, sys_io_uring_register)
> +#define __NR_process_madvise 428
> +__SYSCALL(__NR_process_madvise, sys_process_madvise)
>
> #undef __NR_syscalls
> #define __NR_syscalls 428
> diff --git a/kernel/signal.c b/kernel/signal.c
> index 1c86b78a7597..04e75daab1f8 100644
> --- a/kernel/signal.c
> +++ b/kernel/signal.c
> @@ -3620,7 +3620,7 @@ static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
> return copy_siginfo_from_user(kinfo, info);
> }
>
> -static struct pid *pidfd_to_pid(const struct file *file)
> +struct pid *pidfd_to_pid(const struct file *file)
> {
> if (file->f_op == &pidfd_fops)
> return file->private_data;
> diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
> index 4d9ae5ea6caf..5277421795ab 100644
> --- a/kernel/sys_ni.c
> +++ b/kernel/sys_ni.c
> @@ -278,6 +278,7 @@ COND_SYSCALL(mlockall);
> COND_SYSCALL(munlockall);
> COND_SYSCALL(mincore);
> COND_SYSCALL(madvise);
> +COND_SYSCALL(process_madvise);
> COND_SYSCALL(remap_file_pages);
> COND_SYSCALL(mbind);
> COND_SYSCALL_COMPAT(mbind);
> diff --git a/mm/madvise.c b/mm/madvise.c
> index 119e82e1f065..af02aa17e5c1 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -9,6 +9,7 @@
> #include <linux/mman.h>
> #include <linux/pagemap.h>
> #include <linux/page_idle.h>
> +#include <linux/proc_fs.h>
> #include <linux/syscalls.h>
> #include <linux/mempolicy.h>
> #include <linux/page-isolation.h>
> @@ -16,6 +17,7 @@
> #include <linux/hugetlb.h>
> #include <linux/falloc.h>
> #include <linux/sched.h>
> +#include <linux/sched/mm.h>
> #include <linux/ksm.h>
> #include <linux/fs.h>
> #include <linux/file.h>
> @@ -1140,3 +1142,46 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
> {
> return madvise_core(current, start, len_in, behavior);
> }
> +
> +SYSCALL_DEFINE4(process_madvise, int, pidfd, unsigned long, start,
> + size_t, len_in, int, behavior)
> +{
> + int ret;
> + struct fd f;
> + struct pid *pid;
> + struct task_struct *tsk;
> + struct mm_struct *mm;
> +
> + f = fdget(pidfd);
> + if (!f.file)
> + return -EBADF;
> +
> + pid = pidfd_to_pid(f.file);
pidfd_to_pid() should not be directly exported since this allows
/proc/<pid> fds to be used too. That's something we won't be going
forward with. All new syscalls should only allow to operate on pidfds
created through CLONE_PIDFD or pidfd_open() (cf. [1]).
So e.g. please export a simple helper like
struct pid *pidfd_to_pid(const struct file *file)
{
if (file->f_op == &pidfd_fops)
return file->private_data;
return NULL;
}
turning the old pidfd_to_pid() into something like:
static struct pid *__fd_to_pid(const struct file *file)
{
struct pid *pid;
pid = pidfd_to_pid(file);
if (pid)
return pid;
return tgid_pidfd_to_pid(file);
}
All new syscalls should only be using anon inode pidfds since they can
actually have a clean security model built around them in the future.
Note, pidfd_open() will be sent out together with making pidfds pollable
for the 5.3 merge window.
[1]: https://lore.kernel.org/lkml/20190520155630.21684-1-christian@xxxxxxxxxx/
Thanks!
Christian