Commit fc55dacf authored by Hou Tao's avatar Hou Tao Committed by Richard Weinberger

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: default avatarHou Tao <houtao1@huawei.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 9d6c4742
...@@ -1640,7 +1640,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) ...@@ -1640,7 +1640,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
out_wl: out_wl:
ubi_wl_close(ubi); ubi_wl_close(ubi);
out_vtbl: out_vtbl:
ubi_free_internal_volumes(ubi); ubi_free_all_volumes(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
out_ai: out_ai:
destroy_ai(ai); destroy_ai(ai);
......
...@@ -503,21 +503,42 @@ static void uif_close(struct ubi_device *ubi) ...@@ -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 * @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; int i;
for (i = ubi->vtbl_slots; for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { if (!ubi->volumes[i])
continue;
ubi_eba_replace_table(ubi->volumes[i], NULL); ubi_eba_replace_table(ubi->volumes[i], NULL);
ubi_fastmap_destroy_checkmap(ubi->volumes[i]); ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
kfree(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) static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024)
{ {
int limit, device_pebs; int limit, device_pebs;
...@@ -1013,7 +1034,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -1013,7 +1034,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
out_detach: out_detach:
ubi_devices[ubi_num] = NULL; ubi_devices[ubi_num] = NULL;
ubi_wl_close(ubi); ubi_wl_close(ubi);
ubi_free_internal_volumes(ubi); ubi_free_all_volumes(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
out_free: out_free:
vfree(ubi->peb_buf); vfree(ubi->peb_buf);
......
...@@ -950,6 +950,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -950,6 +950,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol,
int ubi_notify_all(struct ubi_device *ubi, int ntype, int ubi_notify_all(struct ubi_device *ubi, int ntype,
struct notifier_block *nb); struct notifier_block *nb);
int ubi_enumerate_volumes(struct notifier_block *nb); int ubi_enumerate_volumes(struct notifier_block *nb);
void ubi_free_all_volumes(struct ubi_device *ubi);
void ubi_free_internal_volumes(struct ubi_device *ubi); void ubi_free_internal_volumes(struct ubi_device *ubi);
/* kapi.c */ /* kapi.c */
......
...@@ -782,7 +782,7 @@ static int check_attaching_info(const struct ubi_device *ubi, ...@@ -782,7 +782,7 @@ static int check_attaching_info(const struct ubi_device *ubi,
*/ */
int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai) int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
{ {
int i, err; int err;
struct ubi_ainf_volume *av; struct ubi_ainf_volume *av;
empty_vtbl_record.crc = cpu_to_be32(0xf116c36b); empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
...@@ -851,13 +851,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai) ...@@ -851,13 +851,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
out_free: out_free:
vfree(ubi->vtbl); vfree(ubi->vtbl);
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { ubi_free_all_volumes(ubi);
if (!ubi->volumes[i])
continue;
ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
kfree(ubi->volumes[i]);
ubi->volumes[i] = NULL;
}
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment