mm, page_alloc: extend kernelcore and movablecore for percent
authorDavid Rientjes <rientjes@google.com>
Thu, 5 Apr 2018 23:23:09 +0000 (16:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Apr 2018 04:36:25 +0000 (21:36 -0700)
Both kernelcore= and movablecore= can be used to define the amount of
ZONE_NORMAL and ZONE_MOVABLE on a system, respectively.  This requires
the system memory capacity to be known when specifying the command line,
however.

This introduces the ability to define both kernelcore= and movablecore=
as a percentage of total system memory.  This is convenient for systems
software that wants to define the amount of ZONE_MOVABLE, for example,
as a proportion of a system's memory rather than a hardcoded byte value.

To define the percentage, the final character of the parameter should be
a '%'.

mhocko: "why is anyone using these options nowadays?"

rientjes:
:
: Fragmentation of non-__GFP_MOVABLE pages due to low on memory
: situations can pollute most pageblocks on the system, as much as 1GB of
: slab being fragmented over 128GB of memory, for example.  When the
: amount of kernel memory is well bounded for certain systems, it is
: better to aggressively reclaim from existing MIGRATE_UNMOVABLE
: pageblocks rather than eagerly fallback to others.
:
: We have additional patches that help with this fragmentation if you're
: interested, specifically kcompactd compaction of MIGRATE_UNMOVABLE
: pageblocks triggered by fallback of non-__GFP_MOVABLE allocations and
: draining of pcp lists back to the zone free area to prevent stranding.

[rientjes@google.com: updates]
Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1802131700160.71590@chino.kir.corp.google.com
Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1802121622470.179479@chino.kir.corp.google.com
Signed-off-by: David Rientjes <rientjes@google.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mel Gorman <mgorman@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Documentation/admin-guide/kernel-parameters.txt
mm/page_alloc.c

index 5ffe4c4121bda1f2b33ae94bf2af71cfe02e1c4d..7993021a1f6e317787943cc087797c7bbf36e736 100644 (file)
        keepinitrd      [HW,ARM]
 
        kernelcore=     [KNL,X86,IA-64,PPC]
-                       Format: nn[KMGTPE] | "mirror"
-                       This parameter
-                       specifies the amount of memory usable by the kernel
-                       for non-movable allocations.  The requested amount is
-                       spread evenly throughout all nodes in the system. The
-                       remaining memory in each node is used for Movable
-                       pages. In the event, a node is too small to have both
-                       kernelcore and Movable pages, kernelcore pages will
-                       take priority and other nodes will have a larger number
-                       of Movable pages.  The Movable zone is used for the
-                       allocation of pages that may be reclaimed or moved
-                       by the page migration subsystem.  This means that
-                       HugeTLB pages may not be allocated from this zone.
-                       Note that allocations like PTEs-from-HighMem still
-                       use the HighMem zone if it exists, and the Normal
+                       Format: nn[KMGTPE] | nn% | "mirror"
+                       This parameter specifies the amount of memory usable by
+                       the kernel for non-movable allocations.  The requested
+                       amount is spread evenly throughout all nodes in the
+                       system as ZONE_NORMAL.  The remaining memory is used for
+                       movable memory in its own zone, ZONE_MOVABLE.  In the
+                       event, a node is too small to have both ZONE_NORMAL and
+                       ZONE_MOVABLE, kernelcore memory will take priority and
+                       other nodes will have a larger ZONE_MOVABLE.
+
+                       ZONE_MOVABLE is used for the allocation of pages that
+                       may be reclaimed or moved by the page migration
+                       subsystem.  Note that allocations like PTEs-from-HighMem
+                       still use the HighMem zone if it exists, and the Normal
                        zone if it does not.
 
-                       Instead of specifying the amount of memory (nn[KMGTPE]),
-                       you can specify "mirror" option. In case "mirror"
+                       It is possible to specify the exact amount of memory in
+                       the form of "nn[KMGTPE]", a percentage of total system
+                       memory in the form of "nn%", or "mirror".  If "mirror"
                        option is specified, mirrored (reliable) memory is used
                        for non-movable allocations and remaining memory is used
-                       for Movable pages. nn[KMGTPE] and "mirror" are exclusive,
-                       so you can NOT specify nn[KMGTPE] and "mirror" at the same
-                       time.
+                       for Movable pages.  "nn[KMGTPE]", "nn%", and "mirror"
+                       are exclusive, so you cannot specify multiple forms.
 
        kgdbdbgp=       [KGDB,HW] kgdb over EHCI usb debug port.
                        Format: <Controller#>[,poll interval]
        mousedev.yres=  [MOUSE] Vertical screen resolution, used for devices
                        reporting absolute coordinates, such as tablets
 
-       movablecore=nn[KMG]     [KNL,X86,IA-64,PPC] This parameter
-                       is similar to kernelcore except it specifies the
-                       amount of memory used for migratable allocations.
-                       If both kernelcore and movablecore is specified,
-                       then kernelcore will be at *least* the specified
-                       value but may be more. If movablecore on its own
-                       is specified, the administrator must be careful
+       movablecore=    [KNL,X86,IA-64,PPC]
+                       Format: nn[KMGTPE] | nn%
+                       This parameter is the complement to kernelcore=, it
+                       specifies the amount of memory used for migratable
+                       allocations.  If both kernelcore and movablecore is
+                       specified, then kernelcore will be at *least* the
+                       specified value but may be more.  If movablecore on its
+                       own is specified, the administrator must be careful
                        that the amount of memory usable for all allocations
                        is not too small.
 
index a3e2ba4f76bb83864e0666f20d6b9da10dc2c7d9..766ffb5fa94bc118124bfd9aff3c052a128c1d72 100644 (file)
@@ -273,7 +273,9 @@ static unsigned long __meminitdata dma_reserve;
 static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
 static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
 static unsigned long __initdata required_kernelcore;
+static unsigned long required_kernelcore_percent __initdata;
 static unsigned long __initdata required_movablecore;
+static unsigned long required_movablecore_percent __initdata;
 static unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
 static bool mirrored_kernelcore;
 
@@ -6571,7 +6573,18 @@ static void __init find_zone_movable_pfns_for_nodes(void)
        }
 
        /*
-        * If movablecore=nn[KMG] was specified, calculate what size of
+        * If kernelcore=nn% or movablecore=nn% was specified, calculate the
+        * amount of necessary memory.
+        */
+       if (required_kernelcore_percent)
+               required_kernelcore = (totalpages * 100 * required_kernelcore_percent) /
+                                      10000UL;
+       if (required_movablecore_percent)
+               required_movablecore = (totalpages * 100 * required_movablecore_percent) /
+                                       10000UL;
+
+       /*
+        * If movablecore= was specified, calculate what size of
         * kernelcore that corresponds so that memory usable for
         * any allocation type is evenly spread. If both kernelcore
         * and movablecore are specified, then the value of kernelcore
@@ -6811,18 +6824,30 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
        zero_resv_unavail();
 }
 
-static int __init cmdline_parse_core(char *p, unsigned long *core)
+static int __init cmdline_parse_core(char *p, unsigned long *core,
+                                    unsigned long *percent)
 {
        unsigned long long coremem;
+       char *endptr;
+
        if (!p)
                return -EINVAL;
 
-       coremem = memparse(p, &p);
-       *core = coremem >> PAGE_SHIFT;
+       /* Value may be a percentage of total memory, otherwise bytes */
+       coremem = simple_strtoull(p, &endptr, 0);
+       if (*endptr == '%') {
+               /* Paranoid check for percent values greater than 100 */
+               WARN_ON(coremem > 100);
 
-       /* Paranoid check that UL is enough for the coremem value */
-       WARN_ON((coremem >> PAGE_SHIFT) > ULONG_MAX);
+               *percent = coremem;
+       } else {
+               coremem = memparse(p, &p);
+               /* Paranoid check that UL is enough for the coremem value */
+               WARN_ON((coremem >> PAGE_SHIFT) > ULONG_MAX);
 
+               *core = coremem >> PAGE_SHIFT;
+               *percent = 0UL;
+       }
        return 0;
 }
 
@@ -6838,7 +6863,8 @@ static int __init cmdline_parse_kernelcore(char *p)
                return 0;
        }
 
-       return cmdline_parse_core(p, &required_kernelcore);
+       return cmdline_parse_core(p, &required_kernelcore,
+                                 &required_kernelcore_percent);
 }
 
 /*
@@ -6847,7 +6873,8 @@ static int __init cmdline_parse_kernelcore(char *p)
  */
 static int __init cmdline_parse_movablecore(char *p)
 {
-       return cmdline_parse_core(p, &required_movablecore);
+       return cmdline_parse_core(p, &required_movablecore,
+                                 &required_movablecore_percent);
 }
 
 early_param("kernelcore", cmdline_parse_kernelcore);