Skip to content

Commit

Permalink
mm: hugetlb_vmemmap: introduce CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP
Browse files Browse the repository at this point in the history
If the size of "struct page" is not the power of two but with the feature
of minimizing overhead of struct page associated with each HugeTLB is
enabled, then the vmemmap pages of HugeTLB will be corrupted after
remapping (panic is about to happen in theory).  But this only exists when
!CONFIG_MEMCG && !CONFIG_SLUB on x86_64.  However, it is not a conventional
configuration nowadays.  So it is not a real word issue, just the result
of a code review.  But we have to prevent anyone from configuring that
combined configurations.  In order to avoid many checks like "is_power_of_2
(sizeof(struct page))" through mm/hugetlb_vmemmap.c.  Introduce a new macro
CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP to represent the size of struct
page is power of two and CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP is
configured.  Then make the codes of this feature depends on this new macro.
Then we could prevent anyone do any unexpected configurations.  A new
autoconf_ext.h is introduced as well, which serves as an extension for
autoconf.h since those special configurations (e.g.
CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP here) are rely on the autoconf.h
(generated from Kconfig), so we cannot embed those configurations into
Kconfig.  After this change, it would be easy if someone want to do the
similar thing (add a new CONFIG) in the future.

Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Suggested-by: Luis Chamberlain <mcgrof@kernel.org>
  • Loading branch information
Muchun Song authored and intel-lab-lkp committed Apr 12, 2022
1 parent 71e0d84 commit bb63a01
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 14 deletions.
19 changes: 19 additions & 0 deletions Kbuild
Expand Up @@ -2,6 +2,12 @@
#
# Kbuild for top-level directory of the kernel

# autoconf_ext.h is generated last since it depends on other generated headers,
# however those other generated headers may include autoconf_ext.h. Use the
# following macro to avoid circular dependency.

KBUILD_CFLAGS_KERNEL += -D__EXCLUDE_AUTOCONF_EXT_H

#####
# Generate bounds.h

Expand Down Expand Up @@ -36,6 +42,19 @@ arch/$(SRCARCH)/kernel/asm-offsets.s: $(timeconst-file) $(bounds-file)
$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE
$(call filechk,offsets,__ASM_OFFSETS_H__)

#####
# Generate autoconf_ext.h.

autoconf_ext-file := include/generated/autoconf_ext.h

always-y += $(autoconf_ext-file)
targets += kernel/autoconf_ext.s

kernel/autoconf_ext.s: $(bounds-file) $(timeconst-file) $(offsets-file)

$(autoconf_ext-file): kernel/autoconf_ext.s FORCE
$(call filechk,offsets,__LINUX_AUTOCONF_EXT_H__)

#####
# Check for missing system calls

Expand Down
2 changes: 1 addition & 1 deletion arch/x86/mm/init_64.c
Expand Up @@ -1269,7 +1269,7 @@ static struct kcore_list kcore_vsyscall;

