#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
-static int fail_task(struct fault_attr *attr, struct task_struct *task)
+static bool fail_task(struct fault_attr *attr, struct task_struct *task)
{
return !in_interrupt() && task->make_it_fail;
}
-#ifdef CONFIG_STACK_UNWIND
-
-static asmlinkage int fail_stacktrace_callback(struct unwind_frame_info *info,
- void *arg)
-{
- int depth;
- struct fault_attr *attr = arg;
- bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
-
- for (depth = 0; depth < attr->stacktrace_depth
- && unwind(info) == 0 && UNW_PC(info); depth++) {
- if (arch_unw_user_mode(info))
- break;
- if (attr->reject_start <= UNW_PC(info) &&
- UNW_PC(info) < attr->reject_end)
- return 0;
- if (attr->require_start <= UNW_PC(info) &&
- UNW_PC(info) < attr->require_end)
- found = 1;
- }
- return found;
-}
-
-static int fail_stacktrace(struct fault_attr *attr)
-{
- struct unwind_frame_info info;
-
- return unwind_init_running(&info, fail_stacktrace_callback, attr);
-}
-
-#elif defined(CONFIG_STACKTRACE)
-
#define MAX_STACK_TRACE_DEPTH 32
-static int fail_stacktrace(struct fault_attr *attr)
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
+
+static bool fail_stacktrace(struct fault_attr *attr)
{
struct stack_trace trace;
int depth = attr->stacktrace_depth;
trace.nr_entries = 0;
trace.entries = entries;
- trace.max_entries = (depth < MAX_STACK_TRACE_DEPTH) ?
- depth : MAX_STACK_TRACE_DEPTH;
+ trace.max_entries = depth;
trace.skip = 1;
- trace.all_contexts = 0;
- save_stack_trace(&trace, NULL);
+ save_stack_trace(&trace);
for (n = 0; n < trace.nr_entries; n++) {
if (attr->reject_start <= entries[n] &&
entries[n] < attr->reject_end)
- return 0;
+ return false;
if (attr->require_start <= entries[n] &&
entries[n] < attr->require_end)
- found = 1;
+ found = true;
}
return found;
}
#else
-static inline int fail_stacktrace(struct fault_attr *attr)
+static inline bool fail_stacktrace(struct fault_attr *attr)
{
- static int firsttime = 1;
-
- if (firsttime) {
- printk(KERN_WARNING
- "This architecture does not implement save_stack_trace()\n");
- firsttime = 0;
- }
- return 0;
+ return true;
}
-#endif
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
/*
* This code is stolen from failmalloc-1.0
* http://www.nongnu.org/failmalloc/
*/
-int should_fail(struct fault_attr *attr, ssize_t size)
+bool should_fail(struct fault_attr *attr, ssize_t size)
{
if (attr->task_filter && !fail_task(attr, current))
- return 0;
-
- if (!fail_stacktrace(attr))
- return 0;
+ return false;
if (atomic_read(&attr->times) == 0)
- return 0;
+ return false;
if (atomic_read(&attr->space) > size) {
atomic_sub(size, &attr->space);
- return 0;
+ return false;
}
if (attr->interval > 1) {
attr->count++;
if (attr->count % attr->interval)
- return 0;
+ return false;
}
- if (attr->probability > random32() % 100)
- goto fail;
+ if (attr->probability <= random32() % 100)
+ return false;
- return 0;
+ if (!fail_stacktrace(attr))
+ return false;
-fail:
fail_dump(attr);
if (atomic_read(&attr->times) != -1)
atomic_dec_not_zero(&attr->times);
- return 1;
+ return true;
}
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
*(unsigned long *)data = val;
}
+static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, u64 val)
+{
+ *(unsigned long *)data =
+ val < MAX_STACK_TRACE_DEPTH ?
+ val : MAX_STACK_TRACE_DEPTH;
+}
+
static u64 debugfs_ul_get(void *data)
{
return *(unsigned long *)data;
return debugfs_create_file(name, mode, parent, value, &fops_ul);
}
+DEFINE_SIMPLE_ATTRIBUTE(fops_ul_MAX_STACK_TRACE_DEPTH, debugfs_ul_get,
+ debugfs_ul_set_MAX_STACK_TRACE_DEPTH, "%llu\n");
+
+static struct dentry *debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
+ const char *name, mode_t mode,
+ struct dentry *parent, unsigned long *value)
+{
+ return debugfs_create_file(name, mode, parent, value,
+ &fops_ul_MAX_STACK_TRACE_DEPTH);
+}
+
static void debugfs_atomic_t_set(void *data, u64 val)
{
atomic_set((atomic_t *)data, val);
debugfs_remove(attr->dentries.task_filter_file);
attr->dentries.task_filter_file = NULL;
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
+
debugfs_remove(attr->dentries.stacktrace_depth_file);
attr->dentries.stacktrace_depth_file = NULL;
debugfs_remove(attr->dentries.reject_end_file);
attr->dentries.reject_end_file = NULL;
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
+
if (attr->dentries.dir)
WARN_ON(!simple_empty(attr->dentries.dir));
attr->dentries.task_filter_file = debugfs_create_bool("task-filter",
mode, dir, &attr->task_filter);
+ if (!attr->dentries.probability_file || !attr->dentries.interval_file ||
+ !attr->dentries.times_file || !attr->dentries.space_file ||
+ !attr->dentries.verbose_file || !attr->dentries.task_filter_file)
+ goto fail;
+
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
+
attr->dentries.stacktrace_depth_file =
- debugfs_create_ul("stacktrace-depth", mode, dir,
- &attr->stacktrace_depth);
+ debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
+ "stacktrace-depth", mode, dir, &attr->stacktrace_depth);
attr->dentries.require_start_file =
debugfs_create_ul("require-start", mode, dir, &attr->require_start);
attr->dentries.reject_end_file =
debugfs_create_ul("reject-end", mode, dir, &attr->reject_end);
-
- if (!attr->dentries.probability_file || !attr->dentries.interval_file
- || !attr->dentries.times_file || !attr->dentries.space_file
- || !attr->dentries.verbose_file || !attr->dentries.task_filter_file
- || !attr->dentries.stacktrace_depth_file
- || !attr->dentries.require_start_file
- || !attr->dentries.require_end_file
- || !attr->dentries.reject_start_file
- || !attr->dentries.reject_end_file
- )
+ if (!attr->dentries.stacktrace_depth_file ||
+ !attr->dentries.require_start_file ||
+ !attr->dentries.require_end_file ||
+ !attr->dentries.reject_start_file ||
+ !attr->dentries.reject_end_file)
goto fail;
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
+
return 0;
fail:
cleanup_fault_attr_dentries(attr);