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, ×) < 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