Skip to content

Commit 7327e81

Browse files
howlettakpm00
authored andcommitted
maple_tree: fix mas_empty_area_rev() lower bound validation
mas_empty_area_rev() was not correctly validating the start of a gap against the lower limit. This could lead to the range starting lower than the requested minimum. Fix the issue by better validating a gap once one is found. This commit also adds tests to the maple tree test suite for this issue and tests the mas_empty_area() function for similar bound checking. Link: https://lkml.kernel.org/r/[email protected] Link: https://bugzilla.kernel.org/show_bug.cgi?id=216911 Fixes: 54a611b ("Maple Tree: add new data structure") Signed-off-by: Liam R. Howlett <[email protected]> Reported-by: <[email protected]> Link: https://lore.kernel.org/linux-mm/[email protected]/ Tested-by: Holger Hoffsttte <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 24b5308 commit 7327e81

File tree

2 files changed

+97
-9
lines changed

2 files changed

+97
-9
lines changed

lib/maple_tree.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4887,7 +4887,7 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
48874887
unsigned long *pivots, *gaps;
48884888
void __rcu **slots;
48894889
unsigned long gap = 0;
4890-
unsigned long max, min, index;
4890+
unsigned long max, min;
48914891
unsigned char offset;
48924892

48934893
if (unlikely(mas_is_err(mas)))
@@ -4909,8 +4909,7 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
49094909
min = mas_safe_min(mas, pivots, --offset);
49104910

49114911
max = mas_safe_pivot(mas, pivots, offset, type);
4912-
index = mas->index;
4913-
while (index <= max) {
4912+
while (mas->index <= max) {
49144913
gap = 0;
49154914
if (gaps)
49164915
gap = gaps[offset];
@@ -4941,10 +4940,8 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
49414940
min = mas_safe_min(mas, pivots, offset);
49424941
}
49434942

4944-
if (unlikely(index > max)) {
4945-
mas_set_err(mas, -EBUSY);
4946-
return false;
4947-
}
4943+
if (unlikely((mas->index > max) || (size - 1 > max - mas->index)))
4944+
goto no_space;
49484945

49494946
if (unlikely(ma_is_leaf(type))) {
49504947
mas->offset = offset;
@@ -4961,9 +4958,11 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
49614958
return false;
49624959

49634960
ascend:
4964-
if (mte_is_root(mas->node))
4965-
mas_set_err(mas, -EBUSY);
4961+
if (!mte_is_root(mas->node))
4962+
return false;
49664963

4964+
no_space:
4965+
mas_set_err(mas, -EBUSY);
49674966
return false;
49684967
}
49694968

lib/test_maple_tree.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2517,6 +2517,91 @@ static noinline void check_bnode_min_spanning(struct maple_tree *mt)
25172517
mt_set_non_kernel(0);
25182518
}
25192519

2520+
static noinline void check_empty_area_window(struct maple_tree *mt)
2521+
{
2522+
unsigned long i, nr_entries = 20;
2523+
MA_STATE(mas, mt, 0, 0);
2524+
2525+
for (i = 1; i <= nr_entries; i++)
2526+
mtree_store_range(mt, i*10, i*10 + 9,
2527+
xa_mk_value(i), GFP_KERNEL);
2528+
2529+
/* Create another hole besides the one at 0 */
2530+
mtree_store_range(mt, 160, 169, NULL, GFP_KERNEL);
2531+
2532+
/* Check lower bounds that don't fit */
2533+
rcu_read_lock();
2534+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 5, 90, 10) != -EBUSY);
2535+
2536+
mas_reset(&mas);
2537+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 6, 90, 5) != -EBUSY);
2538+
2539+
/* Check lower bound that does fit */
2540+
mas_reset(&mas);
2541+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 5, 90, 5) != 0);
2542+
MT_BUG_ON(mt, mas.index != 5);
2543+
MT_BUG_ON(mt, mas.last != 9);
2544+
rcu_read_unlock();
2545+
2546+
/* Check one gap that doesn't fit and one that does */
2547+
rcu_read_lock();
2548+
mas_reset(&mas);
2549+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 5, 217, 9) != 0);
2550+
MT_BUG_ON(mt, mas.index != 161);
2551+
MT_BUG_ON(mt, mas.last != 169);
2552+
2553+
/* Check one gap that does fit above the min */
2554+
mas_reset(&mas);
2555+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 100, 218, 3) != 0);
2556+
MT_BUG_ON(mt, mas.index != 216);
2557+
MT_BUG_ON(mt, mas.last != 218);
2558+
2559+
/* Check size that doesn't fit any gap */
2560+
mas_reset(&mas);
2561+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 100, 218, 16) != -EBUSY);
2562+
2563+
/*
2564+
* Check size that doesn't fit the lower end of the window but
2565+
* does fit the gap
2566+
*/
2567+
mas_reset(&mas);
2568+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 167, 200, 4) != -EBUSY);
2569+
2570+
/*
2571+
* Check size that doesn't fit the upper end of the window but
2572+
* does fit the gap
2573+
*/
2574+
mas_reset(&mas);
2575+
MT_BUG_ON(mt, mas_empty_area_rev(&mas, 100, 162, 4) != -EBUSY);
2576+
2577+
/* Check mas_empty_area forward */
2578+
mas_reset(&mas);
2579+
MT_BUG_ON(mt, mas_empty_area(&mas, 0, 100, 9) != 0);
2580+
MT_BUG_ON(mt, mas.index != 0);
2581+
MT_BUG_ON(mt, mas.last != 8);
2582+
2583+
mas_reset(&mas);
2584+
MT_BUG_ON(mt, mas_empty_area(&mas, 0, 100, 4) != 0);
2585+
MT_BUG_ON(mt, mas.index != 0);
2586+
MT_BUG_ON(mt, mas.last != 3);
2587+
2588+
mas_reset(&mas);
2589+
MT_BUG_ON(mt, mas_empty_area(&mas, 0, 100, 11) != -EBUSY);
2590+
2591+
mas_reset(&mas);
2592+
MT_BUG_ON(mt, mas_empty_area(&mas, 5, 100, 6) != -EBUSY);
2593+
2594+
mas_reset(&mas);
2595+
MT_BUG_ON(mt, mas_empty_area(&mas, 0, 8, 10) != -EBUSY);
2596+
2597+
mas_reset(&mas);
2598+
mas_empty_area(&mas, 100, 165, 3);
2599+
2600+
mas_reset(&mas);
2601+
MT_BUG_ON(mt, mas_empty_area(&mas, 100, 163, 6) != -EBUSY);
2602+
rcu_read_unlock();
2603+
}
2604+
25202605
static DEFINE_MTREE(tree);
25212606
static int maple_tree_seed(void)
25222607
{
@@ -2765,6 +2850,10 @@ static int maple_tree_seed(void)
27652850
check_bnode_min_spanning(&tree);
27662851
mtree_destroy(&tree);
27672852

2853+
mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
2854+
check_empty_area_window(&tree);
2855+
mtree_destroy(&tree);
2856+
27682857
#if defined(BENCH)
27692858
skip:
27702859
#endif

0 commit comments

Comments
 (0)