@@ -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)
@@ -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;
@@ -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 {
@@ -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;
};
};
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 <ww.tao0320@gmail.com> --- 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(-)