From 5e422cffe822874cefc1657cd287c8647b2782dd Mon Sep 17 00:00:00 2001 From: Alan Date: Fri, 19 Feb 2016 13:56:57 +0100 Subject: lightnvm: fix up nonsensical configure overrun checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of checking a constant 0 actually check the space available. Even better remember to allow for the header and also check the right amount of space is needed. Signed-off-by: Alan Cox Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/lightnvm') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 33224cb91c5b..782ac5d60a49 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -870,20 +870,19 @@ static int nvm_configure_by_str_event(const char *val, static int nvm_configure_get(char *buf, const struct kernel_param *kp) { - int sz = 0; - char *buf_start = buf; + int sz; struct nvm_dev *dev; - buf += sprintf(buf, "available devices:\n"); + sz = sprintf(buf, "available devices:\n"); down_write(&nvm_lock); list_for_each_entry(dev, &nvm_devices, devices) { - if (sz > 4095 - DISK_NAME_LEN) + if (sz > 4095 - DISK_NAME_LEN - 2) break; - buf += sprintf(buf, " %32s\n", dev->name); + sz += sprintf(buf + sz, " %32s\n", dev->name); } up_write(&nvm_lock); - return buf - buf_start - 1; + return sz; } static const struct kernel_param_ops nvm_configure_by_str_event_param_ops = { -- cgit v1.2.3-59-g8ed1b From d5bdec8ddb9f5fac3b351bed463a7132f6ba907b Mon Sep 17 00:00:00 2001 From: Matias Bjørling Date: Fri, 19 Feb 2016 13:56:58 +0100 Subject: lightnvm: fold get bb tbl when using dual/quad plane mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the media manager runs in dual or quad plane mode, lightnvm abstracts away plane specific commands. This poses a problem for get bad block table, as it reports bad blocks per plane, making the table either two or four times bigger than expected. Fold the bad block list before returning. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 2 +- drivers/nvme/host/lightnvm.c | 46 +++++++++++++++++++++++++++++++++++++++----- include/linux/lightnvm.h | 6 +++--- 3 files changed, 45 insertions(+), 9 deletions(-) (limited to 'drivers/lightnvm') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 782ac5d60a49..968ba7ed4158 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -250,7 +250,7 @@ int nvm_set_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd, return 0; } - plane_cnt = (1 << dev->plane_mode); + plane_cnt = dev->plane_mode; rqd->nr_pages = plane_cnt * nr_ppas; if (dev->ops->max_phys_sect < rqd->nr_pages) diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 5cd3725e2fa4..d4f81f07f296 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -373,8 +373,31 @@ out: return ret; } +static void nvme_nvm_bb_tbl_fold(struct nvm_dev *nvmdev, + int nr_dst_blks, u8 *dst_blks, + int nr_src_blks, u8 *src_blks) +{ + int blk, offset, pl, blktype; + + for (blk = 0; blk < nr_dst_blks; blk++) { + offset = blk * nvmdev->plane_mode; + blktype = src_blks[offset]; + + /* Bad blocks on any planes take precedence over other types */ + for (pl = 0; pl < nvmdev->plane_mode; pl++) { + if (src_blks[offset + pl] & + (NVM_BLK_T_BAD|NVM_BLK_T_GRWN_BAD)) { + blktype = src_blks[offset + pl]; + break; + } + } + + dst_blks[blk] = blktype; + } +} + static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa, - int nr_blocks, nvm_bb_update_fn *update_bbtbl, + int nr_dst_blks, nvm_bb_update_fn *update_bbtbl, void *priv) { struct request_queue *q = nvmdev->q; @@ -382,7 +405,9 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa, struct nvme_ctrl *ctrl = ns->ctrl; struct nvme_nvm_command c = {}; struct nvme_nvm_bb_tbl *bb_tbl; - int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blocks; + u8 *dst_blks = NULL; + int nr_src_blks = nr_dst_blks * nvmdev->plane_mode; + int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_src_blks; int ret = 0; c.get_bb.opcode = nvme_nvm_admin_get_bb_tbl; @@ -393,6 +418,12 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa, if (!bb_tbl) return -ENOMEM; + dst_blks = kzalloc(nr_dst_blks, GFP_KERNEL); + if (!dst_blks) { + ret = -ENOMEM; + goto out; + } + ret = nvme_submit_sync_cmd(ctrl->admin_q, (struct nvme_command *)&c, bb_tbl, tblsz); if (ret) { @@ -414,16 +445,21 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa, goto out; } - if (le32_to_cpu(bb_tbl->tblks) != nr_blocks) { + if (le32_to_cpu(bb_tbl->tblks) != nr_src_blks) { ret = -EINVAL; dev_err(ctrl->dev, "bbt unsuspected blocks returned (%u!=%u)", - le32_to_cpu(bb_tbl->tblks), nr_blocks); + le32_to_cpu(bb_tbl->tblks), nr_src_blks); goto out; } + nvme_nvm_bb_tbl_fold(nvmdev, nr_dst_blks, dst_blks, + nr_src_blks, bb_tbl->blk); + ppa = dev_to_generic_addr(nvmdev, ppa); - ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv); + ret = update_bbtbl(ppa, nr_dst_blks, dst_blks, priv); + out: + kfree(dst_blks); kfree(bb_tbl); return ret; } diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index d6750111e48e..7fa1838f7356 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -92,9 +92,9 @@ enum { NVM_ADDRMODE_CHANNEL = 1, /* Plane programming mode for LUN */ - NVM_PLANE_SINGLE = 0, - NVM_PLANE_DOUBLE = 1, - NVM_PLANE_QUAD = 2, + NVM_PLANE_SINGLE = 1, + NVM_PLANE_DOUBLE = 2, + NVM_PLANE_QUAD = 4, /* Status codes */ NVM_RSP_SUCCESS = 0x0, -- cgit v1.2.3-59-g8ed1b From 6adb03de406e8c92579c2e4b11640841fa908277 Mon Sep 17 00:00:00 2001 From: Javier González Date: Sat, 20 Feb 2016 08:52:40 +0100 Subject: lightnvm: update closed list outside of intr context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an I/O finishes, full blocks are moved from the open to the closed list - a lock is taken to protect the list. This happens at the moment in the interrupt context, which is not correct. This patch moves this logic to the block workqueue instead, avoiding holding a spinlock without interrupt save in an interrupt context. Signed-off-by: Javier González Fixes: ff0e498bfa18 ("lightnvm: manage open and closed blocks sepa...") Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/rrpc.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/lightnvm') diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index d8c75958ced3..e2710da5cd78 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -497,12 +497,21 @@ static void rrpc_gc_queue(struct work_struct *work) struct rrpc *rrpc = gcb->rrpc; 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]; spin_lock(&rlun->lock); list_add_tail(&rblk->prio, &rlun->prio_list); spin_unlock(&rlun->lock); + spin_lock(&lun->lock); + lun->nr_open_blocks--; + lun->nr_closed_blocks++; + blk->state &= ~NVM_BLK_ST_OPEN; + blk->state |= NVM_BLK_ST_CLOSED; + list_move_tail(&rblk->list, &rlun->closed_list); + spin_unlock(&lun->lock); + mempool_free(gcb, rrpc->gcb_pool); pr_debug("nvm: block '%lu' is full, allow GC (sched)\n", rblk->parent->id); @@ -666,20 +675,8 @@ static void rrpc_end_io_write(struct rrpc *rrpc, struct rrpc_rq *rrqd, lun = rblk->parent->lun; cmnt_size = atomic_inc_return(&rblk->data_cmnt_size); - if (unlikely(cmnt_size == rrpc->dev->pgs_per_blk)) { - struct nvm_block *blk = rblk->parent; - struct rrpc_lun *rlun = rblk->rlun; - - spin_lock(&lun->lock); - lun->nr_open_blocks--; - lun->nr_closed_blocks++; - blk->state &= ~NVM_BLK_ST_OPEN; - blk->state |= NVM_BLK_ST_CLOSED; - list_move_tail(&rblk->list, &rlun->closed_list); - spin_unlock(&lun->lock); - + if (unlikely(cmnt_size == rrpc->dev->pgs_per_blk)) rrpc_run_gc(rrpc, rblk); - } } } -- cgit v1.2.3-59-g8ed1b From 4ece44af733ff63a7cd12aaa8c85afb6d9fdc664 Mon Sep 17 00:00:00 2001 From: Matias Bjørling Date: Sat, 20 Feb 2016 08:52:41 +0100 Subject: lightnvm: rename ->nr_pages to ->nr_sects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct rrpc->nr_pages can easily be interpreted as the number of flash pages allocated to rrpc, while it is the nr_sects. Make sure that this is reflected from the variable name. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 2 +- drivers/lightnvm/gennvm.c | 7 +++---- drivers/lightnvm/rrpc.c | 29 ++++++++++++++--------------- drivers/lightnvm/rrpc.h | 6 +++--- include/linux/lightnvm.h | 2 +- 5 files changed, 22 insertions(+), 24 deletions(-) (limited to 'drivers/lightnvm') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 968ba7ed4158..1cb4b331c3e8 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -467,7 +467,7 @@ static int nvm_core_init(struct nvm_dev *dev) dev->blks_per_lun * dev->luns_per_chnl * dev->nr_chnls; - dev->total_pages = dev->total_blocks * dev->pgs_per_blk; + dev->total_secs = dev->total_blocks * dev->sec_per_blk; INIT_LIST_HEAD(&dev->online_targets); mutex_init(&dev->mlock); diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 7fb725b16148..d65ec36a2231 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -100,14 +100,13 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private) { struct nvm_dev *dev = private; struct gen_nvm *gn = dev->mp; - sector_t max_pages = dev->total_pages * (dev->sec_size >> 9); u64 elba = slba + nlb; struct gen_lun *lun; struct nvm_block *blk; u64 i; int lun_id; - if (unlikely(elba > dev->total_pages)) { + if (unlikely(elba > dev->total_secs)) { pr_err("gennvm: L2P data from device is out of bounds!\n"); return -EINVAL; } @@ -115,7 +114,7 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private) for (i = 0; i < nlb; i++) { u64 pba = le64_to_cpu(entries[i]); - if (unlikely(pba >= max_pages && pba != U64_MAX)) { + if (unlikely(pba >= dev->total_secs && pba != U64_MAX)) { pr_err("gennvm: L2P data entry is out of bounds!\n"); return -EINVAL; } @@ -197,7 +196,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) } if (dev->ops->get_l2p_tbl) { - ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages, + ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, gennvm_block_map, dev); if (ret) { pr_err("gennvm: could not read L2P table.\n"); diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index e2710da5cd78..c4d0b04ac521 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -552,7 +552,7 @@ static struct rrpc_addr *rrpc_update_map(struct rrpc *rrpc, sector_t laddr, struct rrpc_addr *gp; struct rrpc_rev_addr *rev; - BUG_ON(laddr >= rrpc->nr_pages); + BUG_ON(laddr >= rrpc->nr_sects); gp = &rrpc->trans_map[laddr]; spin_lock(&rrpc->rev_lock); @@ -721,7 +721,7 @@ static int rrpc_read_ppalist_rq(struct rrpc *rrpc, struct bio *bio, for (i = 0; i < npages; i++) { /* We assume that mapping occurs at 4KB granularity */ - BUG_ON(!(laddr + i >= 0 && laddr + i < rrpc->nr_pages)); + BUG_ON(!(laddr + i >= 0 && laddr + i < rrpc->nr_sects)); gp = &rrpc->trans_map[laddr + i]; if (gp->rblk) { @@ -752,7 +752,7 @@ static int rrpc_read_rq(struct rrpc *rrpc, struct bio *bio, struct nvm_rq *rqd, if (!is_gc && rrpc_lock_rq(rrpc, bio, rqd)) return NVM_IO_REQUEUE; - BUG_ON(!(laddr >= 0 && laddr < rrpc->nr_pages)); + BUG_ON(!(laddr >= 0 && laddr < rrpc->nr_sects)); gp = &rrpc->trans_map[laddr]; if (gp->rblk) { @@ -1002,11 +1002,10 @@ static int rrpc_l2p_update(u64 slba, u32 nlb, __le64 *entries, void *private) struct nvm_dev *dev = rrpc->dev; struct rrpc_addr *addr = rrpc->trans_map + slba; struct rrpc_rev_addr *raddr = rrpc->rev_trans_map; - sector_t max_pages = dev->total_pages * (dev->sec_size >> 9); u64 elba = slba + nlb; u64 i; - if (unlikely(elba > dev->total_pages)) { + if (unlikely(elba > dev->total_secs)) { pr_err("nvm: L2P data from device is out of bounds!\n"); return -EINVAL; } @@ -1016,7 +1015,7 @@ static int rrpc_l2p_update(u64 slba, u32 nlb, __le64 *entries, void *private) /* LNVM treats address-spaces as silos, LBA and PBA are * equally large and zero-indexed. */ - if (unlikely(pba >= max_pages && pba != U64_MAX)) { + if (unlikely(pba >= dev->total_secs && pba != U64_MAX)) { pr_err("nvm: L2P data entry is out of bounds!\n"); return -EINVAL; } @@ -1041,16 +1040,16 @@ static int rrpc_map_init(struct rrpc *rrpc) sector_t i; int ret; - rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_pages); + rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects); if (!rrpc->trans_map) return -ENOMEM; rrpc->rev_trans_map = vmalloc(sizeof(struct rrpc_rev_addr) - * rrpc->nr_pages); + * rrpc->nr_sects); if (!rrpc->rev_trans_map) return -ENOMEM; - for (i = 0; i < rrpc->nr_pages; i++) { + 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]; @@ -1062,8 +1061,8 @@ 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_pages, - rrpc_l2p_update, rrpc); + ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, rrpc_l2p_update, + rrpc); if (ret) { pr_err("nvm: rrpc: could not read L2P table.\n"); return -EINVAL; @@ -1163,7 +1162,7 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end) spin_lock_init(&rlun->lock); rrpc->total_blocks += dev->blks_per_lun; - rrpc->nr_pages += dev->sec_per_lun; + rrpc->nr_sects += dev->sec_per_lun; rlun->blocks = vzalloc(sizeof(struct rrpc_block) * rrpc->dev->blks_per_lun); @@ -1216,9 +1215,9 @@ static sector_t rrpc_capacity(void *private) /* cur, gc, and two emergency blocks for each lun */ reserved = rrpc->nr_luns * dev->max_pages_per_blk * 4; - provisioned = rrpc->nr_pages - reserved; + provisioned = rrpc->nr_sects - reserved; - if (reserved > rrpc->nr_pages) { + if (reserved > rrpc->nr_sects) { pr_err("rrpc: not enough space available to expose storage.\n"); return 0; } @@ -1381,7 +1380,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk, blk_queue_max_hw_sectors(tqueue, queue_max_hw_sectors(bqueue)); pr_info("nvm: rrpc initialized with %u luns and %llu pages.\n", - rrpc->nr_luns, (unsigned long long)rrpc->nr_pages); + rrpc->nr_luns, (unsigned long long)rrpc->nr_sects); mod_timer(&rrpc->gc_timer, jiffies + msecs_to_jiffies(10)); diff --git a/drivers/lightnvm/rrpc.h b/drivers/lightnvm/rrpc.h index ef13ac7700c8..dfca5c4d26bb 100644 --- a/drivers/lightnvm/rrpc.h +++ b/drivers/lightnvm/rrpc.h @@ -104,7 +104,7 @@ struct rrpc { struct rrpc_lun *luns; /* calculated values */ - unsigned long long nr_pages; + unsigned long long nr_sects; unsigned long total_blocks; /* Write strategy variables. Move these into each for structure for each @@ -205,7 +205,7 @@ static inline int rrpc_lock_laddr(struct rrpc *rrpc, sector_t laddr, unsigned pages, struct rrpc_inflight_rq *r) { - BUG_ON((laddr + pages) > rrpc->nr_pages); + BUG_ON((laddr + pages) > rrpc->nr_sects); return __rrpc_lock_laddr(rrpc, laddr, pages, r); } @@ -242,7 +242,7 @@ static inline void rrpc_unlock_rq(struct rrpc *rrpc, struct nvm_rq *rqd) struct rrpc_inflight_rq *r = rrpc_get_inflight_rq(rqd); uint8_t pages = rqd->nr_pages; - BUG_ON((r->l_start + pages) > rrpc->nr_pages); + BUG_ON((r->l_start + pages) > rrpc->nr_sects); rrpc_unlock_laddr(rrpc, r); } diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 7fa1838f7356..8f8a74328f20 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -337,8 +337,8 @@ struct nvm_dev { int lps_per_blk; int *lptbl; - unsigned long total_pages; unsigned long total_blocks; + unsigned long total_secs; int nr_luns; unsigned max_pages_per_blk; -- cgit v1.2.3-59-g8ed1b From ed2a92a6b4b8453a0c3a20da641ec79e4b3d7ca4 Mon Sep 17 00:00:00 2001 From: Matias Bjørling Date: Sat, 20 Feb 2016 08:52:42 +0100 Subject: lightnvm: remove struct nvm_dev->total_blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct nvm_dev->total_blocks was only used for calculating total sectors. Remove and instead calculate total sectors from the number of luns and its sectors. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/lightnvm') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 1cb4b331c3e8..773a55da0e20 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -463,11 +463,7 @@ static int nvm_core_init(struct nvm_dev *dev) dev->sec_per_lun = dev->sec_per_blk * dev->blks_per_lun; dev->nr_luns = dev->luns_per_chnl * dev->nr_chnls; - dev->total_blocks = dev->nr_planes * - dev->blks_per_lun * - dev->luns_per_chnl * - dev->nr_chnls; - dev->total_secs = dev->total_blocks * dev->sec_per_blk; + dev->total_secs = dev->nr_luns * dev->sec_per_lun; INIT_LIST_HEAD(&dev->online_targets); mutex_init(&dev->mlock); -- cgit v1.2.3-59-g8ed1b From afb18e0ed862fae05aa41be278c1ddb87473c7b1 Mon Sep 17 00:00:00 2001 From: Javier González Date: Thu, 3 Mar 2016 14:47:53 -0700 Subject: lightnvm: generalize rrpc ppa calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rrpc, some calculations assume a certain configuration (e.g., 1 LUN, 1 sector per page). The reason behind this was that LightNVM used a simple configuration with QEMU to test core features in the beginning. This patch relaxes these assumptions and generalizes calculation, allowing multiple luns to be used. Signed-off-by: Javier González Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/rrpc.c | 48 +++++++++++++++++++++++++++++++----------------- drivers/lightnvm/rrpc.h | 9 +++++++++ 2 files changed, 40 insertions(+), 17 deletions(-) (limited to 'drivers/lightnvm') diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index c4d0b04ac521..f015fdc9c281 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -38,7 +38,7 @@ static void rrpc_page_invalidate(struct rrpc *rrpc, struct rrpc_addr *a) spin_lock(&rblk->lock); - div_u64_rem(a->addr, rrpc->dev->pgs_per_blk, &pg_offset); + div_u64_rem(a->addr, rrpc->dev->sec_per_blk, &pg_offset); WARN_ON(test_and_set_bit(pg_offset, rblk->invalid_pages)); rblk->nr_invalid_pages++; @@ -113,14 +113,24 @@ static void rrpc_discard(struct rrpc *rrpc, struct bio *bio) static int block_is_full(struct rrpc *rrpc, struct rrpc_block *rblk) { - return (rblk->next_page == rrpc->dev->pgs_per_blk); + 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) { struct nvm_block *blk = rblk->parent; - return blk->id * rrpc->dev->pgs_per_blk; + return blk->id * rrpc->dev->sec_per_blk; } static struct ppa_addr linear_to_generic_addr(struct nvm_dev *dev, @@ -136,7 +146,7 @@ static struct ppa_addr linear_to_generic_addr(struct nvm_dev *dev, l.g.sec = secs; sector_div(ppa, dev->sec_per_pg); - div_u64_rem(ppa, dev->sec_per_blk, &pgs); + div_u64_rem(ppa, dev->pgs_per_blk, &pgs); l.g.pg = pgs; sector_div(ppa, dev->pgs_per_blk); @@ -191,12 +201,12 @@ static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun, return NULL; } - rblk = &rlun->blocks[blk->id]; + rblk = rrpc_get_rblk(rlun, blk->id); list_add_tail(&rblk->list, &rlun->open_list); spin_unlock(&lun->lock); blk->priv = rblk; - bitmap_zero(rblk->invalid_pages, rrpc->dev->pgs_per_blk); + bitmap_zero(rblk->invalid_pages, rrpc->dev->sec_per_blk); rblk->next_page = 0; rblk->nr_invalid_pages = 0; atomic_set(&rblk->data_cmnt_size, 0); @@ -286,11 +296,11 @@ static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk) struct bio *bio; struct page *page; int slot; - int nr_pgs_per_blk = rrpc->dev->pgs_per_blk; + int nr_sec_per_blk = rrpc->dev->sec_per_blk; u64 phys_addr; DECLARE_COMPLETION_ONSTACK(wait); - if (bitmap_full(rblk->invalid_pages, nr_pgs_per_blk)) + if (bitmap_full(rblk->invalid_pages, nr_sec_per_blk)) return 0; bio = bio_alloc(GFP_NOIO, 1); @@ -304,10 +314,10 @@ static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk) return -ENOMEM; while ((slot = find_first_zero_bit(rblk->invalid_pages, - nr_pgs_per_blk)) < nr_pgs_per_blk) { + nr_sec_per_blk)) < nr_sec_per_blk) { /* Lock laddr */ - phys_addr = (rblk->parent->id * nr_pgs_per_blk) + slot; + phys_addr = rblk->parent->id * nr_sec_per_blk + slot; try: spin_lock(&rrpc->rev_lock); @@ -379,7 +389,7 @@ finished: mempool_free(page, rrpc->page_pool); bio_put(bio); - if (!bitmap_full(rblk->invalid_pages, nr_pgs_per_blk)) { + if (!bitmap_full(rblk->invalid_pages, nr_sec_per_blk)) { pr_err("nvm: failed to garbage collect block\n"); return -EIO; } @@ -675,7 +685,7 @@ static void rrpc_end_io_write(struct rrpc *rrpc, struct rrpc_rq *rrqd, lun = rblk->parent->lun; cmnt_size = atomic_inc_return(&rblk->data_cmnt_size); - if (unlikely(cmnt_size == rrpc->dev->pgs_per_blk)) + if (unlikely(cmnt_size == rrpc->dev->sec_per_blk)) rrpc_run_gc(rrpc, rblk); } } @@ -1012,6 +1022,7 @@ static int rrpc_l2p_update(u64 slba, u32 nlb, __le64 *entries, void *private) for (i = 0; i < nlb; i++) { u64 pba = le64_to_cpu(entries[i]); + unsigned int mod; /* LNVM treats address-spaces as silos, LBA and PBA are * equally large and zero-indexed. */ @@ -1027,8 +1038,10 @@ static int rrpc_l2p_update(u64 slba, u32 nlb, __le64 *entries, void *private) if (!pba) continue; + div_u64_rem(pba, rrpc->nr_sects, &mod); + addr[i].addr = pba; - raddr[pba].addr = slba + i; + raddr[mod].addr = slba + i; } return 0; @@ -1135,7 +1148,7 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end) struct rrpc_lun *rlun; int i, j; - if (dev->pgs_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) { + if (dev->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) { pr_err("rrpc: number of pages per block too high."); return -EINVAL; } @@ -1236,10 +1249,11 @@ static void rrpc_block_map_update(struct rrpc *rrpc, struct rrpc_block *rblk) struct nvm_dev *dev = rrpc->dev; int offset; struct rrpc_addr *laddr; - u64 paddr, pladdr; + u64 bpaddr, paddr, pladdr; - for (offset = 0; offset < dev->pgs_per_blk; offset++) { - paddr = block_to_addr(rrpc, rblk) + offset; + bpaddr = block_to_rel_addr(rrpc, rblk); + for (offset = 0; offset < dev->sec_per_blk; offset++) { + paddr = bpaddr + offset; pladdr = rrpc->rev_trans_map[paddr].addr; if (pladdr == ADDR_EMPTY) diff --git a/drivers/lightnvm/rrpc.h b/drivers/lightnvm/rrpc.h index dfca5c4d26bb..0577c4dae05f 100644 --- a/drivers/lightnvm/rrpc.h +++ b/drivers/lightnvm/rrpc.h @@ -156,6 +156,15 @@ struct rrpc_rev_addr { u64 addr; }; +static inline struct rrpc_block *rrpc_get_rblk(struct rrpc_lun *rlun, + int blk_id) +{ + struct rrpc *rrpc = rlun->rrpc; + int lun_blk = blk_id % rrpc->dev->blks_per_lun; + + return &rlun->blocks[lun_blk]; +} + static inline sector_t rrpc_get_laddr(struct bio *bio) { return bio->bi_iter.bi_sector / NR_PHY_IN_LOG; -- cgit v1.2.3-59-g8ed1b