[RFC PATCH mtd-utils 081/110] fsck.ubifs: Move common functions and data structures into fsck.ubifs.c

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


This is a preparation for adding TNC checking support. Following data
structures and functions are moved into fsck.ubifs.c:
1. Move 'scanned_files' and 'used_lebs' from rebuild module, make them
resuable for non-rebuild_fs modes.
2. Move function 'handle_error' from load_fs.c, it could be reused in
other steps.
3. Add new function ubifs_tnc_remove_node in libubifs, which could
remove index entry for a node by given position.

Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
---
ubifs-utils/fsck.ubifs/extract_files.c | 2 +-
ubifs-utils/fsck.ubifs/fsck.ubifs.c | 25 +++++++++++++
ubifs-utils/fsck.ubifs/fsck.ubifs.h | 13 ++++---
ubifs-utils/fsck.ubifs/load_fs.c | 27 --------------
ubifs-utils/fsck.ubifs/rebuild_fs.c | 42 +++++++++++-----------
ubifs-utils/libubifs/tnc.c | 64 ++++++++++++++++++++++++++++++++++
ubifs-utils/libubifs/ubifs.h | 2 ++
7 files changed, 122 insertions(+), 53 deletions(-)

diff --git a/ubifs-utils/fsck.ubifs/extract_files.c b/ubifs-utils/fsck.ubifs/extract_files.c
index b8777f6c..c3ab2b76 100644
--- a/ubifs-utils/fsck.ubifs/extract_files.c
+++ b/ubifs-utils/fsck.ubifs/extract_files.c
@@ -1234,7 +1234,7 @@ int check_and_correct_files(struct ubifs_info *c)
int err;
struct rb_node *node;
struct scanned_file *file;
- struct rb_root *tree = &FSCK(c)->rebuild->scanned_files;
+ struct rb_root *tree = &FSCK(c)->scanned_files;

for (node = rb_first(tree); node; node = rb_next(node)) {
file = rb_entry(node, struct scanned_file, rb);
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
index 77013851..471c2cd9 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
@@ -404,6 +404,31 @@ static void destroy_fsck_info(struct ubifs_info *c)
c->dev_name = NULL;
}

+void handle_error(const struct ubifs_info *c, int reason_set)
+{
+ bool handled = false;
+ unsigned int reason = get_failure_reason_callback(c);
+
+ clear_failure_reason_callback(c);
+ if ((reason_set & HAS_DATA_CORRUPTED) && (reason & FR_DATA_CORRUPTED)) {
+ handled = true;
+ reason &= ~FR_DATA_CORRUPTED;
+ if (fix_problem(c, LOG_CORRUPTED, NULL))
+ FSCK(c)->try_rebuild = true;
+ }
+ if ((reason_set & HAS_TNC_CORRUPTED) && (reason & FR_TNC_CORRUPTED)) {
+ ubifs_assert(c, !handled);
+ handled = true;
+ reason &= ~FR_TNC_CORRUPTED;
+ if (fix_problem(c, TNC_CORRUPTED, NULL))
+ FSCK(c)->try_rebuild = true;
+ }
+
+ ubifs_assert(c, reason == 0);
+ if (!handled)
+ exit_code |= FSCK_ERROR;
+}
+
/*
* do_fsck - Check & repair the filesystem.
*/
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
index b98c3f7d..109c3924 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
@@ -40,6 +40,8 @@ enum { NORMAL_MODE = 0, SAFE_MODE, DANGER_MODE0,
enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED,
TNC_CORRUPTED, TNC_DATA_CORRUPTED, ORPHAN_CORRUPTED };

+enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 };
+
struct scanned_file;

