|
@@ -22,6 +22,7 @@
|
|
#include <linux/mmu_notifier.h>
|
|
#include <linux/mmu_notifier.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/mm-arch-hooks.h>
|
|
#include <linux/mm-arch-hooks.h>
|
|
|
|
+#include <linux/userfaultfd_k.h>
|
|
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/tlbflush.h>
|
|
@@ -250,7 +251,8 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
|
|
|
|
|
|
static unsigned long move_vma(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 old_addr, unsigned long old_len,
|
|
- unsigned long new_len, unsigned long new_addr, bool *locked)
|
|
|
|
|
|
+ unsigned long new_len, unsigned long new_addr,
|
|
|
|
+ bool *locked, struct vm_userfaultfd_ctx *uf)
|
|
{
|
|
{
|
|
struct mm_struct *mm = vma->vm_mm;
|
|
struct mm_struct *mm = vma->vm_mm;
|
|
struct vm_area_struct *new_vma;
|
|
struct vm_area_struct *new_vma;
|
|
@@ -309,6 +311,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
|
|
old_addr = new_addr;
|
|
old_addr = new_addr;
|
|
new_addr = err;
|
|
new_addr = err;
|
|
} else {
|
|
} else {
|
|
|
|
+ mremap_userfaultfd_prep(new_vma, uf);
|
|
arch_remap(mm, old_addr, old_addr + old_len,
|
|
arch_remap(mm, old_addr, old_addr + old_len,
|
|
new_addr, new_addr + new_len);
|
|
new_addr, new_addr + new_len);
|
|
}
|
|
}
|
|
@@ -413,7 +416,8 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,
|
|
}
|
|
}
|
|
|
|
|
|
static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
|
|
static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
|
|
- unsigned long new_addr, unsigned long new_len, bool *locked)
|
|
|
|
|
|
+ unsigned long new_addr, unsigned long new_len, bool *locked,
|
|
|
|
+ struct vm_userfaultfd_ctx *uf)
|
|
{
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
struct mm_struct *mm = current->mm;
|
|
struct vm_area_struct *vma;
|
|
struct vm_area_struct *vma;
|
|
@@ -458,7 +462,7 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
|
|
if (offset_in_page(ret))
|
|
if (offset_in_page(ret))
|
|
goto out1;
|
|
goto out1;
|
|
|
|
|
|
- ret = move_vma(vma, addr, old_len, new_len, new_addr, locked);
|
|
|
|
|
|
+ ret = move_vma(vma, addr, old_len, new_len, new_addr, locked, uf);
|
|
if (!(offset_in_page(ret)))
|
|
if (!(offset_in_page(ret)))
|
|
goto out;
|
|
goto out;
|
|
out1:
|
|
out1:
|
|
@@ -497,6 +501,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|
unsigned long ret = -EINVAL;
|
|
unsigned long ret = -EINVAL;
|
|
unsigned long charged = 0;
|
|
unsigned long charged = 0;
|
|
bool locked = false;
|
|
bool locked = false;
|
|
|
|
+ struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX;
|
|
|
|
|
|
if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
|
|
if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
|
|
return ret;
|
|
return ret;
|
|
@@ -523,7 +528,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|
|
|
|
|
if (flags & MREMAP_FIXED) {
|
|
if (flags & MREMAP_FIXED) {
|
|
ret = mremap_to(addr, old_len, new_addr, new_len,
|
|
ret = mremap_to(addr, old_len, new_addr, new_len,
|
|
- &locked);
|
|
|
|
|
|
+ &locked, &uf);
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -592,7 +597,8 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = move_vma(vma, addr, old_len, new_len, new_addr, &locked);
|
|
|
|
|
|
+ ret = move_vma(vma, addr, old_len, new_len, new_addr,
|
|
|
|
+ &locked, &uf);
|
|
}
|
|
}
|
|
out:
|
|
out:
|
|
if (offset_in_page(ret)) {
|
|
if (offset_in_page(ret)) {
|
|
@@ -602,5 +608,6 @@ out:
|
|
up_write(¤t->mm->mmap_sem);
|
|
up_write(¤t->mm->mmap_sem);
|
|
if (locked && new_len > old_len)
|
|
if (locked && new_len > old_len)
|
|
mm_populate(new_addr + old_len, new_len - old_len);
|
|
mm_populate(new_addr + old_len, new_len - old_len);
|
|
|
|
+ mremap_userfaultfd_complete(uf, addr, new_addr, old_len);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|