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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1640,7 +1640,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
out_wl:
	ubi_wl_close(ubi);
out_vtbl:
	ubi_free_internal_volumes(ubi);
	ubi_free_all_volumes(ubi);
	vfree(ubi->vtbl);
out_ai:
	destroy_ai(ai);
+26 −5
Original line number Diff line number Diff line
@@ -503,19 +503,40 @@ 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)
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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,
		   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);

/* kapi.c */
+2 −8
Original line number Diff line number Diff line
@@ -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 i, err;
	int err;
	struct ubi_ainf_volume *av;

	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:
	vfree(ubi->vtbl);
	for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
		if (!ubi->volumes[i])
			continue;
		ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
		kfree(ubi->volumes[i]);
		ubi->volumes[i] = NULL;
	}
	ubi_free_all_volumes(ubi);
	return err;
}