/**
@@ -181,18 +183,14 @@ struct scanned_file {

/**
* ubifs_rebuild_info - UBIFS rebuilding information.
- * @used_lebs: a bitmap used for recording used lebs
* @lpts: lprops table
- * @scanned_files: tree of all scanned files
* @write_buf: write buffer for LEB @head_lnum
* @head_lnum: current writing LEB number
* @head_offs: current writing position in LEB @head_lnum
* @need_update_lpt: whether to update lpt while writing index nodes
*/
struct ubifs_rebuild_info {
- unsigned long *used_lebs;
struct ubifs_lprops *lpts;
- struct rb_root scanned_files;
void *write_buf;
int head_lnum;
int head_offs;
@@ -205,6 +203,8 @@ struct ubifs_rebuild_info {
* @failure_reason: reasons for failed operations
* @lpt_status: the status of lpt, could be: %0(OK), %FR_LPT_CORRUPTED or
* %FR_LPT_INCORRECT
+ * @scanned_files: tree of all scanned files
+ * @used_lebs: a bitmap used for recording used lebs
* @try_rebuild: %true means that try to rebuild fs when fsck failed
* @rebuild: rebuilding-related information
*/
@@ -212,6 +212,8 @@ struct ubifs_fsck_info {
int mode;
unsigned int failure_reason;
unsigned int lpt_status;
+ struct rb_root scanned_files;
+ unsigned long *used_lebs;
bool try_rebuild;
struct ubifs_rebuild_info *rebuild;
};
@@ -260,6 +262,9 @@ static inline const char *mode_name(const struct ubifs_info *c)
/* Exit code for fsck program. */
extern int exit_code;

+/* fsck.ubifs.c */
+void handle_error(const struct ubifs_info *c, int reason_set);
+
/* problem.c */
bool fix_problem(const struct ubifs_info *c, int problem_type, const void *priv);

diff --git a/ubifs-utils/fsck.ubifs/load_fs.c b/ubifs-utils/fsck.ubifs/load_fs.c
index 58540543..04208a14 100644
--- a/ubifs-utils/fsck.ubifs/load_fs.c
+++ b/ubifs-utils/fsck.ubifs/load_fs.c
@@ -17,33 +17,6 @@
#include "misc.h"
#include "fsck.ubifs.h"

-enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 };
-
-static void handle_error(const struct ubifs_info *c, int reason_set)
-{
- bool handled = false;
- unsigned int reason = get_failure_reason_callback(c);
-
- clear_failure_reason_callback(c);
- if ((reason_set & HAS_DATA_CORRUPTED) && (reason & FR_DATA_CORRUPTED)) {
- handled = true;
- reason &= ~FR_DATA_CORRUPTED;
- if (fix_problem(c, LOG_CORRUPTED, NULL))
- FSCK(c)->try_rebuild = true;
- }
- if ((reason_set & HAS_TNC_CORRUPTED) && (reason & FR_TNC_CORRUPTED)) {
- ubifs_assert(c, !handled);
- handled = true;
- reason &= ~FR_TNC_CORRUPTED;
- if (fix_problem(c, TNC_CORRUPTED, NULL))
- FSCK(c)->try_rebuild = true;
- }
-
- ubifs_assert(c, reason == 0);
- if (!handled)
- exit_code |= FSCK_ERROR;
-}
-
int ubifs_load_filesystem(struct ubifs_info *c)
{
int err;
diff --git a/ubifs-utils/fsck.ubifs/rebuild_fs.c b/ubifs-utils/fsck.ubifs/rebuild_fs.c
index 382687b3..f190517c 100644
--- a/ubifs-utils/fsck.ubifs/rebuild_fs.c
+++ b/ubifs-utils/fsck.ubifs/rebuild_fs.c
@@ -73,10 +73,10 @@ static int init_rebuild_info(struct ubifs_info *c)
log_err(c, errno, "can not allocate rebuild info");
goto free_sbuf;
}
- FSCK(c)->rebuild->scanned_files = RB_ROOT;
- FSCK(c)->rebuild->used_lebs = kcalloc(BITS_TO_LONGS(c->main_lebs),
- sizeof(unsigned long), GFP_KERNEL);
- if (!FSCK(c)->rebuild->used_lebs) {
+ FSCK(c)->scanned_files = RB_ROOT;
+ FSCK(c)->used_lebs = kcalloc(BITS_TO_LONGS(c->main_lebs),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!FSCK(c)->used_lebs) {
err = -ENOMEM;
log_err(c, errno, "can not allocate bitmap of used lebs");
goto free_rebuild;
@@ -100,7 +100,7 @@ static int init_rebuild_info(struct ubifs_info *c)
free_lpts:
kfree(FSCK(c)->rebuild->lpts);
free_used_lebs:
- kfree(FSCK(c)->rebuild->used_lebs);
+ kfree(FSCK(c)->used_lebs);
free_rebuild:
kfree(FSCK(c)->rebuild);
free_sbuf:
@@ -112,7 +112,7 @@ static void destroy_rebuild_info(struct ubifs_info *c)
{
vfree(FSCK(c)->rebuild->write_buf);
kfree(FSCK(c)->rebuild->lpts);
- kfree(FSCK(c)->rebuild->used_lebs);
+ kfree(FSCK(c)->used_lebs);
kfree(FSCK(c)->rebuild);
vfree(c->sbuf);
}
@@ -313,7 +313,7 @@ static int process_scanned_node(struct ubifs_info *c, int lnum,
return 1;
}

- tree = &FSCK(c)->rebuild->scanned_files;
+ tree = &FSCK(c)->scanned_files;
return insert_or_update_file(c, tree, sn, key_type(c, key), inum);
}

@@ -331,7 +331,7 @@ static void destroy_scanned_info(struct ubifs_info *c, struct scanned_info *si)
struct scanned_dent_node *dent_node;
struct rb_node *this;

- destroy_file_tree(c, &FSCK(c)->rebuild->scanned_files);
+ destroy_file_tree(c, &FSCK(c)->scanned_files);

this = rb_first(&si->valid_inos);
while (this) {
@@ -377,7 +377,7 @@ static void destroy_scanned_info(struct ubifs_info *c, struct scanned_info *si)
*
* This function scans nodes from flash, all ino/dent nodes are split
* into valid tree and deleted tree, all trun/data nodes are collected
- * into file, the file is inserted into @FSCK(c)->rebuild->scanned_files.
+ * into file, the file is inserted into @FSCK(c)->scanned_files.
*/
static int scan_nodes(struct ubifs_info *c, struct scanned_info *si)
{
@@ -495,7 +495,7 @@ static void update_lpt(struct ubifs_info *c, struct scanned_node *sn,
int index = sn->lnum - c->main_first;
int pos = sn->offs + ALIGN(sn->len, 8);

- set_bit(index, FSCK(c)->rebuild->used_lebs);
+ set_bit(index, FSCK(c)->used_lebs);
FSCK(c)->rebuild->lpts[index].end = max_t(int,
FSCK(c)->rebuild->lpts[index].end, pos);

@@ -572,7 +572,7 @@ static int add_valid_nodes_into_file(struct ubifs_info *c,
struct scanned_ino_node *ino_node;
struct scanned_dent_node *dent_node;
struct rb_node *this;
- struct rb_root *tree = &FSCK(c)->rebuild->scanned_files;
+ struct rb_root *tree = &FSCK(c)->scanned_files;

this = rb_first(&si->valid_inos);
while (this) {
@@ -621,7 +621,7 @@ static void filter_invalid_files(struct ubifs_info *c)
{
struct rb_node *node;
struct scanned_file *file;
- struct rb_root *tree = &FSCK(c)->rebuild->scanned_files;
+ struct rb_root *tree = &FSCK(c)->scanned_files;
LIST_HEAD(tmp_list);

/* Add all xattr files into a list. */
@@ -678,7 +678,7 @@ static void extract_dentry_tree(struct ubifs_info *c)
{
struct rb_node *node;
struct scanned_file *file;
- struct rb_root *tree = &FSCK(c)->rebuild->scanned_files;
+ struct rb_root *tree = &FSCK(c)->scanned_files;
LIST_HEAD(unreachable);

for (node = rb_first(tree); node; node = rb_next(node)) {
@@ -731,7 +731,7 @@ static void init_root_ino(struct ubifs_info *c, struct ubifs_ino_node *ino)
}

/**
- * get_free_leb - get a free LEB according to @FSCK(c)->rebuild->used_lebs.
+ * get_free_leb - get a free LEB according to @FSCK(c)->used_lebs.
* @c: UBIFS file-system description object
*
* This function tries to find a free LEB, lnum is returned if found, otherwise
@@ -741,12 +741,12 @@ static int get_free_leb(struct ubifs_info *c)
{
int lnum;

- lnum = find_next_zero_bit(FSCK(c)->rebuild->used_lebs, c->main_lebs, 0);
+ lnum = find_next_zero_bit(FSCK(c)->used_lebs, c->main_lebs, 0);
if (lnum >= c->main_lebs) {
ubifs_err(c, "No space left.");
return -ENOSPC;
}
- set_bit(lnum, FSCK(c)->rebuild->used_lebs);
+ set_bit(lnum, FSCK(c)->used_lebs);
lnum += c->main_first;

return lnum;
@@ -897,8 +897,8 @@ static int create_root(struct ubifs_info *c)
file->calc_xnms = file->ino.xnms = le32_to_cpu(ino->xattr_names);
file->calc_size = file->ino.size = le64_to_cpu(ino->size);

- rb_link_node(&file->rb, NULL, &FSCK(c)->rebuild->scanned_files.rb_node);
- rb_insert_color(&file->rb, &FSCK(c)->rebuild->scanned_files);
+ rb_link_node(&file->rb, NULL, &FSCK(c)->scanned_files.rb_node);
+ rb_insert_color(&file->rb, &FSCK(c)->scanned_files);

out:
kfree(ino);
@@ -1188,7 +1188,7 @@ static int traverse_files_and_nodes(struct ubifs_info *c)
int i, err = 0, idx_cnt = 0;
struct rb_node *node;
struct scanned_file *file;
- struct rb_root *tree = &FSCK(c)->rebuild->scanned_files;
+ struct rb_root *tree = &FSCK(c)->scanned_files;
struct idx_entry *ie, *tmp_ie;
LIST_HEAD(idx_list);

@@ -1214,7 +1214,7 @@ static int traverse_files_and_nodes(struct ubifs_info *c)
for (i = 0; i < c->main_lebs; ++i) {
int lnum, len, end;

- if (!test_bit(i, FSCK(c)->rebuild->used_lebs))
+ if (!test_bit(i, FSCK(c)->used_lebs))
continue;

lnum = i + c->main_first;
@@ -1268,7 +1268,7 @@ static int build_lpt(struct ubifs_info *c)

/* Update LPT. */
for (i = 0; i < c->main_lebs; i++) {
- if (!test_bit(i, FSCK(c)->rebuild->used_lebs) ||
+ if (!test_bit(i, FSCK(c)->used_lebs) ||
c->gc_lnum == i + c->main_first) {
free = c->leb_size;
dirty = 0;
diff --git a/ubifs-utils/libubifs/tnc.c b/ubifs-utils/libubifs/tnc.c
index cd1013d5..92770623 100644
--- a/ubifs-utils/libubifs/tnc.c
+++ b/ubifs-utils/libubifs/tnc.c
@@ -2457,6 +2457,70 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
}

/**
+ * ubifs_tnc_remove_node - remove an index entry of a node by given position.
+ * @c: UBIFS file-system description object
+ * @key: key of node
+ * @lnum: LEB number of node
+ * @offs: node offset
+ *
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_remove_node(struct ubifs_info *c, const union ubifs_key *key,
+ int lnum, int offs)
+{
+ int found, n, err = 0;
+ struct ubifs_znode *znode;
+
+ mutex_lock(&c->tnc_mutex);
+ dbg_tnck(key, "pos %d:%d, key ", lnum, offs);
+ found = lookup_level0_dirty(c, key, &znode, &n);
+ if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+ if (found == 1) {
+ struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+ if (zbr->lnum == lnum && zbr->offs == offs) {
+ err = tnc_delete(c, znode, n);
+ } else if (is_hash_key(c, key)) {
+ found = resolve_collision_directly(c, key, &znode, &n,
+ lnum, offs);
+ if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+
+ if (found) {
+ /* Ensure the znode is dirtied */
+ if (znode->cnext || !ubifs_zn_dirty(znode)) {
+ znode = dirty_cow_bottom_up(c, znode);
+ if (IS_ERR(znode)) {
+ err = PTR_ERR(znode);
+ goto out_unlock;
+ }
+ }
+ err = tnc_delete(c, znode, n);
+ } else {
+ goto not_found;
+ }
+ } else {
+ goto not_found;
+ }
+ } else {
+not_found:
+ /* Impossible, the node has been found before being deleted. */
+ ubifs_assert(c, 0);
+ }
+ if (!err)
+ err = dbg_check_tnc(c, 0);
+
+out_unlock:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
* ubifs_tnc_next_ent - walk directory or extended attribute entries.
* @c: UBIFS file-system description object
* @key: key of last entry
diff --git a/ubifs-utils/libubifs/ubifs.h b/ubifs-utils/libubifs/ubifs.h
index 8a506a8b..03150cdb 100644
--- a/ubifs-utils/libubifs/ubifs.h
+++ b/ubifs-utils/libubifs/ubifs.h
@@ -1661,6 +1661,8 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
union ubifs_key *to_key);
int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
+int ubifs_tnc_remove_node(struct ubifs_info *c, const union ubifs_key *key,
+ int lnum, int offs);
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
union ubifs_key *key,
const struct fscrypt_name *nm);
--
2.13.6