Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: hugetlb_vmemmap: optimize vmemmap_optimize_mode handling

We hold an another reference to hugetlb_optimize_vmemmap_key when making
vmemmap_optimize_mode on, because we use static_key to tell memory_hotplug
that memory_hotplug.memmap_on_memory should be overridden. However, this
rule has gone when we have introduced PageVmemmapSelfHosted. Therefore,
we could simplify vmemmap_optimize_mode handling by not holding an another
reference to hugetlb_optimize_vmemmap_key. This also means that we not
incur the extra page_fixed_fake_head checks if there are no vmemmap
optinmized hugetlb pages after this change.

Link: https://lkml.kernel.org/r/20220628092235.91270-3-songmuchun@bytedance.com
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Will Deacon <will@kernel.org>
Cc: Xiongchun Duan <duanxiongchun@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Muchun Song and committed by
Andrew Morton
cf5472e5 2da1c309

+9 -62
+2 -4
include/linux/page-flags.h
··· 205 205 #ifndef __GENERATING_BOUNDS_H 206 206 207 207 #ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP 208 - DECLARE_STATIC_KEY_MAYBE(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON, 209 - hugetlb_optimize_vmemmap_key); 208 + DECLARE_STATIC_KEY_FALSE(hugetlb_optimize_vmemmap_key); 210 209 211 210 /* 212 211 * If the feature of optimizing vmemmap pages associated with each HugeTLB ··· 225 226 */ 226 227 static __always_inline const struct page *page_fixed_fake_head(const struct page *page) 227 228 { 228 - if (!static_branch_maybe(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON, 229 - &hugetlb_optimize_vmemmap_key)) 229 + if (!static_branch_unlikely(&hugetlb_optimize_vmemmap_key)) 230 230 return page; 231 231 232 232 /*
+7 -58
mm/hugetlb_vmemmap.c
··· 23 23 #define RESERVE_VMEMMAP_NR 1U 24 24 #define RESERVE_VMEMMAP_SIZE (RESERVE_VMEMMAP_NR << PAGE_SHIFT) 25 25 26 - enum vmemmap_optimize_mode { 27 - VMEMMAP_OPTIMIZE_OFF, 28 - VMEMMAP_OPTIMIZE_ON, 29 - }; 30 - 31 - DEFINE_STATIC_KEY_MAYBE(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON, 32 - hugetlb_optimize_vmemmap_key); 26 + DEFINE_STATIC_KEY_FALSE(hugetlb_optimize_vmemmap_key); 33 27 EXPORT_SYMBOL(hugetlb_optimize_vmemmap_key); 34 28 35 - static enum vmemmap_optimize_mode vmemmap_optimize_mode = 29 + static bool vmemmap_optimize_enabled = 36 30 IS_ENABLED(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON); 37 - 38 - static void vmemmap_optimize_mode_switch(enum vmemmap_optimize_mode to) 39 - { 40 - if (vmemmap_optimize_mode == to) 41 - return; 42 - 43 - if (to == VMEMMAP_OPTIMIZE_OFF) 44 - static_branch_dec(&hugetlb_optimize_vmemmap_key); 45 - else 46 - static_branch_inc(&hugetlb_optimize_vmemmap_key); 47 - WRITE_ONCE(vmemmap_optimize_mode, to); 48 - } 49 31 50 32 static int __init hugetlb_vmemmap_early_param(char *buf) 51 33 { 52 - bool enable; 53 - enum vmemmap_optimize_mode mode; 54 - 55 - if (kstrtobool(buf, &enable)) 56 - return -EINVAL; 57 - 58 - mode = enable ? VMEMMAP_OPTIMIZE_ON : VMEMMAP_OPTIMIZE_OFF; 59 - vmemmap_optimize_mode_switch(mode); 60 - 61 - return 0; 34 + return kstrtobool(buf, &vmemmap_optimize_enabled); 62 35 } 63 36 early_param("hugetlb_free_vmemmap", hugetlb_vmemmap_early_param); 64 37 ··· 73 100 static unsigned int vmemmap_optimizable_pages(struct hstate *h, 74 101 struct page *head) 75 102 { 76 - if (READ_ONCE(vmemmap_optimize_mode) == VMEMMAP_OPTIMIZE_OFF) 103 + if (!READ_ONCE(vmemmap_optimize_enabled)) 77 104 return 0; 78 105 79 106 if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) { ··· 164 191 165 192 if (!is_power_of_2(sizeof(struct page))) { 166 193 pr_warn_once("cannot optimize vmemmap pages because \"struct page\" crosses page boundaries\n"); 167 - static_branch_disable(&hugetlb_optimize_vmemmap_key); 168 194 return; 169 195 } 170 196 ··· 184 212 } 185 213 186 214 #ifdef CONFIG_PROC_SYSCTL 187 - static int hugetlb_optimize_vmemmap_handler(struct ctl_table *table, int write, 188 - void *buffer, size_t *length, 189 - loff_t *ppos) 190 - { 191 - int ret; 192 - enum vmemmap_optimize_mode mode; 193 - static DEFINE_MUTEX(sysctl_mutex); 194 - 195 - if (write && !capable(CAP_SYS_ADMIN)) 196 - return -EPERM; 197 - 198 - mutex_lock(&sysctl_mutex); 199 - mode = vmemmap_optimize_mode; 200 - table->data = &mode; 201 - ret = proc_dointvec_minmax(table, write, buffer, length, ppos); 202 - if (write && !ret) 203 - vmemmap_optimize_mode_switch(mode); 204 - mutex_unlock(&sysctl_mutex); 205 - 206 - return ret; 207 - } 208 - 209 215 static struct ctl_table hugetlb_vmemmap_sysctls[] = { 210 216 { 211 217 .procname = "hugetlb_optimize_vmemmap", 212 - .maxlen = sizeof(enum vmemmap_optimize_mode), 218 + .data = &vmemmap_optimize_enabled, 219 + .maxlen = sizeof(int), 213 220 .mode = 0644, 214 - .proc_handler = hugetlb_optimize_vmemmap_handler, 215 - .extra1 = SYSCTL_ZERO, 216 - .extra2 = SYSCTL_ONE, 221 + .proc_handler = proc_dobool, 217 222 }, 218 223 { } 219 224 };