All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Liam R. Howlett" <Liam.Howlett@Oracle.com>
To: maple-tree@lists.infradead.org, linux-mm@kvack.org,
	linux-kernel@vger.kernel.org
Cc: Andrew Morton <akpm@google.com>, Song Liu <songliubraving@fb.com>,
	Davidlohr Bueso <dave@stgolabs.net>,
	"Paul E . McKenney" <paulmck@kernel.org>,
	Matthew Wilcox <willy@infradead.org>,
	Jerome Glisse <jglisse@redhat.com>,
	David Rientjes <rientjes@google.com>,
	Axel Rasmussen <axelrasmussen@google.com>,
	Suren Baghdasaryan <surenb@google.com>,
	Vlastimil Babka <vbabka@suse.cz>, Rik van Riel <riel@surriel.com>,
	Peter Zijlstra <peterz@infradead.org>
Subject: [PATCH v2 10/70] mm/mmap: Change unmapped_area and unmapped_area_topdown to use maple tree
Date: Tue, 12 Jan 2021 11:11:40 -0500	[thread overview]
Message-ID: <20210112161240.2024684-11-Liam.Howlett@Oracle.com> (raw)
In-Reply-To: <20210112161240.2024684-1-Liam.Howlett@Oracle.com>

Use the new maple tree data structure to find an unmapped area.

Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
---
 mm/mmap.c | 249 ++++++------------------------------------------------
 1 file changed, 27 insertions(+), 222 deletions(-)

diff --git a/mm/mmap.c b/mm/mmap.c
index f123f9c97dfe8..3b3084ee309b7 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2040,260 +2040,65 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
 	return error;
 }
 
+/* unmapped_area() Find an area between the low_limit and the high_limit with
+ * the correct alignment and offset, all from @info. Note: current->mm is used
+ * for the search.
+ *
+ * @info: The unmapped area information including the range (low_limit -
+ * hight_limit), the alignment offset and mask.
+ *
+ * Return: A memory address or -ENOMEM.
+ */
 static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
 {
-	/*
-	 * We implement the search by looking for an rbtree node that
-	 * immediately follows a suitable gap. That is,
-	 * - gap_start = vma->vm_prev->vm_end <= info->high_limit - length;
-	 * - gap_end   = vma->vm_start        >= info->low_limit  + length;
-	 * - gap_end - gap_start >= length
-	 */
+	unsigned long length, gap;
 
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
-	unsigned long length, low_limit, high_limit, gap_start, gap_end;
-	unsigned long gap;
+	MA_STATE(mas, &current->mm->mm_mt, 0, 0);
+	validate_mm(current->mm);
 
-	MA_STATE(mas, &mm->mm_mt, 0, 0);
 	/* Adjust search length to account for worst case alignment overhead */
 	length = info->length + info->align_mask;
 	if (length < info->length)
 		return -ENOMEM;
 
-
-	/* Maple tree is self contained. */
-	rcu_read_lock();
 	if (mas_get_empty_area(&mas, info->low_limit, info->high_limit - 1,
 				  length)) {
 		rcu_read_unlock();
 		return -ENOMEM;
 	}
-	rcu_read_unlock();
 	gap = mas.index;
 	gap += (info->align_offset - gap) & info->align_mask;
-
-	/* Adjust search limits by the desired length */
-	if (info->high_limit < length)
-		return -ENOMEM;
-	high_limit = info->high_limit - length;
-
-	if (info->low_limit > high_limit)
-		return -ENOMEM;
-	low_limit = info->low_limit + length;
-
-	/* Check if rbtree root looks promising */
-	if (RB_EMPTY_ROOT(&mm->mm_rb))
-		goto check_highest;
-	vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb);
-	if (vma->rb_subtree_gap < length)
-		goto check_highest;
-
-	while (true) {
-		/* Visit left subtree if it looks promising */
-		gap_end = vm_start_gap(vma);
-		if (gap_end >= low_limit && vma->vm_rb.rb_left) {
-			struct vm_area_struct *left =
-				rb_entry(vma->vm_rb.rb_left,
-					 struct vm_area_struct, vm_rb);
-			if (left->rb_subtree_gap >= length) {
-				vma = left;
-				continue;
-			}
-		}
-
-		gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
-check_current:
-		/* Check if current node has a suitable gap */
-		if (gap_start > high_limit)
-			return -ENOMEM;
-		if (gap_end >= low_limit &&
-		    gap_end > gap_start && gap_end - gap_start >= length)
-			goto found;
-
-		/* Visit right subtree if it looks promising */
-		if (vma->vm_rb.rb_right) {
-			struct vm_area_struct *right =
-				rb_entry(vma->vm_rb.rb_right,
-					 struct vm_area_struct, vm_rb);
-			if (right->rb_subtree_gap >= length) {
-				vma = right;
-				continue;
-			}
-		}
-
-		/* Go back up the rbtree to find next candidate node */
-		while (true) {
-			struct rb_node *prev = &vma->vm_rb;
-			if (!rb_parent(prev))
-				goto check_highest;
-			vma = rb_entry(rb_parent(prev),
-				       struct vm_area_struct, vm_rb);
-			if (prev == vma->vm_rb.rb_left) {
-				gap_start = vm_end_gap(vma->vm_prev);
-				gap_end = vm_start_gap(vma);
-				goto check_current;
-			}
-		}
-	}
-
-check_highest:
-	/* Check highest gap, which does not precede any rbtree node */
-	gap_start = mm->highest_vm_end;
-	gap_end = ULONG_MAX;  /* Only for VM_BUG_ON below */
-	if (gap_start > high_limit)
-		return -ENOMEM;
-
-found:
-	/* We found a suitable gap. Clip it with the original low_limit. */
-	if (gap_start < info->low_limit)
-		gap_start = info->low_limit;
-
-	/* Adjust gap address to the desired alignment */
-	gap_start += (info->align_offset - gap_start) & info->align_mask;
-
-	VM_BUG_ON(gap_start + info->length > info->high_limit);
-	VM_BUG_ON(gap_start + info->length > gap_end);
-
-	VM_BUG_ON(gap != gap_start);
-	return gap_start;
+	return gap;
 }
 
+/* unmapped_area() Find an area between the low_limit and the high_limit with
+ * the correct alignment and offset at the highest available address, all from
+ * @info. Note: current->mm is used for the search.
+ *
+ * @info: The unmapped area information including the range (low_limit -
+ * hight_limit), the alignment offset and mask.
+ *
+ * Return: A memory address or -ENOMEM.
+ */
 static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
 {
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma = NULL;
-	unsigned long length, low_limit, high_limit, gap_start, gap_end;
-	unsigned long gap;
+	unsigned long length, gap;
 
-	MA_STATE(mas, &mm->mm_mt, 0, 0);
-	validate_mm_mt(mm);
+	MA_STATE(mas, &current->mm->mm_mt, 0, 0);
+	validate_mm_mt(current->mm);
 	/* Adjust search length to account for worst case alignment overhead */
 	length = info->length + info->align_mask;
 	if (length < info->length)
 		return -ENOMEM;
 
-	rcu_read_lock();
-	if (mas_get_empty_area_rev(&mas, info->low_limit, info->high_limit,
+	if (mas_get_empty_area_rev(&mas, info->low_limit, info->high_limit - 1,
 				length)) {
 		rcu_read_unlock();
 		return -ENOMEM;
 	}
-	rcu_read_unlock();
 	gap = (mas.index + info->align_mask) & ~info->align_mask;
 	gap -= info->align_offset & info->align_mask;
-	/*
-	 * Adjust search limits by the desired length.
-	 * See implementation comment at top of unmapped_area().
-	 */
-	gap_end = info->high_limit;
-	if (gap_end < length)
-		return -ENOMEM;
-	high_limit = gap_end - length;
-
-	if (info->low_limit > high_limit)
-		return -ENOMEM;
-	low_limit = info->low_limit + length;
-
-	/* Check highest gap, which does not precede any rbtree node */
-	gap_start = mm->highest_vm_end;
-	if (gap_start <= high_limit)
-		goto found_highest;
-
-	/* Check if rbtree root looks promising */
-	if (RB_EMPTY_ROOT(&mm->mm_rb))
-		return -ENOMEM;
-	vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb);
-	if (vma->rb_subtree_gap < length)
-		return -ENOMEM;
-
-	while (true) {
-		/* Visit right subtree if it looks promising */
-		gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
-		if (gap_start <= high_limit && vma->vm_rb.rb_right) {
-			struct vm_area_struct *right =
-				rb_entry(vma->vm_rb.rb_right,
-					 struct vm_area_struct, vm_rb);
-			if (right->rb_subtree_gap >= length) {
-				vma = right;
-				continue;
-			}
-		}
-
-check_current:
-		/* Check if current node has a suitable gap */
-		gap_end = vm_start_gap(vma);
-		if (gap_end < low_limit)
-			return -ENOMEM;
-		if (gap_start <= high_limit &&
-		    gap_end > gap_start && gap_end - gap_start >= length)
-			goto found;
-
-		/* Visit left subtree if it looks promising */
-		if (vma->vm_rb.rb_left) {
-			struct vm_area_struct *left =
-				rb_entry(vma->vm_rb.rb_left,
-					 struct vm_area_struct, vm_rb);
-			if (left->rb_subtree_gap >= length) {
-				vma = left;
-				continue;
-			}
-		}
-
-		/* Go back up the rbtree to find next candidate node */
-		while (true) {
-			struct rb_node *prev = &vma->vm_rb;
-			if (!rb_parent(prev))
-				return -ENOMEM;
-			vma = rb_entry(rb_parent(prev),
-				       struct vm_area_struct, vm_rb);
-			if (prev == vma->vm_rb.rb_right) {
-				gap_start = vma->vm_prev ?
-					vm_end_gap(vma->vm_prev) : 0;
-				goto check_current;
-			}
-		}
-	}
-
-found:
-	/* We found a suitable gap. Clip it with the original high_limit. */
-	if (gap_end > info->high_limit)
-		gap_end = info->high_limit;
-
-found_highest:
-	/* Compute highest gap address at the desired alignment */
-	gap_end -= info->length;
-	gap_end -= (gap_end - info->align_offset) & info->align_mask;
-
-	VM_BUG_ON(gap_end < info->low_limit);
-	VM_BUG_ON(gap_end < gap_start);
-
-	if (gap != gap_end) {
-		pr_err("%s: %px Gap was found: mt %lu gap_end %lu\n", __func__,
-				mm, gap, gap_end);
-		pr_err("window was %lu - %lu size %lu\n", info->high_limit,
-				info->low_limit, length);
-		pr_err("mas.min %lu max %lu mas.last %lu\n", mas.min, mas.max,
-				mas.last);
-		pr_err("mas.index %lu align mask %lu offset %lu\n", mas.index,
-				info->align_mask, info->align_offset);
-		pr_err("rb_find_vma find on %lu => %px (%px)\n", mas.index,
-				find_vma(mm, mas.index), vma);
-#if defined(CONFIG_DEBUG_MAPLE_TREE)
-		mt_dump(&mm->mm_mt);
-#endif
-		{
-			struct vm_area_struct *dv = mm->mmap;
-
-			while (dv) {
-				printk("vma %px %lu-%lu\n", dv, dv->vm_start, dv->vm_end);
-				dv = dv->vm_next;
-			}
-		}
-		VM_BUG_ON(gap != gap_end);
-	}
-
-	return gap_end;
+	return gap;
 }
 
 /*
-- 
2.28.0


  parent reply	other threads:[~2021-01-12 16:14 UTC|newest]

Thread overview: 76+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-12 16:11 [PATCH v2 00/70] RFC mm: Introducing the Maple Tree Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 01/70] radix tree test suite: Enhancements for " Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 02/70] radix tree test suite: Add support for fallthrough attribute Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 03/70] radix tree test suite: Add support for kmem_cache_free_bulk Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 04/70] radix tree test suite: Add keme_cache_alloc_bulk() support Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 05/70] Maple Tree: Add new data structure Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 06/70] mm: Start tracking VMAs with maple tree Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 07/70] mm/mmap: Introduce unlock_range() for code cleanup Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 08/70] mm/mmap: Change find_vma() to use the maple tree Liam R. Howlett
2021-01-12 21:01   ` Randy Dunlap
2021-01-12 16:11 ` [PATCH v2 09/70] mm/mmap: Change find_vma_prev() to use " Liam R. Howlett
2021-01-12 21:03   ` Randy Dunlap
2021-01-12 16:11 ` Liam R. Howlett [this message]
2021-01-12 21:05   ` [PATCH v2 10/70] mm/mmap: Change unmapped_area and unmapped_area_topdown " Randy Dunlap
2021-01-12 16:11 ` [PATCH v2 11/70] kernel/fork: Convert dup_mmap " Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 12/70] mm: Remove rb tree Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 13/70] mm/gup: Add mm_populate_vma() for use when the vma is known Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 14/70] mm/mmap: Change do_brk_flags() to expand existing VMA and add do_brk_munmap() Liam R. Howlett
2021-01-12 21:15   ` Randy Dunlap
2021-01-13 14:20     ` Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 15/70] mm/mmap: Change vm_brk_flags() to use mm_populate_vma() Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 16/70] mm: Move find_vma_intersection to mmap.c and change implementation to maple tree Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 17/70] mm/mmap: Change mmap_region to use maple tree state Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 18/70] mm/mmap: Drop munmap_vma_range() Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 19/70] mm: Remove vmacache Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 20/70] mm/mmap: Change __do_munmap() to avoid unnecessary lookups Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 21/70] mm/mmap: Move mmap_region() below do_munmap() Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 22/70] mm/mmap: Add do_mas_munmap() and wraper for __do_munmap() Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 23/70] mmap: Use find_vma_intersection in do_mmap() for overlap Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 24/70] mmap: Remove __do_munmap() in favour of do_mas_munmap() Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 25/70] mm/mmap: Change do_brk_munmap() to use do_mas_align_munmap() Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 26/70] mmap: make remove_vma_list() inline Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 27/70] mm: Introduce vma_next() and vma_prev() Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 28/70] arch/arm64: Remove mmap linked list from vdso Liam R. Howlett
2021-01-12 16:11 ` [PATCH v2 29/70] arch/parsic: Remove mmap linked list from kernel/cache Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 30/70] arch/powerpc: Remove mmap linked list from mm/book2s32/tlb Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 31/70] arch/powerpc: Remove mmap linked list from mm/book2s32/subpage_prot Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 32/70] arch/powerpc: Optimize cell spu task sync Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 33/70] arch/s390: Use maple tree iterators instead of linked list Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 34/70] arch/um: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 35/70] arch/x86: Use maple tree iterators for vdso/vma Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 36/70] arch/xtensa: Use maple tree iterators for unmapped area Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 37/70] drivers/misc/cxl: Use maple tree iterators for cxl_prefault_vma() Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 38/70] drivers/oprofile: Lookup address in tree instead of linked list Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 39/70] drivers/tee/optee: Use maple tree iterators for __check_mem_type() Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 40/70] fs/binfmt_elf: Use maple tree iterators for fill_files_note() Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 41/70] fs/coredump: Use maple tree iterators in place of linked list Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 42/70] fs/exec: Use vma_next() instead " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 43/70] fs/proc/base: Use maple tree iterators in place " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 44/70] fs/proc/task_mmu: Stop using linked list and highest_vm_end Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 45/70] fs/userfaultfd: Stop using vma linked list Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 46/70] ipc/shm: Stop using the " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 47/70] kernel/acct: Use maple tree iterators instead of " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 48/70] kernel/events/core: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 49/70] kernel/events/uprobes: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 50/70] kernel/sched/fair: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 51/70] kernel/sys: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 52/70] mm/gup: Use maple tree navigation " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 53/70] mm/huge_memory: Use vma_next() instead of vma " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 54/70] mm/khugepaged: Use maple tree iterators " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 55/70] mm/ksm: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 56/70] mm/madvise: Use vma_next " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 57/70] mm/memcontrol: Stop using mm->highest_vm_end Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 58/70] mm/mempolicy: Use maple tree iterators instead of vma linked list Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 59/70] mm/mlock: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 60/70] mm/mprotect: Use maple tree navigation " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 61/70] mm/mremap: Use vma_next() " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 62/70] mm/msync: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 63/70] mm/nommu: Use maple tree iterators " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 64/70] mm/oom_kill: " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 65/70] mm/pagewalk: Use vma_next() " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 66/70] mm/swapfile: Use maple tree iterator " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 67/70] mm/nommu: Stop inserting into the " Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 68/70] mm/util: Remove __vma_link_list() and __vma_unlink_list() Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 69/70] mm: Remove vma linked list Liam R. Howlett
2021-01-12 16:12 ` [PATCH v2 70/70] mm/mmap: Convert __insert_vm_struct to use mas, convert vma_link to use vma_mas_link() Liam R. Howlett

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210112161240.2024684-11-Liam.Howlett@Oracle.com \
    --to=liam.howlett@oracle.com \
    --cc=akpm@google.com \
    --cc=axelrasmussen@google.com \
    --cc=dave@stgolabs.net \
    --cc=jglisse@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=maple-tree@lists.infradead.org \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=riel@surriel.com \
    --cc=rientjes@google.com \
    --cc=songliubraving@fb.com \
    --cc=surenb@google.com \
    --cc=vbabka@suse.cz \
    --cc=willy@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.