2023-03-27 14:49:18

by Akinobu Mita

[permalink] [raw]
Subject: [PATCH 1/2] fault-inject: allow configuration via configfs

This provides a helper function to allow configuration of fault-injection
for configfs-based drivers.

The config items created by this function have the same interface as the
one created under debugfs by fault_create_debugfs_attr().

Signed-off-by: Akinobu Mita <[email protected]>
---
include/linux/fault-inject.h | 22 ++++
lib/Kconfig.debug | 13 ++-
lib/fault-inject.c | 191 +++++++++++++++++++++++++++++++++++
3 files changed, 225 insertions(+), 1 deletion(-)

diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
index 444236dadcf0..481abf530b3c 100644
--- a/include/linux/fault-inject.h
+++ b/include/linux/fault-inject.h
@@ -6,6 +6,7 @@

#include <linux/types.h>
#include <linux/debugfs.h>
+#include <linux/configfs.h>
#include <linux/ratelimit.h>
#include <linux/atomic.h>

@@ -65,6 +66,27 @@ static inline struct dentry *fault_create_debugfs_attr(const char *name,

#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */

+#ifdef CONFIG_FAULT_INJECTION_CONFIGFS
+
+struct fault_config {
+ struct fault_attr attr;
+ struct config_group group;
+};
+
+void fault_config_init(struct fault_config *config, const char *name);
+
+#else /* CONFIG_FAULT_INJECTION_CONFIGFS */
+
+struct fault_config {
+};
+
+static inline void fault_config_init(struct fault_config *config,
+ const char *name)
+{
+}
+
+#endif /* CONFIG_FAULT_INJECTION_CONFIGFS */
+
#endif /* CONFIG_FAULT_INJECTION */

struct kmem_cache;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index f0d5b82e478d..6f64b49a2a8e 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1977,9 +1977,20 @@ config FAIL_SUNRPC
Provide fault-injection capability for SunRPC and
its consumers.

+config FAULT_INJECTION_CONFIGFS
+ bool "Configfs interface for fault-injection capabilities"
+ depends on FAULT_INJECTION && CONFIGFS_FS
+ help
+ This option allows configfs-based drivers to dynamically configure
+ fault-injection via configfs. Each parameter for driver-specific
+ fault-injection can be made visible as a configfs attribute in a
+ configfs group.
+
+
config FAULT_INJECTION_STACKTRACE_FILTER
bool "stacktrace filter for fault-injection capabilities"
- depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
+ depends on FAULT_INJECTION
+ depends on (FAULT_INJECTION_DEBUG_FS || FAULT_INJECTION_CONFIGFS) && STACKTRACE_SUPPORT
select STACKTRACE
depends on FRAME_POINTER || MIPS || PPC || S390 || MICROBLAZE || ARM || ARC || X86
help
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index 6cff320c4eb4..d608f9b48c10 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -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 */
--
2.34.1


2023-04-15 15:19:24

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 1/2] fault-inject: allow configuration via configfs

Hi Mita-san,

On Mon, Mar 27, 2023 at 4:48 PM Akinobu Mita <[email protected]> wrote:
> This provides a helper function to allow configuration of fault-injection
> for configfs-based drivers.
>
> The config items created by this function have the same interface as the
> one created under debugfs by fault_create_debugfs_attr().
>
> Signed-off-by: Akinobu Mita <[email protected]>

Thanks for your patch, which is now commit 4668c7a2940d134b
("fault-inject: allow configuration via configfs") in linux-next
(to be tagged soon as next-20140414).

> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -1977,9 +1977,20 @@ config FAIL_SUNRPC
> Provide fault-injection capability for SunRPC and
> its consumers.
>
> +config FAULT_INJECTION_CONFIGFS
> + bool "Configfs interface for fault-injection capabilities"
> + depends on FAULT_INJECTION && CONFIGFS_FS

[email protected] reported build failures for e.g. m68k-allmodconfig
http://kisskb.ellerman.id.au/kisskb/buildresult/14911188/:

fault-inject.c:(.text+0x1ee): undefined reference to
`config_group_init_type_name'

This fails because FAULT_INJECTION=y but CONFIGFS_FS=m.

> + help
> + This option allows configfs-based drivers to dynamically configure
> + fault-injection via configfs. Each parameter for driver-specific
> + fault-injection can be made visible as a configfs attribute in a
> + configfs group.
> +
> +

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2023-04-15 16:51:30

by Akinobu Mita

[permalink] [raw]
Subject: Re: [PATCH 1/2] fault-inject: allow configuration via configfs

2023年4月15日(土) 23:53 Geert Uytterhoeven <[email protected]>:
>
> Hi Mita-san,
>
> On Mon, Mar 27, 2023 at 4:48 PM Akinobu Mita <[email protected]> wrote:
> > This provides a helper function to allow configuration of fault-injection
> > for configfs-based drivers.
> >
> > The config items created by this function have the same interface as the
> > one created under debugfs by fault_create_debugfs_attr().
> >
> > Signed-off-by: Akinobu Mita <[email protected]>
>
> Thanks for your patch, which is now commit 4668c7a2940d134b
> ("fault-inject: allow configuration via configfs") in linux-next
> (to be tagged soon as next-20140414).
>
> > --- a/lib/Kconfig.debug
> > +++ b/lib/Kconfig.debug
> > @@ -1977,9 +1977,20 @@ config FAIL_SUNRPC
> > Provide fault-injection capability for SunRPC and
> > its consumers.
> >
> > +config FAULT_INJECTION_CONFIGFS
> > + bool "Configfs interface for fault-injection capabilities"
> > + depends on FAULT_INJECTION && CONFIGFS_FS
>
> [email protected] reported build failures for e.g. m68k-allmodconfig
> http://kisskb.ellerman.id.au/kisskb/buildresult/14911188/:
>
> fault-inject.c:(.text+0x1ee): undefined reference to
> `config_group_init_type_name'
>
> This fails because FAULT_INJECTION=y but CONFIGFS_FS=m.

Oh, I just sent that build fix patch.
https://lore.kernel.org/all/[email protected]/

Could you please check if this is the correct way to fix it?