diff options
author | Matias Bjørling <m@bjorling.me> | 2016-05-06 14:02:59 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-05-06 14:51:10 -0400 |
commit | 7f7c5d03c0e8e177d1ed1c6412ae035e8eff35de (patch) | |
tree | 1a354500001df077c63e14ba63c29fc43d375fcf /drivers/lightnvm/core.c | |
parent | 22e8c9766a669d49cf3749d397082a5cd93374a9 (diff) |
lightnvm: avoid memory leak when lun_map kcalloc fails
A memory leak occurs if the lower page table is initialized and the
following dev->lun_map fails on allocation.
Rearrange the initialization of lower page table to allow dev->lun_map
to fail gracefully without memory leak.
Reviewed by: Johannes Thumshirn <jthumshirn@suse.de>
Move kfree of dev->lun_map to nvm_free()
Signed-off-by: Matias Bjørling <m@bjorling.me>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/lightnvm/core.c')
-rw-r--r-- | drivers/lightnvm/core.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 4cadbe0cd537..74fb049e0b83 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c | |||
@@ -504,6 +504,7 @@ static int nvm_core_init(struct nvm_dev *dev) | |||
504 | { | 504 | { |
505 | struct nvm_id *id = &dev->identity; | 505 | struct nvm_id *id = &dev->identity; |
506 | struct nvm_id_group *grp = &id->groups[0]; | 506 | struct nvm_id_group *grp = &id->groups[0]; |
507 | int ret; | ||
507 | 508 | ||
508 | /* device values */ | 509 | /* device values */ |
509 | dev->nr_chnls = grp->num_ch; | 510 | dev->nr_chnls = grp->num_ch; |
@@ -522,33 +523,16 @@ static int nvm_core_init(struct nvm_dev *dev) | |||
522 | dev->plane_mode = NVM_PLANE_SINGLE; | 523 | dev->plane_mode = NVM_PLANE_SINGLE; |
523 | dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; | 524 | dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; |
524 | 525 | ||
525 | if (grp->mtype != 0) { | ||
526 | pr_err("nvm: memory type not supported\n"); | ||
527 | return -EINVAL; | ||
528 | } | ||
529 | |||
530 | switch (grp->fmtype) { | ||
531 | case NVM_ID_FMTYPE_SLC: | ||
532 | if (nvm_init_slc_tbl(dev, grp)) | ||
533 | return -ENOMEM; | ||
534 | break; | ||
535 | case NVM_ID_FMTYPE_MLC: | ||
536 | if (nvm_init_mlc_tbl(dev, grp)) | ||
537 | return -ENOMEM; | ||
538 | break; | ||
539 | default: | ||
540 | pr_err("nvm: flash type not supported\n"); | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | |||
544 | if (!dev->lps_per_blk) | ||
545 | pr_info("nvm: lower page programming table missing\n"); | ||
546 | |||
547 | if (grp->mpos & 0x020202) | 526 | if (grp->mpos & 0x020202) |
548 | dev->plane_mode = NVM_PLANE_DOUBLE; | 527 | dev->plane_mode = NVM_PLANE_DOUBLE; |
549 | if (grp->mpos & 0x040404) | 528 | if (grp->mpos & 0x040404) |
550 | dev->plane_mode = NVM_PLANE_QUAD; | 529 | dev->plane_mode = NVM_PLANE_QUAD; |
551 | 530 | ||
531 | if (grp->mtype != 0) { | ||
532 | pr_err("nvm: memory type not supported\n"); | ||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
552 | /* calculated values */ | 536 | /* calculated values */ |
553 | dev->sec_per_pl = dev->sec_per_pg * dev->nr_planes; | 537 | dev->sec_per_pl = dev->sec_per_pg * dev->nr_planes; |
554 | dev->sec_per_blk = dev->sec_per_pl * dev->pgs_per_blk; | 538 | dev->sec_per_blk = dev->sec_per_pl * dev->pgs_per_blk; |
@@ -560,11 +544,34 @@ static int nvm_core_init(struct nvm_dev *dev) | |||
560 | sizeof(unsigned long), GFP_KERNEL); | 544 | sizeof(unsigned long), GFP_KERNEL); |
561 | if (!dev->lun_map) | 545 | if (!dev->lun_map) |
562 | return -ENOMEM; | 546 | return -ENOMEM; |
547 | |||
548 | switch (grp->fmtype) { | ||
549 | case NVM_ID_FMTYPE_SLC: | ||
550 | if (nvm_init_slc_tbl(dev, grp)) { | ||
551 | ret = -ENOMEM; | ||
552 | goto err_fmtype; | ||
553 | } | ||
554 | break; | ||
555 | case NVM_ID_FMTYPE_MLC: | ||
556 | if (nvm_init_mlc_tbl(dev, grp)) { | ||
557 | ret = -ENOMEM; | ||
558 | goto err_fmtype; | ||
559 | } | ||
560 | break; | ||
561 | default: | ||
562 | pr_err("nvm: flash type not supported\n"); | ||
563 | ret = -EINVAL; | ||
564 | goto err_fmtype; | ||
565 | } | ||
566 | |||
563 | INIT_LIST_HEAD(&dev->online_targets); | 567 | INIT_LIST_HEAD(&dev->online_targets); |
564 | mutex_init(&dev->mlock); | 568 | mutex_init(&dev->mlock); |
565 | spin_lock_init(&dev->lock); | 569 | spin_lock_init(&dev->lock); |
566 | 570 | ||
567 | return 0; | 571 | return 0; |
572 | err_fmtype: | ||
573 | kfree(dev->lun_map); | ||
574 | return ret; | ||
568 | } | 575 | } |
569 | 576 | ||
570 | static void nvm_free(struct nvm_dev *dev) | 577 | static void nvm_free(struct nvm_dev *dev) |
@@ -576,6 +583,7 @@ static void nvm_free(struct nvm_dev *dev) | |||
576 | dev->mt->unregister_mgr(dev); | 583 | dev->mt->unregister_mgr(dev); |
577 | 584 | ||
578 | kfree(dev->lptbl); | 585 | kfree(dev->lptbl); |
586 | kfree(dev->lun_map); | ||
579 | } | 587 | } |
580 | 588 | ||
581 | static int nvm_init(struct nvm_dev *dev) | 589 | static int nvm_init(struct nvm_dev *dev) |
@@ -705,7 +713,6 @@ void nvm_unregister(char *disk_name) | |||
705 | up_write(&nvm_lock); | 713 | up_write(&nvm_lock); |
706 | 714 | ||
707 | nvm_exit(dev); | 715 | nvm_exit(dev); |
708 | kfree(dev->lun_map); | ||
709 | kfree(dev); | 716 | kfree(dev); |
710 | } | 717 | } |
711 | EXPORT_SYMBOL(nvm_unregister); | 718 | EXPORT_SYMBOL(nvm_unregister); |