[PATCH 2/2] ubifs: dbg_check_ltab: Fix wrong lprops table information caused by missing pnode checking

Zhihao Cheng chengzhihao1 at huawei.com
Wed May 29 04:12:19 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 pnode cannot be found in the LPT tree, the pnode is judged
as dirty(See dbg_is_pnode_dirty). So the dirty space could be more than
the actual value when there exists pnode not traversed, 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 1022 LEBs, it has 1012 main LEBs after auto-resizing, the
traversing results in dbg_is_pnode_dirty() are 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 | 1008 1009 1010 1011 | NA

According to implementations in dbg_is_pnode_dirty, the pnodes p253, p254,
p255 are not traversed and they are wrongly judged as dirty, because the
max main LEB number is 1011.

Fix it by traversing pnodes 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 | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index 9a477924c978..52f091593615 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -1509,24 +1509,27 @@ static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs)
  */
 static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs)
 {
-	int i, cnt;
+	struct ubifs_pnode *pnode;
 
-	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, 0);
+	if (IS_ERR(pnode))
+		return PTR_ERR(pnode);
+	while (pnode) {
 		struct ubifs_nbranch *branch;
 
-		cond_resched();
-		pnode = ubifs_pnode_lookup(c, i);
-		if (IS_ERR(pnode))
-			return PTR_ERR(pnode);
 		branch = &pnode->parent->nbranch[pnode->iip];
 		if (branch->lnum != lnum || branch->offs != offs)
-			continue;
+			goto next_pnode;
 		if (test_bit(DIRTY_CNODE, &pnode->flags))
 			return 1;
 		return 0;
+next_pnode:
+		pnode = find_next_pnode(c, pnode);
+		if (IS_ERR(pnode))
+			return PTR_ERR(pnode);
+		cond_resched();
 	}
+
 	return 1;
 }
 
-- 
2.39.2




More information about the linux-mtd mailing list