summaryrefslogtreecommitdiff
path: root/drivers/lightnvm/gennvm.c
diff options
context:
space:
mode:
authorJavier González <jg@lightnvm.io>2016-11-28 22:39:06 +0100
committerJens Axboe <axboe@fb.com>2016-11-29 12:12:51 -0700
commit8e79b5cb1d3b8eceaf6862995952dd4de431dd99 (patch)
tree85f4647731c3678e9fec4e3cac412aff66a86a86 /drivers/lightnvm/gennvm.c
parent8176117b82e49e043d045f214ba7a892fba6b827 (diff)
lightnvm: move block provisioning to targets
In order to naturally support multi-target instances on an Open-Channel SSD, targets should own the LUNs they get blocks from and manage provisioning internally. This is done in several steps. This patch moves the block provisioning inside of the target and removes the get/put block interface from the media manager. Signed-off-by: Javier González <javier@cnexlabs.com> Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/lightnvm/gennvm.c')
-rw-r--r--drivers/lightnvm/gennvm.c145
1 files changed, 69 insertions, 76 deletions
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index 9671e11356be..8791a2aaa9e3 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -74,6 +74,36 @@ static void gen_release_luns(struct nvm_dev *dev, struct nvm_target *t)
}
}
+static void gen_remove_tgt_dev(struct nvm_tgt_dev *tgt_dev)
+{
+ kfree(tgt_dev);
+}
+
+static struct nvm_tgt_dev *gen_create_tgt_dev(struct nvm_dev *dev,
+ int lun_begin, int lun_end)
+{
+ struct nvm_tgt_dev *tgt_dev = NULL;
+ int nr_luns = lun_end - lun_begin + 1;
+
+ tgt_dev = kmalloc(sizeof(struct nvm_tgt_dev), GFP_KERNEL);
+ if (!tgt_dev)
+ goto out;
+
+ memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo));
+ tgt_dev->geo.nr_chnls = (nr_luns / (dev->geo.luns_per_chnl + 1)) + 1;
+ tgt_dev->geo.nr_luns = nr_luns;
+ tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun;
+ tgt_dev->q = dev->q;
+ tgt_dev->ops = dev->ops;
+ tgt_dev->mt = dev->mt;
+ memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id));
+
+ tgt_dev->parent = dev;
+
+out:
+ return tgt_dev;
+}
+
static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
{
struct gen_dev *gn = dev->mp;
@@ -82,6 +112,7 @@ static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
struct gendisk *tdisk;
struct nvm_tgt_type *tt;
struct nvm_target *t;
+ struct nvm_tgt_dev *tgt_dev;
void *targetdata;
tt = nvm_find_target_type(create->tgttype, 1);
@@ -108,9 +139,13 @@ static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
if (gen_reserve_luns(dev, t, s->lun_begin, s->lun_end))
goto err_t;
+ tgt_dev = gen_create_tgt_dev(dev, s->lun_begin, s->lun_end);
+ if (!tgt_dev)
+ goto err_reserve;
+
tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node);
if (!tqueue)
- goto err_reserve;
+ goto err_dev;
blk_queue_make_request(tqueue, tt->make_rq);
tdisk = alloc_disk(0);
@@ -124,7 +159,7 @@ static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
tdisk->fops = &gen_fops;
tdisk->queue = tqueue;
- targetdata = tt->init(dev, tdisk, s->lun_begin, s->lun_end);
+ targetdata = tt->init(tgt_dev, tdisk, s->lun_begin, s->lun_end);
if (IS_ERR(targetdata))
goto err_init;
@@ -138,7 +173,7 @@ static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
t->type = tt;
t->disk = tdisk;
- t->dev = dev;
+ t->dev = tgt_dev;
mutex_lock(&gn->lock);
list_add_tail(&t->list, &gn->targets);
@@ -149,6 +184,8 @@ err_init:
put_disk(tdisk);
err_queue:
blk_cleanup_queue(tqueue);
+err_dev:
+ kfree(tgt_dev);
err_reserve:
gen_release_luns(dev, t);
err_t:
@@ -168,7 +205,8 @@ static void __gen_remove_target(struct nvm_target *t)
if (tt->exit)
tt->exit(tdisk->private_data);
- gen_release_luns(t->dev, t);
+ gen_release_luns(t->dev->parent, t);
+ gen_remove_tgt_dev(t->dev);
put_disk(tdisk);
list_del(&t->list);
@@ -207,10 +245,11 @@ static int gen_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
static int gen_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len)
{
+ struct nvm_geo *geo = &dev->geo;
struct gen_dev *gn = dev->mp;
struct gen_area *area, *prev, *next;
sector_t begin = 0;
- sector_t max_sectors = (dev->sec_size * dev->total_secs) >> 9;
+ sector_t max_sectors = (geo->sec_size * dev->total_secs) >> 9;
if (len > max_sectors)
return -EINVAL;
@@ -289,10 +328,11 @@ static void gen_luns_free(struct nvm_dev *dev)
static int gen_luns_init(struct nvm_dev *dev, struct gen_dev *gn)
{
+ struct nvm_geo *geo = &dev->geo;
struct nvm_lun *lun;
int i;
- gn->luns = kcalloc(dev->nr_luns, sizeof(struct nvm_lun), GFP_KERNEL);
+ gn->luns = kcalloc(geo->nr_luns, sizeof(struct nvm_lun), GFP_KERNEL);
if (!gn->luns)
return -ENOMEM;
@@ -305,9 +345,9 @@ static int gen_luns_init(struct nvm_dev *dev, struct gen_dev *gn)
spin_lock_init(&lun->lock);
lun->id = i;
- lun->lun_id = i % dev->luns_per_chnl;
- lun->chnl_id = i / dev->luns_per_chnl;
- lun->nr_free_blocks = dev->blks_per_lun;
+ lun->lun_id = i % geo->luns_per_chnl;
+ lun->chnl_id = i / geo->luns_per_chnl;
+ lun->nr_free_blocks = geo->blks_per_lun;
}
return 0;
}
@@ -324,7 +364,7 @@ static int gen_block_bb(struct gen_dev *gn, struct ppa_addr ppa,
if (nr_blks < 0)
return nr_blks;
- lun = &gn->luns[(dev->luns_per_chnl * ppa.g.ch) + ppa.g.lun];
+ lun = &gn->luns[(dev->geo.luns_per_chnl * ppa.g.ch) + ppa.g.lun];
for (i = 0; i < nr_blks; i++) {
if (blks[i] == NVM_BLK_T_FREE)
@@ -342,6 +382,7 @@ static int gen_block_bb(struct gen_dev *gn, struct ppa_addr ppa,
static int gen_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
{
struct nvm_dev *dev = private;
+ struct nvm_geo *geo = &dev->geo;
struct gen_dev *gn = dev->mp;
u64 elba = slba + nlb;
struct nvm_lun *lun;
@@ -370,12 +411,12 @@ static int gen_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
continue;
/* resolve block from physical address */
- lun_id = div_u64(pba, dev->sec_per_lun);
+ lun_id = div_u64(pba, geo->sec_per_lun);
lun = &gn->luns[lun_id];
/* Calculate block offset into lun */
- pba = pba - (dev->sec_per_lun * lun_id);
- blk = &lun->blocks[div_u64(pba, dev->sec_per_blk)];
+ pba = pba - (geo->sec_per_lun * lun_id);
+ blk = &lun->blocks[div_u64(pba, geo->sec_per_blk)];
if (!blk->state) {
/* at this point, we don't know anything about the
@@ -393,26 +434,27 @@ static int gen_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
static int gen_blocks_init(struct nvm_dev *dev, struct gen_dev *gn)
{
+ struct nvm_geo *geo = &dev->geo;
struct nvm_lun *lun;
struct nvm_block *block;
sector_t lun_iter, blk_iter, cur_block_id = 0;
int ret, nr_blks;
u8 *blks;
- nr_blks = dev->blks_per_lun * dev->plane_mode;
+ nr_blks = geo->blks_per_lun * geo->plane_mode;
blks = kmalloc(nr_blks, GFP_KERNEL);
if (!blks)
return -ENOMEM;
gen_for_each_lun(gn, lun, lun_iter) {
lun->blocks = vzalloc(sizeof(struct nvm_block) *
- dev->blks_per_lun);
+ geo->blks_per_lun);
if (!lun->blocks) {
kfree(blks);
return -ENOMEM;
}
- for (blk_iter = 0; blk_iter < dev->blks_per_lun; blk_iter++) {
+ for (blk_iter = 0; blk_iter < geo->blks_per_lun; blk_iter++) {
block = &lun->blocks[blk_iter];
INIT_LIST_HEAD(&block->list);
@@ -474,7 +516,7 @@ static int gen_register(struct nvm_dev *dev)
return -ENOMEM;
gn->dev = dev;
- gn->nr_luns = dev->nr_luns;
+ gn->nr_luns = dev->geo.nr_luns;
INIT_LIST_HEAD(&gn->area_list);
mutex_init(&gn->lock);
INIT_LIST_HEAD(&gn->targets);
@@ -506,7 +548,7 @@ static void gen_unregister(struct nvm_dev *dev)
mutex_lock(&gn->lock);
list_for_each_entry_safe(t, tmp, &gn->targets, list) {
- if (t->dev != dev)
+ if (t->dev->parent != dev)
continue;
__gen_remove_target(t);
}
@@ -516,55 +558,9 @@ static void gen_unregister(struct nvm_dev *dev)
module_put(THIS_MODULE);
}
-static struct nvm_block *gen_get_blk(struct nvm_dev *dev,
- struct nvm_lun *lun, unsigned long flags)
-{
- struct nvm_block *blk = NULL;
- int is_gc = flags & NVM_IOTYPE_GC;
-
- spin_lock(&lun->lock);
- if (list_empty(&lun->free_list)) {
- pr_err_ratelimited("gen: lun %u have no free pages available",
- lun->id);
- goto out;
- }
-
- if (!is_gc && lun->nr_free_blocks < lun->reserved_blocks)
- goto out;
-
- blk = list_first_entry(&lun->free_list, struct nvm_block, list);
-
- list_move_tail(&blk->list, &lun->used_list);
- blk->state = NVM_BLK_ST_TGT;
- lun->nr_free_blocks--;
-out:
- spin_unlock(&lun->lock);
- return blk;
-}
-
-static void gen_put_blk(struct nvm_dev *dev, struct nvm_block *blk)
-{
- struct nvm_lun *lun = blk->lun;
-
- spin_lock(&lun->lock);
- if (blk->state & NVM_BLK_ST_TGT) {
- list_move_tail(&blk->list, &lun->free_list);
- lun->nr_free_blocks++;
- blk->state = NVM_BLK_ST_FREE;
- } else if (blk->state & NVM_BLK_ST_BAD) {
- list_move_tail(&blk->list, &lun->bb_list);
- blk->state = NVM_BLK_ST_BAD;
- } else {
- WARN_ON_ONCE(1);
- pr_err("gen: erroneous block type (%lu -> %u)\n",
- blk->id, blk->state);
- list_move_tail(&blk->list, &lun->bb_list);
- }
- spin_unlock(&lun->lock);
-}
-
static void gen_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type)
{
+ struct nvm_geo *geo = &dev->geo;
struct gen_dev *gn = dev->mp;
struct nvm_lun *lun;
struct nvm_block *blk;
@@ -572,18 +568,18 @@ static void gen_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type)
pr_debug("gen: ppa (ch: %u lun: %u blk: %u pg: %u) -> %u\n",
ppa.g.ch, ppa.g.lun, ppa.g.blk, ppa.g.pg, type);
- if (unlikely(ppa.g.ch > dev->nr_chnls ||
- ppa.g.lun > dev->luns_per_chnl ||
- ppa.g.blk > dev->blks_per_lun)) {
+ if (unlikely(ppa.g.ch > geo->nr_chnls ||
+ ppa.g.lun > geo->luns_per_chnl ||
+ ppa.g.blk > geo->blks_per_lun)) {
WARN_ON_ONCE(1);
pr_err("gen: ppa broken (ch: %u > %u lun: %u > %u blk: %u > %u",
- ppa.g.ch, dev->nr_chnls,
- ppa.g.lun, dev->luns_per_chnl,
- ppa.g.blk, dev->blks_per_lun);
+ ppa.g.ch, geo->nr_chnls,
+ ppa.g.lun, geo->luns_per_chnl,
+ ppa.g.blk, geo->blks_per_lun);
return;
}
- lun = &gn->luns[(dev->luns_per_chnl * ppa.g.ch) + ppa.g.lun];
+ lun = &gn->luns[(geo->luns_per_chnl * ppa.g.ch) + ppa.g.lun];
blk = &lun->blocks[ppa.g.blk];
/* will be moved to bb list on put_blk from target */
@@ -621,7 +617,7 @@ static struct nvm_lun *gen_get_lun(struct nvm_dev *dev, int lunid)
{
struct gen_dev *gn = dev->mp;
- if (unlikely(lunid >= dev->nr_luns))
+ if (unlikely(lunid >= dev->geo.nr_luns))
return NULL;
return &gn->luns[lunid];
@@ -654,9 +650,6 @@ static struct nvmm_type gen = {
.create_tgt = gen_create_tgt,
.remove_tgt = gen_remove_tgt,
- .get_blk = gen_get_blk,
- .put_blk = gen_put_blk,
-
.submit_io = gen_submit_io,
.erase_blk = gen_erase_blk,