[vz7] net/sctp: Suppress high order allocation warning

Submitted by Oleg Babin on March 26, 2018, 10:03 a.m.

Details

Message ID 1522058589-491308-1-git-send-email-obabin@virtuozzo.com
State New
Series "net/sctp: Suppress high order allocation warning"
Headers show

Commit Message

Oleg Babin March 26, 2018, 10:03 a.m.
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@virtuozzo.com>
---
 include/linux/gfp.h | 3 +++
 mm/page_alloc.c     | 4 +++-
 net/sctp/ssnmap.c   | 2 +-
 3 files changed, 7 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index ec5ae8a..a6f000f 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 15575b2..8cc264c 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 da86035..989e1e8 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));