* [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection
[not found] <20241014105514.3206191-1-ryan.roberts@arm.com>
@ 2024-10-14 10:58 ` Ryan Roberts
2024-10-14 10:58 ` [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX Ryan Roberts
` (5 more replies)
0 siblings, 6 replies; 13+ messages in thread
From: Ryan Roberts @ 2024-10-14 10:58 UTC (permalink / raw)
To: David S. Miller, James E.J. Bottomley, Andreas Larsson,
Andrew Morton, Anshuman Khandual, Anton Ivanov, Ard Biesheuvel,
Arnd Bergmann, Borislav Petkov, Catalin Marinas, Chris Zankel,
Dave Hansen, David Hildenbrand, Dinh Nguyen, Geert Uytterhoeven,
Greg Marsden, Helge Deller, Huacai Chen, Ingo Molnar, Ivan Ivanov,
Johannes Berg, John Paul Adrian Glaubitz, Jonas Bonn,
Kalesh Singh, Marc Zyngier, Mark Rutland, Matthias Brugger,
Max Filippov, Miroslav Benes, Rich Felker, Richard Weinberger,
Stafford Horne, Stefan Kristiansson, Thomas Bogendoerfer,
Thomas Gleixner, Will Deacon, Yoshinori Sato, x86
Cc: Ryan Roberts, linux-alpha, linux-arch, linux-arm-kernel,
linux-csky, linux-hexagon, linux-kernel, linux-m68k, linux-mips,
linux-mm, linux-openrisc, linux-parisc, linux-riscv, linux-s390,
linux-sh, linux-snps-arc, linux-um, linuxppc-dev, loongarch,
sparclinux
arm64 can support multiple base page sizes. Instead of selecting a page
size at compile time, as is done today, we will make it possible to
select the desired page size on the command line.
In this case PAGE_SHIFT and it's derivatives, PAGE_SIZE and PAGE_MASK
(as well as a number of other macros related to or derived from
PAGE_SHIFT, but I'm not worrying about those yet), are no longer
compile-time constants. So the code base needs to cope with that.
As a first step, introduce MIN and MAX variants of these macros, which
express the range of possible page sizes. These are always compile-time
constants and can be used in many places where PAGE_[SHIFT|SIZE|MASK]
were previously used where a compile-time constant is required.
(Subsequent patches will do that conversion work). When the arch/build
doesn't support boot-time page size selection, the MIN and MAX variants
are equal and everything resolves as it did previously.
Additionally, introduce DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() which wrap
global variable defintions so that for boot-time page size selection
builds, the variable being wrapped is initialized at boot-time, instead
of compile-time. This is done by defining a function to do the
assignment, which has the "constructor" attribute. Constructor is
preferred over initcall, because when compiling a module, the module is
limited to a single initcall but constructors are unlimited. For
built-in code, constructors are now called earlier to guarrantee that
the variables are initialized by the time they are used. Any arch that
wants to enable boot-time page size selection will need to select
CONFIG_CONSTRUCTORS.
These new macros need to be available anywhere PAGE_SHIFT and friends
are available. Those are defined via asm/page.h (although some arches
have a sub-include that defines them). Unfortunately there is no
reliable asm-generic header we can easily piggy-back on, so let's define
a new one, pgtable-geometry.h, which we include near where each arch
defines PAGE_SHIFT. Ugh.
-------
Most of the problems that need to be solved over the next few patches
fall into these broad categories, which are all solved with the help of
these new macros:
1. Assignment of values derived from PAGE_SIZE in global variables
For boot-time page size builds, we must defer the initialization of
these variables until boot-time, when the page size is known. See
DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() as described above.
2. Define static storage in units related to PAGE_SIZE
This static storage will be defined according to PAGE_SIZE_MAX.
3. Define size of struct so that it is related to PAGE_SIZE
The struct often contains an array that is sized to fill the page. In
this case, use a flexible array with dynamic allocation. In other
cases, the struct fits exactly over a page, which is a header (e.g.
swap file header). In this case, remove the padding, and manually
determine the struct pointer within the page.
4. BUILD_BUG_ON() with values derived from PAGE_SIZE
In most cases, we can change these to compare againt the appropriate
limit (either MIN or MAX). In other cases, we must change these to
run-time BUG_ON().
5. Ensure page alignment of static data structures
Align instead to PAGE_SIZE_MAX.
6. #ifdeffery based on PAGE_SIZE
Often these can be changed to c code constructs. e.g. a macro that
returns a different value depending on page size can be changed to use
the ternary operator and the compiler will dead code strip it for the
compile-time constant case and runtime evaluate it for the non-const
case. Or #if/#else/#endif within a function can be converted to c
if/else blocks, which are also dead code stripped for the const case.
Sometimes we can change the c-preprocessor logic to use the
appropriate MIN/MAX limit.
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
***NOTE***
Any confused maintainers may want to read the cover note here for context:
https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
arch/alpha/include/asm/page.h | 1 +
arch/arc/include/asm/page.h | 1 +
arch/arm/include/asm/page.h | 1 +
arch/arm64/include/asm/page-def.h | 2 +
arch/csky/include/asm/page.h | 3 ++
arch/hexagon/include/asm/page.h | 2 +
arch/loongarch/include/asm/page.h | 2 +
arch/m68k/include/asm/page.h | 1 +
arch/microblaze/include/asm/page.h | 1 +
arch/mips/include/asm/page.h | 1 +
arch/nios2/include/asm/page.h | 2 +
arch/openrisc/include/asm/page.h | 1 +
arch/parisc/include/asm/page.h | 1 +
arch/powerpc/include/asm/page.h | 2 +
arch/riscv/include/asm/page.h | 1 +
arch/s390/include/asm/page.h | 1 +
arch/sh/include/asm/page.h | 1 +
arch/sparc/include/asm/page.h | 3 ++
arch/um/include/asm/page.h | 2 +
arch/x86/include/asm/page_types.h | 2 +
arch/xtensa/include/asm/page.h | 1 +
include/asm-generic/pgtable-geometry.h | 71 ++++++++++++++++++++++++++
init/main.c | 5 +-
23 files changed, 107 insertions(+), 1 deletion(-)
create mode 100644 include/asm-generic/pgtable-geometry.h
diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
index 70419e6be1a35..d0096fb5521b8 100644
--- a/arch/alpha/include/asm/page.h
+++ b/arch/alpha/include/asm/page.h
@@ -88,5 +88,6 @@ typedef struct page *pgtable_t;
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* _ALPHA_PAGE_H */
diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
index def0dfb95b436..8d56549db7a33 100644
--- a/arch/arc/include/asm/page.h
+++ b/arch/arc/include/asm/page.h
@@ -6,6 +6,7 @@
#define __ASM_ARC_PAGE_H
#include <uapi/asm/page.h>
+#include <asm-generic/pgtable-geometry.h>
#ifdef CONFIG_ARC_HAS_PAE40
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index 62af9f7f9e963..417aa8533c718 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -191,5 +191,6 @@ extern int pfn_valid(unsigned long);
#include <asm-generic/getorder.h>
#include <asm-generic/memory_model.h>
+#include <asm-generic/pgtable-geometry.h>
#endif
diff --git a/arch/arm64/include/asm/page-def.h b/arch/arm64/include/asm/page-def.h
index 792e9fe881dcf..d69971cf49cd2 100644
--- a/arch/arm64/include/asm/page-def.h
+++ b/arch/arm64/include/asm/page-def.h
@@ -15,4 +15,6 @@
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
+#include <asm-generic/pgtable-geometry.h>
+
#endif /* __ASM_PAGE_DEF_H */
diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h
index 0ca6c408c07f2..95173d57adc8b 100644
--- a/arch/csky/include/asm/page.h
+++ b/arch/csky/include/asm/page.h
@@ -92,4 +92,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
#include <asm-generic/getorder.h>
#endif /* !__ASSEMBLY__ */
+
+#include <asm-generic/pgtable-geometry.h>
+
#endif /* __ASM_CSKY_PAGE_H */
diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h
index 8a6af57274c2d..ba7ad5231695f 100644
--- a/arch/hexagon/include/asm/page.h
+++ b/arch/hexagon/include/asm/page.h
@@ -139,4 +139,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
#endif /* ifdef __ASSEMBLY__ */
#endif /* ifdef __KERNEL__ */
+#include <asm-generic/pgtable-geometry.h>
+
#endif
diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
index e85df33f11c77..9862e8fb047a6 100644
--- a/arch/loongarch/include/asm/page.h
+++ b/arch/loongarch/include/asm/page.h
@@ -123,4 +123,6 @@ extern int __virt_addr_valid(volatile void *kaddr);
#endif /* !__ASSEMBLY__ */
+#include <asm-generic/pgtable-geometry.h>
+
#endif /* _ASM_PAGE_H */
diff --git a/arch/m68k/include/asm/page.h b/arch/m68k/include/asm/page.h
index 8cfb84b499751..4df4681b02194 100644
--- a/arch/m68k/include/asm/page.h
+++ b/arch/m68k/include/asm/page.h
@@ -60,5 +60,6 @@ extern unsigned long _ramend;
#include <asm-generic/getorder.h>
#include <asm-generic/memory_model.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* _M68K_PAGE_H */
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index 8810f4f1c3b02..abc23c3d743bd 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -142,5 +142,6 @@ static inline const void *pfn_to_virt(unsigned long pfn)
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* _ASM_MICROBLAZE_PAGE_H */
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 4609cb0326cf3..3d91021538f02 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -227,5 +227,6 @@ static inline unsigned long kaslr_offset(void)
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* _ASM_PAGE_H */
diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h
index 0722f88e63cc7..2e5f93beb42b7 100644
--- a/arch/nios2/include/asm/page.h
+++ b/arch/nios2/include/asm/page.h
@@ -97,4 +97,6 @@ extern struct page *mem_map;
#endif /* !__ASSEMBLY__ */
+#include <asm-generic/pgtable-geometry.h>
+
#endif /* _ASM_NIOS2_PAGE_H */
diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h
index 1d5913f67c312..a0da2a9842241 100644
--- a/arch/openrisc/include/asm/page.h
+++ b/arch/openrisc/include/asm/page.h
@@ -88,5 +88,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* __ASM_OPENRISC_PAGE_H */
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index 4bea2e95798f0..2a75496237c09 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -173,6 +173,7 @@ extern int npmem_ranges;
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#include <asm/pdc.h>
#define PAGE0 ((struct zeropage *)absolute_pointer(__PAGE_OFFSET))
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 83d0a4fc5f755..4601c115b6485 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -300,4 +300,6 @@ static inline unsigned long kaslr_offset(void)
#include <asm-generic/memory_model.h>
#endif /* __ASSEMBLY__ */
+#include <asm-generic/pgtable-geometry.h>
+
#endif /* _ASM_POWERPC_PAGE_H */
diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
index 7ede2111c5917..e5af7579e45bf 100644
--- a/arch/riscv/include/asm/page.h
+++ b/arch/riscv/include/asm/page.h
@@ -204,5 +204,6 @@ static __always_inline void *pfn_to_kaddr(unsigned long pfn)
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* _ASM_RISCV_PAGE_H */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 16e4caa931f1f..42157e7690a77 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -275,6 +275,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#define AMODE31_SIZE (3 * PAGE_SIZE)
diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
index f780b467e75d7..09533d46ef033 100644
--- a/arch/sh/include/asm/page.h
+++ b/arch/sh/include/asm/page.h
@@ -162,5 +162,6 @@ typedef struct page *pgtable_t;
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* __ASM_SH_PAGE_H */
diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h
index 5e44cdf2a8f2b..4327fe2bfa010 100644
--- a/arch/sparc/include/asm/page.h
+++ b/arch/sparc/include/asm/page.h
@@ -9,4 +9,7 @@
#else
#include <asm/page_32.h>
#endif
+
+#include <asm-generic/pgtable-geometry.h>
+
#endif
diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
index 9ef9a8aedfa66..f26011808f514 100644
--- a/arch/um/include/asm/page.h
+++ b/arch/um/include/asm/page.h
@@ -119,4 +119,6 @@ extern unsigned long uml_physmem;
#define __HAVE_ARCH_GATE_AREA 1
#endif
+#include <asm-generic/pgtable-geometry.h>
+
#endif /* __UM_PAGE_H */
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index 52f1b4ff0cc16..6d2381342047f 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -71,4 +71,6 @@ extern void initmem_init(void);
#endif /* !__ASSEMBLY__ */
+#include <asm-generic/pgtable-geometry.h>
+
#endif /* _ASM_X86_PAGE_DEFS_H */
diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
index 4db56ef052d22..86952cb32af23 100644
--- a/arch/xtensa/include/asm/page.h
+++ b/arch/xtensa/include/asm/page.h
@@ -200,4 +200,5 @@ static inline unsigned long ___pa(unsigned long va)
#endif /* __ASSEMBLY__ */
#include <asm-generic/memory_model.h>
+#include <asm-generic/pgtable-geometry.h>
#endif /* _XTENSA_PAGE_H */
diff --git a/include/asm-generic/pgtable-geometry.h b/include/asm-generic/pgtable-geometry.h
new file mode 100644
index 0000000000000..358e729a6ac37
--- /dev/null
+++ b/include/asm-generic/pgtable-geometry.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ASM_GENERIC_PGTABLE_GEOMETRY_H
+#define ASM_GENERIC_PGTABLE_GEOMETRY_H
+
+#if defined(PAGE_SHIFT_MAX) && defined(PAGE_SIZE_MAX) && defined(PAGE_MASK_MAX) && \
+ defined(PAGE_SHIFT_MIN) && defined(PAGE_SIZE_MIN) && defined(PAGE_MASK_MIN)
+/* Arch supports boot-time page size selection. */
+#elif defined(PAGE_SHIFT_MAX) || defined(PAGE_SIZE_MAX) || defined(PAGE_MASK_MAX) || \
+ defined(PAGE_SHIFT_MIN) || defined(PAGE_SIZE_MIN) || defined(PAGE_MASK_MIN)
+#error Arch must define all or none of the boot-time page size macros
+#else
+/* Arch does not support boot-time page size selection. */
+#define PAGE_SHIFT_MIN PAGE_SHIFT
+#define PAGE_SIZE_MIN PAGE_SIZE
+#define PAGE_MASK_MIN PAGE_MASK
+#define PAGE_SHIFT_MAX PAGE_SHIFT
+#define PAGE_SIZE_MAX PAGE_SIZE
+#define PAGE_MASK_MAX PAGE_MASK
+#endif
+
+/*
+ * Define a global variable (scalar or struct), whose value is derived from
+ * PAGE_SIZE and friends. When PAGE_SIZE is a compile-time constant, the global
+ * variable is simply defined with the static value. When PAGE_SIZE is
+ * determined at boot-time, a pure initcall is registered and run during boot to
+ * initialize the variable.
+ *
+ * @type: Unqualified type. Do not include "const"; implied by macro variant.
+ * @name: Variable name.
+ * @...: Initialization value. May be scalar or initializer.
+ *
+ * "static" is declared by placing "static" before the macro.
+ *
+ * Example:
+ *
+ * struct my_struct {
+ * int a;
+ * char b;
+ * };
+ *
+ * static DEFINE_GLOBAL_PAGE_SIZE_VAR(struct my_struct, my_variable, {
+ * .a = 10,
+ * .b = 'e',
+ * });
+ */
+#if PAGE_SIZE_MIN != PAGE_SIZE_MAX
+#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
+ type name attrib; \
+ static int __init __attribute__((constructor)) __##name##_init(void) \
+ { \
+ name = (type)__VA_ARGS__; \
+ return 0; \
+ }
+
+#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
+ __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
+
+#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
+ __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, __ro_after_init, __VA_ARGS__)
+#else /* PAGE_SIZE_MIN == PAGE_SIZE_MAX */
+#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
+ type name attrib = __VA_ARGS__; \
+
+#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
+ __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
+
+#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
+ __DEFINE_GLOBAL_PAGE_SIZE_VAR(const type, name, , __VA_ARGS__)
+#endif
+
+#endif /* ASM_GENERIC_PGTABLE_GEOMETRY_H */
diff --git a/init/main.c b/init/main.c
index 206acdde51f5a..ba1515eb20b9d 100644
--- a/init/main.c
+++ b/init/main.c
@@ -899,6 +899,8 @@ static void __init early_numa_node_init(void)
#endif
}
+static __init void do_ctors(void);
+
asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
void start_kernel(void)
{
@@ -910,6 +912,8 @@ void start_kernel(void)
debug_objects_early_init();
init_vmlinux_build_id();
+ do_ctors();
+
cgroup_init_early();
local_irq_disable();
@@ -1360,7 +1364,6 @@ static void __init do_basic_setup(void)
cpuset_init_smp();
driver_init();
init_irq_proc();
- do_ctors();
do_initcalls();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX
2024-10-14 10:58 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Ryan Roberts
@ 2024-10-14 10:58 ` Ryan Roberts
2024-10-14 16:50 ` Christoph Lameter (Ampere)
2024-10-14 10:58 ` [RFC PATCH v1 11/57] fork: Permit boot-time THREAD_SIZE determination Ryan Roberts
` (4 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Ryan Roberts @ 2024-10-14 10:58 UTC (permalink / raw)
To: Andrew Morton, Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Catalin Marinas, Christoph Lameter, David Hildenbrand,
Dennis Zhou, Greg Marsden, Ivan Ivanov, Kalesh Singh,
Marc Zyngier, Mark Rutland, Matthias Brugger, Miroslav Benes,
Tejun Heo, Will Deacon
Cc: Ryan Roberts, linux-arch, linux-arm-kernel, linux-kernel,
linux-mm
Increase alignment of structures requiring at least PAGE_SIZE alignment
to PAGE_SIZE_MAX. For compile-time PAGE_SIZE, PAGE_SIZE_MAX == PAGE_SIZE
so there is no change. For boot-time PAGE_SIZE, PAGE_SIZE_MAX is the
largest selectable page size.
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
***NOTE***
Any confused maintainers may want to read the cover note here for context:
https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
include/asm-generic/vmlinux.lds.h | 32 +++++++++++++++----------------
include/linux/linkage.h | 4 ++--
include/linux/percpu-defs.h | 4 ++--
3 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 1ae44793132a8..5727f883001bb 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -13,7 +13,7 @@
* . = START;
* __init_begin = .;
* HEAD_TEXT_SECTION
- * INIT_TEXT_SECTION(PAGE_SIZE)
+ * INIT_TEXT_SECTION(PAGE_SIZE_MAX)
* INIT_DATA_SECTION(...)
* PERCPU_SECTION(CACHELINE_SIZE)
* __init_end = .;
@@ -23,7 +23,7 @@
* _etext = .;
*
* _sdata = .;
- * RO_DATA(PAGE_SIZE)
+ * RO_DATA(PAGE_SIZE_MAX)
* RW_DATA(...)
* _edata = .;
*
@@ -371,10 +371,10 @@
* Data section helpers
*/
#define NOSAVE_DATA \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
__nosave_begin = .; \
*(.data..nosave) \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
__nosave_end = .;
#define PAGE_ALIGNED_DATA(page_align) \
@@ -733,9 +733,9 @@
. = ALIGN(bss_align); \
.bss : AT(ADDR(.bss) - LOAD_OFFSET) { \
BSS_FIRST_SECTIONS \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
*(.bss..page_aligned) \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
*(.dynbss) \
*(BSS_MAIN) \
*(COMMON) \
@@ -950,9 +950,9 @@
*/
#ifdef CONFIG_AMD_MEM_ENCRYPT
#define PERCPU_DECRYPTED_SECTION \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
*(.data..percpu..decrypted) \
- . = ALIGN(PAGE_SIZE);
+ . = ALIGN(PAGE_SIZE_MAX);
#else
#define PERCPU_DECRYPTED_SECTION
#endif
@@ -1030,7 +1030,7 @@
#define PERCPU_INPUT(cacheline) \
__per_cpu_start = .; \
*(.data..percpu..first) \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
*(.data..percpu..page_aligned) \
. = ALIGN(cacheline); \
*(.data..percpu..read_mostly) \
@@ -1075,16 +1075,16 @@
* PERCPU_SECTION - define output section for percpu area, simple version
* @cacheline: cacheline size
*
- * Align to PAGE_SIZE and outputs output section for percpu area. This
+ * Align to PAGE_SIZE_MAX and outputs output section for percpu area. This
* macro doesn't manipulate @vaddr or @phdr and __per_cpu_load and
* __per_cpu_start will be identical.
*
- * This macro is equivalent to ALIGN(PAGE_SIZE); PERCPU_VADDR(@cacheline,,)
+ * This macro is equivalent to ALIGN(PAGE_SIZE_MAX); PERCPU_VADDR(@cacheline,,)
* except that __per_cpu_load is defined as a relative symbol against
* .data..percpu which is required for relocatable x86_32 configuration.
*/
#define PERCPU_SECTION(cacheline) \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
.data..percpu : AT(ADDR(.data..percpu) - LOAD_OFFSET) { \
__per_cpu_load = .; \
PERCPU_INPUT(cacheline) \
@@ -1102,15 +1102,15 @@
* All sections are combined in a single .data section.
* The sections following CONSTRUCTORS are arranged so their
* typical alignment matches.
- * A cacheline is typical/always less than a PAGE_SIZE so
+ * A cacheline is typical/always less than a PAGE_SIZE_MAX so
* the sections that has this restriction (or similar)
- * is located before the ones requiring PAGE_SIZE alignment.
- * NOSAVE_DATA starts and ends with a PAGE_SIZE alignment which
+ * is located before the ones requiring PAGE_SIZE_MAX alignment.
+ * NOSAVE_DATA starts and ends with a PAGE_SIZE_MAX alignment which
* matches the requirement of PAGE_ALIGNED_DATA.
*
* use 0 as page_align if page_aligned data is not used */
#define RW_DATA(cacheline, pagealigned, inittask) \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(PAGE_SIZE_MAX); \
.data : AT(ADDR(.data) - LOAD_OFFSET) { \
INIT_TASK_DATA(inittask) \
NOSAVE_DATA \
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 5c8865bb59d91..68aa9775fce51 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -36,8 +36,8 @@
__stringify(name))
#endif
-#define __page_aligned_data __section(".data..page_aligned") __aligned(PAGE_SIZE)
-#define __page_aligned_bss __section(".bss..page_aligned") __aligned(PAGE_SIZE)
+#define __page_aligned_data __section(".data..page_aligned") __aligned(PAGE_SIZE_MAX)
+#define __page_aligned_bss __section(".bss..page_aligned") __aligned(PAGE_SIZE_MAX)
/*
* For assembly routines.
diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
index 8efce7414fad6..89c7f430015ba 100644
--- a/include/linux/percpu-defs.h
+++ b/include/linux/percpu-defs.h
@@ -156,11 +156,11 @@
*/
#define DECLARE_PER_CPU_PAGE_ALIGNED(type, name) \
DECLARE_PER_CPU_SECTION(type, name, "..page_aligned") \
- __aligned(PAGE_SIZE)
+ __aligned(PAGE_SIZE_MAX)
#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name) \
DEFINE_PER_CPU_SECTION(type, name, "..page_aligned") \
- __aligned(PAGE_SIZE)
+ __aligned(PAGE_SIZE_MAX)
/*
* Declaration/definition used for per-CPU variables that must be read mostly.
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v1 11/57] fork: Permit boot-time THREAD_SIZE determination
2024-10-14 10:58 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Ryan Roberts
2024-10-14 10:58 ` [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX Ryan Roberts
@ 2024-10-14 10:58 ` Ryan Roberts
2024-11-14 10:42 ` Vlastimil Babka
2024-10-14 10:59 ` [RFC PATCH v1 53/57] arm64: Runtime-fold pmd level Ryan Roberts
` (3 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Ryan Roberts @ 2024-10-14 10:58 UTC (permalink / raw)
To: Andrew Morton, Andrey Ryabinin, Anshuman Khandual, Ard Biesheuvel,
Arnd Bergmann, Catalin Marinas, David Hildenbrand, Greg Marsden,
Ingo Molnar, Ivan Ivanov, Juri Lelli, Kalesh Singh, Marc Zyngier,
Mark Rutland, Matthias Brugger, Miroslav Benes, Peter Zijlstra,
Vincent Guittot, Will Deacon
Cc: Ryan Roberts, kasan-dev, linux-arch, linux-arm-kernel,
linux-kernel, linux-mm
THREAD_SIZE defines the size of a kernel thread stack. To date, it has
been set at compile-time. However, when using vmap stacks, the size must
be a multiple of PAGE_SIZE, and given we are in the process of
supporting boot-time page size, we must also do the same for
THREAD_SIZE.
The alternative would be to define THREAD_SIZE for the largest supported
page size, but this would waste memory when using a smaller page size.
For example, arm64 requires THREAD_SIZE to be 16K, but when using 64K
pages and a vmap stack, we must increase the size to 64K. If we required
64K when 4K or 16K page size was in use, we would waste 48K per kernel
thread.
So let's refactor to allow THREAD_SIZE to not be a compile-time
constant. THREAD_SIZE_MAX (and THREAD_ALIGN_MAX) are introduced to
manage the limits, as is done for PAGE_SIZE.
When THREAD_SIZE is a compile-time constant, behaviour and code size
should be equivalent.
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
***NOTE***
Any confused maintainers may want to read the cover note here for context:
https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
include/asm-generic/vmlinux.lds.h | 6 ++-
include/linux/sched.h | 4 +-
include/linux/thread_info.h | 10 ++++-
init/main.c | 2 +-
kernel/fork.c | 67 +++++++++++--------------------
mm/kasan/report.c | 3 +-
6 files changed, 42 insertions(+), 50 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 5727f883001bb..f19bab7a2e8f9 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -56,6 +56,10 @@
#define LOAD_OFFSET 0
#endif
+#ifndef THREAD_SIZE_MAX
+#define THREAD_SIZE_MAX THREAD_SIZE
+#endif
+
/*
* Only some architectures want to have the .notes segment visible in
* a separate PT_NOTE ELF Program Header. When this happens, it needs
@@ -398,7 +402,7 @@
init_stack = .; \
KEEP(*(.data..init_task)) \
KEEP(*(.data..init_thread_info)) \
- . = __start_init_stack + THREAD_SIZE; \
+ . = __start_init_stack + THREAD_SIZE_MAX; \
__end_init_stack = .;
#define JUMP_TABLE_DATA \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f8d150343d42d..3de4f655ee492 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1863,14 +1863,14 @@ union thread_union {
#ifndef CONFIG_THREAD_INFO_IN_TASK
struct thread_info thread_info;
#endif
- unsigned long stack[THREAD_SIZE/sizeof(long)];
+ unsigned long stack[THREAD_SIZE_MAX/sizeof(long)];
};
#ifndef CONFIG_THREAD_INFO_IN_TASK
extern struct thread_info init_thread_info;
#endif
-extern unsigned long init_stack[THREAD_SIZE / sizeof(unsigned long)];
+extern unsigned long init_stack[THREAD_SIZE_MAX / sizeof(unsigned long)];
#ifdef CONFIG_THREAD_INFO_IN_TASK
# define task_thread_info(task) (&(task)->thread_info)
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index 9ea0b28068f49..a7ccc448cd298 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -74,7 +74,15 @@ static inline long set_restart_fn(struct restart_block *restart,
}
#ifndef THREAD_ALIGN
-#define THREAD_ALIGN THREAD_SIZE
+#define THREAD_ALIGN THREAD_SIZE
+#endif
+
+#ifndef THREAD_SIZE_MAX
+#define THREAD_SIZE_MAX THREAD_SIZE
+#endif
+
+#ifndef THREAD_ALIGN_MAX
+#define THREAD_ALIGN_MAX max(THREAD_ALIGN, THREAD_SIZE_MAX)
#endif
#define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO)
diff --git a/init/main.c b/init/main.c
index ba1515eb20b9d..4dc28115fdf57 100644
--- a/init/main.c
+++ b/init/main.c
@@ -797,7 +797,7 @@ void __init __weak smp_prepare_boot_cpu(void)
{
}
-# if THREAD_SIZE >= PAGE_SIZE
+#ifdef CONFIG_VMAP_STACK
void __init __weak thread_stack_cache_init(void)
{
}
diff --git a/kernel/fork.c b/kernel/fork.c
index ea472566d4fcc..cbc3e73f9b501 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -184,13 +184,7 @@ static inline void free_task_struct(struct task_struct *tsk)
kmem_cache_free(task_struct_cachep, tsk);
}
-/*
- * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
- * kmemcache based allocator.
- */
-# if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)
-
-# ifdef CONFIG_VMAP_STACK
+#ifdef CONFIG_VMAP_STACK
/*
* vmalloc() is a bit slow, and calling vfree() enough times will force a TLB
* flush. Try to minimize the number of calls by caching stacks.
@@ -343,46 +337,21 @@ static void free_thread_stack(struct task_struct *tsk)
tsk->stack_vm_area = NULL;
}
-# else /* !CONFIG_VMAP_STACK */
+#else /* !CONFIG_VMAP_STACK */
-static void thread_stack_free_rcu(struct rcu_head *rh)
-{
- __free_pages(virt_to_page(rh), THREAD_SIZE_ORDER);
-}
-
-static void thread_stack_delayed_free(struct task_struct *tsk)
-{
- struct rcu_head *rh = tsk->stack;
-
- call_rcu(rh, thread_stack_free_rcu);
-}
-
-static int alloc_thread_stack_node(struct task_struct *tsk, int node)
-{
- struct page *page = alloc_pages_node(node, THREADINFO_GFP,
- THREAD_SIZE_ORDER);
-
- if (likely(page)) {
- tsk->stack = kasan_reset_tag(page_address(page));
- return 0;
- }
- return -ENOMEM;
-}
-
-static void free_thread_stack(struct task_struct *tsk)
-{
- thread_stack_delayed_free(tsk);
- tsk->stack = NULL;
-}
-
-# endif /* CONFIG_VMAP_STACK */
-# else /* !(THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)) */
+/*
+ * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
+ * kmemcache based allocator.
+ */
static struct kmem_cache *thread_stack_cache;
static void thread_stack_free_rcu(struct rcu_head *rh)
{
- kmem_cache_free(thread_stack_cache, rh);
+ if (THREAD_SIZE >= PAGE_SIZE)
+ __free_pages(virt_to_page(rh), THREAD_SIZE_ORDER);
+ else
+ kmem_cache_free(thread_stack_cache, rh);
}
static void thread_stack_delayed_free(struct task_struct *tsk)
@@ -395,7 +364,16 @@ static void thread_stack_delayed_free(struct task_struct *tsk)
static int alloc_thread_stack_node(struct task_struct *tsk, int node)
{
unsigned long *stack;
- stack = kmem_cache_alloc_node(thread_stack_cache, THREADINFO_GFP, node);
+ struct page *page;
+
+ if (THREAD_SIZE >= PAGE_SIZE) {
+ page = alloc_pages_node(node, THREADINFO_GFP, THREAD_SIZE_ORDER);
+ stack = likely(page) ? page_address(page) : NULL;
+ } else {
+ stack = kmem_cache_alloc_node(thread_stack_cache,
+ THREADINFO_GFP, node);
+ }
+
stack = kasan_reset_tag(stack);
tsk->stack = stack;
return stack ? 0 : -ENOMEM;
@@ -409,13 +387,16 @@ static void free_thread_stack(struct task_struct *tsk)
void thread_stack_cache_init(void)
{
+ if (THREAD_SIZE >= PAGE_SIZE)
+ return;
+
thread_stack_cache = kmem_cache_create_usercopy("thread_stack",
THREAD_SIZE, THREAD_SIZE, 0, 0,
THREAD_SIZE, NULL);
BUG_ON(thread_stack_cache == NULL);
}
-# endif /* THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK) */
+#endif /* CONFIG_VMAP_STACK */
/* SLAB cache for signal_struct structures (tsk->signal) */
static struct kmem_cache *signal_cachep;
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index b48c768acc84d..57c877852dbc6 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -365,8 +365,7 @@ static inline bool kernel_or_module_addr(const void *addr)
static inline bool init_task_stack_addr(const void *addr)
{
return addr >= (void *)&init_thread_union.stack &&
- (addr <= (void *)&init_thread_union.stack +
- sizeof(init_thread_union.stack));
+ (addr <= (void *)&init_thread_union.stack + THREAD_SIZE);
}
static void print_address_description(void *addr, u8 tag,
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH v1 53/57] arm64: Runtime-fold pmd level
2024-10-14 10:58 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Ryan Roberts
2024-10-14 10:58 ` [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX Ryan Roberts
2024-10-14 10:58 ` [RFC PATCH v1 11/57] fork: Permit boot-time THREAD_SIZE determination Ryan Roberts
@ 2024-10-14 10:59 ` Ryan Roberts
2024-10-14 13:54 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Pingfan Liu
` (2 subsequent siblings)
5 siblings, 0 replies; 13+ messages in thread
From: Ryan Roberts @ 2024-10-14 10:59 UTC (permalink / raw)
To: Aneesh Kumar K.V, Andrew Morton, Anshuman Khandual,
Ard Biesheuvel, Catalin Marinas, David Hildenbrand, Greg Marsden,
Ivan Ivanov, Kalesh Singh, Marc Zyngier, Mark Rutland,
Matthias Brugger, Miroslav Benes, Nick Piggin, Oliver Upton,
Peter Zijlstra, Will Deacon
Cc: Ryan Roberts, kvmarm, linux-arch, linux-arm-kernel, linux-kernel,
linux-mm
For a given VA size, the number of levels of lookup depends on the page
size. With boot-time page size selection, we therefore don't know how
many levels of lookup we require until boot time. So we need to
runtime-fold some levels of lookup.
We already have code to runtime-fold p4d and pud levels; that exists for
LPA2 fallback paths and can be repurposed for our needs. But pmd level
also needs to support runtime folding; for example, 16K/36-bit and
64K/42-bit configs require only 2 levels.
So let's add the required code. However, note that until we actually add
the boot-time page size config, pgtable_l3_enabled() simply returns the
compile-time determined answer.
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
***NOTE***
Any confused maintainers may want to read the cover note here for context:
https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
arch/arm64/include/asm/pgalloc.h | 16 +++-
arch/arm64/include/asm/pgtable.h | 123 +++++++++++++++++++++++--------
arch/arm64/include/asm/tlb.h | 3 +
arch/arm64/kernel/cpufeature.c | 4 +-
arch/arm64/kvm/mmu.c | 9 +--
arch/arm64/mm/fixmap.c | 2 +-
arch/arm64/mm/hugetlbpage.c | 16 ++--
arch/arm64/mm/init.c | 2 +-
arch/arm64/mm/mmu.c | 2 +-
arch/arm64/mm/ptdump.c | 3 +-
10 files changed, 126 insertions(+), 54 deletions(-)
diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
index 8ff5f2a2579e4..51cc2f32931d2 100644
--- a/arch/arm64/include/asm/pgalloc.h
+++ b/arch/arm64/include/asm/pgalloc.h
@@ -15,6 +15,7 @@
#define __HAVE_ARCH_PGD_FREE
#define __HAVE_ARCH_PUD_FREE
+#define __HAVE_ARCH_PMD_FREE
#include <asm-generic/pgalloc.h>
#define PGD_SIZE (PTRS_PER_PGD * sizeof(pgd_t))
@@ -23,7 +24,8 @@
static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
{
- set_pud(pudp, __pud(__phys_to_pud_val(pmdp) | prot));
+ if (pgtable_l3_enabled())
+ set_pud(pudp, __pud(__phys_to_pud_val(pmdp) | prot));
}
static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
@@ -33,6 +35,18 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
pudval |= (mm == &init_mm) ? PUD_TABLE_UXN : PUD_TABLE_PXN;
__pud_populate(pudp, __pa(pmdp), pudval);
}
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+ struct ptdesc *ptdesc = virt_to_ptdesc(pmd);
+
+ if (!pgtable_l3_enabled())
+ return;
+
+ BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
+ pagetable_pmd_dtor(ptdesc);
+ pagetable_free(ptdesc);
+}
#else
static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
{
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index fd47f70a42396..8ead41da715b0 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -672,15 +672,21 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
#define pmd_leaf_size(pmd) (pmd_cont(pmd) ? CONT_PMD_SIZE : PMD_SIZE)
#define pte_leaf_size(pte) (pte_cont(pte) ? CONT_PTE_SIZE : PAGE_SIZE)
-#if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
-static inline bool pud_sect(pud_t pud) { return false; }
-static inline bool pud_table(pud_t pud) { return true; }
-#else
-#define pud_sect(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \
- PUD_TYPE_SECT)
-#define pud_table(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \
- PUD_TYPE_TABLE)
-#endif
+static inline bool pgtable_l3_enabled(void);
+
+static inline bool pud_sect(pud_t pud)
+{
+ if (PAGE_SIZE == SZ_64K || !pgtable_l3_enabled())
+ return false;
+ return (pud_val(pud) & PUD_TYPE_MASK) == PUD_TYPE_SECT;
+}
+
+static inline bool pud_table(pud_t pud)
+{
+ if (PAGE_SIZE == SZ_64K || !pgtable_l3_enabled())
+ return true;
+ return (pud_val(pud) & PUD_TYPE_MASK) == PUD_TYPE_TABLE;
+}
extern pgd_t init_pg_dir[];
extern pgd_t init_pg_end[];
@@ -699,12 +705,10 @@ static inline bool in_swapper_pgdir(void *addr)
static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{
-#ifdef __PAGETABLE_PMD_FOLDED
- if (in_swapper_pgdir(pmdp)) {
+ if (!pgtable_l3_enabled() && in_swapper_pgdir(pmdp)) {
set_swapper_pgd((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
return;
}
-#endif /* __PAGETABLE_PMD_FOLDED */
WRITE_ONCE(*pmdp, pmd);
@@ -749,20 +753,27 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
#if CONFIG_PGTABLE_LEVELS > 2
+static __always_inline bool pgtable_l3_enabled(void)
+{
+ return true;
+}
+
+static inline bool mm_pmd_folded(const struct mm_struct *mm)
+{
+ return !pgtable_l3_enabled();
+}
+#define mm_pmd_folded mm_pmd_folded
+
#define pmd_ERROR(e) \
pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
-#define pud_none(pud) (!pud_val(pud))
-#define pud_bad(pud) (!pud_table(pud))
-#define pud_present(pud) pte_present(pud_pte(pud))
-#ifndef __PAGETABLE_PMD_FOLDED
-#define pud_leaf(pud) (pud_present(pud) && !pud_table(pud))
-#else
-#define pud_leaf(pud) false
-#endif
-#define pud_valid(pud) pte_valid(pud_pte(pud))
-#define pud_user(pud) pte_user(pud_pte(pud))
-#define pud_user_exec(pud) pte_user_exec(pud_pte(pud))
+#define pud_none(pud) (pgtable_l3_enabled() && !pud_val(pud))
+#define pud_bad(pud) (pgtable_l3_enabled() && !pud_table(pud))
+#define pud_present(pud) (!pgtable_l3_enabled() || pte_present(pud_pte(pud)))
+#define pud_leaf(pud) (pgtable_l3_enabled() && pte_present(pud_pte(pud)) && !pud_table(pud))
+#define pud_valid(pud) (pgtable_l3_enabled() && pte_valid(pud_pte(pud)))
+#define pud_user(pud) (pgtable_l3_enabled() && pte_user(pud_pte(pud)))
+#define pud_user_exec(pud) (pgtable_l3_enabled() && pte_user_exec(pud_pte(pud)))
static inline bool pgtable_l4_enabled(void);
@@ -783,7 +794,8 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
static inline void pud_clear(pud_t *pudp)
{
- set_pud(pudp, __pud(0));
+ if (pgtable_l3_enabled())
+ set_pud(pudp, __pud(0));
}
static inline phys_addr_t pud_page_paddr(pud_t pud)
@@ -791,25 +803,74 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
return __pud_to_phys(pud);
}
+#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
+
+static inline pmd_t *pud_to_folded_pmd(pud_t *pudp, unsigned long addr)
+{
+ return (pmd_t *)pudp;
+}
+
static inline pmd_t *pud_pgtable(pud_t pud)
{
return (pmd_t *)__va(pud_page_paddr(pud));
}
-/* Find an entry in the second-level page table. */
-#define pmd_offset_phys(dir, addr) (pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t))
+static inline phys_addr_t pmd_offset_phys(pud_t *pudp, unsigned long addr)
+{
+ BUG_ON(!pgtable_l3_enabled());
+
+ return pud_page_paddr(READ_ONCE(*pudp)) + pmd_index(addr) * sizeof(pmd_t);
+}
+
+static inline pmd_t *pmd_offset_lockless(pud_t *pudp, pud_t pud,
+ unsigned long addr)
+{
+ if (!pgtable_l3_enabled())
+ return pud_to_folded_pmd(pudp, addr);
+ return (pmd_t *)__va(pud_page_paddr(pud)) + pmd_index(addr);
+}
+#define pmd_offset_lockless pmd_offset_lockless
-#define pmd_set_fixmap(addr) ((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
-#define pmd_set_fixmap_offset(pud, addr) pmd_set_fixmap(pmd_offset_phys(pud, addr))
-#define pmd_clear_fixmap() clear_fixmap(FIX_PMD)
+static inline pmd_t *pmd_offset(pud_t *pudp, unsigned long addr)
+{
+ return pmd_offset_lockless(pudp, READ_ONCE(*pudp), addr);
+}
+#define pmd_offset pmd_offset
-#define pud_page(pud) phys_to_page(__pud_to_phys(pud))
+static inline pmd_t *pmd_set_fixmap(unsigned long addr)
+{
+ if (!pgtable_l3_enabled())
+ return NULL;
+ return (pmd_t *)set_fixmap_offset(FIX_PMD, addr);
+}
+
+static inline pmd_t *pmd_set_fixmap_offset(pud_t *pudp, unsigned long addr)
+{
+ if (!pgtable_l3_enabled())
+ return pud_to_folded_pmd(pudp, addr);
+ return pmd_set_fixmap(pmd_offset_phys(pudp, addr));
+}
+
+static inline void pmd_clear_fixmap(void)
+{
+ if (pgtable_l3_enabled())
+ clear_fixmap(FIX_PMD);
+}
/* use ONLY for statically allocated translation tables */
-#define pmd_offset_kimg(dir,addr) ((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
+static inline pmd_t *pmd_offset_kimg(pud_t *pudp, u64 addr)
+{
+ if (!pgtable_l3_enabled())
+ return pud_to_folded_pmd(pudp, addr);
+ return (pmd_t *)__phys_to_kimg(pmd_offset_phys(pudp, addr));
+}
+
+#define pud_page(pud) phys_to_page(__pud_to_phys(pud))
#else
+static inline bool pgtable_l3_enabled(void) { return false; }
+
#define pud_valid(pud) false
#define pud_page_paddr(pud) ({ BUILD_BUG(); 0; })
#define pud_user_exec(pud) pud_user(pud) /* Always 0 with folding */
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index a947c6e784ed2..527630f0803c6 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -92,6 +92,9 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
{
struct ptdesc *ptdesc = virt_to_ptdesc(pmdp);
+ if (!pgtable_l3_enabled())
+ return;
+
pagetable_pmd_dtor(ptdesc);
tlb_remove_ptdesc(tlb, ptdesc);
}
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index e5618423bb99d..663cc76569a27 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1923,8 +1923,10 @@ static int __init __kpti_install_ng_mappings(void *__unused)
if (levels == 5 && !pgtable_l5_enabled())
levels = 4;
- else if (levels == 4 && !pgtable_l4_enabled())
+ if (levels == 4 && !pgtable_l4_enabled())
levels = 3;
+ if (levels == 3 && !pgtable_l3_enabled())
+ levels = 2;
remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 248a2d7ad6dbb..146ecdaaaf647 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1370,12 +1370,11 @@ static int get_vma_page_shift(struct vm_area_struct *vma, unsigned long hva)
pa = (vma->vm_pgoff << PAGE_SHIFT) + (hva - vma->vm_start);
-#ifndef __PAGETABLE_PMD_FOLDED
- if ((hva & (PUD_SIZE - 1)) == (pa & (PUD_SIZE - 1)) &&
+ if (pgtable_l3_enabled() &&
+ (hva & (PUD_SIZE - 1)) == (pa & (PUD_SIZE - 1)) &&
ALIGN_DOWN(hva, PUD_SIZE) >= vma->vm_start &&
ALIGN(hva, PUD_SIZE) <= vma->vm_end)
return PUD_SHIFT;
-#endif
if ((hva & (PMD_SIZE - 1)) == (pa & (PMD_SIZE - 1)) &&
ALIGN_DOWN(hva, PMD_SIZE) >= vma->vm_start &&
@@ -1487,12 +1486,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
vma_shift = get_vma_page_shift(vma, hva);
}
-#ifndef __PAGETABLE_PMD_FOLDED
- if (vma_shift == PUD_SHIFT) {
+ if (pgtable_l3_enabled() && vma_shift == PUD_SHIFT) {
if (!fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE))
vma_shift = PMD_SHIFT;
}
-#endif
if (vma_shift == CONT_PMD_SHIFT) {
vma_shift = PMD_SHIFT;
}
diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
index a0dcf2375ccb4..f2c6678046a96 100644
--- a/arch/arm64/mm/fixmap.c
+++ b/arch/arm64/mm/fixmap.c
@@ -87,7 +87,7 @@ static void __init early_fixmap_init_pud(p4d_t *p4dp, unsigned long addr,
p4d_t p4d = READ_ONCE(*p4dp);
pud_t *pudp;
- if (CONFIG_PGTABLE_LEVELS > 3 && !p4d_none(p4d) &&
+ if (ptg_pgtable_levels > 3 && !p4d_none(p4d) &&
p4d_page_paddr(p4d) != __pa_symbol(bm_pud)) {
/*
* We only end up here if the kernel mapping and the fixmap
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index bc98c20655bba..2add0839179e3 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -51,10 +51,9 @@ void __init arm64_hugetlb_cma_reserve(void)
static bool __hugetlb_valid_size(unsigned long size)
{
-#ifndef __PAGETABLE_PMD_FOLDED
- if (size == PUD_SIZE)
+ if (pgtable_l3_enabled() && size == PUD_SIZE)
return pud_sect_supported();
-#endif
+
if (size == CONT_PMD_SIZE || size == PMD_SIZE || size == CONT_PTE_SIZE)
return true;
@@ -100,13 +99,10 @@ static inline int num_contig_ptes(unsigned long size, size_t *pgsize)
*pgsize = size;
-#ifndef __PAGETABLE_PMD_FOLDED
- if (size == PUD_SIZE) {
+ if (pgtable_l3_enabled() && size == PUD_SIZE) {
if (pud_sect_supported())
contig_ptes = 1;
- } else
-#endif
- if (size == PMD_SIZE) {
+ } else if (size == PMD_SIZE) {
contig_ptes = 1;
} else if (size == CONT_PMD_SIZE) {
*pgsize = PMD_SIZE;
@@ -331,10 +327,8 @@ unsigned long hugetlb_mask_last_page(struct hstate *h)
{
unsigned long hp_size = huge_page_size(h);
-#ifndef __PAGETABLE_PMD_FOLDED
- if (hp_size == PUD_SIZE)
+ if (pgtable_l3_enabled() && hp_size == PUD_SIZE)
return PGDIR_SIZE - PUD_SIZE;
-#endif
if (hp_size == CONT_PMD_SIZE)
return PUD_SIZE - CONT_PMD_SIZE;
if (hp_size == PMD_SIZE)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 4d24034418b39..62587104f30d8 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -396,7 +396,7 @@ void __init mem_init(void)
* scratch using the virtual address range and page size.
*/
VM_BUG_ON(ARM64_HW_PGTABLE_LEVELS(CONFIG_ARM64_VA_BITS) !=
- CONFIG_PGTABLE_LEVELS);
+ ptg_pgtable_levels);
if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
extern int sysctl_overcommit_memory;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index ad7fd3fda705a..b78a341cd9e70 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1046,7 +1046,7 @@ static void free_empty_pmd_table(pud_t *pudp, unsigned long addr,
free_empty_pte_table(pmdp, addr, next, floor, ceiling);
} while (addr = next, addr < end);
- if (CONFIG_PGTABLE_LEVELS <= 2)
+ if (!pgtable_l3_enabled())
return;
if (!pgtable_range_aligned(start, end, floor, ceiling, PUD_MASK))
diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c
index 6986827e0d645..045a4188afc10 100644
--- a/arch/arm64/mm/ptdump.c
+++ b/arch/arm64/mm/ptdump.c
@@ -230,7 +230,8 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
/* check if the current level has been folded dynamically */
if ((level == 1 && mm_p4d_folded(st->mm)) ||
- (level == 2 && mm_pud_folded(st->mm)))
+ (level == 2 && mm_pud_folded(st->mm)) ||
+ (level == 3 && mm_pmd_folded(st->mm)))
level = 0;
if (level >= 0)
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection
2024-10-14 10:58 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Ryan Roberts
` (2 preceding siblings ...)
2024-10-14 10:59 ` [RFC PATCH v1 53/57] arm64: Runtime-fold pmd level Ryan Roberts
@ 2024-10-14 13:54 ` Pingfan Liu
2024-10-14 14:07 ` Ryan Roberts
2024-10-16 14:36 ` Ryan Roberts
2024-10-30 8:45 ` Ryan Roberts
5 siblings, 1 reply; 13+ messages in thread
From: Pingfan Liu @ 2024-10-14 13:54 UTC (permalink / raw)
To: Ryan Roberts
Cc: David S. Miller, James E.J. Bottomley, Andreas Larsson,
Andrew Morton, Anshuman Khandual, Anton Ivanov, Ard Biesheuvel,
Arnd Bergmann, Borislav Petkov, Catalin Marinas, Chris Zankel,
Dave Hansen, David Hildenbrand, Dinh Nguyen, Geert Uytterhoeven,
Greg Marsden, Helge Deller, Huacai Chen, Ingo Molnar, Ivan Ivanov,
Johannes Berg, John Paul Adrian Glaubitz, Jonas Bonn,
Kalesh Singh, Marc Zyngier, Mark Rutland, Matthias Brugger,
Max Filippov, Miroslav Benes, Rich Felker, Richard Weinberger,
Stafford Horne, Stefan Kristiansson, Thomas Bogendoerfer,
Thomas Gleixner, Will Deacon, Yoshinori Sato, x86, linux-alpha,
linux-arch, linux-arm-kernel, linux-csky, linux-hexagon,
linux-kernel, linux-m68k, linux-mips, linux-mm, linux-openrisc,
linux-parisc, linux-riscv, linux-s390, linux-sh, linux-snps-arc,
linux-um, linuxppc-dev, loongarch, sparclinux
Hello Ryan,
On Mon, Oct 14, 2024 at 11:58:08AM +0100, Ryan Roberts wrote:
> arm64 can support multiple base page sizes. Instead of selecting a page
> size at compile time, as is done today, we will make it possible to
> select the desired page size on the command line.
>
> In this case PAGE_SHIFT and it's derivatives, PAGE_SIZE and PAGE_MASK
> (as well as a number of other macros related to or derived from
> PAGE_SHIFT, but I'm not worrying about those yet), are no longer
> compile-time constants. So the code base needs to cope with that.
>
> As a first step, introduce MIN and MAX variants of these macros, which
> express the range of possible page sizes. These are always compile-time
> constants and can be used in many places where PAGE_[SHIFT|SIZE|MASK]
> were previously used where a compile-time constant is required.
> (Subsequent patches will do that conversion work). When the arch/build
> doesn't support boot-time page size selection, the MIN and MAX variants
> are equal and everything resolves as it did previously.
>
MIN and MAX appear to construct a boundary, but it may be not enough.
Please see the following comment inline.
> Additionally, introduce DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() which wrap
> global variable defintions so that for boot-time page size selection
> builds, the variable being wrapped is initialized at boot-time, instead
> of compile-time. This is done by defining a function to do the
> assignment, which has the "constructor" attribute. Constructor is
> preferred over initcall, because when compiling a module, the module is
> limited to a single initcall but constructors are unlimited. For
> built-in code, constructors are now called earlier to guarrantee that
> the variables are initialized by the time they are used. Any arch that
> wants to enable boot-time page size selection will need to select
> CONFIG_CONSTRUCTORS.
>
> These new macros need to be available anywhere PAGE_SHIFT and friends
> are available. Those are defined via asm/page.h (although some arches
> have a sub-include that defines them). Unfortunately there is no
> reliable asm-generic header we can easily piggy-back on, so let's define
> a new one, pgtable-geometry.h, which we include near where each arch
> defines PAGE_SHIFT. Ugh.
>
> -------
>
> Most of the problems that need to be solved over the next few patches
> fall into these broad categories, which are all solved with the help of
> these new macros:
>
> 1. Assignment of values derived from PAGE_SIZE in global variables
>
> For boot-time page size builds, we must defer the initialization of
> these variables until boot-time, when the page size is known. See
> DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() as described above.
>
> 2. Define static storage in units related to PAGE_SIZE
>
> This static storage will be defined according to PAGE_SIZE_MAX.
>
> 3. Define size of struct so that it is related to PAGE_SIZE
>
> The struct often contains an array that is sized to fill the page. In
> this case, use a flexible array with dynamic allocation. In other
> cases, the struct fits exactly over a page, which is a header (e.g.
> swap file header). In this case, remove the padding, and manually
> determine the struct pointer within the page.
>
About two years ago, I tried to do similar thing in your series, but ran
into problem at this point, or maybe not exactly as the point you list
here. I consider this as the most challenged part.
The scenario is
struct X {
a[size_a];
b[size_b];
c;
};
Where size_a = f(PAGE_SHIFT), size_b=g(PAGE_SHIFT). One of f() and g()
is proportional to PAGE_SHIFT, the other is inversely proportional.
How can you fix the reference of X.a and X.b?
Thanks,
Pingfan
> 4. BUILD_BUG_ON() with values derived from PAGE_SIZE
>
> In most cases, we can change these to compare againt the appropriate
> limit (either MIN or MAX). In other cases, we must change these to
> run-time BUG_ON().
>
> 5. Ensure page alignment of static data structures
>
> Align instead to PAGE_SIZE_MAX.
>
> 6. #ifdeffery based on PAGE_SIZE
>
> Often these can be changed to c code constructs. e.g. a macro that
> returns a different value depending on page size can be changed to use
> the ternary operator and the compiler will dead code strip it for the
> compile-time constant case and runtime evaluate it for the non-const
> case. Or #if/#else/#endif within a function can be converted to c
> if/else blocks, which are also dead code stripped for the const case.
> Sometimes we can change the c-preprocessor logic to use the
> appropriate MIN/MAX limit.
>
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>
> ***NOTE***
> Any confused maintainers may want to read the cover note here for context:
> https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
>
> arch/alpha/include/asm/page.h | 1 +
> arch/arc/include/asm/page.h | 1 +
> arch/arm/include/asm/page.h | 1 +
> arch/arm64/include/asm/page-def.h | 2 +
> arch/csky/include/asm/page.h | 3 ++
> arch/hexagon/include/asm/page.h | 2 +
> arch/loongarch/include/asm/page.h | 2 +
> arch/m68k/include/asm/page.h | 1 +
> arch/microblaze/include/asm/page.h | 1 +
> arch/mips/include/asm/page.h | 1 +
> arch/nios2/include/asm/page.h | 2 +
> arch/openrisc/include/asm/page.h | 1 +
> arch/parisc/include/asm/page.h | 1 +
> arch/powerpc/include/asm/page.h | 2 +
> arch/riscv/include/asm/page.h | 1 +
> arch/s390/include/asm/page.h | 1 +
> arch/sh/include/asm/page.h | 1 +
> arch/sparc/include/asm/page.h | 3 ++
> arch/um/include/asm/page.h | 2 +
> arch/x86/include/asm/page_types.h | 2 +
> arch/xtensa/include/asm/page.h | 1 +
> include/asm-generic/pgtable-geometry.h | 71 ++++++++++++++++++++++++++
> init/main.c | 5 +-
> 23 files changed, 107 insertions(+), 1 deletion(-)
> create mode 100644 include/asm-generic/pgtable-geometry.h
>
> diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
> index 70419e6be1a35..d0096fb5521b8 100644
> --- a/arch/alpha/include/asm/page.h
> +++ b/arch/alpha/include/asm/page.h
> @@ -88,5 +88,6 @@ typedef struct page *pgtable_t;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ALPHA_PAGE_H */
> diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
> index def0dfb95b436..8d56549db7a33 100644
> --- a/arch/arc/include/asm/page.h
> +++ b/arch/arc/include/asm/page.h
> @@ -6,6 +6,7 @@
> #define __ASM_ARC_PAGE_H
>
> #include <uapi/asm/page.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #ifdef CONFIG_ARC_HAS_PAE40
>
> diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
> index 62af9f7f9e963..417aa8533c718 100644
> --- a/arch/arm/include/asm/page.h
> +++ b/arch/arm/include/asm/page.h
> @@ -191,5 +191,6 @@ extern int pfn_valid(unsigned long);
>
> #include <asm-generic/getorder.h>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif
> diff --git a/arch/arm64/include/asm/page-def.h b/arch/arm64/include/asm/page-def.h
> index 792e9fe881dcf..d69971cf49cd2 100644
> --- a/arch/arm64/include/asm/page-def.h
> +++ b/arch/arm64/include/asm/page-def.h
> @@ -15,4 +15,6 @@
> #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
> #define PAGE_MASK (~(PAGE_SIZE-1))
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __ASM_PAGE_DEF_H */
> diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h
> index 0ca6c408c07f2..95173d57adc8b 100644
> --- a/arch/csky/include/asm/page.h
> +++ b/arch/csky/include/asm/page.h
> @@ -92,4 +92,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
> #include <asm-generic/getorder.h>
>
> #endif /* !__ASSEMBLY__ */
> +
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __ASM_CSKY_PAGE_H */
> diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h
> index 8a6af57274c2d..ba7ad5231695f 100644
> --- a/arch/hexagon/include/asm/page.h
> +++ b/arch/hexagon/include/asm/page.h
> @@ -139,4 +139,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
> #endif /* ifdef __ASSEMBLY__ */
> #endif /* ifdef __KERNEL__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif
> diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
> index e85df33f11c77..9862e8fb047a6 100644
> --- a/arch/loongarch/include/asm/page.h
> +++ b/arch/loongarch/include/asm/page.h
> @@ -123,4 +123,6 @@ extern int __virt_addr_valid(volatile void *kaddr);
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_PAGE_H */
> diff --git a/arch/m68k/include/asm/page.h b/arch/m68k/include/asm/page.h
> index 8cfb84b499751..4df4681b02194 100644
> --- a/arch/m68k/include/asm/page.h
> +++ b/arch/m68k/include/asm/page.h
> @@ -60,5 +60,6 @@ extern unsigned long _ramend;
>
> #include <asm-generic/getorder.h>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _M68K_PAGE_H */
> diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
> index 8810f4f1c3b02..abc23c3d743bd 100644
> --- a/arch/microblaze/include/asm/page.h
> +++ b/arch/microblaze/include/asm/page.h
> @@ -142,5 +142,6 @@ static inline const void *pfn_to_virt(unsigned long pfn)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_MICROBLAZE_PAGE_H */
> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
> index 4609cb0326cf3..3d91021538f02 100644
> --- a/arch/mips/include/asm/page.h
> +++ b/arch/mips/include/asm/page.h
> @@ -227,5 +227,6 @@ static inline unsigned long kaslr_offset(void)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_PAGE_H */
> diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h
> index 0722f88e63cc7..2e5f93beb42b7 100644
> --- a/arch/nios2/include/asm/page.h
> +++ b/arch/nios2/include/asm/page.h
> @@ -97,4 +97,6 @@ extern struct page *mem_map;
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_NIOS2_PAGE_H */
> diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h
> index 1d5913f67c312..a0da2a9842241 100644
> --- a/arch/openrisc/include/asm/page.h
> +++ b/arch/openrisc/include/asm/page.h
> @@ -88,5 +88,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* __ASM_OPENRISC_PAGE_H */
> diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
> index 4bea2e95798f0..2a75496237c09 100644
> --- a/arch/parisc/include/asm/page.h
> +++ b/arch/parisc/include/asm/page.h
> @@ -173,6 +173,7 @@ extern int npmem_ranges;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
> #include <asm/pdc.h>
>
> #define PAGE0 ((struct zeropage *)absolute_pointer(__PAGE_OFFSET))
> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
> index 83d0a4fc5f755..4601c115b6485 100644
> --- a/arch/powerpc/include/asm/page.h
> +++ b/arch/powerpc/include/asm/page.h
> @@ -300,4 +300,6 @@ static inline unsigned long kaslr_offset(void)
> #include <asm-generic/memory_model.h>
> #endif /* __ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_POWERPC_PAGE_H */
> diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
> index 7ede2111c5917..e5af7579e45bf 100644
> --- a/arch/riscv/include/asm/page.h
> +++ b/arch/riscv/include/asm/page.h
> @@ -204,5 +204,6 @@ static __always_inline void *pfn_to_kaddr(unsigned long pfn)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_RISCV_PAGE_H */
> diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
> index 16e4caa931f1f..42157e7690a77 100644
> --- a/arch/s390/include/asm/page.h
> +++ b/arch/s390/include/asm/page.h
> @@ -275,6 +275,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #define AMODE31_SIZE (3 * PAGE_SIZE)
>
> diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
> index f780b467e75d7..09533d46ef033 100644
> --- a/arch/sh/include/asm/page.h
> +++ b/arch/sh/include/asm/page.h
> @@ -162,5 +162,6 @@ typedef struct page *pgtable_t;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* __ASM_SH_PAGE_H */
> diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h
> index 5e44cdf2a8f2b..4327fe2bfa010 100644
> --- a/arch/sparc/include/asm/page.h
> +++ b/arch/sparc/include/asm/page.h
> @@ -9,4 +9,7 @@
> #else
> #include <asm/page_32.h>
> #endif
> +
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif
> diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
> index 9ef9a8aedfa66..f26011808f514 100644
> --- a/arch/um/include/asm/page.h
> +++ b/arch/um/include/asm/page.h
> @@ -119,4 +119,6 @@ extern unsigned long uml_physmem;
> #define __HAVE_ARCH_GATE_AREA 1
> #endif
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __UM_PAGE_H */
> diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
> index 52f1b4ff0cc16..6d2381342047f 100644
> --- a/arch/x86/include/asm/page_types.h
> +++ b/arch/x86/include/asm/page_types.h
> @@ -71,4 +71,6 @@ extern void initmem_init(void);
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_X86_PAGE_DEFS_H */
> diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
> index 4db56ef052d22..86952cb32af23 100644
> --- a/arch/xtensa/include/asm/page.h
> +++ b/arch/xtensa/include/asm/page.h
> @@ -200,4 +200,5 @@ static inline unsigned long ___pa(unsigned long va)
> #endif /* __ASSEMBLY__ */
>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
> #endif /* _XTENSA_PAGE_H */
> diff --git a/include/asm-generic/pgtable-geometry.h b/include/asm-generic/pgtable-geometry.h
> new file mode 100644
> index 0000000000000..358e729a6ac37
> --- /dev/null
> +++ b/include/asm-generic/pgtable-geometry.h
> @@ -0,0 +1,71 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef ASM_GENERIC_PGTABLE_GEOMETRY_H
> +#define ASM_GENERIC_PGTABLE_GEOMETRY_H
> +
> +#if defined(PAGE_SHIFT_MAX) && defined(PAGE_SIZE_MAX) && defined(PAGE_MASK_MAX) && \
> + defined(PAGE_SHIFT_MIN) && defined(PAGE_SIZE_MIN) && defined(PAGE_MASK_MIN)
> +/* Arch supports boot-time page size selection. */
> +#elif defined(PAGE_SHIFT_MAX) || defined(PAGE_SIZE_MAX) || defined(PAGE_MASK_MAX) || \
> + defined(PAGE_SHIFT_MIN) || defined(PAGE_SIZE_MIN) || defined(PAGE_MASK_MIN)
> +#error Arch must define all or none of the boot-time page size macros
> +#else
> +/* Arch does not support boot-time page size selection. */
> +#define PAGE_SHIFT_MIN PAGE_SHIFT
> +#define PAGE_SIZE_MIN PAGE_SIZE
> +#define PAGE_MASK_MIN PAGE_MASK
> +#define PAGE_SHIFT_MAX PAGE_SHIFT
> +#define PAGE_SIZE_MAX PAGE_SIZE
> +#define PAGE_MASK_MAX PAGE_MASK
> +#endif
> +
> +/*
> + * Define a global variable (scalar or struct), whose value is derived from
> + * PAGE_SIZE and friends. When PAGE_SIZE is a compile-time constant, the global
> + * variable is simply defined with the static value. When PAGE_SIZE is
> + * determined at boot-time, a pure initcall is registered and run during boot to
> + * initialize the variable.
> + *
> + * @type: Unqualified type. Do not include "const"; implied by macro variant.
> + * @name: Variable name.
> + * @...: Initialization value. May be scalar or initializer.
> + *
> + * "static" is declared by placing "static" before the macro.
> + *
> + * Example:
> + *
> + * struct my_struct {
> + * int a;
> + * char b;
> + * };
> + *
> + * static DEFINE_GLOBAL_PAGE_SIZE_VAR(struct my_struct, my_variable, {
> + * .a = 10,
> + * .b = 'e',
> + * });
> + */
> +#if PAGE_SIZE_MIN != PAGE_SIZE_MAX
> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
> + type name attrib; \
> + static int __init __attribute__((constructor)) __##name##_init(void) \
> + { \
> + name = (type)__VA_ARGS__; \
> + return 0; \
> + }
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, __ro_after_init, __VA_ARGS__)
> +#else /* PAGE_SIZE_MIN == PAGE_SIZE_MAX */
> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
> + type name attrib = __VA_ARGS__; \
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(const type, name, , __VA_ARGS__)
> +#endif
> +
> +#endif /* ASM_GENERIC_PGTABLE_GEOMETRY_H */
> diff --git a/init/main.c b/init/main.c
> index 206acdde51f5a..ba1515eb20b9d 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -899,6 +899,8 @@ static void __init early_numa_node_init(void)
> #endif
> }
>
> +static __init void do_ctors(void);
> +
> asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
> void start_kernel(void)
> {
> @@ -910,6 +912,8 @@ void start_kernel(void)
> debug_objects_early_init();
> init_vmlinux_build_id();
>
> + do_ctors();
> +
> cgroup_init_early();
>
> local_irq_disable();
> @@ -1360,7 +1364,6 @@ static void __init do_basic_setup(void)
> cpuset_init_smp();
> driver_init();
> init_irq_proc();
> - do_ctors();
> do_initcalls();
> }
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection
2024-10-14 13:54 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Pingfan Liu
@ 2024-10-14 14:07 ` Ryan Roberts
2024-10-15 3:04 ` Pingfan Liu
0 siblings, 1 reply; 13+ messages in thread
From: Ryan Roberts @ 2024-10-14 14:07 UTC (permalink / raw)
To: Pingfan Liu
Cc: David S. Miller, James E.J. Bottomley, Andreas Larsson,
Andrew Morton, Anshuman Khandual, Anton Ivanov, Ard Biesheuvel,
Arnd Bergmann, Borislav Petkov, Catalin Marinas, Chris Zankel,
Dave Hansen, David Hildenbrand, Dinh Nguyen, Geert Uytterhoeven,
Greg Marsden, Helge Deller, Huacai Chen, Ingo Molnar, Ivan Ivanov,
Johannes Berg, John Paul Adrian Glaubitz, Jonas Bonn,
Kalesh Singh, Marc Zyngier, Mark Rutland, Matthias Brugger,
Max Filippov, Miroslav Benes, Rich Felker, Richard Weinberger,
Stafford Horne, Stefan Kristiansson, Thomas Bogendoerfer,
Thomas Gleixner, Will Deacon, Yoshinori Sato, x86, linux-alpha,
linux-arch, linux-arm-kernel, linux-csky, linux-hexagon,
linux-kernel, linux-m68k, linux-mips, linux-mm, linux-openrisc,
linux-parisc, linux-riscv, linux-s390, linux-sh, linux-snps-arc,
linux-um, linuxppc-dev, loongarch, sparclinux
On 14/10/2024 14:54, Pingfan Liu wrote:
> Hello Ryan,
>
> On Mon, Oct 14, 2024 at 11:58:08AM +0100, Ryan Roberts wrote:
>> arm64 can support multiple base page sizes. Instead of selecting a page
>> size at compile time, as is done today, we will make it possible to
>> select the desired page size on the command line.
>>
>> In this case PAGE_SHIFT and it's derivatives, PAGE_SIZE and PAGE_MASK
>> (as well as a number of other macros related to or derived from
>> PAGE_SHIFT, but I'm not worrying about those yet), are no longer
>> compile-time constants. So the code base needs to cope with that.
>>
>> As a first step, introduce MIN and MAX variants of these macros, which
>> express the range of possible page sizes. These are always compile-time
>> constants and can be used in many places where PAGE_[SHIFT|SIZE|MASK]
>> were previously used where a compile-time constant is required.
>> (Subsequent patches will do that conversion work). When the arch/build
>> doesn't support boot-time page size selection, the MIN and MAX variants
>> are equal and everything resolves as it did previously.
>>
>
> MIN and MAX appear to construct a boundary, but it may be not enough.
> Please see the following comment inline.
>
>> Additionally, introduce DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() which wrap
>> global variable defintions so that for boot-time page size selection
>> builds, the variable being wrapped is initialized at boot-time, instead
>> of compile-time. This is done by defining a function to do the
>> assignment, which has the "constructor" attribute. Constructor is
>> preferred over initcall, because when compiling a module, the module is
>> limited to a single initcall but constructors are unlimited. For
>> built-in code, constructors are now called earlier to guarrantee that
>> the variables are initialized by the time they are used. Any arch that
>> wants to enable boot-time page size selection will need to select
>> CONFIG_CONSTRUCTORS.
>>
>> These new macros need to be available anywhere PAGE_SHIFT and friends
>> are available. Those are defined via asm/page.h (although some arches
>> have a sub-include that defines them). Unfortunately there is no
>> reliable asm-generic header we can easily piggy-back on, so let's define
>> a new one, pgtable-geometry.h, which we include near where each arch
>> defines PAGE_SHIFT. Ugh.
>>
>> -------
>>
>> Most of the problems that need to be solved over the next few patches
>> fall into these broad categories, which are all solved with the help of
>> these new macros:
>>
>> 1. Assignment of values derived from PAGE_SIZE in global variables
>>
>> For boot-time page size builds, we must defer the initialization of
>> these variables until boot-time, when the page size is known. See
>> DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() as described above.
>>
>> 2. Define static storage in units related to PAGE_SIZE
>>
>> This static storage will be defined according to PAGE_SIZE_MAX.
>>
>> 3. Define size of struct so that it is related to PAGE_SIZE
>>
>> The struct often contains an array that is sized to fill the page. In
>> this case, use a flexible array with dynamic allocation. In other
>> cases, the struct fits exactly over a page, which is a header (e.g.
>> swap file header). In this case, remove the padding, and manually
>> determine the struct pointer within the page.
>>
>
> About two years ago, I tried to do similar thing in your series, but ran
> into problem at this point, or maybe not exactly as the point you list
> here. I consider this as the most challenged part.
>
> The scenario is
> struct X {
> a[size_a];
> b[size_b];
> c;
> };
>
> Where size_a = f(PAGE_SHIFT), size_b=g(PAGE_SHIFT). One of f() and g()
> is proportional to PAGE_SHIFT, the other is inversely proportional.
>
> How can you fix the reference of X.a and X.b?
If you need to allocate static memory, then in this scenario, assuming f() is
proportional and g() is inversely-proportional, then I guess you need
size_a=f(PAGE_SIZE_MAX) and size_b=g(PAGE_SIZE_MIN). Or if you can allocate the
memory dynamically, then make a and b pointers to dynamically allocated buffers.
Is there a specific place in the source where this pattern is used today? It
might be easier to discuss in the context of the code if so.
Thanks,
Ryan
>
> Thanks,
>
> Pingfan
>
>
>> 4. BUILD_BUG_ON() with values derived from PAGE_SIZE
>>
>> In most cases, we can change these to compare againt the appropriate
>> limit (either MIN or MAX). In other cases, we must change these to
>> run-time BUG_ON().
>>
>> 5. Ensure page alignment of static data structures
>>
>> Align instead to PAGE_SIZE_MAX.
>>
>> 6. #ifdeffery based on PAGE_SIZE
>>
>> Often these can be changed to c code constructs. e.g. a macro that
>> returns a different value depending on page size can be changed to use
>> the ternary operator and the compiler will dead code strip it for the
>> compile-time constant case and runtime evaluate it for the non-const
>> case. Or #if/#else/#endif within a function can be converted to c
>> if/else blocks, which are also dead code stripped for the const case.
>> Sometimes we can change the c-preprocessor logic to use the
>> appropriate MIN/MAX limit.
>>
>> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
>> ---
>>
>> ***NOTE***
>> Any confused maintainers may want to read the cover note here for context:
>> https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
>>
>> arch/alpha/include/asm/page.h | 1 +
>> arch/arc/include/asm/page.h | 1 +
>> arch/arm/include/asm/page.h | 1 +
>> arch/arm64/include/asm/page-def.h | 2 +
>> arch/csky/include/asm/page.h | 3 ++
>> arch/hexagon/include/asm/page.h | 2 +
>> arch/loongarch/include/asm/page.h | 2 +
>> arch/m68k/include/asm/page.h | 1 +
>> arch/microblaze/include/asm/page.h | 1 +
>> arch/mips/include/asm/page.h | 1 +
>> arch/nios2/include/asm/page.h | 2 +
>> arch/openrisc/include/asm/page.h | 1 +
>> arch/parisc/include/asm/page.h | 1 +
>> arch/powerpc/include/asm/page.h | 2 +
>> arch/riscv/include/asm/page.h | 1 +
>> arch/s390/include/asm/page.h | 1 +
>> arch/sh/include/asm/page.h | 1 +
>> arch/sparc/include/asm/page.h | 3 ++
>> arch/um/include/asm/page.h | 2 +
>> arch/x86/include/asm/page_types.h | 2 +
>> arch/xtensa/include/asm/page.h | 1 +
>> include/asm-generic/pgtable-geometry.h | 71 ++++++++++++++++++++++++++
>> init/main.c | 5 +-
>> 23 files changed, 107 insertions(+), 1 deletion(-)
>> create mode 100644 include/asm-generic/pgtable-geometry.h
>>
>> diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
>> index 70419e6be1a35..d0096fb5521b8 100644
>> --- a/arch/alpha/include/asm/page.h
>> +++ b/arch/alpha/include/asm/page.h
>> @@ -88,5 +88,6 @@ typedef struct page *pgtable_t;
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif /* _ALPHA_PAGE_H */
>> diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
>> index def0dfb95b436..8d56549db7a33 100644
>> --- a/arch/arc/include/asm/page.h
>> +++ b/arch/arc/include/asm/page.h
>> @@ -6,6 +6,7 @@
>> #define __ASM_ARC_PAGE_H
>>
>> #include <uapi/asm/page.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #ifdef CONFIG_ARC_HAS_PAE40
>>
>> diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
>> index 62af9f7f9e963..417aa8533c718 100644
>> --- a/arch/arm/include/asm/page.h
>> +++ b/arch/arm/include/asm/page.h
>> @@ -191,5 +191,6 @@ extern int pfn_valid(unsigned long);
>>
>> #include <asm-generic/getorder.h>
>> #include <asm-generic/memory_model.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif
>> diff --git a/arch/arm64/include/asm/page-def.h b/arch/arm64/include/asm/page-def.h
>> index 792e9fe881dcf..d69971cf49cd2 100644
>> --- a/arch/arm64/include/asm/page-def.h
>> +++ b/arch/arm64/include/asm/page-def.h
>> @@ -15,4 +15,6 @@
>> #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
>> #define PAGE_MASK (~(PAGE_SIZE-1))
>>
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif /* __ASM_PAGE_DEF_H */
>> diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h
>> index 0ca6c408c07f2..95173d57adc8b 100644
>> --- a/arch/csky/include/asm/page.h
>> +++ b/arch/csky/include/asm/page.h
>> @@ -92,4 +92,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>> #include <asm-generic/getorder.h>
>>
>> #endif /* !__ASSEMBLY__ */
>> +
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif /* __ASM_CSKY_PAGE_H */
>> diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h
>> index 8a6af57274c2d..ba7ad5231695f 100644
>> --- a/arch/hexagon/include/asm/page.h
>> +++ b/arch/hexagon/include/asm/page.h
>> @@ -139,4 +139,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>> #endif /* ifdef __ASSEMBLY__ */
>> #endif /* ifdef __KERNEL__ */
>>
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif
>> diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
>> index e85df33f11c77..9862e8fb047a6 100644
>> --- a/arch/loongarch/include/asm/page.h
>> +++ b/arch/loongarch/include/asm/page.h
>> @@ -123,4 +123,6 @@ extern int __virt_addr_valid(volatile void *kaddr);
>>
>> #endif /* !__ASSEMBLY__ */
>>
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif /* _ASM_PAGE_H */
>> diff --git a/arch/m68k/include/asm/page.h b/arch/m68k/include/asm/page.h
>> index 8cfb84b499751..4df4681b02194 100644
>> --- a/arch/m68k/include/asm/page.h
>> +++ b/arch/m68k/include/asm/page.h
>> @@ -60,5 +60,6 @@ extern unsigned long _ramend;
>>
>> #include <asm-generic/getorder.h>
>> #include <asm-generic/memory_model.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif /* _M68K_PAGE_H */
>> diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
>> index 8810f4f1c3b02..abc23c3d743bd 100644
>> --- a/arch/microblaze/include/asm/page.h
>> +++ b/arch/microblaze/include/asm/page.h
>> @@ -142,5 +142,6 @@ static inline const void *pfn_to_virt(unsigned long pfn)
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif /* _ASM_MICROBLAZE_PAGE_H */
>> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
>> index 4609cb0326cf3..3d91021538f02 100644
>> --- a/arch/mips/include/asm/page.h
>> +++ b/arch/mips/include/asm/page.h
>> @@ -227,5 +227,6 @@ static inline unsigned long kaslr_offset(void)
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif /* _ASM_PAGE_H */
>> diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h
>> index 0722f88e63cc7..2e5f93beb42b7 100644
>> --- a/arch/nios2/include/asm/page.h
>> +++ b/arch/nios2/include/asm/page.h
>> @@ -97,4 +97,6 @@ extern struct page *mem_map;
>>
>> #endif /* !__ASSEMBLY__ */
>>
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif /* _ASM_NIOS2_PAGE_H */
>> diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h
>> index 1d5913f67c312..a0da2a9842241 100644
>> --- a/arch/openrisc/include/asm/page.h
>> +++ b/arch/openrisc/include/asm/page.h
>> @@ -88,5 +88,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif /* __ASM_OPENRISC_PAGE_H */
>> diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
>> index 4bea2e95798f0..2a75496237c09 100644
>> --- a/arch/parisc/include/asm/page.h
>> +++ b/arch/parisc/include/asm/page.h
>> @@ -173,6 +173,7 @@ extern int npmem_ranges;
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>> #include <asm/pdc.h>
>>
>> #define PAGE0 ((struct zeropage *)absolute_pointer(__PAGE_OFFSET))
>> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
>> index 83d0a4fc5f755..4601c115b6485 100644
>> --- a/arch/powerpc/include/asm/page.h
>> +++ b/arch/powerpc/include/asm/page.h
>> @@ -300,4 +300,6 @@ static inline unsigned long kaslr_offset(void)
>> #include <asm-generic/memory_model.h>
>> #endif /* __ASSEMBLY__ */
>>
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif /* _ASM_POWERPC_PAGE_H */
>> diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
>> index 7ede2111c5917..e5af7579e45bf 100644
>> --- a/arch/riscv/include/asm/page.h
>> +++ b/arch/riscv/include/asm/page.h
>> @@ -204,5 +204,6 @@ static __always_inline void *pfn_to_kaddr(unsigned long pfn)
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif /* _ASM_RISCV_PAGE_H */
>> diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
>> index 16e4caa931f1f..42157e7690a77 100644
>> --- a/arch/s390/include/asm/page.h
>> +++ b/arch/s390/include/asm/page.h
>> @@ -275,6 +275,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #define AMODE31_SIZE (3 * PAGE_SIZE)
>>
>> diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
>> index f780b467e75d7..09533d46ef033 100644
>> --- a/arch/sh/include/asm/page.h
>> +++ b/arch/sh/include/asm/page.h
>> @@ -162,5 +162,6 @@ typedef struct page *pgtable_t;
>>
>> #include <asm-generic/memory_model.h>
>> #include <asm-generic/getorder.h>
>> +#include <asm-generic/pgtable-geometry.h>
>>
>> #endif /* __ASM_SH_PAGE_H */
>> diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h
>> index 5e44cdf2a8f2b..4327fe2bfa010 100644
>> --- a/arch/sparc/include/asm/page.h
>> +++ b/arch/sparc/include/asm/page.h
>> @@ -9,4 +9,7 @@
>> #else
>> #include <asm/page_32.h>
>> #endif
>> +
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif
>> diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
>> index 9ef9a8aedfa66..f26011808f514 100644
>> --- a/arch/um/include/asm/page.h
>> +++ b/arch/um/include/asm/page.h
>> @@ -119,4 +119,6 @@ extern unsigned long uml_physmem;
>> #define __HAVE_ARCH_GATE_AREA 1
>> #endif
>>
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif /* __UM_PAGE_H */
>> diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
>> index 52f1b4ff0cc16..6d2381342047f 100644
>> --- a/arch/x86/include/asm/page_types.h
>> +++ b/arch/x86/include/asm/page_types.h
>> @@ -71,4 +71,6 @@ extern void initmem_init(void);
>>
>> #endif /* !__ASSEMBLY__ */
>>
>> +#include <asm-generic/pgtable-geometry.h>
>> +
>> #endif /* _ASM_X86_PAGE_DEFS_H */
>> diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
>> index 4db56ef052d22..86952cb32af23 100644
>> --- a/arch/xtensa/include/asm/page.h
>> +++ b/arch/xtensa/include/asm/page.h
>> @@ -200,4 +200,5 @@ static inline unsigned long ___pa(unsigned long va)
>> #endif /* __ASSEMBLY__ */
>>
>> #include <asm-generic/memory_model.h>
>> +#include <asm-generic/pgtable-geometry.h>
>> #endif /* _XTENSA_PAGE_H */
>> diff --git a/include/asm-generic/pgtable-geometry.h b/include/asm-generic/pgtable-geometry.h
>> new file mode 100644
>> index 0000000000000..358e729a6ac37
>> --- /dev/null
>> +++ b/include/asm-generic/pgtable-geometry.h
>> @@ -0,0 +1,71 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +#ifndef ASM_GENERIC_PGTABLE_GEOMETRY_H
>> +#define ASM_GENERIC_PGTABLE_GEOMETRY_H
>> +
>> +#if defined(PAGE_SHIFT_MAX) && defined(PAGE_SIZE_MAX) && defined(PAGE_MASK_MAX) && \
>> + defined(PAGE_SHIFT_MIN) && defined(PAGE_SIZE_MIN) && defined(PAGE_MASK_MIN)
>> +/* Arch supports boot-time page size selection. */
>> +#elif defined(PAGE_SHIFT_MAX) || defined(PAGE_SIZE_MAX) || defined(PAGE_MASK_MAX) || \
>> + defined(PAGE_SHIFT_MIN) || defined(PAGE_SIZE_MIN) || defined(PAGE_MASK_MIN)
>> +#error Arch must define all or none of the boot-time page size macros
>> +#else
>> +/* Arch does not support boot-time page size selection. */
>> +#define PAGE_SHIFT_MIN PAGE_SHIFT
>> +#define PAGE_SIZE_MIN PAGE_SIZE
>> +#define PAGE_MASK_MIN PAGE_MASK
>> +#define PAGE_SHIFT_MAX PAGE_SHIFT
>> +#define PAGE_SIZE_MAX PAGE_SIZE
>> +#define PAGE_MASK_MAX PAGE_MASK
>> +#endif
>> +
>> +/*
>> + * Define a global variable (scalar or struct), whose value is derived from
>> + * PAGE_SIZE and friends. When PAGE_SIZE is a compile-time constant, the global
>> + * variable is simply defined with the static value. When PAGE_SIZE is
>> + * determined at boot-time, a pure initcall is registered and run during boot to
>> + * initialize the variable.
>> + *
>> + * @type: Unqualified type. Do not include "const"; implied by macro variant.
>> + * @name: Variable name.
>> + * @...: Initialization value. May be scalar or initializer.
>> + *
>> + * "static" is declared by placing "static" before the macro.
>> + *
>> + * Example:
>> + *
>> + * struct my_struct {
>> + * int a;
>> + * char b;
>> + * };
>> + *
>> + * static DEFINE_GLOBAL_PAGE_SIZE_VAR(struct my_struct, my_variable, {
>> + * .a = 10,
>> + * .b = 'e',
>> + * });
>> + */
>> +#if PAGE_SIZE_MIN != PAGE_SIZE_MAX
>> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
>> + type name attrib; \
>> + static int __init __attribute__((constructor)) __##name##_init(void) \
>> + { \
>> + name = (type)__VA_ARGS__; \
>> + return 0; \
>> + }
>> +
>> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
>> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
>> +
>> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
>> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, __ro_after_init, __VA_ARGS__)
>> +#else /* PAGE_SIZE_MIN == PAGE_SIZE_MAX */
>> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
>> + type name attrib = __VA_ARGS__; \
>> +
>> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
>> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
>> +
>> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
>> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(const type, name, , __VA_ARGS__)
>> +#endif
>> +
>> +#endif /* ASM_GENERIC_PGTABLE_GEOMETRY_H */
>> diff --git a/init/main.c b/init/main.c
>> index 206acdde51f5a..ba1515eb20b9d 100644
>> --- a/init/main.c
>> +++ b/init/main.c
>> @@ -899,6 +899,8 @@ static void __init early_numa_node_init(void)
>> #endif
>> }
>>
>> +static __init void do_ctors(void);
>> +
>> asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
>> void start_kernel(void)
>> {
>> @@ -910,6 +912,8 @@ void start_kernel(void)
>> debug_objects_early_init();
>> init_vmlinux_build_id();
>>
>> + do_ctors();
>> +
>> cgroup_init_early();
>>
>> local_irq_disable();
>> @@ -1360,7 +1364,6 @@ static void __init do_basic_setup(void)
>> cpuset_init_smp();
>> driver_init();
>> init_irq_proc();
>> - do_ctors();
>> do_initcalls();
>> }
>>
>> --
>> 2.43.0
>>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX
2024-10-14 10:58 ` [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX Ryan Roberts
@ 2024-10-14 16:50 ` Christoph Lameter (Ampere)
2024-10-15 10:53 ` Ryan Roberts
0 siblings, 1 reply; 13+ messages in thread
From: Christoph Lameter (Ampere) @ 2024-10-14 16:50 UTC (permalink / raw)
To: Ryan Roberts
Cc: Andrew Morton, Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Catalin Marinas, David Hildenbrand, Dennis Zhou, Greg Marsden,
Ivan Ivanov, Kalesh Singh, Marc Zyngier, Mark Rutland,
Matthias Brugger, Miroslav Benes, Tejun Heo, Will Deacon,
linux-arch, linux-arm-kernel, linux-kernel, linux-mm
On Mon, 14 Oct 2024, Ryan Roberts wrote:
> Increase alignment of structures requiring at least PAGE_SIZE alignment
> to PAGE_SIZE_MAX. For compile-time PAGE_SIZE, PAGE_SIZE_MAX == PAGE_SIZE
> so there is no change. For boot-time PAGE_SIZE, PAGE_SIZE_MAX is the
> largest selectable page size.
Can you verify that this works with the arch specific portions? This may
also allow to to reduce some of the arch dependent stuff.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection
2024-10-14 14:07 ` Ryan Roberts
@ 2024-10-15 3:04 ` Pingfan Liu
2024-10-15 11:16 ` Ryan Roberts
0 siblings, 1 reply; 13+ messages in thread
From: Pingfan Liu @ 2024-10-15 3:04 UTC (permalink / raw)
To: Ryan Roberts
Cc: David S. Miller, James E.J. Bottomley, Andreas Larsson,
Andrew Morton, Anshuman Khandual, Anton Ivanov, Ard Biesheuvel,
Arnd Bergmann, Borislav Petkov, Catalin Marinas, Chris Zankel,
Dave Hansen, David Hildenbrand, Dinh Nguyen, Geert Uytterhoeven,
Greg Marsden, Helge Deller, Huacai Chen, Ingo Molnar, Ivan Ivanov,
Johannes Berg, John Paul Adrian Glaubitz, Jonas Bonn,
Kalesh Singh, Marc Zyngier, Mark Rutland, Matthias Brugger,
Max Filippov, Miroslav Benes, Rich Felker, Richard Weinberger,
Stafford Horne, Stefan Kristiansson, Thomas Bogendoerfer,
Thomas Gleixner, Will Deacon, Yoshinori Sato, x86, linux-alpha,
linux-arch, linux-arm-kernel, linux-csky, linux-hexagon,
linux-kernel, linux-m68k, linux-mips, linux-mm, linux-openrisc,
linux-parisc, linux-riscv, linux-s390, linux-sh, linux-snps-arc,
linux-um, linuxppc-dev, loongarch, sparclinux
On Mon, Oct 14, 2024 at 10:07 PM Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 14/10/2024 14:54, Pingfan Liu wrote:
> > Hello Ryan,
> >
> > On Mon, Oct 14, 2024 at 11:58:08AM +0100, Ryan Roberts wrote:
> >> arm64 can support multiple base page sizes. Instead of selecting a page
> >> size at compile time, as is done today, we will make it possible to
> >> select the desired page size on the command line.
> >>
> >> In this case PAGE_SHIFT and it's derivatives, PAGE_SIZE and PAGE_MASK
> >> (as well as a number of other macros related to or derived from
> >> PAGE_SHIFT, but I'm not worrying about those yet), are no longer
> >> compile-time constants. So the code base needs to cope with that.
> >>
> >> As a first step, introduce MIN and MAX variants of these macros, which
> >> express the range of possible page sizes. These are always compile-time
> >> constants and can be used in many places where PAGE_[SHIFT|SIZE|MASK]
> >> were previously used where a compile-time constant is required.
> >> (Subsequent patches will do that conversion work). When the arch/build
> >> doesn't support boot-time page size selection, the MIN and MAX variants
> >> are equal and everything resolves as it did previously.
> >>
> >
> > MIN and MAX appear to construct a boundary, but it may be not enough.
> > Please see the following comment inline.
> >
> >> Additionally, introduce DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() which wrap
> >> global variable defintions so that for boot-time page size selection
> >> builds, the variable being wrapped is initialized at boot-time, instead
> >> of compile-time. This is done by defining a function to do the
> >> assignment, which has the "constructor" attribute. Constructor is
> >> preferred over initcall, because when compiling a module, the module is
> >> limited to a single initcall but constructors are unlimited. For
> >> built-in code, constructors are now called earlier to guarrantee that
> >> the variables are initialized by the time they are used. Any arch that
> >> wants to enable boot-time page size selection will need to select
> >> CONFIG_CONSTRUCTORS.
> >>
> >> These new macros need to be available anywhere PAGE_SHIFT and friends
> >> are available. Those are defined via asm/page.h (although some arches
> >> have a sub-include that defines them). Unfortunately there is no
> >> reliable asm-generic header we can easily piggy-back on, so let's define
> >> a new one, pgtable-geometry.h, which we include near where each arch
> >> defines PAGE_SHIFT. Ugh.
> >>
> >> -------
> >>
> >> Most of the problems that need to be solved over the next few patches
> >> fall into these broad categories, which are all solved with the help of
> >> these new macros:
> >>
> >> 1. Assignment of values derived from PAGE_SIZE in global variables
> >>
> >> For boot-time page size builds, we must defer the initialization of
> >> these variables until boot-time, when the page size is known. See
> >> DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() as described above.
> >>
> >> 2. Define static storage in units related to PAGE_SIZE
> >>
> >> This static storage will be defined according to PAGE_SIZE_MAX.
> >>
> >> 3. Define size of struct so that it is related to PAGE_SIZE
> >>
> >> The struct often contains an array that is sized to fill the page. In
> >> this case, use a flexible array with dynamic allocation. In other
> >> cases, the struct fits exactly over a page, which is a header (e.g.
> >> swap file header). In this case, remove the padding, and manually
> >> determine the struct pointer within the page.
> >>
> >
> > About two years ago, I tried to do similar thing in your series, but ran
> > into problem at this point, or maybe not exactly as the point you list
> > here. I consider this as the most challenged part.
> >
> > The scenario is
> > struct X {
> > a[size_a];
> > b[size_b];
> > c;
> > };
> >
> > Where size_a = f(PAGE_SHIFT), size_b=g(PAGE_SHIFT). One of f() and g()
> > is proportional to PAGE_SHIFT, the other is inversely proportional.
> >
> > How can you fix the reference of X.a and X.b?
>
> If you need to allocate static memory, then in this scenario, assuming f() is
> proportional and g() is inversely-proportional, then I guess you need
> size_a=f(PAGE_SIZE_MAX) and size_b=g(PAGE_SIZE_MIN). Or if you can allocate the
My point is that such stuff can not be handled by scripts
automatically and needs manual intervention.
> memory dynamically, then make a and b pointers to dynamically allocated buffers.
>
This seems a better way out.
> Is there a specific place in the source where this pattern is used today? It
> might be easier to discuss in the context of the code if so.
>
No such code at hand. Just throw out the potential issue and be
curious about it which frustrates me.
I hope people can reach an agreement on it and turn this useful series
into reality.
Thanks,
Pingfan
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX
2024-10-14 16:50 ` Christoph Lameter (Ampere)
@ 2024-10-15 10:53 ` Ryan Roberts
0 siblings, 0 replies; 13+ messages in thread
From: Ryan Roberts @ 2024-10-15 10:53 UTC (permalink / raw)
To: Christoph Lameter (Ampere)
Cc: Andrew Morton, Anshuman Khandual, Ard Biesheuvel, Arnd Bergmann,
Catalin Marinas, David Hildenbrand, Dennis Zhou, Greg Marsden,
Ivan Ivanov, Kalesh Singh, Marc Zyngier, Mark Rutland,
Matthias Brugger, Miroslav Benes, Tejun Heo, Will Deacon,
linux-arch, linux-arm-kernel, linux-kernel, linux-mm
On 14/10/2024 17:50, Christoph Lameter (Ampere) wrote:
> On Mon, 14 Oct 2024, Ryan Roberts wrote:
>
>> Increase alignment of structures requiring at least PAGE_SIZE alignment
>> to PAGE_SIZE_MAX. For compile-time PAGE_SIZE, PAGE_SIZE_MAX == PAGE_SIZE
>> so there is no change. For boot-time PAGE_SIZE, PAGE_SIZE_MAX is the
>> largest selectable page size.
>
> Can you verify that this works with the arch specific portions? This may
> also allow to to reduce some of the arch dependent stuff.
Sorry, Chistoph, I'm not exactly sure what you mean here by "arch specific
portions" and "reduce some of the arch dependent stuff"? Could you elaborate?
I can certainly verify that this change works for all the test scenarios I've
listed on the cover letter.
Thanks,
Ryan
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection
2024-10-15 3:04 ` Pingfan Liu
@ 2024-10-15 11:16 ` Ryan Roberts
0 siblings, 0 replies; 13+ messages in thread
From: Ryan Roberts @ 2024-10-15 11:16 UTC (permalink / raw)
To: Pingfan Liu
Cc: David S. Miller, James E.J. Bottomley, Andreas Larsson,
Andrew Morton, Anshuman Khandual, Anton Ivanov, Ard Biesheuvel,
Arnd Bergmann, Borislav Petkov, Catalin Marinas, Chris Zankel,
Dave Hansen, David Hildenbrand, Dinh Nguyen, Geert Uytterhoeven,
Greg Marsden, Helge Deller, Huacai Chen, Ingo Molnar, Ivan Ivanov,
Johannes Berg, John Paul Adrian Glaubitz, Jonas Bonn,
Kalesh Singh, Marc Zyngier, Mark Rutland, Matthias Brugger,
Max Filippov, Miroslav Benes, Rich Felker, Richard Weinberger,
Stafford Horne, Stefan Kristiansson, Thomas Bogendoerfer,
Thomas Gleixner, Will Deacon, Yoshinori Sato, x86, linux-alpha,
linux-arch, linux-arm-kernel, linux-csky, linux-hexagon,
linux-kernel, linux-m68k, linux-mips, linux-mm, linux-openrisc,
linux-parisc, linux-riscv, linux-s390, linux-sh, linux-snps-arc,
linux-um, linuxppc-dev, loongarch, sparclinux
On 15/10/2024 04:04, Pingfan Liu wrote:
> On Mon, Oct 14, 2024 at 10:07 PM Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 14/10/2024 14:54, Pingfan Liu wrote:
>>> Hello Ryan,
>>>
>>> On Mon, Oct 14, 2024 at 11:58:08AM +0100, Ryan Roberts wrote:
>>>> arm64 can support multiple base page sizes. Instead of selecting a page
>>>> size at compile time, as is done today, we will make it possible to
>>>> select the desired page size on the command line.
>>>>
>>>> In this case PAGE_SHIFT and it's derivatives, PAGE_SIZE and PAGE_MASK
>>>> (as well as a number of other macros related to or derived from
>>>> PAGE_SHIFT, but I'm not worrying about those yet), are no longer
>>>> compile-time constants. So the code base needs to cope with that.
>>>>
>>>> As a first step, introduce MIN and MAX variants of these macros, which
>>>> express the range of possible page sizes. These are always compile-time
>>>> constants and can be used in many places where PAGE_[SHIFT|SIZE|MASK]
>>>> were previously used where a compile-time constant is required.
>>>> (Subsequent patches will do that conversion work). When the arch/build
>>>> doesn't support boot-time page size selection, the MIN and MAX variants
>>>> are equal and everything resolves as it did previously.
>>>>
>>>
>>> MIN and MAX appear to construct a boundary, but it may be not enough.
>>> Please see the following comment inline.
>>>
>>>> Additionally, introduce DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() which wrap
>>>> global variable defintions so that for boot-time page size selection
>>>> builds, the variable being wrapped is initialized at boot-time, instead
>>>> of compile-time. This is done by defining a function to do the
>>>> assignment, which has the "constructor" attribute. Constructor is
>>>> preferred over initcall, because when compiling a module, the module is
>>>> limited to a single initcall but constructors are unlimited. For
>>>> built-in code, constructors are now called earlier to guarrantee that
>>>> the variables are initialized by the time they are used. Any arch that
>>>> wants to enable boot-time page size selection will need to select
>>>> CONFIG_CONSTRUCTORS.
>>>>
>>>> These new macros need to be available anywhere PAGE_SHIFT and friends
>>>> are available. Those are defined via asm/page.h (although some arches
>>>> have a sub-include that defines them). Unfortunately there is no
>>>> reliable asm-generic header we can easily piggy-back on, so let's define
>>>> a new one, pgtable-geometry.h, which we include near where each arch
>>>> defines PAGE_SHIFT. Ugh.
>>>>
>>>> -------
>>>>
>>>> Most of the problems that need to be solved over the next few patches
>>>> fall into these broad categories, which are all solved with the help of
>>>> these new macros:
>>>>
>>>> 1. Assignment of values derived from PAGE_SIZE in global variables
>>>>
>>>> For boot-time page size builds, we must defer the initialization of
>>>> these variables until boot-time, when the page size is known. See
>>>> DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() as described above.
>>>>
>>>> 2. Define static storage in units related to PAGE_SIZE
>>>>
>>>> This static storage will be defined according to PAGE_SIZE_MAX.
>>>>
>>>> 3. Define size of struct so that it is related to PAGE_SIZE
>>>>
>>>> The struct often contains an array that is sized to fill the page. In
>>>> this case, use a flexible array with dynamic allocation. In other
>>>> cases, the struct fits exactly over a page, which is a header (e.g.
>>>> swap file header). In this case, remove the padding, and manually
>>>> determine the struct pointer within the page.
>>>>
>>>
>>> About two years ago, I tried to do similar thing in your series, but ran
>>> into problem at this point, or maybe not exactly as the point you list
>>> here. I consider this as the most challenged part.
>>>
>>> The scenario is
>>> struct X {
>>> a[size_a];
>>> b[size_b];
>>> c;
>>> };
>>>
>>> Where size_a = f(PAGE_SHIFT), size_b=g(PAGE_SHIFT). One of f() and g()
>>> is proportional to PAGE_SHIFT, the other is inversely proportional.
>>>
>>> How can you fix the reference of X.a and X.b?
>>
>> If you need to allocate static memory, then in this scenario, assuming f() is
>> proportional and g() is inversely-proportional, then I guess you need
>> size_a=f(PAGE_SIZE_MAX) and size_b=g(PAGE_SIZE_MIN). Or if you can allocate the
>
> My point is that such stuff can not be handled by scripts
> automatically and needs manual intervention.
Yes agreed. I spent some time thinking about how much of this could be automated
(i.e. with Cochinelle or otherwise), but concluded that it's very difficult. As
a result, all of the patches in this series are manually created.
>
>> memory dynamically, then make a and b pointers to dynamically allocated buffers.
>>
>
> This seems a better way out.
>
>> Is there a specific place in the source where this pattern is used today? It
>> might be easier to discuss in the context of the code if so.
>>
>
> No such code at hand. Just throw out the potential issue and be
> curious about it which frustrates me.
> I hope people can reach an agreement on it and turn this useful series
> into reality.
Yes, hope so!
>
> Thanks,
>
> Pingfan
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection
2024-10-14 10:58 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Ryan Roberts
` (3 preceding siblings ...)
2024-10-14 13:54 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Pingfan Liu
@ 2024-10-16 14:36 ` Ryan Roberts
2024-10-30 8:45 ` Ryan Roberts
5 siblings, 0 replies; 13+ messages in thread
From: Ryan Roberts @ 2024-10-16 14:36 UTC (permalink / raw)
To: David S. Miller, James E.J. Bottomley, Andreas Larsson,
Andrew Morton, Anshuman Khandual, Anton Ivanov, Ard Biesheuvel,
Arnd Bergmann, Borislav Petkov, Catalin Marinas, Chris Zankel,
Dave Hansen, David Hildenbrand, Dinh Nguyen, Geert Uytterhoeven,
Greg Marsden, Helge Deller, Huacai Chen, Ingo Molnar, Ivan Ivanov,
Johannes Berg, John Paul Adrian Glaubitz, Jonas Bonn,
Kalesh Singh, Marc Zyngier, Mark Rutland, Matthias Brugger,
Max Filippov, Miroslav Benes, Rich Felker, Richard Weinberger,
Stafford Horne, Stefan Kristiansson, Thomas Bogendoerfer,
Thomas Gleixner, Will Deacon, Yoshinori Sato, x86, Albert Ou,
Alexander Gordeev, Brian Cain, Guo Ren, Heiko Carstens,
Michael Ellerman, Michal Simek, Palmer Dabbelt, Paul Walmsley,
Vasily Gorbik, Vineet Gupta
Cc: linux-alpha, linux-arch, linux-arm-kernel, linux-csky,
linux-hexagon, linux-kernel, linux-m68k, linux-mips, linux-mm,
linux-openrisc, linux-parisc, linux-riscv, linux-s390, linux-sh,
linux-snps-arc, linux-um, linuxppc-dev, loongarch, sparclinux
+ Albert Ou, Alexander Gordeev, Brian Cain, Guo Ren, Heiko Carstens, Michael
Ellerman, Michal Simek, Palmer Dabbelt, Paul Walmsley, Vasily Gorbik, Vineet Gupta.
This was a rather tricky series to get the recipients correct for and my script
did not realize that "supporter" was a pseudonym for "maintainer" so you were
missed off the original post. Appologies!
More context in cover letter:
https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
On 14/10/2024 11:58, Ryan Roberts wrote:
> arm64 can support multiple base page sizes. Instead of selecting a page
> size at compile time, as is done today, we will make it possible to
> select the desired page size on the command line.
>
> In this case PAGE_SHIFT and it's derivatives, PAGE_SIZE and PAGE_MASK
> (as well as a number of other macros related to or derived from
> PAGE_SHIFT, but I'm not worrying about those yet), are no longer
> compile-time constants. So the code base needs to cope with that.
>
> As a first step, introduce MIN and MAX variants of these macros, which
> express the range of possible page sizes. These are always compile-time
> constants and can be used in many places where PAGE_[SHIFT|SIZE|MASK]
> were previously used where a compile-time constant is required.
> (Subsequent patches will do that conversion work). When the arch/build
> doesn't support boot-time page size selection, the MIN and MAX variants
> are equal and everything resolves as it did previously.
>
> Additionally, introduce DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() which wrap
> global variable defintions so that for boot-time page size selection
> builds, the variable being wrapped is initialized at boot-time, instead
> of compile-time. This is done by defining a function to do the
> assignment, which has the "constructor" attribute. Constructor is
> preferred over initcall, because when compiling a module, the module is
> limited to a single initcall but constructors are unlimited. For
> built-in code, constructors are now called earlier to guarrantee that
> the variables are initialized by the time they are used. Any arch that
> wants to enable boot-time page size selection will need to select
> CONFIG_CONSTRUCTORS.
>
> These new macros need to be available anywhere PAGE_SHIFT and friends
> are available. Those are defined via asm/page.h (although some arches
> have a sub-include that defines them). Unfortunately there is no
> reliable asm-generic header we can easily piggy-back on, so let's define
> a new one, pgtable-geometry.h, which we include near where each arch
> defines PAGE_SHIFT. Ugh.
>
> -------
>
> Most of the problems that need to be solved over the next few patches
> fall into these broad categories, which are all solved with the help of
> these new macros:
>
> 1. Assignment of values derived from PAGE_SIZE in global variables
>
> For boot-time page size builds, we must defer the initialization of
> these variables until boot-time, when the page size is known. See
> DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() as described above.
>
> 2. Define static storage in units related to PAGE_SIZE
>
> This static storage will be defined according to PAGE_SIZE_MAX.
>
> 3. Define size of struct so that it is related to PAGE_SIZE
>
> The struct often contains an array that is sized to fill the page. In
> this case, use a flexible array with dynamic allocation. In other
> cases, the struct fits exactly over a page, which is a header (e.g.
> swap file header). In this case, remove the padding, and manually
> determine the struct pointer within the page.
>
> 4. BUILD_BUG_ON() with values derived from PAGE_SIZE
>
> In most cases, we can change these to compare againt the appropriate
> limit (either MIN or MAX). In other cases, we must change these to
> run-time BUG_ON().
>
> 5. Ensure page alignment of static data structures
>
> Align instead to PAGE_SIZE_MAX.
>
> 6. #ifdeffery based on PAGE_SIZE
>
> Often these can be changed to c code constructs. e.g. a macro that
> returns a different value depending on page size can be changed to use
> the ternary operator and the compiler will dead code strip it for the
> compile-time constant case and runtime evaluate it for the non-const
> case. Or #if/#else/#endif within a function can be converted to c
> if/else blocks, which are also dead code stripped for the const case.
> Sometimes we can change the c-preprocessor logic to use the
> appropriate MIN/MAX limit.
>
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>
> ***NOTE***
> Any confused maintainers may want to read the cover note here for context:
> https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
>
> arch/alpha/include/asm/page.h | 1 +
> arch/arc/include/asm/page.h | 1 +
> arch/arm/include/asm/page.h | 1 +
> arch/arm64/include/asm/page-def.h | 2 +
> arch/csky/include/asm/page.h | 3 ++
> arch/hexagon/include/asm/page.h | 2 +
> arch/loongarch/include/asm/page.h | 2 +
> arch/m68k/include/asm/page.h | 1 +
> arch/microblaze/include/asm/page.h | 1 +
> arch/mips/include/asm/page.h | 1 +
> arch/nios2/include/asm/page.h | 2 +
> arch/openrisc/include/asm/page.h | 1 +
> arch/parisc/include/asm/page.h | 1 +
> arch/powerpc/include/asm/page.h | 2 +
> arch/riscv/include/asm/page.h | 1 +
> arch/s390/include/asm/page.h | 1 +
> arch/sh/include/asm/page.h | 1 +
> arch/sparc/include/asm/page.h | 3 ++
> arch/um/include/asm/page.h | 2 +
> arch/x86/include/asm/page_types.h | 2 +
> arch/xtensa/include/asm/page.h | 1 +
> include/asm-generic/pgtable-geometry.h | 71 ++++++++++++++++++++++++++
> init/main.c | 5 +-
> 23 files changed, 107 insertions(+), 1 deletion(-)
> create mode 100644 include/asm-generic/pgtable-geometry.h
>
> diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
> index 70419e6be1a35..d0096fb5521b8 100644
> --- a/arch/alpha/include/asm/page.h
> +++ b/arch/alpha/include/asm/page.h
> @@ -88,5 +88,6 @@ typedef struct page *pgtable_t;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ALPHA_PAGE_H */
> diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
> index def0dfb95b436..8d56549db7a33 100644
> --- a/arch/arc/include/asm/page.h
> +++ b/arch/arc/include/asm/page.h
> @@ -6,6 +6,7 @@
> #define __ASM_ARC_PAGE_H
>
> #include <uapi/asm/page.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #ifdef CONFIG_ARC_HAS_PAE40
>
> diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
> index 62af9f7f9e963..417aa8533c718 100644
> --- a/arch/arm/include/asm/page.h
> +++ b/arch/arm/include/asm/page.h
> @@ -191,5 +191,6 @@ extern int pfn_valid(unsigned long);
>
> #include <asm-generic/getorder.h>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif
> diff --git a/arch/arm64/include/asm/page-def.h b/arch/arm64/include/asm/page-def.h
> index 792e9fe881dcf..d69971cf49cd2 100644
> --- a/arch/arm64/include/asm/page-def.h
> +++ b/arch/arm64/include/asm/page-def.h
> @@ -15,4 +15,6 @@
> #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
> #define PAGE_MASK (~(PAGE_SIZE-1))
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __ASM_PAGE_DEF_H */
> diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h
> index 0ca6c408c07f2..95173d57adc8b 100644
> --- a/arch/csky/include/asm/page.h
> +++ b/arch/csky/include/asm/page.h
> @@ -92,4 +92,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
> #include <asm-generic/getorder.h>
>
> #endif /* !__ASSEMBLY__ */
> +
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __ASM_CSKY_PAGE_H */
> diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h
> index 8a6af57274c2d..ba7ad5231695f 100644
> --- a/arch/hexagon/include/asm/page.h
> +++ b/arch/hexagon/include/asm/page.h
> @@ -139,4 +139,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
> #endif /* ifdef __ASSEMBLY__ */
> #endif /* ifdef __KERNEL__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif
> diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
> index e85df33f11c77..9862e8fb047a6 100644
> --- a/arch/loongarch/include/asm/page.h
> +++ b/arch/loongarch/include/asm/page.h
> @@ -123,4 +123,6 @@ extern int __virt_addr_valid(volatile void *kaddr);
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_PAGE_H */
> diff --git a/arch/m68k/include/asm/page.h b/arch/m68k/include/asm/page.h
> index 8cfb84b499751..4df4681b02194 100644
> --- a/arch/m68k/include/asm/page.h
> +++ b/arch/m68k/include/asm/page.h
> @@ -60,5 +60,6 @@ extern unsigned long _ramend;
>
> #include <asm-generic/getorder.h>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _M68K_PAGE_H */
> diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
> index 8810f4f1c3b02..abc23c3d743bd 100644
> --- a/arch/microblaze/include/asm/page.h
> +++ b/arch/microblaze/include/asm/page.h
> @@ -142,5 +142,6 @@ static inline const void *pfn_to_virt(unsigned long pfn)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_MICROBLAZE_PAGE_H */
> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
> index 4609cb0326cf3..3d91021538f02 100644
> --- a/arch/mips/include/asm/page.h
> +++ b/arch/mips/include/asm/page.h
> @@ -227,5 +227,6 @@ static inline unsigned long kaslr_offset(void)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_PAGE_H */
> diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h
> index 0722f88e63cc7..2e5f93beb42b7 100644
> --- a/arch/nios2/include/asm/page.h
> +++ b/arch/nios2/include/asm/page.h
> @@ -97,4 +97,6 @@ extern struct page *mem_map;
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_NIOS2_PAGE_H */
> diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h
> index 1d5913f67c312..a0da2a9842241 100644
> --- a/arch/openrisc/include/asm/page.h
> +++ b/arch/openrisc/include/asm/page.h
> @@ -88,5 +88,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* __ASM_OPENRISC_PAGE_H */
> diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
> index 4bea2e95798f0..2a75496237c09 100644
> --- a/arch/parisc/include/asm/page.h
> +++ b/arch/parisc/include/asm/page.h
> @@ -173,6 +173,7 @@ extern int npmem_ranges;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
> #include <asm/pdc.h>
>
> #define PAGE0 ((struct zeropage *)absolute_pointer(__PAGE_OFFSET))
> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
> index 83d0a4fc5f755..4601c115b6485 100644
> --- a/arch/powerpc/include/asm/page.h
> +++ b/arch/powerpc/include/asm/page.h
> @@ -300,4 +300,6 @@ static inline unsigned long kaslr_offset(void)
> #include <asm-generic/memory_model.h>
> #endif /* __ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_POWERPC_PAGE_H */
> diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
> index 7ede2111c5917..e5af7579e45bf 100644
> --- a/arch/riscv/include/asm/page.h
> +++ b/arch/riscv/include/asm/page.h
> @@ -204,5 +204,6 @@ static __always_inline void *pfn_to_kaddr(unsigned long pfn)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_RISCV_PAGE_H */
> diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
> index 16e4caa931f1f..42157e7690a77 100644
> --- a/arch/s390/include/asm/page.h
> +++ b/arch/s390/include/asm/page.h
> @@ -275,6 +275,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #define AMODE31_SIZE (3 * PAGE_SIZE)
>
> diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
> index f780b467e75d7..09533d46ef033 100644
> --- a/arch/sh/include/asm/page.h
> +++ b/arch/sh/include/asm/page.h
> @@ -162,5 +162,6 @@ typedef struct page *pgtable_t;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* __ASM_SH_PAGE_H */
> diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h
> index 5e44cdf2a8f2b..4327fe2bfa010 100644
> --- a/arch/sparc/include/asm/page.h
> +++ b/arch/sparc/include/asm/page.h
> @@ -9,4 +9,7 @@
> #else
> #include <asm/page_32.h>
> #endif
> +
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif
> diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
> index 9ef9a8aedfa66..f26011808f514 100644
> --- a/arch/um/include/asm/page.h
> +++ b/arch/um/include/asm/page.h
> @@ -119,4 +119,6 @@ extern unsigned long uml_physmem;
> #define __HAVE_ARCH_GATE_AREA 1
> #endif
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __UM_PAGE_H */
> diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
> index 52f1b4ff0cc16..6d2381342047f 100644
> --- a/arch/x86/include/asm/page_types.h
> +++ b/arch/x86/include/asm/page_types.h
> @@ -71,4 +71,6 @@ extern void initmem_init(void);
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_X86_PAGE_DEFS_H */
> diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
> index 4db56ef052d22..86952cb32af23 100644
> --- a/arch/xtensa/include/asm/page.h
> +++ b/arch/xtensa/include/asm/page.h
> @@ -200,4 +200,5 @@ static inline unsigned long ___pa(unsigned long va)
> #endif /* __ASSEMBLY__ */
>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
> #endif /* _XTENSA_PAGE_H */
> diff --git a/include/asm-generic/pgtable-geometry.h b/include/asm-generic/pgtable-geometry.h
> new file mode 100644
> index 0000000000000..358e729a6ac37
> --- /dev/null
> +++ b/include/asm-generic/pgtable-geometry.h
> @@ -0,0 +1,71 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef ASM_GENERIC_PGTABLE_GEOMETRY_H
> +#define ASM_GENERIC_PGTABLE_GEOMETRY_H
> +
> +#if defined(PAGE_SHIFT_MAX) && defined(PAGE_SIZE_MAX) && defined(PAGE_MASK_MAX) && \
> + defined(PAGE_SHIFT_MIN) && defined(PAGE_SIZE_MIN) && defined(PAGE_MASK_MIN)
> +/* Arch supports boot-time page size selection. */
> +#elif defined(PAGE_SHIFT_MAX) || defined(PAGE_SIZE_MAX) || defined(PAGE_MASK_MAX) || \
> + defined(PAGE_SHIFT_MIN) || defined(PAGE_SIZE_MIN) || defined(PAGE_MASK_MIN)
> +#error Arch must define all or none of the boot-time page size macros
> +#else
> +/* Arch does not support boot-time page size selection. */
> +#define PAGE_SHIFT_MIN PAGE_SHIFT
> +#define PAGE_SIZE_MIN PAGE_SIZE
> +#define PAGE_MASK_MIN PAGE_MASK
> +#define PAGE_SHIFT_MAX PAGE_SHIFT
> +#define PAGE_SIZE_MAX PAGE_SIZE
> +#define PAGE_MASK_MAX PAGE_MASK
> +#endif
> +
> +/*
> + * Define a global variable (scalar or struct), whose value is derived from
> + * PAGE_SIZE and friends. When PAGE_SIZE is a compile-time constant, the global
> + * variable is simply defined with the static value. When PAGE_SIZE is
> + * determined at boot-time, a pure initcall is registered and run during boot to
> + * initialize the variable.
> + *
> + * @type: Unqualified type. Do not include "const"; implied by macro variant.
> + * @name: Variable name.
> + * @...: Initialization value. May be scalar or initializer.
> + *
> + * "static" is declared by placing "static" before the macro.
> + *
> + * Example:
> + *
> + * struct my_struct {
> + * int a;
> + * char b;
> + * };
> + *
> + * static DEFINE_GLOBAL_PAGE_SIZE_VAR(struct my_struct, my_variable, {
> + * .a = 10,
> + * .b = 'e',
> + * });
> + */
> +#if PAGE_SIZE_MIN != PAGE_SIZE_MAX
> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
> + type name attrib; \
> + static int __init __attribute__((constructor)) __##name##_init(void) \
> + { \
> + name = (type)__VA_ARGS__; \
> + return 0; \
> + }
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, __ro_after_init, __VA_ARGS__)
> +#else /* PAGE_SIZE_MIN == PAGE_SIZE_MAX */
> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
> + type name attrib = __VA_ARGS__; \
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(const type, name, , __VA_ARGS__)
> +#endif
> +
> +#endif /* ASM_GENERIC_PGTABLE_GEOMETRY_H */
> diff --git a/init/main.c b/init/main.c
> index 206acdde51f5a..ba1515eb20b9d 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -899,6 +899,8 @@ static void __init early_numa_node_init(void)
> #endif
> }
>
> +static __init void do_ctors(void);
> +
> asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
> void start_kernel(void)
> {
> @@ -910,6 +912,8 @@ void start_kernel(void)
> debug_objects_early_init();
> init_vmlinux_build_id();
>
> + do_ctors();
> +
> cgroup_init_early();
>
> local_irq_disable();
> @@ -1360,7 +1364,6 @@ static void __init do_basic_setup(void)
> cpuset_init_smp();
> driver_init();
> init_irq_proc();
> - do_ctors();
> do_initcalls();
> }
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection
2024-10-14 10:58 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Ryan Roberts
` (4 preceding siblings ...)
2024-10-16 14:36 ` Ryan Roberts
@ 2024-10-30 8:45 ` Ryan Roberts
5 siblings, 0 replies; 13+ messages in thread
From: Ryan Roberts @ 2024-10-30 8:45 UTC (permalink / raw)
To: David S. Miller, James E.J. Bottomley, Andreas Larsson,
Andrew Morton, Anshuman Khandual, Anton Ivanov, Ard Biesheuvel,
Arnd Bergmann, Borislav Petkov, Catalin Marinas, Chris Zankel,
Dave Hansen, David Hildenbrand, Dinh Nguyen, Geert Uytterhoeven,
Greg Marsden, Helge Deller, Huacai Chen, Ingo Molnar, Ivan Ivanov,
Johannes Berg, John Paul Adrian Glaubitz, Jonas Bonn,
Kalesh Singh, Marc Zyngier, Mark Rutland, Matthias Brugger,
Max Filippov, Miroslav Benes, Rich Felker, Richard Weinberger,
Stafford Horne, Stefan Kristiansson, Thomas Bogendoerfer,
Thomas Gleixner, Will Deacon, Yoshinori Sato, x86
Cc: linux-alpha, linux-arch, linux-arm-kernel, linux-csky,
linux-hexagon, linux-kernel, linux-m68k, linux-mips, linux-mm,
linux-openrisc, linux-parisc, linux-riscv, linux-s390, linux-sh,
linux-snps-arc, linux-um, linuxppc-dev, loongarch, sparclinux
Hi all (especially mm people!),
On 14/10/2024 11:58, Ryan Roberts wrote:
> arm64 can support multiple base page sizes. Instead of selecting a page
> size at compile time, as is done today, we will make it possible to
> select the desired page size on the command line.
>
> In this case PAGE_SHIFT and it's derivatives, PAGE_SIZE and PAGE_MASK
> (as well as a number of other macros related to or derived from
> PAGE_SHIFT, but I'm not worrying about those yet), are no longer
> compile-time constants. So the code base needs to cope with that.
>
> As a first step, introduce MIN and MAX variants of these macros, which
> express the range of possible page sizes. These are always compile-time
> constants and can be used in many places where PAGE_[SHIFT|SIZE|MASK]
> were previously used where a compile-time constant is required.
> (Subsequent patches will do that conversion work). When the arch/build
> doesn't support boot-time page size selection, the MIN and MAX variants
> are equal and everything resolves as it did previously.
>
> Additionally, introduce DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() which wrap
> global variable defintions so that for boot-time page size selection
> builds, the variable being wrapped is initialized at boot-time, instead
> of compile-time. This is done by defining a function to do the
> assignment, which has the "constructor" attribute. Constructor is
> preferred over initcall, because when compiling a module, the module is
> limited to a single initcall but constructors are unlimited. For
> built-in code, constructors are now called earlier to guarrantee that
> the variables are initialized by the time they are used. Any arch that
> wants to enable boot-time page size selection will need to select
> CONFIG_CONSTRUCTORS.
>
> These new macros need to be available anywhere PAGE_SHIFT and friends
> are available. Those are defined via asm/page.h (although some arches
> have a sub-include that defines them). Unfortunately there is no
> reliable asm-generic header we can easily piggy-back on, so let's define
> a new one, pgtable-geometry.h, which we include near where each arch
> defines PAGE_SHIFT. Ugh.
I haven't had any feedback on this particular patch yet. It would be great to
get this one into v6.13, since once this is in place, the changes in other
subsystems can go via their respective trees without any dependency issues.
Although time is getting tight.
If anyone has any feedback for this patch it would be great to hear it now. Then
I'll re-post on it's own in a couple of days time.
Thanks,
Ryan
>
> -------
>
> Most of the problems that need to be solved over the next few patches
> fall into these broad categories, which are all solved with the help of
> these new macros:
>
> 1. Assignment of values derived from PAGE_SIZE in global variables
>
> For boot-time page size builds, we must defer the initialization of
> these variables until boot-time, when the page size is known. See
> DEFINE_GLOBAL_PAGE_SIZE_VAR[_CONST]() as described above.
>
> 2. Define static storage in units related to PAGE_SIZE
>
> This static storage will be defined according to PAGE_SIZE_MAX.
>
> 3. Define size of struct so that it is related to PAGE_SIZE
>
> The struct often contains an array that is sized to fill the page. In
> this case, use a flexible array with dynamic allocation. In other
> cases, the struct fits exactly over a page, which is a header (e.g.
> swap file header). In this case, remove the padding, and manually
> determine the struct pointer within the page.
>
> 4. BUILD_BUG_ON() with values derived from PAGE_SIZE
>
> In most cases, we can change these to compare againt the appropriate
> limit (either MIN or MAX). In other cases, we must change these to
> run-time BUG_ON().
>
> 5. Ensure page alignment of static data structures
>
> Align instead to PAGE_SIZE_MAX.
>
> 6. #ifdeffery based on PAGE_SIZE
>
> Often these can be changed to c code constructs. e.g. a macro that
> returns a different value depending on page size can be changed to use
> the ternary operator and the compiler will dead code strip it for the
> compile-time constant case and runtime evaluate it for the non-const
> case. Or #if/#else/#endif within a function can be converted to c
> if/else blocks, which are also dead code stripped for the const case.
> Sometimes we can change the c-preprocessor logic to use the
> appropriate MIN/MAX limit.
>
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>
> ***NOTE***
> Any confused maintainers may want to read the cover note here for context:
> https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/
>
> arch/alpha/include/asm/page.h | 1 +
> arch/arc/include/asm/page.h | 1 +
> arch/arm/include/asm/page.h | 1 +
> arch/arm64/include/asm/page-def.h | 2 +
> arch/csky/include/asm/page.h | 3 ++
> arch/hexagon/include/asm/page.h | 2 +
> arch/loongarch/include/asm/page.h | 2 +
> arch/m68k/include/asm/page.h | 1 +
> arch/microblaze/include/asm/page.h | 1 +
> arch/mips/include/asm/page.h | 1 +
> arch/nios2/include/asm/page.h | 2 +
> arch/openrisc/include/asm/page.h | 1 +
> arch/parisc/include/asm/page.h | 1 +
> arch/powerpc/include/asm/page.h | 2 +
> arch/riscv/include/asm/page.h | 1 +
> arch/s390/include/asm/page.h | 1 +
> arch/sh/include/asm/page.h | 1 +
> arch/sparc/include/asm/page.h | 3 ++
> arch/um/include/asm/page.h | 2 +
> arch/x86/include/asm/page_types.h | 2 +
> arch/xtensa/include/asm/page.h | 1 +
> include/asm-generic/pgtable-geometry.h | 71 ++++++++++++++++++++++++++
> init/main.c | 5 +-
> 23 files changed, 107 insertions(+), 1 deletion(-)
> create mode 100644 include/asm-generic/pgtable-geometry.h
>
> diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
> index 70419e6be1a35..d0096fb5521b8 100644
> --- a/arch/alpha/include/asm/page.h
> +++ b/arch/alpha/include/asm/page.h
> @@ -88,5 +88,6 @@ typedef struct page *pgtable_t;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ALPHA_PAGE_H */
> diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
> index def0dfb95b436..8d56549db7a33 100644
> --- a/arch/arc/include/asm/page.h
> +++ b/arch/arc/include/asm/page.h
> @@ -6,6 +6,7 @@
> #define __ASM_ARC_PAGE_H
>
> #include <uapi/asm/page.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #ifdef CONFIG_ARC_HAS_PAE40
>
> diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
> index 62af9f7f9e963..417aa8533c718 100644
> --- a/arch/arm/include/asm/page.h
> +++ b/arch/arm/include/asm/page.h
> @@ -191,5 +191,6 @@ extern int pfn_valid(unsigned long);
>
> #include <asm-generic/getorder.h>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif
> diff --git a/arch/arm64/include/asm/page-def.h b/arch/arm64/include/asm/page-def.h
> index 792e9fe881dcf..d69971cf49cd2 100644
> --- a/arch/arm64/include/asm/page-def.h
> +++ b/arch/arm64/include/asm/page-def.h
> @@ -15,4 +15,6 @@
> #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
> #define PAGE_MASK (~(PAGE_SIZE-1))
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __ASM_PAGE_DEF_H */
> diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h
> index 0ca6c408c07f2..95173d57adc8b 100644
> --- a/arch/csky/include/asm/page.h
> +++ b/arch/csky/include/asm/page.h
> @@ -92,4 +92,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
> #include <asm-generic/getorder.h>
>
> #endif /* !__ASSEMBLY__ */
> +
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __ASM_CSKY_PAGE_H */
> diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h
> index 8a6af57274c2d..ba7ad5231695f 100644
> --- a/arch/hexagon/include/asm/page.h
> +++ b/arch/hexagon/include/asm/page.h
> @@ -139,4 +139,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
> #endif /* ifdef __ASSEMBLY__ */
> #endif /* ifdef __KERNEL__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif
> diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
> index e85df33f11c77..9862e8fb047a6 100644
> --- a/arch/loongarch/include/asm/page.h
> +++ b/arch/loongarch/include/asm/page.h
> @@ -123,4 +123,6 @@ extern int __virt_addr_valid(volatile void *kaddr);
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_PAGE_H */
> diff --git a/arch/m68k/include/asm/page.h b/arch/m68k/include/asm/page.h
> index 8cfb84b499751..4df4681b02194 100644
> --- a/arch/m68k/include/asm/page.h
> +++ b/arch/m68k/include/asm/page.h
> @@ -60,5 +60,6 @@ extern unsigned long _ramend;
>
> #include <asm-generic/getorder.h>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _M68K_PAGE_H */
> diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
> index 8810f4f1c3b02..abc23c3d743bd 100644
> --- a/arch/microblaze/include/asm/page.h
> +++ b/arch/microblaze/include/asm/page.h
> @@ -142,5 +142,6 @@ static inline const void *pfn_to_virt(unsigned long pfn)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_MICROBLAZE_PAGE_H */
> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
> index 4609cb0326cf3..3d91021538f02 100644
> --- a/arch/mips/include/asm/page.h
> +++ b/arch/mips/include/asm/page.h
> @@ -227,5 +227,6 @@ static inline unsigned long kaslr_offset(void)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_PAGE_H */
> diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h
> index 0722f88e63cc7..2e5f93beb42b7 100644
> --- a/arch/nios2/include/asm/page.h
> +++ b/arch/nios2/include/asm/page.h
> @@ -97,4 +97,6 @@ extern struct page *mem_map;
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_NIOS2_PAGE_H */
> diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h
> index 1d5913f67c312..a0da2a9842241 100644
> --- a/arch/openrisc/include/asm/page.h
> +++ b/arch/openrisc/include/asm/page.h
> @@ -88,5 +88,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* __ASM_OPENRISC_PAGE_H */
> diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
> index 4bea2e95798f0..2a75496237c09 100644
> --- a/arch/parisc/include/asm/page.h
> +++ b/arch/parisc/include/asm/page.h
> @@ -173,6 +173,7 @@ extern int npmem_ranges;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
> #include <asm/pdc.h>
>
> #define PAGE0 ((struct zeropage *)absolute_pointer(__PAGE_OFFSET))
> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
> index 83d0a4fc5f755..4601c115b6485 100644
> --- a/arch/powerpc/include/asm/page.h
> +++ b/arch/powerpc/include/asm/page.h
> @@ -300,4 +300,6 @@ static inline unsigned long kaslr_offset(void)
> #include <asm-generic/memory_model.h>
> #endif /* __ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_POWERPC_PAGE_H */
> diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
> index 7ede2111c5917..e5af7579e45bf 100644
> --- a/arch/riscv/include/asm/page.h
> +++ b/arch/riscv/include/asm/page.h
> @@ -204,5 +204,6 @@ static __always_inline void *pfn_to_kaddr(unsigned long pfn)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* _ASM_RISCV_PAGE_H */
> diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
> index 16e4caa931f1f..42157e7690a77 100644
> --- a/arch/s390/include/asm/page.h
> +++ b/arch/s390/include/asm/page.h
> @@ -275,6 +275,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #define AMODE31_SIZE (3 * PAGE_SIZE)
>
> diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
> index f780b467e75d7..09533d46ef033 100644
> --- a/arch/sh/include/asm/page.h
> +++ b/arch/sh/include/asm/page.h
> @@ -162,5 +162,6 @@ typedef struct page *pgtable_t;
>
> #include <asm-generic/memory_model.h>
> #include <asm-generic/getorder.h>
> +#include <asm-generic/pgtable-geometry.h>
>
> #endif /* __ASM_SH_PAGE_H */
> diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h
> index 5e44cdf2a8f2b..4327fe2bfa010 100644
> --- a/arch/sparc/include/asm/page.h
> +++ b/arch/sparc/include/asm/page.h
> @@ -9,4 +9,7 @@
> #else
> #include <asm/page_32.h>
> #endif
> +
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif
> diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
> index 9ef9a8aedfa66..f26011808f514 100644
> --- a/arch/um/include/asm/page.h
> +++ b/arch/um/include/asm/page.h
> @@ -119,4 +119,6 @@ extern unsigned long uml_physmem;
> #define __HAVE_ARCH_GATE_AREA 1
> #endif
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* __UM_PAGE_H */
> diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
> index 52f1b4ff0cc16..6d2381342047f 100644
> --- a/arch/x86/include/asm/page_types.h
> +++ b/arch/x86/include/asm/page_types.h
> @@ -71,4 +71,6 @@ extern void initmem_init(void);
>
> #endif /* !__ASSEMBLY__ */
>
> +#include <asm-generic/pgtable-geometry.h>
> +
> #endif /* _ASM_X86_PAGE_DEFS_H */
> diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
> index 4db56ef052d22..86952cb32af23 100644
> --- a/arch/xtensa/include/asm/page.h
> +++ b/arch/xtensa/include/asm/page.h
> @@ -200,4 +200,5 @@ static inline unsigned long ___pa(unsigned long va)
> #endif /* __ASSEMBLY__ */
>
> #include <asm-generic/memory_model.h>
> +#include <asm-generic/pgtable-geometry.h>
> #endif /* _XTENSA_PAGE_H */
> diff --git a/include/asm-generic/pgtable-geometry.h b/include/asm-generic/pgtable-geometry.h
> new file mode 100644
> index 0000000000000..358e729a6ac37
> --- /dev/null
> +++ b/include/asm-generic/pgtable-geometry.h
> @@ -0,0 +1,71 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef ASM_GENERIC_PGTABLE_GEOMETRY_H
> +#define ASM_GENERIC_PGTABLE_GEOMETRY_H
> +
> +#if defined(PAGE_SHIFT_MAX) && defined(PAGE_SIZE_MAX) && defined(PAGE_MASK_MAX) && \
> + defined(PAGE_SHIFT_MIN) && defined(PAGE_SIZE_MIN) && defined(PAGE_MASK_MIN)
> +/* Arch supports boot-time page size selection. */
> +#elif defined(PAGE_SHIFT_MAX) || defined(PAGE_SIZE_MAX) || defined(PAGE_MASK_MAX) || \
> + defined(PAGE_SHIFT_MIN) || defined(PAGE_SIZE_MIN) || defined(PAGE_MASK_MIN)
> +#error Arch must define all or none of the boot-time page size macros
> +#else
> +/* Arch does not support boot-time page size selection. */
> +#define PAGE_SHIFT_MIN PAGE_SHIFT
> +#define PAGE_SIZE_MIN PAGE_SIZE
> +#define PAGE_MASK_MIN PAGE_MASK
> +#define PAGE_SHIFT_MAX PAGE_SHIFT
> +#define PAGE_SIZE_MAX PAGE_SIZE
> +#define PAGE_MASK_MAX PAGE_MASK
> +#endif
> +
> +/*
> + * Define a global variable (scalar or struct), whose value is derived from
> + * PAGE_SIZE and friends. When PAGE_SIZE is a compile-time constant, the global
> + * variable is simply defined with the static value. When PAGE_SIZE is
> + * determined at boot-time, a pure initcall is registered and run during boot to
> + * initialize the variable.
> + *
> + * @type: Unqualified type. Do not include "const"; implied by macro variant.
> + * @name: Variable name.
> + * @...: Initialization value. May be scalar or initializer.
> + *
> + * "static" is declared by placing "static" before the macro.
> + *
> + * Example:
> + *
> + * struct my_struct {
> + * int a;
> + * char b;
> + * };
> + *
> + * static DEFINE_GLOBAL_PAGE_SIZE_VAR(struct my_struct, my_variable, {
> + * .a = 10,
> + * .b = 'e',
> + * });
> + */
> +#if PAGE_SIZE_MIN != PAGE_SIZE_MAX
> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
> + type name attrib; \
> + static int __init __attribute__((constructor)) __##name##_init(void) \
> + { \
> + name = (type)__VA_ARGS__; \
> + return 0; \
> + }
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, __ro_after_init, __VA_ARGS__)
> +#else /* PAGE_SIZE_MIN == PAGE_SIZE_MAX */
> +#define __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, attrib, ...) \
> + type name attrib = __VA_ARGS__; \
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(type, name, , __VA_ARGS__)
> +
> +#define DEFINE_GLOBAL_PAGE_SIZE_VAR_CONST(type, name, ...) \
> + __DEFINE_GLOBAL_PAGE_SIZE_VAR(const type, name, , __VA_ARGS__)
> +#endif
> +
> +#endif /* ASM_GENERIC_PGTABLE_GEOMETRY_H */
> diff --git a/init/main.c b/init/main.c
> index 206acdde51f5a..ba1515eb20b9d 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -899,6 +899,8 @@ static void __init early_numa_node_init(void)
> #endif
> }
>
> +static __init void do_ctors(void);
> +
> asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
> void start_kernel(void)
> {
> @@ -910,6 +912,8 @@ void start_kernel(void)
> debug_objects_early_init();
> init_vmlinux_build_id();
>
> + do_ctors();
> +
> cgroup_init_early();
>
> local_irq_disable();
> @@ -1360,7 +1364,6 @@ static void __init do_basic_setup(void)
> cpuset_init_smp();
> driver_init();
> init_irq_proc();
> - do_ctors();
> do_initcalls();
> }
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v1 11/57] fork: Permit boot-time THREAD_SIZE determination
2024-10-14 10:58 ` [RFC PATCH v1 11/57] fork: Permit boot-time THREAD_SIZE determination Ryan Roberts
@ 2024-11-14 10:42 ` Vlastimil Babka
0 siblings, 0 replies; 13+ messages in thread
From: Vlastimil Babka @ 2024-11-14 10:42 UTC (permalink / raw)
To: Ryan Roberts, Andrew Morton, Andrey Ryabinin, Anshuman Khandual,
Ard Biesheuvel, Arnd Bergmann, Catalin Marinas, David Hildenbrand,
Greg Marsden, Ingo Molnar, Ivan Ivanov, Juri Lelli, Kalesh Singh,
Marc Zyngier, Mark Rutland, Matthias Brugger, Miroslav Benes,
Peter Zijlstra, Vincent Guittot, Will Deacon
Cc: kasan-dev, linux-arch, linux-arm-kernel, linux-kernel, linux-mm
On 10/14/24 12:58, Ryan Roberts wrote:
> THREAD_SIZE defines the size of a kernel thread stack. To date, it has
> been set at compile-time. However, when using vmap stacks, the size must
> be a multiple of PAGE_SIZE, and given we are in the process of
> supporting boot-time page size, we must also do the same for
> THREAD_SIZE.
>
> The alternative would be to define THREAD_SIZE for the largest supported
> page size, but this would waste memory when using a smaller page size.
> For example, arm64 requires THREAD_SIZE to be 16K, but when using 64K
> pages and a vmap stack, we must increase the size to 64K. If we required
> 64K when 4K or 16K page size was in use, we would waste 48K per kernel
> thread.
>
> So let's refactor to allow THREAD_SIZE to not be a compile-time
> constant. THREAD_SIZE_MAX (and THREAD_ALIGN_MAX) are introduced to
> manage the limits, as is done for PAGE_SIZE.
>
> When THREAD_SIZE is a compile-time constant, behaviour and code size
> should be equivalent.
>
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2024-11-14 10:42 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20241014105514.3206191-1-ryan.roberts@arm.com>
2024-10-14 10:58 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Ryan Roberts
2024-10-14 10:58 ` [RFC PATCH v1 02/57] vmlinux: Align to PAGE_SIZE_MAX Ryan Roberts
2024-10-14 16:50 ` Christoph Lameter (Ampere)
2024-10-15 10:53 ` Ryan Roberts
2024-10-14 10:58 ` [RFC PATCH v1 11/57] fork: Permit boot-time THREAD_SIZE determination Ryan Roberts
2024-11-14 10:42 ` Vlastimil Babka
2024-10-14 10:59 ` [RFC PATCH v1 53/57] arm64: Runtime-fold pmd level Ryan Roberts
2024-10-14 13:54 ` [RFC PATCH v1 01/57] mm: Add macros ahead of supporting boot-time page size selection Pingfan Liu
2024-10-14 14:07 ` Ryan Roberts
2024-10-15 3:04 ` Pingfan Liu
2024-10-15 11:16 ` Ryan Roberts
2024-10-16 14:36 ` Ryan Roberts
2024-10-30 8:45 ` Ryan Roberts
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox