aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm
diff options
context:
space:
mode:
authorWenwei Tao <ww.tao0320@gmail.com>2015-11-28 10:49:28 -0500
committerJens Axboe <axboe@fb.com>2015-11-29 16:34:58 -0500
commitd0a712ceb83ebaea32d520825ee7b997f59b168f (patch)
tree33c141fe3d4555f86af8eb7275e29e11a1c524d8 /drivers/lightnvm
parent08236c6bb2980561fba657c58fdc76f2865f236c (diff)
lightnvm: missing nvm_lock acquire
To avoid race conditions, traverse dev, media manager, and target lists and also register, unregister entries to/from them, should be always under the nvm_lock control. Signed-off-by: Wenwei Tao <ww.tao0320@gmail.com> 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.c75
1 files changed, 42 insertions, 33 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index ea6dba530f0a..86ce887b2ed6 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -123,6 +123,26 @@ void nvm_unregister_mgr(struct nvmm_type *mt)
123} 123}
124EXPORT_SYMBOL(nvm_unregister_mgr); 124EXPORT_SYMBOL(nvm_unregister_mgr);
125 125
126/* register with device with a supported manager */
127static int register_mgr(struct nvm_dev *dev)
128{
129 struct nvmm_type *mt;
130 int ret = 0;
131
132 list_for_each_entry(mt, &nvm_mgrs, list) {
133 ret = mt->register_mgr(dev);
134 if (ret > 0) {
135 dev->mt = mt;
136 break; /* successfully initialized */
137 }
138 }
139
140 if (!ret)
141 pr_info("nvm: no compatible nvm manager found.\n");
142
143 return ret;
144}
145
126static struct nvm_dev *nvm_find_nvm_dev(const char *name) 146static struct nvm_dev *nvm_find_nvm_dev(const char *name)
127{ 147{
128 struct nvm_dev *dev; 148 struct nvm_dev *dev;
@@ -221,7 +241,6 @@ static void nvm_free(struct nvm_dev *dev)
221 241
222static int nvm_init(struct nvm_dev *dev) 242static int nvm_init(struct nvm_dev *dev)
223{ 243{
224 struct nvmm_type *mt;
225 int ret = -EINVAL; 244 int ret = -EINVAL;
226 245
227 if (!dev->q || !dev->ops) 246 if (!dev->q || !dev->ops)
@@ -252,21 +271,13 @@ static int nvm_init(struct nvm_dev *dev)
252 goto err; 271 goto err;
253 } 272 }
254 273
255 /* register with device with a supported manager */ 274 down_write(&nvm_lock);
256 list_for_each_entry(mt, &nvm_mgrs, list) { 275 ret = register_mgr(dev);
257 ret = mt->register_mgr(dev); 276 up_write(&nvm_lock);
258 if (ret < 0) 277 if (ret < 0)
259 goto err; /* initialization failed */ 278 goto err;
260 if (ret > 0) { 279 if (!ret)
261 dev->mt = mt;
262 break; /* successfully initialized */
263 }
264 }
265
266 if (!ret) {
267 pr_info("nvm: no compatible manager found.\n");
268 return 0; 280 return 0;
269 }
270 281
271 pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n", 282 pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
272 dev->name, dev->sec_per_pg, dev->nr_planes, 283 dev->name, dev->sec_per_pg, dev->nr_planes,
@@ -337,15 +348,17 @@ EXPORT_SYMBOL(nvm_register);
337 348
338void nvm_unregister(char *disk_name) 349void nvm_unregister(char *disk_name)
339{ 350{
340 struct nvm_dev *dev = nvm_find_nvm_dev(disk_name); 351 struct nvm_dev *dev;
341 352
353 down_write(&nvm_lock);
354 dev = nvm_find_nvm_dev(disk_name);
342 if (!dev) { 355 if (!dev) {
343 pr_err("nvm: could not find device %s to unregister\n", 356 pr_err("nvm: could not find device %s to unregister\n",
344 disk_name); 357 disk_name);
358 up_write(&nvm_lock);
345 return; 359 return;
346 } 360 }
347 361
348 down_write(&nvm_lock);
349 list_del(&dev->devices); 362 list_del(&dev->devices);
350 up_write(&nvm_lock); 363 up_write(&nvm_lock);
351 364
@@ -363,38 +376,30 @@ static int nvm_create_target(struct nvm_dev *dev,
363{ 376{
364 struct nvm_ioctl_create_simple *s = &create->conf.s; 377 struct nvm_ioctl_create_simple *s = &create->conf.s;
365 struct request_queue *tqueue; 378 struct request_queue *tqueue;
366 struct nvmm_type *mt;
367 struct gendisk *tdisk; 379 struct gendisk *tdisk;
368 struct nvm_tgt_type *tt; 380 struct nvm_tgt_type *tt;
369 struct nvm_target *t; 381 struct nvm_target *t;
370 void *targetdata; 382 void *targetdata;
371 int ret = 0; 383 int ret = 0;
372 384
385 down_write(&nvm_lock);
373 if (!dev->mt) { 386 if (!dev->mt) {
374 /* register with device with a supported NVM manager */ 387 ret = register_mgr(dev);
375 list_for_each_entry(mt, &nvm_mgrs, list) { 388 if (!ret)
376 ret = mt->register_mgr(dev); 389 ret = -ENODEV;
377 if (ret < 0) 390 if (ret < 0) {
378 return ret; /* initialization failed */ 391 up_write(&nvm_lock);
379 if (ret > 0) { 392 return ret;
380 dev->mt = mt;
381 break; /* successfully initialized */
382 }
383 }
384
385 if (!ret) {
386 pr_info("nvm: no compatible nvm manager found.\n");
387 return -ENODEV;
388 } 393 }
389 } 394 }
390 395
391 tt = nvm_find_target_type(create->tgttype); 396 tt = nvm_find_target_type(create->tgttype);
392 if (!tt) { 397 if (!tt) {
393 pr_err("nvm: target type %s not found\n", create->tgttype); 398 pr_err("nvm: target type %s not found\n", create->tgttype);
399 up_write(&nvm_lock);
394 return -EINVAL; 400 return -EINVAL;
395 } 401 }
396 402
397 down_write(&nvm_lock);
398 list_for_each_entry(t, &dev->online_targets, list) { 403 list_for_each_entry(t, &dev->online_targets, list) {
399 if (!strcmp(create->tgtname, t->disk->disk_name)) { 404 if (!strcmp(create->tgtname, t->disk->disk_name)) {
400 pr_err("nvm: target name already exists.\n"); 405 pr_err("nvm: target name already exists.\n");
@@ -478,7 +483,9 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
478 struct nvm_dev *dev; 483 struct nvm_dev *dev;
479 struct nvm_ioctl_create_simple *s; 484 struct nvm_ioctl_create_simple *s;
480 485
486 down_write(&nvm_lock);
481 dev = nvm_find_nvm_dev(create->dev); 487 dev = nvm_find_nvm_dev(create->dev);
488 up_write(&nvm_lock);
482 if (!dev) { 489 if (!dev) {
483 pr_err("nvm: device not found\n"); 490 pr_err("nvm: device not found\n");
484 return -EINVAL; 491 return -EINVAL;
@@ -537,7 +544,9 @@ static int nvm_configure_show(const char *val)
537 return -EINVAL; 544 return -EINVAL;
538 } 545 }
539 546
547 down_write(&nvm_lock);
540 dev = nvm_find_nvm_dev(devname); 548 dev = nvm_find_nvm_dev(devname);
549 up_write(&nvm_lock);
541 if (!dev) { 550 if (!dev) {
542 pr_err("nvm: device not found\n"); 551 pr_err("nvm: device not found\n");
543 return -EINVAL; 552 return -EINVAL;