* [PATCH v3 0/4] Fix mas_empty_area() search
@ 2023-04-21 13:55 Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 1/4] maple_tree: Make maple state reusable after mas_empty_area_rev() Liam R. Howlett
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Liam R. Howlett @ 2023-04-21 13:55 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, maple-tree, Rick Edgecombe, Peng Zhang,
Liam R. Howlett
mas_empty_area() search could potentially return a sub-optimal position
for a VMAs as it is coded. This patch set is to address the issue by
altering the maple tree search and the mmap call into that search.
Changes from v2:
- Addressed Peng Zhang's concerns around limit checking.
- Updated testing code to work with size of 1 and added tests for this
case.
v2: https://lore.kernel.org/linux-mm/20230414185919.4175572-1-Liam.Howlett@oracle.com/
v1: https://lore.kernel.org/linux-mm/20230414145728.4067069-1-Liam.Howlett@oracle.com/
Liam R. Howlett (4):
maple_tree: Make maple state reusable after mas_empty_area_rev()
maple_tree: Update mtree_alloc_rrange() and mtree_alloc_range()
testing
maple_tree: Fix mas_empty_area() search
mm/mmap: Regression fix for unmapped_area{_topdown}
lib/maple_tree.c | 61 ++++++++++++++++++++++++-------------------
lib/test_maple_tree.c | 27 ++++++++++++++-----
mm/mmap.c | 48 ++++++++++++++++++++++++++++++----
3 files changed, 97 insertions(+), 39 deletions(-)
--
2.39.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/4] maple_tree: Make maple state reusable after mas_empty_area_rev()
2023-04-21 13:55 [PATCH v3 0/4] Fix mas_empty_area() search Liam R. Howlett
@ 2023-04-21 13:55 ` Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 2/4] maple_tree: Update mtree_alloc_rrange() and mtree_alloc_range() testing Liam R. Howlett
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Liam R. Howlett @ 2023-04-21 13:55 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, maple-tree, Rick Edgecombe, Peng Zhang,
Liam R. Howlett
Stop using maple state min/max for the range by passing through pointers
for those values. This will allow the maple state to be reused without
resetting.
Also add some logic to fail out early on searching with invalid
arguments.
This also fixes the currently unused mtree_alloc_range() and
mtree_alloc_rrange() functions validation of limits to work with a
window size of 1.
Fixes: 54a611b60590 ("Maple Tree: add new data structure")
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---
lib/maple_tree.c | 41 +++++++++++++++++++++++------------------
1 file changed, 23 insertions(+), 18 deletions(-)
diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index 4df6a0ce1c1b6..cf4f6cdcaad38 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -4938,7 +4938,8 @@ static inline void *mas_prev_entry(struct ma_state *mas, unsigned long min)
* Return: True if found in a leaf, false otherwise.
*
*/
-static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
+static bool mas_rev_awalk(struct ma_state *mas, unsigned long size,
+ unsigned long *gap_min, unsigned long *gap_max)
{
enum maple_type type = mte_node_type(mas->node);
struct maple_node *node = mas_mn(mas);
@@ -5003,8 +5004,8 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
if (unlikely(ma_is_leaf(type))) {
mas->offset = offset;
- mas->min = min;
- mas->max = min + gap - 1;
+ *gap_min = min;
+ *gap_max = min + gap - 1;
return true;
}
@@ -5280,6 +5281,12 @@ int mas_empty_area(struct ma_state *mas, unsigned long min,
unsigned long *pivots;
enum maple_type mt;
+ if (min > max)
+ return -EINVAL;
+
+ if (size == 0 || max - min < size - 1)
+ return -EINVAL;
+
if (mas_is_start(mas))
mas_start(mas);
else if (mas->offset >= 2)
@@ -5334,6 +5341,12 @@ int mas_empty_area_rev(struct ma_state *mas, unsigned long min,
{
struct maple_enode *last = mas->node;
+ if (min > max)
+ return -EINVAL;
+
+ if (size == 0 || max - min < size - 1)
+ return -EINVAL;
+
if (mas_is_start(mas)) {
mas_start(mas);
mas->offset = mas_data_end(mas);
@@ -5353,7 +5366,7 @@ int mas_empty_area_rev(struct ma_state *mas, unsigned long min,
mas->index = min;
mas->last = max;
- while (!mas_rev_awalk(mas, size)) {
+ while (!mas_rev_awalk(mas, size, &min, &max)) {
if (last == mas->node) {
if (!mas_rewind_node(mas))
return -EBUSY;
@@ -5368,17 +5381,9 @@ int mas_empty_area_rev(struct ma_state *mas, unsigned long min,
if (unlikely(mas->offset == MAPLE_NODE_SLOTS))
return -EBUSY;
- /*
- * mas_rev_awalk() has set mas->min and mas->max to the gap values. If
- * the maximum is outside the window we are searching, then use the last
- * location in the search.
- * mas->max and mas->min is the range of the gap.
- * mas->index and mas->last are currently set to the search range.
- */
-
/* Trim the upper limit to the max. */
- if (mas->max <= mas->last)
- mas->last = mas->max;
+ if (max < mas->last)
+ mas->last = max;
mas->index = mas->last - size + 1;
return 0;
@@ -6360,7 +6365,7 @@ int mtree_alloc_range(struct maple_tree *mt, unsigned long *startp,
{
int ret = 0;
- MA_STATE(mas, mt, min, max - size);
+ MA_STATE(mas, mt, min, min);
if (!mt_is_alloc(mt))
return -EINVAL;
@@ -6380,7 +6385,7 @@ int mtree_alloc_range(struct maple_tree *mt, unsigned long *startp,
retry:
mas.offset = 0;
mas.index = min;
- mas.last = max - size;
+ mas.last = max - size + 1;
ret = mas_alloc(&mas, entry, size, startp);
if (mas_nomem(&mas, gfp))
goto retry;
@@ -6396,14 +6401,14 @@ int mtree_alloc_rrange(struct maple_tree *mt, unsigned long *startp,
{
int ret = 0;
- MA_STATE(mas, mt, min, max - size);
+ MA_STATE(mas, mt, min, max - size + 1);
if (!mt_is_alloc(mt))
return -EINVAL;
if (WARN_ON_ONCE(mt_is_reserved(entry)))
return -EINVAL;
- if (min >= max)
+ if (min > max)
return -EINVAL;
if (max < size - 1)
--
2.39.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 2/4] maple_tree: Update mtree_alloc_rrange() and mtree_alloc_range() testing
2023-04-21 13:55 [PATCH v3 0/4] Fix mas_empty_area() search Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 1/4] maple_tree: Make maple state reusable after mas_empty_area_rev() Liam R. Howlett
@ 2023-04-21 13:55 ` Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 3/4] maple_tree: Fix mas_empty_area() search Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 4/4] mm/mmap: Regression fix for unmapped_area{_topdown} Liam R. Howlett
3 siblings, 0 replies; 5+ messages in thread
From: Liam R. Howlett @ 2023-04-21 13:55 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, maple-tree, Rick Edgecombe, Peng Zhang,
Liam R. Howlett
The previous changes to the gap searching made this testing fail.
Unfortunately, there was not a safe update order, so fix the testing
now.
Fixes: e15e06a83923 ("lib/test_maple_tree: add testing for maple tree")
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---
lib/test_maple_tree.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c
index f1db333270e9f..4d85d04b26f8d 100644
--- a/lib/test_maple_tree.c
+++ b/lib/test_maple_tree.c
@@ -102,7 +102,7 @@ static noinline void check_mtree_alloc_rrange(struct maple_tree *mt,
unsigned long result = expected + 1;
int ret;
- ret = mtree_alloc_rrange(mt, &result, ptr, size, start, end - 1,
+ ret = mtree_alloc_rrange(mt, &result, ptr, size, start, end,
GFP_KERNEL);
MT_BUG_ON(mt, ret != eret);
if (ret)
@@ -680,7 +680,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
0, /* Return value success. */
0x0, /* Min */
- 0x565234AF1 << 12, /* Max */
+ 0x565234AF0 << 12, /* Max */
0x3000, /* Size */
0x565234AEE << 12, /* max - 3. */
0, /* Return value success. */
@@ -692,14 +692,14 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
0, /* Return value success. */
0x0, /* Min */
- 0x7F36D510A << 12, /* Max */
+ 0x7F36D5109 << 12, /* Max */
0x4000, /* Size */
0x7F36D5106 << 12, /* First rev hole of size 0x4000 */
0, /* Return value success. */
/* Ascend test. */
0x0,
- 34148798629 << 12,
+ 34148798628 << 12,
19 << 12,
34148797418 << 12,
0x0,
@@ -711,6 +711,12 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
0x0,
-EBUSY,
+ /* Single space test. */
+ 34148798725 << 12,
+ 34148798725 << 12,
+ 1 << 12,
+ 34148798725 << 12,
+ 0,
};
int i, range_count = ARRAY_SIZE(range);
@@ -759,9 +765,9 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
mas_unlock(&mas);
for (i = 0; i < req_range_count; i += 5) {
#if DEBUG_REV_RANGE
- pr_debug("\tReverse request between %lu-%lu size %lu, should get %lu\n",
- req_range[i] >> 12,
- (req_range[i + 1] >> 12) - 1,
+ pr_debug("\tReverse request %d between %lu-%lu size %lu, should get %lu\n",
+ i, req_range[i] >> 12,
+ (req_range[i + 1] >> 12),
req_range[i+2] >> 12,
req_range[i+3] >> 12);
#endif
@@ -880,6 +886,13 @@ static noinline void check_alloc_range(struct maple_tree *mt)
4503599618982063UL << 12, /* Size */
34359052178 << 12, /* Expected location */
-EBUSY, /* Return failure. */
+
+ /* Test a single entry */
+ 34148798648 << 12, /* Min */
+ 34148798648 << 12, /* Max */
+ 4096, /* Size of 1 */
+ 34148798648 << 12, /* Location is the same as min/max */
+ 0, /* Success */
};
int i, range_count = ARRAY_SIZE(range);
int req_range_count = ARRAY_SIZE(req_range);
--
2.39.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 3/4] maple_tree: Fix mas_empty_area() search
2023-04-21 13:55 [PATCH v3 0/4] Fix mas_empty_area() search Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 1/4] maple_tree: Make maple state reusable after mas_empty_area_rev() Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 2/4] maple_tree: Update mtree_alloc_rrange() and mtree_alloc_range() testing Liam R. Howlett
@ 2023-04-21 13:55 ` Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 4/4] mm/mmap: Regression fix for unmapped_area{_topdown} Liam R. Howlett
3 siblings, 0 replies; 5+ messages in thread
From: Liam R. Howlett @ 2023-04-21 13:55 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, maple-tree, Rick Edgecombe, Peng Zhang,
Liam R. Howlett
The internal function of mas_awalk() was incorrectly skipping the last
entry in a node, which could potentially be NULL. This is only a
problem for the left-most node in the tree - otherwise that NULL would
not exist.
Fix mas_awalk() by using the metadata to obtain the end of the node for
the loop and the logical pivot as apposed to the raw pivot value.
Fixes: 54a611b60590 ("Maple Tree: add new data structure")
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---
lib/maple_tree.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index cf4f6cdcaad38..51910c74d4895 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -5029,10 +5029,10 @@ static inline bool mas_anode_descend(struct ma_state *mas, unsigned long size)
{
enum maple_type type = mte_node_type(mas->node);
unsigned long pivot, min, gap = 0;
- unsigned char offset;
- unsigned long *gaps;
- unsigned long *pivots = ma_pivots(mas_mn(mas), type);
- void __rcu **slots = ma_slots(mas_mn(mas), type);
+ unsigned char offset, data_end;
+ unsigned long *gaps, *pivots;
+ void __rcu **slots;
+ struct maple_node *node;
bool found = false;
if (ma_is_dense(type)) {
@@ -5040,13 +5040,15 @@ static inline bool mas_anode_descend(struct ma_state *mas, unsigned long size)
return true;
}
- gaps = ma_gaps(mte_to_node(mas->node), type);
+ node = mas_mn(mas);
+ pivots = ma_pivots(node, type);
+ slots = ma_slots(node, type);
+ gaps = ma_gaps(node, type);
offset = mas->offset;
min = mas_safe_min(mas, pivots, offset);
- for (; offset < mt_slots[type]; offset++) {
- pivot = mas_safe_pivot(mas, pivots, offset, type);
- if (offset && !pivot)
- break;
+ data_end = ma_data_end(node, type, pivots, mas->max);
+ for (; offset <= data_end; offset++) {
+ pivot = mas_logical_pivot(mas, pivots, offset, type);
/* Not within lower bounds */
if (mas->index > pivot)
--
2.39.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 4/4] mm/mmap: Regression fix for unmapped_area{_topdown}
2023-04-21 13:55 [PATCH v3 0/4] Fix mas_empty_area() search Liam R. Howlett
` (2 preceding siblings ...)
2023-04-21 13:55 ` [PATCH v3 3/4] maple_tree: Fix mas_empty_area() search Liam R. Howlett
@ 2023-04-21 13:55 ` Liam R. Howlett
3 siblings, 0 replies; 5+ messages in thread
From: Liam R. Howlett @ 2023-04-21 13:55 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, maple-tree, Rick Edgecombe, Peng Zhang,
Liam R. Howlett
The maple tree limits the gap returned to a window that specifically
fits what was asked. This may not be optimal in the case of switching
search directions or a gap that does not satisfy the requested space for
other reasons. Fix the search by retrying the operation and limiting
the search window in the rare occasion that a conflict occurs.
Reported-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Fixes: 3499a13168da ("mm/mmap: use maple tree for unmapped_area{_topdown}")
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---
mm/mmap.c | 48 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 5 deletions(-)
diff --git a/mm/mmap.c b/mm/mmap.c
index 055fbd5ed762f..6b9116f1c3049 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1548,7 +1548,8 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
*/
static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
{
- unsigned long length, gap;
+ unsigned long length, gap, low_limit;
+ struct vm_area_struct *tmp;
MA_STATE(mas, ¤t->mm->mm_mt, 0, 0);
@@ -1557,12 +1558,29 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
if (length < info->length)
return -ENOMEM;
- if (mas_empty_area(&mas, info->low_limit, info->high_limit - 1,
- length))
+ low_limit = info->low_limit;
+retry:
+ if (mas_empty_area(&mas, low_limit, info->high_limit - 1, length))
return -ENOMEM;
gap = mas.index;
gap += (info->align_offset - gap) & info->align_mask;
+ tmp = mas_next(&mas, ULONG_MAX);
+ if (tmp && (tmp->vm_flags & VM_GROWSDOWN)) { /* Avoid prev check if possible */
+ if (vm_start_gap(tmp) < gap + length - 1) {
+ low_limit = tmp->vm_end;
+ mas_reset(&mas);
+ goto retry;
+ }
+ } else {
+ tmp = mas_prev(&mas, 0);
+ if (tmp && vm_end_gap(tmp) > gap) {
+ low_limit = vm_end_gap(tmp);
+ mas_reset(&mas);
+ goto retry;
+ }
+ }
+
return gap;
}
@@ -1578,7 +1596,8 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
*/
static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
{
- unsigned long length, gap;
+ unsigned long length, gap, high_limit, gap_end;
+ struct vm_area_struct *tmp;
MA_STATE(mas, ¤t->mm->mm_mt, 0, 0);
/* Adjust search length to account for worst case alignment overhead */
@@ -1586,12 +1605,31 @@ static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
if (length < info->length)
return -ENOMEM;
- if (mas_empty_area_rev(&mas, info->low_limit, info->high_limit - 1,
+ high_limit = info->high_limit;
+retry:
+ if (mas_empty_area_rev(&mas, info->low_limit, high_limit - 1,
length))
return -ENOMEM;
gap = mas.last + 1 - info->length;
gap -= (gap - info->align_offset) & info->align_mask;
+ gap_end = mas.last;
+ tmp = mas_next(&mas, ULONG_MAX);
+ if (tmp && (tmp->vm_flags & VM_GROWSDOWN)) { /* Avoid prev check if possible */
+ if (vm_start_gap(tmp) <= gap_end) {
+ high_limit = vm_start_gap(tmp);
+ mas_reset(&mas);
+ goto retry;
+ }
+ } else {
+ tmp = mas_prev(&mas, 0);
+ if (tmp && vm_end_gap(tmp) > gap) {
+ high_limit = tmp->vm_start;
+ mas_reset(&mas);
+ goto retry;
+ }
+ }
+
return gap;
}
--
2.39.2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-04-21 13:56 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-21 13:55 [PATCH v3 0/4] Fix mas_empty_area() search Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 1/4] maple_tree: Make maple state reusable after mas_empty_area_rev() Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 2/4] maple_tree: Update mtree_alloc_rrange() and mtree_alloc_range() testing Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 3/4] maple_tree: Fix mas_empty_area() search Liam R. Howlett
2023-04-21 13:55 ` [PATCH v3 4/4] mm/mmap: Regression fix for unmapped_area{_topdown} Liam R. Howlett
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox