|
@@ -506,7 +506,8 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
|
|
|
|
|
|
if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) ||
|
|
|
is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm))
|
|
|
- goto out; /* don't set VM_LOCKED, don't count */
|
|
|
+ /* don't set VM_LOCKED or VM_LOCKONFAULT and don't count */
|
|
|
+ goto out;
|
|
|
|
|
|
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
|
|
|
*prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
|
|
@@ -577,7 +578,7 @@ static int apply_vma_lock_flags(unsigned long start, size_t len,
|
|
|
prev = vma;
|
|
|
|
|
|
for (nstart = start ; ; ) {
|
|
|
- vm_flags_t newflags = vma->vm_flags & ~VM_LOCKED;
|
|
|
+ vm_flags_t newflags = vma->vm_flags & VM_LOCKED_CLEAR_MASK;
|
|
|
|
|
|
newflags |= flags;
|
|
|
|
|
@@ -646,10 +647,15 @@ SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len)
|
|
|
|
|
|
SYSCALL_DEFINE3(mlock2, unsigned long, start, size_t, len, int, flags)
|
|
|
{
|
|
|
- if (flags)
|
|
|
+ vm_flags_t vm_flags = VM_LOCKED;
|
|
|
+
|
|
|
+ if (flags & ~MLOCK_ONFAULT)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return do_mlock(start, len, VM_LOCKED);
|
|
|
+ if (flags & MLOCK_ONFAULT)
|
|
|
+ vm_flags |= VM_LOCKONFAULT;
|
|
|
+
|
|
|
+ return do_mlock(start, len, vm_flags);
|
|
|
}
|
|
|
|
|
|
SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len)
|
|
@@ -666,24 +672,43 @@ SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Take the MCL_* flags passed into mlockall (or 0 if called from munlockall)
|
|
|
+ * and translate into the appropriate modifications to mm->def_flags and/or the
|
|
|
+ * flags for all current VMAs.
|
|
|
+ *
|
|
|
+ * There are a couple of subtleties with this. If mlockall() is called multiple
|
|
|
+ * times with different flags, the values do not necessarily stack. If mlockall
|
|
|
+ * is called once including the MCL_FUTURE flag and then a second time without
|
|
|
+ * it, VM_LOCKED and VM_LOCKONFAULT will be cleared from mm->def_flags.
|
|
|
+ */
|
|
|
static int apply_mlockall_flags(int flags)
|
|
|
{
|
|
|
struct vm_area_struct * vma, * prev = NULL;
|
|
|
+ vm_flags_t to_add = 0;
|
|
|
|
|
|
- if (flags & MCL_FUTURE)
|
|
|
+ current->mm->def_flags &= VM_LOCKED_CLEAR_MASK;
|
|
|
+ if (flags & MCL_FUTURE) {
|
|
|
current->mm->def_flags |= VM_LOCKED;
|
|
|
- else
|
|
|
- current->mm->def_flags &= ~VM_LOCKED;
|
|
|
|
|
|
- if (flags == MCL_FUTURE)
|
|
|
- goto out;
|
|
|
+ if (flags & MCL_ONFAULT)
|
|
|
+ current->mm->def_flags |= VM_LOCKONFAULT;
|
|
|
+
|
|
|
+ if (!(flags & MCL_CURRENT))
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (flags & MCL_CURRENT) {
|
|
|
+ to_add |= VM_LOCKED;
|
|
|
+ if (flags & MCL_ONFAULT)
|
|
|
+ to_add |= VM_LOCKONFAULT;
|
|
|
+ }
|
|
|
|
|
|
for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
|
|
|
vm_flags_t newflags;
|
|
|
|
|
|
- newflags = vma->vm_flags & ~VM_LOCKED;
|
|
|
- if (flags & MCL_CURRENT)
|
|
|
- newflags |= VM_LOCKED;
|
|
|
+ newflags = vma->vm_flags & VM_LOCKED_CLEAR_MASK;
|
|
|
+ newflags |= to_add;
|
|
|
|
|
|
/* Ignore errors */
|
|
|
mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
|
|
@@ -698,7 +723,7 @@ SYSCALL_DEFINE1(mlockall, int, flags)
|
|
|
unsigned long lock_limit;
|
|
|
int ret;
|
|
|
|
|
|
- if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
|
|
|
+ if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT)))
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (!can_do_mlock())
|