static void __init register_page_bootmem_info(void)
{
#if defined(CONFIG_NUMA) || defined(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP)
#if defined(CONFIG_NUMA) || defined(CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP)
int i;

for_each_online_node(i)
Expand Down
2 changes: 1 addition & 1 deletion include/linux/hugetlb.h
Expand Up @@ -623,7 +623,7 @@ struct hstate {
unsigned int nr_huge_pages_node[MAX_NUMNODES];
unsigned int free_huge_pages_node[MAX_NUMNODES];
unsigned int surplus_huge_pages_node[MAX_NUMNODES];
#ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
#ifdef CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP
unsigned int optimize_vmemmap_pages;
#endif
#ifdef CONFIG_CGROUP_HUGETLB
Expand Down
4 changes: 4 additions & 0 deletions include/linux/kconfig.h
Expand Up @@ -4,6 +4,10 @@

#include <generated/autoconf.h>

#ifndef __EXCLUDE_AUTOCONF_EXT_H
#include <generated/autoconf_ext.h>
#endif

#ifdef CONFIG_CPU_BIG_ENDIAN
#define __BIG_ENDIAN 4321
#else
Expand Down
2 changes: 1 addition & 1 deletion include/linux/mm.h
Expand Up @@ -3186,7 +3186,7 @@ static inline void print_vma_addr(char *prefix, unsigned long rip)
}
#endif

#ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
#ifdef CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP
int vmemmap_remap_free(unsigned long start, unsigned long end,
unsigned long reuse);
int vmemmap_remap_alloc(unsigned long start, unsigned long end,
Expand Down
2 changes: 1 addition & 1 deletion include/linux/page-flags.h
Expand Up @@ -199,7 +199,7 @@ enum pageflags {

#ifndef __GENERATING_BOUNDS_H

#ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
#ifdef CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP
DECLARE_STATIC_KEY_MAYBE(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON,
hugetlb_optimize_vmemmap_key);

Expand Down
26 changes: 26 additions & 0 deletions kernel/autoconf_ext.c
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Generate definitions needed by the preprocessor.
* This code generates raw asm output which is post-processed
* to extract and format the required data.
*/
#include <linux/mm_types.h>
#include <linux/kbuild.h>
#include <linux/log2.h>

int main(void)
{
if (IS_ENABLED(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP) &&
is_power_of_2(sizeof(struct page))) {
/*
* The 2nd parameter of DEFINE() will go into the comments. Do
* not pass 1 directly to it to make the generated macro more
* clear for the readers.
*/
DEFINE(CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP,
IS_ENABLED(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP) &&
is_power_of_2(sizeof(struct page)));
}

return 0;
}
8 changes: 2 additions & 6 deletions mm/hugetlb_vmemmap.c
Expand Up @@ -178,6 +178,7 @@

#include "hugetlb_vmemmap.h"

#ifdef CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP
/*
* There are a lot of struct page structures associated with each HugeTLB page.
* For tail pages, the value of compound_head is the same. So we can reuse first
Expand All @@ -194,12 +195,6 @@ EXPORT_SYMBOL(hugetlb_optimize_vmemmap_key);

static int __init hugetlb_vmemmap_early_param(char *buf)
{
/* We cannot optimize if a "struct page" crosses page boundaries. */
if (!is_power_of_2(sizeof(struct page))) {
pr_warn("cannot free vmemmap pages because \"struct page\" crosses page boundaries\n");
return 0;
}

if (!buf)
return -EINVAL;

Expand Down Expand Up @@ -300,3 +295,4 @@ void __init hugetlb_vmemmap_init(struct hstate *h)
pr_info("can optimize %d vmemmap pages for %s\n",
h->optimize_vmemmap_pages, h->name);
}
#endif /* CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP */
4 changes: 2 additions & 2 deletions mm/hugetlb_vmemmap.h
Expand Up @@ -10,7 +10,7 @@
#define _LINUX_HUGETLB_VMEMMAP_H
#include <linux/hugetlb.h>

#ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
#ifdef CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP
int hugetlb_vmemmap_alloc(struct hstate *h, struct page *head);
void hugetlb_vmemmap_free(struct hstate *h, struct page *head);
void hugetlb_vmemmap_init(struct hstate *h);
Expand Down Expand Up @@ -41,5 +41,5 @@ static inline unsigned int hugetlb_optimize_vmemmap_pages(struct hstate *h)
{
return 0;
}
#endif /* CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP */
#endif /* CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP */
#endif /* _LINUX_HUGETLB_VMEMMAP_H */
4 changes: 2 additions & 2 deletions mm/sparse-vmemmap.c
Expand Up @@ -34,7 +34,7 @@
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>

#ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
#ifdef CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP
/**
* struct vmemmap_remap_walk - walk vmemmap page table
*
Expand Down Expand Up @@ -420,7 +420,7 @@ int vmemmap_remap_alloc(unsigned long start, unsigned long end,

return 0;
}
#endif /* CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP */
#endif /* CONFIG_HUGETLB_PAGE_HAS_OPTIMIZE_VMEMMAP */

/*
* Allocate a block of memory to be used to back the virtual memory map
Expand Down
2 changes: 2 additions & 0 deletions scripts/mod/Makefile
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
OBJECT_FILES_NON_STANDARD := y
CFLAGS_REMOVE_empty.o += $(CC_FLAGS_LTO)
# See comments in Kbuild
KBUILD_CFLAGS_KERNEL += -D__EXCLUDE_AUTOCONF_EXT_H

hostprogs-always-y += modpost mk_elfconfig
always-y += empty.o
Expand Down

0 comments on commit bb63a01

Please sign in to comment.