Skip to content

Commit 6931fb4

Browse files
ZhaoLong Wangrichardweinberger
authored andcommitted
ubi: Use the fault injection framework to enhance the fault injection capability
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 <wangzhaolong1@huawei.com> Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent 1e02221 commit 6931fb4

5 files changed

Lines changed: 203 additions & 42 deletions

File tree

drivers/mtd/ubi/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,13 @@ config MTD_UBI_BLOCK
104104

105105
If in doubt, say "N".
106106

107+
config MTD_UBI_FAULT_INJECTION
108+
bool "Fault injection capability of UBI device"
109+
default n
110+
depends on FAULT_INJECTION_DEBUG_FS
111+
help
112+
This option enables fault-injection support for UBI devices for
113+
testing purposes.
114+
115+
If in doubt, say "N".
107116
endif # MTD_UBI

drivers/mtd/ubi/debug.c

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,23 @@
1010
#include <linux/uaccess.h>
1111
#include <linux/module.h>
1212
#include <linux/seq_file.h>
13+
#include <linux/fault-inject.h>
1314

15+
#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
16+
static DECLARE_FAULT_ATTR(fault_bitflips_attr);
17+
static DECLARE_FAULT_ATTR(fault_io_failures_attr);
18+
static DECLARE_FAULT_ATTR(fault_power_cut_attr);
19+
20+
#define FAIL_ACTION(name, fault_attr) \
21+
bool should_fail_##name(void) \
22+
{ \
23+
return should_fail(&fault_attr, 1); \
24+
}
25+
26+
FAIL_ACTION(bitflips, fault_bitflips_attr)
27+
FAIL_ACTION(io_failures, fault_io_failures_attr)
28+
FAIL_ACTION(power_cut, fault_power_cut_attr)
29+
#endif
1430

1531
/**
1632
* ubi_dump_flash - dump a region of flash.
@@ -212,6 +228,31 @@ void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
212228
*/
213229
static struct dentry *dfs_rootdir;
214230

