Skip to content

Commit 663faf9

Browse files
mhiramatAlexei Starovoitov
authored andcommitted
error-injection: Add injectable error types
Add injectable error types for each error-injectable function. One motivation of error injection test is to find software flaws, mistakes or mis-handlings of expectable errors. If we find such flaws by the test, that is a program bug, so we need to fix it. But if the tester miss input the error (e.g. just return success code without processing anything), it causes unexpected behavior even if the caller is correctly programmed to handle any errors. That is not what we want to test by error injection. To clarify what type of errors the caller must expect for each injectable function, this introduces injectable error types: - EI_ETYPE_NULL : means the function will return NULL if it fails. No ERR_PTR, just a NULL. - EI_ETYPE_ERRNO : means the function will return -ERRNO if it fails. - EI_ETYPE_ERRNO_NULL : means the function will return -ERRNO (ERR_PTR) or NULL. ALLOW_ERROR_INJECTION() macro is expanded to get one of NULL, ERRNO, ERRNO_NULL to record the error type for each function. e.g. ALLOW_ERROR_INJECTION(open_ctree, ERRNO) This error types are shown in debugfs as below. ==== / # cat /sys/kernel/debug/error_injection/list open_ctree [btrfs] ERRNO io_ctl_init [btrfs] ERRNO ==== Signed-off-by: Masami Hiramatsu <[email protected]> Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 540adea commit 663faf9

File tree

7 files changed

+66
-15
lines changed

7 files changed

+66
-15
lines changed

fs/btrfs/disk-io.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3124,7 +3124,7 @@ int open_ctree(struct super_block *sb,
31243124
goto fail_block_groups;
31253125
goto retry_root_backup;
31263126
}
3127-
ALLOW_ERROR_INJECTION(open_ctree);
3127+
ALLOW_ERROR_INJECTION(open_ctree, ERRNO);
31283128

31293129
static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
31303130
{

fs/btrfs/free-space-cache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ static int io_ctl_init(struct btrfs_io_ctl *io_ctl, struct inode *inode,
333333

334334
return 0;
335335
}
336-
ALLOW_ERROR_INJECTION(io_ctl_init);
336+
ALLOW_ERROR_INJECTION(io_ctl_init, ERRNO);
337337

338338
static void io_ctl_free(struct btrfs_io_ctl *io_ctl)
339339
{

include/asm-generic/error-injection.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,32 @@
33
#define _ASM_GENERIC_ERROR_INJECTION_H
44

55
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
6+
enum {
7+
EI_ETYPE_NONE, /* Dummy value for undefined case */
8+
EI_ETYPE_NULL, /* Return NULL if failure */
9+
EI_ETYPE_ERRNO, /* Return -ERRNO if failure */
10+
EI_ETYPE_ERRNO_NULL, /* Return -ERRNO or NULL if failure */
11+
};
12+
13+
struct error_injection_entry {
14+
unsigned long addr;
15+
int etype;
16+
};
17+
618
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
719
/*
820
* Whitelist ganerating macro. Specify functions which can be
921
* error-injectable using this macro.
1022
*/
11-
#define ALLOW_ERROR_INJECTION(fname) \
12-
static unsigned long __used \
23+
#define ALLOW_ERROR_INJECTION(fname, _etype) \
24+
static struct error_injection_entry __used \
1325
__attribute__((__section__("_error_injection_whitelist"))) \
14-
_eil_addr_##fname = (unsigned long)fname;
26+
_eil_addr_##fname = { \
27+
.addr = (unsigned long)fname, \
28+
.etype = EI_ETYPE_##_etype, \
29+
};
1530
#else
16-
#define ALLOW_ERROR_INJECTION(fname)
31+
#define ALLOW_ERROR_INJECTION(fname, _etype)
1732
#endif
1833
#endif
1934

include/asm-generic/vmlinux.lds.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
#endif
138138

139139
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
140-
#define ERROR_INJECT_WHITELIST() . = ALIGN(8); \
140+
#define ERROR_INJECT_WHITELIST() STRUCT_ALIGN(); \
141141
VMLINUX_SYMBOL(__start_error_injection_whitelist) = .;\
142142
KEEP(*(_error_injection_whitelist)) \
143143
VMLINUX_SYMBOL(__stop_error_injection_whitelist) = .;

include/linux/error-injection.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <asm/error-injection.h>
88

99
extern bool within_error_injection_list(unsigned long addr);
10+
extern int get_injectable_error_type(unsigned long addr);
1011

1112
#else /* !CONFIG_FUNCTION_ERROR_INJECTION */
1213

@@ -16,6 +17,11 @@ static inline bool within_error_injection_list(unsigned long addr)
1617
return false;
1718
}
1819

