mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02: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. [arnd@arndb.de: fix nommu build] Link: http://lkml.kernel.org/r/20170203165141.3665284-1-arnd@arndb.de [mhocko@suse.com: fix nommu build] Link: http://lkml.kernel.org/r/20170202091503.GA22823@dhcp22.suse.cz Link: http://lkml.kernel.org/r/1485542673-24387-3-git-send-email-rppt@linux.vnet.ibm.com Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com> Signed-off-by: Michal Hocko <mhocko@suse.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com> Cc: Mike Kravetz <mike.kravetz@oracle.com> Cc: Pavel Emelyanov <xemul@virtuozzo.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
846b1a0f1d
commit
897ab3e0c4
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user