diff mbox series

[4/4] maple_tree: fix potential allocation failure even has memory

Message ID 20240924123954.18933-5-richard.weiyang@gmail.com (mailing list archive)
State New
Headers show
Series cleanup maple_alloc related functions | expand

Commit Message

Wei Yang Sept. 24, 2024, 12:39 p.m. UTC
We got an rare case when mas_node_count() would fail even there is
enough memory.

The reason is the maple_alloc grows downward. And when hit a full
maple_alloc, the max_req would be 0. This leads to mt_alloc_bulk()
return 0, which means failure here.

For example, here is the test code:

	expect = MAPLE_ALLOC_SLOTS + 1;
	mas_node_count(&ms, expect);
	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));
	expect = MAPLE_ALLOC_SLOTS * 2 + 2;
	mas_node_count(&ms, expect);
	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));

We will get the following output, which shows we fail to allocate the
required number of nodes.

	expect 31 allocated 31
        expect 62 allocated 61

The straight forward way to fix it is go down one level more.

Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
CC: Liam R. Howlett <Liam.Howlett@Oracle.com>
CC: Sidhartha Kumar <sidhartha.kumar@oracle.com>
---
 lib/maple_tree.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Wei Yang Oct. 11, 2024, 1:27 a.m. UTC | #1
Related fix has been posted, but not merged yet.

lkml.kernel.org/r/20240626160631.3636515-1-Liam.Howlett@oracle.com

May drop this one.

