2016-03-19 17:00:25

by Wenwei Tao

[permalink] [raw]
Subject: [PATCH 1/3] lightnvm: divide global reverse translation map into per lun

Divide the target's global reverse translation map into per lun,
to prepare support for the non-continuous lun target creation.

Signed-off-by: Wenwei Tao <[email protected]>
---
drivers/lightnvm/rrpc.c | 183 +++++++++++++++++++++++++++--------------------
drivers/lightnvm/rrpc.h | 7 +-
include/linux/lightnvm.h | 1 +
3 files changed, 112 insertions(+), 79 deletions(-)

diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
index 3ab6495..4cc157a 100644
--- a/drivers/lightnvm/rrpc.c
+++ b/drivers/lightnvm/rrpc.c
@@ -23,28 +23,35 @@ static int rrpc_submit_io(struct rrpc *rrpc, struct bio *bio,
struct nvm_rq *rqd, unsigned long flags);

#define rrpc_for_each_lun(rrpc, rlun, i) \
- for ((i) = 0, rlun = &(rrpc)->luns[0]; \
- (i) < (rrpc)->nr_luns; (i)++, rlun = &(rrpc)->luns[(i)])
+ for ((i) = 0, rlun = &(rrpc)->luns[0]; \
+ (i) < (rrpc)->nr_luns; (i)++, rlun = &(rrpc)->luns[(i)])
+
+static inline u64 lun_poffset(struct nvm_lun *lun, struct nvm_dev *dev)
+{
+ return lun->id * dev->sec_per_lun;
+}

static void rrpc_page_invalidate(struct rrpc *rrpc, struct rrpc_addr *a)
{
struct rrpc_block *rblk = a->rblk;
- unsigned int pg_offset;
+ struct rrpc_lun *rlun = rblk->rlun;
+ u64 pg_offset;

- lockdep_assert_held(&rrpc->rev_lock);
+ lockdep_assert_held(&rlun->rev_lock);

if (a->addr == ADDR_EMPTY || !rblk)
return;

spin_lock(&rblk->lock);

- div_u64_rem(a->addr, rrpc->dev->sec_per_blk, &pg_offset);
+ div_u64_rem(a->addr, rrpc->dev->sec_per_blk, (u32 *)&pg_offset);
WARN_ON(test_and_set_bit(pg_offset, rblk->invalid_pages));
rblk->nr_invalid_pages++;

spin_unlock(&rblk->lock);

- rrpc->rev_trans_map[a->addr - rrpc->poffset].addr = ADDR_EMPTY;
+ pg_offset = lun_poffset(rlun->parent, rrpc->dev);
+ rlun->rev_trans_map[a->addr - pg_offset].addr = ADDR_EMPTY;
}

