Commit 4c9dacb8 authored by Wenwei Tao's avatar Wenwei Tao Committed by Jens Axboe

lightnvm: specify target's logical address area

We can create more than one target on a lightnvm
device by specifying its begin lun and end lun.

But only specify the physical address area is not
enough, we need to get the corresponding non-
intersection logical address area division from
the backend device's logcial address space.
Otherwise the targets on the device might use
the same logical addresses cause incorrect
information in the device's l2p table.
Signed-off-by: default avatarWenwei Tao <ww.tao0320@gmail.com>
Signed-off-by: default avatarMatias Bjørling <m@bjorling.me>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 3681c85d
...@@ -466,6 +466,7 @@ static int nvm_core_init(struct nvm_dev *dev) ...@@ -466,6 +466,7 @@ static int nvm_core_init(struct nvm_dev *dev)
dev->total_secs = dev->nr_luns * dev->sec_per_lun; dev->total_secs = dev->nr_luns * dev->sec_per_lun;
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);
return 0; return 0;
} }
......
...@@ -20,6 +20,68 @@ ...@@ -20,6 +20,68 @@
#include "gennvm.h" #include "gennvm.h"
static int gennvm_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len)
{
struct gen_nvm *gn = dev->mp;
struct gennvm_area *area, *prev, *next;
sector_t begin = 0;
sector_t max_sectors = (dev->sec_size * dev->total_secs) >> 9;
if (len > max_sectors)
return -EINVAL;
area = kmalloc(sizeof(struct gennvm_area), GFP_KERNEL);
if (!area)
return -ENOMEM;
prev = NULL;
spin_lock(&dev->lock);
list_for_each_entry(next, &gn->area_list, list) {
if (begin + len > next->begin) {
begin = next->end;
prev = next;
continue;
}
break;
}
if ((begin + len) > max_sectors) {
spin_unlock(&dev->lock);
kfree(area);
return -EINVAL;
}
area->begin = *lba = begin;
area->end = begin + len;
if (prev) /* insert into sorted order */
list_add(&area->list, &prev->list);
else
list_add(&area->list, &gn->area_list);
spin_unlock(&dev->lock);
return 0;
}
static void gennvm_put_area(struct nvm_dev *dev, sector_t begin)
{
struct gen_nvm *gn = dev->mp;
struct gennvm_area *area;
spin_lock(&dev->lock);
list_for_each_entry(area, &gn->area_list, list) {
if (area->begin != begin)
continue;
list_del(&area->list);
spin_unlock(&dev->lock);
kfree(area);
return;
}
spin_unlock(&dev->lock);
}
static void gennvm_blocks_free(struct nvm_dev *dev) static void gennvm_blocks_free(struct nvm_dev *dev)
{ {
struct gen_nvm *gn = dev->mp; struct gen_nvm *gn = dev->mp;
...@@ -229,6 +291,7 @@ static int gennvm_register(struct nvm_dev *dev) ...@@ -229,6 +291,7 @@ static int gennvm_register(struct nvm_dev *dev)
gn->dev = dev; gn->dev = dev;
gn->nr_luns = dev->nr_luns; gn->nr_luns = dev->nr_luns;
INIT_LIST_HEAD(&gn->area_list);
dev->mp = gn; dev->mp = gn;
ret = gennvm_luns_init(dev, gn); ret = gennvm_luns_init(dev, gn);
...@@ -465,6 +528,10 @@ static struct nvmm_type gennvm = { ...@@ -465,6 +528,10 @@ static struct nvmm_type gennvm = {
.get_lun = gennvm_get_lun, .get_lun = gennvm_get_lun,
.lun_info_print = gennvm_lun_info_print, .lun_info_print = gennvm_lun_info_print,
.get_area = gennvm_get_area,
.put_area = gennvm_put_area,
}; };
static int __init gennvm_module_init(void) static int __init gennvm_module_init(void)
......
...@@ -39,8 +39,14 @@ struct gen_nvm { ...@@ -39,8 +39,14 @@ struct gen_nvm {
int nr_luns; int nr_luns;
struct gen_lun *luns; struct gen_lun *luns;
struct list_head area_list;
}; };
struct gennvm_area {
struct list_head list;
sector_t begin;
sector_t end; /* end is excluded */
};
#define gennvm_for_each_lun(bm, lun, i) \ #define gennvm_for_each_lun(bm, lun, i) \
for ((i) = 0, lun = &(bm)->luns[0]; \ for ((i) = 0, lun = &(bm)->luns[0]; \
(i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)]) (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)])
......
...@@ -1053,8 +1053,11 @@ static int rrpc_map_init(struct rrpc *rrpc) ...@@ -1053,8 +1053,11 @@ static int rrpc_map_init(struct rrpc *rrpc)
{ {
struct nvm_dev *dev = rrpc->dev; struct nvm_dev *dev = rrpc->dev;
sector_t i; sector_t i;
u64 slba;
int ret; int ret;
slba = rrpc->soffset >> (ilog2(dev->sec_size) - 9);
rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects); rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects);
if (!rrpc->trans_map) if (!rrpc->trans_map)
return -ENOMEM; return -ENOMEM;
...@@ -1076,7 +1079,7 @@ static int rrpc_map_init(struct rrpc *rrpc) ...@@ -1076,7 +1079,7 @@ static int rrpc_map_init(struct rrpc *rrpc)
return 0; return 0;
/* Bring up the mapping table from device */ /* Bring up the mapping table from device */
ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, rrpc_l2p_update, ret = dev->ops->get_l2p_tbl(dev, slba, rrpc->nr_sects, rrpc_l2p_update,
rrpc); rrpc);
if (ret) { if (ret) {
pr_err("nvm: rrpc: could not read L2P table.\n"); pr_err("nvm: rrpc: could not read L2P table.\n");
...@@ -1086,7 +1089,6 @@ static int rrpc_map_init(struct rrpc *rrpc) ...@@ -1086,7 +1089,6 @@ static int rrpc_map_init(struct rrpc *rrpc)
return 0; return 0;
} }
/* Minimum pages needed within a lun */ /* Minimum pages needed within a lun */
#define PAGE_POOL_SIZE 16 #define PAGE_POOL_SIZE 16
#define ADDR_POOL_SIZE 64 #define ADDR_POOL_SIZE 64
...@@ -1200,12 +1202,33 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end) ...@@ -1200,12 +1202,33 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
return -ENOMEM; return -ENOMEM;
} }
/* returns 0 on success and stores the beginning address in *begin */
static int rrpc_area_init(struct rrpc *rrpc, sector_t *begin)
{
struct nvm_dev *dev = rrpc->dev;
struct nvmm_type *mt = dev->mt;
sector_t size = rrpc->nr_sects * dev->sec_size;
size >>= 9;
return mt->get_area(dev, begin, size);
}
static void rrpc_area_free(struct rrpc *rrpc)
{
struct nvm_dev *dev = rrpc->dev;
struct nvmm_type *mt = dev->mt;
mt->put_area(dev, rrpc->soffset);
}
static void rrpc_free(struct rrpc *rrpc) static void rrpc_free(struct rrpc *rrpc)
{ {
rrpc_gc_free(rrpc); rrpc_gc_free(rrpc);
rrpc_map_free(rrpc); rrpc_map_free(rrpc);
rrpc_core_free(rrpc); rrpc_core_free(rrpc);
rrpc_luns_free(rrpc); rrpc_luns_free(rrpc);
rrpc_area_free(rrpc);
kfree(rrpc); kfree(rrpc);
} }
...@@ -1327,6 +1350,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk, ...@@ -1327,6 +1350,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
struct request_queue *bqueue = dev->q; struct request_queue *bqueue = dev->q;
struct request_queue *tqueue = tdisk->queue; struct request_queue *tqueue = tdisk->queue;
struct rrpc *rrpc; struct rrpc *rrpc;
sector_t soffset;
int ret; int ret;
if (!(dev->identity.dom & NVM_RSP_L2P)) { if (!(dev->identity.dom & NVM_RSP_L2P)) {
...@@ -1352,6 +1376,13 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk, ...@@ -1352,6 +1376,13 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
/* simple round-robin strategy */ /* simple round-robin strategy */
atomic_set(&rrpc->next_lun, -1); atomic_set(&rrpc->next_lun, -1);
ret = rrpc_area_init(rrpc, &soffset);
if (ret < 0) {
pr_err("nvm: rrpc: could not initialize area\n");
return ERR_PTR(ret);
}
rrpc->soffset = soffset;
ret = rrpc_luns_init(rrpc, lun_begin, lun_end); ret = rrpc_luns_init(rrpc, lun_begin, lun_end);
if (ret) { if (ret) {
pr_err("nvm: rrpc: could not initialize luns\n"); pr_err("nvm: rrpc: could not initialize luns\n");
......
...@@ -97,6 +97,7 @@ struct rrpc { ...@@ -97,6 +97,7 @@ struct rrpc {
struct nvm_dev *dev; struct nvm_dev *dev;
struct gendisk *disk; struct gendisk *disk;
sector_t soffset; /* logical sector offset */
u64 poffset; /* physical page offset */ u64 poffset; /* physical page offset */
int lun_offset; int lun_offset;
......
...@@ -355,6 +355,7 @@ struct nvm_dev { ...@@ -355,6 +355,7 @@ struct nvm_dev {
char name[DISK_NAME_LEN]; char name[DISK_NAME_LEN];
struct mutex mlock; struct mutex mlock;
spinlock_t lock;
}; };
static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev, static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
...@@ -467,6 +468,9 @@ typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, ...@@ -467,6 +468,9 @@ 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 struct nvm_lun *(nvmm_get_lun_fn)(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 void (nvmm_put_area_fn)(struct nvm_dev *, sector_t);
struct nvmm_type { struct nvmm_type {
const char *name; const char *name;
unsigned int version[3]; unsigned int version[3];
...@@ -491,6 +495,10 @@ struct nvmm_type { ...@@ -491,6 +495,10 @@ struct nvmm_type {
/* Statistics */ /* Statistics */
nvmm_lun_info_print_fn *lun_info_print; nvmm_lun_info_print_fn *lun_info_print;
nvmm_get_area_fn *get_area;
nvmm_put_area_fn *put_area;
struct list_head list; struct list_head list;
}; };
......
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