162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <linux/kernel.h>
362306a36Sopenharmony_ci#include <linux/init.h>
462306a36Sopenharmony_ci#include <linux/random.h>
562306a36Sopenharmony_ci#include <linux/sched.h>
662306a36Sopenharmony_ci#include <linux/stat.h>
762306a36Sopenharmony_ci#include <linux/types.h>
862306a36Sopenharmony_ci#include <linux/fs.h>
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/stacktrace.h>
1262306a36Sopenharmony_ci#include <linux/fault-inject.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * setup_fault_attr() is a helper function for various __setup handlers, so it
1662306a36Sopenharmony_ci * returns 0 on error, because that is what __setup handlers do.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ciint setup_fault_attr(struct fault_attr *attr, char *str)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	unsigned long probability;
2162306a36Sopenharmony_ci	unsigned long interval;
2262306a36Sopenharmony_ci	int times;
2362306a36Sopenharmony_ci	int space;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	/* "<interval>,<probability>,<space>,<times>" */
2662306a36Sopenharmony_ci	if (sscanf(str, "%lu,%lu,%d,%d",
2762306a36Sopenharmony_ci			&interval, &probability, &space, &times) < 4) {
2862306a36Sopenharmony_ci		printk(KERN_WARNING
2962306a36Sopenharmony_ci			"FAULT_INJECTION: failed to parse arguments\n");
3062306a36Sopenharmony_ci		return 0;
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	attr->probability = probability;
3462306a36Sopenharmony_ci	attr->interval = interval;
3562306a36Sopenharmony_ci	atomic_set(&attr->times, times);
3662306a36Sopenharmony_ci	atomic_set(&attr->space, space);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return 1;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(setup_fault_attr);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic void fail_dump(struct fault_attr *attr)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) {
4562306a36Sopenharmony_ci		printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n"
4662306a36Sopenharmony_ci		       "name %pd, interval %lu, probability %lu, "
4762306a36Sopenharmony_ci		       "space %d, times %d\n", attr->dname,
4862306a36Sopenharmony_ci		       attr->interval, attr->probability,
4962306a36Sopenharmony_ci		       atomic_read(&attr->space),
5062306a36Sopenharmony_ci		       atomic_read(&attr->times));
5162306a36Sopenharmony_ci		if (attr->verbose > 1)
5262306a36Sopenharmony_ci			dump_stack();
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define atomic_dec_not_zero(v)		atomic_add_unless((v), -1, 0)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic bool fail_task(struct fault_attr *attr, struct task_struct *task)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	return in_task() && task->make_it_fail;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define MAX_STACK_TRACE_DEPTH 32
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic bool fail_stacktrace(struct fault_attr *attr)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int depth = attr->stacktrace_depth;
7062306a36Sopenharmony_ci	unsigned long entries[MAX_STACK_TRACE_DEPTH];
7162306a36Sopenharmony_ci	int n, nr_entries;
7262306a36Sopenharmony_ci	bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (depth == 0 || (found && !attr->reject_start && !attr->reject_end))
7562306a36Sopenharmony_ci		return found;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	nr_entries = stack_trace_save(entries, depth, 1);
7862306a36Sopenharmony_ci	for (n = 0; n < nr_entries; n++) {
7962306a36Sopenharmony_ci		if (attr->reject_start <= entries[n] &&
8062306a36Sopenharmony_ci			       entries[n] < attr->reject_end)
8162306a36Sopenharmony_ci			return false;
8262306a36Sopenharmony_ci		if (attr->require_start <= entries[n] &&
8362306a36Sopenharmony_ci			       entries[n] < attr->require_end)
8462306a36Sopenharmony_ci			found = true;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci	return found;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#else
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic inline bool fail_stacktrace(struct fault_attr *attr)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	return true;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/*
9962306a36Sopenharmony_ci * This code is stolen from failmalloc-1.0
10062306a36Sopenharmony_ci * http://www.nongnu.org/failmalloc/
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cibool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	bool stack_checked = false;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (in_task()) {
10862306a36Sopenharmony_ci		unsigned int fail_nth = READ_ONCE(current->fail_nth);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		if (fail_nth) {
11162306a36Sopenharmony_ci			if (!fail_stacktrace(attr))
11262306a36Sopenharmony_ci				return false;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci			stack_checked = true;
11562306a36Sopenharmony_ci			fail_nth--;
11662306a36Sopenharmony_ci			WRITE_ONCE(current->fail_nth, fail_nth);
11762306a36Sopenharmony_ci			if (!fail_nth)
11862306a36Sopenharmony_ci				goto fail;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci			return false;
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/* No need to check any other properties if the probability is 0 */
12562306a36Sopenharmony_ci	if (attr->probability == 0)
12662306a36Sopenharmony_ci		return false;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (attr->task_filter && !fail_task(attr, current))
12962306a36Sopenharmony_ci		return false;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (atomic_read(&attr->times) == 0)
13262306a36Sopenharmony_ci		return false;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (!stack_checked && !fail_stacktrace(attr))
13562306a36Sopenharmony_ci		return false;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (atomic_read(&attr->space) > size) {
13862306a36Sopenharmony_ci		atomic_sub(size, &attr->space);
13962306a36Sopenharmony_ci		return false;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (attr->interval > 1) {
14362306a36Sopenharmony_ci		attr->count++;
14462306a36Sopenharmony_ci		if (attr->count % attr->interval)
14562306a36Sopenharmony_ci			return false;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (attr->probability <= get_random_u32_below(100))
14962306a36Sopenharmony_ci		return false;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cifail:
15262306a36Sopenharmony_ci	if (!(flags & FAULT_NOWARN))
15362306a36Sopenharmony_ci		fail_dump(attr);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (atomic_read(&attr->times) != -1)
15662306a36Sopenharmony_ci		atomic_dec_not_zero(&attr->times);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return true;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cibool should_fail(struct fault_attr *attr, ssize_t size)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	return should_fail_ex(attr, size, 0);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(should_fail);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int debugfs_ul_set(void *data, u64 val)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	*(unsigned long *)data = val;
17262306a36Sopenharmony_ci	return 0;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic int debugfs_ul_get(void *data, u64 *val)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	*val = *(unsigned long *)data;
17862306a36Sopenharmony_ci	return 0;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ciDEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n");
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void debugfs_create_ul(const char *name, umode_t mode,
18462306a36Sopenharmony_ci			      struct dentry *parent, unsigned long *value)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	debugfs_create_file(name, mode, parent, value, &fops_ul);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int debugfs_stacktrace_depth_set(void *data, u64 val)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	*(unsigned long *)data =
19462306a36Sopenharmony_ci		min_t(unsigned long, val, MAX_STACK_TRACE_DEPTH);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciDEFINE_SIMPLE_ATTRIBUTE(fops_stacktrace_depth, debugfs_ul_get,
20062306a36Sopenharmony_ci			debugfs_stacktrace_depth_set, "%llu\n");
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void debugfs_create_stacktrace_depth(const char *name, umode_t mode,
20362306a36Sopenharmony_ci					    struct dentry *parent,
20462306a36Sopenharmony_ci					    unsigned long *value)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	debugfs_create_file(name, mode, parent, value, &fops_stacktrace_depth);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistruct dentry *fault_create_debugfs_attr(const char *name,
21262306a36Sopenharmony_ci			struct dentry *parent, struct fault_attr *attr)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
21562306a36Sopenharmony_ci	struct dentry *dir;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	dir = debugfs_create_dir(name, parent);
21862306a36Sopenharmony_ci	if (IS_ERR(dir))
21962306a36Sopenharmony_ci		return dir;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	debugfs_create_ul("probability", mode, dir, &attr->probability);
22262306a36Sopenharmony_ci	debugfs_create_ul("interval", mode, dir, &attr->interval);
22362306a36Sopenharmony_ci	debugfs_create_atomic_t("times", mode, dir, &attr->times);
22462306a36Sopenharmony_ci	debugfs_create_atomic_t("space", mode, dir, &attr->space);
22562306a36Sopenharmony_ci	debugfs_create_ul("verbose", mode, dir, &attr->verbose);
22662306a36Sopenharmony_ci	debugfs_create_u32("verbose_ratelimit_interval_ms", mode, dir,
22762306a36Sopenharmony_ci			   &attr->ratelimit_state.interval);
22862306a36Sopenharmony_ci	debugfs_create_u32("verbose_ratelimit_burst", mode, dir,
22962306a36Sopenharmony_ci			   &attr->ratelimit_state.burst);
23062306a36Sopenharmony_ci	debugfs_create_bool("task-filter", mode, dir, &attr->task_filter);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
23362306a36Sopenharmony_ci	debugfs_create_stacktrace_depth("stacktrace-depth", mode, dir,
23462306a36Sopenharmony_ci					&attr->stacktrace_depth);
23562306a36Sopenharmony_ci	debugfs_create_xul("require-start", mode, dir, &attr->require_start);
23662306a36Sopenharmony_ci	debugfs_create_xul("require-end", mode, dir, &attr->require_end);
23762306a36Sopenharmony_ci	debugfs_create_xul("reject-start", mode, dir, &attr->reject_start);
23862306a36Sopenharmony_ci	debugfs_create_xul("reject-end", mode, dir, &attr->reject_end);
23962306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	attr->dname = dget(dir);
24262306a36Sopenharmony_ci	return dir;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fault_create_debugfs_attr);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_CONFIGFS
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/* These configfs attribute utilities are copied from drivers/block/null_blk/main.c */
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic ssize_t fault_uint_attr_show(unsigned int val, char *page)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%u\n", val);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic ssize_t fault_ulong_attr_show(unsigned long val, char *page)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%lu\n", val);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic ssize_t fault_bool_attr_show(bool val, char *page)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%u\n", val);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic ssize_t fault_atomic_t_attr_show(atomic_t val, char *page)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%d\n", atomic_read(&val));
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic ssize_t fault_uint_attr_store(unsigned int *val, const char *page, size_t count)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	unsigned int tmp;
27562306a36Sopenharmony_ci	int result;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	result = kstrtouint(page, 0, &tmp);
27862306a36Sopenharmony_ci	if (result < 0)
27962306a36Sopenharmony_ci		return result;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	*val = tmp;
28262306a36Sopenharmony_ci	return count;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic ssize_t fault_ulong_attr_store(unsigned long *val, const char *page, size_t count)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	int result;
28862306a36Sopenharmony_ci	unsigned long tmp;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	result = kstrtoul(page, 0, &tmp);
29162306a36Sopenharmony_ci	if (result < 0)
29262306a36Sopenharmony_ci		return result;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	*val = tmp;
29562306a36Sopenharmony_ci	return count;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic ssize_t fault_bool_attr_store(bool *val, const char *page, size_t count)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	bool tmp;
30162306a36Sopenharmony_ci	int result;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	result = kstrtobool(page, &tmp);
30462306a36Sopenharmony_ci	if (result < 0)
30562306a36Sopenharmony_ci		return result;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	*val = tmp;
30862306a36Sopenharmony_ci	return count;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic ssize_t fault_atomic_t_attr_store(atomic_t *val, const char *page, size_t count)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	int tmp;
31462306a36Sopenharmony_ci	int result;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	result = kstrtoint(page, 0, &tmp);
31762306a36Sopenharmony_ci	if (result < 0)
31862306a36Sopenharmony_ci		return result;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	atomic_set(val, tmp);
32162306a36Sopenharmony_ci	return count;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci#define CONFIGFS_ATTR_NAMED(_pfx, _name, _attr_name)	\
32562306a36Sopenharmony_cistatic struct configfs_attribute _pfx##attr_##_name = {	\
32662306a36Sopenharmony_ci	.ca_name	= _attr_name,			\
32762306a36Sopenharmony_ci	.ca_mode	= 0644,				\
32862306a36Sopenharmony_ci	.ca_owner	= THIS_MODULE,			\
32962306a36Sopenharmony_ci	.show		= _pfx##_name##_show,		\
33062306a36Sopenharmony_ci	.store		= _pfx##_name##_store,		\
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic struct fault_config *to_fault_config(struct config_item *item)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	return container_of(to_config_group(item), struct fault_config, group);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci#define FAULT_CONFIGFS_ATTR_NAMED(NAME, ATTR_NAME, MEMBER, TYPE)				\
33962306a36Sopenharmony_cistatic ssize_t fault_##NAME##_show(struct config_item *item, char *page)			\
34062306a36Sopenharmony_ci{												\
34162306a36Sopenharmony_ci	return fault_##TYPE##_attr_show(to_fault_config(item)->attr.MEMBER, page);		\
34262306a36Sopenharmony_ci}												\
34362306a36Sopenharmony_cistatic ssize_t fault_##NAME##_store(struct config_item *item, const char *page, size_t count)	\
34462306a36Sopenharmony_ci{												\
34562306a36Sopenharmony_ci	struct fault_config *config = to_fault_config(item);					\
34662306a36Sopenharmony_ci	return fault_##TYPE##_attr_store(&config->attr.MEMBER, page, count);			\
34762306a36Sopenharmony_ci}												\
34862306a36Sopenharmony_ciCONFIGFS_ATTR_NAMED(fault_, NAME, ATTR_NAME)
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci#define FAULT_CONFIGFS_ATTR(NAME, TYPE)	\
35162306a36Sopenharmony_ci	FAULT_CONFIGFS_ATTR_NAMED(NAME, __stringify(NAME), NAME, TYPE)
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR(probability, ulong);
35462306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR(interval, ulong);
35562306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR(times, atomic_t);
35662306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR(space, atomic_t);
35762306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR(verbose, ulong);
35862306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR_NAMED(ratelimit_interval, "verbose_ratelimit_interval_ms",
35962306a36Sopenharmony_ci		ratelimit_state.interval, uint);
36062306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR_NAMED(ratelimit_burst, "verbose_ratelimit_burst",
36162306a36Sopenharmony_ci		ratelimit_state.burst, uint);
36262306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR_NAMED(task_filter, "task-filter", task_filter, bool);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic ssize_t fault_stacktrace_depth_show(struct config_item *item, char *page)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	return fault_ulong_attr_show(to_fault_config(item)->attr.stacktrace_depth, page);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic ssize_t fault_stacktrace_depth_store(struct config_item *item, const char *page,
37262306a36Sopenharmony_ci		size_t count)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	int result;
37562306a36Sopenharmony_ci	unsigned long tmp;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	result = kstrtoul(page, 0, &tmp);
37862306a36Sopenharmony_ci	if (result < 0)
37962306a36Sopenharmony_ci		return result;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	to_fault_config(item)->attr.stacktrace_depth =
38262306a36Sopenharmony_ci		min_t(unsigned long, tmp, MAX_STACK_TRACE_DEPTH);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	return count;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ciCONFIGFS_ATTR_NAMED(fault_, stacktrace_depth, "stacktrace-depth");
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic ssize_t fault_xul_attr_show(unsigned long val, char *page)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE,
39262306a36Sopenharmony_ci			sizeof(val) == sizeof(u32) ? "0x%08lx\n" : "0x%016lx\n", val);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic ssize_t fault_xul_attr_store(unsigned long *val, const char *page, size_t count)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	return fault_ulong_attr_store(val, page, count);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR_NAMED(require_start, "require-start", require_start, xul);
40162306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR_NAMED(require_end, "require-end", require_end, xul);
40262306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR_NAMED(reject_start, "reject-start", reject_start, xul);
40362306a36Sopenharmony_ciFAULT_CONFIGFS_ATTR_NAMED(reject_end, "reject-end", reject_end, xul);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic struct configfs_attribute *fault_config_attrs[] = {
40862306a36Sopenharmony_ci	&fault_attr_probability,
40962306a36Sopenharmony_ci	&fault_attr_interval,
41062306a36Sopenharmony_ci	&fault_attr_times,
41162306a36Sopenharmony_ci	&fault_attr_space,
41262306a36Sopenharmony_ci	&fault_attr_verbose,
41362306a36Sopenharmony_ci	&fault_attr_ratelimit_interval,
41462306a36Sopenharmony_ci	&fault_attr_ratelimit_burst,
41562306a36Sopenharmony_ci	&fault_attr_task_filter,
41662306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
41762306a36Sopenharmony_ci	&fault_attr_stacktrace_depth,
41862306a36Sopenharmony_ci	&fault_attr_require_start,
41962306a36Sopenharmony_ci	&fault_attr_require_end,
42062306a36Sopenharmony_ci	&fault_attr_reject_start,
42162306a36Sopenharmony_ci	&fault_attr_reject_end,
42262306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
42362306a36Sopenharmony_ci	NULL,
42462306a36Sopenharmony_ci};
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic const struct config_item_type fault_config_type = {
42762306a36Sopenharmony_ci	.ct_attrs	= fault_config_attrs,
42862306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
42962306a36Sopenharmony_ci};
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_civoid fault_config_init(struct fault_config *config, const char *name)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	config_group_init_type_name(&config->group, name, &fault_config_type);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fault_config_init);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_CONFIGFS */
438