Add thp_file= cmdline parameter to allow specifying the default enablement of each supported file-backed THP size. The parameter accepts the following format and can be provided multiple times to configure each size: thp_file=<size>[KMG]:<value> See Documentation/admin-guide/mm/transhuge.rst for more details. Configuring the defaults at boot time is often necessary because its not always possible to drop active executable pages from the page cache, especially if they are well used like libc. The command line parameter allows configuring the values before the first page is installed in the page cache. Signed-off-by: Ryan Roberts <ryan.roberts@xxxxxxx> --- .../admin-guide/kernel-parameters.txt | 8 ++++ Documentation/admin-guide/mm/transhuge.rst | 13 ++++++ mm/huge_memory.c | 45 ++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 48443ad12e3f..e3e99def5691 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6600,6 +6600,14 @@ See Documentation/admin-guide/mm/transhuge.rst for more details. + thp_file= [KNL] + Format: <size>[KMG]:always|always+exec|never + Can be used to control the default behavior of the + system with respect to file-backed transparent hugepages. + Can be used multiple times for multiple file-backed THP + sizes. See Documentation/admin-guide/mm/transhuge.rst + for more details. + threadirqs [KNL,EARLY] Force threading of all interrupt handlers except those marked explicitly IRQF_NO_THREAD. diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst index f53d43d986e2..2379ed4ad085 100644 --- a/Documentation/admin-guide/mm/transhuge.rst +++ b/Documentation/admin-guide/mm/transhuge.rst @@ -333,6 +333,19 @@ required. If ``thp_anon=`` is specified at least once, any anon THP sizes not explicitly configured on the command line are implicitly set to ``never``. +Each supported file-backed THP size can be controlled by passing +``thp_file=<size>[KMG]:<state>``, where ``<size>`` is the THP size and +``<state>`` is one of ``always``, ``always+exec`` or ``never``. + +For example, the following will set 64K THP to ``always+exec``:: + + thp_file=64K:always+exec + +``thp_file=`` may be specified multiple times to configure all THP sizes as +required. If ``thp_file=`` is specified at least once, any file-backed THP +sizes not explicitly configured on the command line are implicitly set to +``never``. + Hugepages in tmpfs/shmem ======================== diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 794d2790d90d..4d963dde7aea 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -83,6 +83,7 @@ unsigned long huge_anon_orders_inherit __read_mostly; unsigned long huge_file_orders_always __read_mostly; int huge_file_exec_order __read_mostly = -1; static bool anon_orders_configured; +static bool file_orders_configured; unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma, unsigned long vm_flags, @@ -774,7 +775,10 @@ static int __init hugepage_init_sysfs(struct kobject **hugepage_kobj) * (and therefore THP_ORDERS_ALL_FILE_DEFAULT) isn't a compile-time * constant so we have to do this here. */ - huge_file_orders_always = THP_ORDERS_ALL_FILE_DEFAULT; + if (!file_orders_configured) { + huge_file_orders_always = THP_ORDERS_ALL_FILE_DEFAULT; + file_orders_configured = true; + } *hugepage_kobj = kobject_create_and_add("transparent_hugepage", mm_kobj); if (unlikely(!*hugepage_kobj)) { @@ -1008,6 +1012,45 @@ static int __init setup_thp_anon(char *str) } __setup("thp_anon=", setup_thp_anon); +static int __init setup_thp_file(char *str) +{ + unsigned long size; + char *state; + int order; + int ret = 0; + + if (!str) + goto out; + + size = (unsigned long)memparse(str, &state); + order = ilog2(size >> PAGE_SHIFT); + if (*state != ':' || !is_power_of_2(size) || size <= PAGE_SIZE || + !(BIT(order) & THP_ORDERS_ALL_FILE_DEFAULT)) + goto out; + + state++; + + if (!strcmp(state, "always")) { + set_bit(order, &huge_file_orders_always); + ret = 1; + } else if (!strcmp(state, "always+exec")) { + set_bit(order, &huge_file_orders_always); + huge_file_exec_order = order; + ret = 1; + } else if (!strcmp(state, "never")) { + clear_bit(order, &huge_file_orders_always); + ret = 1; + } + + if (ret) + file_orders_configured = true; +out: + if (!ret) + pr_warn("thp_file=%s: cannot parse, ignored\n", str); + return ret; +} +__setup("thp_file=", setup_thp_file); + pmd_t maybe_pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma) { if (likely(vma->vm_flags & VM_WRITE)) -- 2.43.0