With all hugetlb page processing done in a single file clean up code.
- Make code match desired semantics
  - Update documentation with semantics
- Make all warnings and errors messages start with 'HugeTLB:'.
- Consistently name command line parsing routines.
- Check for hugepages_supported() before processing parameters.
- Add comments to code
  - Describe some of the subtle interactions
  - Describe semantics of command line arguments

Signed-off-by: Mike Kravetz <mike.krav...@oracle.com>
---
 .../admin-guide/kernel-parameters.txt         | 35 ++++---
 Documentation/admin-guide/mm/hugetlbpage.rst  | 44 +++++++++
 mm/hugetlb.c                                  | 96 +++++++++++++++----
 3 files changed, 142 insertions(+), 33 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index 1bd5454b5e5f..de653cfe1726 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -832,12 +832,15 @@
                        See also Documentation/networking/decnet.txt.
 
        default_hugepagesz=
-                       [same as hugepagesz=] The size of the default
-                       HugeTLB page size. This is the size represented by
-                       the legacy /proc/ hugepages APIs, used for SHM, and
-                       default size when mounting hugetlbfs filesystems.
-                       Defaults to the default architecture's huge page size
-                       if not specified.
+                       [HW] The size of the default HugeTLB page size. This
+                       is the size represented by the legacy /proc/ hugepages
+                       APIs.  In addition, this is the default hugetlb size
+                       used for shmget(), mmap() and mounting hugetlbfs
+                       filesystems.  If not specified, defaults to the
+                       architecture's default huge page size.  Huge page
+                       sizes are architecture dependent.  See also
+                       Documentation/admin-guide/mm/hugetlbpage.rst.
+                       Format: size[KMG]
 
        deferred_probe_timeout=
                        [KNL] Debugging option to set a timeout in seconds for
@@ -1480,13 +1483,19 @@
                        If enabled, boot-time allocation of gigantic hugepages
                        is skipped.
 
-       hugepages=      [HW,X86-32,IA-64] HugeTLB pages to allocate at boot.
-       hugepagesz=     [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages.
-                       On x86-64 and powerpc, this option can be specified
-                       multiple times interleaved with hugepages= to reserve
-                       huge pages of different sizes. Valid pages sizes on
-                       x86-64 are 2M (when the CPU supports "pse") and 1G
-                       (when the CPU supports the "pdpe1gb" cpuinfo flag).
+       hugepages=      [HW] Number of HugeTLB pages to allocate at boot.
+                       If this follows hugepagesz (below), it specifies
+                       the number of pages of hugepagesz to be allocated.
+                       Format: <integer>
+       hugepagesz=
+                       [HW] The size of the HugeTLB pages.  This is used in
+                       conjunction with hugepages (above) to allocate huge
+                       pages of a specific size at boot.  The pair
+                       hugepagesz=X hugepages=Y can be specified once for
+                       each supported huge page size. Huge page sizes are
+                       architecture dependent.  See also
+                       Documentation/admin-guide/mm/hugetlbpage.rst.
+                       Format: size[KMG]
 
        hung_task_panic=
                        [KNL] Should the hung task detector generate panics.
diff --git a/Documentation/admin-guide/mm/hugetlbpage.rst 
b/Documentation/admin-guide/mm/hugetlbpage.rst
index 1cc0bc78d10e..de340c586995 100644
--- a/Documentation/admin-guide/mm/hugetlbpage.rst
+++ b/Documentation/admin-guide/mm/hugetlbpage.rst
@@ -100,6 +100,50 @@ with a huge page size selection parameter 
"hugepagesz=<size>".  <size> must
 be specified in bytes with optional scale suffix [kKmMgG].  The default huge
 page size may be selected with the "default_hugepagesz=<size>" boot parameter.
 
+Hugetlb boot command line parameter semantics
+hugepagesz - Specify a huge page size.  Used in conjunction with hugepages
+       parameter to preallocate a number of huge pages of the specified
+       size.  Hence, hugepagesz and hugepages are typically specified in
+       pairs such as:
+               hugepagesz=2M hugepages=512
+       hugepagesz can only be specified once on the command line for a
+       specific huge page size.  Valid huge page sizes are architecture
+       dependent.
+hugepages - Specify the number of huge pages to preallocate.  This typically
+       follows a valid hugepagesz parameter.  However, if hugepages is the
+       first or only hugetlb command line parameter it specifies the number
+       of huge pages of default size to allocate.  The number of huge pages
+       of default size specified in this manner can be overwritten by a
+       hugepagesz,hugepages parameter pair for the default size.
+       For example, on an architecture with 2M default huge page size:
+               hugepages=256 hugepagesz=2M hugepages=512
+       will result in 512 2M huge pages being allocated.  If a hugepages
+       parameter is preceded by an invalid hugepagesz parameter, it will
+       be ignored.
+default_hugepagesz - Specify the default huge page size.  This parameter can
+       only be specified once on the command line.  No other hugetlb command
+       line parameter is associated with default_hugepagesz.  Therefore, it
+       can appear anywhere on the command line.  If hugepages= is the first
+       hugetlb command line parameter, the specified number of huge pages
+       will apply to the default huge page size specified with
+       default_hugepagesz.  For example,
+               hugepages=512 default_hugepagesz=2M
+       will result in 512 2M huge pages being allocated.  However, specifying
+       the number of default huge pages in this manner will not apply to
+       gigantic huge pages.  For example,
+               hugepages=10 default_hugepagesz=1G
+                               or
+               default_hugepagesz=1G hugepages=10
+       will NOT result in the allocation of 10 1G huge pages.  In order to
+       preallocate gigantic huge pages, there must be hugepagesz, hugepages
+       parameter pair.  For example,
+               hugepagesz=1G hugepages=10 default_hugepagesz=1G
+                               or
+               default_hugepagesz=1G hugepagesz=1G hugepages=10
+       will result 10 1G huge pages being allocated and the default huge
+       page size will be set to 1G.  Valid default huge page size is
+       architecture dependent.
+
 When multiple huge page sizes are supported, ``/proc/sys/vm/nr_hugepages``
 indicates the current number of pre-allocated huge pages of the default size.
 Thus, one can use the following command to dynamically allocate/deallocate
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 72a4343509d5..74ef53f7c5a7 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3054,7 +3054,7 @@ static void __init hugetlb_sysfs_init(void)
                err = hugetlb_sysfs_add_hstate(h, hugepages_kobj,
                                         hstate_kobjs, &hstate_attr_group);
                if (err)
-                       pr_err("Hugetlb: Unable to add hstate %s", h->name);
+                       pr_err("HugeTLB: Unable to add hstate %s", h->name);
        }
 }
 
