s390/set_memory: add __set_memory() variant
authorHeiko Carstens <hca@linux.ibm.com>
Fri, 25 Aug 2023 12:29:52 +0000 (14:29 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 30 Aug 2023 09:03:28 +0000 (11:03 +0200)
Add a __set_memory_yy() variant for all set_memory_yy()
implementations. The new variant takes start and end void pointers,
which allows them to be used without the usual unsigned long cast.

However more important: the new variant can be used for areas larger
than 8TB. The old variant comes with an "int numpages" parameter, which
overflows with more than 8TB. Given that for debug_pagealloc
set_memory_4k() is used on the whole kernel mapping this is not only a
theoretical problem, but must be fixed.

Changing all set_memory_yy() variants only on s390 to take an "unsigned
long numpages" parameter is not possible, since the common module code
requires an int parameter from all architectures on these functions.
See module_set_memory().

Therefore change/fix this on s390 only with a new interface, and address
common code later.

Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/set_memory.h
arch/s390/mm/pageattr.c

index 9f6c329a0d4e624beea7e69e56c29089465e8779..06fbabe2f66c982aeae972ec0539c044a85f9ebd 100644 (file)
@@ -24,14 +24,32 @@ enum {
 #define SET_MEMORY_INV BIT(_SET_MEMORY_INV_BIT)
 #define SET_MEMORY_DEF BIT(_SET_MEMORY_DEF_BIT)
 
-int __set_memory(unsigned long addr, int numpages, unsigned long flags);
+int __set_memory(unsigned long addr, unsigned long numpages, unsigned long flags);
 
 #define set_memory_rox set_memory_rox
 
-#define __SET_MEMORY_FUNC(fname, flags)                                \
-static inline int fname(unsigned long addr, int numpages)      \
-{                                                              \
-       return __set_memory(addr, numpages, (flags));           \
+/*
+ * Generate two variants of each set_memory() function:
+ *
+ * set_memory_yy(unsigned long addr, int numpages);
+ * __set_memory_yy(void *start, void *end);
+ *
+ * The second variant exists for both convenience to avoid the usual
+ * (unsigned long) casts, but unlike the first variant it can also be used
+ * for areas larger than 8TB, which may happen at memory initialization.
+ */
+#define __SET_MEMORY_FUNC(fname, flags)                                        \
+static inline int fname(unsigned long addr, int numpages)              \
+{                                                                      \
+       return __set_memory(addr, numpages, (flags));                   \
+}                                                                      \
+                                                                       \
+static inline int __##fname(void *start, void *end)                    \
+{                                                                      \
+       unsigned long numpages;                                         \
+                                                                       \
+       numpages = (end - start) >> PAGE_SHIFT;                         \
+       return __set_memory((unsigned long)start, numpages, (flags));   \
 }
 
 __SET_MEMORY_FUNC(set_memory_ro, SET_MEMORY_RO)
index ca5a418c58a8c87e9671c1869b0abec7b5b26c19..43c919c7bafb23fd8d83d9395bc2dbc3029e6e81 100644 (file)
@@ -373,7 +373,7 @@ static int change_page_attr_alias(unsigned long addr, unsigned long end,
        return rc;
 }
 
-int __set_memory(unsigned long addr, int numpages, unsigned long flags)
+int __set_memory(unsigned long addr, unsigned long numpages, unsigned long flags)
 {
        unsigned long end;
        int rc;