[PATCH RFC 01/17] ubifs: repair: Load filesystem info from volume

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


This is the 1/13 step of repairing. Open UBI volume and read UBIFS super
block, which is similar to UBIFS mounting process. If read superblock
failed, repair is failure.

Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
---
fs/ubifs/Makefile | 2 +-
fs/ubifs/repair.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++
fs/ubifs/super.c | 10 ++---
fs/ubifs/ubifs.h | 5 +++
4 files changed, 120 insertions(+), 6 deletions(-)
create mode 100644 fs/ubifs/repair.c

diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index 314c80b24a76..88a11f85e150 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -5,7 +5,7 @@ ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o
ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o
-ubifs-y += misc.o sysfs.o
+ubifs-y += misc.o sysfs.o repair.o
ubifs-$(CONFIG_FS_ENCRYPTION) += crypto.o
ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o
ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o
diff --git a/fs/ubifs/repair.c b/fs/ubifs/repair.c
new file mode 100644
index 000000000000..b722187de74f
--- /dev/null
+++ b/fs/ubifs/repair.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2023-2024, Huawei Technologies Co, Ltd.
+ *
+ * Authors: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
+ */
+
+/*
+ * This file implements ubifs repair.
+ */
+
+#include <linux/module.h>
+#include "ubifs.h"
+
+int ubifs_repair(const char *dev_name)
+{
+ int err = 0;
+ struct ubifs_info *c;
+ struct ubi_volume_desc *ubi;
+ struct super_block *fake_sb;
+
+ ubi = open_ubi(dev_name, UBI_READWRITE);
+ if (IS_ERR(ubi)) {
+ err = PTR_ERR(ubi);
+ pr_err("cannot open dev %s, err %d\n", dev_name, err);
+ return err;
+ }
+
+ fake_sb = kzalloc(sizeof(struct super_block), GFP_KERNEL);
+ if (!fake_sb) {
+ err = -ENOMEM;
+ goto close_volume;
+ }
+
+ c = alloc_ubifs_info(ubi);
+ if (!c) {
+ err = -ENOMEM;
+ goto free_sb;
+ }
+
+ c->ubi = ubi;
+ c->vfs_sb = fake_sb;
+ c->max_inode_sz = key_max_inode_size(c);
+ if (c->max_inode_sz > MAX_LFS_FILESIZE)
+ c->max_inode_sz = MAX_LFS_FILESIZE;
+
+ err = init_constants_early(c);
+ if (err)
+ goto free_ubifs;
+
+ err = ubifs_debugging_init(c);
+ if (err)
+ goto free_ubifs;
+
+ if (c->ro_media) {
+ err = -EROFS;
+ goto free_debug;
+ }
+
+ err = check_volume_empty(c);
+ if (err)
+ goto free_debug;
+
+ if (c->empty) {
+ ubifs_err(c, "empty filesystem");
+ err = -ENODEV;
+ goto free_debug;
+ }
+
+ c->sbuf = vmalloc(c->leb_size);
+ if (!c->sbuf) {
+ err = -ENOMEM;
+ goto free_debug;
+ }
+
+ /* Step 1: Load filesystem info from volume. */
+ ubifs_msg(c, "Step 1: Load filesystem");
+ err = ubifs_read_superblock(c);
+ if (err)
+ goto free_sup;
+
+ /* TODO: Support repairing authenticated image. */
+ if (le32_to_cpu(c->sup_node->flags) & UBIFS_FLG_AUTHENTICATION) {
+ ubifs_err(c, "not support authentication");
+ err = -EOPNOTSUPP;
+ goto free_sup;
+ }
+
+ err = init_constants_sb(c);
+ if (err)
+ goto free_sup;
+
+ ubifs_msg(c, "Repair success!");
+
+free_sup:
+ kfree(c->sup_node);
+ vfree(c->sbuf);
+free_debug:
+ ubifs_debugging_exit(c);
+free_ubifs:
+ kfree(c);
+free_sb:
+ kfree(fake_sb);
+close_volume:
+ ubi_close_volume(ubi);
+ return err;
+}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index eabb0f44ea3e..ad726523d491 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -506,7 +506,7 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
* requirements. Returns zero in case of success and a negative error code in
* case of failure.
*/
-static int init_constants_early(struct ubifs_info *c)
+int init_constants_early(struct ubifs_info *c)
{
if (c->vi.corrupted) {
ubifs_warn(c, "UBI volume is corrupted - read-only mode");
@@ -670,7 +670,7 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
* makes sure they are all right. Returns zero in case of success and a
* negative error code in case of failure.
*/
-static int init_constants_sb(struct ubifs_info *c)
+int init_constants_sb(struct ubifs_info *c)
{
int tmp, err;
long long tmp64;
@@ -934,7 +934,7 @@ static void free_buds(struct ubifs_info *c)
* Returns zero in case of success and a negative error code in case of
* failure.
*/
-static int check_volume_empty(struct ubifs_info *c)
+int check_volume_empty(struct ubifs_info *c)
{
int lnum, err;

@@ -2086,7 +2086,7 @@ const struct super_operations ubifs_super_operations = {
* returns UBI volume description object in case of success and a negative
* error code in case of failure.
*/
-static struct ubi_volume_desc *open_ubi(const char *name, int mode)
+struct ubi_volume_desc *open_ubi(const char *name, int mode)
{
struct ubi_volume_desc *ubi;
int dev, vol;
@@ -2132,7 +2132,7 @@ static struct ubi_volume_desc *open_ubi(const char *name, int mode)
return ERR_PTR(-EINVAL);
}

-static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
+struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
{
struct ubifs_info *c;

diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 3916dc4f30ca..a7ee8010ad66 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -2072,6 +2072,11 @@ static inline int ubifs_init_security(struct inode *dentry,

/* super.c */
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
+int init_constants_early(struct ubifs_info *c);
+int init_constants_sb(struct ubifs_info *c);
+int check_volume_empty(struct ubifs_info *c);
+struct ubi_volume_desc *open_ubi(const char *name, int mode);
+struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi);

/* recovery.c */
int ubifs_recover_master_node(struct ubifs_info *c);
--
2.31.1