1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#ifndef _DYNAMIC_FAULT_H
#define _DYNAMIC_FAULT_H
#include <linux/bio.h>
#include <linux/jump_label.h>
#include <linux/slab.h>
enum dfault_enabled {
DFAULT_DISABLED,
DFAULT_ENABLED,
DFAULT_ONESHOT,
};
union dfault_state {
struct {
unsigned enabled:2;
unsigned count:30;
};
struct {
unsigned v;
};
};
/*
* An instance of this structure is created in a special
* ELF section at every dynamic fault callsite. At runtime,
* the special section is treated as an array of these.
*/
struct _dfault {
const char *modname;
const char *function;
const char *filename;
const char *class;
const u16 line;
unsigned frequency;
union dfault_state state;
struct static_key enabled;
} __attribute__((aligned(8)));
#ifdef CONFIG_DYNAMIC_FAULT
int dfault_add_module(struct _dfault *tab, unsigned int n, const char *mod);
int dfault_remove_module(char *mod_name);
bool __dynamic_fault_enabled(struct _dfault *);
#define dynamic_fault(_class) \
({ \
static struct _dfault descriptor \
__used __attribute__((section("__faults"), aligned(8))) = { \
.modname = KBUILD_MODNAME, \
.function = __func__, \
.filename = __FILE__, \
.line = __LINE__, \
.class = _class, \
}; \
\
static_key_false(&descriptor.enabled) && \
__dynamic_fault_enabled(&descriptor); \
})
#define memory_fault() dynamic_fault("memory")
#define race_fault() dynamic_fault("race")
#define kmalloc(...) \
(memory_fault() ? NULL : kmalloc(__VA_ARGS__))
#define kzalloc(...) \
(memory_fault() ? NULL : kzalloc(__VA_ARGS__))
#define krealloc(...) \
(memory_fault() ? NULL : krealloc(__VA_ARGS__))
#define mempool_alloc(pool, gfp_mask) \
((!((gfp_mask) & __GFP_WAIT) && memory_fault()) \
? NULL : mempool_alloc(pool, gfp_mask))
#define __get_free_pages(...) \
(memory_fault() ? 0 : __get_free_pages(__VA_ARGS__))
#define alloc_pages_node(...) \
(memory_fault() ? NULL : alloc_pages_node(__VA_ARGS__))
#define alloc_pages_nodemask(...) \
(memory_fault() ? NULL : alloc_pages_nodemask(__VA_ARGS__))
#define bio_alloc_bioset(gfp, ...) \
(!(gfp & __GFP_WAIT) && memory_fault() \
? NULL : bio_alloc_bioset(gfp, __VA_ARGS__))
#define bio_clone(bio, gfp) \
(!(gfp & __GFP_WAIT) && memory_fault() \
? NULL : bio_clone(bio, gfp))
#define bio_clone_bioset(bio, gfp, bs) \
(!(gfp & __GFP_WAIT) && memory_fault() \
? NULL : bio_clone_bioset(bio, gfp, bs))
#define bio_kmalloc(...) \
(memory_fault() ? NULL : bio_kmalloc(__VA_ARGS__))
#define bio_clone_kmalloc(...) \
(memory_fault() ? NULL : bio_clone_kmalloc(__VA_ARGS__))
#define bio_alloc_pages(...) \
(memory_fault() ? -ENOMEM : bio_alloc_pages(__VA_ARGS__))
#define bio_get_user_pages(bio, uaddr, len, write_to_vm) \
bio_get_user_pages(bio, uaddr, \
memory_fault() ? min_t(unsigned long, len, PAGE_SIZE) \
: len, \
write_to_vm)
#else /* CONFIG_DYNAMIC_FAULT */
#define dfault_add_module(tab, n, modname) 0
#define dfault_remove_module(mod) 0
#define dynamic_fault(_class) 0
#define memory_fault() 0
#define race_fault() 0
#endif /* CONFIG_DYNAMIC_FAULT */
#endif
|