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 <aryabi...@virtuozzo.com>
---
 kernel/sysctl.c | 15 +++++++++++++++
 mm/page_alloc.c | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index e2d83c602b01..1de17f161be3 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -128,6 +128,7 @@ static int __maybe_unused one = 1;
 static int __maybe_unused two = 2;
 static int __maybe_unused four = 4;
 static unsigned long one_ul = 1;
+static int ten = 10;
 static int one_hundred = 100;
 #ifdef CONFIG_PRINTK
 static int ten_thousand = 10000;
@@ -174,6 +175,11 @@ extern int unaligned_dump_stack;
 extern int no_unaligned_warning;
 #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);
+
+
 static bool virtual_ptr(void **ptr, void *base, size_t size, void *cur);
 #define sysctl_virtual(sysctl)                                                 
\
 int sysctl ## _virtual(struct ctl_table *table, int write,                     
\
@@ -1664,6 +1670,15 @@ static struct ctl_table vm_table[] = {
                .extra2         = &one_hundred,
        },
 #endif
+       {
+               .procname       = "warn_high_order",
+               .data           = &warn_order,
+               .maxlen         = sizeof(warn_order),
+               .mode           = 0644,
+               .proc_handler   = &proc_warn_high_order,
+               .extra1         = &zero,
+               .extra2         = &ten,
+       },
        { }
 };
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 6f7cb012508e..e0a390866d4f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3138,6 +3138,37 @@ static void __alloc_collect_stats(gfp_t gfp_mask, 
unsigned int order,
 #endif
 }
 
+struct static_key warn_high_order_key = STATIC_KEY_INIT_FALSE;
+int warn_order = MAX_ORDER+1;
+
+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))
+                       WARN(atomic_dec_return(&warn_count),
+                               "order %d >= %d, gfp 0x%x\n",
+                               order, tmp_warn_order, gfp_mask);
+       }
+}
+
 /*
  * This is the 'heart' of the zoned buddy allocator.
  */
@@ -3161,6 +3192,8 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
        WARN_ON_ONCE((gfp_mask & __GFP_FS) && current->journal_info &&
                !(current->flags & PF_MEMALLOC));
 
+       warn_high_order(order, gfp_mask);
+
        if (should_fail_alloc_page(gfp_mask, order))
                return NULL;
 
-- 
2.13.6

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to