Commit 5983ab16 authored by Vasily Gorbik's avatar Vasily Gorbik
Browse files

Merge branch 'strict-mm-typechecks-support' into features

Heiko writes:

"The recent large kernel Rust thread where Linus commented about that
structures may be returned in registers [1] made me again aware that this
is not true for s390 where the ABI defines that structures are returned in
a return value buffer allocated by the caller. This was also mentioned by
Alexander Gordeev a couple of weeks ago.

In theory the -freg-struct-return compiler flag would allow to return small
structures in registers, however that has not been implemented for
s390. Juergen Christ did an experimental gcc implementation which shows the
benefit of such a change (bloat-o-meter):

add/remove: 3/2 grow/shrink: 12/441 up/down: 740/-7182 (-6442)

This result is not very impressive, and doesn't seem to justify a new ABI
for the kernel.

However there is still the existing STRICT_MM_TYPECHECKS which can be used
to change some mm types from structures to simple scalar types. Changing
the mm types results in:

add/remove: 2/8 grow/shrink: 25/116 up/down: 3902/-6204 (-2302)

Which is already a third of the possible savings which would be the result
of the described ABI change.

Therefore add support for a configurable STRICT_MM_TYPECHECKS which allows
to generate better code, but also allows to have type checking for debug
builds."

[1] https://lore.kernel.org/all/CAHk-=wgb1g9VVHRaAnJjrfRFWAOVT2ouNOMqt0js8h3D6zvHDw@mail.gmail.com/



* strict-mm-typechecks-support:
  s390/mm: Add configurable STRICT_MM_TYPECHECKS
  s390/mm: Convert pgste_val() into function
  s390/mm: Convert pgprot_val() into function
  s390/mm: Use pgprot_val() instead of open coding

Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parents 8751b6e9 03544866
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -13,6 +13,16 @@ config DEBUG_ENTRY

	  If unsure, say N.

config STRICT_MM_TYPECHECKS
	bool "Strict Memory Management Type Checks"
	depends on DEBUG_KERNEL
	help
	  Enable strict type checking for memory management types like pte_t
	  and pmd_t. This generates slightly worse code and should be used
	  for debug builds.

	  If unsure, say N.

config CIO_INJECT
	bool "CIO Inject interfaces"
	depends on DEBUG_KERNEL && DEBUG_FS
+1 −0
Original line number Diff line number Diff line
@@ -894,6 +894,7 @@ CONFIG_SAMPLE_FTRACE_DIRECT=m
CONFIG_SAMPLE_FTRACE_DIRECT_MULTI=m
CONFIG_SAMPLE_FTRACE_OPS=m
CONFIG_DEBUG_ENTRY=y
CONFIG_STRICT_MM_TYPECHECKS=y
CONFIG_CIO_INJECT=y
CONFIG_KUNIT=m
CONFIG_KUNIT_DEBUGFS=y
+2 −0
Original line number Diff line number Diff line
# Help: Enable strict memory management typechecks
CONFIG_STRICT_MM_TYPECHECKS=y
+33 −26
Original line number Diff line number Diff line
@@ -71,9 +71,11 @@ static inline void copy_page(void *to, void *from)
#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)

/*
 * These are used to make use of C type-checking..
 */
#ifdef CONFIG_STRICT_MM_TYPECHECKS
#define STRICT_MM_TYPECHECKS
#endif

#ifdef STRICT_MM_TYPECHECKS

typedef struct { unsigned long pgprot; } pgprot_t;
typedef struct { unsigned long pgste; } pgste_t;
@@ -82,43 +84,48 @@ typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pud; } pud_t;
typedef struct { unsigned long p4d; } p4d_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef pte_t *pgtable_t;

#define pgprot_val(x)	((x).pgprot)
#define pgste_val(x)	((x).pgste)

static inline unsigned long pte_val(pte_t pte)
{
	return pte.pte;
#define DEFINE_PGVAL_FUNC(name)						\
static __always_inline unsigned long name ## _val(name ## _t name)	\
{									\
	return name.name;						\
}

static inline unsigned long pmd_val(pmd_t pmd)
{
	return pmd.pmd;
}
#else /* STRICT_MM_TYPECHECKS */

static inline unsigned long pud_val(pud_t pud)
{
	return pud.pud;
}
typedef unsigned long pgprot_t;
typedef unsigned long pgste_t;
typedef unsigned long pte_t;
typedef unsigned long pmd_t;
typedef unsigned long pud_t;
typedef unsigned long p4d_t;
typedef unsigned long pgd_t;

static inline unsigned long p4d_val(p4d_t p4d)
{
	return p4d.p4d;
#define DEFINE_PGVAL_FUNC(name)						\
static __always_inline unsigned long name ## _val(name ## _t name)	\
{									\
	return name;							\
}

static inline unsigned long pgd_val(pgd_t pgd)
{
	return pgd.pgd;
}
#endif /* STRICT_MM_TYPECHECKS */

DEFINE_PGVAL_FUNC(pgprot)
DEFINE_PGVAL_FUNC(pgste)
DEFINE_PGVAL_FUNC(pte)
DEFINE_PGVAL_FUNC(pmd)
DEFINE_PGVAL_FUNC(pud)
DEFINE_PGVAL_FUNC(p4d)
DEFINE_PGVAL_FUNC(pgd)

typedef pte_t *pgtable_t;

#define __pgprot(x)	((pgprot_t) { (x) } )
#define __pgste(x)	((pgste_t) { (x) } )
#define __pte(x)        ((pte_t) { (x) } )
#define __pmd(x)        ((pmd_t) { (x) } )
#define __pud(x)	((pud_t) { (x) } )
#define __p4d(x)	((p4d_t) { (x) } )
#define __pgd(x)        ((pgd_t) { (x) } )
#define __pgprot(x)     ((pgprot_t) { (x) } )

static inline void page_set_storage_key(unsigned long addr,
					unsigned char skey, int mapped)
+10 −0
Original line number Diff line number Diff line
@@ -593,6 +593,16 @@ static inline int mm_alloc_pgste(struct mm_struct *mm)
	return 0;
}

static inline pgste_t clear_pgste_bit(pgste_t pgste, unsigned long mask)
{
	return __pgste(pgste_val(pgste) & ~mask);
}

static inline pgste_t set_pgste_bit(pgste_t pgste, unsigned long mask)
{
	return __pgste(pgste_val(pgste) | mask);
}

static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
{
	return __pte(pte_val(pte) & ~pgprot_val(prot));
Loading