[PATCH RFC 09/17] ubifs: repair: Re-write data

From: Zhihao Cheng
Date: Wed Dec 27 2023 - 20:39:39 EST


This is the 9/13 step of repairing. Re-write data. Read data from LEB
and write back data, make sure that all LEB is ended with empty
data(0xFF). It will prevent failed gc scanning in next mounting.

Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
---
fs/ubifs/repair.c | 117 ++++++++++++++++++++++++++++++++++++----------
fs/ubifs/repair.h | 11 +++++
2 files changed, 104 insertions(+), 24 deletions(-)

diff --git a/fs/ubifs/repair.c b/fs/ubifs/repair.c
index 7d97de6219fa..59b79481974a 100644
--- a/fs/ubifs/repair.c
+++ b/fs/ubifs/repair.c
@@ -32,6 +32,8 @@ struct scanned_info {

static int init_repair_info(struct ubifs_info *c)
{
+ int err;
+
c->repair = kzalloc(sizeof(struct ubifs_repair_info), GFP_KERNEL);
if (!c->repair)
return -ENOMEM;
@@ -39,15 +41,28 @@ static int init_repair_info(struct ubifs_info *c)
c->repair->scanned_files = RB_ROOT;
c->repair->used_lebs = bitmap_zalloc(c->main_lebs, GFP_KERNEL);
if (!c->repair->used_lebs) {
- kfree(c->repair);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto free_repair;
+ }
+ c->repair->lpts = kzalloc(sizeof(struct lprops) * c->main_lebs,
+ GFP_KERNEL);
+ if (!c->repair->lpts) {
+ err = -ENOMEM;
+ goto free_used_lebs;
}

return 0;
+
+free_used_lebs:
+ bitmap_free(c->repair->used_lebs);
+free_repair:
+ kfree(c->repair);
+ return err;
}

static void destroy_repair_info(struct ubifs_info *c)
{
+ kfree(c->repair->lpts);
bitmap_free(c->repair->used_lebs);
kfree(c->repair);
}
@@ -1026,9 +1041,13 @@ static void remove_del_nodes(struct ubifs_info *c, struct scanned_info *si)

valid_ino_node = lookup_valid_ino_node(c, si, del_ino_node);
if (valid_ino_node) {
- int lnum = del_ino_node->header.lnum;
+ int lnum = del_ino_node->header.lnum - c->main_first;
+ int pos = del_ino_node->header.offs +
+ ALIGN(del_ino_node->header.len, 8);

- set_bit(lnum - c->main_first, c->repair->used_lebs);
+ set_bit(lnum, c->repair->used_lebs);
+ c->repair->lpts[lnum].end =
+ max(c->repair->lpts[lnum].end, pos);
rb_erase(&valid_ino_node->rb, &si->valid_inos);
kfree(valid_ino_node);
}
@@ -1045,9 +1064,13 @@ static void remove_del_nodes(struct ubifs_info *c, struct scanned_info *si)

valid_dent_node = lookup_valid_dent_node(c, si, del_dent_node);
if (valid_dent_node) {
- int lnum = del_dent_node->header.lnum;
+ int lnum = del_dent_node->header.lnum - c->main_first;
+ int pos = del_dent_node->header.offs +
+ ALIGN(del_dent_node->header.len, 8);

- set_bit(lnum - c->main_first, c->repair->used_lebs);
+ set_bit(lnum, c->repair->used_lebs);
+ c->repair->lpts[lnum].end =
+ max(c->repair->lpts[lnum].end, pos);
rb_erase(&valid_dent_node->rb, &si->valid_dents);
kfree(valid_dent_node);
}
@@ -1746,21 +1769,37 @@ static char *get_file_name(struct ubifs_info *c, struct scanned_file *file)
return name;
}

