/* * If, at any point, the VMA had unCoW'd mappings from parents, it will maintain * more than one anon_vma_chain connecting it to more than one anon_vma. A merge * would mean a wider range of folios sharing the root anon_vma lock, and thus * potential lock contention, we do not wish to encourage merging such that this * scales to a problem.
*/ staticbool vma_had_uncowed_parents(struct vm_area_struct *vma)
{ /* * The list_is_singular() test is to avoid merging VMA cloned from * parents. This can improve scalability caused by anon_vma lock.
*/ return vma && vma->anon_vma && !list_is_singular(&vma->anon_vma_chain);
}
if (!mpol_equal(vmg->policy, vma_policy(vma))) returnfalse; /* * VM_SOFTDIRTY should not prevent from VMA merging, if we * match the flags but dirty bit -- the caller should mark * merged VMA as dirty. If dirty bit won't be excluded from * comparison, we increase pressure on the memory system forcing * the kernel to generate new VMAs when old one could be * extended instead.
*/ if ((vma->vm_flags ^ vmg->vm_flags) & ~VM_SOFTDIRTY) returnfalse; if (vma->vm_file != vmg->file) returnfalse; if (!is_mergeable_vm_userfaultfd_ctx(vma, vmg->uffd_ctx)) returnfalse; if (!anon_vma_name_eq(anon_vma_name(vma), vmg->anon_name)) returnfalse; returntrue;
}
/* * We _can_ have !src, vmg->anon_vma via copy_vma(). In this instance we * will remove the existing VMA's anon_vma's so there's no scalability * concerns.
*/
VM_WARN_ON(src && src_anon != src->anon_vma);
/* Case 1 - we will dup_anon_vma() from src into tgt. */ if (!tgt_anon && src_anon) return !vma_had_uncowed_parents(src); /* Case 2 - we will simply use tgt's anon_vma. */ if (tgt_anon && !src_anon) return !vma_had_uncowed_parents(tgt); /* Case 3 - the anon_vma's are already shared. */ return src_anon == tgt_anon;
}
/* * init_multi_vma_prep() - Initializer for struct vma_prepare * @vp: The vma_prepare struct * @vma: The vma that will be altered once locked * @vmg: The merge state that will be used to determine adjustment and VMA * removal.
*/ staticvoid init_multi_vma_prep(struct vma_prepare *vp, struct vm_area_struct *vma, struct vma_merge_struct *vmg)
{ struct vm_area_struct *adjust; struct vm_area_struct **remove = &vp->remove;
vp->file = vma->vm_file; if (vp->file)
vp->mapping = vma->vm_file->f_mapping;
if (vmg && vmg->skip_vma_uprobe)
vp->skip_vma_uprobe = true;
}
/* * Return true if we can merge this (vm_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) * anon_vmas, nor if same anon_vma is assigned but offsets incompatible. * * We don't check here for the merged mmap wrapping around the end of pagecache * indices (16TB on ia32) because do_mmap() does not permit mmap's which * wrap, nor mmaps which cover the final page at index -1UL. * * We assume the vma may be removed as part of the merge.
*/ staticbool can_vma_merge_before(struct vma_merge_struct *vmg)
{
pgoff_t pglen = PHYS_PFN(vmg->end - vmg->start);
/* * Return true if we can merge this (vm_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) * anon_vmas, nor if same anon_vma is assigned but offsets incompatible. * * We assume that vma is not removed as part of the merge.
*/ staticbool can_vma_merge_after(struct vma_merge_struct *vmg)
{ if (is_mergeable_vma(vmg, /* merge_next = */ false) &&
is_mergeable_anon_vma(vmg, /* merge_next = */ false)) { if (vmg->prev->vm_pgoff + vma_pages(vmg->prev) == vmg->pgoff) returntrue;
} returnfalse;
}
/* * vma has some anon_vma assigned, and is already inserted on that * anon_vma's interval trees. * * Before updating the vma's vm_start / vm_end / vm_pgoff fields, the * vma must be removed from the anon_vma's interval trees using * anon_vma_interval_tree_pre_update_vma(). * * After the update, the vma will be reinserted using * anon_vma_interval_tree_post_update_vma(). * * The entire update must be protected by exclusive mmap_lock and by * the root anon_vma's mutex.
*/ staticvoid
anon_vma_interval_tree_pre_update_vma(struct vm_area_struct *vma)
{ struct anon_vma_chain *avc;
/* * vma_prepare() - Helper function for handling locking VMAs prior to altering * @vp: The initialized vma_prepare struct
*/ staticvoid vma_prepare(struct vma_prepare *vp)
{ if (vp->file) {
uprobe_munmap(vp->vma, vp->vma->vm_start, vp->vma->vm_end);
if (vp->adj_next)
uprobe_munmap(vp->adj_next, vp->adj_next->vm_start,
vp->adj_next->vm_end);
i_mmap_lock_write(vp->mapping); if (vp->insert && vp->insert->vm_file) { /* * Put into interval tree now, so instantiated pages * are visible to arm/parisc __flush_dcache_page * throughout; but we cannot insert into address * space until vma start or end is updated.
*/
__vma_link_file(vp->insert,
vp->insert->vm_file->f_mapping);
}
}
if (vp->anon_vma) {
anon_vma_lock_write(vp->anon_vma);
anon_vma_interval_tree_pre_update_vma(vp->vma); if (vp->adj_next)
anon_vma_interval_tree_pre_update_vma(vp->adj_next);
}
if (vp->file) {
flush_dcache_mmap_lock(vp->mapping);
vma_interval_tree_remove(vp->vma, &vp->mapping->i_mmap); if (vp->adj_next)
vma_interval_tree_remove(vp->adj_next,
&vp->mapping->i_mmap);
}
}
/* * vma_complete- Helper function for handling the unlocking after altering VMAs, * or for inserting a VMA. * * @vp: The vma_prepare struct * @vmi: The vma iterator * @mm: The mm_struct
*/ staticvoid vma_complete(struct vma_prepare *vp, struct vma_iterator *vmi, struct mm_struct *mm)
{ if (vp->file) { if (vp->adj_next)
vma_interval_tree_insert(vp->adj_next,
&vp->mapping->i_mmap);
vma_interval_tree_insert(vp->vma, &vp->mapping->i_mmap);
flush_dcache_mmap_unlock(vp->mapping);
}
if (vp->remove && vp->file) {
__remove_shared_vm_struct(vp->remove, vp->mapping); if (vp->remove2)
__remove_shared_vm_struct(vp->remove2, vp->mapping);
} elseif (vp->insert) { /* * split_vma has split insert from vma, and needs * us to insert it before dropping the locks * (it may either follow vma or precede it).
*/
vma_iter_store_new(vmi, vp->insert);
mm->map_count++;
}
if (vp->anon_vma) {
anon_vma_interval_tree_post_update_vma(vp->vma); if (vp->adj_next)
anon_vma_interval_tree_post_update_vma(vp->adj_next);
anon_vma_unlock_write(vp->anon_vma);
}
if (vp->file) {
i_mmap_unlock_write(vp->mapping);
if (!vp->skip_vma_uprobe) {
uprobe_mmap(vp->vma);
if (vp->adj_next)
uprobe_mmap(vp->adj_next);
}
}
if (vp->remove) {
again:
vma_mark_detached(vp->remove); if (vp->file) {
uprobe_munmap(vp->remove, vp->remove->vm_start,
vp->remove->vm_end);
fput(vp->file);
} if (vp->remove->anon_vma)
anon_vma_merge(vp->vma, vp->remove);
mm->map_count--;
mpol_put(vma_policy(vp->remove)); if (!vp->remove2)
WARN_ON_ONCE(vp->vma->vm_end < vp->remove->vm_end);
vm_area_free(vp->remove);
/* * In mprotect's case 6 (see comments on vma_merge), * we are removing both mid and next vmas
*/ if (vp->remove2) {
vp->remove = vp->remove2;
vp->remove2 = NULL; goto again;
}
} if (vp->insert && vp->file)
uprobe_mmap(vp->insert);
}
/* * init_vma_prep() - Initializer wrapper for vma_prepare struct * @vp: The vma_prepare struct * @vma: The vma that will be altered once locked
*/ staticvoid init_vma_prep(struct vma_prepare *vp, struct vm_area_struct *vma)
{
init_multi_vma_prep(vp, vma, NULL);
}
/* * Can the proposed VMA be merged with the left (previous) VMA taking into * account the start position of the proposed range.
*/ staticbool can_vma_merge_left(struct vma_merge_struct *vmg)
/* * Can the proposed VMA be merged with the right (next) VMA taking into * account the end position of the proposed range. * * In addition, if we can merge with the left VMA, ensure that left and right * anon_vma's are also compatible.
*/ staticbool can_vma_merge_right(struct vma_merge_struct *vmg, bool can_merge_left)
{ struct vm_area_struct *next = vmg->next; struct vm_area_struct *prev;
if (!next || vmg->end != next->vm_start || !can_vma_merge_before(vmg)) returnfalse;
if (!can_merge_left) returntrue;
/* * If we can merge with prev (left) and next (right), indicating that * each VMA's anon_vma is compatible with the proposed anon_vma, this * does not mean prev and next are compatible with EACH OTHER. * * We therefore check this in addition to mergeability to either side.
*/
prev = vmg->prev; return !prev->anon_vma || !next->anon_vma ||
prev->anon_vma == next->anon_vma;
}
/* * Close a vm structure and free it.
*/ void remove_vma(struct vm_area_struct *vma)
{
might_sleep();
vma_close(vma); if (vma->vm_file)
fput(vma->vm_file);
mpol_put(vma_policy(vma));
vm_area_free(vma);
}
/* * Get rid of page table information in the indicated region. * * Called with the mm semaphore held.
*/ void unmap_region(struct ma_state *mas, struct vm_area_struct *vma, struct vm_area_struct *prev, struct vm_area_struct *next)
{ struct mm_struct *mm = vma->vm_mm; struct mmu_gather tlb;
/* * __split_vma() bypasses sysctl_max_map_count checking. We use this where it * has already been checked or doesn't make sense to fail. * VMA Iterator will point to the original VMA.
*/ static __must_check int
__split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, unsignedlong addr, int new_below)
{ struct vma_prepare vp; struct vm_area_struct *new; int err;
/* * Get rid of huge pages and shared page tables straddling the split * boundary.
*/
vma_adjust_trans_huge(vma, vma->vm_start, addr, NULL); if (is_vm_hugetlb_page(vma))
hugetlb_split(vma, addr);
/* * Split a vma into two pieces at address 'addr', a new vma is allocated * either for the first part or the tail.
*/ staticint split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, unsignedlong addr, int new_below)
{ if (vma->vm_mm->map_count >= sysctl_max_map_count) return -ENOMEM;
return __split_vma(vmi, vma, addr, new_below);
}
/* * dup_anon_vma() - Helper function to duplicate anon_vma on VMA merge in the * instance that the destination VMA has no anon_vma but the source does. * * @dst: The destination VMA * @src: The source VMA * @dup: Pointer to the destination VMA when successful. * * Returns: 0 on success.
*/ staticint dup_anon_vma(struct vm_area_struct *dst, struct vm_area_struct *src, struct vm_area_struct **dup)
{ /* * There are three cases to consider for correctly propagating * anon_vma's on merge. * * The first is trivial - neither VMA has anon_vma, we need not do * anything. * * The second where both have anon_vma is also a no-op, as they must * then be the same, so there is simply nothing to copy. * * Here we cover the third - if the destination VMA has no anon_vma, * that is it is unfaulted, we need to ensure that the newly merged * range is referenced by the anon_vma's of the source.
*/ if (src->anon_vma && !dst->anon_vma) { int ret;
vma_assert_write_locked(dst);
dst->anon_vma = src->anon_vma;
ret = anon_vma_clone(dst, src); if (ret) return ret;
*dup = dst;
}
return 0;
}
#ifdef CONFIG_DEBUG_VM_MAPLE_TREE void validate_mm(struct mm_struct *mm)
{ int bug = 0; int i = 0; struct vm_area_struct *vma;
VMA_ITERATOR(vmi, mm, 0);
if (VM_WARN_ON_ONCE_MM(vma->vm_start != vmi_start, mm))
warn = 1;
if (warn) {
pr_emerg("issue in %s\n", current->comm);
dump_stack();
dump_vma(vma);
pr_emerg("tree range: %px start %lx end %lx\n", vma,
vmi_start, vmi_end - 1);
vma_iter_dump_tree(&vmi);
}
#ifdef CONFIG_DEBUG_VM_RB if (anon_vma) {
anon_vma_lock_read(anon_vma);
list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
anon_vma_interval_tree_verify(avc);
anon_vma_unlock_read(anon_vma);
} #endif /* Check for a infinite loop */ if (++i > mm->map_count + 10) {
i = -1; break;
}
} if (i != mm->map_count) {
pr_emerg("map_count %d vma iterator %d\n", mm->map_count, i);
bug = 1;
}
VM_BUG_ON_MM(bug, mm);
} #endif/* CONFIG_DEBUG_VM_MAPLE_TREE */
/* * Based on the vmg flag indicating whether we need to adjust the vm_start field * for the middle or next VMA, we calculate what the range of the newly adjusted * VMA ought to be, and set the VMA's range accordingly.
*/ staticvoid vmg_adjust_set_range(struct vma_merge_struct *vmg)
{ struct vm_area_struct *adjust;
pgoff_t pgoff;
/* * Actually perform the VMA merge operation. * * IMPORTANT: We guarantee that, should vmg->give_up_on_oom is set, to not * modify any VMAs or cause inconsistent state should an OOM condition arise. * * Returns 0 on success, or an error value on failure.
*/ staticint commit_merge(struct vma_merge_struct *vmg)
{ struct vm_area_struct *vma; struct vma_prepare vp;
if (vmg->__adjust_next_start) { /* We manipulate middle and adjust next, which is the target. */
vma = vmg->middle;
vma_iter_config(vmg->vmi, vmg->end, vmg->next->vm_end);
} else {
vma = vmg->target; /* Note: vma iterator must be pointing to 'start'. */
vma_iter_config(vmg->vmi, vmg->start, vmg->end);
}
init_multi_vma_prep(&vp, vma, vmg);
/* * If vmg->give_up_on_oom is set, we're safe, because we don't actually * manipulate any VMAs until we succeed at preallocation. * * Past this point, we will not return an error.
*/ if (vma_iter_prealloc(vmg->vmi, vma)) return -ENOMEM;
vma_prepare(&vp); /* * THP pages may need to do additional splits if we increase * middle->vm_start.
*/
vma_adjust_trans_huge(vma, vmg->start, vmg->end,
vmg->__adjust_middle_start ? vmg->middle : NULL);
vma_set_range(vma, vmg->start, vmg->end, vmg->pgoff);
vmg_adjust_set_range(vmg);
vma_iter_store_overwrite(vmg->vmi, vmg->target);
vma_complete(&vp, vmg->vmi, vma->vm_mm);
return 0;
}
/* We can only remove VMAs when merging if they do not have a close hook. */ staticbool can_merge_remove_vma(struct vm_area_struct *vma)
{ return !vma->vm_ops || !vma->vm_ops->close;
}
/* * vma_merge_existing_range - Attempt to merge VMAs based on a VMA having its * attributes modified. * * @vmg: Describes the modifications being made to a VMA and associated * metadata. * * When the attributes of a range within a VMA change, then it might be possible * for immediately adjacent VMAs to be merged into that VMA due to having * identical properties. * * This function checks for the existence of any such mergeable VMAs and updates * the maple tree describing the @vmg->middle->vm_mm address space to account * for this, as well as any VMAs shrunk/expanded/deleted as a result of this * merge. * * As part of this operation, if a merge occurs, the @vmg object will have its * vma, start, end, and pgoff fields modified to execute the merge. Subsequent * calls to this function should reset these fields. * * Returns: The merged VMA if merge succeeds, or NULL otherwise. * * ASSUMPTIONS: * - The caller must assign the VMA to be modifed to @vmg->middle. * - The caller must have set @vmg->prev to the previous VMA, if there is one. * - The caller must not set @vmg->next, as we determine this. * - The caller must hold a WRITE lock on the mm_struct->mmap_lock. * - vmi must be positioned within [@vmg->middle->vm_start, @vmg->middle->vm_end).
*/ static __must_check struct vm_area_struct *vma_merge_existing_range( struct vma_merge_struct *vmg)
{ struct vm_area_struct *middle = vmg->middle; struct vm_area_struct *prev = vmg->prev; struct vm_area_struct *next; struct vm_area_struct *anon_dup = NULL; unsignedlong start = vmg->start; unsignedlong end = vmg->end; bool left_side = middle && start == middle->vm_start; bool right_side = middle && end == middle->vm_end; int err = 0; bool merge_left, merge_right, merge_both;
mmap_assert_write_locked(vmg->mm);
VM_WARN_ON_VMG(!middle, vmg); /* We are modifying a VMA, so caller must specify. */
VM_WARN_ON_VMG(vmg->next, vmg); /* We set this. */
VM_WARN_ON_VMG(prev && start <= prev->vm_start, vmg);
VM_WARN_ON_VMG(start >= end, vmg);
/* * If middle == prev, then we are offset into a VMA. Otherwise, if we are * not, we must span a portion of the VMA.
*/
VM_WARN_ON_VMG(middle &&
((middle != prev && vmg->start != middle->vm_start) ||
vmg->end > middle->vm_end), vmg); /* The vmi must be positioned within vmg->middle. */
VM_WARN_ON_VMG(middle &&
!(vma_iter_addr(vmg->vmi) >= middle->vm_start &&
vma_iter_addr(vmg->vmi) < middle->vm_end), vmg);
vmg->state = VMA_MERGE_NOMERGE;
/* * If a special mapping or if the range being modified is neither at the * 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)) return NULL;
if (left_side)
merge_left = can_vma_merge_left(vmg); else
merge_left = false;
if (right_side) {
next = vmg->next = vma_iter_next_range(vmg->vmi);
vma_iter_prev_range(vmg->vmi);
if (merge_left) /* If merging prev, position iterator there. */
vma_prev(vmg->vmi); elseif (!merge_right) /* If we have nothing to merge, abort. */ return NULL;
merge_both = merge_left && merge_right; /* If we span the entire VMA, a merge implies it will be deleted. */
vmg->__remove_middle = left_side && right_side;
/* * If we need to remove middle in its entirety but are unable to do so, * we have no sensible recourse but to abort the merge.
*/ if (vmg->__remove_middle && !can_merge_remove_vma(middle)) return NULL;
/* * If we merge both VMAs, then next is also deleted. This implies * merge_will_delete_vma also.
*/
vmg->__remove_next = merge_both;
/* * If we cannot delete next, then we can reduce the operation to merging * prev and middle (thereby deleting middle).
*/ if (vmg->__remove_next && !can_merge_remove_vma(next)) {
vmg->__remove_next = false;
merge_right = false;
merge_both = false;
}
/* No matter what happens, we will be adjusting middle. */
vma_start_write(middle);
if (merge_right) {
vma_start_write(next);
vmg->target = next;
}
if (merge_left) {
vma_start_write(prev);
vmg->target = prev;
}
if (merge_both) { /* * |<-------------------->| * |-------********-------| * prev middle next * extend delete delete
*/
/* * We already ensured anon_vma compatibility above, so now it's * simply a case of, if prev has no anon_vma object, which of * next or middle contains the anon_vma we must duplicate.
*/
err = dup_anon_vma(prev, next->anon_vma ? next : middle,
&anon_dup);
} elseif (merge_left) { /* * |<------------>| OR * |<----------------->| * |-------************* * prev middle * extend shrink/delete
*/
VM_WARN_ON_VMG(!merge_right, vmg); /* If we are offset into a VMA, then prev must be middle. */
VM_WARN_ON_VMG(vmg->start > middle->vm_start && prev && middle != prev, vmg);
/* * This means we have failed to clone anon_vma's correctly, but no * actual changes to VMAs have occurred, so no harm no foul - if the * user doesn't want this reported and instead just wants to give up on * the merge, allow it.
*/ if (!vmg->give_up_on_oom)
vmg->state = VMA_MERGE_ERROR_NOMEM; return NULL;
}
/* * vma_merge_new_range - Attempt to merge a new VMA into address space * * @vmg: Describes the VMA we are adding, in the range @vmg->start to @vmg->end * (exclusive), which we try to merge with any adjacent VMAs if possible. * * We are about to add a VMA to the address space starting at @vmg->start and * ending at @vmg->end. There are three different possible scenarios: * * 1. There is a VMA with identical properties immediately adjacent to the * proposed new VMA [@vmg->start, @vmg->end) either before or after it - * EXPAND that VMA: * * Proposed: |-----| or |-----| * Existing: |----| |----| * * 2. There are VMAs with identical properties immediately adjacent to the * proposed new VMA [@vmg->start, @vmg->end) both before AND after it - * EXPAND the former and REMOVE the latter: * * Proposed: |-----| * Existing: |----| |----| * * 3. There are no VMAs immediately adjacent to the proposed new VMA or those * VMAs do not have identical attributes - NO MERGE POSSIBLE. * * In instances where we can merge, this function returns the expanded VMA which * will have its range adjusted accordingly and the underlying maple tree also * adjusted. * * Returns: In instances where no merge was possible, NULL. Otherwise, a pointer * to the VMA we expanded. * * This function adjusts @vmg to provide @vmg->next if not already specified, * and adjusts [@vmg->start, @vmg->end) to span the expanded range. * * ASSUMPTIONS: * - The caller must hold a WRITE lock on the mm_struct->mmap_lock. * - The caller must have determined that [@vmg->start, @vmg->end) is empty, other than VMAs that will be unmapped should the operation succeed. * - The caller must have specified the previous vma in @vmg->prev. * - The caller must have specified the next vma in @vmg->next. * - The caller must have positioned the vmi at or before the gap.
*/ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg)
{ struct vm_area_struct *prev = vmg->prev; struct vm_area_struct *next = vmg->next; unsignedlong end = vmg->end; bool can_merge_left, can_merge_right;
mmap_assert_write_locked(vmg->mm);
VM_WARN_ON_VMG(vmg->middle, vmg);
VM_WARN_ON_VMG(vmg->target, vmg); /* vmi must point at or before the gap. */
VM_WARN_ON_VMG(vma_iter_addr(vmg->vmi) > end, vmg);
vmg->state = VMA_MERGE_NOMERGE;
/* Special VMAs are unmergeable, also if no prev/next. */ if ((vmg->vm_flags & VM_SPECIAL) || (!prev && !next)) return NULL;
/* If we can merge with the next VMA, adjust vmg accordingly. */ if (can_merge_right) {
vmg->end = next->vm_end;
vmg->target = next;
}
/* If we can merge with the previous VMA, adjust vmg accordingly. */ if (can_merge_left) {
vmg->start = prev->vm_start;
vmg->target = prev;
vmg->pgoff = prev->vm_pgoff;
/* * If this merge would result in removal of the next VMA but we * are not permitted to do so, reduce the operation to merging * prev and vma.
*/ if (can_merge_right && !can_merge_remove_vma(next))
vmg->end = end;
/* In expand-only case we are already positioned at prev. */ if (!vmg->just_expand) { /* Equivalent to going to the previous range. */
vma_prev(vmg->vmi);
}
}
/* * Now try to expand adjacent VMA(s). This takes care of removing the * following VMA if we have VMAs on both sides.
*/ if (vmg->target && !vma_expand(vmg)) {
khugepaged_enter_vma(vmg->target, vmg->vm_flags);
vmg->state = VMA_MERGE_SUCCESS; return vmg->target;
}
return NULL;
}
/* * vma_expand - Expand an existing VMA * * @vmg: Describes a VMA expansion operation. * * Expand @vma to vmg->start and vmg->end. Can expand off the start and end. * Will expand over vmg->next if it's different from vmg->target and vmg->end == * vmg->next->vm_end. Checking if the vmg->target can expand and merge with * vmg->next needs to be handled by the caller. * * Returns: 0 on success. * * ASSUMPTIONS: * - The caller must hold a WRITE lock on the mm_struct->mmap_lock. * - The caller must have set @vmg->target and @vmg->next.
*/ int vma_expand(struct vma_merge_struct *vmg)
{ struct vm_area_struct *anon_dup = NULL; bool remove_next = false; struct vm_area_struct *target = vmg->target; struct vm_area_struct *next = vmg->next;
VM_WARN_ON_VMG(!target, vmg);
mmap_assert_write_locked(vmg->mm);
vma_start_write(target); if (next && (target != next) && (vmg->end == next->vm_end)) { int ret;
remove_next = true; /* This should already have been checked by this point. */
VM_WARN_ON_VMG(!can_merge_remove_vma(next), vmg);
vma_start_write(next); /* * In this case we don't report OOM, so vmg->give_up_on_mm is * safe.
*/
ret = dup_anon_vma(target, next, &anon_dup); if (ret) return ret;
}
/* Not merging but overwriting any part of next is not handled. */
VM_WARN_ON_VMG(next && !remove_next &&
next != target && vmg->end > next->vm_start, vmg); /* Only handles expanding */
VM_WARN_ON_VMG(target->vm_start < vmg->start ||
target->vm_end > vmg->end, vmg);
if (remove_next)
vmg->__remove_next = true;
if (commit_merge(vmg)) goto nomem;
return 0;
nomem: if (anon_dup)
unlink_anon_vmas(anon_dup); /* * If the user requests that we just give upon OOM, we are safe to do so * here, as commit merge provides this contract to us. Nothing has been * changed - no harm no foul, just don't report it.
*/ if (!vmg->give_up_on_oom)
vmg->state = VMA_MERGE_ERROR_NOMEM; return -ENOMEM;
}
/* * vma_shrink() - Reduce an existing VMAs memory area * @vmi: The vma iterator * @vma: The VMA to modify * @start: The new start * @end: The new end * * Returns: 0 on success, -ENOMEM otherwise
*/ int vma_shrink(struct vma_iterator *vmi, struct vm_area_struct *vma, unsignedlong start, unsignedlong end, pgoff_t pgoff)
{ struct vma_prepare vp;
/* * We can free page tables without write-locking mmap_lock because VMAs * were isolated before we downgraded mmap_lock.
*/
mas_set(mas_detach, 1);
tlb_gather_mmu(&tlb, vms->vma->vm_mm);
update_hiwater_rss(vms->vma->vm_mm);
unmap_vmas(&tlb, mas_detach, vms->vma, vms->start, vms->end,
vms->vma_count, mm_wr_locked);
mas_set(mas_detach, 1); /* start and end may be different if there is no prev or next vma. */
free_pgtables(&tlb, mas_detach, vms->vma, vms->unmap_start,
vms->unmap_end, mm_wr_locked);
tlb_finish_mmu(&tlb);
vms->clear_ptes = false;
}
/* * vms_complete_munmap_vmas() - Finish the munmap() operation * @vms: The vma munmap struct * @mas_detach: The maple state of the detached vmas * * This updates the mm_struct, unmaps the region, frees the resources * used for the munmap() and may downgrade the lock - if requested. Everything * needed to be done once the vma maple tree is updated.
*/ staticvoid vms_complete_munmap_vmas(struct vma_munmap_struct *vms, struct ma_state *mas_detach)
{ struct vm_area_struct *vma; struct mm_struct *mm;
mm = current->mm;
mm->map_count -= vms->vma_count;
mm->locked_vm -= vms->locked_vm; if (vms->unlock)
mmap_write_downgrade(mm);
/* Remove and clean up vmas */
mas_set(mas_detach, 0);
mas_for_each(mas_detach, vma, ULONG_MAX)
remove_vma(vma);
vm_unacct_memory(vms->nr_accounted);
validate_mm(mm); if (vms->unlock)
mmap_read_unlock(mm);
__mt_destroy(mas_detach->tree);
}
/* * reattach_vmas() - Undo any munmap work and free resources * @mas_detach: The maple state with the detached maple tree * * Reattach any detached vmas and free up the maple tree used to track the vmas.
*/ staticvoid reattach_vmas(struct ma_state *mas_detach)
{ struct vm_area_struct *vma;
/* * vms_gather_munmap_vmas() - Put all VMAs within a range into a maple tree * for removal at a later date. Handles splitting first and last if necessary * and marking the vmas as isolated. * * @vms: The vma munmap struct * @mas_detach: The maple state tracking the detached tree * * Return: 0 on success, error otherwise
*/ staticint vms_gather_munmap_vmas(struct vma_munmap_struct *vms, struct ma_state *mas_detach)
{ struct vm_area_struct *next = NULL; int error;
/* * If we need to split any vma, do it now to save pain later. * Does it split the first one?
*/ if (vms->start > vms->vma->vm_start) {
/* * Make sure that map_count on return from munmap() will * not exceed its limit; but let map_count go just above * 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) {
error = -ENOMEM; goto map_count_exceeded;
}
/* Don't bother splitting the VMA if we can't unmap it anyway */ if (vma_is_sealed(vms->vma)) {
error = -EPERM; goto start_split_failed;
}
error = __split_vma(vms->vmi, vms->vma, vms->start, 1); if (error) goto start_split_failed;
}
vms->prev = vma_prev(vms->vmi); if (vms->prev)
vms->unmap_start = vms->prev->vm_end;
/* * Detach a range of VMAs from the mm. Using next as a temp variable as * it is always overwritten.
*/
for_each_vma_range(*(vms->vmi), next, vms->end) { long nrpages;
if (vma_is_sealed(next)) {
error = -EPERM; goto modify_vma_failed;
} /* Does it split the end? */ if (next->vm_end > vms->end) {
error = __split_vma(vms->vmi, next, vms->end, 0); if (error) goto end_split_failed;
}
vma_start_write(next);
mas_set(mas_detach, vms->vma_count++);
error = mas_store_gfp(mas_detach, next, GFP_KERNEL); if (error) goto munmap_gather_failed;
if (vms->uf) { /* * If userfaultfd_unmap_prep returns an error the vmas * will remain split, but userland will get a * highly unexpected error anyway. This is no * different than the case where the first of the two * __split_vma fails, but we don't undo the first * split, despite we could. This is unlikely enough * failure that it's not worth optimizing it for.
*/
error = userfaultfd_unmap_prep(next, vms->start,
vms->end, vms->uf); if (error) goto userfaultfd_error;
} #ifdef CONFIG_DEBUG_VM_MAPLE_TREE
BUG_ON(next->vm_start < vms->start);
BUG_ON(next->vm_start > vms->end); #endif
}
vms->next = vma_next(vms->vmi); if (vms->next)
vms->unmap_end = vms->next->vm_start;
#ifdefined(CONFIG_DEBUG_VM_MAPLE_TREE) /* Make sure no VMAs are about to be lost. */
{
MA_STATE(test, mas_detach->tree, 0, 0); struct vm_area_struct *vma_mas, *vma_test; int test_count = 0;
/* * init_vma_munmap() - Initializer wrapper for vma_munmap_struct * @vms: The vma munmap struct * @vmi: The vma iterator * @vma: The first vm_area_struct to munmap * @start: The aligned start address to munmap * @end: The aligned end address to munmap * @uf: The userfaultfd list_head * @unlock: Unlock after the operation. Only unlocked on success
*/ staticvoid init_vma_munmap(struct vma_munmap_struct *vms, struct vma_iterator *vmi, struct vm_area_struct *vma, unsignedlong start, unsignedlong end, struct list_head *uf, bool unlock)
{
vms->vmi = vmi;
vms->vma = vma; if (vma) {
vms->start = start;
vms->end = end;
} else {
vms->start = vms->end = 0;
}
vms->unlock = unlock;
vms->uf = uf;
vms->vma_count = 0;
vms->nr_pages = vms->locked_vm = vms->nr_accounted = 0;
vms->exec_vm = vms->stack_vm = vms->data_vm = 0;
vms->unmap_start = FIRST_USER_ADDRESS;
vms->unmap_end = USER_PGTABLES_CEILING;
vms->clear_ptes = false;
}
/* * do_vmi_align_munmap() - munmap the aligned region from @start to @end. * @vmi: The vma iterator * @vma: The starting vm_area_struct * @mm: The mm_struct * @start: The aligned start address to munmap. * @end: The aligned end address to munmap. * @uf: The userfaultfd list_head * @unlock: Set to true to drop the mmap_lock. unlocking only happens on * success. * * Return: 0 on success and drops the lock if so directed, error and leaves the * lock held otherwise.
*/ int do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma, struct mm_struct *mm, unsignedlong start, unsignedlong end, struct list_head *uf, bool unlock)
{ struct maple_tree mt_detach;
MA_STATE(mas_detach, &mt_detach, 0, 0);
mt_init_flags(&mt_detach, vmi->mas.tree->ma_flags & MT_FLAGS_LOCK_MASK);
mt_on_stack(mt_detach); struct vma_munmap_struct vms; int error;
/* * do_vmi_munmap() - munmap a given range. * @vmi: The vma iterator * @mm: The mm_struct * @start: The start address to munmap * @len: The length of the range to munmap * @uf: The userfaultfd list_head * @unlock: set to true if the user wants to drop the mmap_lock on success * * This function takes a @mas that is either pointing to the previous VMA or set * to MA_START and sets it up to remove the mapping(s). The @len will be * aligned. * * Return: 0 on success and drops the lock if so directed, error and leaves the * lock held otherwise.
*/ int do_vmi_munmap(struct vma_iterator *vmi, struct mm_struct *mm, unsignedlong start, size_t len, struct list_head *uf, bool unlock)
{ unsignedlong end; struct vm_area_struct *vma;
if ((offset_in_page(start)) || start > TASK_SIZE || len > TASK_SIZE-start) return -EINVAL;
end = start + PAGE_ALIGN(len); if (end == start) return -EINVAL;
/* Find the first overlapping VMA */
vma = vma_find(vmi, end); if (!vma) { if (unlock)
mmap_write_unlock(mm); return 0;
}
return do_vmi_align_munmap(vmi, vma, mm, start, end, uf, unlock);
}
/* * We are about to modify one or multiple of a VMA's flags, policy, userfaultfd * context and anonymous VMA name within the range [start, end). * * As a result, we might be able to merge the newly modified VMA range with an * adjacent VMA with identical properties. * * If no merge is possible and the range does not span the entirety of the VMA, * we then need to split the VMA to accommodate the change. * * The function returns either the merged VMA, the original VMA if a split was * required instead, or an error if the split failed.
*/ staticstruct vm_area_struct *vma_modify(struct vma_merge_struct *vmg)
{ struct vm_area_struct *vma = vmg->middle; unsignedlong start = vmg->start; unsignedlong end = vmg->end; struct vm_area_struct *merged;
/* First, try to merge. */
merged = vma_merge_existing_range(vmg); if (merged) return merged; if (vmg_nomem(vmg)) return ERR_PTR(-ENOMEM);
/* * Split can fail for reasons other than OOM, so if the user requests * this it's probably a mistake.
*/
VM_WARN_ON(vmg->give_up_on_oom &&
(vma->vm_start != start || vma->vm_end != end));
/* Split any preceding portion of the VMA. */ if (vma->vm_start < start) { int err = split_vma(vmg->vmi, vma, start, 1);
if (err) return ERR_PTR(err);
}
/* Split any trailing portion of the VMA. */ if (vma->vm_end > end) { int err = split_vma(vmg->vmi, vma, end, 0);
/* * Unlink a file-based vm structure from its interval tree, to hide * vma from rmap and vmtruncate before freeing its page tables.
*/ void unlink_file_vma(struct vm_area_struct *vma)
{ struct file *file = vma->vm_file;
if (file) { struct address_space *mapping = file->f_mapping;
/* * Copy the vma structure to a new location in the same mm, * prior to moving page table entries, to effect an mremap move.
*/ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, unsignedlong addr, unsignedlong len, pgoff_t pgoff, bool *need_rmap_locks)
{ struct vm_area_struct *vma = *vmap; unsignedlong vma_start = vma->vm_start; struct mm_struct *mm = vma->vm_mm; struct vm_area_struct *new_vma; bool faulted_in_anon_vma = true;
VMA_ITERATOR(vmi, mm, addr);
VMG_VMA_STATE(vmg, &vmi, NULL, vma, addr, addr + len);
/* * If anonymous vma has not yet been faulted, update new pgoff * to match new location, to increase its chance of merging.
*/ if (unlikely(vma_is_anonymous(vma) && !vma->anon_vma)) {
pgoff = addr >> PAGE_SHIFT;
faulted_in_anon_vma = false;
}
/* * If the VMA we are copying might contain a uprobe PTE, ensure * that we do not establish one upon merge. Otherwise, when mremap() * moves page tables, it will orphan the newly created PTE.
*/ if (vma->vm_file)
vmg.skip_vma_uprobe = true;
new_vma = find_vma_prev(mm, addr, &vmg.prev); if (new_vma && new_vma->vm_start < addr + len) return NULL; /* should never get here */
if (new_vma) { /* * Source vma may have been merged into new_vma
*/ if (unlikely(vma_start >= new_vma->vm_start &&
vma_start < new_vma->vm_end)) { /* * The only way we can get a vma_merge with * self during an mremap is if the vma hasn't * been faulted in yet and we were allowed to * reset the dst vma->vm_pgoff to the * destination address of the mremap to allow * the merge to happen. mremap must change the * vm_pgoff linearity between src and dst vmas * (in turn preventing a vma_merge) to be * safe. It is only safe to keep the vm_pgoff * linear if there are no pages mapped yet.
*/
VM_BUG_ON_VMA(faulted_in_anon_vma, new_vma);
*vmap = vma = new_vma;
}
*need_rmap_locks = (new_vma->vm_pgoff <= vma->vm_pgoff);
} else {
new_vma = vm_area_dup(vma); if (!new_vma) goto out;
vma_set_range(new_vma, addr, addr + len, pgoff); if (vma_dup_policy(vma, new_vma)) goto out_free_vma; if (anon_vma_clone(new_vma, vma)) goto out_free_mempol; if (new_vma->vm_file)
get_file(new_vma->vm_file); if (new_vma->vm_ops && new_vma->vm_ops->open)
new_vma->vm_ops->open(new_vma); if (vma_link(mm, new_vma)) goto out_vma_link;
*need_rmap_locks = false;
} return new_vma;
/* * Rough compatibility check to quickly see if it's even worth looking * at sharing an anon_vma. * * They need to have the same vm_file, and the flags can only differ * in things that mprotect may change. * * NOTE! The fact that we share an anon_vma doesn't _have_ to mean that * we can merge the two vma's. For example, we refuse to merge a vma if * there is a vm_ops->close() function, because that indicates that the * driver is doing some kind of reference counting. But that doesn't * really matter for the anon_vma sharing case.
*/ staticint anon_vma_compatible(struct vm_area_struct *a, struct vm_area_struct *b)
{ 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_SOFTDIRTY)) &&
b->vm_pgoff == a->vm_pgoff + ((b->vm_start - a->vm_start) >> PAGE_SHIFT);
}
/* * Do some basic sanity checking to see if we can re-use the anon_vma * from 'old'. The 'a'/'b' vma's are in VM order - one of them will be * the same as 'old', the other will be the new one that is trying * to share the anon_vma. * * NOTE! This runs with mmap_lock held for reading, so it is possible that * the anon_vma of 'old' is concurrently in the process of being set up * by another page fault trying to merge _that_. But that's ok: if it * is being set up, that automatically means that it will be a singleton * acceptable for merging, so we can do all of this optimistically. But * we do that READ_ONCE() to make sure that we never re-load the pointer. * * IOW: that the "list_is_singular()" test on the anon_vma_chain only * matters for the 'stable anon_vma' case (ie the thing we want to avoid * is to return an anon_vma that is "complex" due to having gone through * a fork). * * We also make sure that the two vma's are compatible (adjacent, * and with the same memory policies). That's all stable, even with just * a read lock on the mmap_lock.
*/ staticstruct anon_vma *reusable_anon_vma(struct vm_area_struct *old, struct vm_area_struct *a, struct vm_area_struct *b)
{ if (anon_vma_compatible(a, b)) { struct anon_vma *anon_vma = READ_ONCE(old->anon_vma);
if (anon_vma && list_is_singular(&old->anon_vma_chain)) return anon_vma;
} return NULL;
}
/* * find_mergeable_anon_vma is used by anon_vma_prepare, to check * neighbouring vmas for a suitable anon_vma, before it goes off * to allocate a new anon_vma. It checks because a repetitive * sequence of mprotects and faults may otherwise lead to distinct * anon_vmas being allocated, preventing vma merge in subsequent * mprotect.
*/ struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *vma)
{ struct anon_vma *anon_vma = NULL; struct vm_area_struct *prev, *next;
VMA_ITERATOR(vmi, vma->vm_mm, vma->vm_end);
/* Try next first. */
next = vma_iter_load(&vmi); if (next) {
anon_vma = reusable_anon_vma(next, vma, next); if (anon_vma) return anon_vma;
}
/* * We might reach here with anon_vma == NULL if we can't find * any reusable anon_vma. * There's no absolute need to look only at touching neighbours: * we could search further afield for "compatible" anon_vmas. * But it would probably just be a waste of time searching, * or lead to too many vmas hanging off the same anon_vma. * We're trying to allow mprotect remerging later on, * not trying to minimize memory used for anon_vmas.
*/ return anon_vma;
}
/* * Does this VMA require the underlying folios to have their dirty state * tracked?
*/ bool vma_needs_dirty_tracking(struct vm_area_struct *vma)
{ /* Only shared, writable VMAs require dirty tracking. */ if (!vma_is_shared_writable(vma)) returnfalse;
/* Does the filesystem need to be notified? */ if (vm_ops_needs_writenotify(vma->vm_ops)) returntrue;
/* * Even if the filesystem doesn't indicate a need for writenotify, if it * can writeback, dirty tracking is still required.
*/ return vma_fs_can_writeback(vma);
}
/* * Some shared mappings will want the pages marked read-only * to track write events. If so, we'll downgrade vm_page_prot * to the private version (using protection_map[] without the * VM_SHARED bit).
*/ bool vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot)
{ /* If it was private or non-writable, the write bit is already clear */ if (!vma_is_shared_writable(vma)) returnfalse;
/* The backer wishes to know when pages are first written to? */ if (vm_ops_needs_writenotify(vma->vm_ops)) returntrue;
/* The open routine did something to the protections that pgprot_modify
* won't preserve? */ if (pgprot_val(vm_page_prot) !=
pgprot_val(vm_pgprot_modify(vm_page_prot, vma->vm_flags))) returnfalse;
/* * Do we need to track softdirty? hugetlb does not support softdirty * tracking yet.
*/ if (vma_soft_dirty_enabled(vma) && !is_vm_hugetlb_page(vma)) returntrue;
/* Do we need write faults for uffd-wp tracking? */ if (userfaultfd_wp(vma)) returntrue;
/* Can the mapping track the dirty pages? */ return vma_fs_can_writeback(vma);
}
static DEFINE_MUTEX(mm_all_locks_mutex);
staticvoid vm_lock_anon_vma(struct mm_struct *mm, struct anon_vma *anon_vma)
{ if (!test_bit(0, (unsignedlong *) &anon_vma->root->rb_root.rb_root.rb_node)) { /* * The LSB of head.next can't change from under us * because we hold the mm_all_locks_mutex.
*/
down_write_nest_lock(&anon_vma->root->rwsem, &mm->mmap_lock); /* * We can safely modify head.next after taking the * anon_vma->root->rwsem. If some other vma in this mm shares * the same anon_vma we won't take it again. * * No need of atomic instructions here, head.next * can't change from under us thanks to the * anon_vma->root->rwsem.
*/ if (__test_and_set_bit(0, (unsignedlong *)
&anon_vma->root->rb_root.rb_root.rb_node))
BUG();
}
}
staticvoid vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
{ if (!test_bit(AS_MM_ALL_LOCKS, &mapping->flags)) { /* * AS_MM_ALL_LOCKS can't change from under us because * we hold the mm_all_locks_mutex. * * Operations on ->flags have to be atomic because * even if AS_MM_ALL_LOCKS is stable thanks to the * mm_all_locks_mutex, there may be other cpus * changing other bitflags in parallel to us.
*/ if (test_and_set_bit(AS_MM_ALL_LOCKS, &mapping->flags))
BUG();
down_write_nest_lock(&mapping->i_mmap_rwsem, &mm->mmap_lock);
}
}
/* * This operation locks against the VM for all pte/vma/mm related * operations that could ever happen on a certain mm. This includes * vmtruncate, try_to_unmap, and all page faults. * * The caller must take the mmap_lock in write mode before calling * mm_take_all_locks(). The caller isn't allowed to release the * mmap_lock until mm_drop_all_locks() returns. * * mmap_lock in write mode is required in order to block all operations * that could modify pagetables and free pages without need of * altering the vma layout. It's also needed in write mode to avoid new * anon_vmas to be associated with existing vmas. * * A single task can't take more than one mm_take_all_locks() in a row * or it would deadlock. * * The LSB in anon_vma->rb_root.rb_node and the AS_MM_ALL_LOCKS bitflag in * mapping->flags avoid to take the same lock twice, if more than one * vma in this mm is backed by the same anon_vma or address_space. * * We take locks in following order, accordingly to comment at beginning * of mm/rmap.c: * - all hugetlbfs_i_mmap_rwsem_key locks (aka mapping->i_mmap_rwsem for * hugetlb mapping); * - all vmas marked locked * - all i_mmap_rwsem locks; * - all anon_vma->rwseml * * We can take all locks within these types randomly because the VM code * doesn't nest them and we protected from parallel mm_take_all_locks() by * mm_all_locks_mutex. * * mm_take_all_locks() and mm_drop_all_locks are expensive operations * that may have to take thousand of locks. * * mm_take_all_locks() can fail if it's interrupted by signals.
*/ int mm_take_all_locks(struct mm_struct *mm)
{ struct vm_area_struct *vma; struct anon_vma_chain *avc;
VMA_ITERATOR(vmi, mm, 0);
mmap_assert_write_locked(mm);
mutex_lock(&mm_all_locks_mutex);
/* * vma_start_write() does not have a complement in mm_drop_all_locks() * because vma_start_write() is always asymmetrical; it marks a VMA as * being written to until mmap_write_unlock() or mmap_write_downgrade() * is reached.
*/
for_each_vma(vmi, vma) { if (signal_pending(current)) goto out_unlock;
vma_start_write(vma);
}
vma_iter_init(&vmi, mm, 0);
for_each_vma(vmi, vma) { if (signal_pending(current)) goto out_unlock; if (vma->vm_file && vma->vm_file->f_mapping &&
is_vm_hugetlb_page(vma))
vm_lock_mapping(mm, vma->vm_file->f_mapping);
}
vma_iter_init(&vmi, mm, 0);
for_each_vma(vmi, vma) { if (signal_pending(current)) goto out_unlock; if (vma->vm_file && vma->vm_file->f_mapping &&
!is_vm_hugetlb_page(vma))
vm_lock_mapping(mm, vma->vm_file->f_mapping);
}
vma_iter_init(&vmi, mm, 0);
for_each_vma(vmi, vma) { if (signal_pending(current)) goto out_unlock; if (vma->anon_vma)
list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
vm_lock_anon_vma(mm, avc->anon_vma);
}
staticvoid vm_unlock_anon_vma(struct anon_vma *anon_vma)
{ if (test_bit(0, (unsignedlong *) &anon_vma->root->rb_root.rb_root.rb_node)) { /* * The LSB of head.next can't change to 0 from under * us because we hold the mm_all_locks_mutex. * * We must however clear the bitflag before unlocking * the vma so the users using the anon_vma->rb_root will * never see our bitflag. * * No need of atomic instructions here, head.next * can't change from under us until we release the * anon_vma->root->rwsem.
*/ if (!__test_and_clear_bit(0, (unsignedlong *)
&anon_vma->root->rb_root.rb_root.rb_node))
BUG();
anon_vma_unlock_write(anon_vma);
}
}
staticvoid vm_unlock_mapping(struct address_space *mapping)
{ if (test_bit(AS_MM_ALL_LOCKS, &mapping->flags)) { /* * AS_MM_ALL_LOCKS can't change to 0 from under us * because we hold the mm_all_locks_mutex.
*/
i_mmap_unlock_write(mapping); if (!test_and_clear_bit(AS_MM_ALL_LOCKS,
&mapping->flags))
BUG();
}
}
/* * The mmap_lock cannot be released by the caller until * mm_drop_all_locks() returns.
*/ void mm_drop_all_locks(struct mm_struct *mm)
{ struct vm_area_struct *vma; struct anon_vma_chain *avc;
VMA_ITERATOR(vmi, mm, 0);
for_each_vma(vmi, vma) { if (vma->anon_vma)
list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
vm_unlock_anon_vma(avc->anon_vma); if (vma->vm_file && vma->vm_file->f_mapping)
vm_unlock_mapping(vma->vm_file->f_mapping);
}
mutex_unlock(&mm_all_locks_mutex);
}
/* * We account for memory if it's a private writeable mapping, * not hugepages and VM_NORESERVE wasn't set.
*/ staticbool accountable_mapping(struct file *file, vm_flags_t vm_flags)
{ /* * hugetlb has its own accounting separate from the core VM * VM_HUGETLB may not be set yet so we cannot check for that flag.
*/ if (file && is_file_hugepages(file)) returnfalse;
/* * vms_abort_munmap_vmas() - Undo as much as possible from an aborted munmap() * operation. * @vms: The vma unmap structure * @mas_detach: The maple state with the detached maple tree * * Reattach any detached vmas, free up the maple tree used to track the vmas. * If that's not possible because the ptes are cleared (and vm_ops->closed() may * have been called), then a NULL is written over the vmas and the vmas are * removed (munmap() completed).
*/ staticvoid vms_abort_munmap_vmas(struct vma_munmap_struct *vms, struct ma_state *mas_detach)
{ struct ma_state *mas = &vms->vmi->mas;
if (!vms->nr_pages) return;
if (vms->clear_ptes) return reattach_vmas(mas_detach);
/* * Aborting cannot just call the vm_ops open() because they are often * not symmetrical and state data has been lost. Resort to the old * failure method of leaving a gap where the MAP_FIXED mapping failed.
*/
mas_set_range(mas, vms->start, vms->end - 1);
mas_store_gfp(mas, NULL, GFP_KERNEL|__GFP_NOFAIL); /* Clean up the insertion of the unfortunate gap */
vms_complete_munmap_vmas(vms, mas_detach);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.