summaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-12-04 00:45:16 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2015-12-04 00:45:16 +0100
commit2873d32ff493ecbfb7d2c7f56812ab941dda42f4 (patch)
treeaf8fb130771ed42f9995f16ac26a33ccf816d0a5 /drivers/lightnvm
parentMerge tag 'trace-v4.4-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/r... (diff)
parentnvme: temporary fix for Apple controller reset (diff)
downloadlinux-2873d32ff493ecbfb7d2c7f56812ab941dda42f4.tar.xz
linux-2873d32ff493ecbfb7d2c7f56812ab941dda42f4.zip
Merge branch 'for-linus' of git://git.kernel.dk/linux-block
Pull block fixes from Jens Axboe: "A collection of fixes from this series. The most important here is a regression fix for an issue that some folks would hit in blk-merge.c, and the NVMe queue depth limit for the screwed up Apple "nvme" controller. In more detail, this pull request contains: - a set of fixes for null_blk, including a fix for a few corner cases where we could hang the device. From Arianna and Paolo. - lightnvm: - A build improvement from Keith. - Update the qemu pci id detection from Matias. - Error handling fixes for leaks and other little fixes from Sudip and Wenwei. - fix from Eric where BLKRRPART would not return EBUSY for whole device mounts, only when partitions were mounted. - fix from Jan Kara, where EOF O_DIRECT reads would return negatively. - remove check for rq_mergeable() when checking limits for cloned requests. The check doesn't make any sense. It's assuming that since NOMERGE is set on the request that we don't have to recalculate limits since the request didn't change, but that's not true if the request has been redirected. From Hannes. - correctly get the bio front segment value set for single segment bio's, fixing a BUG() in blk-merge. From Ming" * 'for-linus' of git://git.kernel.dk/linux-block: nvme: temporary fix for Apple controller reset null_blk: change type of completion_nsec to unsigned long null_blk: guarantee device restart in all irq modes null_blk: set a separate timer for each command blk-merge: fix computing bio->bi_seg_front_size in case of single segment direct-io: Fix negative return from dio read beyond eof block: Always check queue limits for cloned requests lightnvm: missing nvm_lock acquire lightnvm: unconverted ppa returned in get_bb_tbl lightnvm: refactor and change vendor id for qemu lightnvm: do device max sectors boundary check first lightnvm: fix ioctl memory leaks lightnvm: free memory when gennvm register fails lightnvm: Simplify config when disabled Return EBUSY from BLKRRPART for mounted whole-dev fs
Diffstat (limited to 'drivers/lightnvm')
-rw-r--r--drivers/lightnvm/core.c94
-rw-r--r--drivers/lightnvm/gennvm.c18
2 files changed, 66 insertions, 46 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 5178645ac42b..86ce887b2ed6 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -123,6 +123,26 @@ void nvm_unregister_mgr(struct nvmm_type *mt)
}
EXPORT_SYMBOL(nvm_unregister_mgr);
+/* register with device with a supported manager */
+static int register_mgr(struct nvm_dev *dev)
+{
+ struct nvmm_type *mt;
+ int ret = 0;
+
+ list_for_each_entry(mt, &nvm_mgrs, list) {
+ ret = mt->register_mgr(dev);
+ if (ret > 0) {
+ dev->mt = mt;
+ break; /* successfully initialized */
+ }
+ }
+
+ if (!ret)
+ pr_info("nvm: no compatible nvm manager found.\n");
+
+ return ret;
+}
+
static struct nvm_dev *nvm_find_nvm_dev(const char *name)
{
struct nvm_dev *dev;
@@ -221,7 +241,6 @@ static void nvm_free(struct nvm_dev *dev)
static int nvm_init(struct nvm_dev *dev)
{
- struct nvmm_type *mt;
int ret = -EINVAL;
if (!dev->q || !dev->ops)
@@ -252,21 +271,13 @@ static int nvm_init(struct nvm_dev *dev)
goto err;
}
- /* register with device with a supported manager */
- list_for_each_entry(mt, &nvm_mgrs, list) {
- ret = mt->register_mgr(dev);
- if (ret < 0)
- goto err; /* initialization failed */
- if (ret > 0) {
- dev->mt = mt;
- break; /* successfully initialized */
- }
- }
-
- if (!ret) {
- pr_info("nvm: no compatible manager found.\n");
+ down_write(&nvm_lock);
+ ret = register_mgr(dev);
+ up_write(&nvm_lock);
+ if (ret < 0)
+ goto err;
+ if (!ret)
return 0;
- }
pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
dev->name, dev->sec_per_pg, dev->nr_planes,
@@ -308,6 +319,12 @@ int nvm_register(struct request_queue *q, char *disk_name,
if (ret)
goto err_init;
+ if (dev->ops->max_phys_sect > 256) {
+ pr_info("nvm: max sectors supported is 256.\n");
+ ret = -EINVAL;
+ goto err_init;
+ }
+
if (dev->ops->max_phys_sect > 1) {
dev->ppalist_pool = dev->ops->create_dma_pool(dev->q,
"ppalist");
@@ -316,10 +333,6 @@ int nvm_register(struct request_queue *q, char *disk_name,
ret = -ENOMEM;
goto err_init;
}
- } else if (dev->ops->max_phys_sect > 256) {
- pr_info("nvm: max sectors supported is 256.\n");
- ret = -EINVAL;
- goto err_init;
}
down_write(&nvm_lock);
@@ -335,15 +348,17 @@ EXPORT_SYMBOL(nvm_register);
void nvm_unregister(char *disk_name)
{
- struct nvm_dev *dev = nvm_find_nvm_dev(disk_name);
+ struct nvm_dev *dev;
+ down_write(&nvm_lock);
+ dev = nvm_find_nvm_dev(disk_name);
if (!dev) {
pr_err("nvm: could not find device %s to unregister\n",
disk_name);
+ up_write(&nvm_lock);
return;
}
- down_write(&nvm_lock);
list_del(&dev->devices);
up_write(&nvm_lock);
@@ -361,38 +376,30 @@ static int nvm_create_target(struct nvm_dev *dev,
{
struct nvm_ioctl_create_simple *s = &create->conf.s;
struct request_queue *tqueue;
- struct nvmm_type *mt;
struct gendisk *tdisk;
struct nvm_tgt_type *tt;
struct nvm_target *t;
void *targetdata;
int ret = 0;
+ down_write(&nvm_lock);
if (!dev->mt) {
- /* register with device with a supported NVM manager */
- list_for_each_entry(mt, &nvm_mgrs, list) {
- ret = mt->register_mgr(dev);
- if (ret < 0)
- return ret; /* initialization failed */
- if (ret > 0) {
- dev->mt = mt;
- break; /* successfully initialized */
- }
- }
-
- if (!ret) {
- pr_info("nvm: no compatible nvm manager found.\n");
- return -ENODEV;
+ ret = register_mgr(dev);
+ if (!ret)
+ ret = -ENODEV;
+ if (ret < 0) {
+ up_write(&nvm_lock);
+ return ret;
}
}
tt = nvm_find_target_type(create->tgttype);
if (!tt) {
pr_err("nvm: target type %s not found\n", create->tgttype);
+ up_write(&nvm_lock);
return -EINVAL;
}
- down_write(&nvm_lock);
list_for_each_entry(t, &dev->online_targets, list) {
if (!strcmp(create->tgtname, t->disk->disk_name)) {
pr_err("nvm: target name already exists.\n");
@@ -476,7 +483,9 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
struct nvm_dev *dev;
struct nvm_ioctl_create_simple *s;
+ down_write(&nvm_lock);
dev = nvm_find_nvm_dev(create->dev);
+ up_write(&nvm_lock);
if (!dev) {
pr_err("nvm: device not found\n");
return -EINVAL;
@@ -535,7 +544,9 @@ static int nvm_configure_show(const char *val)
return -EINVAL;
}
+ down_write(&nvm_lock);
dev = nvm_find_nvm_dev(devname);
+ up_write(&nvm_lock);
if (!dev) {
pr_err("nvm: device not found\n");
return -EINVAL;
@@ -680,8 +691,10 @@ static long nvm_ioctl_info(struct file *file, void __user *arg)
info->tgtsize = tgt_iter;
up_write(&nvm_lock);
- if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info)))
+ if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info))) {
+ kfree(info);
return -EFAULT;
+ }
kfree(info);
return 0;
@@ -724,8 +737,11 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg)
devices->nr_devices = i;
- if (copy_to_user(arg, devices, sizeof(struct nvm_ioctl_get_devices)))
+ if (copy_to_user(arg, devices,
+ sizeof(struct nvm_ioctl_get_devices))) {
+ kfree(devices);
return -EFAULT;
+ }
kfree(devices);
return 0;
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index e20e74ec6b91..35dde84b71e9 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -75,7 +75,6 @@ static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks,
struct nvm_block *blk;
int i;
- ppa = dev_to_generic_addr(gn->dev, ppa);
lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun];
for (i = 0; i < nr_blocks; i++) {
@@ -187,7 +186,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
ppa.g.lun = lun->vlun.id;
ppa = generic_to_dev_addr(dev, ppa);
- ret = dev->ops->get_bb_tbl(dev->q, ppa,
+ ret = dev->ops->get_bb_tbl(dev, ppa,
dev->blks_per_lun,
gennvm_block_bb, gn);
if (ret)
@@ -207,6 +206,14 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
return 0;
}
+static void gennvm_free(struct nvm_dev *dev)
+{
+ gennvm_blocks_free(dev);
+ gennvm_luns_free(dev);
+ kfree(dev->mp);
+ dev->mp = NULL;
+}
+
static int gennvm_register(struct nvm_dev *dev)
{
struct gen_nvm *gn;
@@ -234,16 +241,13 @@ static int gennvm_register(struct nvm_dev *dev)
return 1;
err:
- kfree(gn);
+ gennvm_free(dev);
return ret;
}
static void gennvm_unregister(struct nvm_dev *dev)
{
- gennvm_blocks_free(dev);
- gennvm_luns_free(dev);
- kfree(dev->mp);
- dev->mp = NULL;
+ gennvm_free(dev);
}
static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev,