(vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)))
return -EINVAL;
+ /*
+ * We permit crossing of boundaries for the range being unmapped due to
+ * a shrink.
+ */
+ if (vrm->remap_type == MREMAP_SHRINK)
+ old_len = new_len;
+
/* We can't remap across vm area boundaries */
if (old_len > vma->vm_end - addr)
return -EFAULT;
vrm->old_len = vrm->new_len;
}
- err = remap_is_valid(vrm);
- if (err)
- return err;
-
/* MREMAP_DONTUNMAP expands by old_len since old_len == new_len */
if (vrm->flags & MREMAP_DONTUNMAP) {
vm_flags_t vm_flags = vrm->vma->vm_flags;
{
unsigned long err;
- err = remap_is_valid(vrm);
- if (err)
- return err;
-
/*
* [addr, old_len) spans precisely to the end of the VMA, so try to
* expand it in-place.
return -EINVAL;
}
+/*
+ * Will this operation result in the VMA being expanded or moved and thus need
+ * to map a new portion of virtual address space?
+ */
+static bool vrm_will_map_new(struct vma_remap_struct *vrm)
+{
+ if (vrm->remap_type == MREMAP_EXPAND)
+ return true;
+
+ if (vrm_implies_new_addr(vrm))
+ return true;
+
+ return false;
+}
+
static int check_prep_vma(struct vma_remap_struct *vrm)
{
struct vm_area_struct *vma = vrm->vma;
if (!vrm_implies_new_addr(vrm))
vrm->new_addr = vrm->addr;
+ if (vrm_will_map_new(vrm))
+ return remap_is_valid(vrm);
+
return 0;
}