From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:36:44
Now, we have MADV_PAGEOUT and MADV_COLD as madvise hinting API. With that,
application could give hints to kernel what memory range are preferred to be
reclaimed. However, in some platform(e.g., Android), the information
required to make the hinting decision is not known to the app.
Instead, it is known to a centralized userspace daemon(e.g., ActivityManagerService),
and that daemon must be able to initiate reclaim on its own without any app
involvement.
To solve the concern, this patch introduces new syscall - process_madvise(2).
Bascially, it's same with madvise(2) syscall but it has some differences.
1. It needs pidfd of target process to provide the hint
2. It supports only MADV_{COLD|PAGEOUT|MERGEABLE|UNMEREABLE} at this moment.
Other hints in madvise will be opened when there are explicit requests from
community to prevent unexpected bugs we couldn't support.
3. Only privileged processes can do something for other process's address
space.
For more detail of the new API, please see "mm: introduce external memory hinting API"
description in this patchset.
* from v6 - https://lore.kernel.org/linux-api/20200219014433.88424-1-minchan@kernel.org/
* fix comments and descriptions - Suren
* Add Reviewed-by - Suren
* fix build break reported by 0-day
* from v5 - https://lore.kernel.org/linux-mm/20200214170520.160271-1-minchan@kernel.org/
* use null task and requestor's mm for io_madvise - Jann and Jens
* use right commit description for moving pidfd_get_pid - Christoph
* from v4 - https://lore.kernel.org/linux-mm/20200212233946.246210-1-minchan@kernel.org/
* pass mm down to functions, not accessing task->mm - Jann
* clean up - Alexander
* add Reviewed-by - Alexander, SeongJae
* patch reordering
* from v3 - https://lore.kernel.org/linux-mm/20200128001641.5086-1-minchan@kernel.org/
* verify task->mm aftere access_mm - Oleg
* split some patches for easy review - Alexander
* clean up fatal signal checking - Suren
* from v2 - https://lore.kernel.org/linux-mm/20200116235953.163318-1-minchan@kernel.org/
* check signal callee and caller to bail out - Kirill Tkhai
* put more clarification for justification of new API
* from v1 - https://lore.kernel.org/linux-mm/20200110213433.94739-1-minchan@kernel.org/
* fix syscall number - SeongJae
* use get_pid_task - Kirill Tkhai
* extend API to support pid as well as pidfd - Kirill Tkhai
Minchan Kim (5):
mm: pass task and mm to do_madvise
mm: introduce external memory hinting API
mm: check fatal signal pending of target process
pid: move pidfd_get_pid function to pid.c
mm: support both pid and pidfd for process_madvise
Oleksandr Natalenko (2):
mm/madvise: employ mmget_still_valid for write lock
mm/madvise: allow KSM hints for remote API
arch/alpha/kernel/syscalls/syscall.tbl | 1 +
arch/arm/tools/syscall.tbl | 1 +
arch/arm64/include/asm/unistd.h | 2 +-
arch/arm64/include/asm/unistd32.h | 2 +
arch/ia64/kernel/syscalls/syscall.tbl | 1 +
arch/m68k/kernel/syscalls/syscall.tbl | 1 +
arch/microblaze/kernel/syscalls/syscall.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n32.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n64.tbl | 1 +
arch/parisc/kernel/syscalls/syscall.tbl | 1 +
arch/powerpc/kernel/syscalls/syscall.tbl | 1 +
arch/s390/kernel/syscalls/syscall.tbl | 1 +
arch/sh/kernel/syscalls/syscall.tbl | 1 +
arch/sparc/kernel/syscalls/syscall.tbl | 1 +
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
arch/xtensa/kernel/syscalls/syscall.tbl | 1 +
fs/io_uring.c | 2 +-
include/linux/mm.h | 3 +-
include/linux/pid.h | 1 +
include/linux/syscalls.h | 3 +
include/uapi/asm-generic/unistd.h | 4 +-
kernel/exit.c | 17 ---
kernel/pid.c | 17 +++
kernel/sys_ni.c | 1 +
mm/madvise.c | 144 ++++++++++++++++----
26 files changed, 167 insertions(+), 44 deletions(-)
--
2.25.0.265.gbab2e86ba0-goog
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:36:46
In upcoming patches, do_madvise will be called from external process
context so we shouldn't asssume "current" is always hinted process's
task_struct. Furthermore, we couldn't access mm_struct via task->mm
once it's verified by access_mm which will be introduced in next
patch[1]. And let's pass *current* and current->mm as arguments of
do_madvise so it shouldn't change existing behavior but prepare
next patch to make review easy.
Note: io_madvise pass NULL as target_task argument of do_madvise
because it couldn't know who is target.
[1] http://lore.kernel.org/r/CAG48ez27=pwm5m_N_988xT1huO7g7h6arTQL44zev6TD-h-7Tg@mail.gmail.com
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jann Horn <jannh@google.com>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
fs/io_uring.c | 2 +-
include/linux/mm.h | 3 ++-
mm/madvise.c | 34 +++++++++++++++++++---------------
3 files changed, 22 insertions(+), 17 deletions(-)
@@ -254,6 +254,7 @@ static long madvise_willneed(struct vm_area_struct *vma,structvm_area_struct**prev,unsignedlongstart,unsignedlongend){+structmm_struct*mm=vma->vm_mm;structfile*file=vma->vm_file;loff_toffset;
@@ -288,12 +289,12 @@ static long madvise_willneed(struct vm_area_struct *vma,*/*prev=NULL;/* tell sys_madvise we drop mmap_sem */get_file(file);-up_read(¤t->mm->mmap_sem);+up_read(&mm->mmap_sem);offset=(loff_t)(start-vma->vm_start)+((loff_t)vma->vm_pgoff<<PAGE_SHIFT);vfs_fadvise(file,offset,end-start,POSIX_FADV_WILLNEED);fput(file);-down_read(¤t->mm->mmap_sem);+down_read(&mm->mmap_sem);return0;}
@@ -676,7 +677,6 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,if(nr_swap){if(current->mm==mm)sync_mm_rss(mm);-add_mm_counter(mm,MM_SWAPENTS,nr_swap);}arch_leave_lazy_mmu_mode();
@@ -756,6 +756,8 @@ static long madvise_dontneed_free(struct vm_area_struct *vma,unsignedlongstart,unsignedlongend,intbehavior){+structmm_struct*mm=vma->vm_mm;+*prev=vma;if(!can_madv_lru_vma(vma))return-EINVAL;
@@ -763,8 +765,8 @@ static long madvise_dontneed_free(struct vm_area_struct *vma,if(!userfaultfd_remove(vma,start,end)){*prev=NULL;/* mmap_sem has been dropped, prev is stale */-down_read(¤t->mm->mmap_sem);-vma=find_vma(current->mm,start);+down_read(&mm->mmap_sem);+vma=find_vma(mm,start);if(!vma)return-ENOMEM;if(start<vma->vm_start){
@@ -818,6 +820,7 @@ static long madvise_remove(struct vm_area_struct *vma,loff_toffset;interror;structfile*f;+structmm_struct*mm=vma->vm_mm;*prev=NULL;/* tell sys_madvise we drop mmap_sem */
@@ -845,13 +848,13 @@ static long madvise_remove(struct vm_area_struct *vma,get_file(f);if(userfaultfd_remove(vma,start,end)){/* mmap_sem was not released by userfaultfd_remove() */-up_read(¤t->mm->mmap_sem);+up_read(&mm->mmap_sem);}error=vfs_fallocate(f,FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE,offset,end-start);fput(f);-down_read(¤t->mm->mmap_sem);+down_read(&mm->mmap_sem);returnerror;}
@@ -1082,10 +1086,10 @@ int do_madvise(unsigned long start, size_t len_in, int behavior)write=madvise_need_mmap_write(behavior);if(write){-if(down_write_killable(¤t->mm->mmap_sem))+if(down_write_killable(&mm->mmap_sem))return-EINTR;}else{-down_read(¤t->mm->mmap_sem);+down_read(&mm->mmap_sem);}/*
@@ -1093,7 +1097,7 @@ int do_madvise(unsigned long start, size_t len_in, int behavior)*ranges,justignorethem,butreturn-ENOMEMattheend.*-differentfromthewayofhandlinginmlocketc.*/-vma=find_vma_prev(current->mm,start,&prev);+vma=find_vma_prev(mm,start,&prev);if(vma&&start>vma->vm_start)prev=vma;
@@ -1130,19 +1134,19 @@ int do_madvise(unsigned long start, size_t len_in, int behavior)if(prev)vma=prev->vm_next;else/* madvise_remove dropped mmap_sem */-vma=find_vma(current->mm,start);+vma=find_vma(mm,start);}out:blk_finish_plug(&plug);if(write)-up_write(¤t->mm->mmap_sem);+up_write(&mm->mmap_sem);else-up_read(¤t->mm->mmap_sem);+up_read(&mm->mmap_sem);returnerror;}SYSCALL_DEFINE3(madvise,unsignedlong,start,size_t,len_in,int,behavior){-returndo_madvise(start,len_in,behavior);+returndo_madvise(current,current->mm,start,len_in,behavior);}
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:36:49
There is usecase that System Management Software(SMS) want to give
a memory hint like MADV_[COLD|PAGEEOUT] to other processes and
in the case of Android, it is the ActivityManagerService.
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 a new syscall process_madvise(2).
It uses pidfd of an external process to give the hint.
int process_madvise(int pidfd, void *addr, size_t length, int advise,
unsigned long flag);
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 ptrace the process could use it successfully.
The flag argument is reserved for future use if we need to extend the
API.
I think supporting all hints madvise has/will supported/support to
process_madvise is rather risky. Because we are not sure all hints make
sense from external process and implementation for the hint may rely on
the caller being in the current context so it could be error-prone.
Thus, I just limited hints as MADV_[COLD|PAGEOUT] in this patch.
If someone want to add other hints, we could hear hear the usecase and
review it for each hint. It's safer for maintenance rather than
introducing a buggy syscall but hard to fix it later.
Q.1 - Why does any external entity have better knowledge?
Quote from Sandeep
"For Android, every application (including the special SystemServer) are forked
from Zygote. The reason of course is to share as many libraries and classes between
the two as possible to benefit from the preloading during boot.
After applications start, (almost) all of the APIs end up calling into this
SystemServer process over IPC (binder) and back to the application.
In a fully running system, the SystemServer monitors every single process
periodically to calculate their PSS / RSS and also decides which process is
"important" to the user for interactivity.
So, because of how these processes start _and_ the fact that the SystemServer
is looping to monitor each process, it does tend to *know* which address
range of the application is not used / useful.
Besides, we can never rely on applications to clean things up themselves.
We've had the "hey app1, the system is low on memory, please trim your
memory usage down" notifications for a long time[1]. They rely on
applications honoring the broadcasts and very few do.
So, if we want to avoid the inevitable killing of the application and
restarting it, some way to be able to tell the OS about unimportant memory in
these applications will be useful.
- ssp
Q.2 - How to guarantee the race(i.e., object validation) between when giving a
hint from an external process and get the hint from the target process?
process_madvise operates on the target process's address space as it exists
at the instant that process_madvise is called. If the space target process
can run between the time the process_madvise process inspects the target
process address space and the time that process_madvise is actually called,
process_madvise may operate on memory regions that the calling process does
not expect. It's the responsibility of the process calling process_madvise
to close this race condition. For example, the calling process can suspend
the target process with ptrace, SIGSTOP, or the freezer cgroup so that it
doesn't have an opportunity to change its own address space before
process_madvise is called. Another option is to operate on memory regions
that the caller knows a priori will be unchanged in the target process.
Yet another option is to accept the race for certain process_madvise calls
after reasoning that mistargeting will do no harm. The suggested API itself
does not provide synchronization. It also apply other APIs like move_pages,
process_vm_write.
The race isn't really a problem though. Why is it so wrong to require
that callers do their own synchronization in some manner? Nobody objects
to write(2) merely because it's possible for two processes to open the same
file and clobber each other's writes --- instead, we tell people to use
flock or something. Think about mmap. It never guarantees newly allocated
address space is still valid when the user tries to access it because other
threads could unmap the memory right before. That's where we need
synchronization by using other API or design from userside. It shouldn't
be part of API itself. If someone needs more fine-grained synchronization
rather than process level, there were two ideas suggested - cookie[2] and
anon-fd[3]. Both are applicable via using last reserved argument of the API
but I don't think it's necessary right now since we have already ways to
prevent the race so don't want to add additional complexity with more
fine-grained optimization model.
To make the API extend, it reserved an unsigned long as last argument
so we could support it in future if someone really needs it.
Q.3 - Why doesn't ptrace work?
Injecting an madvise in the target process using ptrace would not work for us
because such injected madvise would have to be executed by the target process,
which means that process would have to be runnable and that creates the risk
of the abovementioned race and hinting a wrong VMA. Furthermore, we want to
act the hint in caller's context, not calle because calle is usually limited
in cpuset/cgroups or even freezed state so they can't act by themselves
quick enough, which causes more thrashing/kill. It doesn't work if the
target process are ptraced(e.g., strace, debugger, minidump) because a
process can have at most one ptracer.
[1] https://developer.android.com/topic/performance/memory"
[2] process_getinfo for getting the cookie which is updated whenever
vma of process address layout are changed - Daniel Colascione
- https://lore.kernel.org/lkml/20190520035254.57579-1-minchan@kernel.org/T/#m7694416fd179b2066a2c62b5b139b14e3894e224
[3] anonymous fd which is used for the object(i.e., address range)
validation - Michal Hocko
- https://lore.kernel.org/lkml/20200120112722.GY18451@dhcp22.suse.cz/
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
arch/alpha/kernel/syscalls/syscall.tbl | 1 +
arch/arm/tools/syscall.tbl | 1 +
arch/arm64/include/asm/unistd.h | 2 +-
arch/arm64/include/asm/unistd32.h | 2 +
arch/ia64/kernel/syscalls/syscall.tbl | 1 +
arch/m68k/kernel/syscalls/syscall.tbl | 1 +
arch/microblaze/kernel/syscalls/syscall.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n32.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n64.tbl | 1 +
arch/parisc/kernel/syscalls/syscall.tbl | 1 +
arch/powerpc/kernel/syscalls/syscall.tbl | 1 +
arch/s390/kernel/syscalls/syscall.tbl | 1 +
arch/sh/kernel/syscalls/syscall.tbl | 1 +
arch/sparc/kernel/syscalls/syscall.tbl | 1 +
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
arch/xtensa/kernel/syscalls/syscall.tbl | 1 +
include/linux/syscalls.h | 2 +
include/uapi/asm-generic/unistd.h | 4 +-
kernel/sys_ni.c | 1 +
mm/madvise.c | 64 +++++++++++++++++++++
21 files changed, 88 insertions(+), 2 deletions(-)
@@ -477,3 +477,4 @@ # 545 reserved for clone3 547 common openat2 sys_openat2 548 common pidfd_getfd sys_pidfd_getfd+549 common process_madvise sys_process_madvise
@@ -451,3 +451,4 @@ 435 common clone3 sys_clone3 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
@@ -358,3 +358,4 @@ # 435 reserved for clone3 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
@@ -437,3 +437,4 @@ 435 common clone3 __sys_clone3 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
@@ -443,3 +443,4 @@ 435 common clone3 sys_clone3 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
@@ -435,3 +435,4 @@ 435 common clone3 sys_clone3_wrapper 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
@@ -440,3 +440,4 @@ # 435 reserved for clone3 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
@@ -483,3 +483,4 @@ # 435 reserved for clone3 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
@@ -359,6 +359,7 @@ 435 common clone3 __x64_sys_clone3/ptregs 437 common openat2 __x64_sys_openat2 438 common pidfd_getfd __x64_sys_pidfd_getfd+439 common process_madvise __x64_sys_process_madvise # # x32-specific system call numbers start at 512 to avoid cache impact
@@ -408,3 +408,4 @@ 435 common clone3 sys_clone3 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd+439 common process_madvise sys_process_madvise
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:36:54
process_madvise syscall needs pidfd_get_pid function to translate
pidfd to pid so this patch move the function to kernel/pid.c.
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Christian Brauner <christian@brauner.io>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Suggested-by: Alexander Duyck <redacted>
Reviewed-by: Alexander Duyck <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
include/linux/pid.h | 1 +
kernel/exit.c | 17 -----------------
kernel/pid.c | 17 +++++++++++++++++
3 files changed, 18 insertions(+), 17 deletions(-)
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:36:57
Bail out to prevent unnecessary CPU overhead if target process has
pending fatal signal during (MADV_COLD|MADV_PAGEOUT) operation.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
mm/madvise.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:36:59
From: Oleksandr Natalenko <redacted>
Do the very same trick as we already do since 04f5866e41fb. KSM hints
will require locking mmap_sem for write since they modify vm_flags, so
for remote KSM hinting this additional check is needed.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Oleksandr Natalenko <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
mm/madvise.c | 3 +++
1 file changed, 3 insertions(+)
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:38:12
From: Oleksandr Natalenko <redacted>
It all began with the fact that KSM works only on memory that is marked
by madvise(). And the only way to get around that is to either:
* use LD_PRELOAD; or
* patch the kernel with something like UKSM or PKSM.
(i skip ptrace can of worms here intentionally)
To overcome this restriction, lets employ a new remote madvise API. This
can be used by some small userspace helper daemon that will do auto-KSM
job for us.
I think of two major consumers of remote KSM hints:
* hosts, that run containers, especially similar ones and especially in
a trusted environment, sharing the same runtime like Node.js;
* heavy applications, that can be run in multiple instances, not
limited to opensource ones like Firefox, but also those that cannot be
modified since they are binary-only and, maybe, statically linked.
Speaking of statistics, more numbers can be found in the very first
submission, that is related to this one [1]. For my current setup with
two Firefox instances I get 100 to 200 MiB saved for the second instance
depending on the amount of tabs.
1 FF instance with 15 tabs:
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
410
2 FF instances, second one has 12 tabs (all the tabs are different):
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
592
At the very moment I do not have specific numbers for containerised
workload, but those should be comparable in case the containers share
similar/same runtime.
[1] https://lore.kernel.org/patchwork/patch/1012142/
Reviewed-by: SeongJae Park <redacted>
Signed-off-by: Oleksandr Natalenko <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
mm/madvise.c | 4 ++++
1 file changed, 4 insertions(+)
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 19:38:22
There is a demand[1] to support pid as well pidfd for process_madvise
to reduce unnecessary syscall to get pidfd if the user has control of
the target process(ie, they could guarantee the process is not gone
or pid is not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(int which, pid_t pid, void *addr,
size_t length, int advise, unsigned long flag);
@which is actually idtype_t for userspace libray and currently,
it supports P_PID and P_PIDFD.
[1] https://lore.kernel.org/linux-mm/9d849087-3359-c4ab-fbec-859e8186c509@virtuozzo.com/
Cc: Christian Brauner <christian@brauner.io>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Suggested-by: Kirill Tkhai <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
include/linux/syscalls.h | 3 ++-
mm/madvise.c | 34 ++++++++++++++++++++++------------
2 files changed, 24 insertions(+), 13 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2020-03-02 21:16:21
On Mon, 2 Mar 2020 11:36:23 -0800 Minchan Kim [off-list ref] wrote:
Now, we have MADV_PAGEOUT and MADV_COLD as madvise hinting API. With that,
application could give hints to kernel what memory range are preferred to be
reclaimed. However, in some platform(e.g., Android), the information
required to make the hinting decision is not known to the app.
Instead, it is known to a centralized userspace daemon(e.g., ActivityManagerService),
and that daemon must be able to initiate reclaim on its own without any app
involvement.
To solve the concern, this patch introduces new syscall - process_madvise(2).
Bascially, it's same with madvise(2) syscall but it has some differences.
1. It needs pidfd of target process to provide the hint
2. It supports only MADV_{COLD|PAGEOUT|MERGEABLE|UNMEREABLE} at this moment.
Other hints in madvise will be opened when there are explicit requests from
community to prevent unexpected bugs we couldn't support.
3. Only privileged processes can do something for other process's address
space.
For more detail of the new API, please see "mm: introduce external memory hinting API"
description in this patchset.
Thanks, I grabbed these.
I massaged the patch titles significantly - mainly to alert readers to
the fact that we're proposing a new syscall.
Is a manpage for process_madvise(2) being prepared?
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-02 21:42:34
On Mon, Mar 02, 2020 at 01:16:18PM -0800, Andrew Morton wrote:
On Mon, 2 Mar 2020 11:36:23 -0800 Minchan Kim [off-list ref] wrote:
quoted
Now, we have MADV_PAGEOUT and MADV_COLD as madvise hinting API. With that,
application could give hints to kernel what memory range are preferred to be
reclaimed. However, in some platform(e.g., Android), the information
required to make the hinting decision is not known to the app.
Instead, it is known to a centralized userspace daemon(e.g., ActivityManagerService),
and that daemon must be able to initiate reclaim on its own without any app
involvement.
To solve the concern, this patch introduces new syscall - process_madvise(2).
Bascially, it's same with madvise(2) syscall but it has some differences.
1. It needs pidfd of target process to provide the hint
2. It supports only MADV_{COLD|PAGEOUT|MERGEABLE|UNMEREABLE} at this moment.
Other hints in madvise will be opened when there are explicit requests from
community to prevent unexpected bugs we couldn't support.
3. Only privileged processes can do something for other process's address
space.
For more detail of the new API, please see "mm: introduce external memory hinting API"
description in this patchset.
Thanks, I grabbed these.
I massaged the patch titles significantly - mainly to alert readers to
the fact that we're proposing a new syscall.
Is a manpage for process_madvise(2) being prepared?
In upcoming patches, do_madvise will be called from external process
context so we shouldn't asssume "current" is always hinted process's
task_struct.
Furthermore, we couldn't access mm_struct via task->mm
once it's verified by access_mm which will be introduced in next
patch[1].
I would suggest to replace with:
Furthermore, we must not access mm_struct via task->mm, but obtain it via
access_mm() once (in the following patch) and only use that pointer [1], so pass
it to do_madvise() as well. Note the vma->vm_mm pointers are safe, so we can use
them further down the call stack.
And let's pass *current* and current->mm as arguments of
do_madvise so it shouldn't change existing behavior but prepare
next patch to make review easy.
Note: io_madvise pass NULL as target_task argument of do_madvise
because it couldn't know who is target.
There is usecase that System Management Software(SMS) want to give
a memory hint like MADV_[COLD|PAGEEOUT] to other processes and
in the case of Android, it is the ActivityManagerService.
It's similar in spirit to madvise(MADV_WONTNEED), but the information
You mean MADV_DONTNEED?
required to make the reclaim decision is not known to the app.
This seems to be mixing up the differences between MADV_DONTNEED and
COLD/PAGEOUT and self-imposed vs external memory hints?
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 a new syscall process_madvise(2).
It uses pidfd of an external process to give the hint.
int process_madvise(int pidfd, void *addr, size_t length, int advise,
unsigned long flag);
It's more common to call the argument 'flags' not 'flag'? The code seems to call
it flags. Also in line with madvise(2), the 'advise' argument should rather be
'advice'. This is more important for the manpage, but let's be consistent.
...
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
For the core parts,
Reviewed-by: Vlastimil Babka <redacted>
Bail out to prevent unnecessary CPU overhead if target process has
pending fatal signal during (MADV_COLD|MADV_PAGEOUT) operation.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
@@ -316,6 +317,10 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,if(fatal_signal_pending(current))return-EINTR;+if(private->target_task&&+fatal_signal_pending(private->target_task))+return-EINTR;
With madvise(2) private->target_task will be current, thus current will be
tested twice. Not wrong, but maybe add a "private->target_task != current"
condition?
process_madvise syscall needs pidfd_get_pid function to translate
pidfd to pid so this patch move the function to kernel/pid.c.
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Christian Brauner <christian@brauner.io>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Suggested-by: Alexander Duyck <redacted>
Reviewed-by: Alexander Duyck <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
From: Christian Brauner <hidden> Date: 2020-03-06 11:14:11
On Mon, Mar 02, 2020 at 11:36:27AM -0800, Minchan Kim wrote:
process_madvise syscall needs pidfd_get_pid function to translate
pidfd to pid so this patch move the function to kernel/pid.c.
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Christian Brauner <christian@brauner.io>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Suggested-by: Alexander Duyck <redacted>
Reviewed-by: Alexander Duyck <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
There is a demand[1] to support pid as well pidfd for process_madvise
to reduce unnecessary syscall to get pidfd if the user has control of
the target process(ie, they could guarantee the process is not gone
or pid is not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(int which, pid_t pid, void *addr,
size_t length, int advise, unsigned long flag);
This is again halfway between kernel and userspace description, so if we stick
to userspace then it's:
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
@which is actually idtype_t for userspace libray and currently,
it supports P_PID and P_PIDFD.
[1] https://lore.kernel.org/linux-mm/9d849087-3359-c4ab-fbec-859e8186c509@virtuozzo.com/
Cc: Christian Brauner <christian@brauner.io>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Suggested-by: Kirill Tkhai <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
From: Oleksandr Natalenko <redacted>
Do the very same trick as we already do since 04f5866e41fb. KSM hints
will require locking mmap_sem for write since they modify vm_flags, so
for remote KSM hinting this additional check is needed.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Oleksandr Natalenko <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
---
mm/madvise.c | 3 +++
1 file changed, 3 insertions(+)
This will return 0, is that correct? Shoudln't there be a similar error e.g. as
when finding the task by pid fails (-ESRCH ?), because IIUC the task here is
going away and dumping the core?
quoted hunk
} else {
down_read(&mm->mmap_sem);
}
@@ -1169,6 +1171,7 @@ int do_madvise(struct task_struct *target_task, struct mm_struct *mm, } out: blk_finish_plug(&plug);+skip_mm: if (write) up_write(&mm->mmap_sem); else
This will return 0, is that correct? Shoudln't there be a similar error e.g. as
when finding the task by pid fails (-ESRCH ?), because IIUC the task here is
going away and dumping the core?
From: Oleksandr Natalenko <redacted>
It all began with the fact that KSM works only on memory that is marked
by madvise(). And the only way to get around that is to either:
* use LD_PRELOAD; or
* patch the kernel with something like UKSM or PKSM.
(i skip ptrace can of worms here intentionally)
To overcome this restriction, lets employ a new remote madvise API. This
can be used by some small userspace helper daemon that will do auto-KSM
job for us.
I think of two major consumers of remote KSM hints:
* hosts, that run containers, especially similar ones and especially in
a trusted environment, sharing the same runtime like Node.js;
* heavy applications, that can be run in multiple instances, not
limited to opensource ones like Firefox, but also those that cannot be
modified since they are binary-only and, maybe, statically linked.
Speaking of statistics, more numbers can be found in the very first
submission, that is related to this one [1]. For my current setup with
two Firefox instances I get 100 to 200 MiB saved for the second instance
depending on the amount of tabs.
1 FF instance with 15 tabs:
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
410
2 FF instances, second one has 12 tabs (all the tabs are different):
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
592
At the very moment I do not have specific numbers for containerised
workload, but those should be comparable in case the containers share
similar/same runtime.
[1] https://lore.kernel.org/patchwork/patch/1012142/
Reviewed-by: SeongJae Park <redacted>
Signed-off-by: Oleksandr Natalenko <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
This will lead to one process calling unmerge_ksm_pages() of another. There's a
(signal_pending(current)) test there, should it check also the other task,
analogically to task 3?
Then break_ksm() is fine as it is, as ksmd also calls it, right?
On Fri, Mar 06, 2020 at 02:13:49PM +0100, Vlastimil Babka wrote:
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
From: Oleksandr Natalenko <redacted>
It all began with the fact that KSM works only on memory that is marked
by madvise(). And the only way to get around that is to either:
* use LD_PRELOAD; or
* patch the kernel with something like UKSM or PKSM.
(i skip ptrace can of worms here intentionally)
To overcome this restriction, lets employ a new remote madvise API. This
can be used by some small userspace helper daemon that will do auto-KSM
job for us.
I think of two major consumers of remote KSM hints:
* hosts, that run containers, especially similar ones and especially in
a trusted environment, sharing the same runtime like Node.js;
* heavy applications, that can be run in multiple instances, not
limited to opensource ones like Firefox, but also those that cannot be
modified since they are binary-only and, maybe, statically linked.
Speaking of statistics, more numbers can be found in the very first
submission, that is related to this one [1]. For my current setup with
two Firefox instances I get 100 to 200 MiB saved for the second instance
depending on the amount of tabs.
1 FF instance with 15 tabs:
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
410
2 FF instances, second one has 12 tabs (all the tabs are different):
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
592
At the very moment I do not have specific numbers for containerised
workload, but those should be comparable in case the containers share
similar/same runtime.
[1] https://lore.kernel.org/patchwork/patch/1012142/
Reviewed-by: SeongJae Park <redacted>
Signed-off-by: Oleksandr Natalenko <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
This will lead to one process calling unmerge_ksm_pages() of another. There's a
(signal_pending(current)) test there, should it check also the other task,
analogically to task 3?
Do we care about current there then? Shall we just pass mm into unmerge_ksm_pages and check the signals of the target task only, be it current or something else?
Then break_ksm() is fine as it is, as ksmd also calls it, right?
I think break_ksm() cares only about mmap_sem protection, so we should
be fine here.
This will return 0, is that correct? Shoudln't there be a similar error e.g. as
when finding the task by pid fails (-ESRCH ?), because IIUC the task here is
going away and dumping the core?
On Fri, Mar 06, 2020 at 02:13:49PM +0100, Vlastimil Babka wrote:
quoted
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
From: Oleksandr Natalenko <redacted>
It all began with the fact that KSM works only on memory that is marked
by madvise(). And the only way to get around that is to either:
* use LD_PRELOAD; or
* patch the kernel with something like UKSM or PKSM.
(i skip ptrace can of worms here intentionally)
To overcome this restriction, lets employ a new remote madvise API. This
can be used by some small userspace helper daemon that will do auto-KSM
job for us.
I think of two major consumers of remote KSM hints:
* hosts, that run containers, especially similar ones and especially in
a trusted environment, sharing the same runtime like Node.js;
Ah, I forgot to ask, given the discussion of races in patch 2 (Question 2),
where android can stop the tasks to apply the madvise hints in a race-free
manner, how does that work for remote KSM hints in your scenarios, especially
the one above?
quoted
quoted
* heavy applications, that can be run in multiple instances, not
limited to opensource ones like Firefox, but also those that cannot be
modified since they are binary-only and, maybe, statically linked.
Speaking of statistics, more numbers can be found in the very first
submission, that is related to this one [1]. For my current setup with
two Firefox instances I get 100 to 200 MiB saved for the second instance
depending on the amount of tabs.
1 FF instance with 15 tabs:
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
410
2 FF instances, second one has 12 tabs (all the tabs are different):
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
592
At the very moment I do not have specific numbers for containerised
workload, but those should be comparable in case the containers share
similar/same runtime.
[1] https://lore.kernel.org/patchwork/patch/1012142/
Reviewed-by: SeongJae Park <redacted>
Signed-off-by: Oleksandr Natalenko <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
This will lead to one process calling unmerge_ksm_pages() of another. There's a
(signal_pending(current)) test there, should it check also the other task,
analogically to task 3?
Do we care about current there then? Shall we just pass mm into unmerge_ksm_pages and check the signals of the target task only, be it current or something else?
Dunno, it's nice to react to signals quickly, for any proces that gets them, no?
quoted
Then break_ksm() is fine as it is, as ksmd also calls it, right?
I think break_ksm() cares only about mmap_sem protection, so we should
be fine here.
This will return 0, is that correct? Shoudln't there be a similar error e.g. as
when finding the task by pid fails (-ESRCH ?), because IIUC the task here is
going away and dumping the core?
Minchan, shall you take this change into the next submission, or you'd
prefer me sending it to you as a new patch?
--
Best regards,
Oleksandr Natalenko (post-factum)
Principal Software Maintenance Engineer
On Fri, Mar 06, 2020 at 05:08:18PM +0100, Vlastimil Babka wrote:
On 3/6/20 2:41 PM, Oleksandr Natalenko wrote:
quoted
On Fri, Mar 06, 2020 at 02:13:49PM +0100, Vlastimil Babka wrote:
quoted
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
From: Oleksandr Natalenko <redacted>
It all began with the fact that KSM works only on memory that is marked
by madvise(). And the only way to get around that is to either:
* use LD_PRELOAD; or
* patch the kernel with something like UKSM or PKSM.
(i skip ptrace can of worms here intentionally)
To overcome this restriction, lets employ a new remote madvise API. This
can be used by some small userspace helper daemon that will do auto-KSM
job for us.
I think of two major consumers of remote KSM hints:
* hosts, that run containers, especially similar ones and especially in
a trusted environment, sharing the same runtime like Node.js;
Ah, I forgot to ask, given the discussion of races in patch 2 (Question 2),
where android can stop the tasks to apply the madvise hints in a race-free
manner, how does that work for remote KSM hints in your scenarios, especially
the one above?
We have cgroup.freeze for that.
quoted
quoted
quoted
* heavy applications, that can be run in multiple instances, not
limited to opensource ones like Firefox, but also those that cannot be
modified since they are binary-only and, maybe, statically linked.
Speaking of statistics, more numbers can be found in the very first
submission, that is related to this one [1]. For my current setup with
two Firefox instances I get 100 to 200 MiB saved for the second instance
depending on the amount of tabs.
1 FF instance with 15 tabs:
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
410
2 FF instances, second one has 12 tabs (all the tabs are different):
$ echo "$(cat /sys/kernel/mm/ksm/pages_sharing) * 4 / 1024" | bc
592
At the very moment I do not have specific numbers for containerised
workload, but those should be comparable in case the containers share
similar/same runtime.
[1] https://lore.kernel.org/patchwork/patch/1012142/
Reviewed-by: SeongJae Park <redacted>
Signed-off-by: Oleksandr Natalenko <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
This will lead to one process calling unmerge_ksm_pages() of another. There's a
(signal_pending(current)) test there, should it check also the other task,
analogically to task 3?
Do we care about current there then? Shall we just pass mm into unmerge_ksm_pages and check the signals of the target task only, be it current or something else?
Dunno, it's nice to react to signals quickly, for any proces that gets them, no?
@@ -849,7 +849,8 @@ static int unmerge_ksm_pages(struct vm_area_struct *vma,for(addr=start;addr<end&&!err;addr+=PAGE_SIZE){if(ksm_test_exit(vma->vm_mm))break;-if(signal_pending(current))+if(signal_pending(current)||+signal_pending(rcu_dereference(vma->vm_mm->owner)))err=-ERESTARTSYS;elseerr=break_ksm(vma,addr);
===
BTW, this won't work with !CONFIG_MEMCG, so probably task_struct should be
passed through instead. IIUC, this would also require amending struct
mm_slot in order to share the same code path with ksmd.
I'm not sure I've seen such a culprit anywhere else, so I'm in doubt
this would be a correct thing to do.
Ideas?
quoted
quoted
Then break_ksm() is fine as it is, as ksmd also calls it, right?
I think break_ksm() cares only about mmap_sem protection, so we should
be fine here.
@@ -849,7 +849,8 @@ static int unmerge_ksm_pages(struct vm_area_struct *vma,for(addr=start;addr<end&&!err;addr+=PAGE_SIZE){if(ksm_test_exit(vma->vm_mm))break;-if(signal_pending(current))+if(signal_pending(current)||+signal_pending(rcu_dereference(vma->vm_mm->owner)))err=-ERESTARTSYS;elseerr=break_ksm(vma,addr);
===
This is broken because mm might be attached to different tasks.
AFAIU this check is meant to allow quick backoff of the _calling_
process so that it doesn't waste time when the context is killed
already. I do not understand why should we care about any other context
here? What is the actual problem this would solve?
--
Michal Hocko
SUSE Labs
@@ -849,7 +849,8 @@ static int unmerge_ksm_pages(struct vm_area_struct *vma,for(addr=start;addr<end&&!err;addr+=PAGE_SIZE){if(ksm_test_exit(vma->vm_mm))break;-if(signal_pending(current))+if(signal_pending(current)||+signal_pending(rcu_dereference(vma->vm_mm->owner)))err=-ERESTARTSYS;elseerr=break_ksm(vma,addr);
===
This is broken because mm might be attached to different tasks.
AFAIU this check is meant to allow quick backoff of the _calling_
process so that it doesn't waste time when the context is killed
already. I do not understand why should we care about any other context
here? What is the actual problem this would solve?
I agree with you, but still trying to understand what does Vlastimil mean
:).
--
Michal Hocko
SUSE Labs
--
Best regards,
Oleksandr Natalenko (post-factum)
Principal Software Maintenance Engineer
@@ -849,7 +849,8 @@ static int unmerge_ksm_pages(struct vm_area_struct *vma,for(addr=start;addr<end&&!err;addr+=PAGE_SIZE){if(ksm_test_exit(vma->vm_mm))break;-if(signal_pending(current))+if(signal_pending(current)||+signal_pending(rcu_dereference(vma->vm_mm->owner)))err=-ERESTARTSYS;elseerr=break_ksm(vma,addr);
===
This is broken because mm might be attached to different tasks.
AFAIU this check is meant to allow quick backoff of the _calling_
process so that it doesn't waste time when the context is killed
already. I do not understand why should we care about any other context
here? What is the actual problem this would solve?
I agree with you, but still trying to understand what does Vlastimil mean
:).
Well you wondered if we should stop caring about current, and I said that
probably wouldn't be nice.
As for caring about the other task, patch 3/7 does that for
(MADV_COLD|MADV_PAGEOUT) so I just pointed out that the KSM case doesn't. AFAIU
if we don't check the signals, we might be blocking the killed task from exiting?
@@ -849,7 +849,8 @@ static int unmerge_ksm_pages(struct vm_area_struct *vma,for(addr=start;addr<end&&!err;addr+=PAGE_SIZE){if(ksm_test_exit(vma->vm_mm))break;-if(signal_pending(current))+if(signal_pending(current)||+signal_pending(rcu_dereference(vma->vm_mm->owner)))err=-ERESTARTSYS;elseerr=break_ksm(vma,addr);
===
This is broken because mm might be attached to different tasks.
AFAIU this check is meant to allow quick backoff of the _calling_
process so that it doesn't waste time when the context is killed
already. I do not understand why should we care about any other context
here? What is the actual problem this would solve?
I agree with you, but still trying to understand what does Vlastimil mean
:).
Well you wondered if we should stop caring about current, and I said that
probably wouldn't be nice.
As for caring about the other task, patch 3/7 does that for
(MADV_COLD|MADV_PAGEOUT) so I just pointed out that the KSM case doesn't. AFAIU
if we don't check the signals, we might be blocking the killed task from exiting?
I would have to double check but I do not think this would be a problem
because the remote task should take mmget to prevent address space to
vanish under its feet. That should also rule out the exclusive mmap_sem
usage from the exit path.
--
Michal Hocko
SUSE Labs
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-10 22:20:15
On Thu, Mar 05, 2020 at 07:15:10PM +0100, Vlastimil Babka wrote:
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
There is usecase that System Management Software(SMS) want to give
a memory hint like MADV_[COLD|PAGEEOUT] to other processes and
in the case of Android, it is the ActivityManagerService.
It's similar in spirit to madvise(MADV_WONTNEED), but the information
You mean MADV_DONTNEED?
Mean to DONT_NEED's future version.
quoted
required to make the reclaim decision is not known to the app.
This seems to be mixing up the differences between MADV_DONTNEED and
COLD/PAGEOUT and self-imposed vs external memory hints?
Sorry, I don't understand what you want here.
quoted
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 a new syscall process_madvise(2).
It uses pidfd of an external process to give the hint.
int process_madvise(int pidfd, void *addr, size_t length, int advise,
unsigned long flag);
It's more common to call the argument 'flags' not 'flag'? The code seems to call
it flags. Also in line with madvise(2), the 'advise' argument should rather be
'advice'. This is more important for the manpage, but let's be consistent.
Yub, I will send the patch along with your comment in previous patch.
...
quoted
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
For the core parts,
Reviewed-by: Vlastimil Babka <redacted>
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-10 22:24:14
On Fri, Mar 06, 2020 at 11:22:07AM +0100, Vlastimil Babka wrote:
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
Bail out to prevent unnecessary CPU overhead if target process has
pending fatal signal during (MADV_COLD|MADV_PAGEOUT) operation.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
@@ -316,6 +317,10 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,if(fatal_signal_pending(current))return-EINTR;+if(private->target_task&&+fatal_signal_pending(private->target_task))+return-EINTR;
With madvise(2) private->target_task will be current, thus current will be
tested twice. Not wrong, but maybe add a "private->target_task != current"
condition?
It was in old series but removed because reviewer(IIRC, suren) wanted it.
I am not strong preference either way. Since you said it's nit and
considering other reviewer wanted to remove it, I will not change
further.
Thanks!
This will return 0, is that correct? Shoudln't there be a similar error e.g. as
when finding the task by pid fails (-ESRCH ?), because IIUC the task here is
going away and dumping the core?
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-11 00:36:52
On Tue, Mar 10, 2020 at 03:20:08PM -0700, Minchan Kim wrote:
On Thu, Mar 05, 2020 at 07:15:10PM +0100, Vlastimil Babka wrote:
quoted
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
There is usecase that System Management Software(SMS) want to give
a memory hint like MADV_[COLD|PAGEEOUT] to other processes and
in the case of Android, it is the ActivityManagerService.
It's similar in spirit to madvise(MADV_WONTNEED), but the information
You mean MADV_DONTNEED?
Mean to DONT_NEED's future version.
quoted
quoted
required to make the reclaim decision is not known to the app.
This seems to be mixing up the differences between MADV_DONTNEED and
COLD/PAGEOUT and self-imposed vs external memory hints?
Sorry, I don't understand what you want here.
quoted
quoted
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 a new syscall process_madvise(2).
It uses pidfd of an external process to give the hint.
int process_madvise(int pidfd, void *addr, size_t length, int advise,
unsigned long flag);
It's more common to call the argument 'flags' not 'flag'? The code seems to call
it flags. Also in line with madvise(2), the 'advise' argument should rather be
'advice'. This is more important for the manpage, but let's be consistent.
Yub, I will send the patch along with your comment in previous patch.
Only place to use *advice* in kernel is comment in madvise_willneed.
Al other places use advise in kernel so I wanted to be more consistent
with other kernel sources. For man page, we could use the term "advice",
no problem.
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-11 00:42:57
On Fri, Mar 06, 2020 at 12:14:19PM +0100, Vlastimil Babka wrote:
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
There is a demand[1] to support pid as well pidfd for process_madvise
to reduce unnecessary syscall to get pidfd if the user has control of
the target process(ie, they could guarantee the process is not gone
or pid is not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(int which, pid_t pid, void *addr,
size_t length, int advise, unsigned long flag);
This is again halfway between kernel and userspace description, so if we stick
to userspace then it's:
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
Yub.
quoted
@which is actually idtype_t for userspace libray and currently,
it supports P_PID and P_PIDFD.
[1] https://lore.kernel.org/linux-mm/9d849087-3359-c4ab-fbec-859e8186c509@virtuozzo.com/
Cc: Christian Brauner <christian@brauner.io>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Suggested-by: Kirill Tkhai <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
On Thu, Mar 05, 2020 at 07:15:10PM +0100, Vlastimil Babka wrote:
quoted
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
There is usecase that System Management Software(SMS) want to give
a memory hint like MADV_[COLD|PAGEEOUT] to other processes and
in the case of Android, it is the ActivityManagerService.
It's similar in spirit to madvise(MADV_WONTNEED), but the information
You mean MADV_DONTNEED?
Mean to DONT_NEED's future version.
What's that exactly?
quoted
quoted
required to make the reclaim decision is not known to the app.
This seems to be mixing up the differences between MADV_DONTNEED and
COLD/PAGEOUT and self-imposed vs external memory hints?
Sorry, I don't understand what you want here.
You say that process_madvise(MADV_[COLD|PAGEEOUT]) is similar to
madvise(MADV_WONTNEED) but the difference is that the information
required to make the reclaim decision is not known to the app.
I see two differences. One is madvise vs process_madvise, which is explained by
"reclaim decision is not known to the app."
The other is MADV_WONTNEED vs MADV_[COLD|PAGEEOUT], which is... I'm not sure
until you say what's "DONT_NEED's future version" :D
Anyway I assume this part is from the versions where the new COLD and PAGEOUT
flags were introduced together with external memory hinting API?
From: Minchan Kim <minchan@kernel.org> Date: 2020-03-12 20:23:44
On Thu, Mar 12, 2020 at 01:40:26PM +0100, Vlastimil Babka wrote:
On 3/10/20 11:20 PM, Minchan Kim wrote:
quoted
On Thu, Mar 05, 2020 at 07:15:10PM +0100, Vlastimil Babka wrote:
quoted
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
There is usecase that System Management Software(SMS) want to give
a memory hint like MADV_[COLD|PAGEEOUT] to other processes and
in the case of Android, it is the ActivityManagerService.
It's similar in spirit to madvise(MADV_WONTNEED), but the information
You mean MADV_DONTNEED?
Mean to DONT_NEED's future version.
What's that exactly?
For zapping timing point of view, dontneed acts immediately so it's very
strong hint. However, MADV_COLD and MADV_PAGEOUT does lazily depending
on the future. For example, the page never discarded if it's touched
before the tail of LRU. If other process which shared the page has
touched the page, never paging out.
quoted
quoted
quoted
required to make the reclaim decision is not known to the app.
This seems to be mixing up the differences between MADV_DONTNEED and
COLD/PAGEOUT and self-imposed vs external memory hints?
Sorry, I don't understand what you want here.
You say that process_madvise(MADV_[COLD|PAGEEOUT]) is similar to
madvise(MADV_WONTNEED) but the difference is that the information
required to make the reclaim decision is not known to the app.
I see two differences. One is madvise vs process_madvise, which is explained by
"reclaim decision is not known to the app."
The other is MADV_WONTNEED vs MADV_[COLD|PAGEEOUT], which is... I'm not sure
until you say what's "DONT_NEED's future version" :D
Anyway I assume this part is from the versions where the new COLD and PAGEOUT
flags were introduced together with external memory hinting API?
Exactly. Maybe it would be better to remove the part once we merged the
COLD and PAGEOUT now.
Thanks for the review, Vlastimil!
From: Minchan Kim <minchan@kernel.org> Date: 2020-05-08 18:21:48
On Thu, Mar 05, 2020 at 04:48:12PM +0100, Vlastimil Babka wrote:
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
In upcoming patches, do_madvise will be called from external process
context so we shouldn't asssume "current" is always hinted process's
task_struct.
quoted
Furthermore, we couldn't access mm_struct via task->mm
once it's verified by access_mm which will be introduced in next
patch[1].
I would suggest to replace with:
Furthermore, we must not access mm_struct via task->mm, but obtain it via
access_mm() once (in the following patch) and only use that pointer [1], so pass
it to do_madvise() as well. Note the vma->vm_mm pointers are safe, so we can use
them further down the call stack.
quoted
And let's pass *current* and current->mm as arguments of
do_madvise so it shouldn't change existing behavior but prepare
next patch to make review easy.
Note: io_madvise pass NULL as target_task argument of do_madvise
because it couldn't know who is target.
can't
Andrew already picked up your suggestion except "can't" part. I don't
think it's enough to resend fix it so I will leave it as-is.
From: Minchan Kim <minchan@kernel.org> Date: 2020-05-08 18:33:30
On Thu, Mar 12, 2020 at 01:23:39PM -0700, Minchan Kim wrote:
On Thu, Mar 12, 2020 at 01:40:26PM +0100, Vlastimil Babka wrote:
quoted
On 3/10/20 11:20 PM, Minchan Kim wrote:
quoted
On Thu, Mar 05, 2020 at 07:15:10PM +0100, Vlastimil Babka wrote:
quoted
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
There is usecase that System Management Software(SMS) want to give
a memory hint like MADV_[COLD|PAGEEOUT] to other processes and
in the case of Android, it is the ActivityManagerService.
It's similar in spirit to madvise(MADV_WONTNEED), but the information
You mean MADV_DONTNEED?
Mean to DONT_NEED's future version.
What's that exactly?
For zapping timing point of view, dontneed acts immediately so it's very
strong hint. However, MADV_COLD and MADV_PAGEOUT does lazily depending
on the future. For example, the page never discarded if it's touched
before the tail of LRU. If other process which shared the page has
touched the page, never paging out.
quoted
quoted
quoted
quoted
required to make the reclaim decision is not known to the app.
This seems to be mixing up the differences between MADV_DONTNEED and
COLD/PAGEOUT and self-imposed vs external memory hints?
Sorry, I don't understand what you want here.
You say that process_madvise(MADV_[COLD|PAGEEOUT]) is similar to
madvise(MADV_WONTNEED) but the difference is that the information
required to make the reclaim decision is not known to the app.
I see two differences. One is madvise vs process_madvise, which is explained by
"reclaim decision is not known to the app."
The other is MADV_WONTNEED vs MADV_[COLD|PAGEEOUT], which is... I'm not sure
until you say what's "DONT_NEED's future version" :D
Anyway I assume this part is from the versions where the new COLD and PAGEOUT
flags were introduced together with external memory hinting API?
Exactly. Maybe it would be better to remove the part once we merged the
COLD and PAGEOUT now.
Thanks for the review, Vlastimil!
Hi Andrew,
Per Vlastimil's review, I removed unnecessary part and changed syscall
argument name "advise and flag" to "advice and flags" in description.
Could you replace the description with this one? Code part is same so
no need to be changed.
Thanks.
From fdb29014c84aebcca4737de735993e87d43ebbbf Mon Sep 17 00:00:00 2001
From: Minchan Kim <minchan@kernel.org>
Date: Wed, 6 May 2020 13:54:39 +0000
Subject: [PATCH] mm/madvise: introduce process_madvise() syscall: an external
memory hinting API
There is usecase that System Management Software(SMS) want to give a
memory hint like MADV_[COLD|PAGEEOUT] to other processes and in the case
of Android, it is the ActivityManagerService.
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 a new syscall process_madvise(2).
It uses pidfd of an external process to give the hint.
int process_madvise(int pidfd, void *addr, size_t length, int advice,
unsigned long flags);
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 ptrace the process could use it successfully. The flag
argument is reserved for future use if we need to extend the API.
I think supporting all hints madvise has/will supported/support to
process_madvise is rather risky. Because we are not sure all hints make
sense from external process and implementation for the hint may rely on
the caller being in the current context so it could be error-prone. Thus,
I just limited hints as MADV_[COLD|PAGEOUT] in this patch.
If someone want to add other hints, we could hear hear the usecase and
review it for each hint. It's safer for maintenance rather than
introducing a buggy syscall but hard to fix it later.
Q.1 - Why does any external entity have better knowledge?
Quote from Sandeep
"For Android, every application (including the special SystemServer) are
forked from Zygote. The reason of course is to share as many libraries
and classes between the two as possible to benefit from the preloading
during boot.
After applications start, (almost) all of the APIs end up calling into
this SystemServer process over IPC (binder) and back to the application.
In a fully running system, the SystemServer monitors every single process
periodically to calculate their PSS / RSS and also decides which process
is "important" to the user for interactivity.
So, because of how these processes start _and_ the fact that the
SystemServer is looping to monitor each process, it does tend to *know*
which address range of the application is not used / useful.
Besides, we can never rely on applications to clean things up themselves.
We've had the "hey app1, the system is low on memory, please trim your
memory usage down" notifications for a long time[1]. They rely on
applications honoring the broadcasts and very few do.
So, if we want to avoid the inevitable killing of the application and
restarting it, some way to be able to tell the OS about unimportant memory
in these applications will be useful.
- ssp
Q.2 - How to guarantee the race(i.e., object validation) between when
giving a hint from an external process and get the hint from the target
process?
process_madvise operates on the target process's address space as it
exists at the instant that process_madvise is called. If the space target
process can run between the time the process_madvise process inspects the
target process address space and the time that process_madvise is actually
called, process_madvise may operate on memory regions that the calling
process does not expect. It's the responsibility of the process calling
process_madvise to close this race condition. For example, the calling
process can suspend the target process with ptrace, SIGSTOP, or the
freezer cgroup so that it doesn't have an opportunity to change its own
address space before process_madvise is called. Another option is to
operate on memory regions that the caller knows a priori will be unchanged
in the target process. Yet another option is to accept the race for
certain process_madvise calls after reasoning that mistargeting will do no
harm. The suggested API itself does not provide synchronization. It also
apply other APIs like move_pages, process_vm_write.
The race isn't really a problem though. Why is it so wrong to require
that callers do their own synchronization in some manner? Nobody objects
to write(2) merely because it's possible for two processes to open the
same file and clobber each other's writes --- instead, we tell people to
use flock or something. Think about mmap. It never guarantees newly
allocated address space is still valid when the user tries to access it
because other threads could unmap the memory right before. That's where
we need synchronization by using other API or design from userside. It
shouldn't be part of API itself. If someone needs more fine-grained
synchronization rather than process level, there were two ideas suggested
- cookie[2] and anon-fd[3]. Both are applicable via using last reserved
argument of the API but I don't think it's necessary right now since we
have already ways to prevent the race so don't want to add additional
complexity with more fine-grained optimization model.
To make the API extend, it reserved an unsigned long as last argument so
we could support it in future if someone really needs it.
Q.3 - Why doesn't ptrace work?
Injecting an madvise in the target process using ptrace would not work for
us because such injected madvise would have to be executed by the target
process, which means that process would have to be runnable and that
creates the risk of the abovementioned race and hinting a wrong VMA.
Furthermore, we want to act the hint in caller's context, not the
callee's, because the callee is usually limited in cpuset/cgroups or even
freezed state so they can't act by themselves quick enough, which causes
more thrashing/kill. It doesn't work if the target process are
ptraced(e.g., strace, debugger, minidump) because a process can have at
most one ptracer.
[1] https://developer.android.com/topic/performance/memory"
[2] process_getinfo for getting the cookie which is updated whenever
vma of process address layout are changed - Daniel Colascione -
https://lore.kernel.org/lkml/20190520035254.57579-1-minchan@kernel.org/T/#m7694416fd179b2066a2c62b5b139b14e3894e224
[3] anonymous fd which is used for the object(i.e., address range)
validation - Michal Hocko -
https://lore.kernel.org/lkml/20200120112722.GY18451@dhcp22.suse.cz/
Link: http://lkml.kernel.org/r/20200302193630.68771-3-minchan@kernel.org
Signed-off-by: Minchan Kim <minchan@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Vlastimil Babka <redacted>
Cc: Alexander Duyck <redacted>
Cc: Brian Geffon <redacted>
Cc: Christian Brauner <christian@brauner.io>
Cc: Daniel Colascione <redacted>
Cc: Jann Horn <jannh@google.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Joel Fernandes <redacted>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Dias <redacted>
Cc: Kirill Tkhai <redacted>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Oleksandr Natalenko <redacted>
Cc: Sandeep Patil <redacted>
Cc: SeongJae Park <redacted>
Cc: SeongJae Park <redacted>
Cc: Shakeel Butt <redacted>
Cc: Sonny Rao <redacted>
Cc: Tim Murray <redacted>
Cc: <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
From: Minchan Kim <minchan@kernel.org> Date: 2020-05-08 18:36:58
On Tue, Mar 10, 2020 at 05:42:51PM -0700, Minchan Kim wrote:
On Fri, Mar 06, 2020 at 12:14:19PM +0100, Vlastimil Babka wrote:
quoted
On 3/2/20 8:36 PM, Minchan Kim wrote:
quoted
There is a demand[1] to support pid as well pidfd for process_madvise
to reduce unnecessary syscall to get pidfd if the user has control of
the target process(ie, they could guarantee the process is not gone
or pid is not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(int which, pid_t pid, void *addr,
size_t length, int advise, unsigned long flag);
This is again halfway between kernel and userspace description, so if we stick
to userspace then it's:
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
Yub.
Hi Andrew,
Per Vlastimil's request, I changed "which and advise" with "idtype and
advice" in function prototype of description.
Could you replace the part in the description? Code is never changed.
Thanks.
From f11cfd023746ae67b89f2d84d960706ba6c5c911 Mon Sep 17 00:00:00 2001
From: Minchan Kim <minchan@kernel.org>
Date: Wed, 6 May 2020 13:54:40 +0000
Subject: [PATCH] mm/madvise: support both pid and pidfd for process_madvise
There is a demand[1] to support pid as well pidfd for process_madvise to
reduce unnecessary syscall to get pidfd if the user has control of the
target process(ie, they could guarantee the process is not gone or pid is
not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
@which is actually idtype_t for userspace libray and currently, it
supports P_PID and P_PIDFD.
[1] https://lore.kernel.org/linux-mm/9d849087-3359-c4ab-fbec-859e8186c509@virtuozzo.com/
Link: http://lkml.kernel.org/r/20200302193630.68771-6-minchan@kernel.org
Signed-off-by: Minchan Kim <minchan@kernel.org>
Suggested-by: Kirill Tkhai <redacted>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Vlastimil Babka <redacted>
Cc: Christian Brauner <christian@brauner.io>
Cc: Alexander Duyck <redacted>
Cc: Brian Geffon <redacted>
Cc: Daniel Colascione <redacted>
Cc: Jann Horn <jannh@google.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Joel Fernandes <redacted>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Dias <redacted>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Oleksandr Natalenko <redacted>
Cc: Sandeep Patil <redacted>
Cc: SeongJae Park <redacted>
Cc: SeongJae Park <redacted>
Cc: Shakeel Butt <redacted>
Cc: Sonny Rao <redacted>
Cc: Tim Murray <redacted>
Cc: <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
From: Andrew Morton <akpm@linux-foundation.org> Date: 2020-05-08 23:04:18
On Fri, 8 May 2020 11:36:53 -0700 Minchan Kim [off-list ref] wrote:
...
Per Vlastimil's request, I changed "which and advise" with "idtype and
advice" in function prototype of description.
Could you replace the part in the description? Code is never changed.
Done, but...
...
There is a demand[1] to support pid as well pidfd for process_madvise to
reduce unnecessary syscall to get pidfd if the user has control of the
target process(ie, they could guarantee the process is not gone or pid is
not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
@which is actually idtype_t for userspace libray and currently, it
supports P_PID and P_PIDFD.
What does "@which is actually idtype_t for userspace libray" mean? Can
you clarify and expand?
Also, does this userspace library exist? If so, where is it?
From: Christian Brauner <hidden> Date: 2020-05-09 12:48:27
On Fri, May 08, 2020 at 04:04:15PM -0700, Andrew Morton wrote:
On Fri, 8 May 2020 11:36:53 -0700 Minchan Kim [off-list ref] wrote:
quoted
...
Per Vlastimil's request, I changed "which and advise" with "idtype and
advice" in function prototype of description.
Could you replace the part in the description? Code is never changed.
Done, but...
quoted
...
There is a demand[1] to support pid as well pidfd for process_madvise to
reduce unnecessary syscall to get pidfd if the user has control of the
target process(ie, they could guarantee the process is not gone or pid is
not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
@which is actually idtype_t for userspace libray and currently, it
supports P_PID and P_PIDFD.
What does "@which is actually idtype_t for userspace libray" mean? Can
you clarify and expand?
If I may clarify, the only case where we've supported both pidfd and pid
in the same system call is waitid() to avoid adding a dedicated system
call for waiting and because waitid() already had this (imho insane)
argument type switching. The idtype_t thing comes from waitid() and is
located int sys/wait.h and is defined as
"The type idtype_t is defined as an enumeration type whose possible
values include at least the following:
P_ALL
P_PID
P_PGID
"
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
If idtype is P_PID, waitid() shall wait for the child with a process ID equal to (pid_t)id.
If idtype is P_PGID, waitid() shall wait for any child with a process group ID equal to (pid_t)id.
If idtype is P_ALL, waitid() shall wait for any children and id is ignored.
I'm personally not a fan of this idtype_t thing and think this should
just have been
quoted
int pidfd_madvise(int pidfd, void *addr,
size_t length, int advice, unsigned long flags);
and call it a day.
Also, if I may ask, why is the flag argument "unsigned long"?
That's pretty unorthodox. The expectation is that flag arguments are
not word-size dependent and should usually use "unsigned int". All new
system calls follow this pattern too.
The current syscall layout will mean that on 64 bit systems you have 64
flag bits and on 32 bit you have 32 flag bits, I think. That has just
recently led to some problems with the clone() syscall (fixed in [1]
which I'm sending Monday) which has the same weird word-size-dependent
flag argument layout. If a system does sign-extension and a userspace
api or glibc uses e.g. an int for the flag argument in the system call
wrapper - which is fairly common - you can get sign extended and then
you end up with garbage in the upper 32 bits of your system call.
Also, does this userspace library exist? If so, where is it?
From: Minchan Kim <minchan@kernel.org> Date: 2020-05-09 23:14:47
Hi Christian,
On Sat, May 09, 2020 at 02:48:17PM +0200, Christian Brauner wrote:
On Fri, May 08, 2020 at 04:04:15PM -0700, Andrew Morton wrote:
quoted
On Fri, 8 May 2020 11:36:53 -0700 Minchan Kim [off-list ref] wrote:
quoted
...
Per Vlastimil's request, I changed "which and advise" with "idtype and
advice" in function prototype of description.
Could you replace the part in the description? Code is never changed.
Done, but...
quoted
...
There is a demand[1] to support pid as well pidfd for process_madvise to
reduce unnecessary syscall to get pidfd if the user has control of the
target process(ie, they could guarantee the process is not gone or pid is
not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
@which is actually idtype_t for userspace libray and currently, it
supports P_PID and P_PIDFD.
What does "@which is actually idtype_t for userspace libray" mean? Can
you clarify and expand?
If I may clarify, the only case where we've supported both pidfd and pid
in the same system call is waitid() to avoid adding a dedicated system
call for waiting and because waitid() already had this (imho insane)
argument type switching. The idtype_t thing comes from waitid() and is
located int sys/wait.h and is defined as
"The type idtype_t is defined as an enumeration type whose possible
values include at least the following:
P_ALL
P_PID
P_PGID
"
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
If idtype is P_PID, waitid() shall wait for the child with a process ID equal to (pid_t)id.
If idtype is P_PGID, waitid() shall wait for any child with a process group ID equal to (pid_t)id.
If idtype is P_ALL, waitid() shall wait for any children and id is ignored.
I'm personally not a fan of this idtype_t thing and think this should
just have been
quoted
quoted
int pidfd_madvise(int pidfd, void *addr,
size_t length, int advice, unsigned long flags);
and call it a day.
That was the argument at that time, Daniel and I didn't want to have
pid along with pidfd even though Kirill strongly wanted to have it.
However you said " Overall, I don't particularly care how or if you
integrate pidfd here." at that time.
https://lore.kernel.org/linux-mm/20200113104256.5ujbplyec2sk4onn@wittgenstein/
I asked a question to Kirll at that time.
"
Sounds like that you want to support both options for every upcoming API
which deals with pid. I'm not sure how it's critical for process_madvise
API this case. In general, we sacrifice some performance for the nicer one
and later, once it's reported as hurdle for some workload, we could fix it
via introducing new flag. What I don't like at this moment is to make
syscall complicated with potential scenarios without real workload.
Yes, I suggest allowing both options for every new process api
"
https://lore.kernel.org/linux-mm/9d849087-3359-c4ab-fbec-859e8186c509@virtuozzo.com/
You didn't give the opinion at that time, either(I expected you will
make some voice then). What I could do to proceed work was separate it
as different patch like this one to get more attention in future.
And now it works.
Let me clarify my side: I still don't like to introduce pid for new API
since we have pidfd. Since you just brought this issue again, I want to
hear *opinions* from others, again.
Also, if I may ask, why is the flag argument "unsigned long"?
That's pretty unorthodox. The expectation is that flag arguments are
not word-size dependent and should usually use "unsigned int". All new
system calls follow this pattern too.
Nothing special in this flag: Let me change it as "unsigned int".
I will send the change once we have an agreement on "pidfd" argument.
Thanks for the review, Christian!
On Sat, May 9, 2020 at 4:14 PM Minchan Kim [off-list ref] wrote:
Hi Christian,
On Sat, May 09, 2020 at 02:48:17PM +0200, Christian Brauner wrote:
quoted
On Fri, May 08, 2020 at 04:04:15PM -0700, Andrew Morton wrote:
quoted
On Fri, 8 May 2020 11:36:53 -0700 Minchan Kim [off-list ref] wrote:
quoted
...
Per Vlastimil's request, I changed "which and advise" with "idtype and
advice" in function prototype of description.
Could you replace the part in the description? Code is never changed.
Done, but...
quoted
...
There is a demand[1] to support pid as well pidfd for process_madvise to
reduce unnecessary syscall to get pidfd if the user has control of the
target process(ie, they could guarantee the process is not gone or pid is
not reused).
This patch aims for supporting both options like waitid(2). So, the
syscall is currently,
int process_madvise(idtype_t idtype, id_t id, void *addr,
size_t length, int advice, unsigned long flags);
@which is actually idtype_t for userspace libray and currently, it
supports P_PID and P_PIDFD.
What does "@which is actually idtype_t for userspace libray" mean? Can
you clarify and expand?
If I may clarify, the only case where we've supported both pidfd and pid
in the same system call is waitid() to avoid adding a dedicated system
call for waiting and because waitid() already had this (imho insane)
argument type switching. The idtype_t thing comes from waitid() and is
located int sys/wait.h and is defined as
"The type idtype_t is defined as an enumeration type whose possible
values include at least the following:
P_ALL
P_PID
P_PGID
"
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
If idtype is P_PID, waitid() shall wait for the child with a process ID equal to (pid_t)id.
If idtype is P_PGID, waitid() shall wait for any child with a process group ID equal to (pid_t)id.
If idtype is P_ALL, waitid() shall wait for any children and id is ignored.
I'm personally not a fan of this idtype_t thing and think this should
just have been
quoted
quoted
int pidfd_madvise(int pidfd, void *addr,
size_t length, int advice, unsigned long flags);
and call it a day.
That was the argument at that time, Daniel and I didn't want to have
pid along with pidfd even though Kirill strongly wanted to have it.
However you said " Overall, I don't particularly care how or if you
integrate pidfd here." at that time.
https://lore.kernel.org/linux-mm/20200113104256.5ujbplyec2sk4onn@wittgenstein/
I asked a question to Kirll at that time.
"
quoted
Sounds like that you want to support both options for every upcoming API
which deals with pid. I'm not sure how it's critical for process_madvise
API this case. In general, we sacrifice some performance for the nicer one
and later, once it's reported as hurdle for some workload, we could fix it
via introducing new flag. What I don't like at this moment is to make
syscall complicated with potential scenarios without real workload.
Yes, I suggest allowing both options for every new process api
"
https://lore.kernel.org/linux-mm/9d849087-3359-c4ab-fbec-859e8186c509@virtuozzo.com/
You didn't give the opinion at that time, either(I expected you will
make some voice then). What I could do to proceed work was separate it
as different patch like this one to get more attention in future.
And now it works.
Let me clarify my side: I still don't like to introduce pid for new API
since we have pidfd. Since you just brought this issue again, I want to
hear *opinions* from others, again.
IIRC Kirill's main complaint was that if we support only pidfds and
userspace has a pid of the process then it would have to convert that
pid into pidfd before calling process_madvise, which involves
additional syscall(s). The overhead would be more tangible if there
are multiple processes needing to be madvised.
I'm not sure how often such a need arises to madvise multiple
processes in a bulk like that and how critical is the overhead of
obtaining pidfd. With pid reuse possibility pid-based API will still
have the issue of possibly sending the request to a wrong process, so
this pidfd obtaining overhead arguably makes the usage more robust and
therefore is not a pure loss.
I don't have a real strong opinion against supporting pid in this
syscall but I think API maintainers should decide going forward
whether new APIs should support pid along with pidfd or switch to
pidfd only.
Thanks!
quoted
Also, if I may ask, why is the flag argument "unsigned long"?
That's pretty unorthodox. The expectation is that flag arguments are
not word-size dependent and should usually use "unsigned int". All new
system calls follow this pattern too.
Nothing special in this flag: Let me change it as "unsigned int".
I will send the change once we have an agreement on "pidfd" argument.
Thanks for the review, Christian!
On Mon, Mar 2, 2020 at 8:36 PM Minchan Kim [off-list ref] wrote:
From: Oleksandr Natalenko <redacted>
It all began with the fact that KSM works only on memory that is marked
by madvise(). And the only way to get around that is to either:
[...]
To overcome this restriction, lets employ a new remote madvise API. This
can be used by some small userspace helper daemon that will do auto-KSM
job for us.
I think of two major consumers of remote KSM hints:
[...]
* heavy applications, that can be run in multiple instances, not
limited to opensource ones like Firefox, but also those that cannot be
modified since they are binary-only and, maybe, statically linked.
Just as a note, since you're mentioning Firefox as a usecase: Memory
deduplication between browser renderers creates new side channels and
is a questionable idea from a security standpoint. Memory
deduplication is (mostly) fine if either all involved processes are
trusted or no involved processes contain secrets, but browsers usually
run tons of untrusted code while at the same time containing lots of
valuable secrets.