]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/lightnvm/pblk-map.c
lightnvm: pblk: use right metadata buffer for recovery
[karo-tx-linux.git] / drivers / lightnvm / pblk-map.c
index 17c16955284da854fddcaf238eb00d4c3c567d02..fddb924f6dde744b3b2836fbda645951e179666c 100644 (file)
@@ -25,9 +25,9 @@ static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry,
                               unsigned int valid_secs)
 {
        struct pblk_line *line = pblk_line_get_data(pblk);
-       struct line_emeta *emeta = line->emeta;
+       struct pblk_emeta *emeta = line->emeta;
        struct pblk_w_ctx *w_ctx;
-       __le64 *lba_list = pblk_line_emeta_to_lbas(emeta);
+       __le64 *lba_list = emeta_to_lbas(pblk, emeta->buf);
        u64 paddr;
        int nr_secs = pblk->min_write_pgs;
        int i;
@@ -51,18 +51,20 @@ static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry,
                        w_ctx->ppa = ppa_list[i];
                        meta_list[i].lba = cpu_to_le64(w_ctx->lba);
                        lba_list[paddr] = cpu_to_le64(w_ctx->lba);
-                       le64_add_cpu(&line->emeta->nr_valid_lbas, 1);
+                       line->nr_valid_lbas++;
                } else {
-                       meta_list[i].lba = cpu_to_le64(ADDR_EMPTY);
-                       lba_list[paddr] = cpu_to_le64(ADDR_EMPTY);
-                       pblk_map_pad_invalidate(pblk, line, paddr);
+                       __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
+
+                       lba_list[paddr] = meta_list[i].lba = addr_empty;
+                       __pblk_map_invalidate(pblk, line, paddr);
                }
        }
 
        if (pblk_line_is_full(line)) {
-               line = pblk_line_replace_data(pblk);
-               if (!line)
-                       return;
+               struct pblk_line *prev_line = line;
+
+               pblk_line_replace_data(pblk);
+               pblk_line_close_meta(pblk, prev_line);
        }
 
        pblk_down_rq(pblk, ppa_list, nr_secs, lun_bitmap);
@@ -91,8 +93,9 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
 {
        struct nvm_tgt_dev *dev = pblk->dev;
        struct nvm_geo *geo = &dev->geo;
-       struct pblk_line *e_line = pblk_line_get_data_next(pblk);
+       struct pblk_line_meta *lm = &pblk->lm;
        struct pblk_sec_meta *meta_list = rqd->meta_list;
+       struct pblk_line *e_line, *d_line;
        unsigned int map_secs;
        int min = pblk->min_write_pgs;
        int i, erase_lun;
@@ -102,35 +105,63 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
                pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i],
                                        lun_bitmap, &meta_list[i], map_secs);
 
-               erase_lun = rqd->ppa_list[i].g.lun * geo->nr_chnls +
-                                                       rqd->ppa_list[i].g.ch;
+               erase_lun = pblk_ppa_to_pos(geo, rqd->ppa_list[i]);
 
-               if (!test_bit(erase_lun, e_line->erase_bitmap)) {
-                       if (down_trylock(&pblk->erase_sem))
-                               continue;
+               /* line can change after page map. We might also be writing the
+                * last line.
+                */
+               e_line = pblk_line_get_erase(pblk);
+               if (!e_line)
+                       return pblk_map_rq(pblk, rqd, sentry, lun_bitmap,
+                                                       valid_secs, i + min);
 
+               spin_lock(&e_line->lock);
+               if (!test_bit(erase_lun, e_line->erase_bitmap)) {
                        set_bit(erase_lun, e_line->erase_bitmap);
                        atomic_dec(&e_line->left_eblks);
+
                        *erase_ppa = rqd->ppa_list[i];
                        erase_ppa->g.blk = e_line->id;
 
+                       spin_unlock(&e_line->lock);
+
                        /* Avoid evaluating e_line->left_eblks */
                        return pblk_map_rq(pblk, rqd, sentry, lun_bitmap,
                                                        valid_secs, i + min);
                }
+               spin_unlock(&e_line->lock);
        }
 
-       /* Erase blocks that are bad in this line but might not be in next */
-       if (unlikely(ppa_empty(*erase_ppa))) {
-               struct pblk_line_meta *lm = &pblk->lm;
+       d_line = pblk_line_get_data(pblk);
+
+       /* line can change after page map. We might also be writing the
+        * last line.
+        */
+       e_line = pblk_line_get_erase(pblk);
+       if (!e_line)
+               return;
 
-               i = find_first_zero_bit(e_line->erase_bitmap, lm->blk_per_line);
-               if (i == lm->blk_per_line)
+       /* Erase blocks that are bad in this line but might not be in next */
+       if (unlikely(ppa_empty(*erase_ppa)) &&
+                       bitmap_weight(d_line->blk_bitmap, lm->blk_per_line)) {
+               int bit = -1;
+
+retry:
+               bit = find_next_bit(d_line->blk_bitmap,
+                                               lm->blk_per_line, bit + 1);
+               if (bit >= lm->blk_per_line)
                        return;
 
-               set_bit(i, e_line->erase_bitmap);
+               spin_lock(&e_line->lock);
+               if (test_bit(bit, e_line->erase_bitmap)) {
+                       spin_unlock(&e_line->lock);
+                       goto retry;
+               }
+               spin_unlock(&e_line->lock);
+
+               set_bit(bit, e_line->erase_bitmap);
                atomic_dec(&e_line->left_eblks);
-               *erase_ppa = pblk->luns[i].bppa; /* set ch and lun */
+               *erase_ppa = pblk->luns[bit].bppa; /* set ch and lun */
                erase_ppa->g.blk = e_line->id;
        }
 }