mtd: pmcmsp-flash: fix error paths in init_msp_flash
[pandora-kernel.git] / drivers / mtd / maps / pmcmsp-flash.c
index 4768bd5..c8fd8da 100644 (file)
@@ -50,7 +50,7 @@ static int fcnt;
 
 static int __init init_msp_flash(void)
 {
-       int i, j;
+       int i, j, ret = -ENOMEM;
        int offset, coff;
        char *env;
        int pcnt;
@@ -75,14 +75,16 @@ static int __init init_msp_flash(void)
        printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
 
        msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
+       if (!msp_flash)
+               return -ENOMEM;
+
        msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+       if (!msp_parts)
+               goto free_msp_flash;
+
        msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
-       if (!msp_flash || !msp_parts || !msp_maps) {
-               kfree(msp_maps);
-               kfree(msp_parts);
-               kfree(msp_flash);
-               return -ENOMEM;
-       }
+       if (!msp_maps)
+               goto free_msp_parts;
 
        /* loop over the flash devices, initializing each */
        for (i = 0; i < fcnt; i++) {
@@ -100,13 +102,18 @@ static int __init init_msp_flash(void)
 
                msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition),
                                       GFP_KERNEL);
+               if (!msp_parts[i])
+                       goto cleanup_loop;
 
                /* now initialize the devices proper */
                flash_name[5] = '0' + i;
                env = prom_getenv(flash_name);
 
-               if (sscanf(env, "%x:%x", &addr, &size) < 2)
-                       return -ENXIO;
+               if (sscanf(env, "%x:%x", &addr, &size) < 2) {
+                       ret = -ENXIO;
+                       kfree(msp_parts[i]);
+                       goto cleanup_loop;
+               }
                addr = CPHYSADDR(addr);
 
                printk(KERN_NOTICE
@@ -122,13 +129,23 @@ static int __init init_msp_flash(void)
                 */
                if (size > CONFIG_MSP_FLASH_MAP_LIMIT)
                        size = CONFIG_MSP_FLASH_MAP_LIMIT;
+
                msp_maps[i].virt = ioremap(addr, size);
+               if (msp_maps[i].virt == NULL) {
+                       ret = -ENXIO;
+                       kfree(msp_parts[i]);
+                       goto cleanup_loop;
+               }
+
                msp_maps[i].bankwidth = 1;
-               msp_maps[i].name = strncpy(kmalloc(7, GFP_KERNEL),
-                                       flash_name, 7);
+               msp_maps[i].name = kmalloc(7, GFP_KERNEL);
+               if (!msp_maps[i].name) {
+                       iounmap(msp_maps[i].virt);
+                       kfree(msp_parts[i]);
+                       goto cleanup_loop;
+               }
 
-               if (msp_maps[i].virt == NULL)
-                       return -ENXIO;
+               msp_maps[i].name = strncpy(msp_maps[i].name, flash_name, 7);
 
                for (j = 0; j < pcnt; j++) {
                        part_name[5] = '0' + i;
@@ -136,8 +153,14 @@ static int __init init_msp_flash(void)
 
                        env = prom_getenv(part_name);
 
-                       if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2)
-                               return -ENXIO;
+                       if (sscanf(env, "%x:%x:%n", &offset, &size,
+                                               &coff) < 2) {
+                               ret = -ENXIO;
+                               kfree(msp_maps[i].name);
+                               iounmap(msp_maps[i].virt);
+                               kfree(msp_parts[i]);
+                               goto cleanup_loop;
+                       }
 
                        msp_parts[i][j].size = size;
                        msp_parts[i][j].offset = offset;
@@ -152,18 +175,37 @@ static int __init init_msp_flash(void)
                        add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt);
                } else {
                        printk(KERN_ERR "map probe failed for flash\n");
-                       return -ENXIO;
+                       ret = -ENXIO;
+                       kfree(msp_maps[i].name);
+                       iounmap(msp_maps[i].virt);
+                       kfree(msp_parts[i]);
+                       goto cleanup_loop;
                }
        }
 
        return 0;
+
+cleanup_loop:
+       while (i--) {
+               del_mtd_partitions(msp_flash[i]);
+               map_destroy(msp_flash[i]);
+               kfree(msp_maps[i].name);
+               iounmap(msp_maps[i].virt);
+               kfree(msp_parts[i]);
+       }
+       kfree(msp_maps);
+free_msp_parts:
+       kfree(msp_parts);
+free_msp_flash:
+       kfree(msp_flash);
+       return ret;
 }
 
 static void __exit cleanup_msp_flash(void)
 {
        int i;
 
-       for (i = 0; i < sizeof(msp_flash) / sizeof(struct mtd_info **); i++) {
+       for (i = 0; i < fcnt; i++) {
                del_mtd_partitions(msp_flash[i]);
                map_destroy(msp_flash[i]);
                iounmap((void *)msp_maps[i].virt);