[PATCH 1/2] ubifs: dbg_check_ltab: Fix wrong lprops table information caused by missing nnode loading

Zhihao Cheng chengzhihao1 at huawei.com
Wed May 29 04:12:18 PDT 2024


The lprops table information calculation depends on the scanning results
in LPT area, and the dirty space calculation depends on the dirty state
of each node. If nnode cannot be found in the LPT tree, the nnode is judged
as dirty(See dbg_is_nnode_dirty). So the dirty space could be more than
the actual value when there exists nnode not loaded from disk, for example:
The max_leb_cnt of the UBIFS image is 1024 and the leb_cnt is 300, it could
have 1014 main LEBs at most and DIV_ROUND_UP(main_lebs, UBIFS_LPT_FANOUT) =
254 pnodes at most. Now, the image has 300 LEBs and it is loaded into a
volume with 1018 LEBs, it has 1008 main LEBs after auto-resizing, the
loaded LPT tree is shown as:
                           n1 (lv4, root)
		n4    n5     n6     n7 (lv3)
          n16 n20 n24 n28 ....    n19 n23 n27 n31 (lv2)
   n64 n80 ...                          n79 n95 n111 | n127 (lv1)
p0 p1 ...                                p251 | p252 p253 p254 p255 (lv0)
0,1,2 ...                        1004 1005 1006 1007 | NA

According to the implementations in dbg_check_ltab(), the nnode n127 is not
loaded, because the max main LEB number is 1007, so the biggest pnodes
(p252,p253,p254,p255) and their parent nnode n127 are not read from didk.
Then we get the following error messages from dbg_check_ltab():
 dbg_check_ltab: invalid dirty space in LEB 7 (dirty 384, expected 372)

Fix it by traversing LPT nodes without limiting LEB number under main_lebs.

Fixes: 1e51764a3c2a ("UBIFS: add new flash file system")
Signed-off-by: Zhihao Cheng <chengzhihao1 at huawei.com>
---
 fs/ubifs/lpt_commit.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index 07351fdce722..9a477924c978 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -541,16 +541,15 @@ static int write_cnodes(struct ubifs_info *c)
 }
 
 /**
- * next_pnode_to_dirty - find next pnode to dirty.
+ * find_next_pnode - find next pnode.
  * @c: UBIFS file-system description object
  * @pnode: pnode
  *
- * This function returns the next pnode to dirty or %NULL if there are no more
- * pnodes.  Note that pnodes that have never been written (lnum == 0) are
- * skipped.
+ * This function returns the next pnode or %NULL if there are no more pnodes.
+ * Note that pnodes that have never been written (lnum == 0) are skipped.
  */
-static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
-					       struct ubifs_pnode *pnode)
+static struct ubifs_pnode *find_next_pnode(struct ubifs_info *c,
+					   struct ubifs_pnode *pnode)
 {
 	struct ubifs_nnode *nnode;
 	int iip;
@@ -664,7 +663,7 @@ static int make_tree_dirty(struct ubifs_info *c)
 
 	while (pnode) {
 		do_make_pnode_dirty(c, pnode);
-		pnode = next_pnode_to_dirty(c, pnode);
+		pnode = find_next_pnode(c, pnode);
 		if (IS_ERR(pnode))
 			return PTR_ERR(pnode);
 	}
@@ -1659,17 +1658,18 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
  */
 int dbg_check_ltab(struct ubifs_info *c)
 {
-	int lnum, err, i, cnt;
+	int lnum, err;
+	struct ubifs_pnode *pnode;
 
 	if (!dbg_is_chk_lprops(c))
 		return 0;
 
 	/* Bring the entire tree into memory */
-	cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
-	for (i = 0; i < cnt; i++) {
-		struct ubifs_pnode *pnode;
-
-		pnode = ubifs_pnode_lookup(c, i);
+	pnode = ubifs_pnode_lookup(c, 0);
+	if (IS_ERR(pnode))
+		return PTR_ERR(pnode);
+	while (pnode) {
+		pnode = find_next_pnode(c, pnode);
 		if (IS_ERR(pnode))
 			return PTR_ERR(pnode);
 		cond_resched();
-- 
2.39.2




More information about the linux-mtd mailing list