lib/show_mem.c: teach show_mem to work with the given nodemask
authorMichal Hocko <mhocko@suse.com>
Wed, 22 Feb 2017 23:46:16 +0000 (15:46 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Feb 2017 00:41:30 +0000 (16:41 -0800)
show_mem() allows to filter out node specific data which is irrelevant
to the allocation request via SHOW_MEM_FILTER_NODES.  The filtering is
done in skip_free_areas_node which skips all nodes which are not in the
mems_allowed of the current process.  This works most of the time as
expected because the nodemask shouldn't be outside of the allocating
task but there are some exceptions.  E.g.  memory hotplug might want to
request allocations from outside of the allowed nodes (see
new_node_page).

Get rid of this hardcoded behavior and push the allocation mask down the
show_mem path and use it instead of cpuset_current_mems_allowed.  NULL
nodemask is interpreted as cpuset_current_mems_allowed.

[akpm@linux-foundation.org: coding-style fixes]
Link: http://lkml.kernel.org/r/20170117091543.25850-5-mhocko@kernel.org
Signed-off-by: Michal Hocko <mhocko@suse.com>
Acked-by: Mel Gorman <mgorman@suse.de>
Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/powerpc/xmon/xmon.c
arch/sparc/kernel/setup_32.c
drivers/net/ethernet/sgi/ioc3-eth.c
drivers/tty/sysrq.c
drivers/tty/vt/keyboard.c
include/linux/mm.h
lib/show_mem.c
mm/nommu.c
mm/oom_kill.c
mm/page_alloc.c

index 1be0499f53975b84e72c560db120dc3ef25a7b35..5720236d02662a175b174ca68a70dfe2b24427cc 100644 (file)
@@ -916,7 +916,7 @@ cmds(struct pt_regs *excp)
                                memzcan();
                                break;
                        case 'i':
-                               show_mem(0);
+                               show_mem(0, NULL);
                                break;
                        default:
                                termch = cmd;
index c4e65cb3280f8ec88da17c2e8cb8ef95252eef9c..6f06058c5ae72a80c71de217c3c105cfe7a08b18 100644 (file)
@@ -82,7 +82,7 @@ static void prom_sync_me(void)
                             "nop\n\t" : : "r" (&trapbase));
 
        prom_printf("PROM SYNC COMMAND...\n");
-       show_free_areas(0);
+       show_free_areas(0, NULL);
        if (!is_idle_task(current)) {
                local_irq_enable();
                sys_sync();
index d390b9663dc32c9ee44393765235cb214150717c..57e6cef81ebec9d566a860424f4f83d7bb602663 100644 (file)
@@ -914,7 +914,7 @@ static void ioc3_alloc_rings(struct net_device *dev)
 
                        skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
                        if (!skb) {
-                               show_free_areas(0);
+                               show_free_areas(0, NULL);
                                continue;
                        }
 
index 701c085bb19b8e03f67316133fa5a4be7e0b05fe..71136742e606b96e4900acf976159923793b87aa 100644 (file)
@@ -317,7 +317,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = {
 
 static void sysrq_handle_showmem(int key)
 {
-       show_mem(0);
+       show_mem(0, NULL);
 }
 static struct sysrq_key_op sysrq_showmem_op = {
        .handler        = sysrq_handle_showmem,
index 3dd6a491cdba536520014d5861306cfd7dac42c2..397e1509fe51cce593b60e555530aedc7bffda33 100644 (file)
@@ -572,7 +572,7 @@ static void fn_scroll_back(struct vc_data *vc)
 
 static void fn_show_mem(struct vc_data *vc)
 {
-       show_mem(0);
+       show_mem(0, NULL);
 }
 
 static void fn_show_state(struct vc_data *vc)
index 28b6c3f8a7f3846f20105e6303d6c9219a514e1b..8a67cae5a07c092a7cac2c6b22b5129d26ec1380 100644 (file)
@@ -1152,8 +1152,7 @@ extern void pagefault_out_of_memory(void);
  */
 #define SHOW_MEM_FILTER_NODES          (0x0001u)       /* disallowed nodes */
 
-extern void show_free_areas(unsigned int flags);
-extern bool skip_free_areas_node(unsigned int flags, int nid);
+extern void show_free_areas(unsigned int flags, nodemask_t *nodemask);
 
 int shmem_zero_setup(struct vm_area_struct *);
 #ifdef CONFIG_SHMEM
@@ -1934,7 +1933,7 @@ extern void setup_per_zone_wmarks(void);
 extern int __meminit init_per_zone_wmark_min(void);
 extern void mem_init(void);
 extern void __init mmap_init(void);
-extern void show_mem(unsigned int flags);
+extern void show_mem(unsigned int flags, nodemask_t *nodemask);
 extern long si_mem_available(void);
 extern void si_meminfo(struct sysinfo * val);
 extern void si_meminfo_node(struct sysinfo *val, int nid);
index 1feed6a2b12ae6abe2750b18adfa0d4c34327b96..0beaa1d899aae5b962410b4ca1b708181fb6cb32 100644 (file)
@@ -9,13 +9,13 @@
 #include <linux/quicklist.h>
 #include <linux/cma.h>
 
-void show_mem(unsigned int filter)
+void show_mem(unsigned int filter, nodemask_t *nodemask)
 {
        pg_data_t *pgdat;
        unsigned long total = 0, reserved = 0, highmem = 0;
 
        printk("Mem-Info:\n");
-       show_free_areas(filter);
+       show_free_areas(filter, nodemask);
 
        for_each_online_pgdat(pgdat) {
                unsigned long flags;
index 24f9f5f391459201f8c07c74f3afb931f716791b..bc964c26be8c1a47f70ed3c639a5bb58e698d8e1 100644 (file)
@@ -1191,7 +1191,7 @@ error_free:
 enomem:
        pr_err("Allocation of length %lu from process %d (%s) failed\n",
               len, current->pid, current->comm);
-       show_free_areas(0);
+       show_free_areas(0, NULL);
        return -ENOMEM;
 }
 
@@ -1412,13 +1412,13 @@ error_getting_vma:
        kmem_cache_free(vm_region_jar, region);
        pr_warn("Allocation of vma for %lu byte allocation from process %d failed\n",
                        len, current->pid);
-       show_free_areas(0);
+       show_free_areas(0, NULL);
        return -ENOMEM;
 
 error_getting_region:
        pr_warn("Allocation of vm region for %lu byte allocation from process %d failed\n",
                        len, current->pid);
-       show_free_areas(0);
+       show_free_areas(0, NULL);
        return -ENOMEM;
 }
 
index ec9f11d4f094467e98b8190b7195379174d6be0a..7176b6a754cf4fe068d18aa1d926cbe06872b250 100644 (file)
@@ -417,7 +417,7 @@ static void dump_header(struct oom_control *oc, struct task_struct *p)
        if (oc->memcg)
                mem_cgroup_print_oom_info(oc->memcg, p);
        else
-               show_mem(SHOW_MEM_FILTER_NODES);
+               show_mem(SHOW_MEM_FILTER_NODES, nm);
        if (sysctl_oom_dump_tasks)
                dump_tasks(oc->memcg, oc->nodemask);
 }
index 96c8fe602dfbe1ee8394969d59c1c560b26284bb..644fb75f6f24c1f3e2466091e673a7a201f4ed78 100644 (file)
@@ -3005,7 +3005,7 @@ static inline bool should_suppress_show_mem(void)
        return ret;
 }
 
-static void warn_alloc_show_mem(gfp_t gfp_mask)
+static void warn_alloc_show_mem(gfp_t gfp_mask, nodemask_t *nodemask)
 {
        unsigned int filter = SHOW_MEM_FILTER_NODES;
        static DEFINE_RATELIMIT_STATE(show_mem_rs, HZ, 1);
@@ -3025,7 +3025,7 @@ static void warn_alloc_show_mem(gfp_t gfp_mask)
        if (in_interrupt() || !(gfp_mask & __GFP_DIRECT_RECLAIM))
                filter &= ~SHOW_MEM_FILTER_NODES;
 
-       show_mem(filter);
+       show_mem(filter, nodemask);
 }
 
 void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...)