231+
#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
232+
static void dfs_create_fault_entry(struct dentry *parent)
233+
{
234+
struct dentry *dir;
235+
236+
dir = debugfs_create_dir("fault_inject", parent);
237+
if (IS_ERR_OR_NULL(dir)) {
238+
int err = dir ? PTR_ERR(dir) : -ENODEV;
239+
240+
pr_warn("UBI error: cannot create \"fault_inject\" debugfs directory, error %d\n",
241+
err);
242+
return;
243+
}
244+
245+
fault_create_debugfs_attr("emulate_bitflips", dir,
246+
&fault_bitflips_attr);
247+
248+
fault_create_debugfs_attr("emulate_io_failures", dir,
249+
&fault_io_failures_attr);
250+
251+
fault_create_debugfs_attr("emulate_power_cut", dir,
252+
&fault_power_cut_attr);
253+
}
254+
#endif
255+
215256
/**
216257
* ubi_debugfs_init - create UBI debugfs directory.
217258
*
@@ -232,6 +273,10 @@ int ubi_debugfs_init(void)
232273
return err;
233274
}
234275

276+
#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
277+
dfs_create_fault_entry(dfs_rootdir);
278+
#endif
279+
235280
return 0;
236281
}
237282

@@ -272,7 +317,12 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
272317
val = d->emulate_bitflips;
273318
else if (dent == d->dfs_emulate_io_failures)
274319
val = d->emulate_io_failures;
275-
else if (dent == d->dfs_emulate_power_cut) {
320+
else if (dent == d->dfs_emulate_failures) {
321+
snprintf(buf, sizeof(buf), "0x%04x\n", d->emulate_failures);
322+
count = simple_read_from_buffer(user_buf, count, ppos,
323+
buf, strlen(buf));
324+
goto out;
325+
} else if (dent == d->dfs_emulate_power_cut) {
276326
snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
277327
count = simple_read_from_buffer(user_buf, count, ppos,
278328
buf, strlen(buf));
@@ -287,8 +337,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
287337
count = simple_read_from_buffer(user_buf, count, ppos,
288338
buf, strlen(buf));
289339
goto out;
290-
}
291-
else {
340+
} else {
292341
count = -EINVAL;
293342
goto out;
294343
}
@@ -330,7 +379,11 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
330379
goto out;
331380
}
332381

333-
if (dent == d->dfs_power_cut_min) {
382+
if (dent == d->dfs_emulate_failures) {
383+
if (kstrtouint(buf, 0, &d->emulate_failures) != 0)
384+
count = -EINVAL;
385+
goto out;
386+
} else if (dent == d->dfs_power_cut_min) {
334387
if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
335388
count = -EINVAL;
336389
goto out;
@@ -559,6 +612,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
559612
debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir,
560613
(void *)ubi_num, &eraseblk_count_fops);
561614

615+
#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
616+
d->dfs_emulate_failures = debugfs_create_file("emulate_failures",
617+
mode, d->dfs_dir,
618+
(void *)ubi_num,
619+
&dfs_fops);
620+
#endif
562621
return 0;
563622
}
564623

@@ -600,7 +659,5 @@ int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
600659
if (ubi->dbg.power_cut_counter)
601660
return 0;
602661

603-
ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
604-
ubi_ro_mode(ubi);
605662
return 1;
606663
}

drivers/mtd/ubi/debug.h

Lines changed: 119 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,56 +53,153 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi);
5353
void ubi_debugfs_exit_dev(struct ubi_device *ubi);
5454

5555
/**
56-
* ubi_dbg_is_bgt_disabled - if the background thread is disabled.
56+
* The following function is a legacy implementation of UBI fault-injection
57+
* hook. When using more powerful fault injection capabilities, the legacy
58+
* fault injection interface should be retained.
59+
*/
60+
int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);
61+
62+
static inline int ubi_dbg_bitflip(const struct ubi_device *ubi)
63+
{
64+
if (ubi->dbg.emulate_bitflips)
65+
return !get_random_u32_below(200);
66+
return 0;
67+
}
68+
69+
static inline int ubi_dbg_write_failure(const struct ubi_device *ubi)
70+
{
71+
if (ubi->dbg.emulate_io_failures)
72+
return !get_random_u32_below(500);
73+
return 0;
74+
}
75+
76+
static inline int ubi_dbg_erase_failure(const struct ubi_device *ubi)
77+
{
78+
if (ubi->dbg.emulate_io_failures)
79+
return !get_random_u32_below(400);
80+
return 0;
81+
}
82+
83+
/**
84+
* MASK_XXX: Mask for emulate_failures in ubi_debug_info.The mask is used to
85+
* precisely control the type and process of fault injection.
86+
*/
87+
/* Emulate a power cut when writing EC/VID header */
88+
#define MASK_POWER_CUT_EC (1 << 0)
89+
#define MASK_POWER_CUT_VID (1 << 1)
90+
91+
#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
92+
/* Emulate bit-flips */
93+
#define MASK_BITFLIPS (1 << 2)
94+
/* Emulates -EIO during write/erase */
95+
#define MASK_IO_FAILURE (1 << 3)
96+
97+
extern bool should_fail_bitflips(void);
98+
extern bool should_fail_io_failures(void);
99+
extern bool should_fail_power_cut(void);
100+
101+
static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi)
102+
{
103+
if (ubi->dbg.emulate_failures & MASK_BITFLIPS)
104+
return should_fail_bitflips();
105+
return false;
106+
}
107+
108+
static inline bool ubi_dbg_fail_write(const struct ubi_device *ubi)
109+
{
110+
if (ubi->dbg.emulate_failures & MASK_IO_FAILURE)
111+
return should_fail_io_failures();
112+
return false;
113+
}
114+
115+
static inline bool ubi_dbg_fail_erase(const struct ubi_device *ubi)
116+
{
117+
if (ubi->dbg.emulate_failures & MASK_IO_FAILURE)
118+
return should_fail_io_failures();
119+
return false;
120+
}
121+
122+
static inline bool ubi_dbg_fail_power_cut(const struct ubi_device *ubi,
123+
unsigned int caller)
124+
{
125+
if (ubi->dbg.emulate_failures & caller)
126+
return should_fail_power_cut();
127+
return false;
128+
}
129+
130+
#else /* CONFIG_MTD_UBI_FAULT_INJECTION */
131+
132+
#define ubi_dbg_fail_bitflip(u) false
133+
#define ubi_dbg_fail_write(u) false
134+
#define ubi_dbg_fail_erase(u) false
135+
#define ubi_dbg_fail_power_cut(u, c) false
136+
#endif
137+
138+
/**
139+
* ubi_dbg_is_power_cut - if it is time to emulate power cut.
57140
* @ubi: UBI device description object
58141
*
59-
* Returns non-zero if the UBI background thread is disabled for testing
60-
* purposes.
142+
* Returns true if power cut should be emulated, otherwise returns false.
61143
*/
62-
static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
144+
static inline bool ubi_dbg_is_power_cut(struct ubi_device *ubi,
145+
unsigned int caller)
63146
{
64-
return ubi->dbg.disable_bgt;
147+
if (ubi_dbg_power_cut(ubi, caller))
148+
return true;
149+
return ubi_dbg_fail_power_cut(ubi, caller);
65150
}
66151

67152
/**
68153
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
69154
* @ubi: UBI device description object
70155
*
71-
* Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
156+
* Returns true if a bit-flip should be emulated, otherwise returns false.
72157
*/
73-
static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
158+
static inline bool ubi_dbg_is_bitflip(const struct ubi_device *ubi)
74159
{
75-
if (ubi->dbg.emulate_bitflips)
76-
return !get_random_u32_below(200);
77-
return 0;
160+
if (ubi_dbg_bitflip(ubi))
161+
return true;
162+
return ubi_dbg_fail_bitflip(ubi);
78163
}
79164

