[PATCH RFC 16/17] ubifs: Enable ubifs_repair in '/sys/kernel/debug/ubifs/repair_fs'

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


Add new interface '/sys/kernel/debug/ubifs/repair_fs' to enable
ubifs repair.

Invoke UBIFS repair by:
echo UBIFS_DEV > /sys/kernel/debug/ubifs/repair_fs, UBIFS_DEV could be:
1. ubiX_Y: X means UBI device number and Y means UBI volume number.
For example: echo "ubi0_0" > /sys/kernel/debug/ubifs/repair_fs
2. /dev/ubiX_Y: X means UBI device number and Y means UBI volume number.
For example: echo "/dev/ubi0_0" > /sys/kernel/debug/ubifs/repair_fs
3. ubiX:NAME: X means UBI device number and NAME means UBI volume name.
For example: echo "ubi0:userdata" > /sys/kernel/debug/ubifs/repair_fs

Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
---
fs/ubifs/debug.c | 33 +++++++++++++++++++++++++++++++++
fs/ubifs/repair.h | 2 ++
2 files changed, 35 insertions(+)

diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 1fe180c22b96..e8d6e948c32c 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -22,6 +22,7 @@
#include <linux/random.h>
#include <linux/ctype.h>
#include "ubifs.h"
+#include "repair.h"

static DEFINE_SPINLOCK(dbg_lock);

@@ -2868,6 +2869,7 @@ static struct dentry *dfs_chk_orph;
static struct dentry *dfs_chk_lprops;
static struct dentry *dfs_chk_fs;
static struct dentry *dfs_tst_rcvry;
+static struct dentry *dfs_repair_fs;

static ssize_t dfs_global_file_read(struct file *file, char __user *u,
size_t count, loff_t *ppos)
@@ -2899,6 +2901,33 @@ static ssize_t dfs_global_file_write(struct file *file, const char __user *u,
struct dentry *dent = file->f_path.dentry;
int val;

+ if (dent == dfs_repair_fs) {
+ int ret, i;
+ size_t buf_size;
+ char *dev_name;
+
+ dev_name = vmalloc(PAGE_SIZE);
+ if (!dev_name)
+ return -ENOMEM;
+
+ buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+ if (copy_from_user(dev_name, u, buf_size)) {
+ vfree(dev_name);
+ return -EFAULT;
+ }
+
+ /* Filter '\n' */
+ for (i = 0; i < buf_size; ++i)
+ if (dev_name[i] == '\n' || dev_name[i] == '\0')
+ break;
+ dev_name[i] = '\0';
+
+ ret = ubifs_repair(dev_name);
+ vfree(dev_name);
+
+ return ret < 0 ? ret : count;
+ }
+
val = interpret_user_input(u, count);
if (val < 0)
return val;
@@ -2965,6 +2994,10 @@ void dbg_debugfs_init(void)
fname = "tst_recovery";
dfs_tst_rcvry = debugfs_create_file(fname, S_IRUSR | S_IWUSR,
dfs_rootdir, NULL, &dfs_global_fops);
+
+ fname = "repair_fs";
+ dfs_repair_fs = debugfs_create_file(fname, S_IWUSR, dfs_rootdir,
+ NULL, &dfs_global_fops);
}

/**
diff --git a/fs/ubifs/repair.h b/fs/ubifs/repair.h
index f8d18f07e324..3dcf94787cbe 100644
--- a/fs/ubifs/repair.h
+++ b/fs/ubifs/repair.h
@@ -171,4 +171,6 @@ struct ubifs_repair_info {
bool need_update_lpt;
};

+int ubifs_repair(const char *dev_name);
+
#endif /* !__UBIFS_REPAIR_H__ */
--
2.31.1