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>
This commit is contained in:
parent
9d6c4742f9
commit
fc55dacf7f
@ -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);
|
||||||
|
@ -502,20 +502,41 @@ static void uif_close(struct ubi_device *ubi)
|
|||||||
unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
|
unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ubi_free_volumes_from - free volumes from specific index.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
* @from: the start index used for volume free.
|
||||||
|
*/
|
||||||
|
static void ubi_free_volumes_from(struct ubi_device *ubi, int from)
|
||||||
|
{
|
||||||
|
int 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_free_internal_volumes - free internal volumes.
|
||||||
* @ubi: UBI device description object
|
* @ubi: UBI device description object
|
||||||
*/
|
*/
|
||||||
void ubi_free_internal_volumes(struct ubi_device *ubi)
|
void ubi_free_internal_volumes(struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
int i;
|
ubi_free_volumes_from(ubi, ubi->vtbl_slots);
|
||||||
|
|
||||||
for (i = ubi->vtbl_slots;
|
|
||||||
i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
|
|
||||||
ubi_eba_replace_table(ubi->volumes[i], NULL);
|
|
||||||
ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
|
|
||||||
kfree(ubi->volumes[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -1013,7 +1034,7 @@ out_uif:
|
|||||||
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,
|
|||||||
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,
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user