Skip to contentSkip to conversation

mm/khugepaged: cap min_free_kbytes recommendation at 1 GiB

PATCH Superseded Nimrod Oren 3 participants 4 messages Jul 28 – Aug 7

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mm/khugepaged: cap min_free_kbytes recommendation at 1 GiB

When THP is enabled, set_recommended_min_free_kbytes() may raise min_free_kbytes using a heuristic that scales with pageblock_nr_pages. With MIGRATE_PCPTYPES equal to 3, the formula accounts for 11 pageblocks for every eligible populated zone before capping the result at 5% of low memory.

This is reasonable when a pageblock is 2 MiB, as on common 4 KiB page configurations, but scales poorly with larger base page sizes. With the default arm64 pageblock sizes, the contribution per eligible zone before the 5% cap is:

4 KiB pages: 2 MiB pageblock, 22 MiB per zone
16 KiB pages: 32 MiB pageblock, 352 MiB per zone 64 KiB pages: 512 MiB pageblock, 5.5 GiB per zone

Consequently, min_free_kbytes can reach excessive and unwanted levels.

Add an absolute 1 GiB cap to the recommendation, in addition to the existing percentage cap. This bounds the automatic recommendation to a sane value on systems with large pageblocks while preserving existing behavior for typical systems with 2 MiB pageblocks.

---
v1:
* Cap the final recommendation at 1 GiB as suggested by Lorenzo.

RFC v1:
https://lore.kernel.org/r/[email protected]/

---
 mm/khugepaged.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
mm/khugepaged.c +6 -1
index 27e8f3077e80..d9caf10e05b5 100644
@@ -23,6 +23,7 @@
 #include <linux/ksm.h>
 #include <linux/pgalloc.h>
 #include <linux/backing-dev.h>
+#include <linux/sizes.h>
 
 #include <asm/tlb.h>
 #include "internal.h"
@@ -3096,9 +3097,13 @@ void set_recommended_min_free_kbytes(void)
 	recommended_min += pageblock_nr_pages * nr_zones *
 			   MIGRATE_PCPTYPES * MIGRATE_PCPTYPES;
 
-	/* don't ever allow to reserve more than 5% of the lowmem */
+	/*
+	 * Don't ever allow to reserve more than 5% of lowmem or 1 GiB,
+	 * whichever is smaller.
+	 */
 	recommended_min = min(recommended_min,
 			      (unsigned long) nr_free_buffer_pages() / 20);
+	recommended_min = min(recommended_min, SZ_1G / PAGE_SIZE);
 	recommended_min <<= (PAGE_SHIFT-10);
 
 	if (recommended_min > min_free_kbytes) {
Signature · 1 line
2.45.0
maintainer
#1 lore raw
Quoted 15 lines · On Tue, 28 Jul 2026 23:20:14 +0300 Nimrod Oren <[email protected]> wrote:

When THP is enabled, set_recommended_min_free_kbytes() may raise min_free_kbytes using a heuristic that scales with pageblock_nr_pages. With MIGRATE_PCPTYPES equal to 3, the formula accounts for 11 pageblocks for every eligible populated zone before capping the result at 5% of low memory.

This is reasonable when a pageblock is 2 MiB, as on common 4 KiB page configurations, but scales poorly with larger base page sizes. With the default arm64 pageblock sizes, the contribution per eligible zone before the 5% cap is:

4 KiB pages: 2 MiB pageblock, 22 MiB per zone
16 KiB pages: 32 MiB pageblock, 352 MiB per zone 64 KiB pages: 512 MiB pageblock, 5.5 GiB per zone

Quoted 6 lines

Consequently, min_free_kbytes can reach excessive and unwanted levels.

Add an absolute 1 GiB cap to the recommendation, in addition to the existing percentage cap. This bounds the automatic recommendation to a sane value on systems with large pageblocks while preserving existing behavior for typical systems with 2 MiB pageblocks.

Another hard-coded number isn't pretty :(

Quoted 1 line
 mm/khugepaged.c | 7 ++++++-

Now, why is a page-allocator function sitting in khugepaged.c?

Perhaps to avoid a #ifdef CONFIG_TRANSPARENT_HUGEPAGE.

Or perhaps so that page-allocator maintainers don't get cc'ed on page-allocator patches ;)