+static void parse_node_location(struct ubifs_info *c, struct scanned_node *sn)
+{
+ int lnum, pos;
+
+ lnum = sn->lnum - c->main_first;
+ pos = sn->offs + ALIGN(sn->len, 8);
+
+ set_bit(lnum, c->repair->used_lebs);
+ c->repair->lpts[lnum].end = max(c->repair->lpts[lnum].end, pos);
+}
+
/**
- * record_used_lebs - record used LEBs.
+ * traverse_files_and_nodes - traverse all nodes from valid files.
* @c: UBIFS file-system description object
*
- * This function records all used LEBs which may hold useful nodes, then left
- * unused LEBs could be taken for storing new index tree.
+ * This function traverses all nodes from valid files and does following
+ * things:
+ * 1. Record all used LEBs which may hold useful nodes, then left unused
+ * LEBs could be taken for storing new index tree.
+ * 2. Re-write data to prevent failed gc scanning in the subsequent mounting
+ * process caused by corrupted data.
*/
-static void record_used_lebs(struct ubifs_info *c)
+static int traverse_files_and_nodes(struct ubifs_info *c)
{
- int lnum;
+ int i, err = 0;
struct rb_node *node, *n;
struct scanned_file *file;
struct scanned_dent_node *dent_node;
struct scanned_data_node *data_node;

+ ubifs_msg(c, "Step 8: Record used LEBs");
for (node = rb_first(&c->repair->scanned_files); node;
node = rb_next(node)) {
cond_resched();
@@ -1772,30 +1811,58 @@ static void record_used_lebs(struct ubifs_info *c)
ubifs_get_type_name(ubifs_get_dent_type(file->ino.mode)),
c->vi.ubi_num, c->vi.vol_id);

- lnum = file->ino.header.lnum;
- set_bit(lnum - c->main_first, c->repair->used_lebs);
+ parse_node_location(c, &file->ino.header);

- if (file->trun.header.exist) {
- lnum = file->trun.header.lnum;
- set_bit(lnum - c->main_first, c->repair->used_lebs);
- }
+ if (file->trun.header.exist)
+ parse_node_location(c, &file->trun.header);

for (n = rb_first(&file->data_nodes); n; n = rb_next(n)) {
cond_resched();
data_node = rb_entry(n, struct scanned_data_node, rb);

- lnum = data_node->header.lnum;
- set_bit(lnum - c->main_first, c->repair->used_lebs);
+ parse_node_location(c, &data_node->header);
}

for (n = rb_first(&file->dent_nodes); n; n = rb_next(n)) {
cond_resched();
dent_node = rb_entry(n, struct scanned_dent_node, rb);

- lnum = dent_node->header.lnum;
- set_bit(lnum - c->main_first, c->repair->used_lebs);
+ parse_node_location(c, &dent_node->header);
}
}
+
+ /* Re-write data. */
+ ubifs_msg(c, "Step 9: Re-write data");
+ for (i = 0; i < c->main_lebs; ++i) {
+ int lnum, len, end;
+
+ if (fatal_signal_pending(current))
+ return -EINTR;
+ cond_resched();
+
+ if (!test_bit(i, c->repair->used_lebs))
+ continue;
+
+ lnum = i + c->main_first;
+ dbg_repair("re-write LEB %d, in ubi%d_%d",
+ lnum, c->vi.ubi_num, c->vi.vol_id);
+
+ end = c->repair->lpts[i].end;
+ len = ALIGN(end, c->min_io_size);
+
+ err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 0);
+ if (err && err != -EBADMSG)
+ return err;
+
+ if (len > end)
+ ubifs_pad(c, c->sbuf + end, len - end);
+
+ err = ubifs_leb_change(c, lnum, c->sbuf, len);
+ if (err)
+ return err;
+ }
+
+ return err;
}

static int do_repair(struct ubifs_info *c)
@@ -1835,9 +1902,11 @@ static int do_repair(struct ubifs_info *c)
if (err)
goto out;

- /* Step 8: Record used LEBs. */
- ubifs_msg(c, "Step 8: Record used LEBs");
- record_used_lebs(c);
+ /*
+ * Step 8: Record used LEBs.
+ * Step 9: Re-write data to clean corrupted data.
+ */
+ err = traverse_files_and_nodes(c);

out:
destroy_scanned_info(c, &si);
diff --git a/fs/ubifs/repair.h b/fs/ubifs/repair.h
index fecf437ff0f7..2ab885fefee0 100644
--- a/fs/ubifs/repair.h
+++ b/fs/ubifs/repair.h
@@ -151,13 +151,24 @@ struct scanned_file {
struct rb_root data_nodes;
};

+
+/**
+ * lprops - logical eraseblock properties.
+ * @end: the end postition of LEB calculated by the last node
+ */
+struct lprops {
+ int end;
+};
+
/**
* ubifs_repair_info - per-FS repairing information.
* @usen_lebs: a bitmap used for recording used lebs
+ * @lpts: lprops table
* @scanned_files: tree of all scanned files
*/
struct ubifs_repair_info {
unsigned long *used_lebs;
+ struct lprops *lpts;
struct rb_root scanned_files;
};

--
2.31.1