]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
mm: linked list many+2
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 18 Dec 2020 01:20:43 +0000 (20:20 -0500)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Tue, 5 Jan 2021 17:33:40 +0000 (12:33 -0500)
Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
17 files changed:
fs/coredump.c
fs/proc/task_mmu.c
fs/userfaultfd.c
include/linux/mm.h
include/linux/mm_types.h
kernel/acct.c
kernel/fork.c
mm/debug.c
mm/huge_memory.c
mm/internal.h
mm/khugepaged.c
mm/memcontrol.c
mm/memory.c
mm/mempolicy.c
mm/mlock.c
mm/mmap.c
mm/util.c

index 0699ce6f6cc197c6e1f6ddb08b622cc5eab1d7e2..5b950af6e793e377ee28833f723d22dc46a58116 100644 (file)
@@ -1043,7 +1043,7 @@ whole:
 static struct vm_area_struct *first_vma(struct task_struct *tsk,
                                        struct vm_area_struct *gate_vma)
 {
-       struct vm_area_struct *ret = tsk->mm->mmap;
+       struct vm_area_struct *ret = find_vma(tsk->mm, 0);
 
        if (ret)
                return ret;
index 20a0fb414c4f38c014f1f0ae19348322579d5606..a331120a1cd31c69bf615d0a1880dfb3b1ea26bb 100644 (file)
@@ -840,16 +840,16 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
 {
        struct proc_maps_private *priv = m->private;
        struct mem_size_stats mss;
-       struct mm_struct *mm;
+       struct mm_struct *mm = priv->mm;
        struct vm_area_struct *vma;
-       unsigned long last_vma_end = 0;
+       unsigned long vma_start, last_vma_end = 0;
        int ret = 0;
+       MA_STATE(mas, &mm->mm_mt, 0, 0);
 
        priv->task = get_proc_task(priv->inode);
        if (!priv->task)
                return -ESRCH;
 
-       mm = priv->mm;
        if (!mm || !mmget_not_zero(mm)) {
                ret = -ESRCH;
                goto out_put_task;
@@ -862,8 +862,16 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
                goto out_put_mm;
 
        hold_task_mempolicy(priv);
+       vma = mas_find(&mas, 0);
+
+       if (vma)
+               vma_start = vma->vm_start;
+
+       mas_reset(&mas);
+       mas_set(&mas, 0);
+
 
-       for (vma = priv->mm->mmap; vma;) {
+       mas_for_each(&mas, vma, -1) {
                smap_gather_stats(vma, &mss, 0);
                last_vma_end = vma->vm_end;
 
@@ -872,6 +880,7 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
                 * access it for write request.
                 */
                if (mmap_lock_is_contended(mm)) {
+                       mas_pause(&mas);
                        mmap_read_unlock(mm);
                        ret = mmap_read_lock_killable(mm);
                        if (ret) {
@@ -915,7 +924,8 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
                         *    contains last_vma_end.
                         *    Iterate VMA' from last_vma_end.
                         */
-                       vma = find_vma(mm, last_vma_end - 1);
+                       mas_set(&mas, last_vma_end - 1);
+                       vma = mas_find(&mas, -1);
                        /* Case 3 above */
                        if (!vma)
                                break;
@@ -929,11 +939,9 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
                                smap_gather_stats(vma, &mss, last_vma_end);
                }
                /* Case 2 above */
-               vma = vma_next(mm, vma);
        }
 
-       show_vma_header_prefix(m, priv->mm->mmap->vm_start,
-                              last_vma_end, 0, 0, 0, 0);
+       show_vma_header_prefix(m, vma_start, last_vma_end, 0, 0, 0, 0);
        seq_pad(m, ' ');
        seq_puts(m, "[rollup]\n");
 
@@ -1257,7 +1265,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                                                0, NULL, mm, 0, -1UL);
                        mmu_notifier_invalidate_range_start(&range);
                }
-               walk_page_range(mm, 0, mm->highest_vm_end, &clear_refs_walk_ops,
+               walk_page_range(mm, 0, -1, &clear_refs_walk_ops,
                                &cp);
                if (type == CLEAR_REFS_SOFT_DIRTY)
                        mmu_notifier_invalidate_range_end(&range);
index 060e35f4bde9e7bf5595d2b69fcdd51acd6653c5..b0eac6fb3e8e2b7d6683b90929513de605989056 100644 (file)
@@ -792,7 +792,7 @@ int userfaultfd_unmap_prep(struct vm_area_struct *vma,
                           unsigned long start, unsigned long end,
                           struct list_head *unmaps)
 {
-       MA_STATE(mas, &mm->mm_mt, vma->vm_start, vma->vm_start);
+       MA_STATE(mas, &vma->vm_mm->mm_mt, vma->vm_start, vma->vm_start);
 
        mas_for_each(&mas, vma, end) {
                struct userfaultfd_unmap_ctx *unmap_ctx;
@@ -1335,7 +1335,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
        found = false;
        basic_ioctls = false;
        mas_set(&mas, vma->vm_start);
-       mas_for_each(&mas, curr, end) {
+       mas_for_each(&mas, cur, end) {
                cond_resched();
 
                BUG_ON(!!cur->vm_userfaultfd_ctx.ctx ^
@@ -1451,7 +1451,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
        skip:
                prev = vma;
                start = vma->vm_end;
-               vma = vma_next(vma);
+               vma = vma_next(mm, vma);
        } while (vma && vma->vm_start < end);
 out_unlock:
        mmap_write_unlock(mm);
@@ -1624,7 +1624,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
        skip:
                prev = vma;
                start = vma->vm_end;
-               vma = vma_next(vma);
+               vma = vma_next(mm, vma);
        } while (vma && vma->vm_start < end);
 out_unlock:
        mmap_write_unlock(mm);
index a9ad566f24fdc49b6ed432fdb9459b87a7205e75..1b8900398a654ebffd47a2472811d3d0603e1eef 100644 (file)
@@ -2655,7 +2655,7 @@ extern struct vm_area_struct *find_vma_intersection(struct mm_struct *mm,
                     unsigned long start_addr, unsigned long end_addr);
 
 static inline struct vm_area_struct *vma_next(struct mm_struct *mm,
-                       struct vm_area_struct *vma)
+                       const struct vm_area_struct *vma)
 {
        MA_STATE(mas, &mm->mm_mt, 0, 0);
 
@@ -2664,7 +2664,7 @@ static inline struct vm_area_struct *vma_next(struct mm_struct *mm,
 }
 
 static inline struct vm_area_struct *vma_prev(struct mm_struct *mm,
-                       struct vm_area_struct *vma)
+                       const struct vm_area_struct *vma)
 {
        MA_STATE(mas, &mm->mm_mt, 0, 0);
 
index 4e87ea66ca3c752ab06e6e01e077fcf523e39cdb..2548f9bda064130a934b9caa40aab4026431e019 100644 (file)
@@ -303,14 +303,11 @@ struct vm_userfaultfd_ctx {};
  * library, the executable area etc).
  */
 struct vm_area_struct {
-       /* The first cache line has the info for VMA tree walking. */
-
        unsigned long vm_start;         /* Our start address within vm_mm. */
        unsigned long vm_end;           /* The first byte after our end address
                                           within vm_mm. */
 
        /* linked list of VM areas per task, sorted by address */
-       struct vm_area_struct *vm_next, *vm_prev;
        struct mm_struct *vm_mm;        /* The address space we belong to. */
 
        /*
@@ -323,7 +320,6 @@ struct vm_area_struct {
        /* Information about our backing store: */
        unsigned long vm_pgoff;         /* Offset (within vm_file) in PAGE_SIZE
                                           units */
-       /* Second cache line starts here. */
        struct file * vm_file;          /* File we map to (can be NULL). */
        /*
         * For areas with an address space and backing store,
@@ -377,7 +373,6 @@ struct core_state {
 struct kioctx_table;
 struct mm_struct {
        struct {
-               struct vm_area_struct *mmap;            /* list of VMAs */
                struct maple_tree mm_mt;
 #ifdef CONFIG_MMU
                unsigned long (*get_unmapped_area) (struct file *filp,
@@ -392,7 +387,6 @@ struct mm_struct {
                unsigned long mmap_compat_legacy_base;
 #endif
                unsigned long task_size;        /* size of task vm space */
-               unsigned long highest_vm_end;   /* highest vma end address */
                pgd_t * pgd;
 
 #ifdef CONFIG_MEMBARRIER
index c1cb3d68948e848c29b0fe9224678ab7147f4234..bcfe2cf7c7c0f315c3211d7d5a321a661d0d2d05 100644 (file)
@@ -537,16 +537,14 @@ void acct_collect(long exitcode, int group_dead)
        struct pacct_struct *pacct = &current->signal->pacct;
        u64 utime, stime;
        unsigned long vsize = 0;
+       MA_STATE(mas, &current->mm->mm_mt, 0, 0);
 
        if (group_dead && current->mm) {
                struct vm_area_struct *vma;
 
                mmap_read_lock(current->mm);
-               vma = current->mm->mmap;
-               while (vma) {
+               mas_for_each(&mas, vma, -1)
                        vsize += vma->vm_end - vma->vm_start;
-                       vma = vma_next(vma->vm_mm, vma);
-               }
                mmap_read_unlock(current->mm);
        }
 
index b8c25c2e9587f72bd967c6a64af0c85c08ff0d5f..d3c22604493f9909062b19e785dc86099f04a27a 100644 (file)
@@ -363,7 +363,6 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
                 */
                *new = data_race(*orig);
                INIT_LIST_HEAD(&new->anon_vma_chain);
-               new->vm_next = new->vm_prev = NULL;
        }
        return new;
 }
@@ -468,7 +467,7 @@ EXPORT_SYMBOL(free_task);
 static __latent_entropy int dup_mmap(struct mm_struct *mm,
                                        struct mm_struct *oldmm)
 {
-       struct vm_area_struct *mpnt, *tmp, *prev, **pprev;
+       struct vm_area_struct *mpnt, *tmp;
        int retval;
        unsigned long charge = 0;
        MA_STATE(old_mas, &oldmm->mm_mt, 0, 0);
@@ -495,7 +494,6 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
        mm->exec_vm = oldmm->exec_vm;
        mm->stack_vm = oldmm->stack_vm;
 
-       pprev = &mm->mmap;
        retval = ksm_fork(mm, oldmm);
        if (retval)
                goto out;
@@ -503,8 +501,6 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
        if (retval)
                goto out;
 
-       prev = NULL;
-
        retval = mas_entry_count(&mas, oldmm->map_count);
        if (retval)
                goto fail_nomem;
@@ -579,14 +575,6 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
                if (is_vm_hugetlb_page(tmp))
                        reset_vma_resv_huge_pages(tmp);
 
-               /*
-                * Link in the new vma and copy the page table entries.
-                */
-               *pprev = tmp;
-               pprev = &tmp->vm_next;
-               tmp->vm_prev = prev;
-               prev = tmp;
-
                /* Link the vma into the MT */
                mas.index = tmp->vm_start;
                mas.last = tmp->vm_end - 1;
@@ -1008,7 +996,6 @@ static void mm_init_uprobes_state(struct mm_struct *mm)
 static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
        struct user_namespace *user_ns)
 {
-       mm->mmap = NULL;
        mt_init_flags(&mm->mm_mt, MAPLE_ALLOC_RANGE);
        atomic_set(&mm->mm_users, 1);
        atomic_set(&mm->mm_count, 1);
index d8ed9d73832671f2970fb3e7edbf161add40a854..8dd7a23782480662b37fba51d56f6096b869a034 100644 (file)
@@ -203,8 +203,8 @@ void dump_vma(const struct vm_area_struct *vma)
                "prot %lx anon_vma %px vm_ops %px\n"
                "pgoff %lx file %px private_data %px\n"
                "flags: %#lx(%pGv)\n",
-               vma, (void *)vma->vm_start, (void *)vma->vm_end, vma->vm_next,
-               vma->vm_prev, vma->vm_mm,
+               vma, (void *)vma->vm_start, (void *)vma->vm_end,
+               vma_next(vma->vm_mm, vma), vma_prev(vma->vm_mm, vma), vma->vm_mm,
                (unsigned long)pgprot_val(vma->vm_page_prot),
                vma->anon_vma, vma->vm_ops, vma->vm_pgoff,
                vma->vm_file, vma->vm_private_data,
@@ -214,11 +214,11 @@ EXPORT_SYMBOL(dump_vma);
 
 void dump_mm(const struct mm_struct *mm)
 {
-       pr_emerg("mm %px mmap %px task_size %lu\n"
+       pr_emerg("mm %px task_size %lu\n"
 #ifdef CONFIG_MMU
                "get_unmapped_area %px\n"
 #endif
-               "mmap_base %lu mmap_legacy_base %lu highest_vm_end %lu\n"
+               "mmap_base %lu mmap_legacy_base %lu\n"
                "pgd %px mm_users %d mm_count %d pgtables_bytes %lu map_count %d\n"
                "hiwater_rss %lx hiwater_vm %lx total_vm %lx locked_vm %lx\n"
                "pinned_vm %llx data_vm %lx exec_vm %lx stack_vm %lx\n"
@@ -242,11 +242,11 @@ void dump_mm(const struct mm_struct *mm)
                "tlb_flush_pending %d\n"
                "def_flags: %#lx(%pGv)\n",
 
-               mm, mm->mmap, mm->task_size,
+               mm, mm->task_size,
 #ifdef CONFIG_MMU
                mm->get_unmapped_area,
 #endif
-               mm->mmap_base, mm->mmap_legacy_base, mm->highest_vm_end,
+               mm->mmap_base, mm->mmap_legacy_base,
                mm->pgd, atomic_read(&mm->mm_users),
                atomic_read(&mm->mm_count),
                mm_pgtables_bytes(mm),
index c2627619d622b87156eaf472c1910eff35f11a37..4005beb23daf9e1cad8601eb1314ff86c64a6bf0 100644 (file)
@@ -2309,7 +2309,7 @@ void vma_adjust_trans_huge(struct vm_area_struct *vma,
         * contain an hugepage: check if we need to split an huge pmd.
         */
        if (adjust_next > 0) {
-               struct vm_area_struct *next = vma_next(vma);
+               struct vm_area_struct *next = vma_next(vma->vm_mm, vma);
                unsigned long nstart = next->vm_start;
                nstart += adjust_next;
                if (nstart & ~HPAGE_PMD_MASK &&
index 39fe966785040d664d8af999ad4e7e7cd595e66e..aaf382dbee14e84aa3c4111ae4f9b083c0c42a29 100644 (file)
@@ -37,7 +37,7 @@ void page_writeback_init(void);
 vm_fault_t do_swap_page(struct vm_fault *vmf);
 
 void free_pgtables(struct mmu_gather *tlb, struct ma_state *mas,
-               unsigned long floor, unsigned long ceiling);
+       struct vm_area_struct *vma, unsigned long floor, unsigned long ceiling);
 
 static inline bool can_madv_lru_vma(struct vm_area_struct *vma)
 {
index b20228f10725c248f5c98717b358aa9fdd856548..fbfcee552da6ce960f182df652ef37c6cc83f5fa 100644 (file)
@@ -2049,7 +2049,7 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
        struct mm_struct *mm;
        struct vm_area_struct *vma;
        int progress = 0;
-       MA_STATE(mas, &mm->mm_mt, 0, 0);
+       MA_STATE(mas, NULL, 0, 0);
 
        VM_BUG_ON(!pages);
        lockdep_assert_held(&khugepaged_mm_lock);
@@ -2066,6 +2066,7 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
        khugepaged_collapse_pte_mapped_thps(mm_slot);
 
        mm = mm_slot->mm;
+       mas.tree = &mm->mm_mt;
        /*
         * Don't wait for semaphore (to avoid long wait times).  Just move to
         * the next mm on the list.
index 29459a6ce1c7ad06f00d9cc3873a4126fd1914cb..7fe753d6a81f1c1ea7ead0b899956402e821f3c5 100644 (file)
@@ -5892,7 +5892,7 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm)
        unsigned long precharge;
 
        mmap_read_lock(mm);
-       walk_page_range(mm, 0, mm->highest_vm_end, &precharge_walk_ops, NULL);
+       walk_page_range(mm, 0, -1, &precharge_walk_ops, NULL);
        mmap_read_unlock(mm);
 
        precharge = mc.precharge;
@@ -6190,9 +6190,7 @@ retry:
         * When we have consumed all precharges and failed in doing
         * additional charge, the page walk just aborts.
         */
-       walk_page_range(mc.mm, 0, mc.mm->highest_vm_end, &charge_walk_ops,
-                       NULL);
-
+       walk_page_range(mc.mm, 0, -1, &charge_walk_ops, NULL);
        mmap_read_unlock(mc.mm);
        atomic_dec(&mc.from->moving_account);
 }
index 18246038e73116e774128de723b658a0d9e39f47..2bf7b6291f13b1dfa2b79bd27c19ed2624af82b4 100644 (file)
@@ -388,15 +388,15 @@ void free_pgd_range(struct mmu_gather *tlb,
 }
 
 void free_pgtables(struct mmu_gather *tlb, struct ma_state *mas,
-                     unsigned long floor, unsigned long ceiling)
+       struct vm_area_struct *vma, unsigned long floor, unsigned long ceiling)
 {
+       struct vm_area_struct *next;
        struct ma_state ma_next = *mas;
-       struct vm_area_struct *vma;
 
-       mas_find(&ma_next, ceiling - 1);
-       mas_for_each(mas, vma, ceiling - 1) {
-               struct vm_area_struct *next = mas_find(&ma_next, ceiling - 1);
+       do {
                unsigned long addr = vma->vm_start;
+               next = mas_find(&ma_next, ceiling - 1);
+
 
                /*
                 * Hide vma from rmap and truncate_pagecache before freeing
@@ -422,7 +422,7 @@ void free_pgtables(struct mmu_gather *tlb, struct ma_state *mas,
                        free_pgd_range(tlb, addr, vma->vm_end,
                                floor, next ? next->vm_start : ceiling);
                }
-       }
+       } while ((vma = mas_find(mas, (ceiling - 1))) != NULL);
 }
 
 int __pte_alloc(struct mm_struct *mm, pmd_t *pmd)
@@ -1504,8 +1504,9 @@ void unmap_vmas(struct mmu_gather *tlb,
        mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0, vma, vma->vm_mm,
                                start_addr, end_addr);
        mmu_notifier_invalidate_range_start(&range);
-       mas_for_each(mas, vma, end_addr - 1)
+       do {
                unmap_single_vma(tlb, vma, start_addr, end_addr, NULL);
+       } while ((vma = mas_find(mas, end_addr - 1)) != NULL);
        mmu_notifier_invalidate_range_end(&range);
 }
 
index f16ff55b10c880c3871373ca73cfe4551eefadad..4757b7939920655ed7f07225e8d9de61709ba874 100644 (file)
@@ -1077,6 +1077,7 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
                           int flags)
 {
        nodemask_t nmask;
+       struct vm_area_struct *vma;
        LIST_HEAD(pagelist);
        int err = 0;
        struct migration_target_control mtc = {
@@ -1092,8 +1093,9 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
         * need migration.  Between passing in the full user address
         * space range and MPOL_MF_DISCONTIG_OK, this call can not fail.
         */
+       vma = find_vma(mm, 0);
        VM_BUG_ON(!(flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)));
-       queue_pages_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
+       queue_pages_range(mm, vma->vm_start, mm->task_size, &nmask,
                        flags | MPOL_MF_DISCONTIG_OK, &pagelist);
 
        if (!list_empty(&pagelist)) {
index c5337fbf7139b969b6abff231a084f3294ad8484..4f6350aa982dc447dfc1101aed561322811258c0 100644 (file)
@@ -652,10 +652,6 @@ static unsigned long count_mm_mlocked_page_nr(struct mm_struct *mm,
        if (mm == NULL)
                mm = current->mm;
 
-       vma = mas_find(&mas, ULONG_MAX);
-       if (vma == NULL)
-               vma = mm->mmap;
-
        mas_for_each(&mas, vma, ULONG_MAX) {
                if (start >= vma->vm_end)
                        continue;
@@ -771,6 +767,7 @@ static int apply_mlockall_flags(int flags)
 {
        struct vm_area_struct * vma, * prev = NULL;
        vm_flags_t to_add = 0;
+       MA_STATE(mas, &current->mm->mm_mt, 0, 0);
 
        current->mm->def_flags &= VM_LOCKED_CLEAR_MASK;
        if (flags & MCL_FUTURE) {
@@ -789,7 +786,7 @@ static int apply_mlockall_flags(int flags)
                        to_add |= VM_LOCKONFAULT;
        }
 
-       for (vma = current->mm->mmap; vma ; vma = vma_next(vma->vm_mm, prev)) {
+       mas_for_each(&mas, vma, ULONG_MAX) {
                vm_flags_t newflags;
 
                newflags = vma->vm_flags & VM_LOCKED_CLEAR_MASK;
@@ -797,6 +794,7 @@ static int apply_mlockall_flags(int flags)
 
                /* Ignore errors */
                mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
+               mas_pause(&mas);
                cond_resched();
        }
 out:
index c270aba9c263097df8bd3213391f8efdb47c1f5d..2945140df9b80f3802640e961c2f9e8b07f7dee2 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -177,8 +177,9 @@ static void remove_vma(struct vm_area_struct *vma)
 
 static int do_brk_munmap(struct ma_state *mas, struct vm_area_struct *vma,
                         unsigned long newbrk, unsigned long oldbrk,
-                        struct list_head *uf, unsigned long max);
-static int do_brk_flags(struct ma_state *mas, struct vm_area_struct **brkvma,
+                        struct list_head *uf);
+static int do_brk_flags(struct ma_state *mas, struct ma_state *ma_prev,
+                       struct vm_area_struct **brkvma,
                        unsigned long addr, unsigned long request,
                        unsigned long flags);
 SYSCALL_DEFINE1(brk, unsigned long, brk)
@@ -191,7 +192,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
        bool downgraded = false;
        LIST_HEAD(uf);
        MA_STATE(mas, &mm->mm_mt, 0, 0);
-       struct ma_state ma_next;
+       struct ma_state ma_neighbour;
 
        if (mmap_write_lock_killable(mm))
                return -EINTR;
@@ -233,8 +234,6 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
 
        mas_set(&mas, newbrk);
        brkvma = mas_walk(&mas);
-       ma_next = mas;
-       next = mas_next(&ma_next, -1);
        if (brkvma) { // munmap necessary, there is something at newbrk.
                /*
                 * Always allow shrinking brk.
@@ -250,9 +249,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
                 * before calling do_brk_munmap().
                 */
                mm->brk = brk;
-               mas.last = oldbrk - 1;
-               ret = do_brk_munmap(&mas, brkvma, newbrk, oldbrk, &uf,
-                           next ? next->vm_start : USER_PGTABLES_CEILING);
+               ret = do_brk_munmap(&mas, brkvma, newbrk, oldbrk, &uf);
                if (ret == 1)  {
                        downgraded = true;
                        goto success;
@@ -262,18 +259,21 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
                mm->brk = origbrk;
                goto out;
        }
+       ma_neighbour = mas;
+       next = mas_next(&ma_neighbour, newbrk + PAGE_SIZE + stack_guard_gap);
        /* Only check if the next VMA is within the stack_guard_gap of the
         * expansion area */
        /* Check against existing mmap mappings. */
        if (next && newbrk + PAGE_SIZE > vm_start_gap(next))
                goto out;
 
-       brkvma = mas_prev(&mas, mm->start_brk);
+       brkvma = mas_prev(&ma_neighbour, mm->start_brk);
        if (brkvma && (brkvma->vm_start >= oldbrk))
                goto out; // Trying to map over another vma.
 
        /* Ok, looks good - let it rip. */
-       if (do_brk_flags(&mas, &brkvma, oldbrk, newbrk - oldbrk, 0) < 0)
+       if (do_brk_flags(&mas, &ma_neighbour, &brkvma, oldbrk,
+                        newbrk - oldbrk, 0) < 0)
                goto out;
 
        mm->brk = brk;
@@ -303,7 +303,6 @@ static void validate_mm(struct mm_struct *mm)
 {
        int bug = 0;
        int i = 0;
-       unsigned long highest_address = 0;
        struct vm_area_struct *vma;
        MA_STATE(mas, &mm->mm_mt, 0, 0);
 
@@ -319,18 +318,12 @@ static void validate_mm(struct mm_struct *mm)
                        anon_vma_unlock_read(anon_vma);
                }
 #endif
-               highest_address = vm_end_gap(vma);
                i++;
        }
        if (i != mm->map_count) {
                pr_emerg("map_count %d mas_for_each %d\n", mm->map_count, i);
                bug = 1;
        }
-       if (highest_address != mm->highest_vm_end) {
-               pr_emerg("mm->highest_vm_end %lx, found %lx\n",
-                         mm->highest_vm_end, highest_address);
-               bug = 1;
-       }
        VM_BUG_ON_MM(bug, mm);
 }
 #else // !CONFIG_DEBUG_MAPLE_TREE
@@ -380,7 +373,7 @@ anon_vma_interval_tree_post_update_vma(struct vm_area_struct *vma)
  *
  * Returns: True if there is an overlapping VMA, false otherwise
  */
-static bool range_has_overlap(struct mm_struct *mm, unsigned long start,
+static inline bool range_has_overlap(struct mm_struct *mm, unsigned long start,
                              unsigned long end, struct vm_area_struct **pprev)
 {
        struct vm_area_struct *existing;
@@ -495,7 +488,7 @@ void vma_store(struct mm_struct *mm, struct vm_area_struct *vma)
 }
 
 static void vma_mas_link(struct mm_struct *mm, struct vm_area_struct *vma,
-                        struct ma_state *mas, struct vm_area_struct *prev)
+                        struct ma_state *mas)
 {
        struct address_space *mapping = NULL;
 
@@ -505,7 +498,6 @@ static void vma_mas_link(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        vma_mas_store(vma, mas);
-       __vma_link_list(mm, vma, prev);
        __vma_link_file(vma);
 
        if (mapping)
@@ -514,8 +506,7 @@ static void vma_mas_link(struct mm_struct *mm, struct vm_area_struct *vma,
        mm->map_count++;
        validate_mm(mm);
 }
-static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
-                       struct vm_area_struct *prev)
+static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma)
 {
        struct address_space *mapping = NULL;
 
@@ -525,7 +516,6 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        vma_mt_store(mm, vma);
-       __vma_link_list(mm, vma, prev);
        __vma_link_file(vma);
 
        if (mapping)
@@ -539,14 +529,12 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
  * Helper for vma_adjust() in the split_vma insert case: insert a vma into the
  * mm's list and the mm tree.  It has already been inserted into the interval tree.
  */
-static void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
+static inline void __insert_vm_struct(struct mm_struct *mm,
+                                     struct vm_area_struct *vma)
 {
-       struct vm_area_struct *prev;
-
-       if (range_has_overlap(mm, vma->vm_start, vma->vm_end, &prev))
+       if (find_vma_intersection(mm, vma->vm_start, vma->vm_end))
                BUG();
        vma_mt_store(mm, vma);
-       __vma_link_list(mm, vma, prev);
        mm->map_count++;
 }
 
@@ -605,13 +593,8 @@ inline int vma_expand(struct ma_state *mas, struct vm_area_struct *vma,
        /* Expanding over the next vma */
        if (remove_next) {
                /* Remove from mm linked list - also updates highest_vm_end */
-               __vma_unlink_list(mm, next);
-
                if (file)
                        __remove_shared_vm_struct(next, file, mapping);
-
-       } else if (!next) {
-               mm->highest_vm_end = vm_end_gap(vma);
        }
 
        if (anon_vma) {
@@ -797,8 +780,6 @@ again:
                else
                        vma_changed = true;
                vma->vm_end = end;
-               if (!next)
-                       mm->highest_vm_end = vm_end_gap(vma);
        }
 
        if (vma_changed)
@@ -819,7 +800,6 @@ again:
        }
 
        if (remove_next) {
-               __vma_unlink_list(mm, next);
                if (file)
                        __remove_shared_vm_struct(next, file, mapping);
        } else if (insert) {
@@ -886,27 +866,6 @@ again:
                        remove_next = 1;
                        end = next->vm_end;
                        goto again;
-               } else if (!next) {
-                       /*
-                        * If remove_next == 2 we obviously can't
-                        * reach this path.
-                        *
-                        * If remove_next == 3 we can't reach this
-                        * path because pre-swap() next is always not
-                        * NULL. pre-swap() "next" is not being
-                        * removed and its next->vm_end is not altered
-                        * (and furthermore "end" already matches
-                        * next->vm_end in remove_next == 3).
-                        *
-                        * We reach this only in the remove_next == 1
-                        * case if the "next" vma that was removed was
-                        * the highest vma of the mm. However in such
-                        * case next->vm_end == "end" and the extended
-                        * "vma" has vma->vm_end == next->vm_end so
-                        * mm->highest_vm_end doesn't need any update
-                        * in remove_next == 1 case.
-                        */
-                       VM_WARN_ON(mm->highest_vm_end != vm_end_gap(vma));
                }
        }
        if (insert && file)
@@ -1005,24 +964,6 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
        return 0;
 }
 
-/*
- * vma_next_wrap() - Get the next VMA of the first.
- * @mm: The mm_struct.
- * @vma: The current vma.
- *
- * If @vma is NULL, return the first vma in the mm.
- *
- * Returns: The next VMA after @vma.
- */
-static inline struct vm_area_struct *vma_next_wrap(struct mm_struct *mm,
-                                        struct vm_area_struct *vma)
-{
-       if (!vma)
-               return mm->mmap;
-
-       return vma_next(mm, vma);
-}
-
 /*
  * Given a mapping request (addr,end,vm_flags,file,pgoff), figure out
  * whether that can be merged with its predecessor or its successor.
@@ -1084,7 +1025,11 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
        if (vm_flags & VM_SPECIAL)
                return NULL;
 
-       next = vma_next_wrap(mm, prev);
+       if (!prev)
+               next = find_vma(mm, 0);
+       else
+               next = vma_next(mm, prev);
+
        area = next;
        if (area && area->vm_end == end)                /* cases 6, 7, 8 */
                next = vma_next(mm, next);
@@ -2052,8 +1997,6 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
                                vma->vm_end = address;
                                vma_mt_store(mm, vma);
                                anon_vma_interval_tree_post_update_vma(vma);
-                               if (!vma_next(mm, vma))
-                                       mm->highest_vm_end = vm_end_gap(vma);
                                spin_unlock(&mm->page_table_lock);
 
                                perf_event_mmap(vma);
@@ -2082,7 +2025,7 @@ int expand_downwards(struct vm_area_struct *vma,
                return -EPERM;
 
        /* Enforce stack_guard_gap */
-       prev = vma->vm_prev;
+       prev = vma_prev(mm, vma);
        /* Check that both stack segments have the same anon_vma? */
        if (prev && !(prev->vm_flags & VM_GROWSDOWN) &&
                        vma_is_accessible(prev)) {
@@ -2254,7 +2197,7 @@ static void unmap_region(struct mm_struct *mm,
        tlb_gather_mmu(&tlb, mm, start, end);
        update_hiwater_rss(mm);
        unmap_vmas(&tlb, vma, mas, start, end);
-       free_pgtables(&tlb, &ma_pgtb,
+       free_pgtables(&tlb, &ma_pgtb, vma,
                      prev ? prev->vm_end : FIRST_USER_ADDRESS,
                      max);
        tlb_finish_mmu(&tlb, start, end);
@@ -2368,10 +2311,8 @@ static inline unsigned long detach_range(struct mm_struct *mm,
        /* Drop removed area from the tree */
        mas_store_gfp(src, NULL, GFP_KERNEL);
        /* Set the upper limit */
-       if (!tmp) {
-               mm->highest_vm_end = prev ? vm_end_gap(prev) : 0;
+       if (!tmp)
                return USER_PGTABLES_CEILING;
-       }
 
        return tmp->vm_start;
 }
@@ -2423,7 +2364,7 @@ int do_mas_align_munmap(struct ma_state *mas, struct vm_area_struct *vma,
                mas->index = start;
                mas_reset(mas);
        } else {
-               prev = vma->vm_prev;
+               prev = vma_prev(mm, vma);
        }
 
        if (vma->vm_end >= end)
@@ -2460,19 +2401,6 @@ int do_mas_align_munmap(struct ma_state *mas, struct vm_area_struct *vma,
        /* Point of no return */
        max = detach_range(mm, mas, &dst, prev, &last);
 
-#if 1
-       /* Detach vmas from the MM linked list */
-       vma->vm_prev = NULL;
-       if (prev)
-               prev->vm_next = last->vm_next;
-       else
-               mm->mmap = last->vm_next;
-
-       if (last->vm_next) {
-               last->vm_next->vm_prev = prev;
-               last->vm_next = NULL;
-       }
-#endif
        /*
         * Do not downgrade mmap_lock if we are next to VM_GROWSDOWN or
         * VM_GROWSUP VMA. Such VMAs can change their size under
@@ -2489,6 +2417,7 @@ int do_mas_align_munmap(struct ma_state *mas, struct vm_area_struct *vma,
 
        mas_reset(&dst);
        mas_set(&dst, start);
+       vma = mas_walk(&dst);
        unmap_region(mm, vma, &dst, start, end, prev, max);
 
        /* Fix up all other VM information */
@@ -2565,6 +2494,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
        unsigned long max = USER_PGTABLES_CEILING;
        pgoff_t vm_pgoff;
        int error;
+       struct ma_state ma_prev;
        MA_STATE(mas, &mm->mm_mt, addr, end - 1);
 
        /* Check against address space limit. */
@@ -2597,15 +2527,16 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
        }
 
 
+       ma_prev = mas;
        if (vm_flags & VM_SPECIAL) {
-               prev = mas_prev(&mas, 0);
+               prev = mas_prev(&ma_prev, 0);
                goto cannot_expand;
        }
 
        /* Attempt to expand an old mapping */
 
        /* Check next */
-       next = mas_next(&mas, ULONG_MAX);
+       next = mas_next(&ma_prev, ULONG_MAX);
        if (next) {
                max = next->vm_start;
 
@@ -2619,7 +2550,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
        }
 
        /* Check prev */
-       prev = mas_prev(&mas, 0);
+       prev = mas_prev(&ma_prev, 0);
        if (prev && prev->vm_end == addr && !vma_policy(prev) &&
            can_vma_merge_after(prev, vm_flags, NULL, file, pgoff,
                                NULL_VM_UFFD_CTX)) {
@@ -2630,7 +2561,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
 
        /* Actually expand, if possible */
        if (vma &&
-           !vma_expand(&mas, vma, merge_start, merge_end, vm_pgoff, next)) {
+           !vma_expand(&ma_prev, vma, merge_start, merge_end, vm_pgoff, next)) {
                khugepaged_enter_vma_merge(prev, vm_flags);
                goto expanded;
        }
@@ -2684,7 +2615,7 @@ cannot_expand:
                                                 pgoff, NULL_VM_UFFD_CTX))) {
                        merge_start = prev->vm_start;
                        vm_pgoff = prev->vm_pgoff;
-                       if (!vma_expand(&mas, prev, merge_start, merge_end,
+                       if (!vma_expand(&ma_prev, prev, merge_start, merge_end,
                                        vm_pgoff, next)) {
                                /* ->mmap() can change vma->vm_file and fput the original file. So
                                 * fput the vma->vm_file here or we would add an extra fput for file
@@ -2730,15 +2661,7 @@ cannot_expand:
                        goto free_vma;
        }
 
-       /*
-        * mas was called for the prev vma, and that may not be the correct
-        * location for the vma being inserted, but is is before that location
-        * and so the call to vma_mas_link()->vma_mas_store()->mas_store_gfp()
-        * will detect the write as a spanning store and reset mas if necessary.
-        */
-       mas.index = mas.last = addr;
-       mas_walk(&mas);
-       vma_mas_link(mm, vma, &mas, prev);
+       vma_mas_link(mm, vma, &mas);
        /* Once vma denies write, undo our temporary denial count */
        if (file) {
 unmap_writable:
@@ -2782,7 +2705,7 @@ unmap_and_free_vma:
        fput(file);
 
        mas.index = mas.last = addr;
-       mas_walk(&mas);
+       vma = mas_walk(&mas);
        /* Undo any partial mapping done by a device driver. */
        unmap_region(mm, vma, &mas, vma->vm_start, vma->vm_end, prev, max);
        charged = 0;
@@ -2939,12 +2862,13 @@ out:
  */
 static int do_brk_munmap(struct ma_state *mas, struct vm_area_struct *vma,
                         unsigned long newbrk, unsigned long oldbrk,
-                        struct list_head *uf, unsigned long max)
+                        struct list_head *uf)
 {
        struct mm_struct *mm = vma->vm_mm;
-       struct vm_area_struct unmap;
+       struct vm_area_struct unmap, *next;
        unsigned long unmap_pages;
        int ret;
+       struct ma_state ma_next;
 
        arch_unmap(mm, newbrk, oldbrk);
 
@@ -2956,6 +2880,7 @@ static int do_brk_munmap(struct ma_state *mas, struct vm_area_struct *vma,
        vma_init(&unmap, mm);
        unmap.vm_start = newbrk;
        unmap.vm_end = oldbrk;
+       unmap.vm_pgoff = newbrk >> PAGE_SHIFT;
        ret = userfaultfd_unmap_prep(&unmap, newbrk, oldbrk, uf);
        if (ret)
                return ret;
@@ -2984,7 +2909,10 @@ static int do_brk_munmap(struct ma_state *mas, struct vm_area_struct *vma,
        }
 
        mmap_write_downgrade(mm);
-       unmap_region(mm, &unmap, mas, newbrk, oldbrk, vma, max);
+       ma_next = *mas;
+       next = mas_next(&ma_next, -1);
+       unmap_region(mm, &unmap, mas, newbrk, oldbrk, vma,
+                    next ? next->vm_start : 0);
        /* Statistics */
        vm_stat_account(mm, unmap.vm_flags, -unmap_pages);
        if (unmap.vm_flags & VM_ACCOUNT)
@@ -3012,12 +2940,13 @@ mas_store_fail:
  * do not match then create a new anonymous VMA.  Eventually we may be able to
  * do some brk-specific accounting here.
  */
-static int do_brk_flags(struct ma_state *mas, struct vm_area_struct **brkvma,
+static int do_brk_flags(struct ma_state *mas, struct ma_state *ma_prev,
+                       struct vm_area_struct **brkvma,
                        unsigned long addr, unsigned long len,
                        unsigned long flags)
 {
        struct mm_struct *mm = current->mm;
-       struct vm_area_struct *prev = NULL, *vma;
+       struct vm_area_struct *vma;
        int error;
        unsigned long mapped_addr;
 
@@ -3044,7 +2973,6 @@ static int do_brk_flags(struct ma_state *mas, struct vm_area_struct **brkvma,
        if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT))
                return -ENOMEM;
 
-       mas->last = addr + len - 1;
        if (*brkvma) {
                vma = *brkvma;
                /* Expand the existing vma if possible; almost never a singular
@@ -3053,7 +2981,8 @@ static int do_brk_flags(struct ma_state *mas, struct vm_area_struct **brkvma,
                if ((!vma->anon_vma ||
                     list_is_singular(&vma->anon_vma_chain)) &&
                     ((vma->vm_flags & ~VM_SOFTDIRTY) == flags)){
-                       mas->index = vma->vm_start;
+                       ma_prev->index = vma->vm_start;
+                       ma_prev->last = addr + len - 1;
 
                        vma_adjust_trans_huge(vma, addr, addr + len, 0);
                        if (vma->anon_vma) {
@@ -3062,7 +2991,7 @@ static int do_brk_flags(struct ma_state *mas, struct vm_area_struct **brkvma,
                        }
                        vma->vm_end = addr + len;
                        vma->vm_flags |= VM_SOFTDIRTY;
-                       if (mas_store_gfp(mas, vma, GFP_KERNEL))
+                       if (mas_store_gfp(ma_prev, vma, GFP_KERNEL))
                                goto mas_mod_fail;
                        if (vma->anon_vma) {
                                anon_vma_interval_tree_post_update_vma(vma);
@@ -3071,11 +3000,9 @@ static int do_brk_flags(struct ma_state *mas, struct vm_area_struct **brkvma,
                        khugepaged_enter_vma_merge(vma, flags);
                        goto out;
                }
-               prev = vma;
        }
-       mas->index = addr;
-       mas_walk(mas);
 
+       mas->last = addr + len - 1;
        /* create a vma struct for an anonymous mapping */
        vma = vm_area_alloc(mm);
        if (!vma)
@@ -3090,10 +3017,6 @@ static int do_brk_flags(struct ma_state *mas, struct vm_area_struct **brkvma,
        if (vma_mas_store(vma, mas))
                goto mas_store_fail;
 
-       if (!prev)
-               prev = mas_prev(mas, 0);
-
-       __vma_link_list(mm, vma, prev);
        mm->map_count++;
        *brkvma = vma;
 out:
@@ -3139,7 +3062,7 @@ int vm_brk_flags(unsigned long addr, unsigned long request, unsigned long flags)
 
        // This vma left intentionally blank.
        mas_walk(&mas);
-       ret = do_brk_flags(&mas, &vma, addr, len, flags);
+       ret = do_brk_flags(&mas, &mas, &vma, addr, len, flags);
        mmap_write_unlock(mm);
        populate = ((mm->def_flags & VM_LOCKED) != 0);
        if (populate && !ret)
@@ -3160,6 +3083,7 @@ void exit_mmap(struct mm_struct *mm)
        struct mmu_gather tlb;
        struct vm_area_struct *vma;
        unsigned long nr_accounted = 0;
+       struct ma_state mas2;
        MA_STATE(mas, &mm->mm_mt, FIRST_USER_ADDRESS, FIRST_USER_ADDRESS);
 
        /* mm's last user has gone, and its about to be pulled down */
@@ -3202,19 +3126,21 @@ void exit_mmap(struct mm_struct *mm)
 
        arch_exit_mmap(mm);
 
-       vma = mm->mmap;
+       vma = mas_find(&mas, -1);
        if (!vma)       /* Can happen if dup_mmap() received an OOM */
                return;
 
+       mas2 = mas;
+       mas_reset(&mas);
+       mas_set(&mas, FIRST_USER_ADDRESS);
+
        lru_add_drain();
        flush_cache_mm(mm);
        tlb_gather_mmu(&tlb, mm, 0, -1);
        /* update_hiwater_rss(mm) here? but nobody should be looking */
        /* Use 0 here to ensure all VMAs in the mm are unmapped */
        unmap_vmas(&tlb, vma, &mas, 0, -1);
-       mas_reset(&mas);
-       mas_set(&mas, FIRST_USER_ADDRESS);
-       free_pgtables(&tlb, &mas, FIRST_USER_ADDRESS, USER_PGTABLES_CEILING);
+       free_pgtables(&tlb, &mas2, vma, FIRST_USER_ADDRESS, USER_PGTABLES_CEILING);
        tlb_finish_mmu(&tlb, 0, -1);
 
        /*
@@ -3241,9 +3167,7 @@ void exit_mmap(struct mm_struct *mm)
  */
 int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
 {
-       struct vm_area_struct *prev;
-
-       if (range_has_overlap(mm, vma->vm_start, vma->vm_end, &prev))
+       if (find_vma_intersection(mm, vma->vm_start, vma->vm_end))
                return -ENOMEM;
 
        if ((vma->vm_flags & VM_ACCOUNT) &&
@@ -3267,7 +3191,7 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
                vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT;
        }
 
-       vma_link(mm, vma, prev);
+       vma_link(mm, vma);
        return 0;
 }
 
@@ -3337,7 +3261,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
                        get_file(new_vma->vm_file);
                if (new_vma->vm_ops && new_vma->vm_ops->open)
                        new_vma->vm_ops->open(new_vma);
-               vma_link(mm, new_vma, prev);
+               vma_link(mm, new_vma);
                *need_rmap_locks = false;
        }
        return new_vma;
index 48c79f2784eca92f4a74dbec41728b02f2d9e285..74888472a0848bb2fe56f2be095415759e74b822 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -271,46 +271,6 @@ void *memdup_user_nul(const void __user *src, size_t len)
 }
 EXPORT_SYMBOL(memdup_user_nul);
 
-void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
-               struct vm_area_struct *prev)
-{
-       struct vm_area_struct *next;
-
-       vma->vm_prev = prev;
-       if (prev) {
-               next = prev->vm_next;
-               prev->vm_next = vma;
-       } else {
-               next = mm->mmap;
-               mm->mmap = vma;
-       }
-       vma->vm_next = next;
-       if (next)
-               next->vm_prev = vma;
-       else
-               mm->highest_vm_end = vm_end_gap(vma);
-}
-
-void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma)
-{
-       struct vm_area_struct *prev, *next;
-
-       next = vma->vm_next;
-       prev = vma->vm_prev;
-       if (prev)
-               prev->vm_next = next;
-       else
-               mm->mmap = next;
-       if (next)
-               next->vm_prev = prev;
-       else {
-               if (prev)
-                       mm->highest_vm_end = vm_end_gap(prev);
-               else
-                       mm->highest_vm_end = 0;
-       }
-}
-
 /* Check if the vma is being used as a stack by this task */
 int vma_is_stack_for_current(struct vm_area_struct *vma)
 {