summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWenwei Tao <ww.tao0320@gmail.com>2016-03-03 09:06:38 -0500
committerJens Axboe <axboe@fb.com>2016-03-18 21:10:38 -0400
commitda1e284919b0b99c5bf0618b6c98cbaf2c17e62e (patch)
treeef1d8fe8821376dd57fbd4d3319a747841df38e6
parent4c9dacb82d5aa36aa2568df60d897f2eb3d8819b (diff)
lightnvm: add a bitmap of luns
Add a bitmap of luns to indicate the status of luns: inuse/available. When create targets do the necessary check to avoid allocating luns that are already allocated. Signed-off-by: Wenwei Tao <ww.tao0320@gmail.com> Freed dev->lun_map if nvm_core_init later failed in the init process. Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/lightnvm/core.c6
-rw-r--r--drivers/lightnvm/gennvm.c18
-rw-r--r--drivers/lightnvm/rrpc.c74
-rw-r--r--include/linux/lightnvm.h5
4 files changed, 74 insertions, 29 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 2925fd0b82bb..0dc9a80adb94 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -464,6 +464,10 @@ static int nvm_core_init(struct nvm_dev *dev)
464 dev->nr_luns = dev->luns_per_chnl * dev->nr_chnls; 464 dev->nr_luns = dev->luns_per_chnl * dev->nr_chnls;
465 465
466 dev->total_secs = dev->nr_luns * dev->sec_per_lun; 466 dev->total_secs = dev->nr_luns * dev->sec_per_lun;
467 dev->lun_map = kcalloc(BITS_TO_LONGS(dev->nr_luns),
468 sizeof(unsigned long), GFP_KERNEL);
469 if (!dev->lun_map)
470 return -ENOMEM;
467 INIT_LIST_HEAD(&dev->online_targets); 471 INIT_LIST_HEAD(&dev->online_targets);
468 mutex_init(&dev->mlock); 472 mutex_init(&dev->mlock);
469 spin_lock_init(&dev->lock); 473 spin_lock_init(&dev->lock);
@@ -586,6 +590,7 @@ int nvm_register(struct request_queue *q, char *disk_name,
586 590
587 return 0; 591 return 0;
588err_init: 592err_init:
593 kfree(dev->lun_map);
589 kfree(dev); 594 kfree(dev);
590 return ret; 595 return ret;
591} 596}
@@ -608,6 +613,7 @@ void nvm_unregister(char *disk_name)
608 up_write(&nvm_lock); 613 up_write(&nvm_lock);
609 614
610 nvm_exit(dev); 615 nvm_exit(dev);
616 kfree(dev->lun_map);
611 kfree(dev); 617 kfree(dev);
612} 618}
613EXPORT_SYMBOL(nvm_unregister); 619EXPORT_SYMBOL(nvm_unregister);
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index d460b37bb016..b97801c00099 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -192,6 +192,9 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
192 lun_id = div_u64(pba, dev->sec_per_lun); 192 lun_id = div_u64(pba, dev->sec_per_lun);
193 lun = &gn->luns[lun_id]; 193 lun = &gn->luns[lun_id];
194 194
195 if (!test_bit(lun_id, dev->lun_map))
196 __set_bit(lun_id, dev->lun_map);
197
195 /* Calculate block offset into lun */ 198 /* Calculate block offset into lun */
196 pba = pba - (dev->sec_per_lun * lun_id); 199 pba = pba - (dev->sec_per_lun * lun_id);
197 blk = &lun->vlun.blocks[div_u64(pba, dev->sec_per_blk)]; 200 blk = &lun->vlun.blocks[div_u64(pba, dev->sec_per_blk)];
@@ -482,10 +485,23 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
482 return nvm_erase_ppa(dev, &addr, 1); 485 return nvm_erase_ppa(dev, &addr, 1);
483} 486}
484 487
488static int gennvm_reserve_lun(struct nvm_dev *dev, int lunid)
489{
490 return test_and_set_bit(lunid, dev->lun_map);
491}
492
493static void gennvm_release_lun(struct nvm_dev *dev, int lunid)
494{
495 WARN_ON(!test_and_clear_bit(lunid, dev->lun_map));
496}
497
485static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid) 498static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
486{ 499{
487 struct gen_nvm *gn = dev->mp; 500 struct gen_nvm *gn = dev->mp;
488 501
502 if (unlikely(lunid >= dev->nr_luns))
503 return NULL;
504
489 return &gn->luns[lunid].vlun; 505 return &gn->luns[lunid].vlun;
490} 506}
491 507
@@ -527,6 +543,8 @@ static struct nvmm_type gennvm = {
527 .erase_blk = gennvm_erase_blk, 543 .erase_blk = gennvm_erase_blk,
528 544
529 .get_lun = gennvm_get_lun, 545 .get_lun = gennvm_get_lun,
546 .reserve_lun = gennvm_reserve_lun,
547 .release_lun = gennvm_release_lun,
530 .lun_info_print = gennvm_lun_info_print, 548 .lun_info_print = gennvm_lun_info_print,
531 549
532 .get_area = gennvm_get_area, 550 .get_area = gennvm_get_area,
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
index c1e3c83f06b3..3ab6495c3fd8 100644
--- a/drivers/lightnvm/rrpc.c
+++ b/drivers/lightnvm/rrpc.c
@@ -965,25 +965,11 @@ static void rrpc_requeue(struct work_struct *work)
965 965
966static void rrpc_gc_free(struct rrpc *rrpc) 966static void rrpc_gc_free(struct rrpc *rrpc)
967{ 967{
968 struct rrpc_lun *rlun;
969 int i;
970
971 if (rrpc->krqd_wq) 968 if (rrpc->krqd_wq)
972 destroy_workqueue(rrpc->krqd_wq); 969 destroy_workqueue(rrpc->krqd_wq);
973 970
974 if (rrpc->kgc_wq) 971 if (rrpc->kgc_wq)
975 destroy_workqueue(rrpc->kgc_wq); 972 destroy_workqueue(rrpc->kgc_wq);
976
977 if (!rrpc->luns)
978 return;
979
980 for (i = 0; i < rrpc->nr_luns; i++) {
981 rlun = &rrpc->luns[i];
982
983 if (!rlun->blocks)
984 break;
985 vfree(rlun->blocks);
986 }
987} 973}
988 974
989static int rrpc_gc_init(struct rrpc *rrpc) 975static int rrpc_gc_init(struct rrpc *rrpc)
@@ -1143,6 +1129,23 @@ static void rrpc_core_free(struct rrpc *rrpc)
1143 1129
1144static void rrpc_luns_free(struct rrpc *rrpc) 1130static void rrpc_luns_free(struct rrpc *rrpc)
1145{ 1131{
1132 struct nvm_dev *dev = rrpc->dev;
1133 struct nvm_lun *lun;
1134 struct rrpc_lun *rlun;
1135 int i;
1136
1137 if (!rrpc->luns)
1138 return;
1139
1140 for (i = 0; i < rrpc->nr_luns; i++) {
1141 rlun = &rrpc->luns[i];
1142 lun = rlun->parent;
1143 if (!lun)
1144 break;
1145 dev->mt->release_lun(dev, lun->id);
1146 vfree(rlun->blocks);
1147 }
1148
1146 kfree(rrpc->luns); 1149 kfree(rrpc->luns);
1147} 1150}
1148 1151
@@ -1150,7 +1153,7 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
1150{ 1153{
1151 struct nvm_dev *dev = rrpc->dev; 1154 struct nvm_dev *dev = rrpc->dev;
1152 struct rrpc_lun *rlun; 1155 struct rrpc_lun *rlun;
1153 int i, j; 1156 int i, j, ret = -EINVAL;
1154 1157
1155 if (dev->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) { 1158 if (dev->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
1156 pr_err("rrpc: number of pages per block too high."); 1159 pr_err("rrpc: number of pages per block too high.");
@@ -1166,25 +1169,26 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
1166 1169
1167 /* 1:1 mapping */ 1170 /* 1:1 mapping */
1168 for (i = 0; i < rrpc->nr_luns; i++) { 1171 for (i = 0; i < rrpc->nr_luns; i++) {
1169 struct nvm_lun *lun = dev->mt->get_lun(dev, lun_begin + i); 1172 int lunid = lun_begin + i;
1170 1173 struct nvm_lun *lun;
1171 rlun = &rrpc->luns[i];
1172 rlun->rrpc = rrpc;
1173 rlun->parent = lun;
1174 INIT_LIST_HEAD(&rlun->prio_list);
1175 INIT_LIST_HEAD(&rlun->open_list);
1176 INIT_LIST_HEAD(&rlun->closed_list);
1177 1174
1178 INIT_WORK(&rlun->ws_gc, rrpc_lun_gc); 1175 if (dev->mt->reserve_lun(dev, lunid)) {
1179 spin_lock_init(&rlun->lock); 1176 pr_err("rrpc: lun %u is already allocated\n", lunid);
1177 goto err;
1178 }
1180 1179
1181 rrpc->total_blocks += dev->blks_per_lun; 1180 lun = dev->mt->get_lun(dev, lunid);
1182 rrpc->nr_sects += dev->sec_per_lun; 1181 if (!lun)
1182 goto err;
1183 1183
1184 rlun = &rrpc->luns[i];
1185 rlun->parent = lun;
1184 rlun->blocks = vzalloc(sizeof(struct rrpc_block) * 1186 rlun->blocks = vzalloc(sizeof(struct rrpc_block) *
1185 rrpc->dev->blks_per_lun); 1187 rrpc->dev->blks_per_lun);
1186 if (!rlun->blocks) 1188 if (!rlun->blocks) {
1189 ret = -ENOMEM;
1187 goto err; 1190 goto err;
1191 }
1188 1192
1189 for (j = 0; j < rrpc->dev->blks_per_lun; j++) { 1193 for (j = 0; j < rrpc->dev->blks_per_lun; j++) {
1190 struct rrpc_block *rblk = &rlun->blocks[j]; 1194 struct rrpc_block *rblk = &rlun->blocks[j];
@@ -1195,11 +1199,23 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
1195 INIT_LIST_HEAD(&rblk->prio); 1199 INIT_LIST_HEAD(&rblk->prio);
1196 spin_lock_init(&rblk->lock); 1200 spin_lock_init(&rblk->lock);
1197 } 1201 }
1202
1203 rlun->rrpc = rrpc;
1204 INIT_LIST_HEAD(&rlun->prio_list);
1205 INIT_LIST_HEAD(&rlun->open_list);
1206 INIT_LIST_HEAD(&rlun->closed_list);
1207
1208 INIT_WORK(&rlun->ws_gc, rrpc_lun_gc);
1209 spin_lock_init(&rlun->lock);
1210
1211 rrpc->total_blocks += dev->blks_per_lun;
1212 rrpc->nr_sects += dev->sec_per_lun;
1213
1198 } 1214 }
1199 1215
1200 return 0; 1216 return 0;
1201err: 1217err:
1202 return -ENOMEM; 1218 return ret;
1203} 1219}
1204 1220
1205/* returns 0 on success and stores the beginning address in *begin */ 1221/* returns 0 on success and stores the beginning address in *begin */
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index b466bd9f2cf8..0ee2c2c78ffd 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -346,6 +346,7 @@ struct nvm_dev {
346 int nr_luns; 346 int nr_luns;
347 unsigned max_pages_per_blk; 347 unsigned max_pages_per_blk;
348 348
349 unsigned long *lun_map;
349 void *ppalist_pool; 350 void *ppalist_pool;
350 351
351 struct nvm_id identity; 352 struct nvm_id identity;
@@ -466,6 +467,8 @@ typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
466typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, 467typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
467 unsigned long); 468 unsigned long);
468typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); 469typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
470typedef int (nvmm_reserve_lun)(struct nvm_dev *, int);
471typedef void (nvmm_release_lun)(struct nvm_dev *, int);
469typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); 472typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
470 473
471typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); 474typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
@@ -492,6 +495,8 @@ struct nvmm_type {
492 495
493 /* Configuration management */ 496 /* Configuration management */
494 nvmm_get_lun_fn *get_lun; 497 nvmm_get_lun_fn *get_lun;
498 nvmm_reserve_lun *reserve_lun;
499 nvmm_release_lun *release_lun;
495 500
496 /* Statistics */ 501 /* Statistics */
497 nvmm_lun_info_print_fn *lun_info_print; 502 nvmm_lun_info_print_fn *lun_info_print;