static void rrpc_invalidate_range(struct rrpc *rrpc, sector_t slba,
@@ -52,14 +59,15 @@ static void rrpc_invalidate_range(struct rrpc *rrpc, sector_t slba,
{
sector_t i;

- spin_lock(&rrpc->rev_lock);
for (i = slba; i < slba + len; i++) {
struct rrpc_addr *gp = &rrpc->trans_map[i];
+ struct rrpc_lun *rlun = gp->rblk->rlun;

+ spin_lock(&rlun->rev_lock);
rrpc_page_invalidate(rrpc, gp);
+ spin_unlock(&rlun->rev_lock);
gp->rblk = NULL;
}
- spin_unlock(&rrpc->rev_lock);
}

static struct nvm_rq *rrpc_inflight_laddr_acquire(struct rrpc *rrpc,
@@ -116,15 +124,6 @@ static int block_is_full(struct rrpc *rrpc, struct rrpc_block *rblk)
return (rblk->next_page == rrpc->dev->sec_per_blk);
}

-/* Calculate relative addr for the given block, considering instantiated LUNs */
-static u64 block_to_rel_addr(struct rrpc *rrpc, struct rrpc_block *rblk)
-{
- struct nvm_block *blk = rblk->parent;
- int lun_blk = blk->id % (rrpc->dev->blks_per_lun * rrpc->nr_luns);
-
- return lun_blk * rrpc->dev->sec_per_blk;
-}
-
/* Calculate global addr for the given block */
static u64 block_to_addr(struct rrpc *rrpc, struct rrpc_block *rblk)
{
@@ -291,13 +290,14 @@ static void rrpc_end_sync_bio(struct bio *bio)
static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk)
{
struct request_queue *q = rrpc->dev->q;
+ struct rrpc_lun *rlun = rblk->rlun;
struct rrpc_rev_addr *rev;
struct nvm_rq *rqd;
struct bio *bio;
struct page *page;
int slot;
int nr_sec_per_blk = rrpc->dev->sec_per_blk;
- u64 phys_addr;
+ u64 phys_addr, poffset;
DECLARE_COMPLETION_ONSTACK(wait);

if (bitmap_full(rblk->invalid_pages, nr_sec_per_blk))
@@ -315,6 +315,7 @@ static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk)
return -ENOMEM;
}

+ poffset = lun_poffset(rlun->parent, rrpc->dev);
while ((slot = find_first_zero_bit(rblk->invalid_pages,
nr_sec_per_blk)) < nr_sec_per_blk) {

@@ -322,23 +323,23 @@ static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk)
phys_addr = rblk->parent->id * nr_sec_per_blk + slot;

try:
- spin_lock(&rrpc->rev_lock);
+ spin_lock(&rlun->rev_lock);
/* Get logical address from physical to logical table */
- rev = &rrpc->rev_trans_map[phys_addr - rrpc->poffset];
+ rev = &rlun->rev_trans_map[phys_addr - poffset];
/* already updated by previous regular write */
if (rev->addr == ADDR_EMPTY) {
- spin_unlock(&rrpc->rev_lock);
+ spin_unlock(&rlun->rev_lock);
continue;
}

rqd = rrpc_inflight_laddr_acquire(rrpc, rev->addr, 1);
if (IS_ERR_OR_NULL(rqd)) {
- spin_unlock(&rrpc->rev_lock);
+ spin_unlock(&rlun->rev_lock);
schedule();
goto try;
}

- spin_unlock(&rrpc->rev_lock);
+ spin_unlock(&rlun->rev_lock);

/* Perform read to do GC */
bio->bi_iter.bi_sector = rrpc_get_sector(rev->addr);
@@ -407,7 +408,7 @@ static void rrpc_block_gc(struct work_struct *work)
struct rrpc_block *rblk = gcb->rblk;
struct nvm_dev *dev = rrpc->dev;
struct nvm_lun *lun = rblk->parent->lun;
- struct rrpc_lun *rlun = &rrpc->luns[lun->id - rrpc->lun_offset];
+ struct rrpc_lun *rlun = lun->private;

mempool_free(gcb, rrpc->gcb_pool);
pr_debug("nvm: block '%lu' being reclaimed\n", rblk->parent->id);
@@ -510,7 +511,7 @@ static void rrpc_gc_queue(struct work_struct *work)
struct rrpc_block *rblk = gcb->rblk;
struct nvm_lun *lun = rblk->parent->lun;
struct nvm_block *blk = rblk->parent;
- struct rrpc_lun *rlun = &rrpc->luns[lun->id - rrpc->lun_offset];
+ struct rrpc_lun *rlun = lun->private;

spin_lock(&rlun->lock);
list_add_tail(&rblk->prio, &rlun->prio_list);
@@ -561,22 +562,25 @@ static struct rrpc_lun *rrpc_get_lun_rr(struct rrpc *rrpc, int is_gc)
static struct rrpc_addr *rrpc_update_map(struct rrpc *rrpc, sector_t laddr,
struct rrpc_block *rblk, u64 paddr)
{
+ struct rrpc_lun *rlun = rblk->rlun;
struct rrpc_addr *gp;
struct rrpc_rev_addr *rev;
+ u64 poffset = lun_poffset(rlun->parent, rrpc->dev);

BUG_ON(laddr >= rrpc->nr_sects);

gp = &rrpc->trans_map[laddr];
- spin_lock(&rrpc->rev_lock);
+ spin_lock(&rlun->rev_lock);
+
if (gp->rblk)
rrpc_page_invalidate(rrpc, gp);

gp->addr = paddr;
gp->rblk = rblk;

- rev = &rrpc->rev_trans_map[gp->addr - rrpc->poffset];
+ rev = &rlun->rev_trans_map[gp->addr - poffset];
rev->addr = laddr;
- spin_unlock(&rrpc->rev_lock);
+ spin_unlock(&rlun->rev_lock);

return gp;
}
@@ -990,7 +994,6 @@ static int rrpc_gc_init(struct rrpc *rrpc)

static void rrpc_map_free(struct rrpc *rrpc)
{
- vfree(rrpc->rev_trans_map);
vfree(rrpc->trans_map);
}

@@ -998,8 +1001,8 @@ static int rrpc_l2p_update(u64 slba, u32 nlb, __le64 *entries, void *private)
{
struct rrpc *rrpc = (struct rrpc *)private;
struct nvm_dev *dev = rrpc->dev;
- struct rrpc_addr *addr = rrpc->trans_map + slba;
- struct rrpc_rev_addr *raddr = rrpc->rev_trans_map;
+ struct rrpc_addr *addr;
+ struct rrpc_rev_addr *raddr;
u64 elba = slba + nlb;
u64 i;

@@ -1008,9 +1011,15 @@ static int rrpc_l2p_update(u64 slba, u32 nlb, __le64 *entries, void *private)
return -EINVAL;
}

+ slba -= rrpc->soffset >> (ilog2(dev->sec_size) - 9);
+ addr = rrpc->trans_map + slba;
for (i = 0; i < nlb; i++) {
+ struct rrpc_lun *rlun;
+ struct nvm_lun *lun;
u64 pba = le64_to_cpu(entries[i]);
- unsigned int mod;
+ u64 poffset;
+ int lunid;
+
/* LNVM treats address-spaces as silos, LBA and PBA are
* equally large and zero-indexed.
*/
@@ -1026,10 +1035,18 @@ static int rrpc_l2p_update(u64 slba, u32 nlb, __le64 *entries, void *private)
if (!pba)
continue;

- div_u64_rem(pba, rrpc->nr_sects, &mod);
+ lunid = div_u64(pba, dev->sec_per_lun);
+ lun = dev->mt->get_lun(dev, lunid);
+
+ if (unlikely(!lun))
+ return -EINVAL;
+
+ rlun = lun->private;
+ raddr = rlun->rev_trans_map;
+ poffset = lun_poffset(lun, dev);

addr[i].addr = pba;
- raddr[mod].addr = slba + i;
+ raddr[pba - poffset].addr = slba + i;
}

return 0;
@@ -1048,17 +1065,10 @@ static int rrpc_map_init(struct rrpc *rrpc)
if (!rrpc->trans_map)
return -ENOMEM;

- rrpc->rev_trans_map = vmalloc(sizeof(struct rrpc_rev_addr)
- * rrpc->nr_sects);
- if (!rrpc->rev_trans_map)
- return -ENOMEM;
-
for (i = 0; i < rrpc->nr_sects; i++) {
struct rrpc_addr *p = &rrpc->trans_map[i];
- struct rrpc_rev_addr *r = &rrpc->rev_trans_map[i];

p->addr = ADDR_EMPTY;
- r->addr = ADDR_EMPTY;
}

if (!dev->ops->get_l2p_tbl)
@@ -1143,25 +1153,69 @@ static void rrpc_luns_free(struct rrpc *rrpc)
if (!lun)
break;
dev->mt->release_lun(dev, lun->id);
+ vfree(rlun->rev_trans_map);
vfree(rlun->blocks);
}

kfree(rrpc->luns);
+ rrpc->luns = NULL;
+}
+
+static int rrpc_lun_init(struct rrpc *rrpc, struct rrpc_lun *rlun,
+ struct nvm_lun *lun)
+{
+ struct nvm_dev *dev = rrpc->dev;
+ int i;
+
+ rlun->rev_trans_map = vmalloc(sizeof(struct rrpc_rev_addr) *
+ dev->sec_per_lun);
+ if (!rlun->rev_trans_map)
+ return -ENOMEM;
+
+ for (i = 0; i < dev->sec_per_lun; i++) {
+ struct rrpc_rev_addr *r = &rlun->rev_trans_map[i];
+
+ r->addr = ADDR_EMPTY;
+ }
+ rlun->blocks = vzalloc(sizeof(struct rrpc_block) * dev->blks_per_lun);
+ if (!rlun->blocks) {
+ vfree(rlun->rev_trans_map);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->blks_per_lun; i++) {
+ struct rrpc_block *rblk = &rlun->blocks[i];
+ struct nvm_block *blk = &lun->blocks[i];
+
+ rblk->parent = blk;
+ rblk->rlun = rlun;
+ INIT_LIST_HEAD(&rblk->prio);
+ spin_lock_init(&rblk->lock);
+ }
+
+ rlun->rrpc = rrpc;
+ lun->private = rlun;
+ 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);
+ spin_lock_init(&rlun->rev_lock);
+
+ return 0;
}

static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
{
struct nvm_dev *dev = rrpc->dev;
struct rrpc_lun *rlun;
- int i, j, ret = -EINVAL;
+ int i, ret = -EINVAL;

if (dev->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
pr_err("rrpc: number of pages per block too high.");
return -EINVAL;
}

- spin_lock_init(&rrpc->rev_lock);
-
rrpc->luns = kcalloc(rrpc->nr_luns, sizeof(struct rrpc_lun),
GFP_KERNEL);
if (!rrpc->luns)
@@ -1183,31 +1237,9 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)

