summaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm/rrpc.c
diff options
context:
space:
mode:
authorWenwei Tao <ww.tao0320@gmail.com>2016-03-03 15:06:37 +0100
committerJens Axboe <axboe@fb.com>2016-03-18 18:10:37 -0700
commit4c9dacb82d5aa36aa2568df60d897f2eb3d8819b (patch)
treebd8e6a81aed966d79e50fc5cee3273c88a1a52ce /drivers/lightnvm/rrpc.c
parent3681c85dffda70e551dead31c8d102bd69033fe8 (diff)
downloadop-kernel-dev-4c9dacb82d5aa36aa2568df60d897f2eb3d8819b.zip
op-kernel-dev-4c9dacb82d5aa36aa2568df60d897f2eb3d8819b.tar.gz
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: Wenwei Tao <ww.tao0320@gmail.com> Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/lightnvm/rrpc.c')
-rw-r--r--drivers/lightnvm/rrpc.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
index 8234378..c1e3c83 100644
--- a/drivers/lightnvm/rrpc.c
+++ b/drivers/lightnvm/rrpc.c
@@ -1053,8 +1053,11 @@ static int rrpc_map_init(struct rrpc *rrpc)
{
struct nvm_dev *dev = rrpc->dev;
sector_t i;
+ u64 slba;
int ret;
+ slba = rrpc->soffset >> (ilog2(dev->sec_size) - 9);
+
rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects);
if (!rrpc->trans_map)
return -ENOMEM;
@@ -1076,7 +1079,7 @@ static int rrpc_map_init(struct rrpc *rrpc)
return 0;
/* 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);
if (ret) {
pr_err("nvm: rrpc: could not read L2P table.\n");
@@ -1086,7 +1089,6 @@ static int rrpc_map_init(struct rrpc *rrpc)
return 0;
}
-
/* Minimum pages needed within a lun */
#define PAGE_POOL_SIZE 16
#define ADDR_POOL_SIZE 64
@@ -1200,12 +1202,33 @@ err:
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)
{
rrpc_gc_free(rrpc);
rrpc_map_free(rrpc);
rrpc_core_free(rrpc);
rrpc_luns_free(rrpc);
+ rrpc_area_free(rrpc);
kfree(rrpc);
}
@@ -1327,6 +1350,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
struct request_queue *bqueue = dev->q;
struct request_queue *tqueue = tdisk->queue;
struct rrpc *rrpc;
+ sector_t soffset;
int ret;
if (!(dev->identity.dom & NVM_RSP_L2P)) {
@@ -1352,6 +1376,13 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
/* simple round-robin strategy */
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);
if (ret) {
pr_err("nvm: rrpc: could not initialize luns\n");
OpenPOWER on IntegriCloud