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

s390/mm: Add configurable STRICT_MM_TYPECHECKS

Add support for configurable STRICT_MM_TYPECHECKS. The s390 ABI defines
that return values with complex types like structures and unions are
returned in a return value buffer allocated by the caller. This is also
true for small structures and unions which would fit into a register. On
the other hand when such types are passed as arguments to functions they
are passed in registers, if they are small enough.
This leads to inefficient code when such a return value of a function call
is then passed as argument to a subsequent function call.

This is especially true for all mm types, like pte_t and others, which are
only for type checking reasons defined as a structure. This however can be
bypassed with the STRICT_MM_TYPECHECKS feature, which is used by a few
other architectures, which seem to have the same problem.

Add CONFIG_STRICT_MM_TYPECHECKS which can be used to change the type of
pte_t and other structures. If the config option is not enabled the types
are defined to unsigned long, allowing for better code generation, however
there is no type checking anymore. If it is enabled the types are
structures like before so that type checking is performed, but less
efficient code is generated.

The option is always enabled in debug_defconfig, and for convenience an
mmtypes.config topic target is added, which allows to easily enable it, in
case memory management code is changed.

CONFIG_STRICT_MM_TYPECHECKS and STRICT_MM_TYPECHECKS are kept separate,
since STRICT_MM_TYPECHECKS is common across architectures and common
code. Therefore use the same define also for s390 code.

Add CONFIG_STRICT_MM_TYPECHECKS to make it build time configurable.

Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

authored by

Heiko Carstens and committed by
Vasily Gorbik
03544866 94d553ce

+51 -38
+10
arch/s390/Kconfig.debug
··· 13 13 14 14 If unsure, say N. 15 15 16 + config STRICT_MM_TYPECHECKS 17 + bool "Strict Memory Management Type Checks" 18 + depends on DEBUG_KERNEL 19 + help 20 + Enable strict type checking for memory management types like pte_t 21 + and pmd_t. This generates slightly worse code and should be used 22 + for debug builds. 23 + 24 + If unsure, say N. 25 + 16 26 config CIO_INJECT 17 27 bool "CIO Inject interfaces" 18 28 depends on DEBUG_KERNEL && DEBUG_FS
+1
arch/s390/configs/debug_defconfig
··· 893 893 CONFIG_SAMPLE_FTRACE_DIRECT_MULTI=m 894 894 CONFIG_SAMPLE_FTRACE_OPS=m 895 895 CONFIG_DEBUG_ENTRY=y 896 + CONFIG_STRICT_MM_TYPECHECKS=y 896 897 CONFIG_CIO_INJECT=y 897 898 CONFIG_KUNIT=m 898 899 CONFIG_KUNIT_DEBUGFS=y
+2
arch/s390/configs/mmtypes.config
··· 1 + # Help: Enable strict memory management typechecks 2 + CONFIG_STRICT_MM_TYPECHECKS=y
+38 -38
arch/s390/include/asm/page.h
··· 71 71 #define vma_alloc_zeroed_movable_folio(vma, vaddr) \ 72 72 vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr) 73 73 74 - /* 75 - * These are used to make use of C type-checking.. 76 - */ 74 + #ifdef CONFIG_STRICT_MM_TYPECHECKS 75 + #define STRICT_MM_TYPECHECKS 76 + #endif 77 + 78 + #ifdef STRICT_MM_TYPECHECKS 77 79 78 80 typedef struct { unsigned long pgprot; } pgprot_t; 79 81 typedef struct { unsigned long pgste; } pgste_t; ··· 84 82 typedef struct { unsigned long pud; } pud_t; 85 83 typedef struct { unsigned long p4d; } p4d_t; 86 84 typedef struct { unsigned long pgd; } pgd_t; 85 + 86 + #define DEFINE_PGVAL_FUNC(name) \ 87 + static __always_inline unsigned long name ## _val(name ## _t name) \ 88 + { \ 89 + return name.name; \ 90 + } 91 + 92 + #else /* STRICT_MM_TYPECHECKS */ 93 + 94 + typedef unsigned long pgprot_t; 95 + typedef unsigned long pgste_t; 96 + typedef unsigned long pte_t; 97 + typedef unsigned long pmd_t; 98 + typedef unsigned long pud_t; 99 + typedef unsigned long p4d_t; 100 + typedef unsigned long pgd_t; 101 + 102 + #define DEFINE_PGVAL_FUNC(name) \ 103 + static __always_inline unsigned long name ## _val(name ## _t name) \ 104 + { \ 105 + return name; \ 106 + } 107 + 108 + #endif /* STRICT_MM_TYPECHECKS */ 109 + 110 + DEFINE_PGVAL_FUNC(pgprot) 111 + DEFINE_PGVAL_FUNC(pgste) 112 + DEFINE_PGVAL_FUNC(pte) 113 + DEFINE_PGVAL_FUNC(pmd) 114 + DEFINE_PGVAL_FUNC(pud) 115 + DEFINE_PGVAL_FUNC(p4d) 116 + DEFINE_PGVAL_FUNC(pgd) 117 + 87 118 typedef pte_t *pgtable_t; 88 - 89 - static inline unsigned long pgprot_val(pgprot_t pgprot) 90 - { 91 - return pgprot.pgprot; 92 - } 93 - 94 - static inline unsigned long pgste_val(pgste_t pgste) 95 - { 96 - return pgste.pgste; 97 - } 98 - 99 - static inline unsigned long pte_val(pte_t pte) 100 - { 101 - return pte.pte; 102 - } 103 - 104 - static inline unsigned long pmd_val(pmd_t pmd) 105 - { 106 - return pmd.pmd; 107 - } 108 - 109 - static inline unsigned long pud_val(pud_t pud) 110 - { 111 - return pud.pud; 112 - } 113 - 114 - static inline unsigned long p4d_val(p4d_t p4d) 115 - { 116 - return p4d.p4d; 117 - } 118 - 119 - static inline unsigned long pgd_val(pgd_t pgd) 120 - { 121 - return pgd.pgd; 122 - } 123 119 124 120 #define __pgprot(x) ((pgprot_t) { (x) } ) 125 121 #define __pgste(x) ((pgste_t) { (x) } )