aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/lightnvm/core.c41
-rw-r--r--include/linux/lightnvm.h1
2 files changed, 32 insertions, 10 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index e2abe88a139c..0e9f7996ff1d 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -45,6 +45,8 @@ struct nvm_dev_map {
45 int num_ch; 45 int num_ch;
46}; 46};
47 47
48static void nvm_free(struct kref *ref);
49
48static struct nvm_target *nvm_find_target(struct nvm_dev *dev, const char *name) 50static struct nvm_target *nvm_find_target(struct nvm_dev *dev, const char *name)
49{ 51{
50 struct nvm_target *tgt; 52 struct nvm_target *tgt;
@@ -501,6 +503,7 @@ static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
501 } 503 }
502 __nvm_remove_target(t, true); 504 __nvm_remove_target(t, true);
503 mutex_unlock(&dev->mlock); 505 mutex_unlock(&dev->mlock);
506 kref_put(&dev->ref, nvm_free);
504 507
505 return 0; 508 return 0;
506} 509}
@@ -1094,15 +1097,16 @@ err_fmtype:
1094 return ret; 1097 return ret;
1095} 1098}
1096 1099
1097static void nvm_free(struct nvm_dev *dev) 1100static void nvm_free(struct kref *ref)
1098{ 1101{
1099 if (!dev) 1102 struct nvm_dev *dev = container_of(ref, struct nvm_dev, ref);
1100 return;
1101 1103
1102 if (dev->dma_pool) 1104 if (dev->dma_pool)
1103 dev->ops->destroy_dma_pool(dev->dma_pool); 1105 dev->ops->destroy_dma_pool(dev->dma_pool);
1104 1106
1105 nvm_unregister_map(dev); 1107 if (dev->rmap)
1108 nvm_unregister_map(dev);
1109
1106 kfree(dev->lun_map); 1110 kfree(dev->lun_map);
1107 kfree(dev); 1111 kfree(dev);
1108} 1112}
@@ -1139,7 +1143,13 @@ err:
1139 1143
1140struct nvm_dev *nvm_alloc_dev(int node) 1144struct nvm_dev *nvm_alloc_dev(int node)
1141{ 1145{
1142 return kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node); 1146 struct nvm_dev *dev;
1147
1148 dev = kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
1149 if (dev)
1150 kref_init(&dev->ref);
1151
1152 return dev;
1143} 1153}
1144EXPORT_SYMBOL(nvm_alloc_dev); 1154EXPORT_SYMBOL(nvm_alloc_dev);
1145 1155
@@ -1147,12 +1157,16 @@ int nvm_register(struct nvm_dev *dev)
1147{ 1157{
1148 int ret, exp_pool_size; 1158 int ret, exp_pool_size;
1149 1159
1150 if (!dev->q || !dev->ops) 1160 if (!dev->q || !dev->ops) {
1161 kref_put(&dev->ref, nvm_free);
1151 return -EINVAL; 1162 return -EINVAL;
1163 }
1152 1164
1153 ret = nvm_init(dev); 1165 ret = nvm_init(dev);
1154 if (ret) 1166 if (ret) {
1167 kref_put(&dev->ref, nvm_free);
1155 return ret; 1168 return ret;
1169 }
1156 1170
1157 exp_pool_size = max_t(int, PAGE_SIZE, 1171 exp_pool_size = max_t(int, PAGE_SIZE,
1158 (NVM_MAX_VLBA * (sizeof(u64) + dev->geo.sos))); 1172 (NVM_MAX_VLBA * (sizeof(u64) + dev->geo.sos)));
@@ -1162,7 +1176,7 @@ int nvm_register(struct nvm_dev *dev)
1162 exp_pool_size); 1176 exp_pool_size);
1163 if (!dev->dma_pool) { 1177 if (!dev->dma_pool) {
1164 pr_err("nvm: could not create dma pool\n"); 1178 pr_err("nvm: could not create dma pool\n");
1165 nvm_free(dev); 1179 kref_put(&dev->ref, nvm_free);
1166 return -ENOMEM; 1180 return -ENOMEM;
1167 } 1181 }
1168 1182
@@ -1184,6 +1198,7 @@ void nvm_unregister(struct nvm_dev *dev)
1184 if (t->dev->parent != dev) 1198 if (t->dev->parent != dev)
1185 continue; 1199 continue;
1186 __nvm_remove_target(t, false); 1200 __nvm_remove_target(t, false);
1201 kref_put(&dev->ref, nvm_free);
1187 } 1202 }
1188 mutex_unlock(&dev->mlock); 1203 mutex_unlock(&dev->mlock);
1189 1204
@@ -1191,13 +1206,14 @@ void nvm_unregister(struct nvm_dev *dev)
1191 list_del(&dev->devices); 1206 list_del(&dev->devices);
1192 up_write(&nvm_lock); 1207 up_write(&nvm_lock);
1193 1208
1194 nvm_free(dev); 1209 kref_put(&dev->ref, nvm_free);
1195} 1210}
1196EXPORT_SYMBOL(nvm_unregister); 1211EXPORT_SYMBOL(nvm_unregister);
1197 1212
1198static int __nvm_configure_create(struct nvm_ioctl_create *create) 1213static int __nvm_configure_create(struct nvm_ioctl_create *create)
1199{ 1214{
1200 struct nvm_dev *dev; 1215 struct nvm_dev *dev;
1216 int ret;
1201 1217
1202 down_write(&nvm_lock); 1218 down_write(&nvm_lock);
1203 dev = nvm_find_nvm_dev(create->dev); 1219 dev = nvm_find_nvm_dev(create->dev);
@@ -1208,7 +1224,12 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
1208 return -EINVAL; 1224 return -EINVAL;
1209 } 1225 }
1210 1226
1211 return nvm_create_tgt(dev, create); 1227 kref_get(&dev->ref);
1228 ret = nvm_create_tgt(dev, create);
1229 if (ret)
1230 kref_put(&dev->ref, nvm_free);
1231
1232 return ret;
1212} 1233}
1213 1234
1214static long nvm_ioctl_info(struct file *file, void __user *arg) 1235static long nvm_ioctl_info(struct file *file, void __user *arg)
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index d3b02708e5f0..4d0d5655c7b2 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -428,6 +428,7 @@ struct nvm_dev {
428 char name[DISK_NAME_LEN]; 428 char name[DISK_NAME_LEN];
429 void *private_data; 429 void *private_data;
430 430
431 struct kref ref;
431 void *rmap; 432 void *rmap;
432 433
433 struct mutex mlock; 434 struct mutex mlock;