mm: shmem: control THP support through the kernel command line
authorMaíra Canal <mcanal@igalia.com>
Fri, 1 Nov 2024 16:54:06 +0000 (13:54 -0300)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 11 Nov 2024 21:09:43 +0000 (13:09 -0800)
Patch series "mm: add more kernel parameters to control mTHP", v5.

This series introduces four patches related to the kernel parameters
controlling mTHP and a fifth patch replacing `strcpy()` for `strscpy()` in
the file `mm/huge_memory.c`.

The first patch is a straightforward documentation update, correcting the
format of the kernel parameter ``thp_anon=``.

The second, third, and fourth patches focus on controlling THP support for
shmem via the kernel command line.  The second patch introduces a
parameter to control the global default huge page allocation policy for
the internal shmem mount.  The third patch moves a piece of code to a
shared header to ease the implementation of the fourth patch.  Finally,
the fourth patch implements a parameter similar to ``thp_anon=``, but for
shmem.

The goal of these changes is to simplify the configuration of systems that
rely on mTHP support for shmem.  For instance, a platform with a GPU that
benefits from huge pages may want to enable huge pages for shmem.  Having
these kernel parameters streamlines the configuration process and ensures
consistency across setups.

This patch (of 4):

Add a new kernel command line to control the hugepage allocation policy
for the internal shmem mount, ``transparent_hugepage_shmem``. The
parameter is similar to ``transparent_hugepage`` and has the following
format:

transparent_hugepage_shmem=<policy>

where ``<policy>`` is one of the seven valid policies available for
shmem.

Configuring the default huge page allocation policy for the internal
shmem mount can be beneficial for DRM GPU drivers. Just as CPU
architectures, GPUs can also take advantage of huge pages, but this is
possible only if DRM GEM objects are backed by huge pages.

Since GEM uses shmem to allocate anonymous pageable memory, having control
over the default huge page allocation policy allows for the exploration of
huge pages use on GPUs that rely on GEM objects backed by shmem.

Link: https://lkml.kernel.org/r/20241101165719.1074234-2-mcanal@igalia.com
Link: https://lkml.kernel.org/r/20241101165719.1074234-4-mcanal@igalia.com
Signed-off-by: Maíra Canal <mcanal@igalia.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Acked-by: David Hildenbrand <david@redhat.com>
Cc: Barry Song <baohua@kernel.org>
Cc: dri-devel@lists.freedesktop.org
Cc: Hugh Dickins <hughd@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: kernel-dev@igalia.com
Cc: Lance Yang <ioworker0@gmail.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/mm/transhuge.rst
mm/shmem.c

index 1666576acc0eba69389ff623aeca286ff550c5b4..acabb04d0dd4898bed3cca1ff99f2cb1798816f0 100644 (file)
                        See Documentation/admin-guide/mm/transhuge.rst
                        for more details.
 
+       transparent_hugepage_shmem= [KNL]
+                       Format: [always|within_size|advise|never|deny|force]
+                       Can be used to control the hugepage allocation policy for
+                       the internal shmem mount.
+                       See Documentation/admin-guide/mm/transhuge.rst
+                       for more details.
+
        trusted.source= [KEYS]
                        Format: <string>
                        This parameter identifies the trust source as a backend
index abdf10a1c7db54925cbe50d5709782860b52f2a6..9c6f6da612c4f24cf638a0af8d05905eb6aa6994 100644 (file)
@@ -326,6 +326,12 @@ PMD_ORDER THP policy will be overridden. If the policy for PMD_ORDER
 is not defined within a valid ``thp_anon``, its policy will default to
 ``never``.
 
+Similarly to ``transparent_hugepage``, you can control the hugepage
+allocation policy for the internal shmem mount by using the kernel parameter
+``transparent_hugepage_shmem=<policy>``, where ``<policy>`` is one of the
+seven valid policies for shmem (``always``, ``within_size``, ``advise``,
+``never``, ``deny``, and ``force``).
+
 Hugepages in tmpfs/shmem
 ========================
 
