When loading a module, as long as the module has memory allocation operations, kmemleak produces a false positive report that resembles the following: unreferenced object (percpu) 0x7dfd232a1650 (size 16): comm "modprobe", pid 1301, jiffies 4294940249 hex dump (first 16 bytes on cpu 2): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace (crc 0): kmemleak_alloc_percpu+0xb4/0xd0 pcpu_alloc_noprof+0x700/0x1098 load_module+0xd4/0x348 codetag_module_init+0x20c/0x450 codetag_load_module+0x70/0xb8 load_module+0xef8/0x1608 init_module_from_file+0xec/0x158 idempotent_init_module+0x354/0x608 __arm64_sys_finit_module+0xbc/0x150 invoke_syscall+0xd4/0x258 el0_svc_common.constprop.0+0xb4/0x240 do_el0_svc+0x48/0x68 el0_svc+0x40/0xf8 el0t_64_sync_handler+0x10c/0x138 el0t_64_sync+0x1ac/0x1b0 This is because the module can only indirectly reference alloc_tag_counters through the alloc_tag section, which misleads kmemleak. However, we don't have a kmemleak ignore interface for percpu allocations yet. So let's create one and invoke it for tag->counters. [gehao@kylinos.cn: fix build error when CONFIG_DEBUG_KMEMLEAK=n, s/igonore/ignore/] Link: https://lkml.kernel.org/r/20250620093102.2416767-1-hao.ge@linux.dev Link: https://lkml.kernel.org/r/20250619183154.2122608-1-hao.ge@linux.dev Fixes: 12ca42c23775 ("alloc_tag: allocate percpu counters for module tags dynamically") Signed-off-by: Hao Ge <gehao@kylinos.cn> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Suren Baghdasaryan <surenb@google.com> [lib/alloc_tag.c] Cc: Kent Overstreet <kent.overstreet@linux.dev> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Showing the changes to include/linux (1 of 3 files). Show all
Unified · Split
| @@ -28,6 +28,7 @@ extern void kmemleak_update_trace(const void *ptr) __ref; · 27 unmodified lines | |||
| 28 | extern void kmemleak_not_leak(const void *ptr) __ref; | 28 | extern void kmemleak_not_leak(const void *ptr) __ref; |
| 29 | extern void kmemleak_transient_leak(const void *ptr) __ref; | 29 | extern void kmemleak_transient_leak(const void *ptr) __ref; |
| 30 | extern void kmemleak_ignore(const void *ptr) __ref; | 30 | extern void kmemleak_ignore(const void *ptr) __ref; |
| 31 | extern void kmemleak_ignore_percpu(const void __percpu *ptr) __ref; | ||
| 31 | extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref; | 32 | extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref; |
| 32 | extern void kmemleak_no_scan(const void *ptr) __ref; | 33 | extern void kmemleak_no_scan(const void *ptr) __ref; |
| 33 | extern void kmemleak_alloc_phys(phys_addr_t phys, size_t size, | 34 | extern void kmemleak_alloc_phys(phys_addr_t phys, size_t size, |
| @@ -97,6 +98,9 @@ static inline void kmemleak_not_leak(const void *ptr) · 63 unmodified lines | |||
| 97 | static inline void kmemleak_transient_leak(const void *ptr) | 98 | static inline void kmemleak_transient_leak(const void *ptr) |
| 98 | { | 99 | { |
| 99 | } | 100 | } |
| 101 | static inline void kmemleak_ignore_percpu(const void __percpu *ptr) | ||
| 102 | { | ||
| 103 | } | ||
| 100 | static inline void kmemleak_ignore(const void *ptr) | 104 | static inline void kmemleak_ignore(const void *ptr) |
| 101 | { | 105 | { |
| 102 | } | 106 | } |