|
@@ -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)
|
|
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)
|
|
|
|
-{
|
|
|
|
- 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)
|
|
|
|
|
|
+static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
|
|
|
|
+ u8 *blks, int nr_blks)
|
|
{
|
|
{
|
|
- struct nvm_geo *geo = &dev->geo;
|
|
|
|
struct ppa_addr ppa;
|
|
struct ppa_addr ppa;
|
|
- u8 *blks;
|
|
|
|
- int nr_blks, ret;
|
|
|
|
-
|
|
|
|
- nr_blks = geo->nr_chks * geo->plane_mode;
|
|
|
|
- blks = kmalloc(nr_blks, GFP_KERNEL);
|
|
|
|
- if (!blks)
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
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)
|
|
|
|
|
|
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) {
|
|
|
|
- ret = nr_blks;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- rlun->bb_list = blks;
|
|
|
|
|
|
+ if (nr_blks < 0)
|
|
|
|
+ return -EIO;
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
-out:
|
|
|
|
- kfree(blks);
|
|
|
|
- return ret;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line,
|
|
|
|
- int blk_per_line)
|
|
|
|
|
|
+static void *pblk_bb_get_log(struct pblk *pblk)
|
|
{
|
|
{
|
|
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;
|
|
|
|
- int bb_cnt = 0;
|
|
|
|
- int i;
|
|
|
|
|
|
+ u8 *log;
|
|
|
|
+ int i, nr_blks, blk_per_lun;
|
|
|
|
+ int ret;
|
|
|
|
|
|
- for (i = 0; i < blk_per_line; i++) {
|
|
|
|
- rlun = &pblk->luns[i];
|
|
|
|
- if (rlun->bb_list[line->id] == NVM_BLK_T_FREE)
|
|
|
|
- continue;
|
|
|
|
|
|
+ blk_per_lun = geo->nr_chks * geo->plane_mode;
|
|
|
|
+ nr_blks = blk_per_lun * geo->all_luns;
|
|
|
|
|
|
- set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap);
|
|
|
|
- bb_cnt++;
|
|
|
|
|
|
+ log = kmalloc(nr_blks, GFP_KERNEL);
|
|
|
|
+ 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);
|
|
|
|
- if (!line->blk_bitmap)
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ for (i = 0; i < blk_per_line; i++) {
|
|
|
|
+ struct pblk_lun *rlun = &pblk->luns[i];
|
|
|
|
+ u8 *lun_bb_log = bb_log + i * blk_per_line;
|
|
|
|
|
|
- line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL);
|
|
|
|
- if (!line->erase_bitmap) {
|
|
|
|
- kfree(line->blk_bitmap);
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ if (lun_bb_log[line->id] == NVM_BLK_T_FREE)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ 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)
|
|
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)
|
|
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 @@ fail_free_smeta:
|
|
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)
|
|
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 @@ add_emeta_page:
|
|
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;
|
|
|
|
- goto fail;
|
|
|
|
|
|
+ return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
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 @@ add_emeta_page:
|
|
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 @@ add_emeta_page:
|
|
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);
|
|
|
|
- if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line) {
|
|
|
|
- pblk_free_line_bitmaps(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) {
|
|
|
|
|
|
+ chk_in_line = lm->blk_per_line - nr_bad_blks;
|
|
|
|
+ if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line ||
|
|
|
|
+ chk_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;
|
|
|
|
- atomic_set(&line->blk_in_line, blk_in_line);
|
|
|
|
|
|
+ nr_free_blks += chk_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 @@ add_emeta_page:
|
|
|
|
|
|
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 */
|
|
|
|
- for (i = 0; i < geo->all_luns; i++)
|
|
|
|
- kfree(pblk->luns[i].bb_list);
|
|
|
|
-
|
|
|
|
|
|
+ kfree(chunk_log);
|
|
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);
|
|
|
|
-fail:
|
|
|
|
- for (i = 0; i < geo->all_luns; i++)
|
|
|
|
- kfree(pblk->luns[i].bb_list);
|
|
|
|
|
|
+ pblk_line_mg_free(pblk);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -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 @@ fail_free_core:
|
|
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:
|