diff options
author | Brian Norris <computersforpeace@gmail.com> | 2017-05-01 20:04:53 -0400 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@free-electrons.com> | 2017-05-22 03:42:29 -0400 |
commit | 787710492911e21148975e1d1914c7409fb32c7e (patch) | |
tree | 643531c181864b2fd26246113b4b48283e3c6817 /drivers/mtd/nand | |
parent | 0545c1720277dd246bd682b23aee425f3830a14f (diff) |
mtd: nand: free vendor-specific resources in init failure paths
If we fail any time after calling nand_detect(), then we don't call the
vendor-specific ->cleanup() callback, and we'll leak any resources the
vendor-specific code might have allocated.
Mark the "fix" against the first commit that started allocating anything
in ->init().
Fixes: 626994e07480 ("mtd: nand: hynix: Add read-retry support for 1x nm MLC NANDs")
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 66782291a762..81f77f9cd784 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -4361,7 +4361,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
4361 | /* Initialize the ->data_interface field. */ | 4361 | /* Initialize the ->data_interface field. */ |
4362 | ret = nand_init_data_interface(chip); | 4362 | ret = nand_init_data_interface(chip); |
4363 | if (ret) | 4363 | if (ret) |
4364 | return ret; | 4364 | goto err_nand_init; |
4365 | 4365 | ||
4366 | /* | 4366 | /* |
4367 | * Setup the data interface correctly on the chip and controller side. | 4367 | * Setup the data interface correctly on the chip and controller side. |
@@ -4373,7 +4373,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
4373 | */ | 4373 | */ |
4374 | ret = nand_setup_data_interface(chip); | 4374 | ret = nand_setup_data_interface(chip); |
4375 | if (ret) | 4375 | if (ret) |
4376 | return ret; | 4376 | goto err_nand_init; |
4377 | 4377 | ||
4378 | nand_maf_id = chip->id.data[0]; | 4378 | nand_maf_id = chip->id.data[0]; |
4379 | nand_dev_id = chip->id.data[1]; | 4379 | nand_dev_id = chip->id.data[1]; |
@@ -4404,6 +4404,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
4404 | mtd->size = i * chip->chipsize; | 4404 | mtd->size = i * chip->chipsize; |
4405 | 4405 | ||
4406 | return 0; | 4406 | return 0; |
4407 | |||
4408 | err_nand_init: | ||
4409 | /* Free manufacturer priv data. */ | ||
4410 | nand_manufacturer_cleanup(chip); | ||
4411 | |||
4412 | return ret; | ||
4407 | } | 4413 | } |
4408 | EXPORT_SYMBOL(nand_scan_ident); | 4414 | EXPORT_SYMBOL(nand_scan_ident); |
4409 | 4415 | ||
@@ -4574,18 +4580,23 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
4574 | 4580 | ||
4575 | /* New bad blocks should be marked in OOB, flash-based BBT, or both */ | 4581 | /* New bad blocks should be marked in OOB, flash-based BBT, or both */ |
4576 | if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && | 4582 | if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && |
4577 | !(chip->bbt_options & NAND_BBT_USE_FLASH))) | 4583 | !(chip->bbt_options & NAND_BBT_USE_FLASH))) { |
4578 | return -EINVAL; | 4584 | ret = -EINVAL; |
4585 | goto err_ident; | ||
4586 | } | ||
4579 | 4587 | ||
4580 | if (invalid_ecc_page_accessors(chip)) { | 4588 | if (invalid_ecc_page_accessors(chip)) { |
4581 | pr_err("Invalid ECC page accessors setup\n"); | 4589 | pr_err("Invalid ECC page accessors setup\n"); |
4582 | return -EINVAL; | 4590 | ret = -EINVAL; |
4591 | goto err_ident; | ||
4583 | } | 4592 | } |
4584 | 4593 | ||
4585 | if (!(chip->options & NAND_OWN_BUFFERS)) { | 4594 | if (!(chip->options & NAND_OWN_BUFFERS)) { |
4586 | nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL); | 4595 | nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL); |
4587 | if (!nbuf) | 4596 | if (!nbuf) { |
4588 | return -ENOMEM; | 4597 | ret = -ENOMEM; |
4598 | goto err_ident; | ||
4599 | } | ||
4589 | 4600 | ||
4590 | nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL); | 4601 | nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL); |
4591 | if (!nbuf->ecccalc) { | 4602 | if (!nbuf->ecccalc) { |
@@ -4608,8 +4619,10 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
4608 | 4619 | ||
4609 | chip->buffers = nbuf; | 4620 | chip->buffers = nbuf; |
4610 | } else { | 4621 | } else { |
4611 | if (!chip->buffers) | 4622 | if (!chip->buffers) { |
4612 | return -ENOMEM; | 4623 | ret = -ENOMEM; |
4624 | goto err_ident; | ||
4625 | } | ||
4613 | } | 4626 | } |
4614 | 4627 | ||
4615 | /* Set the internal oob buffer location, just after the page data */ | 4628 | /* Set the internal oob buffer location, just after the page data */ |
@@ -4854,6 +4867,13 @@ err_free: | |||
4854 | kfree(nbuf->ecccalc); | 4867 | kfree(nbuf->ecccalc); |
4855 | kfree(nbuf); | 4868 | kfree(nbuf); |
4856 | } | 4869 | } |
4870 | |||
4871 | err_ident: | ||
4872 | /* Clean up nand_scan_ident(). */ | ||
4873 | |||
4874 | /* Free manufacturer priv data. */ | ||
4875 | nand_manufacturer_cleanup(chip); | ||
4876 | |||
4857 | return ret; | 4877 | return ret; |
4858 | } | 4878 | } |
4859 | EXPORT_SYMBOL(nand_scan_tail); | 4879 | EXPORT_SYMBOL(nand_scan_tail); |