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 - 2024 Red Hat, Inc.