mm/khugepaged.c line 26

Quoted 10 lines
mm/khugepaged.c +1 -0
index 27e8f3077e80..d9caf10e05b5 100644
@@ -23,6 +23,7 @@
 #include <linux/ksm.h>
 #include <linux/pgalloc.h>
 #include <linux/backing-dev.h>
+#include <linux/sizes.h>

Why this?

Quoted 7 lines
mm/khugepaged.c +0 -1
 #include <asm/tlb.h>
 #include "internal.h"
@@ -3096,9 +3097,13 @@ void set_recommended_min_free_kbytes(void)
 	recommended_min += pageblock_nr_pages * nr_zones *
 			   MIGRATE_PCPTYPES * MIGRATE_PCPTYPES;
 
-	/* don't ever allow to reserve more than 5% of the lowmem */

mm/khugepaged.c void set_recommended_min_free_kbytes(void) · line 3109

Quoted 10 lines
mm/khugepaged.c +5 -0
+	/*
+	 * Don't ever allow to reserve more than 5% of lowmem or 1 GiB,
+	 * whichever is smaller.
+	 */
 	recommended_min = min(recommended_min,
 			      (unsigned long) nr_free_buffer_pages() / 20);
+	recommended_min = min(recommended_min, SZ_1G / PAGE_SIZE);
 	recommended_min <<= (PAGE_SHIFT-10);
 
 	if (recommended_min > min_free_kbytes) {

Is a min_free_kbytes documentation update needed?
Documentation/admin-guide/sysctl/vm.rst.

#2 lore raw
Quoted 7 lines · Andrew Morton
Quoted 4 lines · On Tue, 28 Jul 2026 23:20:14 +0300 Nimrod Oren <[email protected]> wrote:

Add an absolute 1 GiB cap to the recommendation, in addition to the existing percentage cap. This bounds the automatic recommendation to a sane value on systems with large pageblocks while preserving existing behavior for typical systems with 2 MiB pageblocks.

Another hard-coded number isn't pretty :(

The 1 GiB value follows the RFC discussion.
Would a dedicated constant (e.g. THP_MIN_FREE_MAX_PAGES) make it better? Would using a new sysctl be preferable?

Quoted 11 lines

mm/khugepaged.c line 26

Quoted 9 lines
mm/khugepaged.c +1 -0
index 27e8f3077e80..d9caf10e05b5 100644
@@ -23,6 +23,7 @@
 #include <linux/ksm.h>
 #include <linux/pgalloc.h>
 #include <linux/backing-dev.h>
+#include <linux/sizes.h>

Why this?

For SZ_1G. It's already included transitively, so I'll drop it in the next revision.

Quoted 16 lines
Quoted 16 lines
mm/khugepaged.c +5 -1
 #include <asm/tlb.h>
 #include "internal.h"
@@ -3096,9 +3097,13 @@ void set_recommended_min_free_kbytes(void)
 	recommended_min += pageblock_nr_pages * nr_zones *
 			   MIGRATE_PCPTYPES * MIGRATE_PCPTYPES;
 
-	/* don't ever allow to reserve more than 5% of the lowmem */
+	/*
+	 * Don't ever allow to reserve more than 5% of lowmem or 1 GiB,
+	 * whichever is smaller.
+	 */
 	recommended_min = min(recommended_min,
 			      (unsigned long) nr_free_buffer_pages() / 20);
+	recommended_min = min(recommended_min, SZ_1G / PAGE_SIZE);
 	recommended_min <<= (PAGE_SHIFT-10);
 
Quoted 4 lines

mm/khugepaged.c void set_recommended_min_free_kbytes(void) · line 3109

Quoted 1 line
mm/khugepaged.c +0 -0
 	if (recommended_min > min_free_kbytes) {

Is a min_free_kbytes documentation update needed?
Documentation/admin-guide/sysctl/vm.rst.

I can document THP's automatic recommendation there in the next revision, along with whichever capping mechanism we decide on.

Thanks for the review!