Re: [PATCH 2/3] lightnvm: add a bitmap of luns
From: Wenwei Tao
Date: Fri Feb 05 2016 - 07:24:20 EST
Forgot to do that.
Thanks for fixing my mistake.
2016-02-05 19:59 GMT+08:00 Matias BjÃrling <mb@xxxxxxxxxxx>:
> On 02/04/2016 12:34 PM, Wenwei Tao wrote:
>> Add a bitmap of luns to indicate the status
>> of luns: inuse/available. When create targets
>> do the necessary check to avoid allocating luns
>> that are already allocated.
>>
>> Signed-off-by: Wenwei Tao <ww.tao0320@xxxxxxxxx>
>> ---
>> drivers/lightnvm/core.c | 5 ++++
>> drivers/lightnvm/gennvm.c | 18 +++++++++++++++
>> drivers/lightnvm/rrpc.c | 59 +++++++++++++++++++++++++++++++++++------------
>> include/linux/lightnvm.h | 5 ++++
>> 4 files changed, 72 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
>> index 93c035b..11b8e2d 100644
>> --- a/drivers/lightnvm/core.c
>> +++ b/drivers/lightnvm/core.c
>> @@ -464,6 +464,10 @@ static int nvm_core_init(struct nvm_dev *dev)
>> dev->nr_luns = dev->luns_per_chnl * dev->nr_chnls;
>>
>> dev->total_secs = dev->nr_luns * dev->sec_per_lun;
>> + dev->lun_map = kcalloc(BITS_TO_LONGS(dev->nr_luns),
>> + sizeof(unsigned long), GFP_KERNEL);
>> + if (!dev->lun_map)
>> + return -ENOMEM;
>> INIT_LIST_HEAD(&dev->online_targets);
>> mutex_init(&dev->mlock);
>> spin_lock_init(&dev->lock);
>> @@ -606,6 +610,7 @@ void nvm_unregister(char *disk_name)
>> up_write(&nvm_lock);
>>
>> nvm_exit(dev);
>> + kfree(dev->lun_map);
>> kfree(dev);
>> }
>> EXPORT_SYMBOL(nvm_unregister);
>> diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
>> index fba3fbd..adc10c2 100644
>> --- a/drivers/lightnvm/gennvm.c
>> +++ b/drivers/lightnvm/gennvm.c
>> @@ -190,6 +190,9 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
>> lun_id = div_u64(pba, dev->sec_per_lun);
>> lun = &gn->luns[lun_id];
>>
>> + if (!test_bit(lun_id, dev->lun_map))
>> + __set_bit(lun_id, dev->lun_map);
>> +
>> /* Calculate block offset into lun */
>> pba = pba - (dev->sec_per_lun * lun_id);
>> blk = &lun->vlun.blocks[div_u64(pba, dev->sec_per_blk)];
>> @@ -480,10 +483,23 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
>> return nvm_erase_ppa(dev, &addr, 1);
>> }
>>
>> +static int gennvm_reserve_lun(struct nvm_dev *dev, int lunid)
>> +{
>> + return test_and_set_bit(lunid, dev->lun_map);
>> +}
>> +
>> +static void gennvm_release_lun(struct nvm_dev *dev, int lunid)
>> +{
>> + WARN_ON(!test_and_clear_bit(lunid, dev->lun_map));
>> +}
>> +
>> static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
>> {
>> struct gen_nvm *gn = dev->mp;
>>
>> + if (unlikely(lunid >= dev->nr_luns))
>> + return NULL;
>> +
>> return &gn->luns[lunid].vlun;
>> }
>>
>> @@ -525,6 +541,8 @@ static struct nvmm_type gennvm = {
>> .erase_blk = gennvm_erase_blk,
>>
>> .get_lun = gennvm_get_lun,
>> + .reserve_lun = gennvm_reserve_lun,
>> + .release_lun = gennvm_release_lun,
>> .lun_info_print = gennvm_lun_info_print,
>>
>> .get_area = gennvm_get_area,
>> diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
>> index 6ce5f73..2bd5789 100644
>> --- a/drivers/lightnvm/rrpc.c
>> +++ b/drivers/lightnvm/rrpc.c
>> @@ -1128,6 +1128,22 @@ static void rrpc_core_free(struct rrpc *rrpc)
>>
>> static void rrpc_luns_free(struct rrpc *rrpc)
>> {
>> + struct nvm_dev *dev = rrpc->dev;
>> + struct nvm_lun *lun;
>> + struct rrpc_lun *rlun;
>> + int i;
>> +
>> + if (!rrpc->luns)
>> + return;
>> +
>> + for (i = 0; i < rrpc->nr_luns; i++) {
>> + rlun = &rrpc->luns[i];
>> + lun = rlun->parent;
>> + if (!lun)
>> + break;
>> + dev->mt->release_lun(dev, lun->id);
>> + vfree(rlun->blocks);
>> + }
>> kfree(rrpc->luns);
>> }
>>
>> @@ -1135,7 +1151,7 @@ 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;
>> + int i, j, ret = -EINVAL;
>>
>> if (dev->pgs_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
>> pr_err("rrpc: number of pages per block too high.");
>> @@ -1151,25 +1167,26 @@ 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++) {
>> - struct nvm_lun *lun = dev->mt->get_lun(dev, lun_begin + i);
>> + int lunid = lun_begin + i;
>> + struct nvm_lun *lun;
>>
>> - rlun = &rrpc->luns[i];
>> - rlun->rrpc = rrpc;
>> - rlun->parent = lun;
>> - 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);
>> + if (dev->mt->reserve_lun(dev, lunid)) {
>> + pr_err("rrpc: lun %u is already allocated\n", lunid);
>> + goto err;
>> + }
>>
>> - rrpc->total_blocks += dev->blks_per_lun;
>> - rrpc->nr_sects += dev->sec_per_lun;
>> + lun = dev->mt->get_lun(dev, lunid);
>> + if (!lun)
>> + goto err;
>>
>> + rlun = &rrpc->luns[i];
>> + rlun->parent = lun;
>> rlun->blocks = vzalloc(sizeof(struct rrpc_block) *
>> rrpc->dev->blks_per_lun);
>> - if (!rlun->blocks)
>> + if (!rlun->blocks) {
>> + ret = -ENOMEM;
>> goto err;
>> + }
>>
>> for (j = 0; j < rrpc->dev->blks_per_lun; j++) {
>> struct rrpc_block *rblk = &rlun->blocks[j];
>> @@ -1180,11 +1197,23 @@ static int rrpc_luns_init(struct rrpc *rrpc, int lun_begin, int lun_end)
>> 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;
>> +
>> }
>>
>> return 0;
>> err:
>> - return -ENOMEM;
>> + return ret;
>> }
>>
>> /* returns 0 on success and stores the beginning address in *begin */
>> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
>> index ce58ad5..2a17dc1 100644
>> --- a/include/linux/lightnvm.h
>> +++ b/include/linux/lightnvm.h
>> @@ -342,6 +342,7 @@ struct nvm_dev {
>> int nr_luns;
>> unsigned max_pages_per_blk;
>>
>> + unsigned long *lun_map;
>> void *ppalist_pool;
>>
>> struct nvm_id identity;
>> @@ -462,6 +463,8 @@ typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
>> typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
>> unsigned long);
>> 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_lun_info_print_fn)(struct nvm_dev *);
>>
>> typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
>> @@ -488,6 +491,8 @@ struct nvmm_type {
>>
>> /* Configuration management */
>> nvmm_get_lun_fn *get_lun;
>> + nvmm_reserve_lun *reserve_lun;
>> + nvmm_release_lun *release_lun;
>>
>> /* Statistics */
>> nvmm_lun_info_print_fn *lun_info_print;
>>
> Thanks, applied for 4.6. I added an extra kfree(dev->lun_map) at the end
> of nvm_core_init to make sure that we freed the lun_map if other
> allocations fails in initialization.