[2/3] lightnvm: add a bitmap of luns
diff mbox

Message ID 1454585687-4720-2-git-send-email-ww.tao0320@gmail.com
State New
Headers show

Commit Message

Wenwei Tao Feb. 4, 2016, 11:34 a.m. UTC
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@gmail.com>
---
 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(-)

Comments

Matias Bjørling Feb. 5, 2016, 11:59 a.m. UTC | #1
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@gmail.com>
> ---
>  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.
--
To unsubscribe from this list: send the line "unsubscribe linux-block" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Wenwei Tao Feb. 5, 2016, 12:23 p.m. UTC | #2
Forgot to do that.
Thanks for fixing my mistake.

2016-02-05 19:59 GMT+08:00 Matias Bjørling <mb@lightnvm.io>:
> 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@gmail.com>
>> ---
>>  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.
--
To unsubscribe from this list: send the line "unsubscribe linux-block" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Matias Bjørling Feb. 5, 2016, 12:24 p.m. UTC | #3
On 02/05/2016 01:23 PM, Wenwei Tao wrote:
> Forgot to do that.
> Thanks for fixing my mistake.

No worries, you fixed a couple that I introduced ;)
--
To unsubscribe from this list: send the line "unsubscribe linux-block" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

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;