aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Konopko <igor.j.konopko@intel.com>2019-05-04 14:38:09 -0400
committerJens Axboe <axboe@kernel.dk>2019-05-06 12:19:19 -0400
commit843f2edbdde085b4d2764baf6fd8a1fccb1ab26a (patch)
treeed19a493affd72fbfafbc763cf3149f0d441aa7c
parente69397ea05ce0263e3ee72fa8f6f70d2d9a561a7 (diff)
lightnvm: do not remove instance under global lock
Currently all the target instances are removed under global nvm_lock. This was needed to ensure that nvm_dev struct will not be freed by hot unplug event during target removal. However, current implementation has some drawbacks, since the same lock is used when new nvme subsystem is registered, so we can have a situation, that due to long process of target removal on drive A, registration (and listing in OS) of the drive B will take a lot of time, since it will wait for that lock. Now when we have kref which ensures that nvm_dev will not be freed in the meantime, we can easily get rid of this lock for a time when we are removing nvm targets. Signed-off-by: Igor Konopko <igor.j.konopko@intel.com> Reviewed-by: Javier González <javier@javigon.com> Signed-off-by: Matias Bjørling <mb@lightnvm.io> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/lightnvm/core.c34
1 files changed, 16 insertions, 18 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 0e9f7996ff1d..0df7454832ef 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -483,7 +483,6 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful)
483 483
484/** 484/**
485 * nvm_remove_tgt - Removes a target from the media manager 485 * nvm_remove_tgt - Removes a target from the media manager
486 * @dev: device
487 * @remove: ioctl structure with target name to remove. 486 * @remove: ioctl structure with target name to remove.
488 * 487 *
489 * Returns: 488 * Returns:
@@ -491,18 +490,27 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful)
491 * 1: on not found 490 * 1: on not found
492 * <0: on error 491 * <0: on error
493 */ 492 */
494static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove) 493static int nvm_remove_tgt(struct nvm_ioctl_remove *remove)
495{ 494{
496 struct nvm_target *t; 495 struct nvm_target *t;
496 struct nvm_dev *dev;
497 497
498 mutex_lock(&dev->mlock); 498 down_read(&nvm_lock);
499 t = nvm_find_target(dev, remove->tgtname); 499 list_for_each_entry(dev, &nvm_devices, devices) {
500 if (!t) { 500 mutex_lock(&dev->mlock);
501 t = nvm_find_target(dev, remove->tgtname);
502 if (t) {
503 mutex_unlock(&dev->mlock);
504 break;
505 }
501 mutex_unlock(&dev->mlock); 506 mutex_unlock(&dev->mlock);
502 return 1;
503 } 507 }
508 up_read(&nvm_lock);
509
510 if (!t)
511 return 1;
512
504 __nvm_remove_target(t, true); 513 __nvm_remove_target(t, true);
505 mutex_unlock(&dev->mlock);
506 kref_put(&dev->ref, nvm_free); 514 kref_put(&dev->ref, nvm_free);
507 515
508 return 0; 516 return 0;
@@ -1348,8 +1356,6 @@ static long nvm_ioctl_dev_create(struct file *file, void __user *arg)
1348static long nvm_ioctl_dev_remove(struct file *file, void __user *arg) 1356static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
1349{ 1357{
1350 struct nvm_ioctl_remove remove; 1358 struct nvm_ioctl_remove remove;
1351 struct nvm_dev *dev;
1352 int ret = 0;
1353 1359
1354 if (copy_from_user(&remove, arg, sizeof(struct nvm_ioctl_remove))) 1360 if (copy_from_user(&remove, arg, sizeof(struct nvm_ioctl_remove)))
1355 return -EFAULT; 1361 return -EFAULT;
@@ -1361,15 +1367,7 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
1361 return -EINVAL; 1367 return -EINVAL;
1362 } 1368 }
1363 1369
1364 down_read(&nvm_lock); 1370 return nvm_remove_tgt(&remove);
1365 list_for_each_entry(dev, &nvm_devices, devices) {
1366 ret = nvm_remove_tgt(dev, &remove);
1367 if (!ret)
1368 break;
1369 }
1370 up_read(&nvm_lock);
1371
1372 return ret;
1373} 1371}
1374 1372
1375/* kept for compatibility reasons */ 1373/* kept for compatibility reasons */