Skip to content

Commit 3499a13

Browse files
howlettakpm00
authored andcommitted
mm/mmap: use maple tree for unmapped_area{_topdown}
The maple tree code was added to find the unmapped area in a previous commit and was checked against what the rbtree returned, but the actual result was never used. Start using the maple tree implementation and remove the rbtree code. Add kernel documentation comment for these functions. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Liam R. Howlett <[email protected]> Tested-by: Yu Zhao <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: David Howells <[email protected]> Cc: Davidlohr Bueso <[email protected]> Cc: "Matthew Wilcox (Oracle)" <[email protected]> Cc: SeongJae Park <[email protected]> Cc: Sven Schnelle <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 7fdbd37 commit 3499a13

File tree

1 file changed

+34
-221
lines changed

1 file changed

+34
-221
lines changed

mm/mmap.c

Lines changed: 34 additions & 221 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,250 +2013,63 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
20132013
return error;
20142014
}
20152015

2016+
/**
2017+
* unmapped_area() - Find an area between the low_limit and the high_limit with
2018+
* the correct alignment and offset, all from @info. Note: current->mm is used
2019+
* for the search.
2020+
*
2021+
* @info: The unmapped area information including the range (low_limit -
2022+
* hight_limit), the alignment offset and mask.
2023+
*
2024+
* Return: A memory address or -ENOMEM.
2025+
*/
20162026
static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
20172027
{
2018-
/*
2019-
* We implement the search by looking for an rbtree node that
2020-
* immediately follows a suitable gap. That is,
2021-
* - gap_start = vma->vm_prev->vm_end <= info->high_limit - length;
2022-
* - gap_end = vma->vm_start >= info->low_limit + length;
2023-
* - gap_end - gap_start >= length
2024-
*/
2028+
unsigned long length, gap;
20252029

2026-
struct mm_struct *mm = current->mm;
2027-
struct vm_area_struct *vma;
2028-
unsigned long length, low_limit, high_limit, gap_start, gap_end;
2029-
unsigned long gap;
2030-
MA_STATE(mas, &mm->mm_mt, 0, 0);
2030+
MA_STATE(mas, &current->mm->mm_mt, 0, 0);
20312031

20322032
/* Adjust search length to account for worst case alignment overhead */
20332033
length = info->length + info->align_mask;
20342034
if (length < info->length)
20352035
return -ENOMEM;
20362036

2037-
mas_empty_area(&mas, info->low_limit, info->high_limit - 1,
2038-
length);
2039-
gap = mas.index;
2040-
gap += (info->align_offset - gap) & info->align_mask;
2041-
2042-
/* Adjust search limits by the desired length */
2043-
if (info->high_limit < length)
2037+
if (mas_empty_area(&mas, info->low_limit, info->high_limit - 1,
2038+
length))
20442039
return -ENOMEM;
2045-
high_limit = info->high_limit - length;
20462040

2047-
if (info->low_limit > high_limit)
2048-
return -ENOMEM;
2049-
low_limit = info->low_limit + length;
2050-
2051-
/* Check if rbtree root looks promising */
2052-
if (RB_EMPTY_ROOT(&mm->mm_rb))
2053-
goto check_highest;
2054-
vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb);
2055-
if (vma->rb_subtree_gap < length)
2056-
goto check_highest;
2057-
2058-
while (true) {
2059-
/* Visit left subtree if it looks promising */
2060-
gap_end = vm_start_gap(vma);
2061-
if (gap_end >= low_limit && vma->vm_rb.rb_left) {
2062-
struct vm_area_struct *left =
2063-
rb_entry(vma->vm_rb.rb_left,
2064-
struct vm_area_struct, vm_rb);
2065-
if (left->rb_subtree_gap >= length) {
2066-
vma = left;
2067-
continue;
2068-
}
2069-
}
2070-
2071-
gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
2072-
check_current:
2073-
/* Check if current node has a suitable gap */
2074-
if (gap_start > high_limit)
2075-
return -ENOMEM;
2076-
if (gap_end >= low_limit &&
2077-
gap_end > gap_start && gap_end - gap_start >= length)
2078-
goto found;
2079-
2080-
/* Visit right subtree if it looks promising */
2081-
if (vma->vm_rb.rb_right) {
2082-
struct vm_area_struct *right =
2083-
rb_entry(vma->vm_rb.rb_right,
2084-
struct vm_area_struct, vm_rb);
2085-
if (right->rb_subtree_gap >= length) {
2086-
vma = right;
2087-
continue;
2088-
}
2089-
}
2090-
2091-
/* Go back up the rbtree to find next candidate node */
2092-
while (true) {
2093-
struct rb_node *prev = &vma->vm_rb;
2094-
if (!rb_parent(prev))
2095-
goto check_highest;
2096-
vma = rb_entry(rb_parent(prev),
2097-
struct vm_area_struct, vm_rb);
2098-
if (prev == vma->vm_rb.rb_left) {
2099-
gap_start = vm_end_gap(vma->vm_prev);
2100-
gap_end = vm_start_gap(vma);
2101-
goto check_current;
2102-
}
2103-
}
2104-
}
2105-
2106-
check_highest:
2107-
/* Check highest gap, which does not precede any rbtree node */
2108-
gap_start = mm->highest_vm_end;
2109-
gap_end = ULONG_MAX; /* Only for VM_BUG_ON below */
2110-
if (gap_start > high_limit)
2111-
return -ENOMEM;
2112-
2113-
found:
2114-
/* We found a suitable gap. Clip it with the original low_limit. */
2115-
if (gap_start < info->low_limit)
2116-
gap_start = info->low_limit;
2117-
2118-
/* Adjust gap address to the desired alignment */
2119-
gap_start += (info->align_offset - gap_start) & info->align_mask;
2120-
2121-
VM_BUG_ON(gap_start + info->length > info->high_limit);
2122-
VM_BUG_ON(gap_start + info->length > gap_end);
2123-
2124-
VM_BUG_ON(gap != gap_start);
2125-
return gap_start;
2041+
gap = mas.index;
2042+
gap += (info->align_offset - gap) & info->align_mask;
2043+
return gap;
21262044
}
21272045

