kmemleak reported a memleak after the ndctl_test unreferenced object 0xffff88800e6cf2c0 (size 32): comm "modprobe", pid 969, jiffies 4294698691 hex dump (first 32 bytes): 03 00 00 00 a0 0a 00 00 00 b0 b4 00 00 c9 ff ff ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace (crc 807f3e24): __kmalloc_cache_noprof+0x331/0x410 nvdimm_namespace_attach_btt+0xa9b/0xcc0 [nd_btt] platform_probe+0x45/0xa0 ... load_module+0x21f9/0x22f0
faddr2line tells that (based on v6.15-rc4): $ ./scripts/faddr2line drivers/nvdimm/nd_btt.o nvdimm_namespace_attach_btt+0xa9 nvdimm_namespace_attach_btt+0xa9b/0xcc0: log_set_indices at linux/drivers/nvdimm/btt.c:719 (inlined by) discover_arenas at linux/drivers/nvdimm/btt.c:888 (inlined by) btt_init at linux/drivers/nvdimm/btt.c:1583 (inlined by) nvdimm_namespace_attach_btt at linux/drivers/nvdimm/btt.c:1680 It's believed that this was a false positive because the leaking size didn't match any instance in an arena. However during looking into this issue, it's noticed that it does not release an initializing arena instance and instances in btt->arena_list in some error paths. Signed-off-by: Li Zhijian <lizhij...@fujitsu.com> --- drivers/nvdimm/btt.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 423dcd190906..a11e4e7e9a52 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -801,17 +801,22 @@ static struct arena_info *alloc_arena(struct btt *btt, size_t size, return arena; } +static void free_arena(struct arena_info *arena) +{ + kfree(arena->rtt); + kfree(arena->map_locks); + kfree(arena->freelist); + debugfs_remove_recursive(arena->debugfs_dir); + kfree(arena); +} + static void free_arenas(struct btt *btt) { struct arena_info *arena, *next; list_for_each_entry_safe(arena, next, &btt->arena_list, list) { list_del(&arena->list); - kfree(arena->rtt); - kfree(arena->map_locks); - kfree(arena->freelist); - debugfs_remove_recursive(arena->debugfs_dir); - kfree(arena); + free_arena(arena); } } @@ -848,7 +853,7 @@ static void parse_arena_meta(struct arena_info *arena, struct btt_sb *super, static int discover_arenas(struct btt *btt) { int ret = 0; - struct arena_info *arena; + struct arena_info *arena = NULL; size_t remaining = btt->rawsize; u64 cur_nlba = 0; size_t cur_off = 0; @@ -861,8 +866,10 @@ static int discover_arenas(struct btt *btt) while (remaining) { /* Alloc memory for arena */ arena = alloc_arena(btt, 0, 0, 0); - if (!arena) - return -ENOMEM; + if (!arena) { + ret = -ENOMEM; + goto out; + } arena->infooff = cur_off; ret = btt_info_read(arena, super); @@ -921,7 +928,8 @@ static int discover_arenas(struct btt *btt) return ret; out: - kfree(arena); + if (arena) + free_arena(arena); free_arenas(btt); return ret; } -- 2.47.0