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

locking/lockdep: check for freed initmem in static_obj()

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>

authored by

Gerald Schaefer and committed by
Martin Schwidefsky
7a5da02d b2d24b97

+32
+12
arch/s390/include/asm/sections.h
··· 2 2 #ifndef _S390_SECTIONS_H 3 3 #define _S390_SECTIONS_H 4 4 5 + #define arch_is_kernel_initmem_freed arch_is_kernel_initmem_freed 6 + 5 7 #include <asm-generic/sections.h> 8 + 9 + extern bool initmem_freed; 10 + 11 + static inline int arch_is_kernel_initmem_freed(unsigned long addr) 12 + { 13 + if (!initmem_freed) 14 + return 0; 15 + return addr >= (unsigned long)__init_begin && 16 + addr < (unsigned long)__init_end; 17 + } 6 18 7 19 /* 8 20 * .boot.data section contains variables "shared" between the decompressor and
+3
arch/s390/mm/init.c
··· 49 49 EXPORT_SYMBOL(empty_zero_page); 50 50 EXPORT_SYMBOL(zero_page_mask); 51 51 52 + bool initmem_freed; 53 + 52 54 static void __init setup_zero_pages(void) 53 55 { 54 56 unsigned int order; ··· 150 148 151 149 void free_initmem(void) 152 150 { 151 + initmem_freed = true; 153 152 __set_memory((unsigned long)_sinittext, 154 153 (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT, 155 154 SET_MEMORY_RW | SET_MEMORY_NX);
+14
include/asm-generic/sections.h
··· 77 77 } 78 78 #endif 79 79 80 + /* 81 + * Check if an address is part of freed initmem. This is needed on architectures 82 + * with virt == phys kernel mapping, for code that wants to check if an address 83 + * is part of a static object within [_stext, _end]. After initmem is freed, 84 + * memory can be allocated from it, and such allocations would then have 85 + * addresses within the range [_stext, _end]. 86 + */ 87 + #ifndef arch_is_kernel_initmem_freed 88 + static inline int arch_is_kernel_initmem_freed(unsigned long addr) 89 + { 90 + return 0; 91 + } 92 + #endif 93 + 80 94 /** 81 95 * memory_contains - checks if an object is contained within a memory region 82 96 * @begin: virtual address of the beginning of the memory region
+3
kernel/locking/lockdep.c
··· 649 649 end = (unsigned long) &_end, 650 650 addr = (unsigned long) obj; 651 651 652 + if (arch_is_kernel_initmem_freed(addr)) 653 + return 0; 654 + 652 655 /* 653 656 * static variable? 654 657 */