2046+
/**
2047+
* unmapped_area_topdown() - Find an area between the low_limit and the
2048+
* high_limit with * the correct alignment and offset at the highest available
2049+
* address, all from @info. Note: current->mm is used for the search.
2050+
*
2051+
* @info: The unmapped area information including the range (low_limit -
2052+
* hight_limit), the alignment offset and mask.
2053+
*
2054+
* Return: A memory address or -ENOMEM.
2055+
*/
21282056
static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
21292057
{
2130-
struct mm_struct *mm = current->mm;
2131-
struct vm_area_struct *vma = NULL;
2132-
unsigned long length, low_limit, high_limit, gap_start, gap_end;
2133-
unsigned long gap;
2134-
2135-
MA_STATE(mas, &mm->mm_mt, 0, 0);
2136-
validate_mm_mt(mm);
2058+
unsigned long length, gap;
21372059

2060+
MA_STATE(mas, &current->mm->mm_mt, 0, 0);
21382061
/* Adjust search length to account for worst case alignment overhead */
21392062
length = info->length + info->align_mask;
21402063
if (length < info->length)
21412064
return -ENOMEM;
21422065

2143-
mas_empty_area_rev(&mas, info->low_limit, info->high_limit - 1,
2144-
length);
2145-
gap = mas.last + 1 - info->length;
2146-
gap -= (gap - info->align_offset) & info->align_mask;
2147-
2148-
/*
2149-
* Adjust search limits by the desired length.
2150-
* See implementation comment at top of unmapped_area().
2151-
*/
2152-
gap_end = info->high_limit;
2153-
if (gap_end < length)
2154-
return -ENOMEM;
2155-
high_limit = gap_end - length;
2156-
2157-
if (info->low_limit > high_limit)
2066+
if (mas_empty_area_rev(&mas, info->low_limit, info->high_limit - 1,
2067+
length))
21582068
return -ENOMEM;
2159-
low_limit = info->low_limit + length;
21602069

2161-
/* Check highest gap, which does not precede any rbtree node */
2162-
gap_start = mm->highest_vm_end;
2163-
if (gap_start <= high_limit)
2164-
goto found_highest;
2165-
2166-
/* Check if rbtree root looks promising */
2167-
if (RB_EMPTY_ROOT(&mm->mm_rb))
2168-
return -ENOMEM;
2169-
vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb);
2170-
if (vma->rb_subtree_gap < length)
2171-
return -ENOMEM;
2172-
2173-
while (true) {
2174-
/* Visit right subtree if it looks promising */
2175-
gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0;
2176-
if (gap_start <= high_limit && vma->vm_rb.rb_right) {
2177-
struct vm_area_struct *right =
2178-
rb_entry(vma->vm_rb.rb_right,
2179-
struct vm_area_struct, vm_rb);
2180-
if (right->rb_subtree_gap >= length) {
2181-
vma = right;
2182-
continue;
2183-
}
2184-
}
2185-
2186-
check_current:
2187-
/* Check if current node has a suitable gap */
2188-
gap_end = vm_start_gap(vma);
2189-
if (gap_end < low_limit)
2190-
return -ENOMEM;
2191-
if (gap_start <= high_limit &&
2192-
gap_end > gap_start && gap_end - gap_start >= length)
2193-
goto found;
2194-
2195-
/* Visit left subtree if it looks promising */
2196-
if (vma->vm_rb.rb_left) {
2197-
struct vm_area_struct *left =
2198-
rb_entry(vma->vm_rb.rb_left,
2199-
struct vm_area_struct, vm_rb);
2200-
if (left->rb_subtree_gap >= length) {
2201-
vma = left;
2202-
continue;
2203-
}
2204-
}
2205-
2206-
/* Go back up the rbtree to find next candidate node */
2207-
while (true) {
2208-
struct rb_node *prev = &vma->vm_rb;
2209-
if (!rb_parent(prev))
2210-
return -ENOMEM;
2211-
vma = rb_entry(rb_parent(prev),
2212-
struct vm_area_struct, vm_rb);
2213-
if (prev == vma->vm_rb.rb_right) {
2214-
gap_start = vma->vm_prev ?
2215-
vm_end_gap(vma->vm_prev) : 0;
2216-
goto check_current;
2217-
}
2218-
}
2219-
}
2220-
2221-
found:
2222-
/* We found a suitable gap. Clip it with the original high_limit. */
2223-
if (gap_end > info->high_limit)
2224-
gap_end = info->high_limit;
2225-
2226-
found_highest:
2227-
/* Compute highest gap address at the desired alignment */
2228-
gap_end -= info->length;
2229-
gap_end -= (gap_end - info->align_offset) & info->align_mask;
2230-
2231-
VM_BUG_ON(gap_end < info->low_limit);
2232-
VM_BUG_ON(gap_end < gap_start);
2233-
2234-
if (gap != gap_end) {
2235-
pr_err("%s: %p Gap was found: mt %lu gap_end %lu\n", __func__,
2236-
mm, gap, gap_end);
2237-
pr_err("window was %lu - %lu size %lu\n", info->high_limit,
2238-
info->low_limit, length);
2239-
pr_err("mas.min %lu max %lu mas.last %lu\n", mas.min, mas.max,
2240-
mas.last);
2241-
pr_err("mas.index %lu align mask %lu offset %lu\n", mas.index,
2242-
info->align_mask, info->align_offset);
2243-
pr_err("rb_find_vma find on %lu => %p (%p)\n", mas.index,
2244-
find_vma(mm, mas.index), vma);
2245-
#if defined(CONFIG_DEBUG_VM_MAPLE_TREE)
2246-
mt_dump(&mm->mm_mt);
2247-
#endif
2248-
{
2249-
struct vm_area_struct *dv = mm->mmap;
2250-
2251-
while (dv) {
2252-
pr_err("vma %p %lu-%lu\n", dv, dv->vm_start, dv->vm_end);
2253-
dv = dv->vm_next;
2254-
}
2255-
}
2256-
VM_BUG_ON(gap != gap_end);
2257-
}
2258-
2259-
return gap_end;
2070+
gap = mas.last + 1 - info->length;
2071+
gap -= (gap - info->align_offset) & info->align_mask;
2072+
return gap;
22602073
}
22612074

22622075
/*

0 commit comments

Comments
 (0)