Skip to content

Commit 099d743

Browse files
howlettakpm00
authored andcommitted
maple_tree: add GFP_KERNEL to allocations in mas_expected_entries()
Users complained about OOM errors during fork without triggering compaction. This can be fixed by modifying the flags used in mas_expected_entries() so that the compaction will be triggered in low memory situations. Since mas_expected_entries() is only used during fork, the extra argument does not need to be passed through. Additionally, the two test_maple_tree test cases and one benchmark test were altered to use the correct locking type so that allocations would not trigger sleeping and thus fail. Testing was completed with lockdep atomic sleep detection. The additional locking change requires rwsem support additions to the tools/ directory through the use of pthreads pthread_rwlock_t. With this change test_maple_tree works in userspace, as a module, and in-kernel. Users may notice that the system gave up early on attempting to start new processes instead of attempting to reclaim memory. Link: https://lkml.kernel.org/r/20230915093243epcms1p46fa00bbac1ab7b7dca94acb66c44c456@epcms1p4 Link: https://lkml.kernel.org/r/[email protected] Fixes: 54a611b ("Maple Tree: add new data structure") Signed-off-by: Liam R. Howlett <[email protected]> Reviewed-by: Peng Zhang <[email protected]> Cc: <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent e2de156 commit 099d743

File tree

3 files changed

+65
-12
lines changed

3 files changed

+65
-12
lines changed

lib/maple_tree.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -5627,7 +5627,7 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries)
56275627
/* Internal nodes */
56285628
nr_nodes += DIV_ROUND_UP(nr_nodes, nonleaf_cap);
56295629
/* Add working room for split (2 nodes) + new parents */
5630-
mas_node_count(mas, nr_nodes + 3);
5630+
mas_node_count_gfp(mas, nr_nodes + 3, GFP_KERNEL);
56315631

56325632
/* Detect if allocations run out */
56335633
mas->mas_flags |= MA_STATE_PREALLOC;

lib/test_maple_tree.c

+24-11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/maple_tree.h>
1111
#include <linux/module.h>
12+
#include <linux/rwsem.h>
1213

1314
#define MTREE_ALLOC_MAX 0x2000000000000Ul
1415
#define CONFIG_MAPLE_SEARCH
@@ -1841,17 +1842,21 @@ static noinline void __init check_forking(struct maple_tree *mt)
18411842
void *val;
18421843
MA_STATE(mas, mt, 0, 0);
18431844
MA_STATE(newmas, mt, 0, 0);
1845+
struct rw_semaphore newmt_lock;
1846+
1847+
init_rwsem(&newmt_lock);
18441848

18451849
for (i = 0; i <= nr_entries; i++)
18461850
mtree_store_range(mt, i*10, i*10 + 5,
18471851
xa_mk_value(i), GFP_KERNEL);
18481852

18491853
mt_set_non_kernel(99999);
1850-
mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE);
1854+
mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN);
1855+
mt_set_external_lock(&newmt, &newmt_lock);
18511856
newmas.tree = &newmt;
18521857
mas_reset(&newmas);
18531858
mas_reset(&mas);
1854-
mas_lock(&newmas);
1859+
down_write(&newmt_lock);
18551860
mas.index = 0;
18561861
mas.last = 0;
18571862
if (mas_expected_entries(&newmas, nr_entries)) {
@@ -1866,10 +1871,10 @@ static noinline void __init check_forking(struct maple_tree *mt)
18661871
}
18671872
rcu_read_unlock();
18681873
mas_destroy(&newmas);
1869-
mas_unlock(&newmas);
18701874
mt_validate(&newmt);
18711875
mt_set_non_kernel(0);
1872-
mtree_destroy(&newmt);
1876+
__mt_destroy(&newmt);
1877+
up_write(&newmt_lock);
18731878
}
18741879

18751880
static noinline void __init check_iteration(struct maple_tree *mt)
@@ -1980,6 +1985,10 @@ static noinline void __init bench_forking(struct maple_tree *mt)
19801985
void *val;
19811986
MA_STATE(mas, mt, 0, 0);
19821987
MA_STATE(newmas, mt, 0, 0);
1988+
struct rw_semaphore newmt_lock;
1989+
1990+
init_rwsem(&newmt_lock);
1991+
mt_set_external_lock(&newmt, &newmt_lock);
19831992

