Received: by 10.192.165.148 with SMTP id m20csp3379276imm; Mon, 23 Apr 2018 05:43:16 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+6G7a8z1VBZI/Cyd57qmyDSyhXYkrmHP7fzO/EWVQVuICR7ZChqTlxsp60w4SayzLQg8bH X-Received: by 10.98.14.198 with SMTP id 67mr15654243pfo.36.1524487395973; Mon, 23 Apr 2018 05:43:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524487395; cv=none; d=google.com; s=arc-20160816; b=e+rbbbd2MuxKPISN824lzvqvA3Kvmz+eg8FogvgjRuYxqdn8Y8hrwYSfMnsTa/Ki+E +P05xmtxw+LVBJZVjW/4wj9Nxt9dIPW+WOF06l5rljzObm7Xb352/YD5tFMxxamOp39K BVBFanyeVpQ0WjB8zqar1I8UuNQ3DxOwG5HlbdRRKLmmyUjedwErLiTJ1mnrW5TkJD87 AF0LHLE8a5xNbcaaYjQ6OWHue/EI/Pa5QihZqFrHg8KyopacVf6dnLHnM2fjXwvdK/9+ JV4E9T30v7b7J1rpcK4p0yo6EayEUfEthpvwD17Zja1c34SCX6XBPAHkDalKG4WXocaP b7jQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=rQFG5E7Uny+BHN1M7e95mKSVc+ZBhfMw8GE7IJqvFNU=; b=sebmo4aEKrPmn2qbd6IL25SeFf0x+T5TprjQoym6ZyKc28TvybdTrlLcHArM4P4fsl 7R4F89GuTUrUBTKBTiM1VVJpFWctMyQIS49P59ROauXvX91EnIMNL3zG95+qU/IshFuu dPPnsoRppS3VYhS0BZEbS+PMA0a1O64GbFt2JVbTYucydrlSBv0JtWUGxyWxPKmJ1QLq r1TdyiCxyXu7bTbbhfVQyvaNxEEWLmgBhYoTrBK2JV9PhjUvcPj7rsPuXe12yv2SFgOk +MEev6ir2wEz0xqNmZe+E5R7nSLEyhrKAHezPpCv8QCcYOrrfEpZn7NqE+H3IX1UVYtE xwsQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@owltronix-com.20150623.gappssmtp.com header.s=20150623 header.b=Gnesb03m; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 4-v6si11686187pld.371.2018.04.23.05.43.01; Mon, 23 Apr 2018 05:43:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@owltronix-com.20150623.gappssmtp.com header.s=20150623 header.b=Gnesb03m; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754930AbeDWMlp (ORCPT + 99 others); Mon, 23 Apr 2018 08:41:45 -0400 Received: from mail-ua0-f194.google.com ([209.85.217.194]:42752 "EHLO mail-ua0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754832AbeDWMll (ORCPT ); Mon, 23 Apr 2018 08:41:41 -0400 Received: by mail-ua0-f194.google.com with SMTP id f3so4518507uan.9 for ; Mon, 23 Apr 2018 05:41:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=owltronix-com.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=rQFG5E7Uny+BHN1M7e95mKSVc+ZBhfMw8GE7IJqvFNU=; b=Gnesb03muQY7hCWOsUoa+9zoMWfrHvH5gvBvSbLgq97GbgLG1WVUuBzvRTy4h0Zhlu +ce3ql8IEOT7NWM40IylOSoZN13o7JIC18y8vCV7XjmySqzVxksySU1+FLaxUARNepNu rqjwtpbXSYAR81LIYsqRAKrmh74zzddFX/lxRMMu+jb54ZMlKLv3qtiAHaPJyGgKDmcO ooHBTodTQwSmm7tmAA3mG7EztqPIQogSfSvdeisXNrvGZTVRzvilRdGQRL5dLYGQxNXV /ol9hEWpp5MAWY98dtPhS9xGaxS3qRWBVxiwuEGYYkznE0KIhpdUygbXrTswtMf1HhMJ TDjg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=rQFG5E7Uny+BHN1M7e95mKSVc+ZBhfMw8GE7IJqvFNU=; b=RiX3vmYg35hWKrUwCUoJLJw/vYxUa7MddSU/oQJpnx4jmFvADhFWpBkabn0VX6wsX4 wum/YLeXpkrXa3tiCgrLL+49dT2hKAP12FU3dK3Wad5ABgaFfse+88gWjDYiJXDAiIUX sZI9/o9Q0ehSTLtcOCRvtsZNyvOVDEhd0gm2NGRXKY/ZWGkNpPA/sjCHbic1Ao0BDOr6 FqAhLwC3RLyFxZva2jwYeWKAOIXSf9VqxHezPBrjGl61tsGu56vdyy9N0V/mrThbQsdP JhCqL0FsmkgM9u/b2lMx0w/ovWzlmYcyRg7YeMQSqdKNvnJiLI7AvKVFbZKZR5abDcVW kf2Q== X-Gm-Message-State: ALQs6tAnxP9Z6XTHWlhpgZMIaCOnmGlw6JpAjypEg2KrlDAQxzOEHD8Z jnV3h44WbuezsWzfZp/iQl0knT3m0qIQ59yh0CSisg== X-Received: by 10.176.1.210 with SMTP id 76mr9003554ual.200.1524487300725; Mon, 23 Apr 2018 05:41:40 -0700 (PDT) MIME-Version: 1.0 Received: by 10.103.138.72 with HTTP; Mon, 23 Apr 2018 05:41:40 -0700 (PDT) In-Reply-To: <52CBD83E-784F-41E0-BB1E-CE12A93D015E@cnexlabs.com> References: <1524155964-3743-1-git-send-email-hans.ml.holmberg@owltronix.com> <1524155964-3743-3-git-send-email-hans.ml.holmberg@owltronix.com> <52CBD83E-784F-41E0-BB1E-CE12A93D015E@cnexlabs.com> From: Hans Holmberg Date: Mon, 23 Apr 2018 15:41:40 +0300 Message-ID: Subject: Re: [PATCH 2/3] lightnvm: pblk: garbage collect lines with failed writes To: Javier Gonzalez Cc: =?UTF-8?Q?Matias_Bj=C3=B8rling?= , "linux-block@vger.kernel.org" , "linux-kernel@vger.kernel.org" , Hans Holmberg Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, Apr 20, 2018 at 9:49 PM, Javier Gonzalez wrote: >> On 19 Apr 2018, at 09.39, Hans Holmberg wrote: >> >> From: Hans Holmberg >> >> Write failures should not happen under normal circumstances, >> so in order to bring the chunk back into a known state as soon >> as possible, evacuate all the valid data out of the line and let the >> fw judge if the block can be written to in the next reset cycle. >> >> Do this by introducing a new gc list for lines with failed writes, >> and ensure that the rate limiter allocates a small portion of >> the write bandwidth to get the job done. >> >> The lba list is saved in memory for use during gc as we >> cannot gurantee that the emeta data is readable if a write >> error occurred. >> >> Signed-off-by: Hans Holmberg >> --- >> drivers/lightnvm/pblk-core.c | 43 +++++++++++++++++++++-- >> drivers/lightnvm/pblk-gc.c | 79 +++++++++++++++++++++++++++---------------- >> drivers/lightnvm/pblk-init.c | 39 ++++++++++++++------- >> drivers/lightnvm/pblk-rl.c | 29 +++++++++++++--- >> drivers/lightnvm/pblk-sysfs.c | 15 ++++++-- >> drivers/lightnvm/pblk-write.c | 2 ++ >> drivers/lightnvm/pblk.h | 25 +++++++++++--- >> 7 files changed, 178 insertions(+), 54 deletions(-) >> >> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c >> index 7762e89..f6135e4 100644 >> --- a/drivers/lightnvm/pblk-core.c >> +++ b/drivers/lightnvm/pblk-core.c >> @@ -373,7 +373,13 @@ struct list_head *pblk_line_gc_list(struct pblk *pblk, struct pblk_line *line) >> >> lockdep_assert_held(&line->lock); >> >> - if (!vsc) { >> + if (line->w_err_gc->has_write_err) { >> + if (line->gc_group != PBLK_LINEGC_WERR) { >> + line->gc_group = PBLK_LINEGC_WERR; >> + move_list = &l_mg->gc_werr_list; >> + pblk_rl_werr_line_in(&pblk->rl); >> + } >> + } else if (!vsc) { >> if (line->gc_group != PBLK_LINEGC_FULL) { >> line->gc_group = PBLK_LINEGC_FULL; >> move_list = &l_mg->gc_full_list; >> @@ -1603,8 +1609,13 @@ static void __pblk_line_put(struct pblk *pblk, struct pblk_line *line) >> line->state = PBLK_LINESTATE_FREE; >> line->gc_group = PBLK_LINEGC_NONE; >> pblk_line_free(line); >> - spin_unlock(&line->lock); >> >> + if (line->w_err_gc->has_write_err) { >> + pblk_rl_werr_line_out(&pblk->rl); >> + line->w_err_gc->has_write_err = 0; >> + } >> + >> + spin_unlock(&line->lock); >> atomic_dec(&gc->pipeline_gc); >> >> spin_lock(&l_mg->free_lock); >> @@ -1767,11 +1778,32 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line) >> >> spin_lock(&l_mg->close_lock); >> spin_lock(&line->lock); >> + >> + /* Update the in-memory start address for emeta, in case it has >> + * shifted due to write errors >> + */ >> + if (line->emeta_ssec != line->cur_sec) >> + line->emeta_ssec = line->cur_sec; >> + >> list_add_tail(&line->list, &l_mg->emeta_list); >> spin_unlock(&line->lock); >> spin_unlock(&l_mg->close_lock); >> >> pblk_line_should_sync_meta(pblk); >> + >> + >> +} >> + >> +static void pblk_save_lba_list(struct pblk *pblk, struct pblk_line *line) >> +{ >> + struct pblk_line_meta *lm = &pblk->lm; >> + unsigned int lba_list_size = lm->emeta_len[2]; >> + struct pblk_w_err_gc *w_err_gc = line->w_err_gc; >> + struct pblk_emeta *emeta = line->emeta; >> + >> + w_err_gc->lba_list = kmalloc(lba_list_size, GFP_KERNEL); >> + memcpy(w_err_gc->lba_list, emeta_to_lbas(pblk, emeta->buf), >> + lba_list_size); >> } >> >> void pblk_line_close_ws(struct work_struct *work) >> @@ -1780,6 +1812,13 @@ void pblk_line_close_ws(struct work_struct *work) >> ws); >> struct pblk *pblk = line_ws->pblk; >> struct pblk_line *line = line_ws->line; >> + struct pblk_w_err_gc *w_err_gc = line->w_err_gc; >> + >> + /* Write errors makes the emeta start address stored in smeta invalid, >> + * so keep a copy of the lba list until we've gc'd the line >> + */ >> + if (w_err_gc->has_write_err) >> + pblk_save_lba_list(pblk, line); >> >> pblk_line_close(pblk, line); >> mempool_free(line_ws, pblk->gen_ws_pool); >> diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c >> index b0cc277..62f0548 100644 >> --- a/drivers/lightnvm/pblk-gc.c >> +++ b/drivers/lightnvm/pblk-gc.c >> @@ -138,10 +138,10 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) >> struct pblk_line_mgmt *l_mg = &pblk->l_mg; >> struct pblk_line_meta *lm = &pblk->lm; >> struct pblk_gc *gc = &pblk->gc; >> - struct line_emeta *emeta_buf; >> + struct line_emeta *emeta_buf = NULL; >> struct pblk_line_ws *gc_rq_ws; >> struct pblk_gc_rq *gc_rq; >> - __le64 *lba_list; >> + __le64 *lba_list = NULL; >> unsigned long *invalid_bitmap; >> int sec_left, nr_secs, bit; >> int ret; >> @@ -150,34 +150,42 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) >> if (!invalid_bitmap) >> goto fail_free_ws; >> >> - emeta_buf = pblk_malloc(lm->emeta_len[0], l_mg->emeta_alloc_type, >> - GFP_KERNEL); >> - if (!emeta_buf) { >> - pr_err("pblk: cannot use GC emeta\n"); >> - goto fail_free_bitmap; >> - } >> - >> - ret = pblk_line_read_emeta(pblk, line, emeta_buf); >> - if (ret) { >> - pr_err("pblk: line %d read emeta failed (%d)\n", line->id, ret); >> - goto fail_free_emeta; >> - } >> + if (line->w_err_gc->has_write_err) { >> + lba_list = line->w_err_gc->lba_list; >> + } else { >> + emeta_buf = pblk_malloc(lm->emeta_len[0], >> + l_mg->emeta_alloc_type, GFP_KERNEL); >> + if (!emeta_buf) { >> + pr_err("pblk: cannot use GC emeta\n"); >> + goto fail_free_bitmap; >> + } >> >> - /* If this read fails, it means that emeta is corrupted. For now, leave >> - * the line untouched. TODO: Implement a recovery routine that scans and >> - * moves all sectors on the line. >> - */ >> + ret = pblk_line_read_emeta(pblk, line, emeta_buf); >> + if (ret) { >> + pr_err("pblk: line %d read emeta failed (%d)\n", >> + line->id, ret); >> + goto fail_free_emeta; >> + } >> >> - ret = pblk_recov_check_emeta(pblk, emeta_buf); >> - if (ret) { >> - pr_err("pblk: inconsistent emeta (line %d)\n", line->id); >> - goto fail_free_emeta; >> - } >> + /* If this read fails, it means that emeta is corrupted. >> + * For now, leave the line untouched. >> + * TODO: Implement a recovery routine that scans and moves >> + * all sectors on the line., >> + */ >> + >> + ret = pblk_recov_check_emeta(pblk, emeta_buf); >> + if (ret) { >> + pr_err("pblk: inconsistent emeta (line %d)\n", >> + line->id); >> + goto fail_free_emeta; >> + } >> >> - lba_list = emeta_to_lbas(pblk, emeta_buf); >> - if (!lba_list) { >> - pr_err("pblk: could not interpret emeta (line %d)\n", line->id); >> - goto fail_free_emeta; >> + lba_list = emeta_to_lbas(pblk, emeta_buf); >> + if (!lba_list) { >> + pr_err("pblk: could not interpret emeta (line %d)\n", >> + line->id); >> + goto fail_free_emeta; >> + } >> } > > > would it be an idea to make move all the logic above to a different > function returning lba_list? This way, we do not have an extra indent > for a single line use case. Yes, indeed it would. I'll refactor this into a separate function. > >> >> spin_lock(&line->lock); >> @@ -240,7 +248,12 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) >> goto next_rq; >> >> out: >> - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> + if (line->w_err_gc->has_write_err) { >> + kfree(lba_list); >> + line->w_err_gc->lba_list = NULL; >> + } else >> + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> + >> kfree(line_ws); >> kfree(invalid_bitmap); >> >> @@ -252,7 +265,11 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) >> fail_free_gc_rq: >> kfree(gc_rq); >> fail_free_emeta: >> - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> + if (line->w_err_gc->has_write_err) { >> + kfree(lba_list); >> + line->w_err_gc->lba_list = NULL; >> + } else >> + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); > > Can you open/close brackets here too? I'll tidy this up along with the refactoring mentioned above. > >> fail_free_bitmap: >> kfree(invalid_bitmap); >> fail_free_ws: >> @@ -349,12 +366,14 @@ static struct pblk_line *pblk_gc_get_victim_line(struct pblk *pblk, >> static bool pblk_gc_should_run(struct pblk_gc *gc, struct pblk_rl *rl) >> { >> unsigned int nr_blocks_free, nr_blocks_need; >> + unsigned int werr_lines = atomic_read(&rl->werr_lines); >> >> nr_blocks_need = pblk_rl_high_thrs(rl); >> nr_blocks_free = pblk_rl_nr_free_blks(rl); >> >> /* This is not critical, no need to take lock here */ >> - return ((gc->gc_active) && (nr_blocks_need > nr_blocks_free)); >> + return ((werr_lines > 0) || >> + ((gc->gc_active) && (nr_blocks_need > nr_blocks_free))); >> } >> >> void pblk_gc_free_full_lines(struct pblk *pblk) >> diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c >> index 6f06727..092e361 100644 >> --- a/drivers/lightnvm/pblk-init.c >> +++ b/drivers/lightnvm/pblk-init.c >> @@ -495,9 +495,14 @@ static void pblk_line_mg_free(struct pblk *pblk) >> >> static void pblk_line_meta_free(struct pblk_line *line) >> { >> + struct pblk_w_err_gc *w_err_gc = line->w_err_gc; >> + >> kfree(line->blk_bitmap); >> kfree(line->erase_bitmap); >> kfree(line->chks); >> + >> + kfree(w_err_gc->lba_list); >> + kfree(w_err_gc); >> } >> >> static void pblk_lines_free(struct pblk *pblk) >> @@ -813,20 +818,28 @@ static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line) >> return -ENOMEM; >> >> line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); >> - if (!line->erase_bitmap) { >> - kfree(line->blk_bitmap); >> - return -ENOMEM; >> - } >> + if (!line->erase_bitmap) >> + goto free_blk_bitmap; >> + >> >> line->chks = kmalloc(lm->blk_per_line * sizeof(struct nvm_chk_meta), >> GFP_KERNEL); >> - if (!line->chks) { >> - kfree(line->erase_bitmap); >> - kfree(line->blk_bitmap); >> - return -ENOMEM; >> - } >> + if (!line->chks) >> + goto free_erase_bitmap; >> + >> + line->w_err_gc = kzalloc(sizeof(struct pblk_w_err_gc), GFP_KERNEL); >> + if (!line->w_err_gc) >> + goto free_chks; >> >> return 0; >> + >> +free_chks: >> + kfree(line->chks); >> +free_erase_bitmap: >> + kfree(line->erase_bitmap); >> +free_blk_bitmap: >> + kfree(line->blk_bitmap); >> + return -ENOMEM; >> } >> >> static int pblk_line_mg_init(struct pblk *pblk) >> @@ -851,12 +864,14 @@ static int pblk_line_mg_init(struct pblk *pblk) >> INIT_LIST_HEAD(&l_mg->gc_mid_list); >> INIT_LIST_HEAD(&l_mg->gc_low_list); >> INIT_LIST_HEAD(&l_mg->gc_empty_list); >> + INIT_LIST_HEAD(&l_mg->gc_werr_list); >> >> INIT_LIST_HEAD(&l_mg->emeta_list); >> >> - l_mg->gc_lists[0] = &l_mg->gc_high_list; >> - l_mg->gc_lists[1] = &l_mg->gc_mid_list; >> - l_mg->gc_lists[2] = &l_mg->gc_low_list; >> + l_mg->gc_lists[0] = &l_mg->gc_werr_list; >> + l_mg->gc_lists[1] = &l_mg->gc_high_list; >> + l_mg->gc_lists[2] = &l_mg->gc_mid_list; >> + l_mg->gc_lists[3] = &l_mg->gc_low_list; >> >> spin_lock_init(&l_mg->free_lock); >> spin_lock_init(&l_mg->close_lock); >> diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c >> index 883a711..6a0616a 100644 >> --- a/drivers/lightnvm/pblk-rl.c >> +++ b/drivers/lightnvm/pblk-rl.c >> @@ -73,6 +73,16 @@ void pblk_rl_user_in(struct pblk_rl *rl, int nr_entries) >> pblk_rl_kick_u_timer(rl); >> } >> >> +void pblk_rl_werr_line_in(struct pblk_rl *rl) >> +{ >> + atomic_inc(&rl->werr_lines); >> +} >> + >> +void pblk_rl_werr_line_out(struct pblk_rl *rl) >> +{ >> + atomic_dec(&rl->werr_lines); >> +} >> + >> void pblk_rl_gc_in(struct pblk_rl *rl, int nr_entries) >> { >> atomic_add(nr_entries, &rl->rb_gc_cnt); >> @@ -99,11 +109,21 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl, >> { >> struct pblk *pblk = container_of(rl, struct pblk, rl); >> int max = rl->rb_budget; >> + int werr_gc_needed = atomic_read(&rl->werr_lines); >> >> if (free_blocks >= rl->high) { >> - rl->rb_user_max = max; >> - rl->rb_gc_max = 0; >> - rl->rb_state = PBLK_RL_HIGH; >> + if (werr_gc_needed) { >> + /* Allocate a small budget for recovering >> + * lines with write errors >> + */ >> + rl->rb_gc_max = 1 << rl->rb_windows_pw; >> + rl->rb_user_max = max - rl->rb_gc_max; >> + rl->rb_state = PBLK_RL_WERR; >> + } else { >> + rl->rb_user_max = max; >> + rl->rb_gc_max = 0; >> + rl->rb_state = PBLK_RL_OFF; >> + } >> } else if (free_blocks < rl->high) { >> int shift = rl->high_pw - rl->rb_windows_pw; >> int user_windows = free_blocks >> shift; >> @@ -124,7 +144,7 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl, >> rl->rb_state = PBLK_RL_LOW; >> } >> >> - if (rl->rb_state == (PBLK_RL_MID | PBLK_RL_LOW)) >> + if (rl->rb_state != PBLK_RL_OFF) >> pblk_gc_should_start(pblk); >> else >> pblk_gc_should_stop(pblk); >> @@ -221,6 +241,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget) >> atomic_set(&rl->rb_user_cnt, 0); >> atomic_set(&rl->rb_gc_cnt, 0); >> atomic_set(&rl->rb_space, -1); >> + atomic_set(&rl->werr_lines, 0); >> >> timer_setup(&rl->u_timer, pblk_rl_u_timer, 0); >> >> diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c >> index e61909a..88a0a7c 100644 >> --- a/drivers/lightnvm/pblk-sysfs.c >> +++ b/drivers/lightnvm/pblk-sysfs.c >> @@ -173,6 +173,8 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page) >> int free_line_cnt = 0, closed_line_cnt = 0, emeta_line_cnt = 0; >> int d_line_cnt = 0, l_line_cnt = 0; >> int gc_full = 0, gc_high = 0, gc_mid = 0, gc_low = 0, gc_empty = 0; >> + int gc_werr = 0; >> + >> int bad = 0, cor = 0; >> int msecs = 0, cur_sec = 0, vsc = 0, sec_in_line = 0; >> int map_weight = 0, meta_weight = 0; >> @@ -237,6 +239,15 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page) >> gc_empty++; >> } >> >> + list_for_each_entry(line, &l_mg->gc_werr_list, list) { >> + if (line->type == PBLK_LINETYPE_DATA) >> + d_line_cnt++; >> + else if (line->type == PBLK_LINETYPE_LOG) >> + l_line_cnt++; >> + closed_line_cnt++; >> + gc_werr++; >> + } >> + >> list_for_each_entry(line, &l_mg->bad_list, list) >> bad++; >> list_for_each_entry(line, &l_mg->corrupt_list, list) >> @@ -275,8 +286,8 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page) >> l_mg->nr_lines); >> >> sz += snprintf(page + sz, PAGE_SIZE - sz, >> - "GC: full:%d, high:%d, mid:%d, low:%d, empty:%d, queue:%d\n", >> - gc_full, gc_high, gc_mid, gc_low, gc_empty, >> + "GC: full:%d, high:%d, mid:%d, low:%d, empty:%d, werr: %d, queue:%d\n", >> + gc_full, gc_high, gc_mid, gc_low, gc_empty, gc_werr, >> atomic_read(&pblk->gc.read_inflight_gc)); >> >> sz += snprintf(page + sz, PAGE_SIZE - sz, >> diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c >> index ab45157..3b6bead 100644 >> --- a/drivers/lightnvm/pblk-write.c >> +++ b/drivers/lightnvm/pblk-write.c >> @@ -136,6 +136,7 @@ static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa) >> } >> } >> >> + line->w_err_gc->has_write_err = 1; >> spin_unlock(&line->lock); >> } >> >> @@ -277,6 +278,7 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd) >> if (rqd->error) { >> pblk_log_write_err(pblk, rqd); >> pr_err("pblk: metadata I/O failed. Line %d\n", line->id); >> + line->w_err_gc->has_write_err = 1; >> } >> >> sync = atomic_add_return(rqd->nr_ppas, &emeta->sync); >> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h >> index cff6aea..a4e55d8 100644 >> --- a/drivers/lightnvm/pblk.h >> +++ b/drivers/lightnvm/pblk.h >> @@ -89,12 +89,14 @@ struct pblk_sec_meta { >> /* The number of GC lists and the rate-limiter states go together. This way the >> * rate-limiter can dictate how much GC is needed based on resource utilization. >> */ >> -#define PBLK_GC_NR_LISTS 3 >> +#define PBLK_GC_NR_LISTS 4 >> >> enum { >> - PBLK_RL_HIGH = 1, >> - PBLK_RL_MID = 2, >> - PBLK_RL_LOW = 3, >> + PBLK_RL_OFF = 0, >> + PBLK_RL_WERR = 1, >> + PBLK_RL_HIGH = 2, >> + PBLK_RL_MID = 3, >> + PBLK_RL_LOW = 4 >> }; >> >> #define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS) >> @@ -278,6 +280,8 @@ struct pblk_rl { >> int rb_user_active; >> int rb_gc_active; >> >> + atomic_t werr_lines; /* Number of write error lines that needs gc */ >> + >> struct timer_list u_timer; >> >> unsigned long long nr_secs; >> @@ -311,6 +315,7 @@ enum { >> PBLK_LINEGC_MID = 23, >> PBLK_LINEGC_HIGH = 24, >> PBLK_LINEGC_FULL = 25, >> + PBLK_LINEGC_WERR = 26 >> }; >> >> #define PBLK_MAGIC 0x70626c6b /*pblk*/ >> @@ -412,6 +417,11 @@ struct pblk_smeta { >> struct line_smeta *buf; /* smeta buffer in persistent format */ >> }; >> >> +struct pblk_w_err_gc { >> + int has_write_err; >> + __le64 *lba_list; >> +}; >> + >> struct pblk_line { >> struct pblk *pblk; >> unsigned int id; /* Line number corresponds to the >> @@ -457,6 +467,8 @@ struct pblk_line { >> >> struct kref ref; /* Write buffer L2P references */ >> >> + struct pblk_w_err_gc *w_err_gc; /* Write error gc recovery metadata */ >> + >> spinlock_t lock; /* Necessary for invalid_bitmap only */ >> }; >> >> @@ -488,6 +500,8 @@ struct pblk_line_mgmt { >> struct list_head gc_mid_list; /* Full lines ready to GC, mid isc */ >> struct list_head gc_low_list; /* Full lines ready to GC, low isc */ >> >> + struct list_head gc_werr_list; /* Write err recovery list */ >> + >> struct list_head gc_full_list; /* Full lines ready to GC, no valid */ >> struct list_head gc_empty_list; /* Full lines close, all valid */ >> >> @@ -894,6 +908,9 @@ void pblk_rl_free_lines_dec(struct pblk_rl *rl, struct pblk_line *line, >> bool used); >> int pblk_rl_is_limit(struct pblk_rl *rl); >> >> +void pblk_rl_werr_line_in(struct pblk_rl *rl); >> +void pblk_rl_werr_line_out(struct pblk_rl *rl); >> + >> /* >> * pblk sysfs >> */ >> -- >> 2.7.4 > > Otherwise, it looks good to me Great, thanks. > > Javier