Received: by 10.192.165.148 with SMTP id m20csp3560686imm; Mon, 30 Apr 2018 02:19:56 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqfzeFLPzZrK+YoQWrm0tNUvm6VrqB56glHPkPkINveCBqRz2+F2ENPLVnPIHxKSylfHhEQ X-Received: by 2002:a65:5c01:: with SMTP id u1-v6mr9779523pgr.333.1525079996425; Mon, 30 Apr 2018 02:19:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525079996; cv=none; d=google.com; s=arc-20160816; b=l5OVYuTctKenMsZwwoXdmJvokTIVdGiIDEVdWwqnYIRBd3JUp2SpVm2ZbwpXHDY9fL uKTaFrG5cdu9UWc2IbDmrR1NB/EruENtFf4HorM2Kp+5xaqkxokF1Yw/rqbO0ciW5NDy hNf18OYLz1yJwbRW6lsy2fO5cdMCDdxL3Y5i1QOCQSgStHpyHzqJqiggA2IjY/KnKZUg tDBsuPfscnMGRLNQm3xIC3tsSPVB147KoCq/8V2IXeHpIMSwsqi+VrnvAuG/Z9ZBqkLY rneXURHHJo7ux7dvS1ke74zCSiWYOwt5KuENuYOaJMZUNY/WSlpdbcHIWlaEUQY88Nu0 xmKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:spamdiagnosticmetadata :spamdiagnosticoutput:content-language:accept-language:in-reply-to :references:message-id:date:thread-index:thread-topic:subject:cc:to :from:dkim-signature:arc-authentication-results; bh=JdtJPFaO7TUy2fiV9TjqlHA2TnfFvr+CJ9S2xMfc8s8=; b=a3/jDacTv96Px9LTaXT5ypzrc1ChBngMbmwGG0Um5C2QrZgzoirq/ce3HyuV9BP5Zt RpHwbOSEAsX5rt7OskLQhGgIYIXMpzrgYlSerBjB+IfabvGpu1jNpwjA7KpqD9tDVXOO TLoNoweBgtC9QGo148nkf1qejkaW7pIGPeHKs/CLpOkeh7lkeDqxX1jH/FqrDSZkwYHY N42YAn/HqK5ryVjQgpE66NGw5VEQaQf0oPc5kWmy8otInOhaCqAUl6LkJ3pfkEmYWrjh dFsiqKgU8iF+4Bt1tJy9Nf45gK49QEr3hRZC1EoO5CiIP5EXbg+tlwZdrDjnf/hO3sZ9 IGEw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@cnexlabs.onmicrosoft.com header.s=selector1-cnexlabs-com header.b=NgS1xSzR; 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 90-v6si7042531plc.205.2018.04.30.02.19.42; Mon, 30 Apr 2018 02:19:56 -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=@cnexlabs.onmicrosoft.com header.s=selector1-cnexlabs-com header.b=NgS1xSzR; 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 S1752521AbeD3JT1 (ORCPT + 99 others); Mon, 30 Apr 2018 05:19:27 -0400 Received: from mail-co1nam03on0043.outbound.protection.outlook.com ([104.47.40.43]:14593 "EHLO NAM03-CO1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751511AbeD3JTZ (ORCPT ); Mon, 30 Apr 2018 05:19:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cnexlabs.onmicrosoft.com; s=selector1-cnexlabs-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=JdtJPFaO7TUy2fiV9TjqlHA2TnfFvr+CJ9S2xMfc8s8=; b=NgS1xSzR7FrmNThHY3s4thu4xTd2IyxpPorJrMaRWKkYtibfN+HFfML+lc1dGL2oO4QTzPUXYoSY0eZTM46dVi8b/5KaptLqMlOPIN9PkcoAY5HwmdOnAOLCba1UXA2anHmz0VvnIaC8OqayVZzFgg5rECIDpkpe8pa+GYogddA= Received: from CO2PR06MB538.namprd06.prod.outlook.com (10.141.199.23) by CO2PR06MB489.namprd06.prod.outlook.com (10.141.197.141) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.715.18; Mon, 30 Apr 2018 09:19:21 +0000 Received: from CO2PR06MB538.namprd06.prod.outlook.com ([fe80::d3b:2d62:da33:c04e]) by CO2PR06MB538.namprd06.prod.outlook.com ([fe80::d3b:2d62:da33:c04e%18]) with mapi id 15.20.0696.017; Mon, 30 Apr 2018 09:19:20 +0000 From: Javier Gonzalez To: Javier Gonzalez CC: Hans Holmberg , =?utf-8?B?TWF0aWFzIEJqw7hybGluZw==?= , "linux-block@vger.kernel.org" , "linux-kernel@vger.kernel.org" , Hans Holmberg Subject: Re: [PATCH v2 2/3] lightnvm: pblk: garbage collect lines with failed writes Thread-Topic: [PATCH v2 2/3] lightnvm: pblk: garbage collect lines with failed writes Thread-Index: AQHT24+ChfawhRlNy0+cu7vWPMNoyKQZEDOAgAABS4A= Date: Mon, 30 Apr 2018 09:19:19 +0000 Message-ID: <59DA13E5-2CD0-4C95-BE11-C53A4755BF79@cnexlabs.com> References: <1524548732-4326-1-git-send-email-hans.ml.holmberg@owltronix.com> <1524548732-4326-3-git-send-email-hans.ml.holmberg@owltronix.com> <269EA9FA-DD9B-4D22-A7F6-6AB8B937D930@cnexlabs.com> In-Reply-To: <269EA9FA-DD9B-4D22-A7F6-6AB8B937D930@cnexlabs.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: yes X-MS-TNEF-Correlator: authentication-results: spf=none (sender IP is ) smtp.mailfrom=javier@cnexlabs.com; x-originating-ip: [193.106.164.211] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1;CO2PR06MB489;7:hxvcOcCumB+dLZLwg/wlEEsUWOe1inc6/qtc55cJ4JsmU6nFJtjxui2QxESSTQJE8KlOMhDEbSRHWgHtCiCcNv7MwyGUfN+zt18qv8WzISXQpU9DirAlBNwbvXnrlgdLeeUjgopvNXdpGD7jzkhp8LWlTtBst17z/YdBrPN81vFfjx41ZzPVS88vEdw/oNlrEGK2ITMcoOL5u+0VQnnl2iYc9UdRFAbw654YtfJOfXjHD3eEYpZ+6HCGurPz8EZI x-ms-exchange-antispam-srfa-diagnostics: SOS;SOR; x-forefront-antispam-report: SFV:SKI;SCL:-1;SFV:NSPM;SFS:(10009020)(376002)(346002)(39830400003)(366004)(396003)(39380400002)(51234002)(199004)(189003)(486006)(2616005)(476003)(6512007)(11346002)(107886003)(6862004)(446003)(6486002)(81166006)(81156014)(36756003)(66066001)(5660300001)(478600001)(53936002)(6200100001)(229853002)(83716003)(105586002)(14454004)(575784001)(5250100002)(106356001)(86362001)(53946003)(6246003)(82746002)(37006003)(305945005)(54906003)(6506007)(97736004)(102836004)(33656002)(2900100001)(26005)(68736007)(76176011)(8676002)(2906002)(25786009)(6116002)(99936001)(3280700002)(3660700001)(4326008)(8936002)(7736002)(3846002)(6436002)(99286004)(316002)(59450400001);DIR:OUT;SFP:1101;SCL:1;SRVR:CO2PR06MB489;H:CO2PR06MB538.namprd06.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;A:1;MX:1; x-microsoft-antispam: UriScan:;BCL:0;PCL:0;RULEID:(7020095)(4652020)(5600026)(2017052603328)(7153060)(49563074)(7193020);SRVR:CO2PR06MB489; x-ms-traffictypediagnostic: CO2PR06MB489: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:; x-exchange-antispam-report-cfa-test: BCL:0;PCL:0;RULEID:(8211001083)(102415395)(6040522)(2401047)(8121501046)(5005006)(3002001)(93006095)(93001095)(10201501046)(3231254)(944501410)(52105095)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123564045)(20161123560045)(20161123558120)(6072148)(201708071742011);SRVR:CO2PR06MB489;BCL:0;PCL:0;RULEID:;SRVR:CO2PR06MB489; x-forefront-prvs: 0658BAF71F received-spf: None (protection.outlook.com: cnexlabs.com does not designate permitted sender hosts) x-microsoft-antispam-message-info: o+mdw1yLwP7zx/7TpK31XrMRaHwiUeJgLK8M/Cf14XKW/JCHd1CehGQdYxZEglZH7R7y1nSAOWpkShPTqiE9Y2R8YaKirX8FsYV45WI71boVfZwgJV90OqARLQo1vrP3sr7wRltr7xRf0xLhzQJnGXXjQjpZ4XrYWmXB9tLf06/GbPKy1sqk/CDmZbJydYeXz68vfgLvqpaI8dfUKN8yGQ== spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM Content-Type: multipart/signed; boundary="Apple-Mail=_033826BA-F62C-4A3B-8E14-C277C2A51A44"; protocol="application/pgp-signature"; micalg=pgp-sha512 MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 1e09434a-1caf-4c27-ec8a-08d5ae7b7485 X-OriginatorOrg: cnexlabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1e09434a-1caf-4c27-ec8a-08d5ae7b7485 X-MS-Exchange-CrossTenant-originalarrivaltime: 30 Apr 2018 09:19:19.9281 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: e40dfc2e-c6c1-463a-a598-38602b2c3cff X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO2PR06MB489 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org --Apple-Mail=_033826BA-F62C-4A3B-8E14-C277C2A51A44 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On 30 Apr 2018, at 11.14, Javier Gonzalez wrote: >=20 >> On 24 Apr 2018, at 07.45, Hans Holmberg = wrote: >>=20 >> From: Hans Holmberg >>=20 >> 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. >>=20 >> 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. >>=20 >> 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. >>=20 >> Signed-off-by: Hans Holmberg >> --- >> drivers/lightnvm/pblk-core.c | 45 ++++++++++++++++++- >> drivers/lightnvm/pblk-gc.c | 102 = +++++++++++++++++++++++++++--------------- >> drivers/lightnvm/pblk-init.c | 45 ++++++++++++------- >> 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, 199 insertions(+), 64 deletions(-) >>=20 >> diff --git a/drivers/lightnvm/pblk-core.c = b/drivers/lightnvm/pblk-core.c >> index 7762e89..413cf3b 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) >>=20 >> lockdep_assert_held(&line->lock); >>=20 >> - if (!vsc) { >> + if (line->w_err_gc->has_write_err) { >> + if (line->gc_group !=3D PBLK_LINEGC_WERR) { >> + line->gc_group =3D PBLK_LINEGC_WERR; >> + move_list =3D &l_mg->gc_werr_list; >> + pblk_rl_werr_line_in(&pblk->rl); >> + } >> + } else if (!vsc) { >> if (line->gc_group !=3D PBLK_LINEGC_FULL) { >> line->gc_group =3D PBLK_LINEGC_FULL; >> move_list =3D &l_mg->gc_full_list; >> @@ -1603,8 +1609,13 @@ static void __pblk_line_put(struct pblk *pblk, = struct pblk_line *line) >> line->state =3D PBLK_LINESTATE_FREE; >> line->gc_group =3D PBLK_LINEGC_NONE; >> pblk_line_free(line); >> - spin_unlock(&line->lock); >>=20 >> + if (line->w_err_gc->has_write_err) { >> + pblk_rl_werr_line_out(&pblk->rl); >> + line->w_err_gc->has_write_err =3D 0; >> + } >> + >> + spin_unlock(&line->lock); >> atomic_dec(&gc->pipeline_gc); >>=20 >> spin_lock(&l_mg->free_lock); >> @@ -1767,11 +1778,34 @@ void pblk_line_close_meta(struct pblk *pblk, = struct pblk_line *line) >>=20 >> 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 !=3D line->cur_sec) >> + line->emeta_ssec =3D line->cur_sec; >> + >> list_add_tail(&line->list, &l_mg->emeta_list); >> spin_unlock(&line->lock); >> spin_unlock(&l_mg->close_lock); >>=20 >> pblk_line_should_sync_meta(pblk); >> + >> + >> +} >> + >> +static void pblk_save_lba_list(struct pblk *pblk, struct pblk_line = *line) >> +{ >> + struct pblk_line_meta *lm =3D &pblk->lm; >> + struct pblk_line_mgmt *l_mg =3D &pblk->l_mg; >> + unsigned int lba_list_size =3D lm->emeta_len[2]; >> + struct pblk_w_err_gc *w_err_gc =3D line->w_err_gc; >> + struct pblk_emeta *emeta =3D line->emeta; >> + >> + w_err_gc->lba_list =3D pblk_malloc(lba_list_size, >> + l_mg->emeta_alloc_type, = GFP_KERNEL); >> + memcpy(w_err_gc->lba_list, emeta_to_lbas(pblk, emeta->buf), >> + lba_list_size); >> } >>=20 >> void pblk_line_close_ws(struct work_struct *work) >> @@ -1780,6 +1814,13 @@ void pblk_line_close_ws(struct work_struct = *work) >> = ws); >> struct pblk *pblk =3D line_ws->pblk; >> struct pblk_line *line =3D line_ws->line; >> + struct pblk_w_err_gc *w_err_gc =3D 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); >>=20 >> 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..df88f1b 100644 >> --- a/drivers/lightnvm/pblk-gc.c >> +++ b/drivers/lightnvm/pblk-gc.c >> @@ -129,6 +129,53 @@ static void pblk_gc_line_ws(struct work_struct = *work) >> kfree(gc_rq_ws); >> } >>=20 >> +static __le64 *get_lba_list_from_emeta(struct pblk *pblk, >> + struct pblk_line *line) >> +{ >> + struct line_emeta *emeta_buf; >> + struct pblk_line_mgmt *l_mg =3D &pblk->l_mg; >> + struct pblk_line_meta *lm =3D &pblk->lm; >> + unsigned int lba_list_size =3D lm->emeta_len[2]; >> + __le64 *lba_list; >> + int ret; >> + >> + emeta_buf =3D pblk_malloc(lm->emeta_len[0], >> + l_mg->emeta_alloc_type, GFP_KERNEL); >> + if (!emeta_buf) >> + return NULL; >> + >> + ret =3D pblk_line_read_emeta(pblk, line, emeta_buf); >> + if (ret) { >> + pr_err("pblk: line %d read emeta failed (%d)\n", >> + line->id, ret); >> + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> + return NULL; >> + } >> + >> + /* 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 =3D pblk_recov_check_emeta(pblk, emeta_buf); >> + if (ret) { >> + pr_err("pblk: inconsistent emeta (line %d)\n", >> + line->id); >> + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> + return NULL; >> + } >> + >> + lba_list =3D pblk_malloc(lba_list_size, >> + l_mg->emeta_alloc_type, GFP_KERNEL); >> + if (lba_list) >> + memcpy(lba_list, emeta_to_lbas(pblk, emeta_buf), = lba_list_size); >> + >> + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> + >> + return lba_list; >> +} >> + >> static void pblk_gc_line_prepare_ws(struct work_struct *work) >> { >> struct pblk_line_ws *line_ws =3D container_of(work, struct = pblk_line_ws, >> @@ -138,46 +185,26 @@ static void pblk_gc_line_prepare_ws(struct = work_struct *work) >> struct pblk_line_mgmt *l_mg =3D &pblk->l_mg; >> struct pblk_line_meta *lm =3D &pblk->lm; >> struct pblk_gc *gc =3D &pblk->gc; >> - struct line_emeta *emeta_buf; >> struct pblk_line_ws *gc_rq_ws; >> struct pblk_gc_rq *gc_rq; >> __le64 *lba_list; >> unsigned long *invalid_bitmap; >> int sec_left, nr_secs, bit; >> - int ret; >>=20 >> invalid_bitmap =3D kmalloc(lm->sec_bitmap_len, GFP_KERNEL); >> if (!invalid_bitmap) >> goto fail_free_ws; >>=20 >> - emeta_buf =3D 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 =3D 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 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 =3D 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 =3D 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; >> + if (line->w_err_gc->has_write_err) { >> + lba_list =3D line->w_err_gc->lba_list; >> + line->w_err_gc->lba_list =3D NULL; >> + } else { >> + lba_list =3D get_lba_list_from_emeta(pblk, line); >> + if (!lba_list) { >> + pr_err("pblk: could not interpret emeta (line = %d)\n", >> + line->id); >> + goto fail_free_ws; >> + } >> } >>=20 >> spin_lock(&line->lock); >> @@ -187,14 +214,14 @@ static void pblk_gc_line_prepare_ws(struct = work_struct *work) >>=20 >> if (sec_left < 0) { >> pr_err("pblk: corrupted GC line (%d)\n", line->id); >> - goto fail_free_emeta; >> + goto fail_free_lba_list; >> } >>=20 >> bit =3D -1; >> next_rq: >> gc_rq =3D kmalloc(sizeof(struct pblk_gc_rq), GFP_KERNEL); >> if (!gc_rq) >> - goto fail_free_emeta; >> + goto fail_free_lba_list; >>=20 >> nr_secs =3D 0; >> do { >> @@ -240,7 +267,7 @@ static void pblk_gc_line_prepare_ws(struct = work_struct *work) >> goto next_rq; >>=20 >> out: >> - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> + pblk_mfree(lba_list, l_mg->emeta_alloc_type); >> kfree(line_ws); >> kfree(invalid_bitmap); >>=20 >> @@ -251,9 +278,8 @@ static void pblk_gc_line_prepare_ws(struct = work_struct *work) >>=20 >> fail_free_gc_rq: >> kfree(gc_rq); >> -fail_free_emeta: >> - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); >> -fail_free_bitmap: >> +fail_free_lba_list: >> + pblk_mfree(lba_list, l_mg->emeta_alloc_type); >> kfree(invalid_bitmap); >> fail_free_ws: >> kfree(line_ws); >> @@ -349,12 +375,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 =3D atomic_read(&rl->werr_lines); >>=20 >> nr_blocks_need =3D pblk_rl_high_thrs(rl); >> nr_blocks_free =3D pblk_rl_nr_free_blks(rl); >>=20 >> /* 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))); >> } >>=20 >> 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..931ba32 100644 >> --- a/drivers/lightnvm/pblk-init.c >> +++ b/drivers/lightnvm/pblk-init.c >> @@ -493,11 +493,16 @@ static void pblk_line_mg_free(struct pblk = *pblk) >> } >> } >>=20 >> -static void pblk_line_meta_free(struct pblk_line *line) >> +static void pblk_line_meta_free(struct pblk_line_mgmt *l_mg, struct = pblk_line *line) Actually, this goes over 80 lines - please run checkpatch. Matias: can you fix this when picking it up? Thanks! >> { >> + struct pblk_w_err_gc *w_err_gc =3D line->w_err_gc; >> + >> kfree(line->blk_bitmap); >> kfree(line->erase_bitmap); >> kfree(line->chks); >> + >> + pblk_mfree(w_err_gc->lba_list, l_mg->emeta_alloc_type); >> + kfree(w_err_gc); >> } >>=20 >> static void pblk_lines_free(struct pblk *pblk) >> @@ -511,7 +516,7 @@ static void pblk_lines_free(struct pblk *pblk) >> line =3D &pblk->lines[i]; >>=20 >> pblk_line_free(line); >> - pblk_line_meta_free(line); >> + pblk_line_meta_free(l_mg, line); >> } >> spin_unlock(&l_mg->free_lock); >>=20 >> @@ -813,20 +818,28 @@ static int pblk_alloc_line_meta(struct pblk = *pblk, struct pblk_line *line) >> return -ENOMEM; >>=20 >> line->erase_bitmap =3D 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; >> + >>=20 >> line->chks =3D 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 =3D kzalloc(sizeof(struct pblk_w_err_gc), = GFP_KERNEL); >> + if (!line->w_err_gc) >> + goto free_chks; >>=20 >> return 0; >> + >> +free_chks: >> + kfree(line->chks); >> +free_erase_bitmap: >> + kfree(line->erase_bitmap); >> +free_blk_bitmap: >> + kfree(line->blk_bitmap); >> + return -ENOMEM; >> } >>=20 >> 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); >>=20 >> INIT_LIST_HEAD(&l_mg->emeta_list); >>=20 >> - l_mg->gc_lists[0] =3D &l_mg->gc_high_list; >> - l_mg->gc_lists[1] =3D &l_mg->gc_mid_list; >> - l_mg->gc_lists[2] =3D &l_mg->gc_low_list; >> + l_mg->gc_lists[0] =3D &l_mg->gc_werr_list; >> + l_mg->gc_lists[1] =3D &l_mg->gc_high_list; >> + l_mg->gc_lists[2] =3D &l_mg->gc_mid_list; >> + l_mg->gc_lists[3] =3D &l_mg->gc_low_list; >>=20 >> spin_lock_init(&l_mg->free_lock); >> spin_lock_init(&l_mg->close_lock); >> @@ -1063,7 +1078,7 @@ static int pblk_lines_init(struct pblk *pblk) >>=20 >> fail_free_lines: >> while (--i >=3D 0) >> - pblk_line_meta_free(&pblk->lines[i]); >> + pblk_line_meta_free(l_mg, &pblk->lines[i]); >> kfree(pblk->lines); >> fail_free_chunk_meta: >> kfree(chunk_meta); >> 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); >> } >>=20 >> +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 =3D container_of(rl, struct pblk, rl); >> int max =3D rl->rb_budget; >> + int werr_gc_needed =3D atomic_read(&rl->werr_lines); >>=20 >> if (free_blocks >=3D rl->high) { >> - rl->rb_user_max =3D max; >> - rl->rb_gc_max =3D 0; >> - rl->rb_state =3D PBLK_RL_HIGH; >> + if (werr_gc_needed) { >> + /* Allocate a small budget for recovering >> + * lines with write errors >> + */ >> + rl->rb_gc_max =3D 1 << rl->rb_windows_pw; >> + rl->rb_user_max =3D max - rl->rb_gc_max; >> + rl->rb_state =3D PBLK_RL_WERR; >> + } else { >> + rl->rb_user_max =3D max; >> + rl->rb_gc_max =3D 0; >> + rl->rb_state =3D PBLK_RL_OFF; >> + } >> } else if (free_blocks < rl->high) { >> int shift =3D rl->high_pw - rl->rb_windows_pw; >> int user_windows =3D free_blocks >> shift; >> @@ -124,7 +144,7 @@ static void __pblk_rl_update_rates(struct pblk_rl = *rl, >> rl->rb_state =3D PBLK_RL_LOW; >> } >>=20 >> - if (rl->rb_state =3D=3D (PBLK_RL_MID | PBLK_RL_LOW)) >> + if (rl->rb_state !=3D 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); >>=20 >> timer_setup(&rl->u_timer, pblk_rl_u_timer, 0); >>=20 >> 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 =3D 0, closed_line_cnt =3D 0, emeta_line_cnt =3D= 0; >> int d_line_cnt =3D 0, l_line_cnt =3D 0; >> int gc_full =3D 0, gc_high =3D 0, gc_mid =3D 0, gc_low =3D 0, = gc_empty =3D 0; >> + int gc_werr =3D 0; >> + >> int bad =3D 0, cor =3D 0; >> int msecs =3D 0, cur_sec =3D 0, vsc =3D 0, sec_in_line =3D 0; >> int map_weight =3D 0, meta_weight =3D 0; >> @@ -237,6 +239,15 @@ static ssize_t pblk_sysfs_lines(struct pblk = *pblk, char *page) >> gc_empty++; >> } >>=20 >> + list_for_each_entry(line, &l_mg->gc_werr_list, list) { >> + if (line->type =3D=3D PBLK_LINETYPE_DATA) >> + d_line_cnt++; >> + else if (line->type =3D=3D 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); >>=20 >> sz +=3D 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)); >>=20 >> sz +=3D snprintf(page + sz, PAGE_SIZE - sz, >> diff --git a/drivers/lightnvm/pblk-write.c = b/drivers/lightnvm/pblk-write.c >> index f62e432f..f33c2c3 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) >> } >> } >>=20 >> + line->w_err_gc->has_write_err =3D 1; >> spin_unlock(&line->lock); >> } >>=20 >> @@ -279,6 +280,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 =3D 1; >> } >>=20 >> sync =3D atomic_add_return(rqd->nr_ppas, &emeta->sync); >> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h >> index f8434a3..25ad026 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 >>=20 >> enum { >> - PBLK_RL_HIGH =3D 1, >> - PBLK_RL_MID =3D 2, >> - PBLK_RL_LOW =3D 3, >> + PBLK_RL_OFF =3D 0, >> + PBLK_RL_WERR =3D 1, >> + PBLK_RL_HIGH =3D 2, >> + PBLK_RL_MID =3D 3, >> + PBLK_RL_LOW =3D 4 >> }; >>=20 >> #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; >>=20 >> + atomic_t werr_lines; /* Number of write error lines that = needs gc */ >> + >> struct timer_list u_timer; >>=20 >> unsigned long long nr_secs; >> @@ -311,6 +315,7 @@ enum { >> PBLK_LINEGC_MID =3D 23, >> PBLK_LINEGC_HIGH =3D 24, >> PBLK_LINEGC_FULL =3D 25, >> + PBLK_LINEGC_WERR =3D 26 >> }; >>=20 >> #define PBLK_MAGIC 0x70626c6b /*pblk*/ >> @@ -412,6 +417,11 @@ struct pblk_smeta { >> struct line_smeta *buf; /* smeta buffer in persistent = format */ >> }; >>=20 >> +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 { >>=20 >> struct kref ref; /* Write buffer L2P references = */ >>=20 >> + struct pblk_w_err_gc *w_err_gc; /* Write error gc recovery = metadata */ >> + >> spinlock_t lock; /* Necessary for invalid_bitmap = only */ >> }; >>=20 >> @@ -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 */ >>=20 >> + 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 = */ >>=20 >> @@ -891,6 +905,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); >>=20 >> +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 >=20 > LGTM >=20 > Reviewed-by: Javier Gonz=C3=A1lez --Apple-Mail=_033826BA-F62C-4A3B-8E14-C277C2A51A44 Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="signature.asc" Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Message signed with OpenPGP -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEE+ws7Qq+qZPG1bJoyIX4xUKFRnnQFAlrm35MACgkQIX4xUKFR nnQa6Q//dyFcQzKg+qU7/j7Qdon5fohHcDPsjbb9gsVbl1lJzipOdkMdrnkP1Zjh PQjOBxdmM+Fbm3sse4XOeBB/NCri0Wv7on13SqopBziLwXxTeYzAqkxKkkSKlGhW mnQ+xaT8E6nPCfUXqPig9b3BFEEEdOa/NWnHxZndvXO9rjIMiD6i8SnZPTtilHKl RQciAJUnONESQX9rRPs1Hxm7FgnxY+1flbMtT4aVOlx2QfVg40LSep1E6KU6Msx1 IqrpWRS3NmSoQOMuWM/Cs5aWXW8azCTz2siyruxid/4wd8bPRJ3MWfpi/+2MdA+y Ot2RmYiuIWpod24u+dBO/3kzEQeTwsszbWJ513FAZ9/RHSaYhKR5z/r6dd0j41BV C5ffA8Is+dOnpyALXRkx/YSuFH8YI13wQQAJVRql2vPvxCWii0mgAtWrmB3BDuGu pDue1fNgTQQJ6ONplDfCwt3VHbYaRsCv79lDUFrhv+IF4JeqPR+U4rdviz3LNVEl CTtYSlUPoZhNSM70MlTGN04TZH00Bptiqs8mhBNdQueiQ7/HcXouIYgOovFTBb0x s4bKklQe87N/M0D8bIgnNSHAikMaH0TAWLhp8dSvZSXAg7XqTUBdRGhTLktwaNrU Hnt+XEqtZh2ymcz0/DYZJaZXZ1ypnuObC3IyirxvD/2wmBUHpEA= =OgYm -----END PGP SIGNATURE----- --Apple-Mail=_033826BA-F62C-4A3B-8E14-C277C2A51A44--