Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754373AbbLKI1h (ORCPT ); Fri, 11 Dec 2015 03:27:37 -0500 Received: from mailout.micron.com ([137.201.242.129]:51369 "EHLO mailout.micron.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753317AbbLKI1g (ORCPT ); Fri, 11 Dec 2015 03:27:36 -0500 From: =?gb2312?B?QmVhbiBIdW8gu/Sx87HzIChiZWFuaHVvKQ==?= To: Artem Bityutskiy , Adrian Hunter , Richard Weinberger , Brian Norris CC: "linux-mtd@lists.infradead.org" , "linux-kernel@vger.kernel.org" , "Boris Brezillon" Subject: [PATCH 1/1] fs:ubifs:recovery:fixup UBIFS cannot recover master node issue Thread-Topic: [PATCH 1/1] fs:ubifs:recovery:fixup UBIFS cannot recover master node issue Thread-Index: AdEz7ROr5GzlYrlhTsKg+356EiZmUQ== Date: Fri, 11 Dec 2015 08:26:53 +0000 Message-ID: Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.167.84.5] X-TM-AS-Product-Ver: SMEX-11.0.0.4179-8.000.1202-21994.005 X-TM-AS-Result: No--1.673000-0.000000-31 X-TM-AS-User-Approved-Sender: Yes X-TM-AS-User-Blocked-Sender: No x-mt-checkinternalsenderrule: True Content-Type: text/plain; charset="gb2312" MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from base64 to 8bit by mail.home.local id tBB8RgiV007865 Content-Length: 4518 Lines: 151 For MLC NAND, paired page issue is now a common known issue. This patch is just for master node cannot be recovered while there will two pages be damaged in one single master node block. As for this patch, if there are more than one page data in master node block being damaged, and as long as exist one uncorrupted master node block, master node will be recovered. This patch has been tested on Micron MLC NAND MT29F32G08CBADAWP. Issue descripted: http://lists.infradead.org/pipermail/linux-mtd/2015-November/063016.html Signed-off-by: Bean Huo --- fs/ubifs/recovery.c | 75 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 695fc71..e3154e6 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -128,7 +128,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf, while (offs + UBIFS_MST_NODE_SZ <= c->leb_size) { struct ubifs_ch *ch = buf; - if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) + if (le32_to_cpu(ch->magic) == 0xFFFFFFFF) break; offs += sz; buf += sz; @@ -137,37 +137,40 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf, /* See if there was a valid master node before that */ if (offs) { int ret; - +retry: offs -= sz; buf -= sz; len += sz; ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); - if (ret != SCANNED_A_NODE && offs) { - /* Could have been corruption so check one place back */ - offs -= sz; - buf -= sz; - len += sz; - ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); - if (ret != SCANNED_A_NODE) - /* - * We accept only one area of corruption because - * we are assuming that it was caused while - * trying to write a master node. - */ - goto out_err; - } - if (ret == SCANNED_A_NODE) { - struct ubifs_ch *ch = buf; - - if (ch->node_type != UBIFS_MST_NODE) + if (ret != SCANNED_A_NODE) { + /* Could have been corruption so check more + * place back. We accept two areas of corruption + * because we are assuming that for MLC NAND,it + * was caused while trying to write a lower + * page, upper page being damaged. + */ + if (offs > 0) + goto retry; + else goto out_err; + } + if (ret == SCANNED_A_NODE) { + struct ubifs_ch *ch = buf; + + if (ch->node_type != UBIFS_MST_NODE) { + if (offs) + goto retry; + else + goto out_err; + } dbg_rcvry("found a master node at %d:%d", lnum, offs); *mst = buf; offs += sz; buf += sz; len -= sz; - } + } } + /* Check for corruption */ if (offs < c->leb_size) { if (!is_empty(buf, min_t(int, len, sz))) { @@ -178,10 +181,6 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf, buf += sz; len -= sz; } - /* Check remaining empty space */ - if (offs < c->leb_size) - if (!is_empty(buf, len)) - goto out_err; *pbuf = sbuf; return 0; @@ -236,7 +235,7 @@ out: int ubifs_recover_master_node(struct ubifs_info *c) { void *buf1 = NULL, *buf2 = NULL, *cor1 = NULL, *cor2 = NULL; - struct ubifs_mst_node *mst1 = NULL, *mst2 = NULL, *mst; + struct ubifs_mst_node *mst1 = NULL, *mst2 = NULL, *mst = NULL; const int sz = c->mst_node_alsz; int err, offs1, offs2; @@ -280,6 +279,28 @@ int ubifs_recover_master_node(struct ubifs_info *c) if (cor1) goto out_err; mst = mst1; + } else if (offs2 + sz != offs1) { + if (le32_to_cpu(mst1->ch.sqnum) > + le32_to_cpu(mst2->ch.sqnum)) { + /* + * 1st LEB written, occurred power + * loss while writing 2nd LEB. + */ + if (cor1) + goto out_err; + mst = mst1; + } else if (le32_to_cpu(mst1->ch.sqnum) < + le32_to_cpu(mst2->ch.sqnum)) { + /* While writing 1st LEB, occurred power loss */ + if (!cor2) { + if (mst2->flags & + cpu_to_le32(UBIFS_MST_DIRTY)) + mst = mst2; + else + goto out_err; + } else + goto out_err; + } } else goto out_err; } else { @@ -305,6 +326,8 @@ int ubifs_recover_master_node(struct ubifs_info *c) mst = mst2; } + if (mst == NULL) + goto out_err; ubifs_msg(c, "recovered master node from LEB %d", (mst == mst1 ? UBIFS_MST_LNUM : UBIFS_MST_LNUM + 1)); -- 1.9.1 ????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?