80165
/**
81166
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
82167
* @ubi: UBI device description object
83168
*
84-
* Returns non-zero if a write failure should be emulated, otherwise returns
85-
* zero.
169+
* Returns true if a write failure should be emulated, otherwise returns
170+
* false.
86171
*/
87-
static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
172+
static inline bool ubi_dbg_is_write_failure(const struct ubi_device *ubi)
88173
{
89-
if (ubi->dbg.emulate_io_failures)
90-
return !get_random_u32_below(500);
91-
return 0;
174+
if (ubi_dbg_write_failure(ubi))
175+
return true;
176+
return ubi_dbg_fail_write(ubi);
92177
}
93178

94179
/**
95180
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
96181
* @ubi: UBI device description object
97182
*
98-
* Returns non-zero if an erase failure should be emulated, otherwise returns
99-
* zero.
183+
* Returns true if an erase failure should be emulated, otherwise returns
184+
* false.
100185
*/
101-
static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
186+
static inline bool ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
102187
{
103-
if (ubi->dbg.emulate_io_failures)
104-
return !get_random_u32_below(400);
105-
return 0;
188+
if (ubi_dbg_erase_failure(ubi))
189+
return true;
190+
return ubi_dbg_fail_erase(ubi);
191+
}
192+
193+
/**
194+
* ubi_dbg_is_bgt_disabled - if the background thread is disabled.
195+
* @ubi: UBI device description object
196+
*
197+
* Returns non-zero if the UBI background thread is disabled for testing
198+
* purposes.
199+
*/
200+
static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
201+
{
202+
return ubi->dbg.disable_bgt;
106203
}
107204

108205
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)
125222
ubi->dbg.chk_fastmap = 1;
126223
}
127224

128-
int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);
129225
#endif /* !__UBI_DEBUG_H__ */

drivers/mtd/ubi/io.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,8 +821,11 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
821821
if (err)
822822
return err;
823823

824-
if (ubi_dbg_power_cut(ubi, POWER_CUT_EC_WRITE))
824+
if (ubi_dbg_is_power_cut(ubi, MASK_POWER_CUT_EC)) {
825+
ubi_warn(ubi, "emulating a power cut when writing EC header");
826+
ubi_ro_mode(ubi);
825827
return -EROFS;
828+
}
826829

827830
err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
828831
return err;
@@ -1071,8 +1074,11 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
10711074
if (err)
10721075
return err;
10731076

1074-
if (ubi_dbg_power_cut(ubi, POWER_CUT_VID_WRITE))
1077+
if (ubi_dbg_is_power_cut(ubi, MASK_POWER_CUT_VID)) {
1078+
ubi_warn(ubi, "emulating a power cut when writing VID header");
1079+
ubi_ro_mode(ubi);
10751080
return -EROFS;
1081+
}
10761082

10771083
err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
10781084
ubi->vid_hdr_alsize);

drivers/mtd/ubi/ubi.h

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,6 @@ enum {
145145
UBI_BAD_FASTMAP,
146146
};
147147

148-
/*
149-
* Flags for emulate_power_cut in ubi_debug_info
150-
*
151-
* POWER_CUT_EC_WRITE: Emulate a power cut when writing an EC header
152-
* POWER_CUT_VID_WRITE: Emulate a power cut when writing a VID header
153-
*/
154-
enum {
155-
POWER_CUT_EC_WRITE = 0x01,
156-
POWER_CUT_VID_WRITE = 0x02,
157-
};
158-
159148
/**
160149
* struct ubi_vid_io_buf - VID buffer used to read/write VID info to/from the
161150
* flash.
@@ -404,6 +393,7 @@ struct ubi_volume_desc {
404393
* @power_cut_counter: count down for writes left until emulated power cut
405394
* @power_cut_min: minimum number of writes before emulating a power cut
406395
* @power_cut_max: maximum number of writes until emulating a power cut
396+
* @emulate_failures: emulate failures for testing purposes
407397
* @dfs_dir_name: name of debugfs directory containing files of this UBI device
408398
* @dfs_dir: direntry object of the UBI device debugfs directory
409399
* @dfs_chk_gen: debugfs knob to enable UBI general extra checks
@@ -415,6 +405,7 @@ struct ubi_volume_desc {
415405
* @dfs_emulate_power_cut: debugfs knob to emulate power cuts
416406
* @dfs_power_cut_min: debugfs knob for minimum writes before power cut
417407
* @dfs_power_cut_max: debugfs knob for maximum writes until power cut
408+
* @dfs_emulate_failures: debugfs entry to control the fault injection type
418409
*/
419410
struct ubi_debug_info {
420411
unsigned int chk_gen:1;
@@ -427,6 +418,7 @@ struct ubi_debug_info {
427418
unsigned int power_cut_counter;
428419
unsigned int power_cut_min;
429420
unsigned int power_cut_max;
421+
unsigned int emulate_failures;
430422
char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
431423
struct dentry *dfs_dir;
432424
struct dentry *dfs_chk_gen;
@@ -438,6 +430,7 @@ struct ubi_debug_info {
438430
struct dentry *dfs_emulate_power_cut;
439431
struct dentry *dfs_power_cut_min;
440432
struct dentry *dfs_power_cut_max;
433+
struct dentry *dfs_emulate_failures;
441434
};
442435

443436
/**

0 commit comments

Comments
 (0)