Commit 7f7c5d03 authored by Matias Bjørling's avatar Matias Bjørling Committed by Jens Axboe

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: default avatarMatias Bjørling <m@bjorling.me>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 22e8c976
...@@ -504,6 +504,7 @@ static int nvm_core_init(struct nvm_dev *dev) ...@@ -504,6 +504,7 @@ static int nvm_core_init(struct nvm_dev *dev)
{ {
struct nvm_id *id = &dev->identity; struct nvm_id *id = &dev->identity;
struct nvm_id_group *grp = &id->groups[0]; struct nvm_id_group *grp = &id->groups[0];
int ret;
/* device values */ /* device values */
dev->nr_chnls = grp->num_ch; dev->nr_chnls = grp->num_ch;
...@@ -522,33 +523,16 @@ static int nvm_core_init(struct nvm_dev *dev) ...@@ -522,33 +523,16 @@ static int nvm_core_init(struct nvm_dev *dev)
dev->plane_mode = NVM_PLANE_SINGLE; dev->plane_mode = NVM_PLANE_SINGLE;
dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; 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) if (grp->mpos & 0x020202)
dev->plane_mode = NVM_PLANE_DOUBLE; dev->plane_mode = NVM_PLANE_DOUBLE;
if (grp->mpos & 0x040404) if (grp->mpos & 0x040404)
dev->plane_mode = NVM_PLANE_QUAD; dev->plane_mode = NVM_PLANE_QUAD;
if (grp->mtype != 0) {
pr_err("nvm: memory type not supported\n");
return -EINVAL;
}
/* calculated values */ /* calculated values */
dev->sec_per_pl = dev->sec_per_pg * dev->nr_planes; dev->sec_per_pl = dev->sec_per_pg * dev->nr_planes;
dev->sec_per_blk = dev->sec_per_pl * dev->pgs_per_blk; 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,11 +544,34 @@ static int nvm_core_init(struct nvm_dev *dev)
sizeof(unsigned long), GFP_KERNEL); sizeof(unsigned long), GFP_KERNEL);
if (!dev->lun_map) if (!dev->lun_map)
return -ENOMEM; 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); INIT_LIST_HEAD(&dev->online_targets);
mutex_init(&dev->mlock); mutex_init(&dev->mlock);
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
return 0; return 0;
err_fmtype:
kfree(dev->lun_map);
return ret;
} }
static void nvm_free(struct nvm_dev *dev) static void nvm_free(struct nvm_dev *dev)
...@@ -576,6 +583,7 @@ 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); dev->mt->unregister_mgr(dev);
kfree(dev->lptbl); kfree(dev->lptbl);
kfree(dev->lun_map);
} }
static int nvm_init(struct nvm_dev *dev) static int nvm_init(struct nvm_dev *dev)
...@@ -705,7 +713,6 @@ void nvm_unregister(char *disk_name) ...@@ -705,7 +713,6 @@ void nvm_unregister(char *disk_name)
up_write(&nvm_lock); up_write(&nvm_lock);
nvm_exit(dev); nvm_exit(dev);
kfree(dev->lun_map);
kfree(dev); kfree(dev);
} }
EXPORT_SYMBOL(nvm_unregister); EXPORT_SYMBOL(nvm_unregister);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment