Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp133944imu; Wed, 7 Nov 2018 14:17:12 -0800 (PST) X-Google-Smtp-Source: AJdET5dCjSD7fRJMARM4yVAzCn1e/QSyvNZbHSgbnuklZ69Abl8mwnVA98emTDFcnKiGFZUZ+m0h X-Received: by 2002:a17:902:b103:: with SMTP id q3-v6mr2105560plr.83.1541629032362; Wed, 07 Nov 2018 14:17:12 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541629032; cv=none; d=google.com; s=arc-20160816; b=A54/RhIY65dJDw0wgEtfv6oAlpdcNL2mgfumOFbrmDpqL/h6h9qDPBkeqEsDMbaZst 7byOettnzwOBlzvkJVXaiYbGFUxlzcVaaBkybi41RCQY5XO0JSRGmWYiRxUaCZ2a2Zjx WlE9C+XJQKHXgfhEeMRMrUHzqSaM97YLvk+7Rjt1VXahLprWklHFA+wCem7lw2FVQFxU /5Mm+OpYAAMU3RnPH7JOVCcueviWcppHLoln5S60rd6n+dqc4vdNX5TOIEsyo1oP4O/x Y7ysuZnlTjwmIkPbnsWp3YJy6y8Oi9x/HpeCNMuB2grzbu/RyL91Bu+89E4rJJ7+Hmjn 3z8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=M9A9qVtrL86/9SSSuQXkYX53z6FBdCrSO1VFV+4b3q8=; b=QleSO5Tp/XdXvUujOxk/hUwRYem2PJTydNR2R4YFz5DCrA9q9X7X3fniAJYx14az5X LW6uwGD3ahkFtmrkoqbZ1wMf5jyd4ovjDkOP47ds/PzqsXEFlF/iUB2V0gQLjI3TpyIQ d8ULKeucsiVMyyPdM5gJCoBVwqf9JJNDcu4iLyYpX6B49HvdydAcVvsHfmLfQ27A5e2z 4fCLjIFoagsa311lUOiMAq+AdlCG/+gG63kGbsqae8kczef4T+2HdP/9a//B2OlQqwJv II8P1WcmZ2t+aQV/PVSw15F1ThEkEKI3O8lx8mfEq6jFEAEwnmqEKCGRRRVPR5kmjU3P ys4g== ARC-Authentication-Results: i=1; mx.google.com; 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 o1si1714204pgq.13.2018.11.07.14.16.56; Wed, 07 Nov 2018 14:17:12 -0800 (PST) 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; 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 S1727879AbeKHHsw (ORCPT + 99 others); Thu, 8 Nov 2018 02:48:52 -0500 Received: from lilium.sigma-star.at ([109.75.188.150]:38058 "EHLO lilium.sigma-star.at" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727164AbeKHHsv (ORCPT ); Thu, 8 Nov 2018 02:48:51 -0500 Received: from localhost (localhost [127.0.0.1]) by lilium.sigma-star.at (Postfix) with ESMTP id D72C618013774; Wed, 7 Nov 2018 23:16:26 +0100 (CET) From: Richard Weinberger To: linux-mtd@lists.infradead.org Cc: linux-kernel@vger.kernel.org, thomas.roeder@harman.com, juergen.lachmann@harman.com, Richard Weinberger Subject: [PATCH 2/2] ubi: Expose the bitrot interface Date: Wed, 7 Nov 2018 23:16:19 +0100 Message-Id: <20181107221619.32498-2-richard@nod.at> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181107221619.32498-1-richard@nod.at> References: <20181107221619.32498-1-richard@nod.at> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Using UBI_IOCRPEB and UBI_IOCSPEB userspace can force reading and scrubbing of PEBs. In case of bitflips UBI will automatically take action and move data to a different PEB. This interface allows a daemon to foster your NAND. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/cdev.c | 30 ++++++++ drivers/mtd/ubi/ubi.h | 1 + drivers/mtd/ubi/wl.c | 144 ++++++++++++++++++++++++++++++++++++ include/uapi/mtd/ubi-user.h | 5 ++ 4 files changed, 180 insertions(+) diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 22547d7a84ea..947a8adbc799 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -974,6 +974,36 @@ static long ubi_cdev_ioctl(struct file *file, unsign= ed int cmd, break; } =20 + /* Check a specific PEB for bitflips and scrub it if needed */ + case UBI_IOCRPEB: + { + int pnum; + + err =3D get_user(pnum, (__user int32_t *)argp); + if (err) { + err =3D -EFAULT; + break; + } + + err =3D ubi_bitflip_check(ubi, pnum, 0); + break; + } + + /* Force scrubbing for a specific PEB */ + case UBI_IOCSPEB: + { + int pnum; + + err =3D get_user(pnum, (__user int32_t *)argp); + if (err) { + err =3D -EFAULT; + break; + } + + err =3D ubi_bitflip_check(ubi, pnum, 1); + break; + } + default: err =3D -ENOTTY; break; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index d47b9e436e67..a1b9e764d489 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -929,6 +929,7 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct = ubi_wl_entry *used_e, int ubi_is_erase_work(struct ubi_work *wrk); void ubi_refill_pools(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); +int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force_scrub)= ; =20 /* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int o= ffset, diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index ca1b31385eb5..5540599a60c6 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1440,6 +1440,150 @@ int ubi_wl_flush(struct ubi_device *ubi, int vol_= id, int lnum) return err; } =20 +static bool scrub_possible(struct ubi_device *ubi, struct ubi_wl_entry *= e) +{ + if (in_wl_tree(e, &ubi->scrub)) + return false; + else if (in_wl_tree(e, &ubi->erroneous)) + return false; + else if (ubi->move_from =3D=3D e) + return false; + else if (ubi->move_to =3D=3D e) + return false; + + return true; +} + +/** + * ubi_bitflip_check - Check an eraseblock for bitflips and scrub it if = needed. + * @ubi: UBI device description object + * @pnum: the physical eraseblock to schedule + * @force_scrub: force scrubbing if non-zero, schedule erase otherwise + * + * This function reads the given eraseblock and checks if bitflips occur= ed. + * In case of bitflips, the eraseblock is scheduled for scrubbing. + * If scrubbing is forced with @force_scrub, the eraseblock is not read, + * but scheduled for scrubbing right away. + * + * Returns: + * %EINVAL, PEB is out of range + * %ENOENT, PEB is no longer used by UBI + * %EBUSY, PEB cannot be checked now or a check is currently running on = it + * %EAGAIN, bit flips happened but scrubbing is currently not possible + * %EUCLEAN, bit flips happened and PEB is scheduled for scrubbing + * %0, no bit flips detected + */ +int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force_scrub) +{ + int err; + struct ubi_wl_entry *e; + + if (pnum < 0 || pnum >=3D ubi->peb_count) { + err =3D -EINVAL; + goto out; + } + + /* + * Pause all parallel work, otherwise it can happen that the + * erase worker frees a wl entry under us. + */ + down_write(&ubi->work_sem); + + /* + * Make sure that the wl entry does not change state while + * inspecting it. + */ + spin_lock(&ubi->wl_lock); + e =3D ubi->lookuptbl[pnum]; + if (!e) { + spin_unlock(&ubi->wl_lock); + err =3D -ENOENT; + goto out_resume; + } + + /* + * Does it make sense to check this PEB? + */ + if (!scrub_possible(ubi, e)) { + spin_unlock(&ubi->wl_lock); + err =3D -EBUSY; + goto out_resume; + } + spin_unlock(&ubi->wl_lock); + + if (!force_scrub) { + mutex_lock(&ubi->buf_mutex); + err =3D ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size); + mutex_unlock(&ubi->buf_mutex); + } + + if (err =3D=3D UBI_IO_BITFLIPS || force_scrub) { + /* + * Okay, bit flip happened, let's figure out what we can do. + */ + spin_lock(&ubi->wl_lock); + + /* + * Recheck. We released wl_lock, UBI might have killed the + * wl entry under us. + */ + e =3D ubi->lookuptbl[pnum]; + if (!e) { + spin_unlock(&ubi->wl_lock); + err =3D -ENOENT; + goto out_resume; + } + + /* + * Need to re-check state + */ + if (!scrub_possible(ubi, e)) { + spin_unlock(&ubi->wl_lock); + err =3D -EBUSY; + goto out_resume; + } + + if (in_pq(ubi, e)) { + prot_queue_del(ubi, e->pnum); + wl_tree_add(e, &ubi->scrub); + spin_unlock(&ubi->wl_lock); + + err =3D ensure_wear_leveling(ubi, 1); + } else if (in_wl_tree(e, &ubi->used)) { + rb_erase(&e->u.rb, &ubi->used); + wl_tree_add(e, &ubi->scrub); + spin_unlock(&ubi->wl_lock); + + err =3D ensure_wear_leveling(ubi, 1); + } else if (in_wl_tree(e, &ubi->free)) { + rb_erase(&e->u.rb, &ubi->free); + ubi->free_count--; + spin_unlock(&ubi->wl_lock); + + /* + * This PEB is empty we can schedule it for + * erasure right away. No wear leveling needed. + */ + err =3D schedule_erase(ubi, e, UBI_UNKNOWN, UBI_UNKNOWN, + force_scrub ? 0 : 1, true); + } else { + spin_unlock(&ubi->wl_lock); + err =3D -EAGAIN; + } + + if (!err && !force_scrub) + err =3D -EUCLEAN; + } else { + err =3D 0; + } + +out_resume: + up_write(&ubi->work_sem); +out: + + return err; +} + /** * tree_destroy - destroy an RB-tree. * @ubi: UBI device description object diff --git a/include/uapi/mtd/ubi-user.h b/include/uapi/mtd/ubi-user.h index aad3b6201fc0..b69e9ba6742b 100644 --- a/include/uapi/mtd/ubi-user.h +++ b/include/uapi/mtd/ubi-user.h @@ -171,6 +171,11 @@ /* Re-name volumes */ #define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req) =20 +/* Read the specified PEB and scrub it if there are bitflips */ +#define UBI_IOCRPEB _IOW(UBI_IOC_MAGIC, 4, __s32) +/* Force scrubbing on the specified PEB */ +#define UBI_IOCSPEB _IOW(UBI_IOC_MAGIC, 5, __s32) + /* ioctl commands of the UBI control character device */ =20 #define UBI_CTRL_IOC_MAGIC 'o' --=20 2.19.1