[RFC PATCH mtd-utils 092/110] fsck.ubifs: Check and correct the index size

From: Zhihao Cheng
Date: Fri Jun 07 2024 - 00:47:21 EST


This is the 14/18 step of fsck. Check and correct the index size by
traversing TNC just like dbg_check_idx_size does. This step should
be executed after first committing, because 'c->calc_idx_sz' can be
changed in 'ubifs_tnc_start_commit' and the initial value of
'c->calc_idx_sz' read from disk is untrusted.

Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
---
ubifs-utils/fsck.ubifs/check_space.c | 28 ++++++++++++++++++++++++++++
ubifs-utils/fsck.ubifs/fsck.ubifs.c | 8 ++++++++
ubifs-utils/fsck.ubifs/fsck.ubifs.h | 3 ++-
ubifs-utils/fsck.ubifs/problem.c | 9 +++++++++
4 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/ubifs-utils/fsck.ubifs/check_space.c b/ubifs-utils/fsck.ubifs/check_space.c
index cf4b8d3f..a22e5ae1 100644
--- a/ubifs-utils/fsck.ubifs/check_space.c
+++ b/ubifs-utils/fsck.ubifs/check_space.c
@@ -656,3 +656,31 @@ rebuild:

return err;
}
+
+/**
+ * check_and_correct_index_size - check & correct the index size.
+ * @c: UBIFS file-system description object
+ *
+ * This function checks and corrects the index size by traversing TNC: Returns
+ * zero in case of success, a negative error code in case of failure.
+ */
+int check_and_correct_index_size(struct ubifs_info *c)
+{
+ int err;
+ unsigned long long index_size = 0;
+
+ ubifs_assert(c, c->bi.old_idx_sz == c->calc_idx_sz);
+ err = dbg_walk_index(c, NULL, add_size, &index_size);
+ if (err) {
+ /* All TNC nodes must be accessible. */
+ ubifs_assert(c, !get_failure_reason_callback(c));
+ return err;
+ }
+
+ dbg_fsck("total index size %llu, in %s", index_size, c->dev_name);
+ if (index_size != c->calc_idx_sz &&
+ fix_problem(c, INCORRECT_IDX_SZ, &index_size))
+ c->bi.old_idx_sz = c->calc_idx_sz = index_size;
+
+ return 0;
+}
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
index 66b9c578..d3525e30 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
@@ -512,6 +512,13 @@ static int do_fsck(void)
}

err = commit_fix_modifications(c);
+ if (err) {
+ exit_code |= FSCK_ERROR;
+ goto free_disconnected_files_2;
+ }
+
+ log_out(c, "Check and correct the index size");
+ err = check_and_correct_index_size(c);
if (err)
exit_code |= FSCK_ERROR;

@@ -567,6 +574,7 @@ int main(int argc, char *argv[])
* Step 11: Check whether the TNC is empty
* Step 12: Check and correct the space statistics
* Step 13: Commit problem fixing modifications
+ * Step 14: Check and correct the index size
*/
err = do_fsck();
if (err && FSCK(c)->try_rebuild) {
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
index cc8b71f5..2d17b205 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
@@ -45,7 +45,7 @@ enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED,
XATTR_HAS_WRONG_HOST, FILE_HAS_NO_ENCRYPT, FILE_IS_DISCONNECTED,
FILE_ROOT_HAS_DENT, DENTRY_IS_UNREACHABLE, FILE_IS_INCONSISTENT,
EMPTY_TNC, LPT_CORRUPTED, NNODE_INCORRECT, PNODE_INCORRECT,
- LP_INCORRECT, SPACE_STAT_INCORRECT, LTAB_INCORRECT };
+ LP_INCORRECT, SPACE_STAT_INCORRECT, LTAB_INCORRECT, INCORRECT_IDX_SZ };

enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 };

@@ -380,5 +380,6 @@ int get_free_leb(struct ubifs_info *c);
int build_lpt(struct ubifs_info *c, calculate_lp_callback calculate_lp_cb,
bool free_ltab);
int check_and_correct_space(struct ubifs_info *c);
+int check_and_correct_index_size(struct ubifs_info *c);

#endif
diff --git a/ubifs-utils/fsck.ubifs/problem.c b/ubifs-utils/fsck.ubifs/problem.c
index f987e480..32182c91 100644
--- a/ubifs-utils/fsck.ubifs/problem.c
+++ b/ubifs-utils/fsck.ubifs/problem.c
@@ -67,6 +67,7 @@ static const struct fsck_problem problem_table[] = {
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "Inconsistent properties for LEB"}, // LP_INCORRECT
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "Incorrect space statistics"}, // SPACE_STAT_INCORRECT
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "Inconsistent properties for lprops table"}, // LTAB_INCORRECT
+ {PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "Incorrect index size"}, // INCORRECT_IDX_SZ
};

static const char *get_question(const struct fsck_problem *problem,
@@ -280,6 +281,14 @@ static void print_problem(const struct ubifs_info *c,
ssp->calc_lst->total_dead, ssp->calc_lst->total_dark);
break;
}
+ case INCORRECT_IDX_SZ:
+ {
+ const unsigned long long *calc_sz = (const unsigned long long *)priv;
+
+ log_out(c, "problem: %s, index size is %llu, should be %llu",
+ problem->desc, c->calc_idx_sz, *calc_sz);
+ break;
+ }
default:
log_out(c, "problem: %s", problem->desc);
break;
--
2.13.6