@@ -3158,7 +3158,7 @@ static void hugetlb_register_node(struct node *node)
                                                nhs->hstate_kobjs,
                                                &per_node_hstate_attr_group);
                if (err) {
-                       pr_err("Hugetlb: Unable to add hstate %s for node %d\n",
+                       pr_err("HugeTLB: Unable to add hstate %s for node %d\n",
                                h->name, node->dev.id);
                        hugetlb_unregister_node(node);
                        break;
@@ -3209,19 +3209,35 @@ static int __init hugetlb_init(void)
        if (!hugepages_supported())
                return 0;
 
-       if (!size_to_hstate(default_hstate_size)) {
-               if (default_hstate_size != 0) {
-                       pr_err("HugeTLB: unsupported default_hugepagesz %lu. 
Reverting to %lu\n",
-                              default_hstate_size, HPAGE_SIZE);
-               }
-
+       /*
+        * Make sure HPAGE_SIZE (HUGETLB_PAGE_ORDER) hstate exists.  Some
+        * architectures depend on setup being done here.
+        *
+        * If a valid default huge page size was specified on the command line,
+        * add associated hstate if necessary.  If not, set default_hstate_size
+        * to default size.  default_hstate_idx is used at runtime to identify
+        * the default huge page size/hstate.
+        */
+       hugetlb_add_hstate(HUGETLB_PAGE_ORDER);
+       if (default_hstate_size)
+               hugetlb_add_hstate(ilog2(default_hstate_size) - PAGE_SHIFT);
+       else
                default_hstate_size = HPAGE_SIZE;
-               hugetlb_add_hstate(HUGETLB_PAGE_ORDER);
-       }
        default_hstate_idx = hstate_index(size_to_hstate(default_hstate_size));
+
+       /*
+        * default_hstate_max_huge_pages != 0 indicates a count (hugepages=)
+        * specified before a size (hugepagesz=).  Use this count for the
+        * default huge page size, unless a specific value was specified for
+        * this size in a hugepagesz/hugepages pair.
+        */
        if (default_hstate_max_huge_pages) {
                if (!default_hstate.max_huge_pages)
-                       default_hstate.max_huge_pages = 
default_hstate_max_huge_pages;
+                       default_hstate.max_huge_pages =
+                               default_hstate_max_huge_pages;
+               else
+                       pr_warn("HugeTLB: First hugepages=%lu ignored\n",
+                               default_hstate_max_huge_pages);
        }
 
        hugetlb_init_hstates();
@@ -3274,20 +3290,31 @@ void __init hugetlb_add_hstate(unsigned int order)
        parsed_hstate = h;
 }
 
-static int __init hugetlb_nrpages_setup(char *s)
+/*
+ * hugepages command line processing
+ * hugepages normally follows a valid hugepagsz specification.  If not, ignore
+ * the hugepages value.  hugepages can also be the first huge page command line
+ * option in which case it specifies the number of huge pages for the default
+ * size.
+ */
+static int __init hugepages_setup(char *s)
 {
        unsigned long *mhp;
        static unsigned long *last_mhp;
 
+       if (!hugepages_supported()) {
+               pr_warn("HugeTLB: huge pages not supported, ignoring hugepages 
= %s\n", s);
+               return 0;
+       }
+
        if (!parsed_valid_hugepagesz) {
-               pr_warn("hugepages = %s preceded by "
-                       "an unsupported hugepagesz, ignoring\n", s);
+               pr_warn("HugeTLB: hugepages = %s preceded by an unsupported 
hugepagesz, ignoring\n", s);
                parsed_valid_hugepagesz = true;
-               return 1;
+               return 0;
        }
        /*
-        * !hugetlb_max_hstate means we haven't parsed a hugepagesz= parameter 
yet,
-        * so this hugepages= parameter goes to the "default hstate".
+        * !hugetlb_max_hstate means we haven't parsed a hugepagesz= parameter
+        * yet, so this hugepages= parameter goes to the "default hstate".
         */
        else if (!hugetlb_max_hstate)
                mhp = &default_hstate_max_huge_pages;
@@ -3295,8 +3322,8 @@ static int __init hugetlb_nrpages_setup(char *s)
                mhp = &parsed_hstate->max_huge_pages;
 
        if (mhp == last_mhp) {
-               pr_warn("hugepages= specified twice without interleaving 
hugepagesz=, ignoring\n");
-               return 1;
+               pr_warn("HugeTLB: hugepages= specified twice without 
interleaving hugepagesz=, ignoring hugepages=%s\n", s);
+               return 0;
        }
 
        if (sscanf(s, "%lu", mhp) <= 0)
@@ -3314,12 +3341,24 @@ static int __init hugetlb_nrpages_setup(char *s)
 
        return 1;
 }
-__setup("hugepages=", hugetlb_nrpages_setup);
+__setup("hugepages=", hugepages_setup);
 
+/*
+ * hugepagesz command line processing
+ * A specific huge page size can only be specified once with hugepagesz.
+ * hugepagesz is followed by hugepages on the command line.  The global
+ * variable 'parsed_valid_hugepagesz' is used to determine if prior
+ * hugepagesz argument was valid.
+ */
 static int __init hugepagesz_setup(char *s)
 {
        unsigned long size;
 
+       if (!hugepages_supported()) {
+               pr_warn("HugeTLB: huge pages not supported, ignoring hugepagesz 
= %s\n", s);
+               return 0;
+       }
+
        size = (unsigned long)memparse(s, NULL);
 
        if (!arch_hugetlb_valid_size(size)) {
@@ -3329,19 +3368,31 @@ static int __init hugepagesz_setup(char *s)
        }
 
        if (size_to_hstate(size)) {
+               parsed_valid_hugepagesz = false;
                pr_warn("HugeTLB: hugepagesz %s specified twice, ignoring\n", 
s);
                return 0;
        }
 
+       parsed_valid_hugepagesz = true;
        hugetlb_add_hstate(ilog2(size) - PAGE_SHIFT);
        return 1;
 }
 __setup("hugepagesz=", hugepagesz_setup);
 
+/*
+ * default_hugepagesz command line input
+ * Only one instance of default_hugepagesz allowed on command line.  Do not
+ * add hstate here as that will confuse hugepagesz/hugepages processing.
+ */
 static int __init default_hugepagesz_setup(char *s)
 {
        unsigned long size;
 
+       if (!hugepages_supported()) {
+               pr_warn("HugeTLB: huge pages not supported, ignoring 
default_hugepagesz = %s\n", s);
+               return 0;
+       }
+
        size = (unsigned long)memparse(s, NULL);
 
        if (!arch_hugetlb_valid_size(size)) {
@@ -3349,6 +3400,11 @@ static int __init default_hugepagesz_setup(char *s)
                return 0;
        }
 
+       if (default_hstate_size) {
+               pr_err("HugeTLB: default_hugepagesz previously specified, 
ignoring %s\n", s);
+               return 0;
+       }
+
        default_hstate_size = size;
        return 1;
 }
-- 
2.25.1

Reply via email to