[Devel] [PATCH RHEL7 COMMIT] net/sctp: Suppress high order allocation warning

Konstantin Khorenko khorenko at virtuozzo.com
Mon Apr 2 17:34:38 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-693.21.1.vz7.46.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.21.1.vz7.46.2
------>
commit 2f98c3fcb08a028de56103d6251ebefd2f611d7f
Author: Oleg Babin <obabin at virtuozzo.com>
Date:   Mon Apr 2 17:34:38 2018 +0300

    net/sctp: Suppress high order allocation warning
    
    SCTP protocol allocates TCB on INIT and COOKIE ECHO chunks, those
    chunks specify input and output stream count (can be up to 65535
    each), so the size of TCB depends on these values and can include
    up to 65535 * 2 * 2 bytes describing input/output streams (2 bytes
    per each stream), i.e. up to seventh order.
    
    As the chunks are handled in softirq context, allocation is made
    with kmalloc() with GFP_ATOMIC flag, so we can't just replace
    kmalloc() call with kvmalloc().
    
    So it was decided to introduce our own flag __GFP_NOWARNHIGHORDER
    and update warn_high_order() function accordingly so that we could
    selectively suppress high order warnings which can not be fixed
    right now without proper algorithm refactoring.
    
    https://jira.sw.ru/browse/PSBM-82552
    Signed-off-by: Oleg Babin <obabin at virtuozzo.com>
---
 include/linux/gfp.h | 3 +++
 mm/page_alloc.c     | 4 +++-
 net/sctp/ssnmap.c   | 2 +-
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index ec5ae8aa1085..a6f000f3702a 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -41,6 +41,7 @@ struct vm_area_struct;
 #define ___GFP_NO_KSWAPD	0x400000u
 #define ___GFP_OTHER_NODE	0x800000u
 #define ___GFP_WRITE		0x1000000u
+#define ___GFP_NOWARNHIGHORDER	0x2000000u
 /* If the above are modified, __GFP_BITS_SHIFT may need updating */
 
 /*
@@ -98,6 +99,8 @@ struct vm_area_struct;
 #define __GFP_NO_KSWAPD	((__force gfp_t)___GFP_NO_KSWAPD)
 #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */
 #define __GFP_WRITE	((__force gfp_t)___GFP_WRITE)	/* Allocator intends to dirty page */
+#define __GFP_NOWARNHIGHORDER ((__force gfp_t)___GFP_NOWARNHIGHORDER) /* Don't warn
+							 * on high order allocations */
 
 /*
  * This may seem redundant, but it's a way of annotating false positives vs.
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 15575b24a97c..8cc264c56fb2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3184,6 +3184,8 @@ int proc_warn_high_order(struct ctl_table *table, int write,
 	return ret;
 }
 
+#define ORDER_NOWARN_MASK (__GFP_NOWARN | __GFP_NOWARNHIGHORDER)
+
 static __always_inline void warn_high_order(int order, gfp_t gfp_mask)
 {
 	static atomic_t warn_count = ATOMIC_INIT(32);
@@ -3191,7 +3193,7 @@ static __always_inline void warn_high_order(int order, gfp_t gfp_mask)
 	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))
+		if (order >= tmp_warn_order && !(gfp_mask & ORDER_NOWARN_MASK))
 			WARN(atomic_dec_if_positive(&warn_count) >= 0,
 				"order %d >= %d, gfp 0x%x\n",
 				order, tmp_warn_order, gfp_mask);
diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c
index da8603523808..989e1e8b4569 100644
--- a/net/sctp/ssnmap.c
+++ b/net/sctp/ssnmap.c
@@ -64,7 +64,7 @@ struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out,
 
 	size = sctp_ssnmap_size(in, out);
 	if (size <= KMALLOC_MAX_SIZE)
-		retval = kmalloc(size, gfp);
+		retval = kmalloc(size, gfp | __GFP_NOWARNHIGHORDER);
 	else
 		retval = (struct sctp_ssnmap *)
 			  __get_free_pages(gfp, get_order(size));


More information about the Devel mailing list