[PATCH RFC 13/17] ubifs: repair: Build LPT

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


This is the 11/13 step of repairing. All LEBs' properties can be
calculated in previous steps according to all nodes' position, then
construct LPT just like mkfs does, and write TNC on flash.

Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
---
fs/ubifs/repair.c | 113 ++++++++++++++++++++++++++++++++++++++--------
1 file changed, 93 insertions(+), 20 deletions(-)

diff --git a/fs/ubifs/repair.c b/fs/ubifs/repair.c
index 724f58510599..8d40cff26f7a 100644
--- a/fs/ubifs/repair.c
+++ b/fs/ubifs/repair.c
@@ -1059,6 +1059,21 @@ lookup_valid_dent_node(struct ubifs_info *c, struct scanned_info *si,
return NULL;
}

+static void update_lpt(struct ubifs_info *c, struct scanned_node *sn,
+ bool deleted)
+{
+ int lnum = sn->lnum - c->main_first;
+ int 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);
+
+ if (deleted)
+ return;
+
+ c->repair->lpts[lnum].used += ALIGN(sn->len, 8);
+}
+
/**
* remove_del_nodes - remove deleted nodes from valid node tree.
* @c: UBIFS file-system description object
@@ -1083,13 +1098,7 @@ 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 - c->main_first;
- int pos = del_ino_node->header.offs +
- ALIGN(del_ino_node->header.len, 8);
-
- set_bit(lnum, c->repair->used_lebs);
- c->repair->lpts[lnum].end =
- max(c->repair->lpts[lnum].end, pos);
+ update_lpt(c, &del_ino_node->header, true);
rb_erase(&valid_ino_node->rb, &si->valid_inos);
kfree(valid_ino_node);
}
@@ -1106,13 +1115,7 @@ 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 - c->main_first;
- int pos = del_dent_node->header.offs +
- ALIGN(del_dent_node->header.len, 8);
-
- set_bit(lnum, c->repair->used_lebs);
- c->repair->lpts[lnum].end =
- max(c->repair->lpts[lnum].end, pos);
+ update_lpt(c, &del_dent_node->header, true);
rb_erase(&valid_dent_node->rb, &si->valid_dents);
kfree(valid_dent_node);
}
@@ -1861,6 +1864,14 @@ static int flush_write_buf(struct ubifs_info *c)
if (err)
return err;

+ if (c->repair->need_update_lpt) {
+ int lnum = c->repair->head_lnum - c->main_first;
+
+ c->repair->lpts[lnum].free = c->leb_size - len;
+ c->repair->lpts[lnum].dirty = pad;
+ c->repair->lpts[lnum].flags = LPROPS_INDEX;
+ }
+
c->repair->head_lnum = -1;

return 0;
@@ -2001,14 +2012,9 @@ static int parse_node_info(struct ubifs_info *c, struct scanned_node *sn,
union ubifs_key *key, char *name, int name_len,
struct list_head *idx_list, int *idx_cnt)
{
- int lnum, pos;
struct idx_entry *e;

- 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);
+ update_lpt(c, sn, idx_cnt == NULL);

if (idx_cnt == NULL)
/* Skip truncation node. */
@@ -2085,6 +2091,7 @@ static int build_tnc(struct ubifs_info *c, struct list_head *lower_idxs,
return -ENOMEM;

list_sort(c, lower_idxs, cmp_idx);
+ c->repair->need_update_lpt = true;

ubifs_assert(c, lower_cnt != 0);

@@ -2156,6 +2163,7 @@ static int build_tnc(struct ubifs_info *c, struct list_head *lower_idxs,

/* Flush the last index LEB */
err = flush_write_buf(c);
+ c->repair->need_update_lpt = false;

out:
list_for_each_entry_safe(e, tmp_e, lower_idxs, list) {
@@ -2300,6 +2308,65 @@ static int traverse_files_and_nodes(struct ubifs_info *c)
return err;
}

+/**
+ * build_lpt - construct LPT and write it into flash.
+ * @c: UBIFS file-system description object
+ *
+ * This function builds LPT according to @c->repair->lpts and writes LPT
+ * into flash.
+ */
+int build_lpt(struct ubifs_info *c)
+{
+ int i, len, free, dirty, err;
+ u8 hash_lpt[UBIFS_HASH_ARR_SZ];
+
+ /* Set gc lnum. */
+ err = get_free_leb(c);
+ if (err)
+ return err;
+ c->gc_lnum = c->repair->head_lnum;
+ /* GC LEB is empty. */
+ c->lst.empty_lebs = 1;
+
+ /* Update LPT. */
+ for (i = 0; i < c->main_lebs; i++) {
+ cond_resched();
+
+ if (!test_bit(i, c->repair->used_lebs)) {
+ free = c->leb_size;
+ dirty = 0;
+ c->lst.empty_lebs++;
+ } else if (c->repair->lpts[i].flags & LPROPS_INDEX) {
+ free = c->repair->lpts[i].free;
+ dirty = c->repair->lpts[i].dirty;
+ c->lst.idx_lebs += 1;
+ } else {
+ len = ALIGN(c->repair->lpts[i].end, c->min_io_size);
+ free = c->leb_size - len;
+ dirty = len - c->repair->lpts[i].used;
+ }
+
+ c->repair->lpts[i].free = free;
+ c->repair->lpts[i].dirty = dirty;
+ c->lst.total_free += free;
+ c->lst.total_dirty += dirty;
+
+ if (!(c->repair->lpts[i].flags & LPROPS_INDEX)) {
+ int spc;
+
+ spc = free + dirty;
+ if (spc < c->dead_wm)
+ c->lst.total_dead += spc;
+ else
+ c->lst.total_dark += ubifs_calc_dark(c, spc);
+ c->lst.total_used += c->leb_size - spc;
+ }
+ }
+
+ /* Write LPT. */
+ return ubifs_create_lpt(c, c->repair->lpts, c->main_lebs, hash_lpt);
+}
+
static int do_repair(struct ubifs_info *c)
{
int err = 0;
@@ -2343,6 +2410,12 @@ static int do_repair(struct ubifs_info *c)
* Step 10: Build TNC.
*/
err = traverse_files_and_nodes(c);
+ if (err)
+ goto out;
+
+ /* Step 11. Build LPT. */
+ ubifs_msg(c, "Step 11: Build LPT");
+ err = build_lpt(c);

out:
destroy_scanned_info(c, &si);
--
2.31.1