Skip to content

Commit 9c07b3b

Browse files
chaseyugregkh
authored andcommitted
staging: erofs: introduce error injection infrastructure
This patch introduces error injection infrastructure, with it, we can inject error in any kernel exported common functions which erofs used, so that it can force erofs running into error paths, it turns out that tests can cover real rare paths more easily to find bugs. Reviewed-by: Gao Xiang <gaoxiang25@huawei.com> Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d5beb31 commit 9c07b3b

File tree

4 files changed

+103
-1
lines changed

4 files changed

+103
-1
lines changed

drivers/staging/erofs/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,9 @@ config EROFS_FS_USE_VM_MAP_RAM
7171

7272
If you don't know what these are, say N.
7373

74+
config EROFS_FAULT_INJECTION
75+
bool "EROFS fault injection facility"
76+
depends on EROFS_FS
77+
help
78+
Test EROFS to inject faults such as ENOMEM, EIO, and so on.
79+
If unsure, say N.

drivers/staging/erofs/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ static int read_inode(struct inode *inode, void *data)
113113
static int fill_inline_data(struct inode *inode, void *data, unsigned m_pofs)
114114
{
115115
struct erofs_vnode *vi = EROFS_V(inode);
116+
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
116117
int mode = vi->data_mapping_mode;
117118

118119
DBG_BUGON(mode >= EROFS_INODE_LAYOUT_MAX);
@@ -123,7 +124,7 @@ static int fill_inline_data(struct inode *inode, void *data, unsigned m_pofs)
123124

124125
/* fast symlink (following ext4) */
125126
if (S_ISLNK(inode->i_mode) && inode->i_size < PAGE_SIZE) {
126-
char *lnk = kmalloc(inode->i_size + 1, GFP_KERNEL);
127+
char *lnk = erofs_kmalloc(sbi, inode->i_size + 1, GFP_KERNEL);
127128

128129
if (unlikely(lnk == NULL))
129130
return -ENOMEM;

drivers/staging/erofs/internal.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,22 @@
4242
#define DBG_BUGON(...) ((void)0)
4343
#endif
4444

45+
#ifdef CONFIG_EROFS_FAULT_INJECTION
46+
enum {
47+
FAULT_KMALLOC,
48+
FAULT_MAX,
49+
};
50+
51+
extern char *erofs_fault_name[FAULT_MAX];
52+
#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type)))
53+
54+
struct erofs_fault_info {
55+
atomic_t inject_ops;
56+
unsigned int inject_rate;
57+
unsigned int inject_type;
58+
};
59+
#endif
60+
4561
/* EROFS_SUPER_MAGIC_V1 to represent the whole file system */
4662
#define EROFS_SUPER_MAGIC EROFS_SUPER_MAGIC_V1
4763

@@ -70,14 +86,55 @@ struct erofs_sb_info {
7086
char *dev_name;
7187

7288
unsigned int mount_opt;
89+
90+
#ifdef CONFIG_EROFS_FAULT_INJECTION
91+
struct erofs_fault_info fault_info; /* For fault injection */
92+
#endif
7393
};
7494

95+
#ifdef CONFIG_EROFS_FAULT_INJECTION
96+
#define erofs_show_injection_info(type) \
97+
infoln("inject %s in %s of %pS", erofs_fault_name[type], \
98+
__func__, __builtin_return_address(0))
99+
100+
static inline bool time_to_inject(struct erofs_sb_info *sbi, int type)
101+
{
102+
struct erofs_fault_info *ffi = &sbi->fault_info;
103+
104+
if (!ffi->inject_rate)
105+
return false;
106+
107+
if (!IS_FAULT_SET(ffi, type))
108+
return false;
109+
110+
atomic_inc(&ffi->inject_ops);
111+
if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) {
112+
atomic_set(&ffi->inject_ops, 0);
113+
return true;
114+
}
115+
return false;
116+
}
117+
#endif
118+
119+
static inline void *erofs_kmalloc(struct erofs_sb_info *sbi,
120+
size_t size, gfp_t flags)
121+
{
122+
#ifdef CONFIG_EROFS_FAULT_INJECTION
123+
if (time_to_inject(sbi, FAULT_KMALLOC)) {
124+
erofs_show_injection_info(FAULT_KMALLOC);
125+
return NULL;
126+
}
127+
#endif
128+
return kmalloc(size, flags);
129+
}
130+
75131
#define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info)
76132
#define EROFS_I_SB(inode) ((struct erofs_sb_info *)(inode)->i_sb->s_fs_info)
77133

78134
/* Mount flags set via mount options or defaults */
79135
#define EROFS_MOUNT_XATTR_USER 0x00000010
80136
#define EROFS_MOUNT_POSIX_ACL 0x00000020
137+
#define EROFS_MOUNT_FAULT_INJECTION 0x00000040
81138

82139
#define clear_opt(sbi, option) ((sbi)->mount_opt &= ~EROFS_MOUNT_##option)
83140
#define set_opt(sbi, option) ((sbi)->mount_opt |= EROFS_MOUNT_##option)

drivers/staging/erofs/super.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,26 @@ static int superblock_read(struct super_block *sb)
129129
return ret;
130130
}
131131

