summaryrefslogtreecommitdiff
path: root/mm/vma.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/vma.c')
-rw-r--r--mm/vma.c289
1 files changed, 166 insertions, 123 deletions
diff --git a/mm/vma.c b/mm/vma.c
index c8df5f561ad7..377321b48734 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -38,13 +38,11 @@ struct mmap_state {
/* Determine if we can check KSM flags early in mmap() logic. */
bool check_ksm_early :1;
- /* If we map new, hold the file rmap lock on mapping. */
- bool hold_file_rmap_lock :1;
/* If .mmap_prepare changed the file, we don't need to pin. */
bool file_doesnt_need_get :1;
};
-#define MMAP_STATE(name, mm_, vmi_, addr_, len_, pgoff_, vm_flags_, file_) \
+#define MMAP_STATE(name, mm_, vmi_, addr_, len_, pgoff_, vma_flags_, file_) \
struct mmap_state name = { \
.mm = mm_, \
.vmi = vmi_, \
@@ -52,9 +50,9 @@ struct mmap_state {
.end = (addr_) + (len_), \
.pgoff = pgoff_, \
.pglen = PHYS_PFN(len_), \
- .vm_flags = vm_flags_, \
+ .vma_flags = vma_flags_, \
.file = file_, \
- .page_prot = vm_get_page_prot(vm_flags_), \
+ .page_prot = vma_get_page_prot(vma_flags_), \
}
#define VMG_MMAP_STATE(name, map_, vma_) \
@@ -63,7 +61,7 @@ struct mmap_state {
.vmi = (map_)->vmi, \
.start = (map_)->addr, \
.end = (map_)->end, \
- .vm_flags = (map_)->vm_flags, \
+ .vma_flags = (map_)->vma_flags, \
.pgoff = (map_)->pgoff, \
.file = (map_)->file, \
.prev = (map_)->prev, \
@@ -86,10 +84,15 @@ static bool vma_is_fork_child(struct vm_area_struct *vma)
static inline bool is_mergeable_vma(struct vma_merge_struct *vmg, bool merge_next)
{
struct vm_area_struct *vma = merge_next ? vmg->next : vmg->prev;
+ vma_flags_t diff;
if (!mpol_equal(vmg->policy, vma_policy(vma)))
return false;
- if ((vma->vm_flags ^ vmg->vm_flags) & ~VM_IGNORE_MERGE)
+
+ diff = vma_flags_diff_pair(&vma->flags, &vmg->vma_flags);
+ vma_flags_clear_mask(&diff, VMA_IGNORE_MERGE_FLAGS);
+
+ if (!vma_flags_empty(&diff))
return false;
if (vma->vm_file != vmg->file)
return false;
@@ -180,7 +183,7 @@ static void init_multi_vma_prep(struct vma_prepare *vp,
}
/*
- * Return true if we can merge this (vm_flags,anon_vma,file,vm_pgoff)
+ * Return true if we can merge this (vma_flags,anon_vma,file,vm_pgoff)
* in front of (at a lower virtual address and file offset than) the vma.
*
* We cannot merge two vmas if they have differently assigned (non-NULL)
@@ -206,7 +209,7 @@ static bool can_vma_merge_before(struct vma_merge_struct *vmg)
}
/*
- * Return true if we can merge this (vm_flags,anon_vma,file,vm_pgoff)
+ * Return true if we can merge this (vma_flags,anon_vma,file,vm_pgoff)
* beyond (at a higher virtual address and file offset than) the vma.
*
* We cannot merge two vmas if they have differently assigned (non-NULL)
@@ -590,7 +593,7 @@ out_free_vma:
static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
unsigned long addr, int new_below)
{
- if (vma->vm_mm->map_count >= sysctl_max_map_count)
+ if (vma->vm_mm->map_count >= get_sysctl_max_map_count())
return -ENOMEM;
return __split_vma(vmi, vma, addr, new_below);
@@ -805,7 +808,8 @@ static bool can_merge_remove_vma(struct vm_area_struct *vma)
static __must_check struct vm_area_struct *vma_merge_existing_range(
struct vma_merge_struct *vmg)
{
- vm_flags_t sticky_flags = vmg->vm_flags & VM_STICKY;
+ vma_flags_t sticky_flags = vma_flags_and_mask(&vmg->vma_flags,
+ VMA_STICKY_FLAGS);
struct vm_area_struct *middle = vmg->middle;
struct vm_area_struct *prev = vmg->prev;
struct vm_area_struct *next;
@@ -844,7 +848,8 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
* furthermost left or right side of the VMA, then we have no chance of
* merging and should abort.
*/
- if (vmg->vm_flags & VM_SPECIAL || (!left_side && !right_side))
+ if (vma_flags_test_any_mask(&vmg->vma_flags, VMA_SPECIAL_FLAGS) ||
+ (!left_side && !right_side))
return NULL;
if (left_side)
@@ -898,15 +903,22 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
vma_start_write(middle);
if (merge_right) {
+ vma_flags_t next_sticky;
+
vma_start_write(next);
vmg->target = next;
- sticky_flags |= (next->vm_flags & VM_STICKY);
+ next_sticky = vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS);
+ vma_flags_set_mask(&sticky_flags, next_sticky);
}
if (merge_left) {
+ vma_flags_t prev_sticky;
+
vma_start_write(prev);
vmg->target = prev;
- sticky_flags |= (prev->vm_flags & VM_STICKY);
+
+ prev_sticky = vma_flags_and_mask(&prev->flags, VMA_STICKY_FLAGS);
+ vma_flags_set_mask(&sticky_flags, prev_sticky);
}
if (merge_both) {
@@ -976,7 +988,7 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
if (err || commit_merge(vmg))
goto abort;
- vm_flags_set(vmg->target, sticky_flags);
+ vma_set_flags_mask(vmg->target, sticky_flags);
khugepaged_enter_vma(vmg->target, vmg->vm_flags);
vmg->state = VMA_MERGE_SUCCESS;
return vmg->target;
@@ -1059,7 +1071,8 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg)
vmg->state = VMA_MERGE_NOMERGE;
/* Special VMAs are unmergeable, also if no prev/next. */
- if ((vmg->vm_flags & VM_SPECIAL) || (!prev && !next))
+ if (vma_flags_test_any_mask(&vmg->vma_flags, VMA_SPECIAL_FLAGS) ||
+ (!prev && !next))
return NULL;
can_merge_left = can_vma_merge_left(vmg);
@@ -1154,12 +1167,16 @@ int vma_expand(struct vma_merge_struct *vmg)
struct vm_area_struct *target = vmg->target;
struct vm_area_struct *next = vmg->next;
bool remove_next = false;
- vm_flags_t sticky_flags;
+ vma_flags_t sticky_flags =
+ vma_flags_and_mask(&vmg->vma_flags, VMA_STICKY_FLAGS);
+ vma_flags_t target_sticky;
int ret = 0;
mmap_assert_write_locked(vmg->mm);
vma_start_write(target);
+ target_sticky = vma_flags_and_mask(&target->flags, VMA_STICKY_FLAGS);
+
if (next && target != next && vmg->end == next->vm_end)
remove_next = true;
@@ -1174,10 +1191,7 @@ int vma_expand(struct vma_merge_struct *vmg)
VM_WARN_ON_VMG(target->vm_start < vmg->start ||
target->vm_end > vmg->end, vmg);
- sticky_flags = vmg->vm_flags & VM_STICKY;
- sticky_flags |= target->vm_flags & VM_STICKY;
- if (remove_next)
- sticky_flags |= next->vm_flags & VM_STICKY;
+ vma_flags_set_mask(&sticky_flags, target_sticky);
/*
* If we are removing the next VMA or copying from a VMA
@@ -1194,13 +1208,18 @@ int vma_expand(struct vma_merge_struct *vmg)
return ret;
if (remove_next) {
+ vma_flags_t next_sticky;
+
vma_start_write(next);
vmg->__remove_next = true;
+
+ next_sticky = vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS);
+ vma_flags_set_mask(&sticky_flags, next_sticky);
}
if (commit_merge(vmg))
goto nomem;
- vm_flags_set(target, sticky_flags);
+ vma_set_flags_mask(target, sticky_flags);
return 0;
nomem:
@@ -1394,7 +1413,7 @@ static int vms_gather_munmap_vmas(struct vma_munmap_struct *vms,
* its limit temporarily, to help free resources as expected.
*/
if (vms->end < vms->vma->vm_end &&
- vms->vma->vm_mm->map_count >= sysctl_max_map_count) {
+ vms->vma->vm_mm->map_count >= get_sysctl_max_map_count()) {
error = -ENOMEM;
goto map_count_exceeded;
}
@@ -1440,17 +1459,17 @@ static int vms_gather_munmap_vmas(struct vma_munmap_struct *vms,
nrpages = vma_pages(next);
vms->nr_pages += nrpages;
- if (next->vm_flags & VM_LOCKED)
+ if (vma_test(next, VMA_LOCKED_BIT))
vms->locked_vm += nrpages;
- if (next->vm_flags & VM_ACCOUNT)
+ if (vma_test(next, VMA_ACCOUNT_BIT))
vms->nr_accounted += nrpages;
if (is_exec_mapping(next->vm_flags))
vms->exec_vm += nrpages;
else if (is_stack_mapping(next->vm_flags))
vms->stack_vm += nrpages;
- else if (is_data_mapping(next->vm_flags))
+ else if (is_data_mapping_vma_flags(&next->flags))
vms->data_vm += nrpages;
if (vms->uf) {
@@ -1689,13 +1708,13 @@ static struct vm_area_struct *vma_modify(struct vma_merge_struct *vmg)
struct vm_area_struct *vma_modify_flags(struct vma_iterator *vmi,
struct vm_area_struct *prev, struct vm_area_struct *vma,
unsigned long start, unsigned long end,
- vm_flags_t *vm_flags_ptr)
+ vma_flags_t *vma_flags_ptr)
{
VMG_VMA_STATE(vmg, vmi, prev, vma, start, end);
- const vm_flags_t vm_flags = *vm_flags_ptr;
+ const vma_flags_t vma_flags = *vma_flags_ptr;
struct vm_area_struct *ret;
- vmg.vm_flags = vm_flags;
+ vmg.vma_flags = vma_flags;
ret = vma_modify(&vmg);
if (IS_ERR(ret))
@@ -1707,7 +1726,7 @@ struct vm_area_struct *vma_modify_flags(struct vma_iterator *vmi,
* them to the caller.
*/
if (vmg.state == VMA_MERGE_SUCCESS)
- *vm_flags_ptr = ret->vm_flags;
+ *vma_flags_ptr = ret->flags;
return ret;
}
@@ -1737,12 +1756,13 @@ struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi,
struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi,
struct vm_area_struct *prev, struct vm_area_struct *vma,
- unsigned long start, unsigned long end, vm_flags_t vm_flags,
- struct vm_userfaultfd_ctx new_ctx, bool give_up_on_oom)
+ unsigned long start, unsigned long end,
+ const vma_flags_t *vma_flags, struct vm_userfaultfd_ctx new_ctx,
+ bool give_up_on_oom)
{
VMG_VMA_STATE(vmg, vmi, prev, vma, start, end);
- vmg.vm_flags = vm_flags;
+ vmg.vma_flags = *vma_flags;
vmg.uffd_ctx = new_ctx;
if (give_up_on_oom)
vmg.give_up_on_oom = true;
@@ -1950,10 +1970,15 @@ out:
*/
static int anon_vma_compatible(struct vm_area_struct *a, struct vm_area_struct *b)
{
+ vma_flags_t diff = vma_flags_diff_pair(&a->flags, &b->flags);
+
+ vma_flags_clear_mask(&diff, VMA_ACCESS_FLAGS);
+ vma_flags_clear_mask(&diff, VMA_IGNORE_MERGE_FLAGS);
+
return a->vm_end == b->vm_start &&
mpol_equal(vma_policy(a), vma_policy(b)) &&
a->vm_file == b->vm_file &&
- !((a->vm_flags ^ b->vm_flags) & ~(VM_ACCESS_FLAGS | VM_IGNORE_MERGE)) &&
+ vma_flags_empty(&diff) &&
b->vm_pgoff == a->vm_pgoff + ((b->vm_start - a->vm_start) >> PAGE_SHIFT);
}
@@ -2041,14 +2066,13 @@ static bool vm_ops_needs_writenotify(const struct vm_operations_struct *vm_ops)
static bool vma_is_shared_writable(struct vm_area_struct *vma)
{
- return (vma->vm_flags & (VM_WRITE | VM_SHARED)) ==
- (VM_WRITE | VM_SHARED);
+ return vma_test_all(vma, VMA_WRITE_BIT, VMA_SHARED_BIT);
}
static bool vma_fs_can_writeback(struct vm_area_struct *vma)
{
/* No managed pages to writeback. */
- if (vma->vm_flags & VM_PFNMAP)
+ if (vma_test(vma, VMA_PFNMAP_BIT))
return false;
return vma->vm_file && vma->vm_file->f_mapping &&
@@ -2314,8 +2338,10 @@ void mm_drop_all_locks(struct mm_struct *mm)
* We account for memory if it's a private writeable mapping,
* not hugepages and VM_NORESERVE wasn't set.
*/
-static bool accountable_mapping(struct file *file, vm_flags_t vm_flags)
+static bool accountable_mapping(struct mmap_state *map)
{
+ const struct file *file = map->file;
+
/*
* hugetlb has its own accounting separate from the core VM
* VM_HUGETLB may not be set yet so we cannot check for that flag.
@@ -2323,7 +2349,9 @@ static bool accountable_mapping(struct file *file, vm_flags_t vm_flags)
if (file && is_file_hugepages(file))
return false;
- return (vm_flags & (VM_NORESERVE | VM_SHARED | VM_WRITE)) == VM_WRITE;
+ return vma_flags_test(&map->vma_flags, VMA_WRITE_BIT) &&
+ !vma_flags_test_any(&map->vma_flags, VMA_NORESERVE_BIT,
+ VMA_SHARED_BIT);
}
/*
@@ -2361,7 +2389,7 @@ static void vms_abort_munmap_vmas(struct vma_munmap_struct *vms,
static void update_ksm_flags(struct mmap_state *map)
{
- map->vm_flags = ksm_vma_flags(map->mm, map->file, map->vm_flags);
+ map->vma_flags = ksm_vma_flags(map->mm, map->file, map->vma_flags);
}
static void set_desc_from_map(struct vm_area_desc *desc,
@@ -2422,11 +2450,11 @@ static int __mmap_setup(struct mmap_state *map, struct vm_area_desc *desc,
}
/* Check against address space limit. */
- if (!may_expand_vm(map->mm, map->vm_flags, map->pglen - vms->nr_pages))
+ if (!may_expand_vm(map->mm, &map->vma_flags, map->pglen - vms->nr_pages))
return -ENOMEM;
/* Private writable mapping: check memory availability. */
- if (accountable_mapping(map->file, map->vm_flags)) {
+ if (accountable_mapping(map)) {
map->charged = map->pglen;
map->charged -= vms->nr_accounted;
if (map->charged) {
@@ -2436,7 +2464,7 @@ static int __mmap_setup(struct mmap_state *map, struct vm_area_desc *desc,
}
vms->nr_accounted = 0;
- map->vm_flags |= VM_ACCOUNT;
+ vma_flags_set(&map->vma_flags, VMA_ACCOUNT_BIT);
}
/*
@@ -2484,12 +2512,12 @@ static int __mmap_new_file_vma(struct mmap_state *map,
* Drivers should not permit writability when previously it was
* disallowed.
*/
- VM_WARN_ON_ONCE(map->vm_flags != vma->vm_flags &&
- !(map->vm_flags & VM_MAYWRITE) &&
- (vma->vm_flags & VM_MAYWRITE));
+ VM_WARN_ON_ONCE(!vma_flags_same_pair(&map->vma_flags, &vma->flags) &&
+ !vma_flags_test(&map->vma_flags, VMA_MAYWRITE_BIT) &&
+ vma_test(vma, VMA_MAYWRITE_BIT));
map->file = vma->vm_file;
- map->vm_flags = vma->vm_flags;
+ map->vma_flags = vma->flags;
return 0;
}
@@ -2500,10 +2528,12 @@ static int __mmap_new_file_vma(struct mmap_state *map,
*
* @map: Mapping state.
* @vmap: Output pointer for the new VMA.
+ * @action: Any mmap_prepare action that is still to complete.
*
* Returns: Zero on success, or an error.
*/
-static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap)
+static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap,
+ struct mmap_action *action)
{
struct vma_iterator *vmi = map->vmi;
int error = 0;
@@ -2520,7 +2550,7 @@ static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap)
vma_iter_config(vmi, map->addr, map->end);
vma_set_range(vma, map->addr, map->end, map->pgoff);
- vm_flags_init(vma, map->vm_flags);
+ vma->flags = map->vma_flags;
vma->vm_page_prot = map->page_prot;
if (vma_iter_prealloc(vmi, vma)) {
@@ -2530,7 +2560,7 @@ static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap)
if (map->file)
error = __mmap_new_file_vma(map, vma);
- else if (map->vm_flags & VM_SHARED)
+ else if (vma_flags_test(&map->vma_flags, VMA_SHARED_BIT))
error = shmem_zero_setup(vma);
else
vma_set_anonymous(vma);
@@ -2540,7 +2570,7 @@ static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap)
if (!map->check_ksm_early) {
update_ksm_flags(map);
- vm_flags_init(vma, map->vm_flags);
+ vma->flags = map->vma_flags;
}
#ifdef CONFIG_SPARC64
@@ -2552,7 +2582,7 @@ static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap)
vma_start_write(vma);
vma_iter_store_new(vmi, vma);
map->mm->map_count++;
- vma_link_file(vma, map->hold_file_rmap_lock);
+ vma_link_file(vma, action->hide_from_rmap_until_complete);
/*
* vma_merge_new_range() calls khugepaged_enter_vma() too, the below
@@ -2580,7 +2610,6 @@ free_vma:
static void __mmap_complete(struct mmap_state *map, struct vm_area_struct *vma)
{
struct mm_struct *mm = map->mm;
- vm_flags_t vm_flags = vma->vm_flags;
perf_event_mmap(vma);
@@ -2588,11 +2617,9 @@ static void __mmap_complete(struct mmap_state *map, struct vm_area_struct *vma)
vms_complete_munmap_vmas(&map->vms, &map->mas_detach);
vm_stat_account(mm, vma->vm_flags, map->pglen);
- if (vm_flags & VM_LOCKED) {
- if ((vm_flags & VM_SPECIAL) || vma_is_dax(vma) ||
- is_vm_hugetlb_page(vma) ||
- vma == get_gate_vma(mm))
- vm_flags_clear(vma, VM_LOCKED_MASK);
+ if (vma_test(vma, VMA_LOCKED_BIT)) {
+ if (!vma_supports_mlock(vma))
+ vma_clear_flags_mask(vma, VMA_LOCKED_MASK);
else
mm->locked_vm += map->pglen;
}
@@ -2608,20 +2635,21 @@ static void __mmap_complete(struct mmap_state *map, struct vm_area_struct *vma)
* a completely new data area).
*/
if (pgtable_supports_soft_dirty())
- vm_flags_set(vma, VM_SOFTDIRTY);
+ vma_set_flags(vma, VMA_SOFTDIRTY_BIT);
vma_set_page_prot(vma);
}
-static void call_action_prepare(struct mmap_state *map,
- struct vm_area_desc *desc)
+static int call_action_prepare(struct mmap_state *map,
+ struct vm_area_desc *desc)
{
- struct mmap_action *action = &desc->action;
+ int err;
- mmap_action_prepare(action, desc);
+ err = mmap_action_prepare(desc);
+ if (err)
+ return err;
- if (action->hide_from_rmap_until_complete)
- map->hold_file_rmap_lock = true;
+ return 0;
}
/*
@@ -2645,7 +2673,9 @@ static int call_mmap_prepare(struct mmap_state *map,
if (err)
return err;
- call_action_prepare(map, desc);
+ err = call_action_prepare(map, desc);
+ if (err)
+ return err;
/* Update fields permitted to be changed. */
map->pgoff = desc->pgoff;
@@ -2699,33 +2729,15 @@ static bool can_set_ksm_flags_early(struct mmap_state *map)
return false;
}
-static int call_action_complete(struct mmap_state *map,
- struct vm_area_desc *desc,
- struct vm_area_struct *vma)
-{
- struct mmap_action *action = &desc->action;
- int ret;
-
- ret = mmap_action_complete(action, vma);
-
- /* If we held the file rmap we need to release it. */
- if (map->hold_file_rmap_lock) {
- struct file *file = vma->vm_file;
-
- i_mmap_unlock_write(file->f_mapping);
- }
- return ret;
-}
-
static unsigned long __mmap_region(struct file *file, unsigned long addr,
- unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
- struct list_head *uf)
+ unsigned long len, vma_flags_t vma_flags,
+ unsigned long pgoff, struct list_head *uf)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma = NULL;
bool have_mmap_prepare = file && file->f_op->mmap_prepare;
VMA_ITERATOR(vmi, mm, addr);
- MMAP_STATE(map, mm, &vmi, addr, len, pgoff, vm_flags, file);
+ MMAP_STATE(map, mm, &vmi, addr, len, pgoff, vma_flags, file);
struct vm_area_desc desc = {
.mm = mm,
.file = file,
@@ -2756,7 +2768,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,
/* ...but if we can't, allocate a new VMA. */
if (!vma) {
- error = __mmap_new_vma(&map, &vma);
+ error = __mmap_new_vma(&map, &vma, &desc.action);
if (error)
goto unacct_error;
allocated_new = true;
@@ -2768,8 +2780,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,
__mmap_complete(&map, vma);
if (have_mmap_prepare && allocated_new) {
- error = call_action_complete(&map, &desc, vma);
-
+ error = mmap_action_complete(vma, &desc.action);
if (error)
return error;
}
@@ -2816,16 +2827,17 @@ abort_munmap:
* been performed.
*/
unsigned long mmap_region(struct file *file, unsigned long addr,
- unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
- struct list_head *uf)
+ unsigned long len, vm_flags_t vm_flags,
+ unsigned long pgoff, struct list_head *uf)
{
unsigned long ret;
bool writable_file_mapping = false;
+ const vma_flags_t vma_flags = legacy_to_vma_flags(vm_flags);
mmap_assert_write_locked(current->mm);
/* Check to see if MDWE is applicable. */
- if (map_deny_write_exec(vm_flags, vm_flags))
+ if (map_deny_write_exec(&vma_flags, &vma_flags))
return -EACCES;
/* Allow architectures to sanity-check the vm_flags. */
@@ -2833,7 +2845,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
return -EINVAL;
/* Map writable and ensure this isn't a sealed memfd. */
- if (file && is_shared_maywrite_vm_flags(vm_flags)) {
+ if (file && is_shared_maywrite(&vma_flags)) {
int error = mapping_map_writable(file->f_mapping);
if (error)
@@ -2841,7 +2853,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
writable_file_mapping = true;
}
- ret = __mmap_region(file, addr, len, vm_flags, pgoff, uf);
+ ret = __mmap_region(file, addr, len, vma_flags, pgoff, uf);
/* Clear our write mapping regardless of error. */
if (writable_file_mapping)
@@ -2851,20 +2863,22 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
return ret;
}
-/*
+/**
* do_brk_flags() - Increase the brk vma if the flags match.
* @vmi: The vma iterator
* @addr: The start address
* @len: The length of the increase
* @vma: The vma,
- * @vm_flags: The VMA Flags
+ * @vma_flags: The VMA Flags
*
* Extend the brk VMA from addr to addr + len. If the VMA is NULL or the flags
* do not match then create a new anonymous VMA. Eventually we may be able to
* do some brk-specific accounting here.
+ *
+ * Returns: %0 on success, or otherwise an error.
*/
int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *vma,
- unsigned long addr, unsigned long len, vm_flags_t vm_flags)
+ unsigned long addr, unsigned long len, vma_flags_t vma_flags)
{
struct mm_struct *mm = current->mm;
@@ -2872,12 +2886,15 @@ int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *vma,
* Check against address space limits by the changed size
* Note: This happens *after* clearing old mappings in some code paths.
*/
- vm_flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
- vm_flags = ksm_vma_flags(mm, NULL, vm_flags);
- if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT))
+ vma_flags_set_mask(&vma_flags, VMA_DATA_DEFAULT_FLAGS);
+ vma_flags_set(&vma_flags, VMA_ACCOUNT_BIT);
+ vma_flags_set_mask(&vma_flags, mm->def_vma_flags);
+
+ vma_flags = ksm_vma_flags(mm, NULL, vma_flags);
+ if (!may_expand_vm(mm, &vma_flags, len >> PAGE_SHIFT))
return -ENOMEM;
- if (mm->map_count > sysctl_max_map_count)
+ if (mm->map_count > get_sysctl_max_map_count())
return -ENOMEM;
if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT))
@@ -2888,7 +2905,7 @@ int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *vma,
* occur after forking, so the expand will only happen on new VMAs.
*/
if (vma && vma->vm_end == addr) {
- VMG_STATE(vmg, mm, vmi, addr, addr + len, vm_flags, PHYS_PFN(addr));
+ VMG_STATE(vmg, mm, vmi, addr, addr + len, vma_flags, PHYS_PFN(addr));
vmg.prev = vma;
/* vmi is positioned at prev, which this mode expects. */
@@ -2909,8 +2926,8 @@ int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *vma,
vma_set_anonymous(vma);
vma_set_range(vma, addr, addr + len, addr >> PAGE_SHIFT);
- vm_flags_init(vma, vm_flags);
- vma->vm_page_prot = vm_get_page_prot(vm_flags);
+ vma->flags = vma_flags;
+ vma->vm_page_prot = vm_get_page_prot(vma_flags_to_legacy(vma_flags));
vma_start_write(vma);
if (vma_iter_store_gfp(vmi, vma, GFP_KERNEL))
goto mas_store_fail;
@@ -2921,10 +2938,10 @@ out:
perf_event_mmap(vma);
mm->total_vm += len >> PAGE_SHIFT;
mm->data_vm += len >> PAGE_SHIFT;
- if (vm_flags & VM_LOCKED)
+ if (vma_flags_test(&vma_flags, VMA_LOCKED_BIT))
mm->locked_vm += (len >> PAGE_SHIFT);
if (pgtable_supports_soft_dirty())
- vm_flags_set(vma, VM_SOFTDIRTY);
+ vma_set_flags(vma, VMA_SOFTDIRTY_BIT);
return 0;
mas_store_fail:
@@ -2973,7 +2990,8 @@ retry:
gap = vma_iter_addr(&vmi) + info->start_gap;
gap += (info->align_offset - gap) & info->align_mask;
tmp = vma_next(&vmi);
- if (tmp && (tmp->vm_flags & VM_STARTGAP_FLAGS)) { /* Avoid prev check if possible */
+ /* Avoid prev check if possible */
+ if (tmp && vma_test_any_mask(tmp, VMA_STARTGAP_FLAGS)) {
if (vm_start_gap(tmp) < gap + length - 1) {
low_limit = tmp->vm_end;
vma_iter_reset(&vmi);
@@ -3025,7 +3043,8 @@ retry:
gap -= (gap - info->align_offset) & info->align_mask;
gap_end = vma_iter_end(&vmi);
tmp = vma_next(&vmi);
- if (tmp && (tmp->vm_flags & VM_STARTGAP_FLAGS)) { /* Avoid prev check if possible */
+ /* Avoid prev check if possible */
+ if (tmp && vma_test_any_mask(tmp, VMA_STARTGAP_FLAGS)) {
if (vm_start_gap(tmp) < gap_end) {
high_limit = vm_start_gap(tmp);
vma_iter_reset(&vmi);
@@ -3055,7 +3074,7 @@ static int acct_stack_growth(struct vm_area_struct *vma,
unsigned long new_start;
/* address space limit tests */
- if (!may_expand_vm(mm, vma->vm_flags, grow))
+ if (!may_expand_vm(mm, &vma->flags, grow))
return -ENOMEM;
/* Stack limit test */
@@ -3063,12 +3082,16 @@ static int acct_stack_growth(struct vm_area_struct *vma,
return -ENOMEM;
/* mlock limit tests */
- if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, grow << PAGE_SHIFT))
+ if (!mlock_future_ok(mm, vma_test(vma, VMA_LOCKED_BIT),
+ grow << PAGE_SHIFT))
return -ENOMEM;
/* Check to ensure the stack will not grow into a hugetlb-only region */
- new_start = (vma->vm_flags & VM_GROWSUP) ? vma->vm_start :
- vma->vm_end - size;
+ new_start = vma->vm_end - size;
+#ifdef CONFIG_STACK_GROWSUP
+ if (vma_test(vma, VMA_GROWSUP_BIT))
+ new_start = vma->vm_start;
+#endif
if (is_hugepage_only_range(vma->vm_mm, new_start, size))
return -EFAULT;
@@ -3082,7 +3105,7 @@ static int acct_stack_growth(struct vm_area_struct *vma,
return 0;
}
-#if defined(CONFIG_STACK_GROWSUP)
+#ifdef CONFIG_STACK_GROWSUP
/*
* PA-RISC uses this for its stack.
* vma is the last one with address > vma->vm_end. Have to extend vma.
@@ -3095,7 +3118,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
int error = 0;
VMA_ITERATOR(vmi, mm, vma->vm_start);
- if (!(vma->vm_flags & VM_GROWSUP))
+ if (!vma_test(vma, VMA_GROWSUP_BIT))
return -EFAULT;
mmap_assert_write_locked(mm);
@@ -3115,7 +3138,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
next = find_vma_intersection(mm, vma->vm_end, gap_addr);
if (next && vma_is_accessible(next)) {
- if (!(next->vm_flags & VM_GROWSUP))
+ if (!vma_test(next, VMA_GROWSUP_BIT))
return -ENOMEM;
/* Check that both stack segments have the same anon_vma? */
}
@@ -3149,7 +3172,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) {
error = acct_stack_growth(vma, size, grow);
if (!error) {
- if (vma->vm_flags & VM_LOCKED)
+ if (vma_test(vma, VMA_LOCKED_BIT))
mm->locked_vm += grow;
vm_stat_account(mm, vma->vm_flags, grow);
anon_vma_interval_tree_pre_update_vma(vma);
@@ -3180,7 +3203,7 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
int error = 0;
VMA_ITERATOR(vmi, mm, vma->vm_start);
- if (!(vma->vm_flags & VM_GROWSDOWN))
+ if (!vma_test(vma, VMA_GROWSDOWN_BIT))
return -EFAULT;
mmap_assert_write_locked(mm);
@@ -3193,7 +3216,7 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
prev = vma_prev(&vmi);
/* Check that both stack segments have the same anon_vma? */
if (prev) {
- if (!(prev->vm_flags & VM_GROWSDOWN) &&
+ if (!vma_test(prev, VMA_GROWSDOWN_BIT) &&
vma_is_accessible(prev) &&
(address - prev->vm_end < stack_guard_gap))
return -ENOMEM;
@@ -3228,7 +3251,7 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
if (grow <= vma->vm_pgoff) {
error = acct_stack_growth(vma, size, grow);
if (!error) {
- if (vma->vm_flags & VM_LOCKED)
+ if (vma_test(vma, VMA_LOCKED_BIT))
mm->locked_vm += grow;
vm_stat_account(mm, vma->vm_flags, grow);
anon_vma_interval_tree_pre_update_vma(vma);
@@ -3274,11 +3297,10 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
{
unsigned long charged = vma_pages(vma);
-
if (find_vma_intersection(mm, vma->vm_start, vma->vm_end))
return -ENOMEM;
- if ((vma->vm_flags & VM_ACCOUNT) &&
+ if (vma_test(vma, VMA_ACCOUNT_BIT) &&
security_vm_enough_memory_mm(mm, charged))
return -ENOMEM;
@@ -3300,10 +3322,31 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
}
if (vma_link(mm, vma)) {
- if (vma->vm_flags & VM_ACCOUNT)
+ if (vma_test(vma, VMA_ACCOUNT_BIT))
vm_unacct_memory(charged);
return -ENOMEM;
}
return 0;
}
+
+/**
+ * vma_mmu_pagesize - Default MMU page size granularity for this VMA.
+ * @vma: The user mapping.
+ *
+ * In the common case, the default page size used by the MMU matches the
+ * default page size used by the kernel (see vma_kernel_pagesize()). On
+ * architectures where it differs, an architecture-specific 'strong' version
+ * of this symbol is required.
+ *
+ * The default MMU page size is not affected by Transparent Huge Pages
+ * being in effect, or any usage of larger MMU page sizes (either through
+ * architectural huge-page mappings or other explicit/implicit coalescing of
+ * virtual ranges performed by the MMU).
+ *
+ * Return: The default MMU page size granularity for this VMA.
+ */
+__weak unsigned long vma_mmu_pagesize(struct vm_area_struct *vma)
+{
+ return vma_kernel_pagesize(vma);
+}