index 5afc5b1f7ae144aa30adc428a469fbac399f3c09..c83675c271909dfe08b0f350635178cb40a630a7 100644 (file)
@@ -582,24 +582,39 @@ static bool shmem_huge_global_enabled(struct inode *inode, pgoff_t index,
        }
 }
 
-#if defined(CONFIG_SYSFS)
 static int shmem_parse_huge(const char *str)
 {
+       int huge;
+
+       if (!str)
+               return -EINVAL;
+
        if (!strcmp(str, "never"))
-               return SHMEM_HUGE_NEVER;
-       if (!strcmp(str, "always"))
-               return SHMEM_HUGE_ALWAYS;
-       if (!strcmp(str, "within_size"))
-               return SHMEM_HUGE_WITHIN_SIZE;
-       if (!strcmp(str, "advise"))
-               return SHMEM_HUGE_ADVISE;
-       if (!strcmp(str, "deny"))
-               return SHMEM_HUGE_DENY;
-       if (!strcmp(str, "force"))
-               return SHMEM_HUGE_FORCE;
-       return -EINVAL;
+               huge = SHMEM_HUGE_NEVER;
+       else if (!strcmp(str, "always"))
+               huge = SHMEM_HUGE_ALWAYS;
+       else if (!strcmp(str, "within_size"))
+               huge = SHMEM_HUGE_WITHIN_SIZE;
+       else if (!strcmp(str, "advise"))
+               huge = SHMEM_HUGE_ADVISE;
+       else if (!strcmp(str, "deny"))
+               huge = SHMEM_HUGE_DENY;
+       else if (!strcmp(str, "force"))
+               huge = SHMEM_HUGE_FORCE;
+       else
+               return -EINVAL;
+
+       if (!has_transparent_hugepage() &&
+           huge != SHMEM_HUGE_NEVER && huge != SHMEM_HUGE_DENY)
+               return -EINVAL;
+
+       /* Do not override huge allocation policy with non-PMD sized mTHP */
+       if (huge == SHMEM_HUGE_FORCE &&
+           huge_shmem_orders_inherit != BIT(HPAGE_PMD_ORDER))
+               return -EINVAL;
+
+       return huge;
 }
-#endif
 
 #if defined(CONFIG_SYSFS) || defined(CONFIG_TMPFS)
 static const char *shmem_format_huge(int huge)
@@ -5065,15 +5080,7 @@ static ssize_t shmem_enabled_store(struct kobject *kobj,
 
        huge = shmem_parse_huge(tmp);
        if (huge == -EINVAL)
-               return -EINVAL;
-       if (!has_transparent_hugepage() &&
-                       huge != SHMEM_HUGE_NEVER && huge != SHMEM_HUGE_DENY)
-               return -EINVAL;
-
-       /* Do not override huge allocation policy with non-PMD sized mTHP */
-       if (huge == SHMEM_HUGE_FORCE &&
-           huge_shmem_orders_inherit != BIT(HPAGE_PMD_ORDER))
-               return -EINVAL;
+               return huge;
 
        shmem_huge = huge;
        if (shmem_huge > SHMEM_HUGE_DENY)
@@ -5170,6 +5177,25 @@ struct kobj_attribute thpsize_shmem_enabled_attr =
        __ATTR(shmem_enabled, 0644, thpsize_shmem_enabled_show, thpsize_shmem_enabled_store);
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE && CONFIG_SYSFS */
 
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE)
+
+static int __init setup_transparent_hugepage_shmem(char *str)
+{
+       int huge;
+
+       huge = shmem_parse_huge(str);
+       if (huge == -EINVAL) {
+               pr_warn("transparent_hugepage_shmem= cannot parse, ignored\n");
+               return huge;
+       }
+
+       shmem_huge = huge;
+       return 1;
+}
+__setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
+
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
 #else /* !CONFIG_SHMEM */
 
 /*