19841993
for (i = 0; i <= nr_entries; i++)
19851994
mtree_store_range(mt, i*10, i*10 + 5,
@@ -1994,7 +2003,7 @@ static noinline void __init bench_forking(struct maple_tree *mt)
19942003
mas.index = 0;
19952004
mas.last = 0;
19962005
rcu_read_lock();
1997-
mas_lock(&newmas);
2006+
down_write(&newmt_lock);
19982007
if (mas_expected_entries(&newmas, nr_entries)) {
19992008
printk("OOM!");
20002009
BUG_ON(1);
@@ -2005,11 +2014,11 @@ static noinline void __init bench_forking(struct maple_tree *mt)
20052014
mas_store(&newmas, val);
20062015
}
20072016
mas_destroy(&newmas);
2008-
mas_unlock(&newmas);
20092017
rcu_read_unlock();
20102018
mt_validate(&newmt);
20112019
mt_set_non_kernel(0);
2012-
mtree_destroy(&newmt);
2020+
__mt_destroy(&newmt);
2021+
up_write(&newmt_lock);
20132022
}
20142023
}
20152024
#endif
@@ -2616,6 +2625,10 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
26162625
void *tmp;
26172626
MA_STATE(mas, mt, 0, 0);
26182627
MA_STATE(newmas, &newmt, 0, 0);
2628+
struct rw_semaphore newmt_lock;
2629+
2630+
init_rwsem(&newmt_lock);
2631+
mt_set_external_lock(&newmt, &newmt_lock);
26192632

26202633
if (!zero_start)
26212634
i = 1;
@@ -2625,9 +2638,9 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
26252638
mtree_store_range(mt, i*10, (i+1)*10 - gap,
26262639
xa_mk_value(i), GFP_KERNEL);
26272640

2628-
mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE);
2641+
mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN);
26292642
mt_set_non_kernel(99999);
2630-
mas_lock(&newmas);
2643+
down_write(&newmt_lock);
26312644
ret = mas_expected_entries(&newmas, nr_entries);
26322645
mt_set_non_kernel(0);
26332646
MT_BUG_ON(mt, ret != 0);
@@ -2640,9 +2653,9 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
26402653
}
26412654
rcu_read_unlock();
26422655
mas_destroy(&newmas);
2643-
mas_unlock(&newmas);
26442656

2645-
mtree_destroy(&newmt);
2657+
__mt_destroy(&newmt);
2658+
up_write(&newmt_lock);
26462659
}
26472660

26482661
/* Duplicate many sizes of trees. Mainly to test expected entry values */

tools/include/linux/rwsem.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* SPDX-License-Identifier: GPL-2.0+ */
2+
#ifndef _TOOLS__RWSEM_H
3+
#define _TOOLS__RWSEM_H
4+
5+
#include <pthread.h>
6+
7+
struct rw_semaphore {
8+
pthread_rwlock_t lock;
9+
};
10+
11+
static inline int init_rwsem(struct rw_semaphore *sem)
12+
{
13+
return pthread_rwlock_init(&sem->lock, NULL);
14+
}
15+
16+
static inline int exit_rwsem(struct rw_semaphore *sem)
17+
{
18+
return pthread_rwlock_destroy(&sem->lock);
19+
}
20+
21+
static inline int down_read(struct rw_semaphore *sem)
22+
{
23+
return pthread_rwlock_rdlock(&sem->lock);
24+
}
25+
26+
static inline int up_read(struct rw_semaphore *sem)
27+
{
28+
return pthread_rwlock_unlock(&sem->lock);
29+
}
30+
31+
static inline int down_write(struct rw_semaphore *sem)
32+
{
33+
return pthread_rwlock_wrlock(&sem->lock);
34+
}
35+
36+
static inline int up_write(struct rw_semaphore *sem)
37+
{
38+
return pthread_rwlock_unlock(&sem->lock);
39+
}
40+
#endif /* _TOOLS_RWSEM_H */

0 commit comments

Comments
 (0)