mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
userfaultfd: non-cooperative: add event for memory unmaps
When a non-cooperative userfaultfd monitor copies pages in the background, it may encounter regions that were already unmapped. Addition of UFFD_EVENT_UNMAP allows the uffd monitor to track precisely changes in the virtual memory layout. Since there might be different uffd contexts for the affected VMAs, we first should create a temporary representation for the unmap event for each uffd context and then notify them one by one to the appropriate userfault file descriptors. The event notification occurs after the mmap_sem has been released. [[email protected]: fix nommu build] Link: http://lkml.kernel.org/r/[email protected] [[email protected]: fix nommu build] Link: http://lkml.kernel.org/r/[email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Mike Rapoport <[email protected]> Signed-off-by: Michal Hocko <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]> Acked-by: Hillf Danton <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: "Dr. David Alan Gilbert" <[email protected]> Cc: Mike Kravetz <[email protected]> Cc: Pavel Emelyanov <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
846b1a0f1d
commit
897ab3e0c4
15 changed files with 160 additions and 45 deletions
23
mm/mremap.c
23
mm/mremap.c
|
|
@ -252,7 +252,8 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
|
|||
static unsigned long move_vma(struct vm_area_struct *vma,
|
||||
unsigned long old_addr, unsigned long old_len,
|
||||
unsigned long new_len, unsigned long new_addr,
|
||||
bool *locked, struct vm_userfaultfd_ctx *uf)
|
||||
bool *locked, struct vm_userfaultfd_ctx *uf,
|
||||
struct list_head *uf_unmap)
|
||||
{
|
||||
struct mm_struct *mm = vma->vm_mm;
|
||||
struct vm_area_struct *new_vma;
|
||||
|
|
@ -341,7 +342,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
|
|||
if (unlikely(vma->vm_flags & VM_PFNMAP))
|
||||
untrack_pfn_moved(vma);
|
||||
|
||||
if (do_munmap(mm, old_addr, old_len) < 0) {
|
||||
if (do_munmap(mm, old_addr, old_len, uf_unmap) < 0) {
|
||||
/* OOM: unable to split vma, just get accounts right */
|
||||
vm_unacct_memory(excess >> PAGE_SHIFT);
|
||||
excess = 0;
|
||||
|
|
@ -417,7 +418,8 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,
|
|||
|
||||
static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
|
||||
unsigned long new_addr, unsigned long new_len, bool *locked,
|
||||
struct vm_userfaultfd_ctx *uf)
|
||||
struct vm_userfaultfd_ctx *uf,
|
||||
struct list_head *uf_unmap)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
|
|
@ -435,12 +437,12 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
|
|||
if (addr + old_len > new_addr && new_addr + new_len > addr)
|
||||
goto out;
|
||||
|
||||
ret = do_munmap(mm, new_addr, new_len);
|
||||
ret = do_munmap(mm, new_addr, new_len, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (old_len >= new_len) {
|
||||
ret = do_munmap(mm, addr+new_len, old_len - new_len);
|
||||
ret = do_munmap(mm, addr+new_len, old_len - new_len, uf_unmap);
|
||||
if (ret && old_len != new_len)
|
||||
goto out;
|
||||
old_len = new_len;
|
||||
|
|
@ -462,7 +464,8 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
|
|||
if (offset_in_page(ret))
|
||||
goto out1;
|
||||
|
||||
ret = move_vma(vma, addr, old_len, new_len, new_addr, locked, uf);
|
||||
ret = move_vma(vma, addr, old_len, new_len, new_addr, locked, uf,
|
||||
uf_unmap);
|
||||
if (!(offset_in_page(ret)))
|
||||
goto out;
|
||||
out1:
|
||||
|
|
@ -502,6 +505,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|||
unsigned long charged = 0;
|
||||
bool locked = false;
|
||||
struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX;
|
||||
LIST_HEAD(uf_unmap);
|
||||
|
||||
if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
|
||||
return ret;
|
||||
|
|
@ -528,7 +532,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|||
|
||||
if (flags & MREMAP_FIXED) {
|
||||
ret = mremap_to(addr, old_len, new_addr, new_len,
|
||||
&locked, &uf);
|
||||
&locked, &uf, &uf_unmap);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -538,7 +542,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|||
* do_munmap does all the needed commit accounting
|
||||
*/
|
||||
if (old_len >= new_len) {
|
||||
ret = do_munmap(mm, addr+new_len, old_len - new_len);
|
||||
ret = do_munmap(mm, addr+new_len, old_len - new_len, &uf_unmap);
|
||||
if (ret && old_len != new_len)
|
||||
goto out;
|
||||
ret = addr;
|
||||
|
|
@ -598,7 +602,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|||
}
|
||||
|
||||
ret = move_vma(vma, addr, old_len, new_len, new_addr,
|
||||
&locked, &uf);
|
||||
&locked, &uf, &uf_unmap);
|
||||
}
|
||||
out:
|
||||
if (offset_in_page(ret)) {
|
||||
|
|
@ -609,5 +613,6 @@ out:
|
|||
if (locked && new_len > old_len)
|
||||
mm_populate(new_addr + old_len, new_len - old_len);
|
||||
mremap_userfaultfd_complete(&uf, addr, new_addr, old_len);
|
||||
userfaultfd_unmap_complete(mm, &uf_unmap);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue