From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from mail.x-arc.co.uk ([217.6.246.34] helo=root.phytec.de) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fuzSh-0005UV-QC for barebox@lists.infradead.org; Wed, 29 Aug 2018 12:20:48 +0000 Received: from idefix.phytec.de (idefix.phytec.de [172.16.0.10]) by root.phytec.de (Postfix) with ESMTP id 1313BA009D5 for ; Wed, 29 Aug 2018 14:20:53 +0200 (CEST) From: Teresa Remmet Date: Wed, 29 Aug 2018 14:19:23 +0200 Message-Id: <1535545212-18871-8-git-send-email-t.remmet@phytec.de> In-Reply-To: <1535545212-18871-1-git-send-email-t.remmet@phytec.de> References: <1535545212-18871-1-git-send-email-t.remmet@phytec.de> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "barebox" Errors-To: barebox-bounces+u.kleine-koenig=pengutronix.de@lists.infradead.org Subject: [PATCH 07/56] UBI: Fix static volume checks when Fastmap is used To: barebox@lists.infradead.org From: Richard Weinberger Ezequiel reported that he's facing UBI going into read-only mode after power cut. It turned out that this behavior happens only when updating a static volume is interrupted and Fastmap is used. A possible trace can look like: ubi0 warning: ubi_io_read_vid_hdr [ubi]: no VID header found at PEB 2323, only 0xFF bytes ubi0 warning: ubi_eba_read_leb [ubi]: switch to read-only mode CPU: 0 PID: 833 Comm: ubiupdatevol Not tainted 4.6.0-rc2-ARCH #4 Hardware name: SAMSUNG ELECTRONICS CO., LTD. 300E4C/300E5C/300E7C/NP300E5C-AD8AR, BIOS P04RAP 10/15/2012 0000000000000286 00000000eba949bd ffff8800c45a7b38 ffffffff8140d841 ffff8801964be000 ffff88018eaa4800 ffff8800c45a7bb8 ffffffffa003abf6 ffffffff850e2ac0 8000000000000163 ffff8801850e2ac0 ffff8801850e2ac0 Call Trace: [] dump_stack+0x63/0x82 [] ubi_eba_read_leb+0x486/0x4a0 [ubi] [] ubi_check_volume+0x83/0xf0 [ubi] [] ubi_open_volume+0x177/0x350 [ubi] [] vol_cdev_open+0x58/0xb0 [ubi] [] chrdev_open+0xae/0x1d0 [] do_dentry_open+0x1ff/0x300 [] ? cdev_put+0x30/0x30 [] vfs_open+0x56/0x60 [] path_openat+0x4f4/0x1190 [] do_filp_open+0x91/0x100 [] ? __alloc_fd+0xc7/0x190 [] do_sys_open+0x13f/0x210 [] SyS_open+0x1e/0x20 [] entry_SYSCALL_64_fastpath+0x1a/0xa4 UBI checks static volumes for data consistency and reads the whole volume upon first open. If the volume is found erroneous users of UBI cannot read from it, but another volume update is possible to fix it. The check is performed by running ubi_eba_read_leb() on every allocated LEB of the volume. For static volumes ubi_eba_read_leb() computes the checksum of all data stored in a LEB. To verify the computed checksum it has to read the LEB's volume header which stores the original checksum. If the volume header is not found UBI treats this as fatal internal error and switches to RO mode. If the UBI device was attached via a full scan the assumption is correct, the volume header has to be present as it had to be there while scanning to get known as mapped. If the attach operation happened via Fastmap the assumption is no longer correct. When attaching via Fastmap UBI learns the mapping table from Fastmap's snapshot of the system state and not via a full scan. It can happen that a LEB got unmapped after a Fastmap was written to the flash. Then UBI can learn the LEB still as mapped and accessing it returns only 0xFF bytes. As UBI is not a FTL it is allowed to have mappings to empty PEBs, it assumes that the layer above takes care of LEB accounting and referencing. UBIFS does so using the LEB property tree (LPT). For static volumes UBI blindly assumes that all LEBs are present and therefore special actions have to be taken. The described situation can happen when updating a static volume is interrupted, either by a user or a power cut. The volume update code first unmaps all LEBs of a volume and then writes LEB by LEB. If the sequence of operations is interrupted UBI detects this either by the absence of LEBs, no volume header present at scan time, or corrupted payload, detected via checksum. In the Fastmap case the former method won't trigger as no scan happened and UBI automatically thinks all LEBs are present. Only by reading data from a LEB it detects that the volume header is missing and incorrectly treats this as fatal error. To deal with the situation ubi_eba_read_leb() from now on checks whether we attached via Fastmap and handles the absence of a volume header like a data corruption error. This way interrupted static volume updates will correctly get detected also when Fastmap is used. Cc: Reported-by: Ezequiel Garcia Tested-by: Ezequiel Garcia Signed-off-by: Richard Weinberger [Fixed conflict] Signed-off-by: Teresa Remmet --- drivers/mtd/ubi/eba.c | 21 +++++++++++++++++++-- drivers/mtd/ubi/fastmap.c | 1 + drivers/mtd/ubi/ubi.h | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index c242c460e849..6e09cfb0a119 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -392,8 +392,25 @@ retry: pnum, vol_id, lnum); err = -EBADMSG; } else { - err = -EINVAL; - ubi_ro_mode(ubi); + /* + * Ending up here in the non-Fastmap case + * is a clear bug as the VID header had to + * be present at scan time to have it referenced. + * With fastmap the story is more complicated. + * Fastmap has the mapping info without the need + * of a full scan. So the LEB could have been + * unmapped, Fastmap cannot know this and keeps + * the LEB referenced. + * This is valid and works as the layer above UBI + * has to do bookkeeping about used/referenced + * LEBs in any case. + */ + if (ubi->fast_attach) { + err = -EBADMSG; + } else { + err = -EINVAL; + ubi_ro_mode(ubi); + } } } goto out_free; diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 2e0fdb7583e4..5bbbd7c6ae2a 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -991,6 +991,7 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ubi_msg(ubi, "fastmap WL pool size: %d", ubi->fm_wl_pool.max_size); ubi->fm_disabled = 0; + ubi->fast_attach = 1; ubi_free_vid_hdr(ubi, vh); kfree(ech); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 1f0ad386b45e..368b829fa17f 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -416,6 +416,7 @@ struct ubi_debug_info { * @fm_size: fastmap size in bytes * @fm_sem: allows ubi_update_fastmap() to block EBA table changes * @fm_work: fastmap work queue + * @fast_attach: non-zero if UBI was attached by fastmap * * @used: RB-tree of used physical eraseblocks * @erroneous: RB-tree of erroneous used physical eraseblocks @@ -515,6 +516,7 @@ struct ubi_device { struct ubi_fm_pool fm_wl_pool; void *fm_buf; size_t fm_size; + int fast_attach; /* Wear-leveling sub-system's stuff */ struct rb_root used; -- 2.7.4 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox