From: ZhaoLong Wang wangzhaolong1@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I60L5U CVE: NA
-----------------------------------------
To make debug parameters configurable at run time, use the fault injection framework to reconstruct the debugfs interface.
Now, the file emulate_failures and fault_attr files control whether to enable fault emmulation.
The file emulate_failures receives a mask that controls type and process of fault injection. Generally, for ease of use, you can directly enter a mask with all 1s.
echo 0xffff > /sys/kernel/debug/ubi/ubi0/emulate_failures
And you need to configure other fault-injection capabilities for testing purpose:
echo 100 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/probability echo 15 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/space echo 2 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/verbose printf %#x 1 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/times
The CONFIG_MTD_UBI_FAULT_INJECTION to enable the Fault Injection is added to kconfig.
Signed-off-by: ZhaoLong Wang wangzhaolong1@huawei.com Reviewed-by: Zhihao Cheng chengzhihao1@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/mtd/ubi/Kconfig | 7 ++ drivers/mtd/ubi/debug.c | 148 ++++++++++++++++------------------------ drivers/mtd/ubi/debug.h | 91 +++++++++++++++++++----- drivers/mtd/ubi/io.c | 10 ++- drivers/mtd/ubi/ubi.h | 37 ++-------- 5 files changed, 150 insertions(+), 143 deletions(-)
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index 2ed77b7b3fcb..a739c533b66a 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -103,5 +103,12 @@ config MTD_UBI_BLOCK When selected, this feature will be built in the UBI driver.
If in doubt, say "N". +config MTD_UBI_FAULT_INJECTION + bool "Fault injection capability of UBI device" + default n + depends on FAULT_INJECTION_DEBUG_FS + help + this option enable fault-injection support for UBI devices for + testing purposes.
endif # MTD_UBI diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 5a704d598181..24b7775241a8 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -10,6 +10,23 @@ #include <linux/uaccess.h> #include <linux/module.h> #include <linux/seq_file.h> +#include <linux/fault-inject.h> + +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION +static DECLARE_FAULT_ATTR(fault_bitflips_attr); +static DECLARE_FAULT_ATTR(fault_io_failures_attr); +static DECLARE_FAULT_ATTR(fault_power_cut_attr); + +#define FAIL_ACTION(name, fault_attr) \ +bool should_fail_##name(void) \ +{ \ + return should_fail(&fault_attr, 1); \ +} + +FAIL_ACTION(bitflips, fault_bitflips_attr) +FAIL_ACTION(io_failures, fault_io_failures_attr) +FAIL_ACTION(power_cut, fault_power_cut_attr) +#endif
/** @@ -212,6 +229,32 @@ void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req) */ static struct dentry *dfs_rootdir;
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION +static void dfs_create_fault_entry(struct dentry *parent) +{ + struct dentry *dir; + + dir = debugfs_create_dir("fault_inject", parent); + + if (IS_ERR_OR_NULL(dir)) { + int err = dir ? PTR_ERR(dir) : -ENODEV; + + pr_warn("UBI error: cannot create "fault_inject" debugfs directory, error %d\n", + err); + return; + } + + fault_create_debugfs_attr("emulate_bitflips", dir, + &fault_bitflips_attr); + + fault_create_debugfs_attr("emulate_io_failures", dir, + &fault_io_failures_attr); + + fault_create_debugfs_attr("emulate_power_cut", dir, + &fault_power_cut_attr); +} +#endif + /** * ubi_debugfs_init - create UBI debugfs directory. * @@ -232,6 +275,10 @@ int ubi_debugfs_init(void) return err; }
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION + dfs_create_fault_entry(dfs_rootdir); +#endif + return 0; }
@@ -268,27 +315,12 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf, val = d->chk_fastmap; else if (dent == d->dfs_disable_bgt) val = d->disable_bgt; - else if (dent == d->dfs_emulate_bitflips) - val = d->emulate_bitflips; - else if (dent == d->dfs_emulate_io_failures) - val = d->emulate_io_failures; - else if (dent == d->dfs_emulate_power_cut) { - snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut); + else if (dent == d->dfs_emulate_failures) { + snprintf(buf, sizeof(buf), "%u\n", d->emulate_failures); count = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); goto out; - } else if (dent == d->dfs_power_cut_min) { - snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min); - count = simple_read_from_buffer(user_buf, count, ppos, - buf, strlen(buf)); - goto out; - } else if (dent == d->dfs_power_cut_max) { - snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max); - count = simple_read_from_buffer(user_buf, count, ppos, - buf, strlen(buf)); - goto out; - } - else { + } else { count = -EINVAL; goto out; } @@ -330,20 +362,10 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, goto out; }
- if (dent == d->dfs_power_cut_min) { - if (kstrtouint(buf, 0, &d->power_cut_min) != 0) - count = -EINVAL; - goto out; - } else if (dent == d->dfs_power_cut_max) { - if (kstrtouint(buf, 0, &d->power_cut_max) != 0) + if (dent == d->dfs_emulate_failures) { + if (kstrtouint(buf, 0, &d->emulate_failures) != 0) count = -EINVAL; goto out; - } else if (dent == d->dfs_emulate_power_cut) { - if (kstrtoint(buf, 0, &val) != 0) - count = -EINVAL; - else - d->emulate_power_cut = val; - goto out; }
if (buf[0] == '1') @@ -363,10 +385,6 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, d->chk_fastmap = val; else if (dent == d->dfs_disable_bgt) d->disable_bgt = val; - else if (dent == d->dfs_emulate_bitflips) - d->emulate_bitflips = val; - else if (dent == d->dfs_emulate_io_failures) - d->emulate_io_failures = val; else count = -EINVAL;
@@ -386,6 +404,7 @@ static const struct file_operations dfs_fops = { .owner = THIS_MODULE, };
+ /* As long as the position is less then that total number of erase blocks, * we still have more to print. */ @@ -533,32 +552,14 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) d->dfs_dir, (void *)ubi_num, &dfs_fops);
- d->dfs_emulate_bitflips = debugfs_create_file("tst_emulate_bitflips", - mode, d->dfs_dir, - (void *)ubi_num, - &dfs_fops); - - d->dfs_emulate_io_failures = debugfs_create_file("tst_emulate_io_failures", - mode, d->dfs_dir, - (void *)ubi_num, - &dfs_fops); - - d->dfs_emulate_power_cut = debugfs_create_file("tst_emulate_power_cut", - mode, d->dfs_dir, - (void *)ubi_num, - &dfs_fops); - - d->dfs_power_cut_min = debugfs_create_file("tst_emulate_power_cut_min", - mode, d->dfs_dir, - (void *)ubi_num, &dfs_fops); - - d->dfs_power_cut_max = debugfs_create_file("tst_emulate_power_cut_max", - mode, d->dfs_dir, - (void *)ubi_num, &dfs_fops); - debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir, (void *)ubi_num, &eraseblk_count_fops);
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION + d->dfs_emulate_failures = debugfs_create_file("emulate_failures", mode, + d->dfs_dir, (void *)ubi_num, + &dfs_fops); +#endif return 0; }
@@ -571,36 +572,3 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi) if (IS_ENABLED(CONFIG_DEBUG_FS)) debugfs_remove_recursive(ubi->dbg.dfs_dir); } - -/** - * ubi_dbg_power_cut - emulate a power cut if it is time to do so - * @ubi: UBI device description object - * @caller: Flags set to indicate from where the function is being called - * - * Returns non-zero if a power cut was emulated, zero if not. - */ -int ubi_dbg_power_cut(struct ubi_device *ubi, int caller) -{ - unsigned int range; - - if ((ubi->dbg.emulate_power_cut & caller) == 0) - return 0; - - if (ubi->dbg.power_cut_counter == 0) { - ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min; - - if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) { - range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min; - ubi->dbg.power_cut_counter += prandom_u32() % range; - } - return 0; - } - - ubi->dbg.power_cut_counter--; - if (ubi->dbg.power_cut_counter) - return 0; - - ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX"); - ubi_ro_mode(ubi); - return 1; -} diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 118248a5d7d4..bb0f9b26b5c9 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -8,6 +8,18 @@ #ifndef __UBI_DEBUG_H__ #define __UBI_DEBUG_H__
+/** + * MASK_XXX: Mask for emulate_failures in ubi_debug_info.The mask is used to + * precisely control the type and process of fault injection. + */ +/* Emulate bit-flips */ +#define MASK_BITFLIPS (1 << 0) +/* Emulates -EIO during write/erase */ +#define MASK_IO_FAILURE (1 << 1) +/* Emulate a power cut when writing EC/VID header */ +#define MASK_POWER_CUT_EC (1 << 2) +#define MASK_POWER_CUT_VID (1 << 3) + void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len); void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr); void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr); @@ -64,47 +76,91 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) return ubi->dbg.disable_bgt; }
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION + +extern bool should_fail_bitflips(void); +extern bool should_fail_io_failures(void); +extern bool should_fail_power_cut(void); + /** * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip. * @ubi: UBI device description object * - * Returns non-zero if a bit-flip should be emulated, otherwise returns zero. + * Returns true if a bit-flip should be emulated, otherwise returns false. */ -static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_bitflip(const struct ubi_device *ubi) { - if (ubi->dbg.emulate_bitflips) - return !(prandom_u32() % 200); - return 0; + if (ubi->dbg.emulate_failures & MASK_BITFLIPS) + return should_fail_bitflips(); + return false; }
/** * ubi_dbg_is_write_failure - if it is time to emulate a write failure. * @ubi: UBI device description object * - * Returns non-zero if a write failure should be emulated, otherwise returns - * zero. + * Returns true if a write failure should be emulated, otherwise returns + * false. */ -static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_write_failure(const struct ubi_device *ubi) { - if (ubi->dbg.emulate_io_failures) - return !(prandom_u32() % 500); - return 0; + if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) + return should_fail_io_failures(); + return false; }
/** * ubi_dbg_is_erase_failure - if its time to emulate an erase failure. * @ubi: UBI device description object * - * Returns non-zero if an erase failure should be emulated, otherwise returns - * zero. + * Returns true if an erase failure should be emulated, otherwise returns + * false. */ -static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_erase_failure(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) + return should_fail_io_failures(); + return false; +} + +/** + * ubi_dbg_power_cut - if it is time to emulate power cut. + * @ubi: UBI device description object + * + * Returns true if power cut should be emulated, otherwise returns false. + */ +static inline bool ubi_dbg_power_cut(const struct ubi_device *ubi, + unsigned int caller) +{ + if (ubi->dbg.emulate_failures & caller) + return should_fail_power_cut(); + return false; +} + +#else /* CONFIG_MTD_UBI_FAULT_INJECTION */ + +static inline bool ubi_dbg_is_bitflip(const struct ubi_device *ubi) +{ + return false; +} + +static inline bool ubi_dbg_is_write_failure(const struct ubi_device *ubi) +{ + return false; +} + +static inline bool ubi_dbg_is_erase_failure(const struct ubi_device *ubi) +{ + return false; +} + +static inline bool ubi_dbg_power_cut(const struct ubi_device *ubi, + unsigned int caller) { - if (ubi->dbg.emulate_io_failures) - return !(prandom_u32() % 400); - return 0; + return false; }
+#endif static inline int ubi_dbg_chk_io(const struct ubi_device *ubi) { return ubi->dbg.chk_io; @@ -125,5 +181,4 @@ static inline void ubi_enable_dbg_chk_fastmap(struct ubi_device *ubi) ubi->dbg.chk_fastmap = 1; }
-int ubi_dbg_power_cut(struct ubi_device *ubi, int caller); #endif /* !__UBI_DEBUG_H__ */ diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 14d890b00d2c..51bc4a73eaaf 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -814,8 +814,11 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, if (err) return err;
- if (ubi_dbg_power_cut(ubi, POWER_CUT_EC_WRITE)) + if (ubi_dbg_power_cut(ubi, MASK_POWER_CUT_EC)) { + ubi_warn(ubi, "XXXXX emulating a power cut when writing EC header XXXXX"); + ubi_ro_mode(ubi); return -EROFS; + }
err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize); return err; @@ -1069,8 +1072,11 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, if (err) return err;
- if (ubi_dbg_power_cut(ubi, POWER_CUT_VID_WRITE)) + if (ubi_dbg_power_cut(ubi, MASK_POWER_CUT_VID)) { + ubi_warn(ubi, "XXXXX emulating a power cut when writing VID header XXXXX"); + ubi_ro_mode(ubi); return -EROFS; + }
err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 4f84607dafb4..c8df4ad91534 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -142,17 +142,6 @@ enum { UBI_BAD_FASTMAP, };
-/* - * Flags for emulate_power_cut in ubi_debug_info - * - * POWER_CUT_EC_WRITE: Emulate a power cut when writing an EC header - * POWER_CUT_VID_WRITE: Emulate a power cut when writing a VID header - */ -enum { - POWER_CUT_EC_WRITE = 0x01, - POWER_CUT_VID_WRITE = 0x02, -}; - /** * struct ubi_vid_io_buf - VID buffer used to read/write VID info to/from the * flash. @@ -397,46 +386,28 @@ struct ubi_wl_entry; * @chk_io: if UBI I/O extra checks are enabled * @chk_fastmap: if UBI fastmap extra checks are enabled * @disable_bgt: disable the background task for testing purposes - * @emulate_bitflips: emulate bit-flips for testing purposes - * @emulate_io_failures: emulate write/erase failures for testing purposes - * @emulate_power_cut: emulate power cut for testing purposes - * @power_cut_counter: count down for writes left until emulated power cut - * @power_cut_min: minimum number of writes before emulating a power cut - * @power_cut_max: maximum number of writes until emulating a power cut + * @emulate_failures: emulate failures for testing purposes * @dfs_dir_name: name of debugfs directory containing files of this UBI device * @dfs_dir: direntry object of the UBI device debugfs directory * @dfs_chk_gen: debugfs knob to enable UBI general extra checks * @dfs_chk_io: debugfs knob to enable UBI I/O extra checks * @dfs_chk_fastmap: debugfs knob to enable UBI fastmap extra checks * @dfs_disable_bgt: debugfs knob to disable the background task - * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips - * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures - * @dfs_emulate_power_cut: debugfs knob to emulate power cuts - * @dfs_power_cut_min: debugfs knob for minimum writes before power cut - * @dfs_power_cut_max: debugfs knob for maximum writes until power cut + * @dfs_emulate_failures: debugfs entry to control the fault injection type */ struct ubi_debug_info { unsigned int chk_gen:1; unsigned int chk_io:1; unsigned int chk_fastmap:1; unsigned int disable_bgt:1; - unsigned int emulate_bitflips:1; - unsigned int emulate_io_failures:1; - unsigned int emulate_power_cut:2; - unsigned int power_cut_counter; - unsigned int power_cut_min; - unsigned int power_cut_max; + unsigned int emulate_failures; char dfs_dir_name[UBI_DFS_DIR_LEN + 1]; struct dentry *dfs_dir; struct dentry *dfs_chk_gen; struct dentry *dfs_chk_io; struct dentry *dfs_chk_fastmap; struct dentry *dfs_disable_bgt; - struct dentry *dfs_emulate_bitflips; - struct dentry *dfs_emulate_io_failures; - struct dentry *dfs_emulate_power_cut; - struct dentry *dfs_power_cut_min; - struct dentry *dfs_power_cut_max; + struct dentry *dfs_emulate_failures; };
/**