summaryrefslogtreecommitdiff
path: root/include/linux/dynamic_fault.h
blob: 6322b85838e181e782db851306adc5f32ae8339b (plain)
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
#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 __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