Received: by 2002:a05:6358:7058:b0:131:369:b2a3 with SMTP id 24csp6562615rwp; Tue, 18 Jul 2023 02:17:30 -0700 (PDT) X-Google-Smtp-Source: APBJJlEw/8osJ4niORogqWPYcjAf8/8+dj3A9y6/Y4fIh8JNWOnojGEY58c8Gtzt7ebb2gTWrn3X X-Received: by 2002:a17:906:8a61:b0:98e:2423:708 with SMTP id hy1-20020a1709068a6100b0098e24230708mr1232368ejc.62.1689671849700; Tue, 18 Jul 2023 02:17:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689671849; cv=none; d=google.com; s=arc-20160816; b=Q0kxNetT4ovydCI/IRw1WD4kBIgTaGs32cGymCgU5KWULTdzCfY5dyyLwcAslHRqRv fy6qKhEOo3KsMQd9G1BB9hAQHWxi+R689jmswZ3KPVOKOtKzm9WNWilwTfCBkxJfiI/Q xhpzsk9stFL2hGySoiS6r2TNFsizC7k9YH6ZE7HUoq8ErixfTTfkWhzRw1ad/Fs8xdR9 lWi5GgC2l0CY9E1rF4Zp+p4gppr2qTgfM9CxOV/nY/LXmnZdRmhNJJDtLf1hSpLguE75 0t7HBmlt6cf5dIXJz2SpOevpJgc+hnvX3THCGI3MSTj9mgc8mUL3IbrzqR5bq3x3vEwW 9DIQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=6yTJ/wGlEPZLPxnnC8jXW7P3km7/RHp5WjSYCx9JVfA=; fh=wVYnlJkdCBQCsPBltOpwRZY1Ob8weyxSizm8alLbX9s=; b=OuzZz1qQNAHyMztu5e9Yb8fUlbE8Ke1hQWGlO6xBwxJiVantA665ZgZRELwLusQgqj BuX13qt4fbCJH43i5XZ4ltJS7nizKc1bV+/istM9uBfuebSnMqXTBSXHxMfnCEeDtZCA s5z7Cl+FVEe3iXHHkufdagPpLOLOy4JmFm5lD2US1M/BnW/3mGSZdcgG81YnTH+GcjSF CaxqDeuNZKEMmSe6hE3/VAL1KfEB25H+fywFy2nHNFN3o+TXbuwflW0qNTyF1+ea3oAJ W9+2uq/u0VwjsOExZJQyXNC14BLkRHuj1xtYYJ4ipRNAT6DDb5dWvfzb7Flyp19bSmdi m9bw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id sb24-20020a170906edd800b00992e14af9b7si902282ejb.460.2023.07.18.02.17.04; Tue, 18 Jul 2023 02:17:29 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232048AbjGRIya (ORCPT + 99 others); Tue, 18 Jul 2023 04:54:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38172 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231928AbjGRIyR (ORCPT ); Tue, 18 Jul 2023 04:54:17 -0400 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 518A8E55 for ; Tue, 18 Jul 2023 01:54:15 -0700 (PDT) Received: from dggpemm500009.china.huawei.com (unknown [172.30.72.57]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4R4t2j1p5VzCrJc; Tue, 18 Jul 2023 16:50:53 +0800 (CST) Received: from huawei.com (10.175.127.227) by dggpemm500009.china.huawei.com (7.185.36.225) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Tue, 18 Jul 2023 16:54:12 +0800 From: ZhaoLong Wang To: , , CC: , , , , Subject: [PATCH V2 1/5] ubi: Use the fault injection framework to enhance the fault injection capability Date: Tue, 18 Jul 2023 16:51:15 +0800 Message-ID: <20230718085119.3885747-2-wangzhaolong1@huawei.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20230718085119.3885747-1-wangzhaolong1@huawei.com> References: <20230718085119.3885747-1-wangzhaolong1@huawei.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7BIT Content-Type: text/plain; charset=US-ASCII X-Originating-IP: [10.175.127.227] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To dggpemm500009.china.huawei.com (7.185.36.225) X-CFilter-Loop: Reflected X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_MED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org To make debug parameters configurable at run time, use the fault injection framework to reconstruct the debugfs interface, and retain the legacy fault injection 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 echo -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 --- V2: - Retain the original interface. - When both the new and original interfaces are enabled, the original interface takes precedence over the new interface. - Adjusted the order of masks to be compatible with original interfaces. drivers/mtd/ubi/Kconfig | 9 +++ drivers/mtd/ubi/debug.c | 68 +++++++++++++++++-- drivers/mtd/ubi/debug.h | 142 +++++++++++++++++++++++++++++++++------- drivers/mtd/ubi/io.c | 10 ++- drivers/mtd/ubi/ubi.h | 15 ++--- 5 files changed, 202 insertions(+), 42 deletions(-) diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index 2ed77b7b3fcb..138fae7e8f96 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -104,4 +104,13 @@ config MTD_UBI_BLOCK 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. + + If in doubt, say "N". endif # MTD_UBI diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 27168f511d6d..9ca584da32c6 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -10,7 +10,23 @@ #include #include #include +#include +#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 /** * ubi_dump_flash - dump a region of flash. @@ -212,6 +228,31 @@ 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 +273,10 @@ int ubi_debugfs_init(void) return err; } +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION + dfs_create_fault_entry(dfs_rootdir); +#endif + return 0; } @@ -272,7 +317,12 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf, 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) { + 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_emulate_power_cut) { snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut); count = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); @@ -287,8 +337,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf, count = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); goto out; - } - else { + } else { count = -EINVAL; goto out; } @@ -330,7 +379,11 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, goto out; } - if (dent == d->dfs_power_cut_min) { + if (dent == d->dfs_emulate_failures) { + if (kstrtouint(buf, 0, &d->emulate_failures) != 0) + count = -EINVAL; + goto out; + } else if (dent == d->dfs_power_cut_min) { if (kstrtouint(buf, 0, &d->power_cut_min) != 0) count = -EINVAL; goto out; @@ -559,6 +612,11 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) 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; } @@ -600,7 +658,5 @@ int ubi_dbg_power_cut(struct ubi_device *ubi, int caller) 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 23676f32b681..fc4234c9a90a 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -53,56 +53,153 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi); void ubi_debugfs_exit_dev(struct ubi_device *ubi); /** - * ubi_dbg_is_bgt_disabled - if the background thread is disabled. + * The following function is a legacy implementation of UBI fault-injection + * hook. When using more powerful fault injection capabilities, the legacy + * fault injection interface should be retained. + */ +int ubi_dbg_power_cut(struct ubi_device *ubi, int caller); + +static inline int ubi_dbg_bitflip(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_bitflips) + return !get_random_u32_below(200); + return 0; +} + +static inline int ubi_dbg_write_failure(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_io_failures) + return !get_random_u32_below(500); + return 0; +} + +static inline int ubi_dbg_erase_failure(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_io_failures) + return !get_random_u32_below(400); + return 0; +} + +/** + * 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 a power cut when writing EC/VID header */ +#define MASK_POWER_CUT_EC (1 << 1) +#define MASK_POWER_CUT_VID (1 << 2) + +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION +/* Emulate bit-flips */ +#define MASK_BITFLIPS (1 << 3) +/* Emulates -EIO during write/erase */ +#define MASK_IO_FAILURE (1 << 4) + +extern bool should_fail_bitflips(void); +extern bool should_fail_io_failures(void); +extern bool should_fail_power_cut(void); + +static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_BITFLIPS) + return should_fail_bitflips(); + return false; +} + +static inline bool ubi_dbg_fail_write(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) + return should_fail_io_failures(); + return false; +} + +static inline bool ubi_dbg_fail_erase(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) + return should_fail_io_failures(); + return false; +} + +static inline bool ubi_dbg_fail_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 */ + +#define ubi_dbg_fail_bitflip(u) false +#define ubi_dbg_fail_write(u) false +#define ubi_dbg_fail_erase(u) false +#define ubi_dbg_fail_power_cut(u,c) false +#endif + +/** + * ubi_dbg_is_power_cut - if it is time to emulate power cut. * @ubi: UBI device description object * - * Returns non-zero if the UBI background thread is disabled for testing - * purposes. + * Returns true if power cut should be emulated, otherwise returns false. */ -static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_power_cut(struct ubi_device *ubi, + unsigned int caller) { - return ubi->dbg.disable_bgt; + if (ubi_dbg_power_cut(ubi, caller)) + return true; + return ubi_dbg_fail_power_cut(ubi, caller); } /** * 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 !get_random_u32_below(200); - return 0; + if (ubi_dbg_bitflip(ubi)) + return true; + return ubi_dbg_fail_bitflip(ubi); } /** * 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 !get_random_u32_below(500); - return 0; + if (ubi_dbg_write_failure(ubi)) + return true;; + return ubi_dbg_fail_write(ubi); } /** * 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_io_failures) - return !get_random_u32_below(400); - return 0; + if (ubi_dbg_erase_failure(ubi)) + return true; + return ubi_dbg_fail_erase(ubi); +} + +/** + * ubi_dbg_is_bgt_disabled - if the background thread is disabled. + * @ubi: UBI device description object + * + * Returns non-zero if the UBI background thread is disabled for testing + * purposes. + */ +static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) +{ + return ubi->dbg.disable_bgt; } static inline int ubi_dbg_chk_io(const struct ubi_device *ubi) @@ -125,5 +222,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 01b644861253..ffa7bbf27bc2 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -821,8 +821,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_is_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; @@ -1071,8 +1074,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_is_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 c8f1bd4fa100..41f57d5717b2 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. @@ -401,6 +390,7 @@ struct ubi_volume_desc { * @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 @@ -412,6 +402,7 @@ struct ubi_volume_desc { * @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; @@ -424,6 +415,7 @@ struct ubi_debug_info { 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; @@ -435,6 +427,7 @@ struct ubi_debug_info { struct dentry *dfs_emulate_power_cut; struct dentry *dfs_power_cut_min; struct dentry *dfs_power_cut_max; + struct dentry *dfs_emulate_failures; }; /** -- 2.31.1