diff options
author | Matias Bjørling <m@bjorling.me> | 2016-05-06 20:02:59 +0200 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-05-06 12:51:10 -0600 |
commit | 7f7c5d03c0e8e177d1ed1c6412ae035e8eff35de (patch) | |
tree | 1a354500001df077c63e14ba63c29fc43d375fcf /drivers/lightnvm | |
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')
-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) { struct nvm_id *id = &dev->identity; struct nvm_id_group *grp = &id->groups[0]; + int ret; /* device values */ dev->nr_chnls = grp->num_ch; @@ -522,33 +523,16 @@ static int nvm_core_init(struct nvm_dev *dev) dev->plane_mode = NVM_PLANE_SINGLE; dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; - if (grp->mtype != 0) { - pr_err("nvm: memory type not supported\n"); - return -EINVAL; - } - - switch (grp->fmtype) { - case NVM_ID_FMTYPE_SLC: - if (nvm_init_slc_tbl(dev, grp)) - return -ENOMEM; - break; - case NVM_ID_FMTYPE_MLC: - if (nvm_init_mlc_tbl(dev, grp)) - return -ENOMEM; - break; - default: - pr_err("nvm: flash type not supported\n"); - return -EINVAL; - } - - if (!dev->lps_per_blk) - pr_info("nvm: lower page programming table missing\n"); - if (grp->mpos & 0x020202) dev->plane_mode = NVM_PLANE_DOUBLE; if (grp->mpos & 0x040404) dev->plane_mode = NVM_PLANE_QUAD; + if (grp->mtype != 0) { + pr_err("nvm: memory type not supported\n"); + return -EINVAL; + } + /* calculated values */ dev->sec_per_pl = dev->sec_per_pg * dev->nr_planes; 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) sizeof(unsigned long), GFP_KERNEL); if (!dev->lun_map) return -ENOMEM; + + switch (grp->fmtype) { + case NVM_ID_FMTYPE_SLC: + if (nvm_init_slc_tbl(dev, grp)) { + ret = -ENOMEM; + goto err_fmtype; + } + break; + case NVM_ID_FMTYPE_MLC: + if (nvm_init_mlc_tbl(dev, grp)) { + ret = -ENOMEM; + goto err_fmtype; + } + break; + default: + pr_err("nvm: flash type not supported\n"); + ret = -EINVAL; + goto err_fmtype; + } + INIT_LIST_HEAD(&dev->online_targets); mutex_init(&dev->mlock); spin_lock_init(&dev->lock); return 0; +err_fmtype: + kfree(dev->lun_map); + return ret; } static void nvm_free(struct nvm_dev *dev) @@ -576,6 +583,7 @@ static void nvm_free(struct nvm_dev *dev) dev->mt->unregister_mgr(dev); kfree(dev->lptbl); + kfree(dev->lun_map); } static int nvm_init(struct nvm_dev *dev) @@ -705,7 +713,6 @@ void nvm_unregister(char *disk_name) up_write(&nvm_lock); nvm_exit(dev); - kfree(dev->lun_map); kfree(dev); } EXPORT_SYMBOL(nvm_unregister); |