@@ -3052,7 +3052,7 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...)
        cpuset_print_current_mems_allowed();
 
        dump_stack();
-       warn_alloc_show_mem(gfp_mask);
+       warn_alloc_show_mem(gfp_mask, nm);
 }
 
 static inline struct page *
@@ -4274,20 +4274,20 @@ void si_meminfo_node(struct sysinfo *val, int nid)
  * Determine whether the node should be displayed or not, depending on whether
  * SHOW_MEM_FILTER_NODES was passed to show_free_areas().
  */
-bool skip_free_areas_node(unsigned int flags, int nid)
+static bool show_mem_node_skip(unsigned int flags, int nid, nodemask_t *nodemask)
 {
-       bool ret = false;
-       unsigned int cpuset_mems_cookie;
-
        if (!(flags & SHOW_MEM_FILTER_NODES))
-               goto out;
+               return false;
 
-       do {
-               cpuset_mems_cookie = read_mems_allowed_begin();
-               ret = !node_isset(nid, cpuset_current_mems_allowed);
-       } while (read_mems_allowed_retry(cpuset_mems_cookie));
-out:
-       return ret;
+       /*
+        * no node mask - aka implicit memory numa policy. Do not bother with
+        * the synchronization - read_mems_allowed_begin - because we do not
+        * have to be precise here.
+        */
+       if (!nodemask)
+               nodemask = &cpuset_current_mems_allowed;
+
+       return !node_isset(nid, *nodemask);
 }
 
 #define K(x) ((x) << (PAGE_SHIFT-10))
@@ -4328,7 +4328,7 @@ static void show_migration_types(unsigned char type)
  * SHOW_MEM_FILTER_NODES: suppress nodes that are not allowed by current's
  *   cpuset.
  */
-void show_free_areas(unsigned int filter)
+void show_free_areas(unsigned int filter, nodemask_t *nodemask)
 {
        unsigned long free_pcp = 0;
        int cpu;
@@ -4336,7 +4336,7 @@ void show_free_areas(unsigned int filter)
        pg_data_t *pgdat;
 
        for_each_populated_zone(zone) {
-               if (skip_free_areas_node(filter, zone_to_nid(zone)))
+               if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask))
                        continue;
 
                for_each_online_cpu(cpu)
@@ -4370,7 +4370,7 @@ void show_free_areas(unsigned int filter)
                global_page_state(NR_FREE_CMA_PAGES));
 
        for_each_online_pgdat(pgdat) {
-               if (skip_free_areas_node(filter, pgdat->node_id))
+               if (show_mem_node_skip(filter, pgdat->node_id, nodemask))
                        continue;
 
                printk("Node %d"
@@ -4422,7 +4422,7 @@ void show_free_areas(unsigned int filter)
        for_each_populated_zone(zone) {
                int i;
 
-               if (skip_free_areas_node(filter, zone_to_nid(zone)))
+               if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask))
                        continue;
 
                free_pcp = 0;
@@ -4487,7 +4487,7 @@ void show_free_areas(unsigned int filter)
                unsigned long nr[MAX_ORDER], flags, total = 0;
                unsigned char types[MAX_ORDER];
 
-               if (skip_free_areas_node(filter, zone_to_nid(zone)))
+               if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask))
                        continue;
                show_node(zone);
                printk(KERN_CONT "%s: ", zone->name);