[Devel] [PATCH RHEL COMMIT] mm: add warning about high order allocations

Konstantin Khorenko khorenko at virtuozzo.com
Thu Sep 30 16:03:49 MSK 2021


The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after ark-5.14
------>
commit 560f7380ac26fdcfefbb166dcf21a750fd72e6d9
Author: Andrey Ryabinin <ryabinin.a.a at gmail.com>
Date:   Thu Sep 30 16:03:48 2021 +0300

    mm: add warning about high order allocations
    
    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 55b2ec1f965a..39de4eb1190d 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -55,8 +55,9 @@ struct vm_area_struct;
 #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 @@ struct vm_area_struct;
  * %__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 99dabb3a64e7..7244a1d1f2b8 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -166,6 +166,10 @@ int sysctl ## _virtual(struct ctl_table *table, int write,			\
 	return -EINVAL;								\
 }
 
+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
 
 /**
@@ -3224,6 +3228,15 @@ static struct ctl_table vm_table[] = {
 		.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 07512b81aa2e..710e60eaa581 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;


More information about the Devel mailing list