Skip to contentSkip to conversation

mm:free unused pages in kmalloc_order

PATCH In review Long Li 3 participants 6 messages Jun 27, 2020 – Jul 1, 2020

Subsystems (2)
lore
Share & tools
lore

Long Li

author
#0 lore raw

PATCH 1/1 mm:free unused pages in kmalloc_order

Environment using the slub allocator, 1G memory in my ARM32. kmalloc(1024, GFP_HIGHUSER) can allocate memory normally, kmalloc(64*1024, GFP_HIGHUSER) will cause a memory leak, because alloc_pages returns highmem physical pages, but it cannot be directly converted into a virtual address and return NULL, the pages has not been released. Usually driver developers will not use the GFP_HIGHUSER flag to allocate memory in kmalloc, but I think this memory leak is not perfect, it is best to be fixed. This is the first time I have posted a patch, there may be something wrong.

---
 mm/slab_common.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
mm/slab_common.c +6 -2
index a143a8c8f874..d2c53b980ab3 100644
@@ -819,8 +819,12 @@ void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
 	page = alloc_pages(flags, order);
 	if (likely(page)) {
 		ret = page_address(page);
-		mod_node_page_state(page_pgdat(page), NR_SLAB_UNRECLAIMABLE_B,
-				    PAGE_SIZE << order);
+		if (ret)
+			mod_node_page_state(page_pgdat(page),
+					NR_SLAB_UNRECLAIMABLE_B,
+					PAGE_SIZE << order);
+		else
+			__free_pages(page, order);
 	}
 	ret = kasan_kmalloc_large(ret, size, flags);
 	/* As ret might get tagged, call kmemleak hook after KASAN. */
Signature · 1 line
2.17.1
#1 lore raw
Quoted 9 lines · Long Li

Environment using the slub allocator, 1G memory in my ARM32. kmalloc(1024, GFP_HIGHUSER) can allocate memory normally, kmalloc(64*1024, GFP_HIGHUSER) will cause a memory leak, because alloc_pages returns highmem physical pages, but it cannot be directly converted into a virtual address and return NULL, the pages has not been released. Usually driver developers will not use the GFP_HIGHUSER flag to allocate memory in kmalloc, but I think this memory leak is not perfect, it is best to be fixed. This is the first time I have posted a patch, there may be something wrong.

Slab used to disallow GFP_HIGHMEM allocations earlier than this, so you'd never get here. See one moron's patch here, 20 years ago ...
https://lore.kernel.org/lkml/[email protected]/

Things changed a bit since then. SLAB_LEVEL_MASK became GFP_SLAB_BUG_MASK, then GFP_SLAB_BUG_MASK moved to mm/internal.h. Nowadays, GFP_SLAB_BUG_MASK is checked only in new_slab(), and it is definitely skipped when we go through the kmalloc_large() patch.

Could you send a replacement patch which checks GFP_SLAB_BUG_MASK before calling alloc_pages()?

Quoted 20 lines

+++ b/mm/slab_common.c

mm/slab_common.c +6 -2
@@ -819,8 +819,12 @@ void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
 	page = alloc_pages(flags, order);
 	if (likely(page)) {
 		ret = page_address(page);
-		mod_node_page_state(page_pgdat(page), NR_SLAB_UNRECLAIMABLE_B,
-				    PAGE_SIZE << order);
+		if (ret)
+			mod_node_page_state(page_pgdat(page),
+					NR_SLAB_UNRECLAIMABLE_B,
+					PAGE_SIZE << order);
+		else
+			__free_pages(page, order);
 	}
 	ret = kasan_kmalloc_large(ret, size, flags);
 	/* As ret might get tagged, call kmemleak hook after KASAN. */
Signature · 1 line
2.17.1
#2 lore raw
Quoted 1 line · Matthew Wilcox

Slab used to disallow GFP_HIGHMEM allocations earlier than this,

It is still not allowed and not supported.

#3 lore raw
In reply to Long Li
Quoted 9 lines · Long Li

Environment using the slub allocator, 1G memory in my ARM32. kmalloc(1024, GFP_HIGHUSER) can allocate memory normally, kmalloc(64*1024, GFP_HIGHUSER) will cause a memory leak, because alloc_pages returns highmem physical pages, but it cannot be directly converted into a virtual address and return NULL, the pages has not been released. Usually driver developers will not use the GFP_HIGHUSER flag to allocate memory in kmalloc, but I think this memory leak is not perfect, it is best to be fixed. This is the first time I have posted a patch, there may be something wrong.

Highmem is not supported by the slab allocators. Please ensure that there is a warning generated if someone attempts to do such an allocation. We used to check for that.

In order to make such allocations possible one would have to create yet another kmalloc array for high memory.

#4 lore raw
Quoted 11 lines · Christopher Lameter
Quoted 9 lines · Long Li

Environment using the slub allocator, 1G memory in my ARM32. kmalloc(1024, GFP_HIGHUSER) can allocate memory normally, kmalloc(64*1024, GFP_HIGHUSER) will cause a memory leak, because alloc_pages returns highmem physical pages, but it cannot be directly converted into a virtual address and return NULL, the pages has not been released. Usually driver developers will not use the GFP_HIGHUSER flag to allocate memory in kmalloc, but I think this memory leak is not perfect, it is best to be fixed. This is the first time I have posted a patch, there may be something wrong.

Quoted 3 lines

Highmem is not supported by the slab allocators. Please ensure that there is a warning generated if someone attempts to do such an allocation. We used to check for that.

Sounds like we need a test somewhere that checks this behaviour.

Quoted 2 lines

In order to make such allocations possible one would have to create yet another kmalloc array for high memory.

Not for this case because it goes straight to kmalloc_order(). What does make this particular case impossible is that we can't kmap() a compound page. We could vmap it, but why are we bothering?

#5 lore raw
Quoted 8 lines · Matthew Wilcox

Sounds like we need a test somewhere that checks this behaviour.

Quoted 2 lines

In order to make such allocations possible one would have to create yet another kmalloc array for high memory.

Not for this case because it goes straight to kmalloc_order(). What does make this particular case impossible is that we can't kmap() a compound page. We could vmap it, but why are we bothering?

Well yes it will work if the slab allocator falls back to the page allocator. Higher order allocation through kmalloc ;-). How much fun and uselessness ....

Why not call the page allocator directly and play with all the bits you want? Any regular small object allocation with GFP_HIGH will lead to strange effects if the bit is not checked.