diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-06-04 10:58:37 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-07-24 06:32:55 -0400 |
commit | 472018f73e7308a7f29b753ee8c742b6f45f103f (patch) | |
tree | 327c1e008a30b79fc527daf26802b795f3a99b32 /drivers/mtd/ubi | |
parent | 505d1caa79cd61a70615e9a7eae2eab85e797a83 (diff) |
UBI: fix memory leak on error path
Normally UBI volumes are freed in the release function of
the struct device object. However, on error path they may
have to be freed before the struct device objects have been
initialized.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r-- | drivers/mtd/ubi/build.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 33205e4c1f5b..a5b19944eca8 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
@@ -355,15 +355,34 @@ static void kill_volumes(struct ubi_device *ubi) | |||
355 | } | 355 | } |
356 | 356 | ||
357 | /** | 357 | /** |
358 | * free_user_volumes - free all user volumes. | ||
359 | * @ubi: UBI device description object | ||
360 | * | ||
361 | * Normally the volumes are freed at the release function of the volume device | ||
362 | * objects. However, on error paths the volumes have to be freed before the | ||
363 | * device objects have been initialized. | ||
364 | */ | ||
365 | static void free_user_volumes(struct ubi_device *ubi) | ||
366 | { | ||
367 | int i; | ||
368 | |||
369 | for (i = 0; i < ubi->vtbl_slots; i++) | ||
370 | if (ubi->volumes[i]) { | ||
371 | kfree(ubi->volumes[i]->eba_tbl); | ||
372 | kfree(ubi->volumes[i]); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | /** | ||
358 | * uif_init - initialize user interfaces for an UBI device. | 377 | * uif_init - initialize user interfaces for an UBI device. |
359 | * @ubi: UBI device description object | 378 | * @ubi: UBI device description object |
360 | * | 379 | * |
361 | * This function returns zero in case of success and a negative error code in | 380 | * This function returns zero in case of success and a negative error code in |
362 | * case of failure. | 381 | * case of failure. Note, this function destroys all volumes if it failes. |
363 | */ | 382 | */ |
364 | static int uif_init(struct ubi_device *ubi) | 383 | static int uif_init(struct ubi_device *ubi) |
365 | { | 384 | { |
366 | int i, err; | 385 | int i, err, do_free = 0; |
367 | dev_t dev; | 386 | dev_t dev; |
368 | 387 | ||
369 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); | 388 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); |
@@ -410,10 +429,13 @@ static int uif_init(struct ubi_device *ubi) | |||
410 | 429 | ||
411 | out_volumes: | 430 | out_volumes: |
412 | kill_volumes(ubi); | 431 | kill_volumes(ubi); |
432 | do_free = 0; | ||
413 | out_sysfs: | 433 | out_sysfs: |
414 | ubi_sysfs_close(ubi); | 434 | ubi_sysfs_close(ubi); |
415 | cdev_del(&ubi->cdev); | 435 | cdev_del(&ubi->cdev); |
416 | out_unreg: | 436 | out_unreg: |
437 | if (do_free) | ||
438 | free_user_volumes(ubi); | ||
417 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); | 439 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); |
418 | ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); | 440 | ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); |
419 | return err; | 441 | return err; |
@@ -722,7 +744,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) | |||
722 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | 744 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) |
723 | { | 745 | { |
724 | struct ubi_device *ubi; | 746 | struct ubi_device *ubi; |
725 | int i, err; | 747 | int i, err, do_free = 1; |
726 | 748 | ||
727 | /* | 749 | /* |
728 | * Check if we already have the same MTD device attached. | 750 | * Check if we already have the same MTD device attached. |
@@ -822,7 +844,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
822 | 844 | ||
823 | err = uif_init(ubi); | 845 | err = uif_init(ubi); |
824 | if (err) | 846 | if (err) |
825 | goto out_detach; | 847 | goto out_nofree; |
826 | 848 | ||
827 | ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); | 849 | ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); |
828 | if (IS_ERR(ubi->bgt_thread)) { | 850 | if (IS_ERR(ubi->bgt_thread)) { |
@@ -859,8 +881,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
859 | 881 | ||
860 | out_uif: | 882 | out_uif: |
861 | uif_close(ubi); | 883 | uif_close(ubi); |
884 | out_nofree: | ||
885 | do_free = 0; | ||
862 | out_detach: | 886 | out_detach: |
863 | ubi_wl_close(ubi); | 887 | ubi_wl_close(ubi); |
888 | if (do_free) | ||
889 | free_user_volumes(ubi); | ||
864 | free_internal_volumes(ubi); | 890 | free_internal_volumes(ubi); |
865 | vfree(ubi->vtbl); | 891 | vfree(ubi->vtbl); |
866 | out_free: | 892 | out_free: |