kernel/fork: Stop using dup tree and pre-allocate the nodes needed.
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Mon, 28 Sep 2020 19:46:55 +0000 (15:46 -0400)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 30 Oct 2020 19:12:30 +0000 (15:12 -0400)
Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
kernel/fork.c

index d90228f23df8d320475beb8e5e33d3a222a6c55e..09b77bb73bc165bc853769f05d6fe23c3e741e4a 100644 (file)
@@ -471,7 +471,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
 {
        struct vm_area_struct *mpnt, *tmp, *prev, **pprev;
        int retval;
-       unsigned long charge;
+       unsigned long charge = 0;
        MA_STATE(old_mas, &oldmm->mm_mt, 0, 0);
        MA_STATE(mas, &mm->mm_mt, 0, 0);
        LIST_HEAD(uf);
@@ -506,17 +506,14 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
 
        prev = NULL;
 
-       rcu_read_lock();
-       mas_dup_tree(&old_mas, &mas);
-       mas_reset(&old_mas);
-       mas_reset(&mas);
+       retval = mas_entry_cnt(&mas, oldmm->map_count * 2);
+       if (retval)
+               goto fail_nomem;
 
+       mas_lock(&old_mas);
        mas_for_each(&old_mas, mpnt, ULONG_MAX) {
                struct file *file;
 
-               if (xa_is_zero(mpnt))
-                       continue;
-
                if (mpnt->vm_flags & VM_DONTCOPY) {
                        vm_stat_account(mm, mpnt->vm_flags, -vma_pages(mpnt));
                        continue;
@@ -528,7 +525,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
                 */
                if (fatal_signal_pending(current)) {
                        retval = -EINTR;
-                       goto out;
+                       goto loop_out;
                }
                if (mpnt->vm_flags & VM_ACCOUNT) {
                        unsigned long len = vma_pages(mpnt);
@@ -593,7 +590,9 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
                prev = tmp;
 
                /* Link the vma into the MT */
-               mas_dup_store(&mas, tmp);
+               mas.index = tmp->vm_start;
+               mas.last = tmp->vm_end - 1;
+               mas_store(&mas, tmp);
 
                mm->map_count++;
                if (!(tmp->vm_flags & VM_WIPEONFORK))
@@ -603,12 +602,13 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
                        tmp->vm_ops->open(tmp);
 
                if (retval)
-                       goto out;
+                       goto loop_out;
        }
        /* a new mm has just been created */
        retval = arch_dup_mmap(oldmm, mm);
+loop_out:
+       mas_unlock(&old_mas);
 out:
-       rcu_read_unlock();
        mmap_write_unlock(mm);
        flush_tlb_mm(oldmm);
        mmap_write_unlock(oldmm);