aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/build.c
diff options
context:
space:
mode:
authorHou Tao <houtao1@huawei.com>2019-11-30 17:48:25 +0800
committerRichard Weinberger <richard@nod.at>2020-01-16 23:35:59 +0100
commitfc55dacf7fea793e70c9c75a1acff47a4fb02017 (patch)
tree322ea53989f168fdce2826455193d77364dadf43 /drivers/mtd/ubi/build.c
parentubi: Check the presence of volume before call ubi_fastmap_destroy_checkmap() (diff)
downloadlinux-dev-fc55dacf7fea793e70c9c75a1acff47a4fb02017.tar.xz
linux-dev-fc55dacf7fea793e70c9c75a1acff47a4fb02017.zip
ubi: Free the normal volumes in error paths of ubi_attach_mtd_dev()
The allocated normal volumes saved in ubi->volumes are not freed in the error paths in ubi_attach_mtd_dev() and its callees (e.g. ubi_attach() and ubi_read_volume_table()). These normal volumes should be freed through kill_volumes() and vol_release(), but ubi_attach_mtd_dev() may fail before calling uif_init(), and there will be memory leaks. So adding a new helper ubi_free_all_volumes() to free the normal and the internal volumes. And in order to prevent double-free of volume, reset ubi->volumes[i] to NULL after freeing. Signed-off-by: Hou Tao <houtao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers/mtd/ubi/build.c')
-rw-r--r--drivers/mtd/ubi/build.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index d636bbe214cb..25fb72b2efa0 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -503,21 +503,42 @@ static void uif_close(struct ubi_device *ubi)
}
/**
- * ubi_free_internal_volumes - free internal volumes.
+ * ubi_free_volumes_from - free volumes from specific index.
* @ubi: UBI device description object
+ * @from: the start index used for volume free.
*/
-void ubi_free_internal_volumes(struct ubi_device *ubi)
+static void ubi_free_volumes_from(struct ubi_device *ubi, int from)
{
int i;
- for (i = ubi->vtbl_slots;
- i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+ for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+ if (!ubi->volumes[i])
+ continue;
ubi_eba_replace_table(ubi->volumes[i], NULL);
ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
kfree(ubi->volumes[i]);
+ ubi->volumes[i] = NULL;
}
}
+/**
+ * ubi_free_all_volumes - free all volumes.
+ * @ubi: UBI device description object
+ */
+void ubi_free_all_volumes(struct ubi_device *ubi)
+{
+ ubi_free_volumes_from(ubi, 0);
+}
+
+/**
+ * ubi_free_internal_volumes - free internal volumes.
+ * @ubi: UBI device description object
+ */
+void ubi_free_internal_volumes(struct ubi_device *ubi)
+{
+ ubi_free_volumes_from(ubi, ubi->vtbl_slots);
+}
+
static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024)
{
int limit, device_pebs;
@@ -1013,7 +1034,7 @@ out_uif:
out_detach:
ubi_devices[ubi_num] = NULL;
ubi_wl_close(ubi);
- ubi_free_internal_volumes(ubi);
+ ubi_free_all_volumes(ubi);
vfree(ubi->vtbl);
out_free:
vfree(ubi->peb_buf);