20+
static inline int get_injectable_error_type(unsigned long addr)
21+
{
22+
return EI_ETYPE_NONE;
23+
}
24+
1925
#endif
2026

2127
#endif /* _LINUX_ERROR_INJECTION_H */

include/linux/module.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/jump_label.h>
2020
#include <linux/export.h>
2121
#include <linux/rbtree_latch.h>
22+
#include <linux/error-injection.h>
2223

2324
#include <linux/percpu.h>
2425
#include <asm/module.h>
@@ -477,8 +478,8 @@ struct module {
477478
#endif
478479

479480
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
481+
struct error_injection_entry *ei_funcs;
480482
unsigned int num_ei_funcs;
481-
unsigned long *ei_funcs;
482483
#endif
483484
} ____cacheline_aligned __randomize_layout;
484485
#ifndef MODULE_ARCH_INIT

lib/error-inject.c

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct ei_entry {
1616
struct list_head list;
1717
unsigned long start_addr;
1818
unsigned long end_addr;
19+
int etype;
1920
void *priv;
2021
};
2122

@@ -35,23 +36,35 @@ bool within_error_injection_list(unsigned long addr)
3536
return ret;
3637
}
3738

39+
int get_injectable_error_type(unsigned long addr)
40+
{
41+
struct ei_entry *ent;
42+
43+
list_for_each_entry(ent, &error_injection_list, list) {
44+
if (addr >= ent->start_addr && addr < ent->end_addr)
45+
return ent->etype;
46+
}
47+
return EI_ETYPE_NONE;
48+
}
49+
3850
/*
3951
* Lookup and populate the error_injection_list.
4052
*
4153
* For safety reasons we only allow certain functions to be overridden with
4254
* bpf_error_injection, so we need to populate the list of the symbols that have
4355
* been marked as safe for overriding.
4456
*/
45-
static void populate_error_injection_list(unsigned long *start,
46-
unsigned long *end, void *priv)
57+
static void populate_error_injection_list(struct error_injection_entry *start,
58+
struct error_injection_entry *end,
59+
void *priv)
4760
{
48-
unsigned long *iter;
61+
struct error_injection_entry *iter;
4962
struct ei_entry *ent;
5063
unsigned long entry, offset = 0, size = 0;
5164

5265
mutex_lock(&ei_mutex);
5366
for (iter = start; iter < end; iter++) {
54-
entry = arch_deref_entry_point((void *)*iter);
67+
entry = arch_deref_entry_point((void *)iter->addr);
5568

5669
if (!kernel_text_address(entry) ||
5770
!kallsyms_lookup_size_offset(entry, &size, &offset)) {
@@ -65,6 +78,7 @@ static void populate_error_injection_list(unsigned long *start,
6578
break;
6679
ent->start_addr = entry;
6780
ent->end_addr = entry + size;
81+
ent->etype = iter->etype;
6882
ent->priv = priv;
6983
INIT_LIST_HEAD(&ent->list);
7084
list_add_tail(&ent->list, &error_injection_list);
@@ -73,8 +87,8 @@ static void populate_error_injection_list(unsigned long *start,
7387
}
7488

7589
/* Markers of the _error_inject_whitelist section */
76-
extern unsigned long __start_error_injection_whitelist[];
77-
extern unsigned long __stop_error_injection_whitelist[];
90+
extern struct error_injection_entry __start_error_injection_whitelist[];
91+
extern struct error_injection_entry __stop_error_injection_whitelist[];
7892

7993
static void __init populate_kernel_ei_list(void)
8094
{
@@ -157,11 +171,26 @@ static void *ei_seq_next(struct seq_file *m, void *v, loff_t *pos)
157171
return seq_list_next(v, &error_injection_list, pos);
158172
}
159173

174+
static const char *error_type_string(int etype)
175+
{
176+
switch (etype) {
177+
case EI_ETYPE_NULL:
178+
return "NULL";
179+
case EI_ETYPE_ERRNO:
180+
return "ERRNO";
181+
case EI_ETYPE_ERRNO_NULL:
182+
return "ERRNO_NULL";
183+
default:
184+
return "(unknown)";
185+
}
186+
}
187+
160188
static int ei_seq_show(struct seq_file *m, void *v)
161189
{
162190
struct ei_entry *ent = list_entry(v, struct ei_entry, list);
163191

164-
seq_printf(m, "%pf\n", (void *)ent->start_addr);
192+
seq_printf(m, "%pf\t%s\n", (void *)ent->start_addr,
193+
error_type_string(ent->etype));
165194
return 0;
166195
}
167196

0 commit comments

Comments
 (0)