Merge tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg...
[linux-block.git] / lib / fault-inject.c
index 6cff320c4eb4085b0dc93cb43909cb4fce8fac94..d608f9b48c10069a3e701f610249c4cca0eb4fd9 100644 (file)
@@ -244,3 +244,194 @@ struct dentry *fault_create_debugfs_attr(const char *name,
 EXPORT_SYMBOL_GPL(fault_create_debugfs_attr);
 
 #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+#ifdef CONFIG_FAULT_INJECTION_CONFIGFS
+
+/* These configfs attribute utilities are copied from drivers/block/null_blk/main.c */
+
+static ssize_t fault_uint_attr_show(unsigned int val, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", val);
+}
+
+static ssize_t fault_ulong_attr_show(unsigned long val, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%lu\n", val);
+}
+
+static ssize_t fault_bool_attr_show(bool val, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", val);
+}
+
+static ssize_t fault_atomic_t_attr_show(atomic_t val, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%d\n", atomic_read(&val));
+}
+
+static ssize_t fault_uint_attr_store(unsigned int *val, const char *page, size_t count)
+{
+       unsigned int tmp;
+       int result;
+
+       result = kstrtouint(page, 0, &tmp);
+       if (result < 0)
+               return result;
+
+       *val = tmp;
+       return count;
+}
+
+static ssize_t fault_ulong_attr_store(unsigned long *val, const char *page, size_t count)
+{
+       int result;
+       unsigned long tmp;
+
+       result = kstrtoul(page, 0, &tmp);
+       if (result < 0)
+               return result;
+
+       *val = tmp;
+       return count;
+}
+
+static ssize_t fault_bool_attr_store(bool *val, const char *page, size_t count)
+{
+       bool tmp;
+       int result;
+
+       result = kstrtobool(page, &tmp);
+       if (result < 0)
+               return result;
+
+       *val = tmp;
+       return count;
+}
+
+static ssize_t fault_atomic_t_attr_store(atomic_t *val, const char *page, size_t count)
+{
+       int tmp;
+       int result;
+
+       result = kstrtoint(page, 0, &tmp);
+       if (result < 0)
+               return result;
+
+       atomic_set(val, tmp);
+       return count;
+}
+
+#define CONFIGFS_ATTR_NAMED(_pfx, _name, _attr_name)   \
+static struct configfs_attribute _pfx##attr_##_name = {        \
+       .ca_name        = _attr_name,                   \
+       .ca_mode        = 0644,                         \
+       .ca_owner       = THIS_MODULE,                  \
+       .show           = _pfx##_name##_show,           \
+       .store          = _pfx##_name##_store,          \
+}
+
+static struct fault_config *to_fault_config(struct config_item *item)
+{
+       return container_of(to_config_group(item), struct fault_config, group);
+}
+
+#define FAULT_CONFIGFS_ATTR_NAMED(NAME, ATTR_NAME, MEMBER, TYPE)                               \
+static ssize_t fault_##NAME##_show(struct config_item *item, char *page)                       \
+{                                                                                              \
+       return fault_##TYPE##_attr_show(to_fault_config(item)->attr.MEMBER, page);              \
+}                                                                                              \
+static ssize_t fault_##NAME##_store(struct config_item *item, const char *page, size_t count)  \
+{                                                                                              \
+       struct fault_config *config = to_fault_config(item);                                    \
+       return fault_##TYPE##_attr_store(&config->attr.MEMBER, page, count);                    \
+}                                                                                              \
+CONFIGFS_ATTR_NAMED(fault_, NAME, ATTR_NAME)
+
+#define FAULT_CONFIGFS_ATTR(NAME, TYPE)        \
+       FAULT_CONFIGFS_ATTR_NAMED(NAME, __stringify(NAME), NAME, TYPE)
+
+FAULT_CONFIGFS_ATTR(probability, ulong);
+FAULT_CONFIGFS_ATTR(interval, ulong);
+FAULT_CONFIGFS_ATTR(times, atomic_t);
+FAULT_CONFIGFS_ATTR(space, atomic_t);
+FAULT_CONFIGFS_ATTR(verbose, ulong);
+FAULT_CONFIGFS_ATTR_NAMED(ratelimit_interval, "verbose_ratelimit_interval_ms",
+               ratelimit_state.interval, uint);
+FAULT_CONFIGFS_ATTR_NAMED(ratelimit_burst, "verbose_ratelimit_burst",
+               ratelimit_state.burst, uint);
+FAULT_CONFIGFS_ATTR_NAMED(task_filter, "task-filter", task_filter, bool);
+
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
+
+static ssize_t fault_stacktrace_depth_show(struct config_item *item, char *page)
+{
+       return fault_ulong_attr_show(to_fault_config(item)->attr.stacktrace_depth, page);
+}
+
+static ssize_t fault_stacktrace_depth_store(struct config_item *item, const char *page,
+               size_t count)
+{
+       int result;
+       unsigned long tmp;
+
+       result = kstrtoul(page, 0, &tmp);
+       if (result < 0)
+               return result;
+
+       to_fault_config(item)->attr.stacktrace_depth =
+               min_t(unsigned long, tmp, MAX_STACK_TRACE_DEPTH);
+
+       return count;
+}
+
+CONFIGFS_ATTR_NAMED(fault_, stacktrace_depth, "stacktrace-depth");
+
+static ssize_t fault_xul_attr_show(unsigned long val, char *page)
+{
+       return snprintf(page, PAGE_SIZE,
+                       sizeof(val) == sizeof(u32) ? "0x%08lx\n" : "0x%016lx\n", val);
+}
+
+static ssize_t fault_xul_attr_store(unsigned long *val, const char *page, size_t count)
+{
+       return fault_ulong_attr_store(val, page, count);
+}
+
+FAULT_CONFIGFS_ATTR_NAMED(require_start, "require-start", require_start, xul);
+FAULT_CONFIGFS_ATTR_NAMED(require_end, "require-end", require_end, xul);
+FAULT_CONFIGFS_ATTR_NAMED(reject_start, "reject-start", reject_start, xul);
+FAULT_CONFIGFS_ATTR_NAMED(reject_end, "reject-end", reject_end, xul);
+
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
+
+static struct configfs_attribute *fault_config_attrs[] = {
+       &fault_attr_probability,
+       &fault_attr_interval,
+       &fault_attr_times,
+       &fault_attr_space,
+       &fault_attr_verbose,
+       &fault_attr_ratelimit_interval,
+       &fault_attr_ratelimit_burst,
+       &fault_attr_task_filter,
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
+       &fault_attr_stacktrace_depth,
+       &fault_attr_require_start,
+       &fault_attr_require_end,
+       &fault_attr_reject_start,
+       &fault_attr_reject_end,
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
+       NULL,
+};
+
+static const struct config_item_type fault_config_type = {
+       .ct_attrs       = fault_config_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+void fault_config_init(struct fault_config *config, const char *name)
+{
+       config_group_init_type_name(&config->group, name, &fault_config_type);
+}
+EXPORT_SYMBOL_GPL(fault_config_init);
+
+#endif /* CONFIG_FAULT_INJECTION_CONFIGFS */