132+
#ifdef CONFIG_EROFS_FAULT_INJECTION
133+
char *erofs_fault_name[FAULT_MAX] = {
134+
[FAULT_KMALLOC] = "kmalloc",
135+
};
136+
137+
static void erofs_build_fault_attr(struct erofs_sb_info *sbi,
138+
unsigned int rate)
139+
{
140+
struct erofs_fault_info *ffi = &sbi->fault_info;
141+
142+
if (rate) {
143+
atomic_set(&ffi->inject_ops, 0);
144+
ffi->inject_rate = rate;
145+
ffi->inject_type = (1 << FAULT_MAX) - 1;
146+
} else {
147+
memset(ffi, 0, sizeof(struct erofs_fault_info));
148+
}
149+
}
150+
#endif
151+
132152
static void default_options(struct erofs_sb_info *sbi)
133153
{
134154
#ifdef CONFIG_EROFS_FS_XATTR
@@ -145,6 +165,7 @@ enum {
145165
Opt_nouser_xattr,
146166
Opt_acl,
147167
Opt_noacl,
168+
Opt_fault_injection,
148169
Opt_err
149170
};
150171

@@ -153,13 +174,15 @@ static match_table_t erofs_tokens = {
153174
{Opt_nouser_xattr, "nouser_xattr"},
154175
{Opt_acl, "acl"},
155176
{Opt_noacl, "noacl"},
177+
{Opt_fault_injection, "fault_injection=%u"},
156178
{Opt_err, NULL}
157179
};
158180

159181
static int parse_options(struct super_block *sb, char *options)
160182
{
161183
substring_t args[MAX_OPT_ARGS];
162184
char *p;
185+
int arg = 0;
163186

164187
if (!options)
165188
return 0;
@@ -204,6 +227,16 @@ static int parse_options(struct super_block *sb, char *options)
204227
infoln("noacl options not supported");
205228
break;
206229
#endif
230+
case Opt_fault_injection:
231+
if (args->from && match_int(args, &arg))
232+
return -EINVAL;
233+
#ifdef CONFIG_EROFS_FAULT_INJECTION
234+
erofs_build_fault_attr(EROFS_SB(sb), arg);
235+
set_opt(EROFS_SB(sb), FAULT_INJECTION);
236+
#else
237+
infoln("FAULT_INJECTION was not selected");
238+
#endif
239+
break;
207240
default:
208241
errln("Unrecognized mount option \"%s\" "
209242
"or missing value", p);
@@ -452,6 +485,11 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root)
452485
seq_puts(seq, ",acl");
453486
else
454487
seq_puts(seq, ",noacl");
488+
#endif
489+
#ifdef CONFIG_EROFS_FAULT_INJECTION
490+
if (test_opt(sbi, FAULT_INJECTION))
491+
seq_printf(seq, ",fault_injection=%u",
492+
sbi->fault_info.inject_rate);
455493
#endif
456494
return 0;
457495
}

0 commit comments

Comments
 (0)