Add the ``thp_shmem=`` kernel command line to allow specifying the
default policy of each supported shmem hugepage size. The kernel parameter
accepts the following format:
thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
For example,
thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
By configuring the default policy of several shmem huge pages, the user
can take advantage of mTHP before it's been configured through sysfs.
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
.../admin-guide/kernel-parameters.txt | 10 ++
Documentation/admin-guide/mm/transhuge.rst | 17 +++
mm/shmem.c | 109 +++++++++++++++++-
3 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index acabb04d0dd4..595fa096e28b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6700,6 +6700,16 @@
Force threading of all interrupt handlers except those
marked explicitly IRQF_NO_THREAD.
+ shmem_anon= [KNL]
+ Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
+ Control the default policy of each hugepage size for the
+ internal shmem mount. <policy> is one of policies available
+ for the shmem mount ("always", "inherit", "never", "within_size",
+ and "advise").
+ It can be used multiple times for multiple shmem THP sizes.
+ See Documentation/admin-guide/mm/transhuge.rst for more
+ details.
+
topology= [S390,EARLY]
Format: {off | on}
Specify if the kernel should make use of the cpu
diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
index 9b5b02c4d1ab..47e7fc30e22d 100644
--- a/Documentation/admin-guide/mm/transhuge.rst
+++ b/Documentation/admin-guide/mm/transhuge.rst
@@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
seven valid policies for shmem (``always``, ``within_size``, ``advise``,
``never``, ``deny``, and ``force``).
+In the same manner as ``thp_anon`` controls each supported anonymous THP
+size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
+has the same format as ``thp_anon``, but also supports the policy
+``within_size``.
+
+``thp_shmem=`` may be specified multiple times to configure all THP sizes
+as required. If ``thp_shmem=`` is specified at least once, any shmem THP
+sizes not explicitly configured on the command line are implicitly set to
+``never``.
+
+``transparent_hugepage_shmem`` setting only affects the global toggle. If
+``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
+``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
+user, the PMD_ORDER hugepage policy will be overridden. If the policy for
+PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
+default to ``never``.
+
Hugepages in tmpfs/shmem
========================
diff --git a/mm/shmem.c b/mm/shmem.c
index 24cdeafd8260..0a7a7d04f725 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -136,6 +136,7 @@ static unsigned long huge_shmem_orders_always __read_mostly;
static unsigned long huge_shmem_orders_madvise __read_mostly;
static unsigned long huge_shmem_orders_inherit __read_mostly;
static unsigned long huge_shmem_orders_within_size __read_mostly;
+static bool shmem_orders_configured __initdata;
#endif
#ifdef CONFIG_TMPFS
@@ -5013,7 +5014,8 @@ void __init shmem_init(void)
* Default to setting PMD-sized THP to inherit the global setting and
* disable all other multi-size THPs.
*/
- huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
+ if (!shmem_orders_configured)
+ huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
#endif
return;
@@ -5174,6 +5176,26 @@ struct kobj_attribute thpsize_shmem_enabled_attr =
#if defined(CONFIG_TRANSPARENT_HUGEPAGE)
+static inline int get_order_from_str(const char *size_str)
+{
+ unsigned long size;
+ char *endptr;
+ int order;
+
+ size = memparse(size_str, &endptr);
+
+ if (!is_power_of_2(size))
+ goto err;
+ order = get_order(size);
+ if (BIT(order) & ~THP_ORDERS_ALL_FILE_DEFAULT)
+ goto err;
+
+ return order;
+err:
+ pr_err("invalid size %s in thp_shmem boot parameter\n", size_str);
+ return -EINVAL;
+}
+
static int __init setup_transparent_hugepage_shmem(char *str)
{
int huge, ret = 0;
@@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
}
__setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
+static char str_dup[PAGE_SIZE] __initdata;
+static int __init setup_thp_shmem(char *str)
+{
+ char *token, *range, *policy, *subtoken;
+ unsigned long always, inherit, madvise, within_size;
+ char *start_size, *end_size;
+ int start, end, nr;
+ char *p;
+
+ if (!str || strlen(str) + 1 > PAGE_SIZE)
+ goto err;
+ strcpy(str_dup, str);
+
+ always = huge_shmem_orders_always;
+ inherit = huge_shmem_orders_inherit;
+ madvise = huge_shmem_orders_madvise;
+ within_size = huge_shmem_orders_within_size;
+ p = str_dup;
+ while ((token = strsep(&p, ";")) != NULL) {
+ range = strsep(&token, ":");
+ policy = token;
+
+ if (!policy)
+ goto err;
+
+ while ((subtoken = strsep(&range, ",")) != NULL) {
+ if (strchr(subtoken, '-')) {
+ start_size = strsep(&subtoken, "-");
+ end_size = subtoken;
+
+ start = get_order_from_str(start_size);
+ end = get_order_from_str(end_size);
+ } else {
+ start = end = get_order_from_str(subtoken);
+ }
+
+ if (start < 0 || end < 0 || start > end)
+ goto err;
+
+ nr = end - start + 1;
+ if (!strcmp(policy, "always")) {
+ bitmap_set(&always, start, nr);
+ bitmap_clear(&inherit, start, nr);
+ bitmap_clear(&madvise, start, nr);
+ bitmap_clear(&within_size, start, nr);
+ } else if (!strcmp(policy, "advise")) {
+ bitmap_set(&madvise, start, nr);
+ bitmap_clear(&inherit, start, nr);
+ bitmap_clear(&always, start, nr);
+ bitmap_clear(&within_size, start, nr);
+ } else if (!strcmp(policy, "inherit")) {
+ bitmap_set(&inherit, start, nr);
+ bitmap_clear(&madvise, start, nr);
+ bitmap_clear(&always, start, nr);
+ bitmap_clear(&within_size, start, nr);
+ } else if (!strcmp(policy, "within_size")) {
+ bitmap_set(&within_size, start, nr);
+ bitmap_clear(&inherit, start, nr);
+ bitmap_clear(&madvise, start, nr);
+ bitmap_clear(&always, start, nr);
+ } else if (!strcmp(policy, "never")) {
+ bitmap_clear(&inherit, start, nr);
+ bitmap_clear(&madvise, start, nr);
+ bitmap_clear(&always, start, nr);
+ bitmap_clear(&within_size, start, nr);
+ } else {
+ pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
+ goto err;
+ }
+ }
+ }
+
+ huge_shmem_orders_always = always;
+ huge_shmem_orders_madvise = madvise;
+ huge_shmem_orders_inherit = inherit;
+ huge_shmem_orders_within_size = within_size;
+ shmem_orders_configured = true;
+ return 1;
+
+err:
+ pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
+ return 0;
+}
+__setup("thp_shmem=", setup_thp_shmem);
+
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#else /* !CONFIG_SHMEM */
--
2.46.2
On Mon, Oct 28, 2024 at 6:58 AM Maíra Canal <mcanal@igalia.com> wrote:
>
> Add the ``thp_shmem=`` kernel command line to allow specifying the
> default policy of each supported shmem hugepage size. The kernel parameter
> accepts the following format:
>
> thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
>
> For example,
>
> thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
>
> By configuring the default policy of several shmem huge pages, the user
> can take advantage of mTHP before it's been configured through sysfs.
>
> Signed-off-by: Maíra Canal <mcanal@igalia.com>
> ---
> .../admin-guide/kernel-parameters.txt | 10 ++
> Documentation/admin-guide/mm/transhuge.rst | 17 +++
> mm/shmem.c | 109 +++++++++++++++++-
> 3 files changed, 135 insertions(+), 1 deletion(-)
>
Hi Maíra,
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index acabb04d0dd4..595fa096e28b 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6700,6 +6700,16 @@
> Force threading of all interrupt handlers except those
> marked explicitly IRQF_NO_THREAD.
>
> + shmem_anon= [KNL]
> + Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
> + Control the default policy of each hugepage size for the
> + internal shmem mount. <policy> is one of policies available
> + for the shmem mount ("always", "inherit", "never", "within_size",
> + and "advise").
> + It can be used multiple times for multiple shmem THP sizes.
> + See Documentation/admin-guide/mm/transhuge.rst for more
> + details.
I'm not sure this is the right name. How about "thp_shmem"?
> +
> topology= [S390,EARLY]
> Format: {off | on}
> Specify if the kernel should make use of the cpu
> diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
> index 9b5b02c4d1ab..47e7fc30e22d 100644
> --- a/Documentation/admin-guide/mm/transhuge.rst
> +++ b/Documentation/admin-guide/mm/transhuge.rst
> @@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
> seven valid policies for shmem (``always``, ``within_size``, ``advise``,
> ``never``, ``deny``, and ``force``).
>
> +In the same manner as ``thp_anon`` controls each supported anonymous THP
> +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
> +has the same format as ``thp_anon``, but also supports the policy
> +``within_size``.
> +
> +``thp_shmem=`` may be specified multiple times to configure all THP sizes
> +as required. If ``thp_shmem=`` is specified at least once, any shmem THP
> +sizes not explicitly configured on the command line are implicitly set to
> +``never``.
> +
> +``transparent_hugepage_shmem`` setting only affects the global toggle. If
> +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
> +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
> +user, the PMD_ORDER hugepage policy will be overridden. If the policy for
> +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
> +default to ``never``.
> +
> Hugepages in tmpfs/shmem
> ========================
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 24cdeafd8260..0a7a7d04f725 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -136,6 +136,7 @@ static unsigned long huge_shmem_orders_always __read_mostly;
> static unsigned long huge_shmem_orders_madvise __read_mostly;
> static unsigned long huge_shmem_orders_inherit __read_mostly;
> static unsigned long huge_shmem_orders_within_size __read_mostly;
> +static bool shmem_orders_configured __initdata;
> #endif
>
> #ifdef CONFIG_TMPFS
> @@ -5013,7 +5014,8 @@ void __init shmem_init(void)
> * Default to setting PMD-sized THP to inherit the global setting and
> * disable all other multi-size THPs.
> */
> - huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
> + if (!shmem_orders_configured)
> + huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
> #endif
> return;
>
> @@ -5174,6 +5176,26 @@ struct kobj_attribute thpsize_shmem_enabled_attr =
>
> #if defined(CONFIG_TRANSPARENT_HUGEPAGE)
>
> +static inline int get_order_from_str(const char *size_str)
> +{
> + unsigned long size;
> + char *endptr;
> + int order;
> +
> + size = memparse(size_str, &endptr);
> +
> + if (!is_power_of_2(size))
> + goto err;
> + order = get_order(size);
> + if (BIT(order) & ~THP_ORDERS_ALL_FILE_DEFAULT)
> + goto err;
> +
> + return order;
> +err:
> + pr_err("invalid size %s in thp_shmem boot parameter\n", size_str);
> + return -EINVAL;
> +}
> +
> static int __init setup_transparent_hugepage_shmem(char *str)
> {
> int huge, ret = 0;
> @@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
> }
> __setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
>
> +static char str_dup[PAGE_SIZE] __initdata;
> +static int __init setup_thp_shmem(char *str)
> +{
> + char *token, *range, *policy, *subtoken;
> + unsigned long always, inherit, madvise, within_size;
> + char *start_size, *end_size;
> + int start, end, nr;
> + char *p;
> +
> + if (!str || strlen(str) + 1 > PAGE_SIZE)
> + goto err;
> + strcpy(str_dup, str);
> +
> + always = huge_shmem_orders_always;
> + inherit = huge_shmem_orders_inherit;
> + madvise = huge_shmem_orders_madvise;
> + within_size = huge_shmem_orders_within_size;
> + p = str_dup;
> + while ((token = strsep(&p, ";")) != NULL) {
> + range = strsep(&token, ":");
> + policy = token;
> +
> + if (!policy)
> + goto err;
> +
> + while ((subtoken = strsep(&range, ",")) != NULL) {
> + if (strchr(subtoken, '-')) {
> + start_size = strsep(&subtoken, "-");
> + end_size = subtoken;
> +
> + start = get_order_from_str(start_size);
> + end = get_order_from_str(end_size);
> + } else {
> + start = end = get_order_from_str(subtoken);
> + }
> +
> + if (start < 0 || end < 0 || start > end)
> + goto err;
> +
> + nr = end - start + 1;
> + if (!strcmp(policy, "always")) {
> + bitmap_set(&always, start, nr);
> + bitmap_clear(&inherit, start, nr);
> + bitmap_clear(&madvise, start, nr);
> + bitmap_clear(&within_size, start, nr);
> + } else if (!strcmp(policy, "advise")) {
> + bitmap_set(&madvise, start, nr);
> + bitmap_clear(&inherit, start, nr);
> + bitmap_clear(&always, start, nr);
> + bitmap_clear(&within_size, start, nr);
> + } else if (!strcmp(policy, "inherit")) {
> + bitmap_set(&inherit, start, nr);
> + bitmap_clear(&madvise, start, nr);
> + bitmap_clear(&always, start, nr);
> + bitmap_clear(&within_size, start, nr);
> + } else if (!strcmp(policy, "within_size")) {
> + bitmap_set(&within_size, start, nr);
> + bitmap_clear(&inherit, start, nr);
> + bitmap_clear(&madvise, start, nr);
> + bitmap_clear(&always, start, nr);
> + } else if (!strcmp(policy, "never")) {
> + bitmap_clear(&inherit, start, nr);
> + bitmap_clear(&madvise, start, nr);
> + bitmap_clear(&always, start, nr);
> + bitmap_clear(&within_size, start, nr);
> + } else {
> + pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
> + goto err;
> + }
> + }
> + }
> +
> + huge_shmem_orders_always = always;
> + huge_shmem_orders_madvise = madvise;
> + huge_shmem_orders_inherit = inherit;
> + huge_shmem_orders_within_size = within_size;
> + shmem_orders_configured = true;
> + return 1;
> +
> +err:
> + pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
> + return 0;
> +}
Can we share source code with thp_anon since there's a lot of duplication?
> +__setup("thp_shmem=", setup_thp_shmem);
> +
> #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>
> #else /* !CONFIG_SHMEM */
> --
> 2.46.2
>
Thanks
barry
Hi Barry,
On 27/10/24 18:54, Barry Song wrote:
> On Mon, Oct 28, 2024 at 6:58 AM Maíra Canal <mcanal@igalia.com> wrote:
>>
>> Add the ``thp_shmem=`` kernel command line to allow specifying the
>> default policy of each supported shmem hugepage size. The kernel parameter
>> accepts the following format:
>>
>> thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
>>
>> For example,
>>
>> thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
>>
>> By configuring the default policy of several shmem huge pages, the user
>> can take advantage of mTHP before it's been configured through sysfs.
>>
>> Signed-off-by: Maíra Canal <mcanal@igalia.com>
>> ---
>> .../admin-guide/kernel-parameters.txt | 10 ++
>> Documentation/admin-guide/mm/transhuge.rst | 17 +++
>> mm/shmem.c | 109 +++++++++++++++++-
>> 3 files changed, 135 insertions(+), 1 deletion(-)
>>
>
> Hi Maíra,
>
>> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
>> index acabb04d0dd4..595fa096e28b 100644
>> --- a/Documentation/admin-guide/kernel-parameters.txt
>> +++ b/Documentation/admin-guide/kernel-parameters.txt
>> @@ -6700,6 +6700,16 @@
>> Force threading of all interrupt handlers except those
>> marked explicitly IRQF_NO_THREAD.
>>
>> + shmem_anon= [KNL]
>> + Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
>> + Control the default policy of each hugepage size for the
>> + internal shmem mount. <policy> is one of policies available
>> + for the shmem mount ("always", "inherit", "never", "within_size",
>> + and "advise").
>> + It can be used multiple times for multiple shmem THP sizes.
>> + See Documentation/admin-guide/mm/transhuge.rst for more
>> + details.
>
> I'm not sure this is the right name. How about "thp_shmem"?
Oops, sorry about that.
>
>> +
>> topology= [S390,EARLY]
>> Format: {off | on}
>> Specify if the kernel should make use of the cpu
>> diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
>> index 9b5b02c4d1ab..47e7fc30e22d 100644
>> --- a/Documentation/admin-guide/mm/transhuge.rst
>> +++ b/Documentation/admin-guide/mm/transhuge.rst
>> @@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
>> seven valid policies for shmem (``always``, ``within_size``, ``advise``,
>> ``never``, ``deny``, and ``force``).
>>
>> +In the same manner as ``thp_anon`` controls each supported anonymous THP
>> +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
>> +has the same format as ``thp_anon``, but also supports the policy
>> +``within_size``.
>> +
>> +``thp_shmem=`` may be specified multiple times to configure all THP sizes
>> +as required. If ``thp_shmem=`` is specified at least once, any shmem THP
>> +sizes not explicitly configured on the command line are implicitly set to
>> +``never``.
>> +
>> +``transparent_hugepage_shmem`` setting only affects the global toggle. If
>> +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
>> +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
>> +user, the PMD_ORDER hugepage policy will be overridden. If the policy for
>> +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
>> +default to ``never``.
>> +
>> Hugepages in tmpfs/shmem
>> ========================
>>
>> diff --git a/mm/shmem.c b/mm/shmem.c
>> index 24cdeafd8260..0a7a7d04f725 100644
>> --- a/mm/shmem.c
>> +++ b/mm/shmem.c
>> @@ -136,6 +136,7 @@ static unsigned long huge_shmem_orders_always __read_mostly;
>> static unsigned long huge_shmem_orders_madvise __read_mostly;
>> static unsigned long huge_shmem_orders_inherit __read_mostly;
>> static unsigned long huge_shmem_orders_within_size __read_mostly;
>> +static bool shmem_orders_configured __initdata;
>> #endif
>>
>> #ifdef CONFIG_TMPFS
>> @@ -5013,7 +5014,8 @@ void __init shmem_init(void)
>> * Default to setting PMD-sized THP to inherit the global setting and
>> * disable all other multi-size THPs.
>> */
>> - huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
>> + if (!shmem_orders_configured)
>> + huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
>> #endif
>> return;
>>
>> @@ -5174,6 +5176,26 @@ struct kobj_attribute thpsize_shmem_enabled_attr =
>>
>> #if defined(CONFIG_TRANSPARENT_HUGEPAGE)
>>
>> +static inline int get_order_from_str(const char *size_str)
>> +{
>> + unsigned long size;
>> + char *endptr;
>> + int order;
>> +
>> + size = memparse(size_str, &endptr);
>> +
>> + if (!is_power_of_2(size))
>> + goto err;
>> + order = get_order(size);
>> + if (BIT(order) & ~THP_ORDERS_ALL_FILE_DEFAULT)
>> + goto err;
>> +
>> + return order;
>> +err:
>> + pr_err("invalid size %s in thp_shmem boot parameter\n", size_str);
>> + return -EINVAL;
>> +}
>> +
>> static int __init setup_transparent_hugepage_shmem(char *str)
>> {
>> int huge, ret = 0;
>> @@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
>> }
>> __setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
>>
>> +static char str_dup[PAGE_SIZE] __initdata;
>> +static int __init setup_thp_shmem(char *str)
>> +{
>> + char *token, *range, *policy, *subtoken;
>> + unsigned long always, inherit, madvise, within_size;
>> + char *start_size, *end_size;
>> + int start, end, nr;
>> + char *p;
>> +
>> + if (!str || strlen(str) + 1 > PAGE_SIZE)
>> + goto err;
>> + strcpy(str_dup, str);
>> +
>> + always = huge_shmem_orders_always;
>> + inherit = huge_shmem_orders_inherit;
>> + madvise = huge_shmem_orders_madvise;
>> + within_size = huge_shmem_orders_within_size;
>> + p = str_dup;
>> + while ((token = strsep(&p, ";")) != NULL) {
>> + range = strsep(&token, ":");
>> + policy = token;
>> +
>> + if (!policy)
>> + goto err;
>> +
>> + while ((subtoken = strsep(&range, ",")) != NULL) {
>> + if (strchr(subtoken, '-')) {
>> + start_size = strsep(&subtoken, "-");
>> + end_size = subtoken;
>> +
>> + start = get_order_from_str(start_size);
>> + end = get_order_from_str(end_size);
>> + } else {
>> + start = end = get_order_from_str(subtoken);
>> + }
>> +
>> + if (start < 0 || end < 0 || start > end)
>> + goto err;
>> +
>> + nr = end - start + 1;
>> + if (!strcmp(policy, "always")) {
>> + bitmap_set(&always, start, nr);
>> + bitmap_clear(&inherit, start, nr);
>> + bitmap_clear(&madvise, start, nr);
>> + bitmap_clear(&within_size, start, nr);
>> + } else if (!strcmp(policy, "advise")) {
>> + bitmap_set(&madvise, start, nr);
>> + bitmap_clear(&inherit, start, nr);
>> + bitmap_clear(&always, start, nr);
>> + bitmap_clear(&within_size, start, nr);
>> + } else if (!strcmp(policy, "inherit")) {
>> + bitmap_set(&inherit, start, nr);
>> + bitmap_clear(&madvise, start, nr);
>> + bitmap_clear(&always, start, nr);
>> + bitmap_clear(&within_size, start, nr);
>> + } else if (!strcmp(policy, "within_size")) {
>> + bitmap_set(&within_size, start, nr);
>> + bitmap_clear(&inherit, start, nr);
>> + bitmap_clear(&madvise, start, nr);
>> + bitmap_clear(&always, start, nr);
>> + } else if (!strcmp(policy, "never")) {
>> + bitmap_clear(&inherit, start, nr);
>> + bitmap_clear(&madvise, start, nr);
>> + bitmap_clear(&always, start, nr);
>> + bitmap_clear(&within_size, start, nr);
>> + } else {
>> + pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
>> + goto err;
>> + }
>> + }
>> + }
>> +
>> + huge_shmem_orders_always = always;
>> + huge_shmem_orders_madvise = madvise;
>> + huge_shmem_orders_inherit = inherit;
>> + huge_shmem_orders_within_size = within_size;
>> + shmem_orders_configured = true;
>> + return 1;
>> +
>> +err:
>> + pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
>> + return 0;
>> +}
>
> Can we share source code with thp_anon since there's a lot of duplication?
I'm not a regular mm contributor and I'm most usually around drivers, so
I don't know exactly here I could add shared code. Should I add the
headers to "internal.h"?
Best Regards,
- Maíra
>
>> +__setup("thp_shmem=", setup_thp_shmem);
>> +
>> #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>>
>> #else /* !CONFIG_SHMEM */
>> --
>> 2.46.2
>>
>
> Thanks
> barry
On Mon, Oct 28, 2024 at 6:10 PM Maíra Canal <mcanal@igalia.com> wrote:
>
> Hi Barry,
>
> On 27/10/24 18:54, Barry Song wrote:
> > On Mon, Oct 28, 2024 at 6:58 AM Maíra Canal <mcanal@igalia.com> wrote:
> >>
> >> Add the ``thp_shmem=`` kernel command line to allow specifying the
> >> default policy of each supported shmem hugepage size. The kernel parameter
> >> accepts the following format:
> >>
> >> thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
> >>
> >> For example,
> >>
> >> thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
> >>
> >> By configuring the default policy of several shmem huge pages, the user
> >> can take advantage of mTHP before it's been configured through sysfs.
> >>
> >> Signed-off-by: Maíra Canal <mcanal@igalia.com>
> >> ---
> >> .../admin-guide/kernel-parameters.txt | 10 ++
> >> Documentation/admin-guide/mm/transhuge.rst | 17 +++
> >> mm/shmem.c | 109 +++++++++++++++++-
> >> 3 files changed, 135 insertions(+), 1 deletion(-)
> >>
> >
> > Hi Maíra,
> >
> >> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> >> index acabb04d0dd4..595fa096e28b 100644
> >> --- a/Documentation/admin-guide/kernel-parameters.txt
> >> +++ b/Documentation/admin-guide/kernel-parameters.txt
> >> @@ -6700,6 +6700,16 @@
> >> Force threading of all interrupt handlers except those
> >> marked explicitly IRQF_NO_THREAD.
> >>
> >> + shmem_anon= [KNL]
> >> + Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
> >> + Control the default policy of each hugepage size for the
> >> + internal shmem mount. <policy> is one of policies available
> >> + for the shmem mount ("always", "inherit", "never", "within_size",
> >> + and "advise").
> >> + It can be used multiple times for multiple shmem THP sizes.
> >> + See Documentation/admin-guide/mm/transhuge.rst for more
> >> + details.
> >
> > I'm not sure this is the right name. How about "thp_shmem"?
>
> Oops, sorry about that.
>
> >
> >> +
> >> topology= [S390,EARLY]
> >> Format: {off | on}
> >> Specify if the kernel should make use of the cpu
> >> diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
> >> index 9b5b02c4d1ab..47e7fc30e22d 100644
> >> --- a/Documentation/admin-guide/mm/transhuge.rst
> >> +++ b/Documentation/admin-guide/mm/transhuge.rst
> >> @@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
> >> seven valid policies for shmem (``always``, ``within_size``, ``advise``,
> >> ``never``, ``deny``, and ``force``).
> >>
> >> +In the same manner as ``thp_anon`` controls each supported anonymous THP
> >> +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
> >> +has the same format as ``thp_anon``, but also supports the policy
> >> +``within_size``.
> >> +
> >> +``thp_shmem=`` may be specified multiple times to configure all THP sizes
> >> +as required. If ``thp_shmem=`` is specified at least once, any shmem THP
> >> +sizes not explicitly configured on the command line are implicitly set to
> >> +``never``.
> >> +
> >> +``transparent_hugepage_shmem`` setting only affects the global toggle. If
> >> +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
> >> +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
> >> +user, the PMD_ORDER hugepage policy will be overridden. If the policy for
> >> +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
> >> +default to ``never``.
> >> +
> >> Hugepages in tmpfs/shmem
> >> ========================
> >>
> >> diff --git a/mm/shmem.c b/mm/shmem.c
> >> index 24cdeafd8260..0a7a7d04f725 100644
> >> --- a/mm/shmem.c
> >> +++ b/mm/shmem.c
> >> @@ -136,6 +136,7 @@ static unsigned long huge_shmem_orders_always __read_mostly;
> >> static unsigned long huge_shmem_orders_madvise __read_mostly;
> >> static unsigned long huge_shmem_orders_inherit __read_mostly;
> >> static unsigned long huge_shmem_orders_within_size __read_mostly;
> >> +static bool shmem_orders_configured __initdata;
> >> #endif
> >>
> >> #ifdef CONFIG_TMPFS
> >> @@ -5013,7 +5014,8 @@ void __init shmem_init(void)
> >> * Default to setting PMD-sized THP to inherit the global setting and
> >> * disable all other multi-size THPs.
> >> */
> >> - huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
> >> + if (!shmem_orders_configured)
> >> + huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
> >> #endif
> >> return;
> >>
> >> @@ -5174,6 +5176,26 @@ struct kobj_attribute thpsize_shmem_enabled_attr =
> >>
> >> #if defined(CONFIG_TRANSPARENT_HUGEPAGE)
> >>
> >> +static inline int get_order_from_str(const char *size_str)
> >> +{
> >> + unsigned long size;
> >> + char *endptr;
> >> + int order;
> >> +
> >> + size = memparse(size_str, &endptr);
> >> +
> >> + if (!is_power_of_2(size))
> >> + goto err;
> >> + order = get_order(size);
> >> + if (BIT(order) & ~THP_ORDERS_ALL_FILE_DEFAULT)
> >> + goto err;
> >> +
> >> + return order;
> >> +err:
> >> + pr_err("invalid size %s in thp_shmem boot parameter\n", size_str);
> >> + return -EINVAL;
> >> +}
> >> +
> >> static int __init setup_transparent_hugepage_shmem(char *str)
> >> {
> >> int huge, ret = 0;
> >> @@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
> >> }
> >> __setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
> >>
> >> +static char str_dup[PAGE_SIZE] __initdata;
> >> +static int __init setup_thp_shmem(char *str)
> >> +{
> >> + char *token, *range, *policy, *subtoken;
> >> + unsigned long always, inherit, madvise, within_size;
> >> + char *start_size, *end_size;
> >> + int start, end, nr;
> >> + char *p;
> >> +
> >> + if (!str || strlen(str) + 1 > PAGE_SIZE)
> >> + goto err;
> >> + strcpy(str_dup, str);
> >> +
> >> + always = huge_shmem_orders_always;
> >> + inherit = huge_shmem_orders_inherit;
> >> + madvise = huge_shmem_orders_madvise;
> >> + within_size = huge_shmem_orders_within_size;
> >> + p = str_dup;
> >> + while ((token = strsep(&p, ";")) != NULL) {
> >> + range = strsep(&token, ":");
> >> + policy = token;
> >> +
> >> + if (!policy)
> >> + goto err;
> >> +
> >> + while ((subtoken = strsep(&range, ",")) != NULL) {
> >> + if (strchr(subtoken, '-')) {
> >> + start_size = strsep(&subtoken, "-");
> >> + end_size = subtoken;
> >> +
> >> + start = get_order_from_str(start_size);
> >> + end = get_order_from_str(end_size);
> >> + } else {
> >> + start = end = get_order_from_str(subtoken);
> >> + }
> >> +
> >> + if (start < 0 || end < 0 || start > end)
> >> + goto err;
> >> +
> >> + nr = end - start + 1;
> >> + if (!strcmp(policy, "always")) {
> >> + bitmap_set(&always, start, nr);
> >> + bitmap_clear(&inherit, start, nr);
> >> + bitmap_clear(&madvise, start, nr);
> >> + bitmap_clear(&within_size, start, nr);
> >> + } else if (!strcmp(policy, "advise")) {
> >> + bitmap_set(&madvise, start, nr);
> >> + bitmap_clear(&inherit, start, nr);
> >> + bitmap_clear(&always, start, nr);
> >> + bitmap_clear(&within_size, start, nr);
> >> + } else if (!strcmp(policy, "inherit")) {
> >> + bitmap_set(&inherit, start, nr);
> >> + bitmap_clear(&madvise, start, nr);
> >> + bitmap_clear(&always, start, nr);
> >> + bitmap_clear(&within_size, start, nr);
> >> + } else if (!strcmp(policy, "within_size")) {
> >> + bitmap_set(&within_size, start, nr);
> >> + bitmap_clear(&inherit, start, nr);
> >> + bitmap_clear(&madvise, start, nr);
> >> + bitmap_clear(&always, start, nr);
> >> + } else if (!strcmp(policy, "never")) {
> >> + bitmap_clear(&inherit, start, nr);
> >> + bitmap_clear(&madvise, start, nr);
> >> + bitmap_clear(&always, start, nr);
> >> + bitmap_clear(&within_size, start, nr);
> >> + } else {
> >> + pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
> >> + goto err;
> >> + }
> >> + }
> >> + }
> >> +
> >> + huge_shmem_orders_always = always;
> >> + huge_shmem_orders_madvise = madvise;
> >> + huge_shmem_orders_inherit = inherit;
> >> + huge_shmem_orders_within_size = within_size;
> >> + shmem_orders_configured = true;
> >> + return 1;
> >> +
> >> +err:
> >> + pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
> >> + return 0;
> >> +}
> >
> > Can we share source code with thp_anon since there's a lot of duplication?
>
> I'm not a regular mm contributor and I'm most usually around drivers, so
> I don't know exactly here I could add shared code. Should I add the
> headers to "internal.h"?
My comment isn't related to drivers or memory management. It's solely about
avoiding code duplication. For example, we could create a shared function to
handle both controls, reducing redundant code :-)
>
> Best Regards,
> - Maíra
>
> >
> >> +__setup("thp_shmem=", setup_thp_shmem);
> >> +
> >> #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
> >>
> >> #else /* !CONFIG_SHMEM */
> >> --
> >> 2.46.2
> >>
> >
> > Thanks
> > barry
>
Hi Barry,
On 28/10/24 08:09, Barry Song wrote:
> On Mon, Oct 28, 2024 at 6:10 PM Maíra Canal <mcanal@igalia.com> wrote:
>>
>> Hi Barry,
>>
>> On 27/10/24 18:54, Barry Song wrote:
>>> On Mon, Oct 28, 2024 at 6:58 AM Maíra Canal <mcanal@igalia.com> wrote:
>>>>
>>>> Add the ``thp_shmem=`` kernel command line to allow specifying the
>>>> default policy of each supported shmem hugepage size. The kernel parameter
>>>> accepts the following format:
>>>>
>>>> thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
>>>>
>>>> For example,
>>>>
>>>> thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
>>>>
>>>> By configuring the default policy of several shmem huge pages, the user
>>>> can take advantage of mTHP before it's been configured through sysfs.
>>>>
>>>> Signed-off-by: Maíra Canal <mcanal@igalia.com>
>>>> ---
>>>> .../admin-guide/kernel-parameters.txt | 10 ++
>>>> Documentation/admin-guide/mm/transhuge.rst | 17 +++
>>>> mm/shmem.c | 109 +++++++++++++++++-
>>>> 3 files changed, 135 insertions(+), 1 deletion(-)
>>>>
>>>
>>> Hi Maíra,
>>>
>>>> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
>>>> index acabb04d0dd4..595fa096e28b 100644
>>>> --- a/Documentation/admin-guide/kernel-parameters.txt
>>>> +++ b/Documentation/admin-guide/kernel-parameters.txt
>>>> @@ -6700,6 +6700,16 @@
>>>> Force threading of all interrupt handlers except those
>>>> marked explicitly IRQF_NO_THREAD.
>>>>
>>>> + shmem_anon= [KNL]
>>>> + Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
>>>> + Control the default policy of each hugepage size for the
>>>> + internal shmem mount. <policy> is one of policies available
>>>> + for the shmem mount ("always", "inherit", "never", "within_size",
>>>> + and "advise").
>>>> + It can be used multiple times for multiple shmem THP sizes.
>>>> + See Documentation/admin-guide/mm/transhuge.rst for more
>>>> + details.
>>>
>>> I'm not sure this is the right name. How about "thp_shmem"?
>>
>> Oops, sorry about that.
>>
>>>
>>>> +
>>>> topology= [S390,EARLY]
>>>> Format: {off | on}
>>>> Specify if the kernel should make use of the cpu
>>>> diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
>>>> index 9b5b02c4d1ab..47e7fc30e22d 100644
>>>> --- a/Documentation/admin-guide/mm/transhuge.rst
>>>> +++ b/Documentation/admin-guide/mm/transhuge.rst
>>>> @@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
>>>> seven valid policies for shmem (``always``, ``within_size``, ``advise``,
>>>> ``never``, ``deny``, and ``force``).
>>>>
>>>> +In the same manner as ``thp_anon`` controls each supported anonymous THP
>>>> +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
>>>> +has the same format as ``thp_anon``, but also supports the policy
>>>> +``within_size``.
>>>> +
>>>> +``thp_shmem=`` may be specified multiple times to configure all THP sizes
>>>> +as required. If ``thp_shmem=`` is specified at least once, any shmem THP
>>>> +sizes not explicitly configured on the command line are implicitly set to
>>>> +``never``.
>>>> +
>>>> +``transparent_hugepage_shmem`` setting only affects the global toggle. If
>>>> +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
>>>> +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
>>>> +user, the PMD_ORDER hugepage policy will be overridden. If the policy for
>>>> +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
>>>> +default to ``never``.
>>>> +
>>>> Hugepages in tmpfs/shmem
>>>> ========================
>>>>
>>>> diff --git a/mm/shmem.c b/mm/shmem.c
>>>> index 24cdeafd8260..0a7a7d04f725 100644
>>>> --- a/mm/shmem.c
>>>> +++ b/mm/shmem.c
[...]
>>>> static int __init setup_transparent_hugepage_shmem(char *str)
>>>> {
>>>> int huge, ret = 0;
>>>> @@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
>>>> }
>>>> __setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
>>>>
>>>> +static char str_dup[PAGE_SIZE] __initdata;
>>>> +static int __init setup_thp_shmem(char *str)
>>>> +{
>>>> + char *token, *range, *policy, *subtoken;
>>>> + unsigned long always, inherit, madvise, within_size;
>>>> + char *start_size, *end_size;
>>>> + int start, end, nr;
>>>> + char *p;
>>>> +
>>>> + if (!str || strlen(str) + 1 > PAGE_SIZE)
>>>> + goto err;
>>>> + strcpy(str_dup, str);
>>>> +
>>>> + always = huge_shmem_orders_always;
>>>> + inherit = huge_shmem_orders_inherit;
>>>> + madvise = huge_shmem_orders_madvise;
>>>> + within_size = huge_shmem_orders_within_size;
>>>> + p = str_dup;
>>>> + while ((token = strsep(&p, ";")) != NULL) {
>>>> + range = strsep(&token, ":");
>>>> + policy = token;
>>>> +
>>>> + if (!policy)
>>>> + goto err;
>>>> +
>>>> + while ((subtoken = strsep(&range, ",")) != NULL) {
>>>> + if (strchr(subtoken, '-')) {
>>>> + start_size = strsep(&subtoken, "-");
>>>> + end_size = subtoken;
>>>> +
>>>> + start = get_order_from_str(start_size);
>>>> + end = get_order_from_str(end_size);
>>>> + } else {
>>>> + start = end = get_order_from_str(subtoken);
>>>> + }
>>>> +
>>>> + if (start < 0 || end < 0 || start > end)
>>>> + goto err;
>>>> +
>>>> + nr = end - start + 1;
>>>> + if (!strcmp(policy, "always")) {
>>>> + bitmap_set(&always, start, nr);
>>>> + bitmap_clear(&inherit, start, nr);
>>>> + bitmap_clear(&madvise, start, nr);
>>>> + bitmap_clear(&within_size, start, nr);
>>>> + } else if (!strcmp(policy, "advise")) {
>>>> + bitmap_set(&madvise, start, nr);
>>>> + bitmap_clear(&inherit, start, nr);
>>>> + bitmap_clear(&always, start, nr);
>>>> + bitmap_clear(&within_size, start, nr);
>>>> + } else if (!strcmp(policy, "inherit")) {
>>>> + bitmap_set(&inherit, start, nr);
>>>> + bitmap_clear(&madvise, start, nr);
>>>> + bitmap_clear(&always, start, nr);
>>>> + bitmap_clear(&within_size, start, nr);
>>>> + } else if (!strcmp(policy, "within_size")) {
>>>> + bitmap_set(&within_size, start, nr);
>>>> + bitmap_clear(&inherit, start, nr);
>>>> + bitmap_clear(&madvise, start, nr);
>>>> + bitmap_clear(&always, start, nr);
>>>> + } else if (!strcmp(policy, "never")) {
>>>> + bitmap_clear(&inherit, start, nr);
>>>> + bitmap_clear(&madvise, start, nr);
>>>> + bitmap_clear(&always, start, nr);
>>>> + bitmap_clear(&within_size, start, nr);
>>>> + } else {
>>>> + pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
>>>> + goto err;
>>>> + }
>>>> + }
>>>> + }
>>>> +
>>>> + huge_shmem_orders_always = always;
>>>> + huge_shmem_orders_madvise = madvise;
>>>> + huge_shmem_orders_inherit = inherit;
>>>> + huge_shmem_orders_within_size = within_size;
>>>> + shmem_orders_configured = true;
>>>> + return 1;
>>>> +
>>>> +err:
>>>> + pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
>>>> + return 0;
>>>> +}
>>>
>>> Can we share source code with thp_anon since there's a lot of duplication?
>>
>> I'm not a regular mm contributor and I'm most usually around drivers, so
>> I don't know exactly here I could add shared code. Should I add the
>> headers to "internal.h"?
>
> My comment isn't related to drivers or memory management. It's solely about
> avoiding code duplication. For example, we could create a shared function to
> handle both controls, reducing redundant code :-)
Let me rephrase it.
I completely agree that we should avoid code duplication. I'm asking
where is the best place to add the headers of the shared functions.
"linux/shmem_fs.h" doesn't look appropriate to me, so I believe the
remaining options would be "linux/huge_mm.h" or "internal.h".
I would like to know your opinion about those two options.
Best Regards,
- Maíra
>
>>
>> Best Regards,
>> - Maíra
>>
>>>
>>>> +__setup("thp_shmem=", setup_thp_shmem);
>>>> +
>>>> #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>>>>
>>>> #else /* !CONFIG_SHMEM */
>>>> --
>>>> 2.46.2
>>>>
>>>
>>> Thanks
>>> barry
>>
On Mon, Oct 28, 2024 at 7:34 PM Maíra Canal <mcanal@igalia.com> wrote:
>
> Hi Barry,
>
> On 28/10/24 08:09, Barry Song wrote:
> > On Mon, Oct 28, 2024 at 6:10 PM Maíra Canal <mcanal@igalia.com> wrote:
> >>
> >> Hi Barry,
> >>
> >> On 27/10/24 18:54, Barry Song wrote:
> >>> On Mon, Oct 28, 2024 at 6:58 AM Maíra Canal <mcanal@igalia.com> wrote:
> >>>>
> >>>> Add the ``thp_shmem=`` kernel command line to allow specifying the
> >>>> default policy of each supported shmem hugepage size. The kernel parameter
> >>>> accepts the following format:
> >>>>
> >>>> thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
> >>>>
> >>>> For example,
> >>>>
> >>>> thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
> >>>>
> >>>> By configuring the default policy of several shmem huge pages, the user
> >>>> can take advantage of mTHP before it's been configured through sysfs.
> >>>>
> >>>> Signed-off-by: Maíra Canal <mcanal@igalia.com>
> >>>> ---
> >>>> .../admin-guide/kernel-parameters.txt | 10 ++
> >>>> Documentation/admin-guide/mm/transhuge.rst | 17 +++
> >>>> mm/shmem.c | 109 +++++++++++++++++-
> >>>> 3 files changed, 135 insertions(+), 1 deletion(-)
> >>>>
> >>>
> >>> Hi Maíra,
> >>>
> >>>> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> >>>> index acabb04d0dd4..595fa096e28b 100644
> >>>> --- a/Documentation/admin-guide/kernel-parameters.txt
> >>>> +++ b/Documentation/admin-guide/kernel-parameters.txt
> >>>> @@ -6700,6 +6700,16 @@
> >>>> Force threading of all interrupt handlers except those
> >>>> marked explicitly IRQF_NO_THREAD.
> >>>>
> >>>> + shmem_anon= [KNL]
> >>>> + Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
> >>>> + Control the default policy of each hugepage size for the
> >>>> + internal shmem mount. <policy> is one of policies available
> >>>> + for the shmem mount ("always", "inherit", "never", "within_size",
> >>>> + and "advise").
> >>>> + It can be used multiple times for multiple shmem THP sizes.
> >>>> + See Documentation/admin-guide/mm/transhuge.rst for more
> >>>> + details.
> >>>
> >>> I'm not sure this is the right name. How about "thp_shmem"?
> >>
> >> Oops, sorry about that.
> >>
> >>>
> >>>> +
> >>>> topology= [S390,EARLY]
> >>>> Format: {off | on}
> >>>> Specify if the kernel should make use of the cpu
> >>>> diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
> >>>> index 9b5b02c4d1ab..47e7fc30e22d 100644
> >>>> --- a/Documentation/admin-guide/mm/transhuge.rst
> >>>> +++ b/Documentation/admin-guide/mm/transhuge.rst
> >>>> @@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
> >>>> seven valid policies for shmem (``always``, ``within_size``, ``advise``,
> >>>> ``never``, ``deny``, and ``force``).
> >>>>
> >>>> +In the same manner as ``thp_anon`` controls each supported anonymous THP
> >>>> +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
> >>>> +has the same format as ``thp_anon``, but also supports the policy
> >>>> +``within_size``.
> >>>> +
> >>>> +``thp_shmem=`` may be specified multiple times to configure all THP sizes
> >>>> +as required. If ``thp_shmem=`` is specified at least once, any shmem THP
> >>>> +sizes not explicitly configured on the command line are implicitly set to
> >>>> +``never``.
> >>>> +
> >>>> +``transparent_hugepage_shmem`` setting only affects the global toggle. If
> >>>> +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
> >>>> +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
> >>>> +user, the PMD_ORDER hugepage policy will be overridden. If the policy for
> >>>> +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
> >>>> +default to ``never``.
> >>>> +
> >>>> Hugepages in tmpfs/shmem
> >>>> ========================
> >>>>
> >>>> diff --git a/mm/shmem.c b/mm/shmem.c
> >>>> index 24cdeafd8260..0a7a7d04f725 100644
> >>>> --- a/mm/shmem.c
> >>>> +++ b/mm/shmem.c
>
> [...]
>
> >>>> static int __init setup_transparent_hugepage_shmem(char *str)
> >>>> {
> >>>> int huge, ret = 0;
> >>>> @@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
> >>>> }
> >>>> __setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
> >>>>
> >>>> +static char str_dup[PAGE_SIZE] __initdata;
> >>>> +static int __init setup_thp_shmem(char *str)
> >>>> +{
> >>>> + char *token, *range, *policy, *subtoken;
> >>>> + unsigned long always, inherit, madvise, within_size;
> >>>> + char *start_size, *end_size;
> >>>> + int start, end, nr;
> >>>> + char *p;
> >>>> +
> >>>> + if (!str || strlen(str) + 1 > PAGE_SIZE)
> >>>> + goto err;
> >>>> + strcpy(str_dup, str);
> >>>> +
> >>>> + always = huge_shmem_orders_always;
> >>>> + inherit = huge_shmem_orders_inherit;
> >>>> + madvise = huge_shmem_orders_madvise;
> >>>> + within_size = huge_shmem_orders_within_size;
> >>>> + p = str_dup;
> >>>> + while ((token = strsep(&p, ";")) != NULL) {
> >>>> + range = strsep(&token, ":");
> >>>> + policy = token;
> >>>> +
> >>>> + if (!policy)
> >>>> + goto err;
> >>>> +
> >>>> + while ((subtoken = strsep(&range, ",")) != NULL) {
> >>>> + if (strchr(subtoken, '-')) {
> >>>> + start_size = strsep(&subtoken, "-");
> >>>> + end_size = subtoken;
> >>>> +
> >>>> + start = get_order_from_str(start_size);
> >>>> + end = get_order_from_str(end_size);
> >>>> + } else {
> >>>> + start = end = get_order_from_str(subtoken);
> >>>> + }
> >>>> +
> >>>> + if (start < 0 || end < 0 || start > end)
> >>>> + goto err;
> >>>> +
> >>>> + nr = end - start + 1;
> >>>> + if (!strcmp(policy, "always")) {
> >>>> + bitmap_set(&always, start, nr);
> >>>> + bitmap_clear(&inherit, start, nr);
> >>>> + bitmap_clear(&madvise, start, nr);
> >>>> + bitmap_clear(&within_size, start, nr);
> >>>> + } else if (!strcmp(policy, "advise")) {
> >>>> + bitmap_set(&madvise, start, nr);
> >>>> + bitmap_clear(&inherit, start, nr);
> >>>> + bitmap_clear(&always, start, nr);
> >>>> + bitmap_clear(&within_size, start, nr);
> >>>> + } else if (!strcmp(policy, "inherit")) {
> >>>> + bitmap_set(&inherit, start, nr);
> >>>> + bitmap_clear(&madvise, start, nr);
> >>>> + bitmap_clear(&always, start, nr);
> >>>> + bitmap_clear(&within_size, start, nr);
> >>>> + } else if (!strcmp(policy, "within_size")) {
> >>>> + bitmap_set(&within_size, start, nr);
> >>>> + bitmap_clear(&inherit, start, nr);
> >>>> + bitmap_clear(&madvise, start, nr);
> >>>> + bitmap_clear(&always, start, nr);
> >>>> + } else if (!strcmp(policy, "never")) {
> >>>> + bitmap_clear(&inherit, start, nr);
> >>>> + bitmap_clear(&madvise, start, nr);
> >>>> + bitmap_clear(&always, start, nr);
> >>>> + bitmap_clear(&within_size, start, nr);
> >>>> + } else {
> >>>> + pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
> >>>> + goto err;
> >>>> + }
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + huge_shmem_orders_always = always;
> >>>> + huge_shmem_orders_madvise = madvise;
> >>>> + huge_shmem_orders_inherit = inherit;
> >>>> + huge_shmem_orders_within_size = within_size;
> >>>> + shmem_orders_configured = true;
> >>>> + return 1;
> >>>> +
> >>>> +err:
> >>>> + pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
> >>>> + return 0;
> >>>> +}
> >>>
> >>> Can we share source code with thp_anon since there's a lot of duplication?
> >>
> >> I'm not a regular mm contributor and I'm most usually around drivers, so
> >> I don't know exactly here I could add shared code. Should I add the
> >> headers to "internal.h"?
> >
> > My comment isn't related to drivers or memory management. It's solely about
> > avoiding code duplication. For example, we could create a shared function to
> > handle both controls, reducing redundant code :-)
>
> Let me rephrase it.
>
> I completely agree that we should avoid code duplication. I'm asking
> where is the best place to add the headers of the shared functions.
> "linux/shmem_fs.h" doesn't look appropriate to me, so I believe the
> remaining options would be "linux/huge_mm.h" or "internal.h".
Both locations seem quite odd. I have a feeling that these boot command
elements are purely internal, yet internal.h contains something that is
actually 'external' to mm. The shared code isn't 'external' enough to belong
in internal.h.
I didn't realize that shmem has placed these controls in its own file;
I thought they
were also located in mm/huge_memory.c. Given the current situation, I would
prefer to keep the code as it is and tolerate the code duplication.
Unless we are going to place controls for shmem and other thp controls in
one place, I feel your code is better than having a shared function either in
internal.h or linux/huge_mm.h.
>
> I would like to know your opinion about those two options.
>
> Best Regards,
> - Maíra
>
> >
> >>
> >> Best Regards,
> >> - Maíra
> >>
> >>>
> >>>> +__setup("thp_shmem=", setup_thp_shmem);
> >>>> +
> >>>> #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
> >>>>
> >>>> #else /* !CONFIG_SHMEM */
> >>>> --
> >>>> 2.46.2
> >>>>
> >>>
Thanks
barry
Hi Barry,
On 28/10/24 19:35, Barry Song wrote:
> On Mon, Oct 28, 2024 at 7:34 PM Maíra Canal <mcanal@igalia.com> wrote:
>>
>> Hi Barry,
>>
>> On 28/10/24 08:09, Barry Song wrote:
>>> On Mon, Oct 28, 2024 at 6:10 PM Maíra Canal <mcanal@igalia.com> wrote:
>>>>
>>>> Hi Barry,
>>>>
>>>> On 27/10/24 18:54, Barry Song wrote:
>>>>> On Mon, Oct 28, 2024 at 6:58 AM Maíra Canal <mcanal@igalia.com> wrote:
>>>>>>
>>>>>> Add the ``thp_shmem=`` kernel command line to allow specifying the
>>>>>> default policy of each supported shmem hugepage size. The kernel parameter
>>>>>> accepts the following format:
>>>>>>
>>>>>> thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
>>>>>>
>>>>>> For example,
>>>>>>
>>>>>> thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
>>>>>>
>>>>>> By configuring the default policy of several shmem huge pages, the user
>>>>>> can take advantage of mTHP before it's been configured through sysfs.
>>>>>>
>>>>>> Signed-off-by: Maíra Canal <mcanal@igalia.com>
>>>>>> ---
>>>>>> .../admin-guide/kernel-parameters.txt | 10 ++
>>>>>> Documentation/admin-guide/mm/transhuge.rst | 17 +++
>>>>>> mm/shmem.c | 109 +++++++++++++++++-
>>>>>> 3 files changed, 135 insertions(+), 1 deletion(-)
>>>>>>
>>>>>
>>>>> Hi Maíra,
>>>>>
>>>>>> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
>>>>>> index acabb04d0dd4..595fa096e28b 100644
>>>>>> --- a/Documentation/admin-guide/kernel-parameters.txt
>>>>>> +++ b/Documentation/admin-guide/kernel-parameters.txt
>>>>>> @@ -6700,6 +6700,16 @@
>>>>>> Force threading of all interrupt handlers except those
>>>>>> marked explicitly IRQF_NO_THREAD.
>>>>>>
>>>>>> + shmem_anon= [KNL]
>>>>>> + Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
>>>>>> + Control the default policy of each hugepage size for the
>>>>>> + internal shmem mount. <policy> is one of policies available
>>>>>> + for the shmem mount ("always", "inherit", "never", "within_size",
>>>>>> + and "advise").
>>>>>> + It can be used multiple times for multiple shmem THP sizes.
>>>>>> + See Documentation/admin-guide/mm/transhuge.rst for more
>>>>>> + details.
>>>>>
>>>>> I'm not sure this is the right name. How about "thp_shmem"?
>>>>
>>>> Oops, sorry about that.
>>>>
>>>>>
>>>>>> +
>>>>>> topology= [S390,EARLY]
>>>>>> Format: {off | on}
>>>>>> Specify if the kernel should make use of the cpu
>>>>>> diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
>>>>>> index 9b5b02c4d1ab..47e7fc30e22d 100644
>>>>>> --- a/Documentation/admin-guide/mm/transhuge.rst
>>>>>> +++ b/Documentation/admin-guide/mm/transhuge.rst
>>>>>> @@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
>>>>>> seven valid policies for shmem (``always``, ``within_size``, ``advise``,
>>>>>> ``never``, ``deny``, and ``force``).
>>>>>>
>>>>>> +In the same manner as ``thp_anon`` controls each supported anonymous THP
>>>>>> +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
>>>>>> +has the same format as ``thp_anon``, but also supports the policy
>>>>>> +``within_size``.
>>>>>> +
>>>>>> +``thp_shmem=`` may be specified multiple times to configure all THP sizes
>>>>>> +as required. If ``thp_shmem=`` is specified at least once, any shmem THP
>>>>>> +sizes not explicitly configured on the command line are implicitly set to
>>>>>> +``never``.
>>>>>> +
>>>>>> +``transparent_hugepage_shmem`` setting only affects the global toggle. If
>>>>>> +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
>>>>>> +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
>>>>>> +user, the PMD_ORDER hugepage policy will be overridden. If the policy for
>>>>>> +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
>>>>>> +default to ``never``.
>>>>>> +
>>>>>> Hugepages in tmpfs/shmem
>>>>>> ========================
>>>>>>
>>>>>> diff --git a/mm/shmem.c b/mm/shmem.c
>>>>>> index 24cdeafd8260..0a7a7d04f725 100644
>>>>>> --- a/mm/shmem.c
>>>>>> +++ b/mm/shmem.c
>>
>> [...]
>>
>>>>>> static int __init setup_transparent_hugepage_shmem(char *str)
>>>>>> {
>>>>>> int huge, ret = 0;
>>>>>> @@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
>>>>>> }
>>>>>> __setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
>>>>>>
>>>>>> +static char str_dup[PAGE_SIZE] __initdata;
>>>>>> +static int __init setup_thp_shmem(char *str)
>>>>>> +{
>>>>>> + char *token, *range, *policy, *subtoken;
>>>>>> + unsigned long always, inherit, madvise, within_size;
>>>>>> + char *start_size, *end_size;
>>>>>> + int start, end, nr;
>>>>>> + char *p;
>>>>>> +
>>>>>> + if (!str || strlen(str) + 1 > PAGE_SIZE)
>>>>>> + goto err;
>>>>>> + strcpy(str_dup, str);
>>>>>> +
>>>>>> + always = huge_shmem_orders_always;
>>>>>> + inherit = huge_shmem_orders_inherit;
>>>>>> + madvise = huge_shmem_orders_madvise;
>>>>>> + within_size = huge_shmem_orders_within_size;
>>>>>> + p = str_dup;
>>>>>> + while ((token = strsep(&p, ";")) != NULL) {
>>>>>> + range = strsep(&token, ":");
>>>>>> + policy = token;
>>>>>> +
>>>>>> + if (!policy)
>>>>>> + goto err;
>>>>>> +
>>>>>> + while ((subtoken = strsep(&range, ",")) != NULL) {
>>>>>> + if (strchr(subtoken, '-')) {
>>>>>> + start_size = strsep(&subtoken, "-");
>>>>>> + end_size = subtoken;
>>>>>> +
>>>>>> + start = get_order_from_str(start_size);
>>>>>> + end = get_order_from_str(end_size);
>>>>>> + } else {
>>>>>> + start = end = get_order_from_str(subtoken);
>>>>>> + }
>>>>>> +
>>>>>> + if (start < 0 || end < 0 || start > end)
>>>>>> + goto err;
>>>>>> +
>>>>>> + nr = end - start + 1;
>>>>>> + if (!strcmp(policy, "always")) {
>>>>>> + bitmap_set(&always, start, nr);
>>>>>> + bitmap_clear(&inherit, start, nr);
>>>>>> + bitmap_clear(&madvise, start, nr);
>>>>>> + bitmap_clear(&within_size, start, nr);
>>>>>> + } else if (!strcmp(policy, "advise")) {
>>>>>> + bitmap_set(&madvise, start, nr);
>>>>>> + bitmap_clear(&inherit, start, nr);
>>>>>> + bitmap_clear(&always, start, nr);
>>>>>> + bitmap_clear(&within_size, start, nr);
>>>>>> + } else if (!strcmp(policy, "inherit")) {
>>>>>> + bitmap_set(&inherit, start, nr);
>>>>>> + bitmap_clear(&madvise, start, nr);
>>>>>> + bitmap_clear(&always, start, nr);
>>>>>> + bitmap_clear(&within_size, start, nr);
>>>>>> + } else if (!strcmp(policy, "within_size")) {
>>>>>> + bitmap_set(&within_size, start, nr);
>>>>>> + bitmap_clear(&inherit, start, nr);
>>>>>> + bitmap_clear(&madvise, start, nr);
>>>>>> + bitmap_clear(&always, start, nr);
>>>>>> + } else if (!strcmp(policy, "never")) {
>>>>>> + bitmap_clear(&inherit, start, nr);
>>>>>> + bitmap_clear(&madvise, start, nr);
>>>>>> + bitmap_clear(&always, start, nr);
>>>>>> + bitmap_clear(&within_size, start, nr);
>>>>>> + } else {
>>>>>> + pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
>>>>>> + goto err;
>>>>>> + }
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + huge_shmem_orders_always = always;
>>>>>> + huge_shmem_orders_madvise = madvise;
>>>>>> + huge_shmem_orders_inherit = inherit;
>>>>>> + huge_shmem_orders_within_size = within_size;
>>>>>> + shmem_orders_configured = true;
>>>>>> + return 1;
>>>>>> +
>>>>>> +err:
>>>>>> + pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
>>>>>> + return 0;
>>>>>> +}
>>>>>
>>>>> Can we share source code with thp_anon since there's a lot of duplication?
>>>>
>>>> I'm not a regular mm contributor and I'm most usually around drivers, so
>>>> I don't know exactly here I could add shared code. Should I add the
>>>> headers to "internal.h"?
>>>
>>> My comment isn't related to drivers or memory management. It's solely about
>>> avoiding code duplication. For example, we could create a shared function to
>>> handle both controls, reducing redundant code :-)
>>
>> Let me rephrase it.
>>
>> I completely agree that we should avoid code duplication. I'm asking
>> where is the best place to add the headers of the shared functions.
>> "linux/shmem_fs.h" doesn't look appropriate to me, so I believe the
>> remaining options would be "linux/huge_mm.h" or "internal.h".
>
> Both locations seem quite odd. I have a feeling that these boot command
> elements are purely internal, yet internal.h contains something that is
> actually 'external' to mm. The shared code isn't 'external' enough to belong
> in internal.h.
>
> I didn't realize that shmem has placed these controls in its own file;
> I thought they
> were also located in mm/huge_memory.c. Given the current situation, I would
> prefer to keep the code as it is and tolerate the code duplication.
>
> Unless we are going to place controls for shmem and other thp controls in
> one place, I feel your code is better than having a shared function either in
> internal.h or linux/huge_mm.h.
Sorry, I only catch your e-mail after sending v2. If possible, please,
take a look on v2 [1] and let me know if you still prefer to duplicate
the code.
[1]
https://lore.kernel.org/linux-mm/20241029002324.1062723-1-mcanal@igalia.com/T/
Best Regards,
- Maíra
>
>>
>> I would like to know your opinion about those two options.
>>
>> Best Regards,
>> - Maíra
>>
>>>
>>>>
>>>> Best Regards,
>>>> - Maíra
>>>>
>>>>>
>>>>>> +__setup("thp_shmem=", setup_thp_shmem);
>>>>>> +
>>>>>> #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>>>>>>
>>>>>> #else /* !CONFIG_SHMEM */
>>>>>> --
>>>>>> 2.46.2
>>>>>>
>>>>>
>
> Thanks
> barry
Hi Maíra,
On Mon, Oct 28, 2024 at 5:54 AM Barry Song <21cnbao@gmail.com> wrote:
>
> On Mon, Oct 28, 2024 at 6:58 AM Maíra Canal <mcanal@igalia.com> wrote:
> >
> > Add the ``thp_shmem=`` kernel command line to allow specifying the
> > default policy of each supported shmem hugepage size. The kernel parameter
> > accepts the following format:
> >
> > thp_shmem=<size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
> >
> > For example,
> >
> > thp_shmem=16K-64K:always;128K,512K:inherit;256K:advise;1M-2M:never;4M-8M:within_size
> >
> > By configuring the default policy of several shmem huge pages, the user
> > can take advantage of mTHP before it's been configured through sysfs.
> >
> > Signed-off-by: Maíra Canal <mcanal@igalia.com>
> > ---
> > .../admin-guide/kernel-parameters.txt | 10 ++
> > Documentation/admin-guide/mm/transhuge.rst | 17 +++
> > mm/shmem.c | 109 +++++++++++++++++-
> > 3 files changed, 135 insertions(+), 1 deletion(-)
> >
>
> Hi Maíra,
>
> > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> > index acabb04d0dd4..595fa096e28b 100644
> > --- a/Documentation/admin-guide/kernel-parameters.txt
> > +++ b/Documentation/admin-guide/kernel-parameters.txt
> > @@ -6700,6 +6700,16 @@
> > Force threading of all interrupt handlers except those
> > marked explicitly IRQF_NO_THREAD.
> >
> > + shmem_anon= [KNL]
> > + Format: <size>[KMG],<size>[KMG]:<policy>;<size>[KMG]-<size>[KMG]:<policy>
> > + Control the default policy of each hugepage size for the
> > + internal shmem mount. <policy> is one of policies available
> > + for the shmem mount ("always", "inherit", "never", "within_size",
> > + and "advise").
> > + It can be used multiple times for multiple shmem THP sizes.
> > + See Documentation/admin-guide/mm/transhuge.rst for more
> > + details.
>
> I'm not sure this is the right name. How about "thp_shmem"?
+1
IHMO, it seems like 'thp_shmem' would be better, as it appears to fit well
with 'thp_anon' in naming style ;)
Thanks,
Lance
>
> > +
> > topology= [S390,EARLY]
> > Format: {off | on}
> > Specify if the kernel should make use of the cpu
> > diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
> > index 9b5b02c4d1ab..47e7fc30e22d 100644
> > --- a/Documentation/admin-guide/mm/transhuge.rst
> > +++ b/Documentation/admin-guide/mm/transhuge.rst
> > @@ -332,6 +332,23 @@ allocation policy for the internal shmem mount by using the kernel parameter
> > seven valid policies for shmem (``always``, ``within_size``, ``advise``,
> > ``never``, ``deny``, and ``force``).
> >
> > +In the same manner as ``thp_anon`` controls each supported anonymous THP
> > +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
> > +has the same format as ``thp_anon``, but also supports the policy
> > +``within_size``.
> > +
> > +``thp_shmem=`` may be specified multiple times to configure all THP sizes
> > +as required. If ``thp_shmem=`` is specified at least once, any shmem THP
> > +sizes not explicitly configured on the command line are implicitly set to
> > +``never``.
> > +
> > +``transparent_hugepage_shmem`` setting only affects the global toggle. If
> > +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
> > +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
> > +user, the PMD_ORDER hugepage policy will be overridden. If the policy for
> > +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
> > +default to ``never``.
> > +
> > Hugepages in tmpfs/shmem
> > ========================
> >
> > diff --git a/mm/shmem.c b/mm/shmem.c
> > index 24cdeafd8260..0a7a7d04f725 100644
> > --- a/mm/shmem.c
> > +++ b/mm/shmem.c
> > @@ -136,6 +136,7 @@ static unsigned long huge_shmem_orders_always __read_mostly;
> > static unsigned long huge_shmem_orders_madvise __read_mostly;
> > static unsigned long huge_shmem_orders_inherit __read_mostly;
> > static unsigned long huge_shmem_orders_within_size __read_mostly;
> > +static bool shmem_orders_configured __initdata;
> > #endif
> >
> > #ifdef CONFIG_TMPFS
> > @@ -5013,7 +5014,8 @@ void __init shmem_init(void)
> > * Default to setting PMD-sized THP to inherit the global setting and
> > * disable all other multi-size THPs.
> > */
> > - huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
> > + if (!shmem_orders_configured)
> > + huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
> > #endif
> > return;
> >
> > @@ -5174,6 +5176,26 @@ struct kobj_attribute thpsize_shmem_enabled_attr =
> >
> > #if defined(CONFIG_TRANSPARENT_HUGEPAGE)
> >
> > +static inline int get_order_from_str(const char *size_str)
> > +{
> > + unsigned long size;
> > + char *endptr;
> > + int order;
> > +
> > + size = memparse(size_str, &endptr);
> > +
> > + if (!is_power_of_2(size))
> > + goto err;
> > + order = get_order(size);
> > + if (BIT(order) & ~THP_ORDERS_ALL_FILE_DEFAULT)
> > + goto err;
> > +
> > + return order;
> > +err:
> > + pr_err("invalid size %s in thp_shmem boot parameter\n", size_str);
> > + return -EINVAL;
> > +}
> > +
> > static int __init setup_transparent_hugepage_shmem(char *str)
> > {
> > int huge, ret = 0;
> > @@ -5206,6 +5228,91 @@ static int __init setup_transparent_hugepage_shmem(char *str)
> > }
> > __setup("transparent_hugepage_shmem=", setup_transparent_hugepage_shmem);
> >
> > +static char str_dup[PAGE_SIZE] __initdata;
> > +static int __init setup_thp_shmem(char *str)
> > +{
> > + char *token, *range, *policy, *subtoken;
> > + unsigned long always, inherit, madvise, within_size;
> > + char *start_size, *end_size;
> > + int start, end, nr;
> > + char *p;
> > +
> > + if (!str || strlen(str) + 1 > PAGE_SIZE)
> > + goto err;
> > + strcpy(str_dup, str);
> > +
> > + always = huge_shmem_orders_always;
> > + inherit = huge_shmem_orders_inherit;
> > + madvise = huge_shmem_orders_madvise;
> > + within_size = huge_shmem_orders_within_size;
> > + p = str_dup;
> > + while ((token = strsep(&p, ";")) != NULL) {
> > + range = strsep(&token, ":");
> > + policy = token;
> > +
> > + if (!policy)
> > + goto err;
> > +
> > + while ((subtoken = strsep(&range, ",")) != NULL) {
> > + if (strchr(subtoken, '-')) {
> > + start_size = strsep(&subtoken, "-");
> > + end_size = subtoken;
> > +
> > + start = get_order_from_str(start_size);
> > + end = get_order_from_str(end_size);
> > + } else {
> > + start = end = get_order_from_str(subtoken);
> > + }
> > +
> > + if (start < 0 || end < 0 || start > end)
> > + goto err;
> > +
> > + nr = end - start + 1;
> > + if (!strcmp(policy, "always")) {
> > + bitmap_set(&always, start, nr);
> > + bitmap_clear(&inherit, start, nr);
> > + bitmap_clear(&madvise, start, nr);
> > + bitmap_clear(&within_size, start, nr);
> > + } else if (!strcmp(policy, "advise")) {
> > + bitmap_set(&madvise, start, nr);
> > + bitmap_clear(&inherit, start, nr);
> > + bitmap_clear(&always, start, nr);
> > + bitmap_clear(&within_size, start, nr);
> > + } else if (!strcmp(policy, "inherit")) {
> > + bitmap_set(&inherit, start, nr);
> > + bitmap_clear(&madvise, start, nr);
> > + bitmap_clear(&always, start, nr);
> > + bitmap_clear(&within_size, start, nr);
> > + } else if (!strcmp(policy, "within_size")) {
> > + bitmap_set(&within_size, start, nr);
> > + bitmap_clear(&inherit, start, nr);
> > + bitmap_clear(&madvise, start, nr);
> > + bitmap_clear(&always, start, nr);
> > + } else if (!strcmp(policy, "never")) {
> > + bitmap_clear(&inherit, start, nr);
> > + bitmap_clear(&madvise, start, nr);
> > + bitmap_clear(&always, start, nr);
> > + bitmap_clear(&within_size, start, nr);
> > + } else {
> > + pr_err("invalid policy %s in thp_shmem boot parameter\n", policy);
> > + goto err;
> > + }
> > + }
> > + }
> > +
> > + huge_shmem_orders_always = always;
> > + huge_shmem_orders_madvise = madvise;
> > + huge_shmem_orders_inherit = inherit;
> > + huge_shmem_orders_within_size = within_size;
> > + shmem_orders_configured = true;
> > + return 1;
> > +
> > +err:
> > + pr_warn("thp_shmem=%s: error parsing string, ignoring setting\n", str);
> > + return 0;
> > +}
>
> Can we share source code with thp_anon since there's a lot of duplication?
>
> > +__setup("thp_shmem=", setup_thp_shmem);
> > +
> > #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
> >
> > #else /* !CONFIG_SHMEM */
> > --
> > 2.46.2
> >
>
> Thanks
> barry
© 2016 - 2026 Red Hat, Inc.