0001
0002 #include <linux/kernel.h>
0003 #include <linux/init.h>
0004 #include <linux/random.h>
0005 #include <linux/sched.h>
0006 #include <linux/stat.h>
0007 #include <linux/types.h>
0008 #include <linux/fs.h>
0009 #include <linux/export.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/stacktrace.h>
0012 #include <linux/fault-inject.h>
0013
0014
0015
0016
0017
0018 int setup_fault_attr(struct fault_attr *attr, char *str)
0019 {
0020 unsigned long probability;
0021 unsigned long interval;
0022 int times;
0023 int space;
0024
0025
0026 if (sscanf(str, "%lu,%lu,%d,%d",
0027 &interval, &probability, &space, ×) < 4) {
0028 printk(KERN_WARNING
0029 "FAULT_INJECTION: failed to parse arguments\n");
0030 return 0;
0031 }
0032
0033 attr->probability = probability;
0034 attr->interval = interval;
0035 atomic_set(&attr->times, times);
0036 atomic_set(&attr->space, space);
0037
0038 return 1;
0039 }
0040 EXPORT_SYMBOL_GPL(setup_fault_attr);
0041
0042 static void fail_dump(struct fault_attr *attr)
0043 {
0044 if (attr->no_warn)
0045 return;
0046
0047 if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) {
0048 printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n"
0049 "name %pd, interval %lu, probability %lu, "
0050 "space %d, times %d\n", attr->dname,
0051 attr->interval, attr->probability,
0052 atomic_read(&attr->space),
0053 atomic_read(&attr->times));
0054 if (attr->verbose > 1)
0055 dump_stack();
0056 }
0057 }
0058
0059 #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
0060
0061 static bool fail_task(struct fault_attr *attr, struct task_struct *task)
0062 {
0063 return in_task() && task->make_it_fail;
0064 }
0065
0066 #define MAX_STACK_TRACE_DEPTH 32
0067
0068 #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
0069
0070 static bool fail_stacktrace(struct fault_attr *attr)
0071 {
0072 int depth = attr->stacktrace_depth;
0073 unsigned long entries[MAX_STACK_TRACE_DEPTH];
0074 int n, nr_entries;
0075 bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
0076
0077 if (depth == 0)
0078 return found;
0079
0080 nr_entries = stack_trace_save(entries, depth, 1);
0081 for (n = 0; n < nr_entries; n++) {
0082 if (attr->reject_start <= entries[n] &&
0083 entries[n] < attr->reject_end)
0084 return false;
0085 if (attr->require_start <= entries[n] &&
0086 entries[n] < attr->require_end)
0087 found = true;
0088 }
0089 return found;
0090 }
0091
0092 #else
0093
0094 static inline bool fail_stacktrace(struct fault_attr *attr)
0095 {
0096 return true;
0097 }
0098
0099 #endif
0100
0101
0102
0103
0104
0105
0106 bool should_fail(struct fault_attr *attr, ssize_t size)
0107 {
0108 if (in_task()) {
0109 unsigned int fail_nth = READ_ONCE(current->fail_nth);
0110
0111 if (fail_nth) {
0112 fail_nth--;
0113 WRITE_ONCE(current->fail_nth, fail_nth);
0114 if (!fail_nth)
0115 goto fail;
0116
0117 return false;
0118 }
0119 }
0120
0121
0122 if (attr->probability == 0)
0123 return false;
0124
0125 if (attr->task_filter && !fail_task(attr, current))
0126 return false;
0127
0128 if (atomic_read(&attr->times) == 0)
0129 return false;
0130
0131 if (atomic_read(&attr->space) > size) {
0132 atomic_sub(size, &attr->space);
0133 return false;
0134 }
0135
0136 if (attr->interval > 1) {
0137 attr->count++;
0138 if (attr->count % attr->interval)
0139 return false;
0140 }
0141
0142 if (attr->probability <= prandom_u32() % 100)
0143 return false;
0144
0145 if (!fail_stacktrace(attr))
0146 return false;
0147
0148 fail:
0149 fail_dump(attr);
0150
0151 if (atomic_read(&attr->times) != -1)
0152 atomic_dec_not_zero(&attr->times);
0153
0154 return true;
0155 }
0156 EXPORT_SYMBOL_GPL(should_fail);
0157
0158 #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
0159
0160 static int debugfs_ul_set(void *data, u64 val)
0161 {
0162 *(unsigned long *)data = val;
0163 return 0;
0164 }
0165
0166 static int debugfs_ul_get(void *data, u64 *val)
0167 {
0168 *val = *(unsigned long *)data;
0169 return 0;
0170 }
0171
0172 DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n");
0173
0174 static void debugfs_create_ul(const char *name, umode_t mode,
0175 struct dentry *parent, unsigned long *value)
0176 {
0177 debugfs_create_file(name, mode, parent, value, &fops_ul);
0178 }
0179
0180 #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
0181
0182 static int debugfs_stacktrace_depth_set(void *data, u64 val)
0183 {
0184 *(unsigned long *)data =
0185 min_t(unsigned long, val, MAX_STACK_TRACE_DEPTH);
0186
0187 return 0;
0188 }
0189
0190 DEFINE_SIMPLE_ATTRIBUTE(fops_stacktrace_depth, debugfs_ul_get,
0191 debugfs_stacktrace_depth_set, "%llu\n");
0192
0193 static void debugfs_create_stacktrace_depth(const char *name, umode_t mode,
0194 struct dentry *parent,
0195 unsigned long *value)
0196 {
0197 debugfs_create_file(name, mode, parent, value, &fops_stacktrace_depth);
0198 }
0199
0200 #endif
0201
0202 struct dentry *fault_create_debugfs_attr(const char *name,
0203 struct dentry *parent, struct fault_attr *attr)
0204 {
0205 umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
0206 struct dentry *dir;
0207
0208 dir = debugfs_create_dir(name, parent);
0209 if (IS_ERR(dir))
0210 return dir;
0211
0212 debugfs_create_ul("probability", mode, dir, &attr->probability);
0213 debugfs_create_ul("interval", mode, dir, &attr->interval);
0214 debugfs_create_atomic_t("times", mode, dir, &attr->times);
0215 debugfs_create_atomic_t("space", mode, dir, &attr->space);
0216 debugfs_create_ul("verbose", mode, dir, &attr->verbose);
0217 debugfs_create_u32("verbose_ratelimit_interval_ms", mode, dir,
0218 &attr->ratelimit_state.interval);
0219 debugfs_create_u32("verbose_ratelimit_burst", mode, dir,
0220 &attr->ratelimit_state.burst);
0221 debugfs_create_bool("task-filter", mode, dir, &attr->task_filter);
0222
0223 #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
0224 debugfs_create_stacktrace_depth("stacktrace-depth", mode, dir,
0225 &attr->stacktrace_depth);
0226 debugfs_create_ul("require-start", mode, dir, &attr->require_start);
0227 debugfs_create_ul("require-end", mode, dir, &attr->require_end);
0228 debugfs_create_ul("reject-start", mode, dir, &attr->reject_start);
0229 debugfs_create_ul("reject-end", mode, dir, &attr->reject_end);
0230 #endif
0231
0232 attr->dname = dget(dir);
0233 return dir;
0234 }
0235 EXPORT_SYMBOL_GPL(fault_create_debugfs_attr);
0236
0237 #endif