On Tue, Sep 24, 2024 at 12:39:54PM +0000, Wei Yang wrote:
>We got an rare case when mas_node_count() would fail even there is
>enough memory.
>
>The reason is the maple_alloc grows downward. And when hit a full
>maple_alloc, the max_req would be 0. This leads to mt_alloc_bulk()
>return 0, which means failure here.
>
>For example, here is the test code:
>
>	expect = MAPLE_ALLOC_SLOTS + 1;
>	mas_node_count(&ms, expect);
>	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));
>	expect = MAPLE_ALLOC_SLOTS * 2 + 2;
>	mas_node_count(&ms, expect);
>	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));
>
>We will get the following output, which shows we fail to allocate the
>required number of nodes.
>
>	expect 31 allocated 31
>        expect 62 allocated 61
>
>The straight forward way to fix it is go down one level more.
>
>Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
>CC: Liam R. Howlett <Liam.Howlett@Oracle.com>
>CC: Sidhartha Kumar <sidhartha.kumar@oracle.com>
>---
> lib/maple_tree.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
>diff --git a/lib/maple_tree.c b/lib/maple_tree.c
>index 1cbc5f7ca40d..dd33d0793dd1 100644
>--- a/lib/maple_tree.c
>+++ b/lib/maple_tree.c
>@@ -1253,8 +1253,10 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> 	}
> 
> 	node = mas->alloc;
>-	while (requested) {
>+	for (; requested; node = node->slot[0]) {
> 		max_req = MAPLE_ALLOC_SLOTS - node->node_count;
>+		if (unlikely(!max_req))
>+			continue;
> 		slots = (void **)&node->slot[node->node_count];
> 		max_req = min(requested, max_req);
> 		count = mt_alloc_bulk(gfp, max_req, slots);
>@@ -1268,7 +1270,6 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> 
> 		node->node_count += count;
> 		allocated += count;
>-		node = node->slot[0];
> 		requested -= count;
> 	}
> 	mas->alloc->total = allocated;
>-- 
>2.34.1
Liam R. Howlett Oct. 15, 2024, 1:14 a.m. UTC | #2
* Wei Yang <richard.weiyang@gmail.com> [241010 21:27]:
> 
> Related fix has been posted, but not merged yet.
> 
> lkml.kernel.org/r/20240626160631.3636515-1-Liam.Howlett@oracle.com
> 
> May drop this one.

Yes, I thought we had fixed this already.

> 
> On Tue, Sep 24, 2024 at 12:39:54PM +0000, Wei Yang wrote:
> >We got an rare case when mas_node_count() would fail even there is
> >enough memory.
> >
> >The reason is the maple_alloc grows downward. And when hit a full
> >maple_alloc, the max_req would be 0. This leads to mt_alloc_bulk()
> >return 0, which means failure here.
> >
> >For example, here is the test code:
> >
> >	expect = MAPLE_ALLOC_SLOTS + 1;
> >	mas_node_count(&ms, expect);
> >	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));
> >	expect = MAPLE_ALLOC_SLOTS * 2 + 2;
> >	mas_node_count(&ms, expect);
> >	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));
> >
> >We will get the following output, which shows we fail to allocate the
> >required number of nodes.
> >
> >	expect 31 allocated 31
> >        expect 62 allocated 61
> >
> >The straight forward way to fix it is go down one level more.
> >
> >Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
> >CC: Liam R. Howlett <Liam.Howlett@Oracle.com>
> >CC: Sidhartha Kumar <sidhartha.kumar@oracle.com>
> >---
> > lib/maple_tree.c | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> >diff --git a/lib/maple_tree.c b/lib/maple_tree.c
> >index 1cbc5f7ca40d..dd33d0793dd1 100644
> >--- a/lib/maple_tree.c
> >+++ b/lib/maple_tree.c
> >@@ -1253,8 +1253,10 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> > 	}
> > 
> > 	node = mas->alloc;
> >-	while (requested) {
> >+	for (; requested; node = node->slot[0]) {
> > 		max_req = MAPLE_ALLOC_SLOTS - node->node_count;
> >+		if (unlikely(!max_req))
> >+			continue;
> > 		slots = (void **)&node->slot[node->node_count];
> > 		max_req = min(requested, max_req);
> > 		count = mt_alloc_bulk(gfp, max_req, slots);
> >@@ -1268,7 +1270,6 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> > 
> > 		node->node_count += count;
> > 		allocated += count;
> >-		node = node->slot[0];
> > 		requested -= count;
> > 	}
> > 	mas->alloc->total = allocated;
> >-- 
> >2.34.1
> 
> -- 
> Wei Yang
> Help you, Help me
>
Liam R. Howlett Oct. 15, 2024, 1:29 a.m. UTC | #3
* Wei Yang <richard.weiyang@gmail.com> [241010 21:27]:
> 
> Related fix has been posted, but not merged yet.
> 
> lkml.kernel.org/r/20240626160631.3636515-1-Liam.Howlett@oracle.com
> 
> May drop this one.

Yes, thanks.  This can be dropped in favour of the other commit.

> 
> On Tue, Sep 24, 2024 at 12:39:54PM +0000, Wei Yang wrote:
> >We got an rare case when mas_node_count() would fail even there is
> >enough memory.
> >
> >The reason is the maple_alloc grows downward. And when hit a full
> >maple_alloc, the max_req would be 0. This leads to mt_alloc_bulk()
> >return 0, which means failure here.
> >
> >For example, here is the test code:
> >
> >	expect = MAPLE_ALLOC_SLOTS + 1;
> >	mas_node_count(&ms, expect);
> >	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));
> >	expect = MAPLE_ALLOC_SLOTS * 2 + 2;
> >	mas_node_count(&ms, expect);
> >	pr_info("expect %d allocated %lu\n", expect, mas_allocated(&ms));
> >
> >We will get the following output, which shows we fail to allocate the
> >required number of nodes.
> >
> >	expect 31 allocated 31
> >        expect 62 allocated 61
> >
> >The straight forward way to fix it is go down one level more.
> >
> >Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
> >CC: Liam R. Howlett <Liam.Howlett@Oracle.com>
> >CC: Sidhartha Kumar <sidhartha.kumar@oracle.com>
> >---
> > lib/maple_tree.c | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> >diff --git a/lib/maple_tree.c b/lib/maple_tree.c
> >index 1cbc5f7ca40d..dd33d0793dd1 100644
> >--- a/lib/maple_tree.c
> >+++ b/lib/maple_tree.c
> >@@ -1253,8 +1253,10 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> > 	}
> > 
> > 	node = mas->alloc;
> >-	while (requested) {
> >+	for (; requested; node = node->slot[0]) {
> > 		max_req = MAPLE_ALLOC_SLOTS - node->node_count;
> >+		if (unlikely(!max_req))
> >+			continue;
> > 		slots = (void **)&node->slot[node->node_count];
> > 		max_req = min(requested, max_req);
> > 		count = mt_alloc_bulk(gfp, max_req, slots);
> >@@ -1268,7 +1270,6 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> > 
> > 		node->node_count += count;
> > 		allocated += count;
> >-		node = node->slot[0];
> > 		requested -= count;
> > 	}
> > 	mas->alloc->total = allocated;
> >-- 
> >2.34.1
> 
> -- 
> Wei Yang
> Help you, Help me
>
diff mbox series

Patch

diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index 1cbc5f7ca40d..dd33d0793dd1 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -1253,8 +1253,10 @@  static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
 	}
 
 	node = mas->alloc;
-	while (requested) {
+	for (; requested; node = node->slot[0]) {
 		max_req = MAPLE_ALLOC_SLOTS - node->node_count;
+		if (unlikely(!max_req))
+			continue;
 		slots = (void **)&node->slot[node->node_count];
 		max_req = min(requested, max_req);
 		count = mt_alloc_bulk(gfp, max_req, slots);
@@ -1268,7 +1270,6 @@  static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
 
 		node->node_count += count;
 		allocated += count;
-		node = node->slot[0];
 		requested -= count;
 	}
 	mas->alloc->total = allocated;