Commit da1e2849 authored by Wenwei Tao's avatar Wenwei Tao Committed by Jens Axboe

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: default avatarWenwei Tao <ww.tao0320@gmail.com>
Freed dev->lun_map if nvm_core_init later failed in the init process.
Signed-off-by: default avatarMatias Bjørling <m@bjorling.me>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 4c9dacb8
...@@ -464,6 +464,10 @@ static int nvm_core_init(struct nvm_dev *dev) ...@@ -464,6 +464,10 @@ static int nvm_core_init(struct nvm_dev *dev)
dev->nr_luns = dev->luns_per_chnl * dev->nr_chnls; dev->nr_luns = dev->luns_per_chnl * dev->nr_chnls;
dev->total_secs = dev->nr_luns * dev->sec_per_lun; dev->total_secs = dev->nr_luns * dev->sec_per_lun;
dev->lun_map = kcalloc(BITS_TO_LONGS(dev->nr_luns),
sizeof(unsigned long), GFP_KERNEL);
if (!dev->lun_map)
return -ENOMEM;
INIT_LIST_HEAD(&dev->online_targets); INIT_LIST_HEAD(&dev->online_targets);
mutex_init(&dev->mlock); mutex_init(&dev->mlock);
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
...@@ -586,6 +590,7 @@ int nvm_register(struct request_queue *q, char *disk_name, ...@@ -586,6 +590,7 @@ int nvm_register(struct request_queue *q, char *disk_name,
return 0; return 0;
err_init: err_init:
kfree(dev->lun_map);
kfree(dev); kfree(dev);
return ret; return ret;
} }
...@@ -608,6 +613,7 @@ void nvm_unregister(char *disk_name) ...@@ -608,6 +613,7 @@ void nvm_unregister(char *disk_name)
up_write(&nvm_lock); up_write(&nvm_lock);
nvm_exit(dev); nvm_exit(dev);
kfree(dev->lun_map);
kfree(dev); kfree(dev);
} }
EXPORT_SYMBOL(nvm_unregister); EXPORT_SYMBOL(nvm_unregister);
......
...@@ -192,6 +192,9 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private) ...@@ -192,6 +192,9 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
lun_id = div_u64(pba, dev->sec_per_lun); lun_id = div_u64(pba, dev->sec_per_lun);
lun = &gn->luns[lun_id]; lun = &gn->luns[lun_id];
if (!test_bit(lun_id, dev->lun_map))
__set_bit(lun_id, dev->lun_map);
/* Calculate block offset into lun */ /* Calculate block offset into lun */
pba = pba - (dev->sec_per_lun * lun_id); pba = pba - (dev->sec_per_lun * lun_id);
blk = &lun->vlun.blocks[div_u64(pba, dev->sec_per_blk)]; 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,10 +485,23 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
return nvm_erase_ppa(dev, &addr, 1); return nvm_erase_ppa(dev, &addr, 1);
} }
static int gennvm_reserve_lun(struct nvm_dev *dev, int lunid)
{
return test_and_set_bit(lunid, dev->lun_map);
}
static void gennvm_release_lun(struct nvm_dev *dev, int lunid)
{
WARN_ON(!test_and_clear_bit(lunid, dev->lun_map));
}
static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid) static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
{ {
struct gen_nvm *gn = dev->mp; struct gen_nvm *gn = dev->mp;
if (unlikely(lunid >= dev->nr_luns))
return NULL;
return &gn->luns[lunid].vlun; return &gn->luns[lunid].vlun;
} }
...@@ -527,6 +543,8 @@ static struct nvmm_type gennvm = { ...@@ -527,6 +543,8 @@ static struct nvmm_type gennvm = {
.erase_blk = gennvm_erase_blk, .erase_blk = gennvm_erase_blk,
.get_lun = gennvm_get_lun, .get_lun = gennvm_get_lun,
.reserve_lun = gennvm_reserve_lun,
.release_lun = gennvm_release_lun,
.lun_info_print = gennvm_lun_info_print, .lun_info_print = gennvm_lun_info_print,
.get_area = gennvm_get_area, .get_area = gennvm_get_area,
......
...@@ -965,25 +965,11 @@ static void rrpc_requeue(struct work_struct *work) ...@@ -965,25 +965,11 @@ static void rrpc_requeue(struct work_struct *work)
static void rrpc_gc_free(struct rrpc *rrpc) static void rrpc_gc_free(struct rrpc *rrpc)
{ {
struct rrpc_lun *rlun;
int i;
if (rrpc->krqd_wq) if (rrpc->krqd_wq)
destroy_workqueue(rrpc->krqd_wq); destroy_workqueue(rrpc->krqd_wq);
if (rrpc->kgc_wq) if (rrpc->kgc_wq)
destroy_workqueue(rrpc->kgc_wq); destroy_workqueue(rrpc->kgc_wq);
if (!rrpc->luns)
return;
for (i = 0; i < rrpc->nr_luns; i++) {
rlun = &rrpc->luns[i];
if (!rlun->blocks)
break;
vfree(rlun->blocks);
}
} }
static int rrpc_gc_init(struct rrpc *rrpc) static int rrpc_gc_init(struct rrpc *rrpc)
...@@ -1143,6 +1129,23 @@ static void rrpc_core_free(struct rrpc *rrpc) ...@@ -1143,6 +1129,23 @@ static void rrpc_core_free(struct rrpc *rrpc)
static void rrpc_luns_free(struct rrpc *rrpc) static void rrpc_luns_free(struct rrpc *rrpc)
{ {
struct nvm_dev *dev = rrpc->dev;
struct nvm_lun *lun;
struct rrpc_lun *rlun;
int i;
if (!rrpc->luns)
return;
for (i = 0; i < rrpc->nr_luns; i++) {
rlun = &rrpc->luns[i];
lun = rlun->parent;
if (!lun)
break;
dev->mt->release_lun(dev, lun->id);
vfree(rlun->blocks);
}
kfree(rrpc->luns); kfree(rrpc->luns);
} }
...@@ -1150,7 +1153,7 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end) ...@@ -1150,7 +1153,7 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
{ {
struct nvm_dev *dev = rrpc->dev; struct nvm_dev *dev = rrpc->dev;
struct rrpc_lun *rlun; struct rrpc_lun *rlun;
int i, j; int i, j, ret = -EINVAL;
if (dev->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) { if (dev->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
pr_err("rrpc: number of pages per block too high."); 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,25 +1169,26 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
/* 1:1 mapping */ /* 1:1 mapping */
for (i = 0; i < rrpc->nr_luns; i++) { for (i = 0; i < rrpc->nr_luns; i++) {
struct nvm_lun *lun = dev->mt->get_lun(dev, lun_begin + i); int lunid = lun_begin + i;
struct nvm_lun *lun;
rlun = &rrpc->luns[i];
rlun->rrpc = rrpc;
rlun->parent = lun;
INIT_LIST_HEAD(&rlun->prio_list);
INIT_LIST_HEAD(&rlun->open_list);
INIT_LIST_HEAD(&rlun->closed_list);
INIT_WORK(&rlun->ws_gc, rrpc_lun_gc); if (dev->mt->reserve_lun(dev, lunid)) {
spin_lock_init(&rlun->lock); pr_err("rrpc: lun %u is already allocated\n", lunid);
goto err;
}
rrpc->total_blocks += dev->blks_per_lun; lun = dev->mt->get_lun(dev, lunid);
rrpc->nr_sects += dev->sec_per_lun; if (!lun)
goto err;
rlun = &rrpc->luns[i];
rlun->parent = lun;
rlun->blocks = vzalloc(sizeof(struct rrpc_block) * rlun->blocks = vzalloc(sizeof(struct rrpc_block) *
rrpc->dev->blks_per_lun); rrpc->dev->blks_per_lun);
if (!rlun->blocks) if (!rlun->blocks) {
ret = -ENOMEM;
goto err; goto err;
}
for (j = 0; j < rrpc->dev->blks_per_lun; j++) { for (j = 0; j < rrpc->dev->blks_per_lun; j++) {
struct rrpc_block *rblk = &rlun->blocks[j]; 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,11 +1199,23 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
INIT_LIST_HEAD(&rblk->prio); INIT_LIST_HEAD(&rblk->prio);
spin_lock_init(&rblk->lock); spin_lock_init(&rblk->lock);
} }
rlun->rrpc = rrpc;
INIT_LIST_HEAD(&rlun->prio_list);
INIT_LIST_HEAD(&rlun->open_list);
INIT_LIST_HEAD(&rlun->closed_list);
INIT_WORK(&rlun->ws_gc, rrpc_lun_gc);
spin_lock_init(&rlun->lock);
rrpc->total_blocks += dev->blks_per_lun;
rrpc->nr_sects += dev->sec_per_lun;
} }
return 0; return 0;
err: err:
return -ENOMEM; return ret;
} }
/* returns 0 on success and stores the beginning address in *begin */ /* returns 0 on success and stores the beginning address in *begin */
......
...@@ -346,6 +346,7 @@ struct nvm_dev { ...@@ -346,6 +346,7 @@ struct nvm_dev {
int nr_luns; int nr_luns;
unsigned max_pages_per_blk; unsigned max_pages_per_blk;
unsigned long *lun_map;
void *ppalist_pool; void *ppalist_pool;
struct nvm_id identity; struct nvm_id identity;
...@@ -466,6 +467,8 @@ typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *); ...@@ -466,6 +467,8 @@ typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
unsigned long); unsigned long);
typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
typedef int (nvmm_reserve_lun)(struct nvm_dev *, int);
typedef void (nvmm_release_lun)(struct nvm_dev *, int);
typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
...@@ -492,6 +495,8 @@ struct nvmm_type { ...@@ -492,6 +495,8 @@ struct nvmm_type {
/* Configuration management */ /* Configuration management */
nvmm_get_lun_fn *get_lun; nvmm_get_lun_fn *get_lun;
nvmm_reserve_lun *reserve_lun;
nvmm_release_lun *release_lun;
/* Statistics */ /* Statistics */
nvmm_lun_info_print_fn *lun_info_print; nvmm_lun_info_print_fn *lun_info_print;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment