]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ubi: fastmap: fix ubi->fm memory leak
authorLiyuan Pang <pangliyuan1@huawei.com>
Fri, 7 Nov 2025 10:00:57 +0000 (18:00 +0800)
committerRichard Weinberger <richard@nod.at>
Fri, 28 Nov 2025 20:49:01 +0000 (21:49 +0100)
The problem is that scan_fast() allocate memory for ubi->fm
and ubi->fm->e[x], but if the following attach process fails
in ubi_wl_init or ubi_read_volume_table, the whole attach
process will fail without executing ubi_wl_close to free the
memory under ubi->fm.

Fix this by add a new ubi_free_fastmap function in fastmap.c
to free the memory allocated for fm.

If SLUB_DEBUG and KUNIT are enabled, the following warning messages
will show:
ubi0: detaching mtd0
ubi0: mtd0 is detached
ubi0: default fastmap pool size: 200
ubi0: default fastmap WL pool size: 100
ubi0: attaching mtd0
ubi0: attached by fastmap
ubi0: fastmap pool size: 200
ubi0: fastmap WL pool size: 100
ubi0 error: ubi_wl_init [ubi]: no enough physical eraseblocks (4, need 203)
ubi0 error: ubi_attach_mtd_dev [ubi]: failed to attach mtd0, error -28
UBI error: cannot attach mtd0
=================================================================
BUG ubi_wl_entry_slab (Tainted: G    B      O L   ): Objects remaining in ubi_wl_entry_slab on __kmem_cache_shutdown()
-----------------------------------------------------------------------------

Slab 0xffff2fd23a40cd00 objects=22 used=1 fp=0xffff2fd1d0334fd8 flags=0x883fffc010200(slab|head|section=34|node=0|zone=1|lastcpupid=0x7fff)
CPU: 0 PID: 5884 Comm: insmod Tainted: G    B      O L    5.10.0 #1
Hardware name: LS1043A RDB Board (DT)
Call trace:
 dump_backtrace+0x0/0x198
 show_stack+0x18/0x28
 dump_stack+0xe8/0x15c
 slab_err+0x94/0xc0
 __kmem_cache_shutdown+0x1fc/0x39c
 kmem_cache_destroy+0x48/0x138
 ubi_init+0x1d4/0xf34 [ubi]
 do_one_initcall+0xb4/0x24c
 do_init_module+0x4c/0x1dc
 load_module+0x212c/0x2260
 __se_sys_finit_module+0xb4/0xd8
 __arm64_sys_finit_module+0x18/0x28
 el0_svc_common.constprop.0+0x78/0x1a0
 do_el0_svc+0x78/0x90
 el0_svc+0x20/0x38
 el0_sync_handler+0xf0/0x140
 normal+0x3d8/0x400
Object 0xffff2fd1d0334e68 @offset=3688
Allocated in ubi_scan_fastmap+0xf04/0xf40 [ubi] age=80 cpu=0 pid=5884
__slab_alloc.isra.21+0x6c/0xb4
kmem_cache_alloc+0x1e4/0x80c
ubi_scan_fastmap+0xf04/0xf40 [ubi]
ubi_attach+0x1f0/0x3a8 [ubi]
ubi_attach_mtd_dev+0x810/0xbc8 [ubi]
ubi_init+0x238/0xf34 [ubi]
do_one_initcall+0xb4/0x24c
do_init_module+0x4c/0x1dc
load_module+0x212c/0x2260
__se_sys_finit_module+0xb4/0xd8
__arm64_sys_finit_module+0x18/0x28
el0_svc_common.constprop.0+0x78/0x1a0
do_el0_svc+0x78/0x90
el0_svc+0x20/0x38
el0_sync_handler+0xf0/0x140
normal+0x3d8/0x400

Link: https://bugzilla.kernel.org/show_bug.cgi?id=220744
Signed-off-by: Liyuan Pang <pangliyuan1@huawei.com>
Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
drivers/mtd/ubi/attach.c
drivers/mtd/ubi/fastmap-wl.c
drivers/mtd/ubi/ubi.h

index adc47b87b38a5f89a35aa064913a2c503690efa5..884171871d0e54977f6e42f756877c4e0a1ff9fb 100644 (file)
@@ -1600,7 +1600,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
 
        err = ubi_read_volume_table(ubi, ai);
        if (err)
-               goto out_ai;
+               goto out_fm;
 
        err = ubi_wl_init(ubi, ai);
        if (err)
@@ -1642,6 +1642,8 @@ out_wl:
 out_vtbl:
        ubi_free_all_volumes(ubi);
        vfree(ubi->vtbl);
+out_fm:
+       ubi_free_fastmap(ubi);
 out_ai:
        destroy_ai(ai);
        return err;
index 9bdb6525f1281f28f5b9fc9ddc5db87bf86e9b0f..e2bc1122bfd31981eea774f1a570b1e6e6bafd91 100644 (file)
@@ -530,8 +530,6 @@ int ubi_is_erase_work(struct ubi_work *wrk)
 
 static void ubi_fastmap_close(struct ubi_device *ubi)
 {
-       int i;
-
        return_unused_pool_pebs(ubi, &ubi->fm_pool);
        return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);
 
@@ -540,11 +538,7 @@ static void ubi_fastmap_close(struct ubi_device *ubi)
                ubi->fm_anchor = NULL;
        }
 
-       if (ubi->fm) {
-               for (i = 0; i < ubi->fm->used_blocks; i++)
-                       kfree(ubi->fm->e[i]);
-       }
-       kfree(ubi->fm);
+       ubi_free_fastmap(ubi);
 }
 
 /**
index c792b9bcab9bcebe5648ade95c70309d43d121c6..44803d3329f42455b397693cbda75eaafb019af6 100644 (file)
@@ -969,10 +969,22 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
                     struct ubi_attach_info *scan_ai);
 int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count);
 void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol);
+static inline void ubi_free_fastmap(struct ubi_device *ubi)
+{
+       if (ubi->fm) {
+               int i;
+
+               for (i = 0; i < ubi->fm->used_blocks; i++)
+                       kmem_cache_free(ubi_wl_entry_slab, ubi->fm->e[i]);
+               kfree(ubi->fm);
+               ubi->fm = NULL;
+       }
+}
 #else
 static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
 static inline int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) { return 0; }
 static inline void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) {}
+static inline void ubi_free_fastmap(struct ubi_device *ubi) { }
 #endif
 
 /* block.c */