[Devel] [PATCH RH9 02/30] mm: add warning about high order allocations

Andrey Zhadchenko andrey.zhadchenko at virtuozzo.com
Tue Sep 28 21:48:53 MSK 2021


From: Andrey Ryabinin <aryabinin at virtuozzo.com>

Add sysctl vm.warn_high_order. If set it will warn about
about allocations with order >= vm.warn_high_order.
Prints only 32 warning at most and skips all __GFP_NOWARN allocations.
Disabled by default.

https://jira.sw.ru/browse/PSBM-79892
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

+++
mm: fix high order allocation warning limits

After sysctl parameter 'vm.warn_high_order' is modified it can't be
returned back to the default value MAX_ORDER+1, only to the fixed
value 10.

Set the maximum value to 100 which is always larger than any maximum
order. Also set the default value to MAX_ORDER as it is already the
value which can never be allocated.

Also there is a logic to stop generating the warning after 32 occurences,
but the logic is broken (the warning is generated even after the counter
becomes less than zero). Modify the procedure of checking the counter.

mFixes: 1ab81385c03f ("mm: add warning about high order allocations")

https://jira.sw.ru/browse/PSBM-82202

Signed-off-by: Oleg Babin <obabin at virtuozzo.com>
Acked-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

https://jira.sw.ru/browse/PSBM-103814

(cherry picked from commit d853914118665ae6fe7b87bd4702215ba6f5daef)
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

+++
mm: add __GFP_ flag to hide verified high order allocation warnings

Using __GFP_NOWARN to hide known high order allocation warnings
is not the best solution as it supresses allocation failures as well,
so let's add an independent __GFP_ORDER_NOWARN flag for that.

mFixes: 22b422587aab mm: add warning about high order allocations

https://pmc.acronis.com/browse/VSTOR-20383
https://pmc.acronis.com/browse/VSTOR-20349

Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

https://jira.sw.ru/browse/PSBM-103814

(cherry picked from commit 66f0d9c1678847ee476af8d511839728d144c83b)
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

(cherry picked from vz8 commit b536d715903644b3095ab2f935a205bca3af49da)
Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
---
 include/linux/gfp.h |  9 +++++++--
 kernel/sysctl.c     | 13 +++++++++++++
 mm/page_alloc.c     | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 55b2ec1..39de4eb 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -55,8 +55,9 @@
 #define ___GFP_ACCOUNT		0x400000u
 #define ___GFP_ZEROTAGS		0x800000u
 #define ___GFP_SKIP_KASAN_POISON	0x1000000u
+#define ___GFP_ORDER_NOWARN	0x2000000u
 #ifdef CONFIG_LOCKDEP
-#define ___GFP_NOLOCKDEP	0x2000000u
+#define ___GFP_NOLOCKDEP	0x4000000u
 #else
 #define ___GFP_NOLOCKDEP	0
 #endif
@@ -238,18 +239,22 @@
  * %__GFP_SKIP_KASAN_POISON returns a page which does not need to be poisoned
  * on deallocation. Typically used for userspace pages. Currently only has an
  * effect in HW tags mode.
+ *
+ * __GFP_ORDER_NOWARN suppresses reports about allocation of too high order
+ * pages.
  */
 #define __GFP_NOWARN	((__force gfp_t)___GFP_NOWARN)
 #define __GFP_COMP	((__force gfp_t)___GFP_COMP)
 #define __GFP_ZERO	((__force gfp_t)___GFP_ZERO)
 #define __GFP_ZEROTAGS	((__force gfp_t)___GFP_ZEROTAGS)
 #define __GFP_SKIP_KASAN_POISON	((__force gfp_t)___GFP_SKIP_KASAN_POISON)
+#define __GFP_ORDER_NOWARN ((__force gfp_t)___GFP_ORDER_NOWARN)
 
 /* Disable lockdep for GFP context tracking */
 #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP)
 
 /* Room for N __GFP_FOO bits */
-#define __GFP_BITS_SHIFT (25 + IS_ENABLED(CONFIG_LOCKDEP))
+#define __GFP_BITS_SHIFT (26 + IS_ENABLED(CONFIG_LOCKDEP))
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 
 /**
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 081e4217..65d57a4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -155,6 +155,10 @@
 #include <linux/fanotify.h>
 #endif
 
+extern int warn_order;
+extern int proc_warn_high_order(struct ctl_table *table, int write,
+			void __user *buffer, size_t *lenp, loff_t *ppos);
+
 #ifdef CONFIG_PROC_SYSCTL
 
 /**
@@ -3171,6 +3175,15 @@ int proc_do_static_key(struct ctl_table *table, int write,
 		.extra2		= SYSCTL_ONE,
 	},
 #endif
+	{
+		.procname       = "warn_high_order",
+		.data           = &warn_order,
+		.maxlen         = sizeof(warn_order),
+		.mode           = 0644,
+		.proc_handler   = &proc_warn_high_order,
+		.extra1         = SYSCTL_ONE,
+		.extra2         = &one_hundred,
+	},
 	{ }
 };
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 07512b8..710e60e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5346,6 +5346,38 @@ unsigned long __alloc_pages_bulk(gfp_t gfp, int preferred_nid,
 }
 EXPORT_SYMBOL_GPL(__alloc_pages_bulk);
 
+struct static_key warn_high_order_key = STATIC_KEY_INIT_FALSE;
+int warn_order = MAX_ORDER;
+
+int proc_warn_high_order(struct ctl_table *table, int write,
+			void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	int ret;
+
+	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+	if (!ret) {
+		smp_wmb();
+		static_key_slow_inc(&warn_high_order_key);
+	}
+
+	return ret;
+}
+
+static __always_inline void warn_high_order(int order, gfp_t gfp_mask)
+{
+	static atomic_t warn_count = ATOMIC_INIT(32);
+
+	if (static_key_false(&warn_high_order_key)) {
+		int tmp_warn_order = smp_load_acquire(&warn_order);
+
+		if (order >= tmp_warn_order &&
+		    !(gfp_mask & (__GFP_NOWARN|__GFP_ORDER_NOWARN)))
+			WARN(atomic_dec_if_positive(&warn_count) >= 0,
+				"order %d >= %d, gfp 0x%x\n",
+				order, tmp_warn_order, gfp_mask);
+	}
+}
+
 /*
  * This is the 'heart' of the zoned buddy allocator.
  */
@@ -5376,6 +5408,9 @@ struct page *__alloc_pages(gfp_t gfp, unsigned int order, int preferred_nid,
 	 */
 	gfp = current_gfp_context(gfp);
 	alloc_gfp = gfp;
+
+	warn_high_order(order, gfp);
+
 	if (!prepare_alloc_pages(gfp, order, preferred_nid, nodemask, &ac,
 			&alloc_gfp, &alloc_flags))
 		return NULL;
-- 
1.8.3.1



More information about the Devel mailing list