]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
locking/lockdep: check for freed initmem in static_obj()
authorGerald Schaefer <gerald.schaefer@de.ibm.com>
Thu, 18 Apr 2019 14:24:50 +0000 (16:24 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 29 Apr 2019 08:47:10 +0000 (10:47 +0200)
The following warning occurred on s390:
WARNING: CPU: 0 PID: 804 at kernel/locking/lockdep.c:1025 lockdep_register_key+0x30/0x150

This is because the check in static_obj() assumes that all memory within
[_stext, _end] belongs to static objects, which at least for s390 isn't
true. The init section is also part of this range, and freeing it allows
the buddy allocator to allocate memory from it. We have virt == phys for
the kernel on s390, so that such allocations would then have addresses
within the range [_stext, _end].

To fix this, introduce arch_is_kernel_initmem_freed(), similar to
arch_is_kernel_text/data(), and add it to the checks in static_obj().
This will always return 0 on architectures that do not define
arch_is_kernel_initmem_freed. On s390, it will return 1 if initmem has
been freed and the address is in the range [__init_begin, __init_end].

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/sections.h
arch/s390/mm/init.c
include/asm-generic/sections.h
kernel/locking/lockdep.c

index af670fa4b12aa421a5770d2d482f9a25c205b051..42de04ad9c07bee8967b03c6285e0741702e2e67 100644 (file)
@@ -2,8 +2,20 @@
 #ifndef _S390_SECTIONS_H
 #define _S390_SECTIONS_H
 
+#define arch_is_kernel_initmem_freed arch_is_kernel_initmem_freed
+
 #include <asm-generic/sections.h>
 
+extern bool initmem_freed;
+
+static inline int arch_is_kernel_initmem_freed(unsigned long addr)
+{
+       if (!initmem_freed)
+               return 0;
+       return addr >= (unsigned long)__init_begin &&
+              addr < (unsigned long)__init_end;
+}
+
 /*
  * .boot.data section contains variables "shared" between the decompressor and
  * the decompressed kernel. The decompressor will store values in them, and
index 3e82f66d5c613e82e051235786f49c5d2e79b31f..7cf48eefec8fc291ee3090c77107327547b85e95 100644 (file)
@@ -49,6 +49,8 @@ unsigned long empty_zero_page, zero_page_mask;
 EXPORT_SYMBOL(empty_zero_page);
 EXPORT_SYMBOL(zero_page_mask);
 
+bool initmem_freed;
+
 static void __init setup_zero_pages(void)
 {
        unsigned int order;
@@ -148,6 +150,7 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
+       initmem_freed = true;
        __set_memory((unsigned long)_sinittext,
                     (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT,
                     SET_MEMORY_RW | SET_MEMORY_NX);
index d79abca81a52a15a425ea045881f4ed0d514b299..d1779d442aa51a4d223ae8fd855c8fd93aa34077 100644 (file)
@@ -77,6 +77,20 @@ static inline int arch_is_kernel_data(unsigned long addr)
 }
 #endif
 
+/*
+ * Check if an address is part of freed initmem. This is needed on architectures
+ * with virt == phys kernel mapping, for code that wants to check if an address
+ * is part of a static object within [_stext, _end]. After initmem is freed,
+ * memory can be allocated from it, and such allocations would then have
+ * addresses within the range [_stext, _end].
+ */
+#ifndef arch_is_kernel_initmem_freed
+static inline int arch_is_kernel_initmem_freed(unsigned long addr)
+{
+       return 0;
+}
+#endif
+
 /**
  * memory_contains - checks if an object is contained within a memory region
  * @begin: virtual address of the beginning of the memory region
index 34cdcbedda492b84cb610af67cb11113ea04065d..22a99530983e6a5bda13645d58a11fbc5c9ffe9a 100644 (file)
@@ -649,6 +649,9 @@ static int static_obj(const void *obj)
                      end   = (unsigned long) &_end,
                      addr  = (unsigned long) obj;
 
+       if (arch_is_kernel_initmem_freed(addr))
+               return 0;
+
        /*
         * static variable?
         */