]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/lightnvm/rrpc.c
lightnvm: do not free unused metadata on rrpc
[mirror_ubuntu-artful-kernel.git] / drivers / lightnvm / rrpc.c
index 82343783aa47239b427fee1bbc7e066e5160b630..ffcfee6684ba21bb51940661a5f972b42492f19a 100644 (file)
@@ -711,8 +711,6 @@ static void rrpc_end_io(struct nvm_rq *rqd)
 
        if (npages > 1)
                nvm_dev_dma_free(rrpc->dev, rqd->ppa_list, rqd->dma_ppa_list);
-       if (rqd->metadata)
-               nvm_dev_dma_free(rrpc->dev, rqd->metadata, rqd->dma_metadata);
 
        mempool_free(rqd, rrpc->rq_pool);
 }
@@ -965,25 +963,11 @@ static void rrpc_requeue(struct work_struct *work)
 
 static void rrpc_gc_free(struct rrpc *rrpc)
 {
-       struct rrpc_lun *rlun;
-       int i;
-
        if (rrpc->krqd_wq)
                destroy_workqueue(rrpc->krqd_wq);
 
        if (rrpc->kgc_wq)
                destroy_workqueue(rrpc->kgc_wq);
-
-       if (!rrpc->luns)
-               return;
-
-       for (i = 0; i < rrpc->nr_luns; i++) {
-               rlun = &rrpc->luns[i];
-
-               if (!rlun->blocks)
-                       break;
-               vfree(rlun->blocks);
-       }
 }
 
 static int rrpc_gc_init(struct rrpc *rrpc)
@@ -1076,8 +1060,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_secs, rrpc_l2p_update,
-                                                                       rrpc);
+       ret = dev->ops->get_l2p_tbl(dev, rrpc->soffset, rrpc->nr_sects,
+                                       rrpc_l2p_update, rrpc);
        if (ret) {
                pr_err("nvm: rrpc: could not read L2P table.\n");
                return -EINVAL;
@@ -1086,7 +1070,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
@@ -1141,6 +1124,23 @@ 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);
 }
 
@@ -1148,7 +1148,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->sec_per_blk > MAX_INVALID_PAGES_STORAGE * BITS_PER_LONG) {
                pr_err("rrpc: number of pages per block too high.");
@@ -1164,25 +1164,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);
-
-               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);
+               int lunid = lun_begin + i;
+               struct nvm_lun *lun;
 
-               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];
@@ -1193,11 +1194,45 @@ 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);
        }
 
        return 0;
 err:
-       return -ENOMEM;
+       return ret;
+}
+
+/* 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;
+       int ret;
+
+       size >>= 9;
+
+       ret = mt->get_area(dev, begin, size);
+       if (!ret)
+               *begin >>= (ilog2(dev->sec_size) - 9);
+
+       return ret;
+}
+
+static void rrpc_area_free(struct rrpc *rrpc)
+{
+       struct nvm_dev *dev = rrpc->dev;
+       struct nvmm_type *mt = dev->mt;
+       sector_t begin = rrpc->soffset << (ilog2(dev->sec_size) - 9);
+
+       mt->put_area(dev, begin);
 }
 
 static void rrpc_free(struct rrpc *rrpc)
@@ -1206,6 +1241,7 @@ static void rrpc_free(struct rrpc *rrpc)
        rrpc_map_free(rrpc);
        rrpc_core_free(rrpc);
        rrpc_luns_free(rrpc);
+       rrpc_area_free(rrpc);
 
        kfree(rrpc);
 }
@@ -1327,6 +1363,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)) {
@@ -1348,10 +1385,19 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
        INIT_WORK(&rrpc->ws_requeue, rrpc_requeue);
 
        rrpc->nr_luns = lun_end - lun_begin + 1;
+       rrpc->total_blocks = (unsigned long)dev->blks_per_lun * rrpc->nr_luns;
+       rrpc->nr_sects = (unsigned long long)dev->sec_per_lun * rrpc->nr_luns;
 
        /* 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");
@@ -1421,12 +1467,12 @@ static struct nvm_tgt_type tt_rrpc = {
 
 static int __init rrpc_module_init(void)
 {
-       return nvm_register_target(&tt_rrpc);
+       return nvm_register_tgt_type(&tt_rrpc);
 }
 
 static void rrpc_module_exit(void)
 {
-       nvm_unregister_target(&tt_rrpc);
+       nvm_unregister_tgt_type(&tt_rrpc);
 }
 
 module_init(rrpc_module_init);