rlun = &rrpc->luns[i];
rlun->parent = lun;
- rlun->blocks = vzalloc(sizeof(struct rrpc_block) *
- rrpc->dev->blks_per_lun);
- if (!rlun->blocks) {
- ret = -ENOMEM;
+ ret = rrpc_lun_init(rrpc, rlun, lun);
+ if (ret)
goto err;
- }
-
- for (j = 0; j < rrpc->dev->blks_per_lun; j++) {
- struct rrpc_block *rblk = &rlun->blocks[j];
- struct nvm_block *blk = &lun->blocks[j];
-
- rblk->parent = blk;
- rblk->rlun = rlun;
- INIT_LIST_HEAD(&rblk->prio);
- 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;

@@ -1215,6 +1247,7 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)

return 0;
err:
+ rrpc_luns_free(rrpc);
return ret;
}

@@ -1288,15 +1321,16 @@ static sector_t rrpc_capacity(void *private)
static void rrpc_block_map_update(struct rrpc *rrpc, struct rrpc_block *rblk)
{
struct nvm_dev *dev = rrpc->dev;
+ struct rrpc_lun *rlun = rblk->rlun;
int offset;
struct rrpc_addr *laddr;
- u64 bpaddr, paddr, pladdr;
+ u64 paddr, pladdr, poffset;

- bpaddr = block_to_rel_addr(rrpc, rblk);
- for (offset = 0; offset < dev->sec_per_blk; offset++) {
- paddr = bpaddr + offset;
+ poffset = lun_poffset(rlun->parent, dev);
+ for (offset = 0; offset < dev->pgs_per_blk; offset++) {
+ paddr = block_to_addr(rrpc, rblk) + offset;

- pladdr = rrpc->rev_trans_map[paddr].addr;
+ pladdr = rlun->rev_trans_map[paddr - poffset].addr;
if (pladdr == ADDR_EMPTY)
continue;

@@ -1405,9 +1439,6 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
goto err;
}

- rrpc->poffset = dev->sec_per_lun * lun_begin;
- rrpc->lun_offset = lun_begin;
-
ret = rrpc_core_init(rrpc);
if (ret) {
pr_err("nvm: rrpc: could not initialize core\n");
diff --git a/drivers/lightnvm/rrpc.h b/drivers/lightnvm/rrpc.h
index 2653484..032e987 100644
--- a/drivers/lightnvm/rrpc.h
+++ b/drivers/lightnvm/rrpc.h
@@ -87,6 +87,10 @@ struct rrpc_lun {

struct work_struct ws_gc;

+ /* store a reverse map for garbage collection */
+ struct rrpc_rev_addr *rev_trans_map;
+ spinlock_t rev_lock;
+
spinlock_t lock;
};

@@ -124,9 +128,6 @@ struct rrpc {
* addresses are used when writing to the disk block device.
*/
struct rrpc_addr *trans_map;
- /* also store a reverse map for garbage collection */
- struct rrpc_rev_addr *rev_trans_map;
- spinlock_t rev_lock;

struct rrpc_inflight inflights;

diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index cdcb2cc..419a3db 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -276,6 +276,7 @@ struct nvm_lun {
spinlock_t lock;

struct nvm_block *blocks;
+ void *private;
};

enum {
--
1.9.1


2016-03-19 17:00:42

by Wenwei Tao

[permalink] [raw]
Subject: [PATCH v5 2/3] lightnvm: add non-continuous lun target creation support

When create a target, we specify the begin lunid and
the end lunid, and get the corresponding continuous
luns from media manager, if one of the luns is not free,
we failed to create the target, even if the device's
total free luns are enough.

So add non-continuous lun target creation support,
thus we can improve the backend device's space utilization.

Signed-off-by: Wenwei Tao <[email protected]>
---
Changes since v4
-fix target creation fail.
-move code concerning the per-lun reverse translation
map to a new patch.

Changes since v3
-limit list luns to 768, thus we don't go
above a single memory page.
-move NVM_DEV_FREE_LUNS to its own patch and
rename it to NVM_DEV_LUNS_STATUS.
-insert and delete some lines to increase
readability.
-rebase to for-4.6

Changes since v2
-rebase on for-next branch
-move luns bitmap to PATCH 2
-remove the logic to dynamically select another lun than
the one requested
-implment lunid list in the lnvm ioctl interface

Changes since v1
-use NVM_FIXED instead NVM_C_FIXED in gennvm_get_lun
-add target creation flags check
-rebase to v4.5-rc1

drivers/lightnvm/core.c | 64 ++++++++++++++++++++++++-------------------
drivers/lightnvm/rrpc.c | 31 +++++++++++++++++----
include/linux/lightnvm.h | 3 +-
include/uapi/linux/lightnvm.h | 9 ++++++
4 files changed, 73 insertions(+), 34 deletions(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 0dc9a80..84bc72d 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -625,7 +625,7 @@ static const struct block_device_operations nvm_fops = {
static int nvm_create_target(struct nvm_dev *dev,
struct nvm_ioctl_create *create)
{
- struct nvm_ioctl_create_simple *s = &create->conf.s;
+ struct nvm_ioctl_create_conf *conf = &create->conf;
struct request_queue *tqueue;
struct gendisk *tdisk;
struct nvm_tgt_type *tt;
@@ -674,7 +674,7 @@ static int nvm_create_target(struct nvm_dev *dev,
tdisk->fops = &nvm_fops;
tdisk->queue = tqueue;

- targetdata = tt->init(dev, tdisk, s->lun_begin, s->lun_end);
+ targetdata = tt->init(dev, tdisk, conf);
if (IS_ERR(targetdata))
goto err_init;

@@ -726,7 +726,6 @@ static void nvm_remove_target(struct nvm_target *t)
static int __nvm_configure_create(struct nvm_ioctl_create *create)
{
struct nvm_dev *dev;
- struct nvm_ioctl_create_simple *s;

down_write(&nvm_lock);
dev = nvm_find_nvm_dev(create->dev);
@@ -736,17 +735,11 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
return -EINVAL;
}

- if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) {
+ if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE &&
+ create->conf.type != NVM_CONFIG_TYPE_LIST) {
pr_err("nvm: config type not valid\n");
return -EINVAL;
}
- s = &create->conf.s;
-
- if (s->lun_begin > s->lun_end || s->lun_end > dev->nr_luns) {
- pr_err("nvm: lun out of bound (%u:%u > %u)\n",
- s->lun_begin, s->lun_end, dev->nr_luns);
- return -EINVAL;
- }

return nvm_create_target(dev, create);
}
@@ -824,24 +817,29 @@ static int nvm_configure_remove(const char *val)

static int nvm_configure_create(const char *val)
{
- struct nvm_ioctl_create create;
+ struct nvm_ioctl_create *create;
char opcode;
int lun_begin, lun_end, ret;

- ret = sscanf(val, "%c %256s %256s %48s %u:%u", &opcode, create.dev,
- create.tgtname, create.tgttype,
+ create = kzalloc(sizeof(struct nvm_ioctl_create), GFP_KERNEL);
+ if (!create)
+ return -ENOMEM;
+
+ ret = sscanf(val, "%c %256s %256s %48s %u:%u", &opcode, create->dev,
+ create->tgtname, create->tgttype,
&lun_begin, &lun_end);
if (ret != 6) {
pr_err("nvm: invalid command. Use \"opcode device name tgttype lun_begin:lun_end\".\n");
+ kfree(create);
return -EINVAL;
}

- create.flags = 0;
- create.conf.type = NVM_CONFIG_TYPE_SIMPLE;
- create.conf.s.lun_begin = lun_begin;
- create.conf.s.lun_end = lun_end;
+ create->flags = 0;
+ create->conf.type = NVM_CONFIG_TYPE_SIMPLE;
+ create->conf.s.lun_begin = lun_begin;
+ create->conf.s.lun_end = lun_end;

- return __nvm_configure_create(&create);
+ return __nvm_configure_create(create);
}


@@ -993,24 +991,34 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg)

static long nvm_ioctl_dev_create(struct file *file, void __user *arg)
{
- struct nvm_ioctl_create create;
+ struct nvm_ioctl_create *create;
+ long ret = -EINVAL;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ create = kzalloc(sizeof(struct nvm_ioctl_create), GFP_KERNEL);
+ if (!create)
+ return -ENOMEM;

- if (copy_from_user(&create, arg, sizeof(struct nvm_ioctl_create)))
- return -EFAULT;
+ if (copy_from_user(create, arg, sizeof(struct nvm_ioctl_create))) {
+ ret = -EFAULT;
+ goto out;
+ }

- create.dev[DISK_NAME_LEN - 1] = '\0';
- create.tgttype[NVM_TTYPE_NAME_MAX - 1] = '\0';
- create.tgtname[DISK_NAME_LEN - 1] = '\0';
+ create->dev[DISK_NAME_LEN - 1] = '\0';
+ create->tgttype[NVM_TTYPE_NAME_MAX - 1] = '\0';
+ create->tgtname[DISK_NAME_LEN - 1] = '\0';

- if (create.flags != 0) {
+ if (create->flags != 0) {
pr_err("nvm: no flags supported\n");
- return -EINVAL;
+ goto out;
}

- return __nvm_configure_create(&create);
+ ret = __nvm_configure_create(create);
+
+out:
+ kfree(create);
+ return ret;
}

static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
index 4cc157a..9ed8374 100644
--- a/drivers/lightnvm/rrpc.c
+++ b/drivers/lightnvm/rrpc.c
@@ -1205,7 +1205,7 @@ static int rrpc_lun_init(struct rrpc *rrpc, struct rrpc_lun *rlun,
return 0;
}

-static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
+static int rrpc_luns_init(struct rrpc *rrpc, struct nvm_ioctl_create_conf *conf)
{
struct nvm_dev *dev = rrpc->dev;
struct rrpc_lun *rlun;
@@ -1223,8 +1223,21 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)

/* 1:1 mapping */
for (i = 0; i < rrpc->nr_luns; i++) {
- int lunid = lun_begin + i;
struct nvm_lun *lun;
+ int lunid;
+
+ if (conf->type == NVM_CONFIG_TYPE_SIMPLE)
+ lunid = conf->s.lun_begin + i;
+ else if (conf->type == NVM_CONFIG_TYPE_LIST)
+ lunid = conf->l.lunid[i];
+ else
+ goto err;
+
+ if (lunid >= dev->nr_luns) {
+ pr_err("rrpc: lun out of bound (%u >= %u)\n",
+ lunid, dev->nr_luns);
+ goto err;
+ }

if (dev->mt->reserve_lun(dev, lunid)) {
pr_err("rrpc: lun %u is already allocated\n", lunid);
@@ -1395,7 +1408,7 @@ err:
static struct nvm_tgt_type tt_rrpc;

static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
- int lun_begin, int lun_end)
+ struct nvm_ioctl_create_conf *conf)
{
struct request_queue *bqueue = dev->q;
struct request_queue *tqueue = tdisk->queue;
@@ -1421,7 +1434,15 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
spin_lock_init(&rrpc->bio_lock);
INIT_WORK(&rrpc->ws_requeue, rrpc_requeue);

- rrpc->nr_luns = lun_end - lun_begin + 1;
+ if (conf->type == NVM_CONFIG_TYPE_SIMPLE)
+ rrpc->nr_luns = conf->s.lun_end - conf->s.lun_begin + 1;
+
+ else if (conf->type == NVM_CONFIG_TYPE_LIST)
+ rrpc->nr_luns = conf->l.nr_luns;
+ else {
+ kfree(rrpc);
+ return ERR_PTR(-EINVAL);
+ }

/* simple round-robin strategy */
atomic_set(&rrpc->next_lun, -1);
@@ -1433,7 +1454,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
}
rrpc->soffset = soffset;

- ret = rrpc_luns_init(rrpc, lun_begin, lun_end);
+ ret = rrpc_luns_init(rrpc, conf);
if (ret) {
pr_err("nvm: rrpc: could not initialize luns\n");
goto err;
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 419a3db..b941a8c 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -431,7 +431,8 @@ static inline int ppa_to_slc(struct nvm_dev *dev, int slc_pg)

typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
typedef sector_t (nvm_tgt_capacity_fn)(void *);
-typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *, int, int);
+typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *,
+ struct nvm_ioctl_create_conf *);
typedef void (nvm_tgt_exit_fn)(void *);

struct nvm_tgt_type {
diff --git a/include/uapi/linux/lightnvm.h b/include/uapi/linux/lightnvm.h
index 774a431..6dbf6a0 100644
--- a/include/uapi/linux/lightnvm.h
+++ b/include/uapi/linux/lightnvm.h
@@ -35,6 +35,8 @@
#define NVM_TTYPE_MAX 63
#define NVM_MMTYPE_LEN 8

+#define NVM_LUNS_MAX 768
+
#define NVM_CTRL_FILE "/dev/lightnvm/control"

struct nvm_ioctl_info_tgt {
@@ -74,14 +76,21 @@ struct nvm_ioctl_create_simple {
__u32 lun_end;
};

+struct nvm_ioctl_create_list {
+ __u32 nr_luns;
+ __u32 lunid[NVM_LUNS_MAX];
+};
+
enum {
NVM_CONFIG_TYPE_SIMPLE = 0,
+ NVM_CONFIG_TYPE_LIST,
};

struct nvm_ioctl_create_conf {
__u32 type;
union {
struct nvm_ioctl_create_simple s;
+ struct nvm_ioctl_create_list l;
};
};

--
1.9.1

2016-03-19 17:01:01

by Wenwei Tao

[permalink] [raw]
Subject: [PATCH 3/3] lightnvm: export per lun information to user

Export per lun information to user, let the user
know more detail information about underlying device.

Signed-off-by: Wenwei Tao <[email protected]>
---
drivers/lightnvm/core.c | 59 ++++++++++++++++++++++++++++++++++++++++++-
drivers/lightnvm/gennvm.c | 34 +++++++++++++++++++++++++
include/linux/lightnvm.h | 3 +++
include/uapi/linux/lightnvm.h | 23 +++++++++++++++++
4 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 84bc72d..7701eab 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -28,7 +28,6 @@
#include <linux/miscdevice.h>
#include <linux/lightnvm.h>
#include <linux/sched/sysctl.h>
-#include <uapi/linux/lightnvm.h>

static LIST_HEAD(nvm_targets);
static LIST_HEAD(nvm_mgrs);
@@ -1041,6 +1040,62 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
return __nvm_configure_remove(&remove);
}

+static long nvm_ioctl_dev_luns_status(struct file *file, void __user *arg)
+{
+ struct nvm_dev *dev;
+ struct nvm_ioctl_luns_status *status;
+ long ret = -EINVAL;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ status = kzalloc(sizeof(struct nvm_ioctl_luns_status), GFP_KERNEL);
+ if (!status)
+ return -ENOMEM;
+
+ if (copy_from_user(status, arg,
+ sizeof(struct nvm_ioctl_luns_status))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ status->dev[DISK_NAME_LEN - 1] = '\0';
+ down_write(&nvm_lock);
+ dev = nvm_find_nvm_dev(status->dev);
+ up_write(&nvm_lock);
+ if (!dev) {
+ pr_err("nvm: device not found\n");
+ goto out;
+ }
+
+ if (!dev->mt) {
+ pr_info("nvm: device has no media manager registered.\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (status->lun_begin > status->lun_end ||
+ status->lun_end > dev->nr_luns) {
+ pr_err("nvm: lun out of bound (%u:%u > %u)\n",
+ status->lun_begin, status->lun_end, dev->nr_luns);
+ goto out;
+ }
+
+ dev->mt->get_luns_status(dev, status);
+
+ if (copy_to_user(arg, status,
+ sizeof(struct nvm_ioctl_luns_status))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ kfree(status);
+ return ret;
+}
+
static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info)
{
info->seqnr = 1;
@@ -1150,6 +1205,8 @@ static long nvm_ctl_ioctl(struct file *file, uint cmd, unsigned long arg)
return nvm_ioctl_dev_create(file, argp);
case NVM_DEV_REMOVE:
return nvm_ioctl_dev_remove(file, argp);
+ case NVM_DEV_LUNS_STATUS:
+ return nvm_ioctl_dev_luns_status(file, argp);
case NVM_DEV_INIT:
return nvm_ioctl_dev_init(file, argp);
case NVM_DEV_FACTORY:
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index 72e124a..b2390f4 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -502,6 +502,39 @@ static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
return &gn->luns[lunid].vlun;
}

+static void gennvm_get_luns_status(struct nvm_dev *dev,
+ struct nvm_ioctl_luns_status *status)
+{
+ int i, lun_begin = status->lun_begin;
+ int nr_luns, lun_end = status->lun_end;
+ struct gen_nvm *gn = dev->mp;
+ struct nvm_lun_status *lun_stat;
+ struct gen_lun *lun;
+
+ status->nr_luns = dev->nr_luns;
+ nr_luns = min(lun_end - lun_begin + 1,
+ NVM_LUNS_STATUS);
+
+ for (i = 0; i < nr_luns; i++) {
+ lun = &gn->luns[i + lun_begin];
+ lun_stat = &status->status[i];
+
+ lun_stat->reserved =
+ test_bit(i + lun_begin, dev->lun_map);
+ lun_stat->id = lun->vlun.id;
+ lun_stat->lun_id = lun->vlun.lun_id;
+ lun_stat->chnl_id = lun->vlun.chnl_id;
+ lun_stat->nr_free_blocks =
+ lun->vlun.nr_free_blocks;
+ lun_stat->nr_open_blocks =
+ lun->vlun.nr_open_blocks;
+ lun_stat->nr_closed_blocks =
+ lun->vlun.nr_closed_blocks;
+ lun_stat->nr_bad_blocks =
+ lun->vlun.nr_bad_blocks;
+ }
+}
+
static void gennvm_lun_info_print(struct nvm_dev *dev)
{
struct gen_nvm *gn = dev->mp;
@@ -542,6 +575,7 @@ static struct nvmm_type gennvm = {
.get_lun = gennvm_get_lun,
.reserve_lun = gennvm_reserve_lun,
.release_lun = gennvm_release_lun,
+ .get_luns_status = gennvm_get_luns_status,
.lun_info_print = gennvm_lun_info_print,

.get_area = gennvm_get_area,
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index b941a8c..88b95f9 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -472,6 +472,8 @@ typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
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_get_luns_status)(struct nvm_dev *,
+ struct nvm_ioctl_luns_status *);
typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);

typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
@@ -502,6 +504,7 @@ struct nvmm_type {
nvmm_release_lun *release_lun;

/* Statistics */
+ nvmm_get_luns_status *get_luns_status;
nvmm_lun_info_print_fn *lun_info_print;

nvmm_get_area_fn *get_area;
diff --git a/include/uapi/linux/lightnvm.h b/include/uapi/linux/lightnvm.h
index 6dbf6a0..2d52d6d 100644
--- a/include/uapi/linux/lightnvm.h
+++ b/include/uapi/linux/lightnvm.h
@@ -36,6 +36,7 @@
#define NVM_MMTYPE_LEN 8

#define NVM_LUNS_MAX 768
+#define NVM_LUNS_STATUS 64

#define NVM_CTRL_FILE "/dev/lightnvm/control"

@@ -110,6 +111,25 @@ struct nvm_ioctl_remove {
__u32 flags;
};

+struct nvm_lun_status {
+ bool reserved;
+ __u32 id;
+ __u32 lun_id;
+ __u32 chnl_id;
+ __u32 nr_open_blocks;
+ __u32 nr_closed_blocks;
+ __u32 nr_free_blocks;
+ __u32 nr_bad_blocks;
+};
+
+struct nvm_ioctl_luns_status {
+ char dev[DISK_NAME_LEN];
+ __u32 nr_luns;
+ __u32 lun_begin;
+ __u32 lun_end;
+ struct nvm_lun_status status[NVM_LUNS_STATUS];
+};
+
struct nvm_ioctl_dev_init {
char dev[DISK_NAME_LEN]; /* open-channel SSD device */
char mmtype[NVM_MMTYPE_LEN]; /* register to media manager */
@@ -140,6 +160,7 @@ enum {
/* device level cmds */
NVM_DEV_CREATE_CMD,
NVM_DEV_REMOVE_CMD,
+ NVM_DEV_LUNS_STATUS_CMD,

/* Init a device to support LightNVM media managers */
NVM_DEV_INIT_CMD,
@@ -158,6 +179,8 @@ enum {
struct nvm_ioctl_create)
#define NVM_DEV_REMOVE _IOW(NVM_IOCTL, NVM_DEV_REMOVE_CMD, \
struct nvm_ioctl_remove)
+#define NVM_DEV_LUNS_STATUS _IOW(NVM_IOCTL, NVM_DEV_LUNS_STATUS_CMD, \
+ struct nvm_ioctl_luns_status)
#define NVM_DEV_INIT _IOW(NVM_IOCTL, NVM_DEV_INIT_CMD, \
struct nvm_ioctl_dev_init)
#define NVM_DEV_FACTORY _IOW(NVM_IOCTL, NVM_DEV_FACTORY_CMD, \
--
1.9.1

2016-03-21 10:27:48

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 3/3] lightnvm: export per lun information to user

On 03/19/2016 05:58 PM, Wenwei Tao wrote:
> Export per lun information to user, let the user
> know more detail information about underlying device.
>
> Signed-off-by: Wenwei Tao <[email protected]>
> ---
> drivers/lightnvm/core.c | 59 ++++++++++++++++++++++++++++++++++++++++++-
> drivers/lightnvm/gennvm.c | 34 +++++++++++++++++++++++++
> include/linux/lightnvm.h | 3 +++
> include/uapi/linux/lightnvm.h | 23 +++++++++++++++++
> 4 files changed, 118 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
> index 84bc72d..7701eab 100644
> --- a/drivers/lightnvm/core.c
> +++ b/drivers/lightnvm/core.c
> @@ -28,7 +28,6 @@
> #include <linux/miscdevice.h>
> #include <linux/lightnvm.h>
> #include <linux/sched/sysctl.h>
> -#include <uapi/linux/lightnvm.h>
>
> static LIST_HEAD(nvm_targets);
> static LIST_HEAD(nvm_mgrs);
> @@ -1041,6 +1040,62 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
> return __nvm_configure_remove(&remove);
> }
>
> +static long nvm_ioctl_dev_luns_status(struct file *file, void __user *arg)
> +{
> + struct nvm_dev *dev;
> + struct nvm_ioctl_luns_status *status;
> + long ret = -EINVAL;
> +
> + if (!capable(CAP_SYS_ADMIN))
> + return -EPERM;
> +
> + status = kzalloc(sizeof(struct nvm_ioctl_luns_status), GFP_KERNEL);
> + if (!status)
> + return -ENOMEM;
> +
> + if (copy_from_user(status, arg,
> + sizeof(struct nvm_ioctl_luns_status))) {
> + ret = -EFAULT;
> + goto out;
> + }
> +
> + status->dev[DISK_NAME_LEN - 1] = '\0';
> + down_write(&nvm_lock);
> + dev = nvm_find_nvm_dev(status->dev);
> + up_write(&nvm_lock);
> + if (!dev) {
> + pr_err("nvm: device not found\n");
> + goto out;
> + }
> +
> + if (!dev->mt) {
> + pr_info("nvm: device has no media manager registered.\n");
> + ret = -ENODEV;
> + goto out;
> + }
> +
> + if (status->lun_begin > status->lun_end ||
> + status->lun_end > dev->nr_luns) {
> + pr_err("nvm: lun out of bound (%u:%u > %u)\n",
> + status->lun_begin, status->lun_end, dev->nr_luns);
> + goto out;
> + }
> +
> + dev->mt->get_luns_status(dev, status);
> +
> + if (copy_to_user(arg, status,
> + sizeof(struct nvm_ioctl_luns_status))) {
> + ret = -EFAULT;
> + goto out;
> + }
> +
> + ret = 0;
> +
> +out:
> + kfree(status);
> + return ret;
> +}
> +
> static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info)
> {
> info->seqnr = 1;
> @@ -1150,6 +1205,8 @@ static long nvm_ctl_ioctl(struct file *file, uint cmd, unsigned long arg)
> return nvm_ioctl_dev_create(file, argp);
> case NVM_DEV_REMOVE:
> return nvm_ioctl_dev_remove(file, argp);
> + case NVM_DEV_LUNS_STATUS:
> + return nvm_ioctl_dev_luns_status(file, argp);
> case NVM_DEV_INIT:
> return nvm_ioctl_dev_init(file, argp);
> case NVM_DEV_FACTORY:
> diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
> index 72e124a..b2390f4 100644
> --- a/drivers/lightnvm/gennvm.c
> +++ b/drivers/lightnvm/gennvm.c
> @@ -502,6 +502,39 @@ static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
> return &gn->luns[lunid].vlun;
> }
>
> +static void gennvm_get_luns_status(struct nvm_dev *dev,
> + struct nvm_ioctl_luns_status *status)
> +{
> + int i, lun_begin = status->lun_begin;
> + int nr_luns, lun_end = status->lun_end;
> + struct gen_nvm *gn = dev->mp;
> + struct nvm_lun_status *lun_stat;
> + struct gen_lun *lun;
> +
> + status->nr_luns = dev->nr_luns;
> + nr_luns = min(lun_end - lun_begin + 1,
> + NVM_LUNS_STATUS);
> +
> + for (i = 0; i < nr_luns; i++) {
> + lun = &gn->luns[i + lun_begin];
> + lun_stat = &status->status[i];
> +
> + lun_stat->reserved =
> + test_bit(i + lun_begin, dev->lun_map);
> + lun_stat->id = lun->vlun.id;
> + lun_stat->lun_id = lun->vlun.lun_id;
> + lun_stat->chnl_id = lun->vlun.chnl_id;
> + lun_stat->nr_free_blocks =
> + lun->vlun.nr_free_blocks;
> + lun_stat->nr_open_blocks =
> + lun->vlun.nr_open_blocks;
> + lun_stat->nr_closed_blocks =
> + lun->vlun.nr_closed_blocks;
> + lun_stat->nr_bad_blocks =
> + lun->vlun.nr_bad_blocks;
> + }
> +}
> +
> static void gennvm_lun_info_print(struct nvm_dev *dev)
> {
> struct gen_nvm *gn = dev->mp;
> @@ -542,6 +575,7 @@ static struct nvmm_type gennvm = {
> .get_lun = gennvm_get_lun,
> .reserve_lun = gennvm_reserve_lun,
> .release_lun = gennvm_release_lun,
> + .get_luns_status = gennvm_get_luns_status,
> .lun_info_print = gennvm_lun_info_print,
>
> .get_area = gennvm_get_area,
> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
> index b941a8c..88b95f9 100644
> --- a/include/linux/lightnvm.h
> +++ b/include/linux/lightnvm.h
> @@ -472,6 +472,8 @@ typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
> 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_get_luns_status)(struct nvm_dev *,
> + struct nvm_ioctl_luns_status *);
> typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
>
> typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
> @@ -502,6 +504,7 @@ struct nvmm_type {
> nvmm_release_lun *release_lun;
>
> /* Statistics */
> + nvmm_get_luns_status *get_luns_status;
> nvmm_lun_info_print_fn *lun_info_print;
>
> nvmm_get_area_fn *get_area;
> diff --git a/include/uapi/linux/lightnvm.h b/include/uapi/linux/lightnvm.h
> index 6dbf6a0..2d52d6d 100644
> --- a/include/uapi/linux/lightnvm.h
> +++ b/include/uapi/linux/lightnvm.h
> @@ -36,6 +36,7 @@
> #define NVM_MMTYPE_LEN 8
>
> #define NVM_LUNS_MAX 768
> +#define NVM_LUNS_STATUS 64
>
> #define NVM_CTRL_FILE "/dev/lightnvm/control"
>
> @@ -110,6 +111,25 @@ struct nvm_ioctl_remove {
> __u32 flags;
> };
>
> +struct nvm_lun_status {
> + bool reserved;
> + __u32 id;
> + __u32 lun_id;
> + __u32 chnl_id;
> + __u32 nr_open_blocks;
> + __u32 nr_closed_blocks;
> + __u32 nr_free_blocks;
> + __u32 nr_bad_blocks;
> +};
> +
> +struct nvm_ioctl_luns_status {
> + char dev[DISK_NAME_LEN];
> + __u32 nr_luns;
> + __u32 lun_begin;
> + __u32 lun_end;
> + struct nvm_lun_status status[NVM_LUNS_STATUS];
> +};
> +
> struct nvm_ioctl_dev_init {
> char dev[DISK_NAME_LEN]; /* open-channel SSD device */
> char mmtype[NVM_MMTYPE_LEN]; /* register to media manager */
> @@ -140,6 +160,7 @@ enum {
> /* device level cmds */
> NVM_DEV_CREATE_CMD,
> NVM_DEV_REMOVE_CMD,
> + NVM_DEV_LUNS_STATUS_CMD,
>
> /* Init a device to support LightNVM media managers */
> NVM_DEV_INIT_CMD,
> @@ -158,6 +179,8 @@ enum {
> struct nvm_ioctl_create)
> #define NVM_DEV_REMOVE _IOW(NVM_IOCTL, NVM_DEV_REMOVE_CMD, \
> struct nvm_ioctl_remove)
> +#define NVM_DEV_LUNS_STATUS _IOW(NVM_IOCTL, NVM_DEV_LUNS_STATUS_CMD, \
> + struct nvm_ioctl_luns_status)
> #define NVM_DEV_INIT _IOW(NVM_IOCTL, NVM_DEV_INIT_CMD, \
> struct nvm_ioctl_dev_init)
> #define NVM_DEV_FACTORY _IOW(NVM_IOCTL, NVM_DEV_FACTORY_CMD, \
>

I think it will be better to expose this through sysfs. There is a patch
coming up that will add support and enable us to get the luns.

2016-03-22 11:28:32

by Wenwei Tao

[permalink] [raw]
Subject: Re: [PATCH 3/3] lightnvm: export per lun information to user

I notice that sysfs already have lun information exposed, we only need
to add some more,

2016-03-21 18:27 GMT+08:00 Matias Bjørling <[email protected]>:
> On 03/19/2016 05:58 PM, Wenwei Tao wrote:
>>
>> Export per lun information to user, let the user
>> know more detail information about underlying device.
>>
>> Signed-off-by: Wenwei Tao <[email protected]>
>> ---
>> drivers/lightnvm/core.c | 59
>> ++++++++++++++++++++++++++++++++++++++++++-
>> drivers/lightnvm/gennvm.c | 34 +++++++++++++++++++++++++
>> include/linux/lightnvm.h | 3 +++
>> include/uapi/linux/lightnvm.h | 23 +++++++++++++++++
>> 4 files changed, 118 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
>> index 84bc72d..7701eab 100644
>> --- a/drivers/lightnvm/core.c
>> +++ b/drivers/lightnvm/core.c
>> @@ -28,7 +28,6 @@
>> #include <linux/miscdevice.h>
>> #include <linux/lightnvm.h>
>> #include <linux/sched/sysctl.h>
>> -#include <uapi/linux/lightnvm.h>
>>
>> static LIST_HEAD(nvm_targets);
>> static LIST_HEAD(nvm_mgrs);
>> @@ -1041,6 +1040,62 @@ static long nvm_ioctl_dev_remove(struct file *file,
>> void __user *arg)
>> return __nvm_configure_remove(&remove);
>> }
>>
>> +static long nvm_ioctl_dev_luns_status(struct file *file, void __user
>> *arg)
>> +{
>> + struct nvm_dev *dev;
>> + struct nvm_ioctl_luns_status *status;
>> + long ret = -EINVAL;
>> +
>> + if (!capable(CAP_SYS_ADMIN))
>> + return -EPERM;
>> +
>> + status = kzalloc(sizeof(struct nvm_ioctl_luns_status),
>> GFP_KERNEL);
>> + if (!status)
>> + return -ENOMEM;
>> +
>> + if (copy_from_user(status, arg,
>> + sizeof(struct nvm_ioctl_luns_status))) {
>> + ret = -EFAULT;
>> + goto out;
>> + }
>> +
>> + status->dev[DISK_NAME_LEN - 1] = '\0';
>> + down_write(&nvm_lock);
>> + dev = nvm_find_nvm_dev(status->dev);
>> + up_write(&nvm_lock);
>> + if (!dev) {
>> + pr_err("nvm: device not found\n");
>> + goto out;
>> + }
>> +
>> + if (!dev->mt) {
>> + pr_info("nvm: device has no media manager registered.\n");
>> + ret = -ENODEV;
>> + goto out;
>> + }
>> +
>> + if (status->lun_begin > status->lun_end ||
>> + status->lun_end > dev->nr_luns) {
>> + pr_err("nvm: lun out of bound (%u:%u > %u)\n",
>> + status->lun_begin, status->lun_end, dev->nr_luns);
>> + goto out;
>> + }
>> +
>> + dev->mt->get_luns_status(dev, status);
>> +
>> + if (copy_to_user(arg, status,
>> + sizeof(struct nvm_ioctl_luns_status))) {
>> + ret = -EFAULT;
>> + goto out;
>> + }
>> +
>> + ret = 0;
>> +
>> +out:
>> + kfree(status);
>> + return ret;
>> +}
>> +
>> static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info)
>> {
>> info->seqnr = 1;
>> @@ -1150,6 +1205,8 @@ static long nvm_ctl_ioctl(struct file *file, uint
>> cmd, unsigned long arg)
>> return nvm_ioctl_dev_create(file, argp);
>> case NVM_DEV_REMOVE:
>> return nvm_ioctl_dev_remove(file, argp);
>> + case NVM_DEV_LUNS_STATUS:
>> + return nvm_ioctl_dev_luns_status(file, argp);
>> case NVM_DEV_INIT:
>> return nvm_ioctl_dev_init(file, argp);
>> case NVM_DEV_FACTORY:
>> diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
>> index 72e124a..b2390f4 100644
>> --- a/drivers/lightnvm/gennvm.c
>> +++ b/drivers/lightnvm/gennvm.c
>> @@ -502,6 +502,39 @@ static struct nvm_lun *gennvm_get_lun(struct nvm_dev
>> *dev, int lunid)
>> return &gn->luns[lunid].vlun;
>> }
>>
>> +static void gennvm_get_luns_status(struct nvm_dev *dev,
>> + struct nvm_ioctl_luns_status *status)
>> +{
>> + int i, lun_begin = status->lun_begin;
>> + int nr_luns, lun_end = status->lun_end;
>> + struct gen_nvm *gn = dev->mp;
>> + struct nvm_lun_status *lun_stat;
>> + struct gen_lun *lun;
>> +
>> + status->nr_luns = dev->nr_luns;
>> + nr_luns = min(lun_end - lun_begin + 1,
>> + NVM_LUNS_STATUS);
>> +
>> + for (i = 0; i < nr_luns; i++) {
>> + lun = &gn->luns[i + lun_begin];
>> + lun_stat = &status->status[i];
>> +
>> + lun_stat->reserved =
>> + test_bit(i + lun_begin, dev->lun_map);
>> + lun_stat->id = lun->vlun.id;
>> + lun_stat->lun_id = lun->vlun.lun_id;
>> + lun_stat->chnl_id = lun->vlun.chnl_id;
>> + lun_stat->nr_free_blocks =
>> + lun->vlun.nr_free_blocks;
>> + lun_stat->nr_open_blocks =
>> + lun->vlun.nr_open_blocks;
>> + lun_stat->nr_closed_blocks =
>> + lun->vlun.nr_closed_blocks;
>> + lun_stat->nr_bad_blocks =
>> + lun->vlun.nr_bad_blocks;
>> + }
>> +}
>> +
>> static void gennvm_lun_info_print(struct nvm_dev *dev)
>> {
>> struct gen_nvm *gn = dev->mp;
>> @@ -542,6 +575,7 @@ static struct nvmm_type gennvm = {
>> .get_lun = gennvm_get_lun,
>> .reserve_lun = gennvm_reserve_lun,
>> .release_lun = gennvm_release_lun,
>> + .get_luns_status = gennvm_get_luns_status,
>> .lun_info_print = gennvm_lun_info_print,
>>
>> .get_area = gennvm_get_area,
>> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
>> index b941a8c..88b95f9 100644
>> --- a/include/linux/lightnvm.h
>> +++ b/include/linux/lightnvm.h
>> @@ -472,6 +472,8 @@ typedef int (nvmm_erase_blk_fn)(struct nvm_dev *,
>> struct nvm_block *,
>> 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_get_luns_status)(struct nvm_dev *,
>> + struct nvm_ioctl_luns_status *);
>> typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
>>
>> typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
>> @@ -502,6 +504,7 @@ struct nvmm_type {
>> nvmm_release_lun *release_lun;
>>
>> /* Statistics */
>> + nvmm_get_luns_status *get_luns_status;
>> nvmm_lun_info_print_fn *lun_info_print;
>>
>> nvmm_get_area_fn *get_area;
>> diff --git a/include/uapi/linux/lightnvm.h b/include/uapi/linux/lightnvm.h
>> index 6dbf6a0..2d52d6d 100644
>> --- a/include/uapi/linux/lightnvm.h
>> +++ b/include/uapi/linux/lightnvm.h
>> @@ -36,6 +36,7 @@
>> #define NVM_MMTYPE_LEN 8
>>
>> #define NVM_LUNS_MAX 768
>> +#define NVM_LUNS_STATUS 64
>>
>> #define NVM_CTRL_FILE "/dev/lightnvm/control"
>>
>> @@ -110,6 +111,25 @@ struct nvm_ioctl_remove {
>> __u32 flags;
>> };
>>
>> +struct nvm_lun_status {
>> + bool reserved;
>> + __u32 id;
>> + __u32 lun_id;
>> + __u32 chnl_id;
>> + __u32 nr_open_blocks;
>> + __u32 nr_closed_blocks;
>> + __u32 nr_free_blocks;
>> + __u32 nr_bad_blocks;
>> +};
>> +
>> +struct nvm_ioctl_luns_status {
>> + char dev[DISK_NAME_LEN];
>> + __u32 nr_luns;
>> + __u32 lun_begin;
>> + __u32 lun_end;
>> + struct nvm_lun_status status[NVM_LUNS_STATUS];
>> +};
>> +
>> struct nvm_ioctl_dev_init {
>> char dev[DISK_NAME_LEN]; /* open-channel SSD device
>> */
>> char mmtype[NVM_MMTYPE_LEN]; /* register to media
>> manager */
>> @@ -140,6 +160,7 @@ enum {
>> /* device level cmds */
>> NVM_DEV_CREATE_CMD,
>> NVM_DEV_REMOVE_CMD,
>> + NVM_DEV_LUNS_STATUS_CMD,
>>
>> /* Init a device to support LightNVM media managers */
>> NVM_DEV_INIT_CMD,
>> @@ -158,6 +179,8 @@ enum {
>> struct nvm_ioctl_create)
>> #define NVM_DEV_REMOVE _IOW(NVM_IOCTL,
>> NVM_DEV_REMOVE_CMD, \
>> struct nvm_ioctl_remove)
>> +#define NVM_DEV_LUNS_STATUS _IOW(NVM_IOCTL, NVM_DEV_LUNS_STATUS_CMD, \
>> + struct
>> nvm_ioctl_luns_status)
>> #define NVM_DEV_INIT _IOW(NVM_IOCTL, NVM_DEV_INIT_CMD, \
>> struct nvm_ioctl_dev_init)
>> #define NVM_DEV_FACTORY _IOW(NVM_IOCTL,
>> NVM_DEV_FACTORY_CMD, \
>>
>
> I think it will be better to expose this through sysfs. There is a patch
> coming up that will add support and enable us to get the luns.
>

2016-03-22 20:56:53

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 3/3] lightnvm: export per lun information to user

On 03/22/2016 12:28 PM, Wenwei Tao wrote:
> I notice that sysfs already have lun information exposed, we only need
> to add some more,
>

You are right, but that is for the configure_debug interface. It is not
compiled in on production kernels.