From 6e7d80161066c99d12580d1b985cb1408bb58cf1 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 16 May 2018 22:17:03 +0200 Subject: ubi: fastmap: Cancel work upon detach Ben Hutchings pointed out that 29b7a6fa1ec0 ("ubi: fastmap: Don't flush fastmap work on detach") does not really fix the problem, it just reduces the risk to hit the race window where fastmap work races against free()'ing ubi->volumes[]. The correct approach is making sure that no more fastmap work is in progress before we free ubi data structures. So we cancel fastmap work right after the ubi background thread is stopped. By setting ubi->thread_enabled to zero we make sure that no further work tries to wake the thread. Fixes: 29b7a6fa1ec0 ("ubi: fastmap: Don't flush fastmap work on detach") Fixes: 74cdaf24004a ("UBI: Fastmap: Fix memory leaks while closing the WL sub-system") Cc: stable@vger.kernel.org Cc: Ben Hutchings Cc: Martin Townsend Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/build.c | 3 +++ drivers/mtd/ubi/wl.c | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 753494e042d5..74425af840d6 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1091,6 +1091,9 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) if (ubi->bgt_thread) kthread_stop(ubi->bgt_thread); +#ifdef CONFIG_MTD_UBI_FASTMAP + cancel_work_sync(&ubi->fm_work); +#endif ubi_debugfs_exit_dev(ubi); uif_close(ubi); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 2052a647220e..f66b3b22f328 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1505,6 +1505,7 @@ int ubi_thread(void *u) } dbg_wl("background thread \"%s\" is killed", ubi->bgt_name); + ubi->thread_enabled = 0; return 0; } @@ -1514,9 +1515,6 @@ int ubi_thread(void *u) */ static void shutdown_work(struct ubi_device *ubi) { -#ifdef CONFIG_MTD_UBI_FASTMAP - flush_work(&ubi->fm_work); -#endif while (!list_empty(&ubi->works)) { struct ubi_work *wrk; -- cgit v1.2.3 From 781932375ffc6411713ee0926ccae8596ed0261c Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 28 May 2018 22:04:32 +0200 Subject: ubi: fastmap: Correctly handle interrupted erasures in EBA Fastmap cannot track the LEB unmap operation, therefore it can happen that after an interrupted erasure the mapping still looks good from Fastmap's point of view, while reading from the PEB will cause an ECC error and confuses the upper layer. Instead of teaching users of UBI how to deal with that, we read back the VID header and check for errors. If the PEB is empty or shows ECC errors we fixup the mapping and schedule the PEB for erasure. Fixes: dbb7d2a88d2a ("UBI: Add fastmap core") Cc: Reported-by: martin bayern Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/eba.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 250e30fac61b..593a4f9d97e3 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -490,6 +490,82 @@ out_unlock: return err; } +#ifdef CONFIG_MTD_UBI_FASTMAP +/** + * check_mapping - check and fixup a mapping + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @pnum: physical eraseblock number + * + * Checks whether a given mapping is valid. Fastmap cannot track LEB unmap + * operations, if such an operation is interrupted the mapping still looks + * good, but upon first read an ECC is reported to the upper layer. + * Normaly during the full-scan at attach time this is fixed, for Fastmap + * we have to deal with it while reading. + * If the PEB behind a LEB shows this symthom we change the mapping to + * %UBI_LEB_UNMAPPED and schedule the PEB for erasure. + * + * Returns 0 on success, negative error code in case of failure. + */ +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + int err; + struct ubi_vid_io_buf *vidb; + + if (!ubi->fast_attach) + return 0; + + vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS); + if (!vidb) + return -ENOMEM; + + err = ubi_io_read_vid_hdr(ubi, *pnum, vidb, 0); + if (err > 0 && err != UBI_IO_BITFLIPS) { + int torture = 0; + + switch (err) { + case UBI_IO_FF: + case UBI_IO_FF_BITFLIPS: + case UBI_IO_BAD_HDR: + case UBI_IO_BAD_HDR_EBADMSG: + break; + default: + ubi_assert(0); + } + + if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_FF_BITFLIPS) + torture = 1; + + down_read(&ubi->fm_eba_sem); + vol->eba_tbl->entries[lnum].pnum = UBI_LEB_UNMAPPED; + up_read(&ubi->fm_eba_sem); + ubi_wl_put_peb(ubi, vol->vol_id, lnum, *pnum, torture); + + *pnum = UBI_LEB_UNMAPPED; + } else if (err < 0) { + ubi_err(ubi, "unable to read VID header back from PEB %i: %i", + *pnum, err); + + goto out_free; + } + + err = 0; + +out_free: + ubi_free_vid_buf(vidb); + + return err; +} +#else +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + return 0; +} +#endif + /** * ubi_eba_read_leb - read data. * @ubi: UBI device description object @@ -522,7 +598,13 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl->entries[lnum].pnum; - if (pnum < 0) { + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) + goto out_unlock; + } + + if (pnum == UBI_LEB_UNMAPPED) { /* * The logical eraseblock is not mapped, fill the whole buffer * with 0xFF bytes. The exception is static volumes for which @@ -930,6 +1012,12 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl->entries[lnum].pnum; + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) + goto out; + } + if (pnum >= 0) { dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); -- cgit v1.2.3 From 34653fd8c46e771585fce5975e4243f8fd401914 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 28 May 2018 22:04:33 +0200 Subject: ubi: fastmap: Check each mapping only once Maintain a bitmap to keep track of which LEB->PEB mapping was checked already. That way we have to read back VID headers only once. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/build.c | 1 + drivers/mtd/ubi/eba.c | 4 ++++ drivers/mtd/ubi/fastmap.c | 20 ++++++++++++++++++++ drivers/mtd/ubi/ubi.h | 11 +++++++++++ drivers/mtd/ubi/vmt.c | 1 + drivers/mtd/ubi/vtbl.c | 16 +++++++++++++++- 6 files changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 74425af840d6..d2a726654ff1 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -526,6 +526,7 @@ void ubi_free_internal_volumes(struct ubi_device *ubi) for (i = ubi->vtbl_slots; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { ubi_eba_replace_table(ubi->volumes[i], NULL); + ubi_fastmap_destroy_checkmap(ubi->volumes[i]); kfree(ubi->volumes[i]); } } diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 593a4f9d97e3..1ceab201a27b 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -517,6 +517,9 @@ static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnu if (!ubi->fast_attach) return 0; + if (!vol->checkmap || test_bit(lnum, vol->checkmap)) + return 0; + vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS); if (!vidb) return -ENOMEM; @@ -551,6 +554,7 @@ static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnu goto out_free; } + set_bit(lnum, vol->checkmap); err = 0; out_free: diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 91705962ba73..462526a10537 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -1100,6 +1100,26 @@ free_fm_sb: goto out; } +int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) +{ + struct ubi_device *ubi = vol->ubi; + + if (!ubi->fast_attach) + return 0; + + vol->checkmap = kcalloc(BITS_TO_LONGS(leb_count), sizeof(unsigned long), + GFP_KERNEL); + if (!vol->checkmap) + return -ENOMEM; + + return 0; +} + +void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) +{ + kfree(vol->checkmap); +} + /** * ubi_write_fastmap - writes a fastmap. * @ubi: UBI device object diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 5fe62653995e..f5ba97c46160 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -334,6 +334,9 @@ struct ubi_eba_leb_desc { * @changing_leb: %1 if the atomic LEB change ioctl command is in progress * @direct_writes: %1 if direct writes are enabled for this volume * + * @checkmap: bitmap to remember which PEB->LEB mappings got checked, + * protected by UBI LEB lock tree. + * * The @corrupted field indicates that the volume's contents is corrupted. * Since UBI protects only static volumes, this field is not relevant to * dynamic volumes - it is user's responsibility to assure their data @@ -377,6 +380,10 @@ struct ubi_volume { unsigned int updating:1; unsigned int changing_leb:1; unsigned int direct_writes:1; + +#ifdef CONFIG_MTD_UBI_FASTMAP + unsigned long *checkmap; +#endif }; /** @@ -965,8 +972,12 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi); int ubi_update_fastmap(struct ubi_device *ubi); int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, struct ubi_attach_info *scan_ai); +int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count); +void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol); #else static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; } +int static inline ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) { return 0; } +static inline void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) {} #endif /* block.c */ diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 3fd8d7ff7a02..0be516780e92 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -139,6 +139,7 @@ static void vol_release(struct device *dev) struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); ubi_eba_replace_table(vol, NULL); + ubi_fastmap_destroy_checkmap(vol); kfree(vol); } diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 263743e7b741..94d7a865b135 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -534,7 +534,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_attach_info *ai, const struct ubi_vtbl_record *vtbl) { - int i, reserved_pebs = 0; + int i, err, reserved_pebs = 0; struct ubi_ainf_volume *av; struct ubi_volume *vol; @@ -620,6 +620,16 @@ static int init_volumes(struct ubi_device *ubi, (long long)(vol->used_ebs - 1) * vol->usable_leb_size; vol->used_bytes += av->last_data_size; vol->last_eb_bytes = av->last_data_size; + + /* + * We use ubi->peb_count and not vol->reserved_pebs because + * we want to keep the code simple. Otherwise we'd have to + * resize/check the bitmap upon volume resize too. + * Allocating a few bytes more does not hurt. + */ + err = ubi_fastmap_init_checkmap(vol, ubi->peb_count); + if (err) + return err; } /* And add the layout volume */ @@ -645,6 +655,9 @@ static int init_volumes(struct ubi_device *ubi, reserved_pebs += vol->reserved_pebs; ubi->vol_count += 1; vol->ubi = ubi; + err = ubi_fastmap_init_checkmap(vol, UBI_LAYOUT_VOLUME_EBS); + if (err) + return err; if (reserved_pebs > ubi->avail_pebs) { ubi_err(ubi, "not enough PEBs, required %d, available %d", @@ -849,6 +862,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai) out_free: vfree(ubi->vtbl); for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { + ubi_fastmap_destroy_checkmap(ubi->volumes[i]); kfree(ubi->volumes[i]); ubi->volumes[i] = NULL; } -- cgit v1.2.3 From 3e5e4335cc0ffd668054564b113fb3c9c97badb8 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 28 May 2018 22:04:34 +0200 Subject: ubi: fastmap: Detect EBA mismatches on-the-fly Now we have the machinery to detect EBA mismatches on-the-fly by comparing the in-memory volume ID and LEB number with the found VID header. This helps to detect malfunction of Fastmap. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/eba.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 1ceab201a27b..edb1c8362faa 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -513,6 +513,7 @@ static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnu { int err; struct ubi_vid_io_buf *vidb; + struct ubi_vid_hdr *vid_hdr; if (!ubi->fast_attach) return 0; @@ -552,6 +553,22 @@ static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnu *pnum, err); goto out_free; + } else { + int found_vol_id, found_lnum; + + ubi_assert(err == 0 || err == UBI_IO_BITFLIPS); + + vid_hdr = ubi_get_vid_hdr(vidb); + found_vol_id = be32_to_cpu(vid_hdr->vol_id); + found_lnum = be32_to_cpu(vid_hdr->lnum); + + if (found_lnum != lnum || found_vol_id != vol->vol_id) { + ubi_err(ubi, "EBA mismatch! PEB %i is LEB %i:%i instead of LEB %i:%i", + *pnum, found_vol_id, found_lnum, vol->vol_id, lnum); + ubi_ro_mode(ubi); + err = -EINVAL; + goto out_free; + } } set_bit(lnum, vol->checkmap); -- cgit v1.2.3 From f5a926dd529870de4bd19199ce7b36985f130d70 Mon Sep 17 00:00:00 2001 From: Lionel Debieve Date: Mon, 4 Jun 2018 15:21:37 +0200 Subject: mtd: ubi: Update ubi-media.h to dual license Update license template using SPDX. Move the global layout of UBI headers to dual license helping UBI to be the standard solution for raw NAND management. Signed-off-by: Lionel Debieve Acked-by: Thomas Gleixner Acked-by: Artem Bityutskiy Acked-by: Paul E. McKenney Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/ubi-media.h | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h index bfceae5a890e..195ff8ca8211 100644 --- a/drivers/mtd/ubi/ubi-media.h +++ b/drivers/mtd/ubi/ubi-media.h @@ -1,28 +1,12 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * Copyright (C) International Business Machines Corp., 2006 * Authors: Artem Bityutskiy (Битюцкий Артём) * Thomas Gleixner * Frank Haverkamp * Oliver Lohmann * Andreas Arnez - */ - -/* + * * This file defines the layout of UBI headers and all the other UBI on-flash * data structures. */ -- cgit v1.2.3