Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm, show_mem: suppress page counts in non-blockable contexts

On large systems with a lot of memory, walking all RAM to determine page
types may take a half second or even more.

In non-blockable contexts, the page allocator will emit a page allocation
failure warning unless __GFP_NOWARN is specified. In such contexts, irqs
are typically disabled and such a lengthy delay may even result in NMI
watchdog timeouts.

To fix this, suppress the page walk in such contexts when printing the
page allocation failure warning.

Signed-off-by: David Rientjes <rientjes@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Dave Hansen <dave@linux.vnet.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Rientjes and committed by
Linus Torvalds
4b59e6c4 fe0bfaaf

+24 -1
+3
arch/arm/mm/init.c
··· 99 99 printk("Mem-info:\n"); 100 100 show_free_areas(filter); 101 101 102 + if (filter & SHOW_MEM_FILTER_PAGE_COUNT) 103 + return; 104 + 102 105 for_each_bank (i, mi) { 103 106 struct membank *bank = &mi->bank[i]; 104 107 unsigned int pfn1, pfn2;
+2
arch/ia64/mm/contig.c
··· 47 47 printk(KERN_INFO "Mem-info:\n"); 48 48 show_free_areas(filter); 49 49 printk(KERN_INFO "Node memory in pages:\n"); 50 + if (filter & SHOW_MEM_FILTER_PAGE_COUNT) 51 + return; 50 52 for_each_online_pgdat(pgdat) { 51 53 unsigned long present; 52 54 unsigned long flags;
+2
arch/ia64/mm/discontig.c
··· 623 623 624 624 printk(KERN_INFO "Mem-info:\n"); 625 625 show_free_areas(filter); 626 + if (filter & SHOW_MEM_FILTER_PAGE_COUNT) 627 + return; 626 628 printk(KERN_INFO "Node memory in pages:\n"); 627 629 for_each_online_pgdat(pgdat) { 628 630 unsigned long present;
+2
arch/parisc/mm/init.c
··· 697 697 698 698 printk(KERN_INFO "Mem-info:\n"); 699 699 show_free_areas(filter); 700 + if (filter & SHOW_MEM_FILTER_PAGE_COUNT) 701 + return; 700 702 #ifndef CONFIG_DISCONTIGMEM 701 703 i = max_mapnr; 702 704 while (i-- > 0) {
+3
arch/unicore32/mm/init.c
··· 66 66 printk(KERN_DEFAULT "Mem-info:\n"); 67 67 show_free_areas(filter); 68 68 69 + if (filter & SHOW_MEM_FILTER_PAGE_COUNT) 70 + return; 71 + 69 72 for_each_bank(i, mi) { 70 73 struct membank *bank = &mi->bank[i]; 71 74 unsigned int pfn1, pfn2;
+2 -1
include/linux/mm.h
··· 899 899 * Flags passed to show_mem() and show_free_areas() to suppress output in 900 900 * various contexts. 901 901 */ 902 - #define SHOW_MEM_FILTER_NODES (0x0001u) /* filter disallowed nodes */ 902 + #define SHOW_MEM_FILTER_NODES (0x0001u) /* disallowed nodes */ 903 + #define SHOW_MEM_FILTER_PAGE_COUNT (0x0002u) /* page type count */ 903 904 904 905 extern void show_free_areas(unsigned int flags); 905 906 extern bool skip_free_areas_node(unsigned int flags, int nid);
+3
lib/show_mem.c
··· 18 18 printk("Mem-Info:\n"); 19 19 show_free_areas(filter); 20 20 21 + if (filter & SHOW_MEM_FILTER_PAGE_COUNT) 22 + return; 23 + 21 24 for_each_online_pgdat(pgdat) { 22 25 unsigned long i, flags; 23 26
+7
mm/page_alloc.c
··· 2003 2003 return; 2004 2004 2005 2005 /* 2006 + * Walking all memory to count page types is very expensive and should 2007 + * be inhibited in non-blockable contexts. 2008 + */ 2009 + if (!(gfp_mask & __GFP_WAIT)) 2010 + filter |= SHOW_MEM_FILTER_PAGE_COUNT; 2011 + 2012 + /* 2006 2013 * This documents exceptions given to allocations in certain 2007 2014 * contexts that are allowed to allocate outside current's set 2008 2015 * of allowed nodes.