diff options
author | Wenwei Tao <ww.tao0320@gmail.com> | 2016-03-03 09:06:38 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-03-18 21:10:38 -0400 |
commit | da1e284919b0b99c5bf0618b6c98cbaf2c17e62e (patch) | |
tree | ef1d8fe8821376dd57fbd4d3319a747841df38e6 | |
parent | 4c9dacb82d5aa36aa2568df60d897f2eb3d8819b (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.c | 6 | ||||
-rw-r--r-- | drivers/lightnvm/gennvm.c | 18 | ||||
-rw-r--r-- | drivers/lightnvm/rrpc.c | 74 | ||||
-rw-r--r-- | include/linux/lightnvm.h | 5 |
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; |
588 | err_init: | 592 | err_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 | } |
613 | EXPORT_SYMBOL(nvm_unregister); | 619 | EXPORT_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 | ||
488 | static int gennvm_reserve_lun(struct nvm_dev *dev, int lunid) | ||
489 | { | ||
490 | return test_and_set_bit(lunid, dev->lun_map); | ||
491 | } | ||
492 | |||
493 | static void gennvm_release_lun(struct nvm_dev *dev, int lunid) | ||
494 | { | ||
495 | WARN_ON(!test_and_clear_bit(lunid, dev->lun_map)); | ||
496 | } | ||
497 | |||
485 | static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid) | 498 | static 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 | ||
966 | static void rrpc_gc_free(struct rrpc *rrpc) | 966 | static 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 | ||
989 | static int rrpc_gc_init(struct rrpc *rrpc) | 975 | static int rrpc_gc_init(struct rrpc *rrpc) |
@@ -1143,6 +1129,23 @@ static void rrpc_core_free(struct rrpc *rrpc) | |||
1143 | 1129 | ||
1144 | static void rrpc_luns_free(struct rrpc *rrpc) | 1130 | static 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; |
1201 | err: | 1217 | err: |
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 *); | |||
466 | typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, | 467 | typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, |
467 | unsigned long); | 468 | unsigned long); |
468 | typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); | 469 | typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); |
470 | typedef int (nvmm_reserve_lun)(struct nvm_dev *, int); | ||
471 | typedef void (nvmm_release_lun)(struct nvm_dev *, int); | ||
469 | typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); | 472 | typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); |
470 | 473 | ||
471 | typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); | 474 | typedef 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; |