Commit e411b331 authored by Javier González's avatar Javier González Committed by Jens Axboe

lightnvm: pblk: refactor bad block identification

In preparation for the OCSSD 2.0 spec. bad block identification,
refactor the current code to generalize bad block get/set functions and
structures.
Signed-off-by: default avatarJavier González <javier@cnexlabs.com>
Signed-off-by: default avatarMatias Bjørling <mb@lightnvm.io>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 3c05ef11
...@@ -1025,7 +1025,6 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line, ...@@ -1025,7 +1025,6 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
struct nvm_geo *geo = &dev->geo; struct nvm_geo *geo = &dev->geo;
struct pblk_line_meta *lm = &pblk->lm; struct pblk_line_meta *lm = &pblk->lm;
struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_mgmt *l_mg = &pblk->l_mg;
int nr_bb = 0;
u64 off; u64 off;
int bit = -1; int bit = -1;
int emeta_secs; int emeta_secs;
...@@ -1041,8 +1040,6 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line, ...@@ -1041,8 +1040,6 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
bitmap_or(line->map_bitmap, line->map_bitmap, l_mg->bb_aux, bitmap_or(line->map_bitmap, line->map_bitmap, l_mg->bb_aux,
lm->sec_per_line); lm->sec_per_line);
line->sec_in_line -= geo->sec_per_chk; line->sec_in_line -= geo->sec_per_chk;
if (bit >= lm->emeta_bb)
nr_bb++;
} }
/* Mark smeta metadata sectors as bad sectors */ /* Mark smeta metadata sectors as bad sectors */
......
...@@ -365,7 +365,25 @@ static void pblk_luns_free(struct pblk *pblk) ...@@ -365,7 +365,25 @@ static void pblk_luns_free(struct pblk *pblk)
kfree(pblk->luns); kfree(pblk->luns);
} }
static void pblk_free_line_bitmaps(struct pblk_line *line) static void pblk_line_mg_free(struct pblk *pblk)
{
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
int i;
kfree(l_mg->bb_template);
kfree(l_mg->bb_aux);
kfree(l_mg->vsc_list);
for (i = 0; i < PBLK_DATA_LINES; i++) {
kfree(l_mg->sline_meta[i]);
pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type);
kfree(l_mg->eline_meta[i]);
}
kfree(pblk->lines);
}
static void pblk_line_meta_free(struct pblk_line *line)
{ {
kfree(line->blk_bitmap); kfree(line->blk_bitmap);
kfree(line->erase_bitmap); kfree(line->erase_bitmap);
...@@ -382,40 +400,16 @@ static void pblk_lines_free(struct pblk *pblk) ...@@ -382,40 +400,16 @@ static void pblk_lines_free(struct pblk *pblk)
line = &pblk->lines[i]; line = &pblk->lines[i];
pblk_line_free(pblk, line); pblk_line_free(pblk, line);
pblk_free_line_bitmaps(line); pblk_line_meta_free(line);
} }
spin_unlock(&l_mg->free_lock); spin_unlock(&l_mg->free_lock);
} }
static void pblk_line_meta_free(struct pblk *pblk) static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
{ u8 *blks, int nr_blks)
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
int i;
kfree(l_mg->bb_template);
kfree(l_mg->bb_aux);
kfree(l_mg->vsc_list);
for (i = 0; i < PBLK_DATA_LINES; i++) {
kfree(l_mg->sline_meta[i]);
pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type);
kfree(l_mg->eline_meta[i]);
}
kfree(pblk->lines);
}
static int pblk_bb_discovery(struct nvm_tgt_dev *dev, struct pblk_lun *rlun)
{ {
struct nvm_geo *geo = &dev->geo;
struct ppa_addr ppa; struct ppa_addr ppa;
u8 *blks; int ret;
int nr_blks, ret;
nr_blks = geo->nr_chks * geo->plane_mode;
blks = kmalloc(nr_blks, GFP_KERNEL);
if (!blks)
return -ENOMEM;
ppa.ppa = 0; ppa.ppa = 0;
ppa.g.ch = rlun->bppa.g.ch; ppa.g.ch = rlun->bppa.g.ch;
...@@ -423,58 +417,63 @@ static int pblk_bb_discovery(struct nvm_tgt_dev *dev, struct pblk_lun *rlun) ...@@ -423,58 +417,63 @@ static int pblk_bb_discovery(struct nvm_tgt_dev *dev, struct pblk_lun *rlun)
ret = nvm_get_tgt_bb_tbl(dev, ppa, blks); ret = nvm_get_tgt_bb_tbl(dev, ppa, blks);
if (ret) if (ret)
goto out; return ret;
nr_blks = nvm_bb_tbl_fold(dev->parent, blks, nr_blks); nr_blks = nvm_bb_tbl_fold(dev->parent, blks, nr_blks);
if (nr_blks < 0) { if (nr_blks < 0)
ret = nr_blks; return -EIO;
goto out;
}
rlun->bb_list = blks;
return 0; return 0;
out:
kfree(blks);
return ret;
} }
static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line, static void *pblk_bb_get_log(struct pblk *pblk)
int blk_per_line)
{ {
struct nvm_tgt_dev *dev = pblk->dev; struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo; struct nvm_geo *geo = &dev->geo;
struct pblk_lun *rlun; u8 *log;
int bb_cnt = 0; int i, nr_blks, blk_per_lun;
int i; int ret;
for (i = 0; i < blk_per_line; i++) { blk_per_lun = geo->nr_chks * geo->plane_mode;
rlun = &pblk->luns[i]; nr_blks = blk_per_lun * geo->all_luns;
if (rlun->bb_list[line->id] == NVM_BLK_T_FREE)
continue;
set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap); log = kmalloc(nr_blks, GFP_KERNEL);
bb_cnt++; if (!log)
return ERR_PTR(-ENOMEM);
for (i = 0; i < geo->all_luns; i++) {
struct pblk_lun *rlun = &pblk->luns[i];
u8 *log_pos = log + i * blk_per_lun;
ret = pblk_bb_get_tbl(dev, rlun, log_pos, blk_per_lun);
if (ret) {
kfree(log);
return ERR_PTR(-EIO);
}
} }
return bb_cnt; return log;
} }
static int pblk_alloc_line_bitmaps(struct pblk *pblk, struct pblk_line *line) static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line,
u8 *bb_log, int blk_per_line)
{ {
struct pblk_line_meta *lm = &pblk->lm; struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
int i, bb_cnt = 0;
line->blk_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); for (i = 0; i < blk_per_line; i++) {
if (!line->blk_bitmap) struct pblk_lun *rlun = &pblk->luns[i];
return -ENOMEM; u8 *lun_bb_log = bb_log + i * blk_per_line;
line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); if (lun_bb_log[line->id] == NVM_BLK_T_FREE)
if (!line->erase_bitmap) { continue;
kfree(line->blk_bitmap);
return -ENOMEM; set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap);
bb_cnt++;
} }
return 0; return bb_cnt;
} }
static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
...@@ -482,7 +481,7 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) ...@@ -482,7 +481,7 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
struct nvm_tgt_dev *dev = pblk->dev; struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo; struct nvm_geo *geo = &dev->geo;
struct pblk_lun *rlun; struct pblk_lun *rlun;
int i, ret; int i;
/* TODO: Implement unbalanced LUN support */ /* TODO: Implement unbalanced LUN support */
if (geo->nr_luns < 0) { if (geo->nr_luns < 0) {
...@@ -505,13 +504,6 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) ...@@ -505,13 +504,6 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
rlun->bppa = luns[lunid]; rlun->bppa = luns[lunid];
sema_init(&rlun->wr_sem, 1); sema_init(&rlun->wr_sem, 1);
ret = pblk_bb_discovery(dev, rlun);
if (ret) {
while (--i >= 0)
kfree(pblk->luns[i].bb_list);
return ret;
}
} }
return 0; return 0;
...@@ -689,6 +681,26 @@ static int pblk_lines_alloc_metadata(struct pblk *pblk) ...@@ -689,6 +681,26 @@ static int pblk_lines_alloc_metadata(struct pblk *pblk)
return -ENOMEM; return -ENOMEM;
} }
static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
void *chunk_log, long *nr_bad_blks)
{
struct pblk_line_meta *lm = &pblk->lm;
line->blk_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL);
if (!line->blk_bitmap)
return -ENOMEM;
line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL);
if (!line->erase_bitmap) {
kfree(line->blk_bitmap);
return -ENOMEM;
}
*nr_bad_blks = pblk_bb_line(pblk, line, chunk_log, lm->blk_per_line);
return 0;
}
static int pblk_lines_init(struct pblk *pblk) static int pblk_lines_init(struct pblk *pblk)
{ {
struct nvm_tgt_dev *dev = pblk->dev; struct nvm_tgt_dev *dev = pblk->dev;
...@@ -696,8 +708,9 @@ static int pblk_lines_init(struct pblk *pblk) ...@@ -696,8 +708,9 @@ static int pblk_lines_init(struct pblk *pblk)
struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_mgmt *l_mg = &pblk->l_mg;
struct pblk_line_meta *lm = &pblk->lm; struct pblk_line_meta *lm = &pblk->lm;
struct pblk_line *line; struct pblk_line *line;
void *chunk_log;
unsigned int smeta_len, emeta_len; unsigned int smeta_len, emeta_len;
long nr_bad_blks, nr_free_blks; long nr_bad_blks = 0, nr_free_blks = 0;
int bb_distance, max_write_ppas, mod; int bb_distance, max_write_ppas, mod;
int i, ret; int i, ret;
...@@ -771,13 +784,12 @@ static int pblk_lines_init(struct pblk *pblk) ...@@ -771,13 +784,12 @@ static int pblk_lines_init(struct pblk *pblk)
if (lm->min_blk_line > lm->blk_per_line) { if (lm->min_blk_line > lm->blk_per_line) {
pr_err("pblk: config. not supported. Min. LUN in line:%d\n", pr_err("pblk: config. not supported. Min. LUN in line:%d\n",
lm->blk_per_line); lm->blk_per_line);
ret = -EINVAL; return -EINVAL;
goto fail;
} }
ret = pblk_lines_alloc_metadata(pblk); ret = pblk_lines_alloc_metadata(pblk);
if (ret) if (ret)
goto fail; return ret;
l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
if (!l_mg->bb_template) { if (!l_mg->bb_template) {
...@@ -821,9 +833,16 @@ static int pblk_lines_init(struct pblk *pblk) ...@@ -821,9 +833,16 @@ static int pblk_lines_init(struct pblk *pblk)
goto fail_free_bb_aux; goto fail_free_bb_aux;
} }
nr_free_blks = 0; chunk_log = pblk_bb_get_log(pblk);
if (IS_ERR(chunk_log)) {
pr_err("pblk: could not get bad block log (%lu)\n",
PTR_ERR(chunk_log));
ret = PTR_ERR(chunk_log);
goto fail_free_bb_aux;
}
for (i = 0; i < l_mg->nr_lines; i++) { for (i = 0; i < l_mg->nr_lines; i++) {
int blk_in_line; int chk_in_line;
line = &pblk->lines[i]; line = &pblk->lines[i];
...@@ -835,26 +854,20 @@ static int pblk_lines_init(struct pblk *pblk) ...@@ -835,26 +854,20 @@ static int pblk_lines_init(struct pblk *pblk)
line->vsc = &l_mg->vsc_list[i]; line->vsc = &l_mg->vsc_list[i];
spin_lock_init(&line->lock); spin_lock_init(&line->lock);
ret = pblk_alloc_line_bitmaps(pblk, line); ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks);
if (ret) if (ret)
goto fail_free_lines; goto fail_free_chunk_log;
nr_bad_blks = pblk_bb_line(pblk, line, lm->blk_per_line); chk_in_line = lm->blk_per_line - nr_bad_blks;
if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line) { if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line ||
pblk_free_line_bitmaps(line); chk_in_line < lm->min_blk_line) {
ret = -EINVAL;
goto fail_free_lines;
}
blk_in_line = lm->blk_per_line - nr_bad_blks;
if (blk_in_line < lm->min_blk_line) {
line->state = PBLK_LINESTATE_BAD; line->state = PBLK_LINESTATE_BAD;
list_add_tail(&line->list, &l_mg->bad_list); list_add_tail(&line->list, &l_mg->bad_list);
continue; continue;
} }
nr_free_blks += blk_in_line; nr_free_blks += chk_in_line;
atomic_set(&line->blk_in_line, blk_in_line); atomic_set(&line->blk_in_line, chk_in_line);
l_mg->nr_free_lines++; l_mg->nr_free_lines++;
list_add_tail(&line->list, &l_mg->free_list); list_add_tail(&line->list, &l_mg->free_list);
...@@ -862,23 +875,19 @@ static int pblk_lines_init(struct pblk *pblk) ...@@ -862,23 +875,19 @@ static int pblk_lines_init(struct pblk *pblk)
pblk_set_provision(pblk, nr_free_blks); pblk_set_provision(pblk, nr_free_blks);
/* Cleanup per-LUN bad block lists - managed within lines on run-time */ kfree(chunk_log);
for (i = 0; i < geo->all_luns; i++)
kfree(pblk->luns[i].bb_list);
return 0; return 0;
fail_free_lines:
fail_free_chunk_log:
kfree(chunk_log);
while (--i >= 0) while (--i >= 0)
pblk_free_line_bitmaps(&pblk->lines[i]); pblk_line_meta_free(&pblk->lines[i]);
fail_free_bb_aux: fail_free_bb_aux:
kfree(l_mg->bb_aux); kfree(l_mg->bb_aux);
fail_free_bb_template: fail_free_bb_template:
kfree(l_mg->bb_template); kfree(l_mg->bb_template);
fail_free_meta: fail_free_meta:
pblk_line_meta_free(pblk); pblk_line_mg_free(pblk);
fail:
for (i = 0; i < geo->all_luns; i++)
kfree(pblk->luns[i].bb_list);
return ret; return ret;
} }
...@@ -922,7 +931,7 @@ static void pblk_free(struct pblk *pblk) ...@@ -922,7 +931,7 @@ static void pblk_free(struct pblk *pblk)
pblk_luns_free(pblk); pblk_luns_free(pblk);
pblk_lines_free(pblk); pblk_lines_free(pblk);
kfree(pblk->pad_dist); kfree(pblk->pad_dist);
pblk_line_meta_free(pblk); pblk_line_mg_free(pblk);
pblk_core_free(pblk); pblk_core_free(pblk);
pblk_l2p_free(pblk); pblk_l2p_free(pblk);
...@@ -1110,7 +1119,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, ...@@ -1110,7 +1119,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
fail_free_pad_dist: fail_free_pad_dist:
kfree(pblk->pad_dist); kfree(pblk->pad_dist);
fail_free_line_meta: fail_free_line_meta:
pblk_line_meta_free(pblk); pblk_line_mg_free(pblk);
fail_free_luns: fail_free_luns:
pblk_luns_free(pblk); pblk_luns_free(pblk);
fail: fail:
......
...@@ -201,12 +201,6 @@ struct pblk_rb { ...@@ -201,12 +201,6 @@ struct pblk_rb {
struct pblk_lun { struct pblk_lun {
struct ppa_addr bppa; struct ppa_addr bppa;
u8 *bb_list; /* Bad block list for LUN. Only used on
* bring up. Bad blocks are managed
* within lines on run-time.
*/
struct semaphore wr_sem; struct semaphore wr_sem;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment