Skip to content

Commit 4668c7a

Browse files
mitaaxboe
authored andcommitted
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 <akinobu.mita@gmail.com> Link: https://lore.kernel.org/r/20230327143733.14599-2-akinobu.mita@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 4d5bba5 commit 4668c7a

3 files changed

Lines changed: 225 additions & 1 deletion

File tree

include/linux/fault-inject.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <linux/types.h>
88
#include <linux/debugfs.h>
9+
#include <linux/configfs.h>
910
#include <linux/ratelimit.h>
1011
#include <linux/atomic.h>
1112

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

6667
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
6768

69+
#ifdef CONFIG_FAULT_INJECTION_CONFIGFS
70+
71+
struct fault_config {
72+
struct fault_attr attr;
73+
struct config_group group;
74+
};
75+
76+
void fault_config_init(struct fault_config *config, const char *name);
77+
78+
#else /* CONFIG_FAULT_INJECTION_CONFIGFS */
79+
80+
struct fault_config {
81+
};
82+
83+
static inline void fault_config_init(struct fault_config *config,
84+
const char *name)
85+
{
86+
}
87+
88+
#endif /* CONFIG_FAULT_INJECTION_CONFIGFS */
89+
6890
#endif /* CONFIG_FAULT_INJECTION */
6991

7092
struct kmem_cache;

lib/Kconfig.debug

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1958,9 +1958,20 @@ config FAIL_SUNRPC
19581958
Provide fault-injection capability for SunRPC and
19591959
its consumers.
19601960

1961+
config FAULT_INJECTION_CONFIGFS
1962+
bool "Configfs interface for fault-injection capabilities"
1963+
depends on FAULT_INJECTION && CONFIGFS_FS
1964+
help
1965+
This option allows configfs-based drivers to dynamically configure
1966+
fault-injection via configfs. Each parameter for driver-specific
1967+
fault-injection can be made visible as a configfs attribute in a
1968+
configfs group.
1969+
1970+
19611971
config FAULT_INJECTION_STACKTRACE_FILTER
19621972
bool "stacktrace filter for fault-injection capabilities"
1963-
depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
1973+
depends on FAULT_INJECTION
1974+
depends on (FAULT_INJECTION_DEBUG_FS || FAULT_INJECTION_CONFIGFS) && STACKTRACE_SUPPORT
19641975
select STACKTRACE
19651976
depends on FRAME_POINTER || MIPS || PPC || S390 || MICROBLAZE || ARM || ARC || X86
19661977
help

lib/fault-inject.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,194 @@ struct dentry *fault_create_debugfs_attr(const char *name,
244244
EXPORT_SYMBOL_GPL(fault_create_debugfs_attr);
245245

246246
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
247+
248+
#ifdef CONFIG_FAULT_INJECTION_CONFIGFS
249+
250+
/* These configfs attribute utilities are copied from drivers/block/null_blk/main.c */
251+
252+
static ssize_t fault_uint_attr_show(unsigned int val, char *page)
253+
{
254+
return snprintf(page, PAGE_SIZE, "%u\n", val);
255+
}
256+
257+
static ssize_t fault_ulong_attr_show(unsigned long val, char *page)
258+
{
259+
return snprintf(page, PAGE_SIZE, "%lu\n", val);
260+
}
261+
262+
static ssize_t fault_bool_attr_show(bool val, char *page)
263+
{
264+
return snprintf(page, PAGE_SIZE, "%u\n", val);
265+
}
266+
267+
static ssize_t fault_atomic_t_attr_show(atomic_t val, char *page)
268+
{
269+
return snprintf(page, PAGE_SIZE, "%d\n", atomic_read(&val));
270+
}
271+
272+
static ssize_t fault_uint_attr_store(unsigned int *val, const char *page, size_t count)
273+
{
274+
unsigned int tmp;
275+
int result;
276+
277+
result = kstrtouint(page, 0, &tmp);
278+
if (result < 0)
279+
return result;
280+
281+
*val = tmp;
282+
return count;
283+
}
284+
285+
static ssize_t fault_ulong_attr_store(unsigned long *val, const char *page, size_t count)
286+
{
287+
int result;
288+
unsigned long tmp;
289+
290+
result = kstrtoul(page, 0, &tmp);
291+
if (result < 0)
292+
return result;
293+
294+
*val = tmp;
295+
return count;
296+
}
297+
298+
static ssize_t fault_bool_attr_store(bool *val, const char *page, size_t count)
299+
{
300+
bool tmp;
301+
int result;
302+
303+
result = kstrtobool(page, &tmp);
304+
if (result < 0)
305+
return result;
306+
307+
*val = tmp;
308+
return count;
309+
}
310+
311+
static ssize_t fault_atomic_t_attr_store(atomic_t *val, const char *page, size_t count)
312+
{
313+
int tmp;
314+
int result;
315+
316+
result = kstrtoint(page, 0, &tmp);
317+
if (result < 0)
318+
return result;
319+
320+
atomic_set(val, tmp);
321+
return count;
322+
}
323+
324+
#define CONFIGFS_ATTR_NAMED(_pfx, _name, _attr_name) \
325+
static struct configfs_attribute _pfx##attr_##_name = { \
326+
.ca_name = _attr_name, \
327+
.ca_mode = 0644, \
328+
.ca_owner = THIS_MODULE, \
329+
.show = _pfx##_name##_show, \
330+
.store = _pfx##_name##_store, \
331+
}
332+
333+
static struct fault_config *to_fault_config(struct config_item *item)
334+
{
335+
return container_of(to_config_group(item), struct fault_config, group);
336+
}
337+
338+
#define FAULT_CONFIGFS_ATTR_NAMED(NAME, ATTR_NAME, MEMBER, TYPE) \
339+
static ssize_t fault_##NAME##_show(struct config_item *item, char *page) \
340+
{ \
341+
return fault_##TYPE##_attr_show(to_fault_config(item)->attr.MEMBER, page); \
342+
} \
343+
static ssize_t fault_##NAME##_store(struct config_item *item, const char *page, size_t count) \
344+
{ \
345+
struct fault_config *config = to_fault_config(item); \
346+
return fault_##TYPE##_attr_store(&config->attr.MEMBER, page, count); \
347+
} \
348+
CONFIGFS_ATTR_NAMED(fault_, NAME, ATTR_NAME)
349+
350+
#define FAULT_CONFIGFS_ATTR(NAME, TYPE) \
351+
FAULT_CONFIGFS_ATTR_NAMED(NAME, __stringify(NAME), NAME, TYPE)
352+
353+
FAULT_CONFIGFS_ATTR(probability, ulong);
354+
FAULT_CONFIGFS_ATTR(interval, ulong);
355+
FAULT_CONFIGFS_ATTR(times, atomic_t);
356+
FAULT_CONFIGFS_ATTR(space, atomic_t);
357+
FAULT_CONFIGFS_ATTR(verbose, ulong);
358+
FAULT_CONFIGFS_ATTR_NAMED(ratelimit_interval, "verbose_ratelimit_interval_ms",
359+
ratelimit_state.interval, uint);
360+
FAULT_CONFIGFS_ATTR_NAMED(ratelimit_burst, "verbose_ratelimit_burst",
361+
ratelimit_state.burst, uint);
362+
FAULT_CONFIGFS_ATTR_NAMED(task_filter, "task-filter", task_filter, bool);
363+
364+
#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
365+
366+
static ssize_t fault_stacktrace_depth_show(struct config_item *item, char *page)
367+
{
368+
return fault_ulong_attr_show(to_fault_config(item)->attr.stacktrace_depth, page);
369+
}
370+
371+
static ssize_t fault_stacktrace_depth_store(struct config_item *item, const char *page,
372+
size_t count)
373+
{
374+
int result;
375+
unsigned long tmp;
376+
377+
result = kstrtoul(page, 0, &tmp);
378+
if (result < 0)
379+
return result;
380+
381+
to_fault_config(item)->attr.stacktrace_depth =
382+
min_t(unsigned long, tmp, MAX_STACK_TRACE_DEPTH);
383+
384+
return count;
385+
}
386+
387+
CONFIGFS_ATTR_NAMED(fault_, stacktrace_depth, "stacktrace-depth");
388+
389+
static ssize_t fault_xul_attr_show(unsigned long val, char *page)
390+
{
391+
return snprintf(page, PAGE_SIZE,
392+
sizeof(val) == sizeof(u32) ? "0x%08lx\n" : "0x%016lx\n", val);
393+
}
394+
395+
static ssize_t fault_xul_attr_store(unsigned long *val, const char *page, size_t count)
396+
{
397+
return fault_ulong_attr_store(val, page, count);
398+
}
399+
400+
FAULT_CONFIGFS_ATTR_NAMED(require_start, "require-start", require_start, xul);
401+
FAULT_CONFIGFS_ATTR_NAMED(require_end, "require-end", require_end, xul);
402+
FAULT_CONFIGFS_ATTR_NAMED(reject_start, "reject-start", reject_start, xul);
403+
FAULT_CONFIGFS_ATTR_NAMED(reject_end, "reject-end", reject_end, xul);
404+
405+
#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
406+
407+
static struct configfs_attribute *fault_config_attrs[] = {
408+
&fault_attr_probability,
409+
&fault_attr_interval,
410+
&fault_attr_times,
411+
&fault_attr_space,
412+
&fault_attr_verbose,
413+
&fault_attr_ratelimit_interval,
414+
&fault_attr_ratelimit_burst,
415+
&fault_attr_task_filter,
416+
#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
417+
&fault_attr_stacktrace_depth,
418+
&fault_attr_require_start,
419+
&fault_attr_require_end,
420+
&fault_attr_reject_start,
421+
&fault_attr_reject_end,
422+
#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
423+
NULL,
424+
};
425+
426+
static const struct config_item_type fault_config_type = {
427+
.ct_attrs = fault_config_attrs,
428+
.ct_owner = THIS_MODULE,
429+
};
430+
431+
void fault_config_init(struct fault_config *config, const char *name)
432+
{
433+
config_group_init_type_name(&config->group, name, &fault_config_type);
434+
}
435+
EXPORT_SYMBOL_GPL(fault_config_init);
436+
437+
#endif /* CONFIG_FAULT_INJECTION_CONFIGFS */

0 commit comments

Comments
 (0)