aboutsummaryrefslogtreecommitdiff
path: root/ubifs-utils/fsck.ubifs
diff options
context:
space:
mode:
authorZhihao Cheng <chengzhihao1@huawei.com>2024-11-11 17:01:09 +0800
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2024-11-11 10:32:45 +0100
commita65c63e7252e69984f61b0cf348dbd5a38729ac6 (patch)
treec116ae65efd679933516e8f4728668e246028670 /ubifs-utils/fsck.ubifs
parent022cd74567186eb44478dc371d46427ecfb4380b (diff)
fsck.ubifs: rebuild_fs: Remove deleted nodes from valid node tree
This is the 2/12 step of rebuilding. Traverse nodes from del_inos and del_dents trees, remove inode nodes and dentry nodes with smaller sqnum from valid trees. This step handles deleting case, for example, file A is deleted, deleted inode node and deleted dentry node are written, if we ignore the deleted nodes, file A can be recovered after rebuilding because undeleted inode node and undeleted dentry node can be scanned. There's an exception, if deleted inode node and deleted dentry node are reclaimed(by gc) after deletion, file A is recovered. UBIFS rebuild_fs cannot solve it, because the real existence information of nodes depends on TNC, but TNC should not be depended for UBIFS rebuild_fs. Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'ubifs-utils/fsck.ubifs')
-rw-r--r--ubifs-utils/fsck.ubifs/rebuild_fs.c120
1 files changed, 119 insertions, 1 deletions
diff --git a/ubifs-utils/fsck.ubifs/rebuild_fs.c b/ubifs-utils/fsck.ubifs/rebuild_fs.c
index 3ca9486..dbb0f3b 100644
--- a/ubifs-utils/fsck.ubifs/rebuild_fs.c
+++ b/ubifs-utils/fsck.ubifs/rebuild_fs.c
@@ -364,6 +364,117 @@ out:
return err;
}
+static struct scanned_ino_node *
+lookup_valid_ino_node(struct ubifs_info *c, struct scanned_info *si,
+ struct scanned_ino_node *target)
+{
+ int cmp;
+ struct scanned_ino_node *ino_node;
+ struct rb_node *p;
+
+ p = si->valid_inos.rb_node;
+ while (p) {
+ ino_node = rb_entry(p, struct scanned_ino_node, rb);
+ cmp = keys_cmp(c, &target->key, &ino_node->key);
+ if (cmp < 0) {
+ p = p->rb_left;
+ } else if (cmp > 0) {
+ p = p->rb_right;
+ } else {
+ if (target->header.sqnum > ino_node->header.sqnum)
+ return ino_node;
+ else
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static struct scanned_dent_node *
+lookup_valid_dent_node(struct ubifs_info *c, struct scanned_info *si,
+ struct scanned_dent_node *target)
+{
+ int cmp, nlen;
+ struct scanned_dent_node *dent_node;
+ struct rb_node *p;
+
+ p = si->valid_dents.rb_node;
+ while (p) {
+ dent_node = rb_entry(p, struct scanned_dent_node, rb);
+ cmp = keys_cmp(c, &target->key, &dent_node->key);
+ if (cmp < 0) {
+ p = p->rb_left;
+ } else if (cmp > 0) {
+ p = p->rb_right;
+ } else {
+ nlen = min(target->nlen, dent_node->nlen);
+ cmp = strncmp(target->name, dent_node->name, nlen) ? :
+ target->nlen - dent_node->nlen;
+ if (cmp < 0) {
+ p = p->rb_left;
+ } else if (cmp > 0) {
+ p = p->rb_right;
+ } else {
+ if (target->header.sqnum >
+ dent_node->header.sqnum)
+ return dent_node;
+ else
+ return NULL;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * remove_del_nodes - remove deleted nodes from valid node tree.
+ * @c: UBIFS file-system description object
+ * @si: records nodes and files information during scanning
+ *
+ * This function compares sqnum between deleted node and corresponding valid
+ * node, removes valid node from tree if the sqnum of deleted node is bigger.
+ * Deleted ino/dent nodes will be removed from @si->del_inos/@si->del_dents
+ * after this function finished.
+ */
+static void remove_del_nodes(struct ubifs_info *c, struct scanned_info *si)
+{
+ struct scanned_ino_node *del_ino_node, *valid_ino_node;
+ struct scanned_dent_node *del_dent_node, *valid_dent_node;
+ struct rb_node *this;
+
+ this = rb_first(&si->del_inos);
+ while (this) {
+ del_ino_node = rb_entry(this, struct scanned_ino_node, rb);
+ this = rb_next(this);
+
+ valid_ino_node = lookup_valid_ino_node(c, si, del_ino_node);
+ if (valid_ino_node) {
+ rb_erase(&valid_ino_node->rb, &si->valid_inos);
+ kfree(valid_ino_node);
+ }
+
+ rb_erase(&del_ino_node->rb, &si->del_inos);
+ kfree(del_ino_node);
+ }
+
+ this = rb_first(&si->del_dents);
+ while (this) {
+ del_dent_node = rb_entry(this, struct scanned_dent_node, rb);
+ this = rb_next(this);
+
+ valid_dent_node = lookup_valid_dent_node(c, si, del_dent_node);
+ if (valid_dent_node) {
+ rb_erase(&valid_dent_node->rb, &si->valid_dents);
+ kfree(valid_dent_node);
+ }
+
+ rb_erase(&del_dent_node->rb, &si->del_dents);
+ kfree(del_dent_node);
+ }
+}
+
/**
* ubifs_rebuild_filesystem - Rebuild filesystem.
* @c: UBIFS file-system description object
@@ -389,9 +500,16 @@ int ubifs_rebuild_filesystem(struct ubifs_info *c)
/* Step 1: Scan valid/deleted nodes from volume. */
log_out(c, "Scan nodes");
err = scan_nodes(c, &si);
- if (err)
+ if (err) {
exit_code |= FSCK_ERROR;
+ goto out;
+ }
+
+ /* Step 2: Remove deleted nodes from valid node tree. */
+ log_out(c, "Remove deleted nodes");
+ remove_del_nodes(c, &si);
+out:
destroy_scanned_info(c, &si);
destroy_rebuild_info(c);