forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PATCH] fault-injection capabilities infrastructure
This patch provides base functions implement to fault-injection capabilities. - The function should_fail() is taken from failmalloc-1.0 (http://www.nongnu.org/failmalloc/) [[email protected]: cleanups, comments, add __init] Cc: <[email protected]> Signed-off-by: Akinobu Mita <[email protected]> Signed-off-by: Don Mullis <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
4 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#ifndef _LINUX_FAULT_INJECT_H | ||
#define _LINUX_FAULT_INJECT_H | ||
|
||
#ifdef CONFIG_FAULT_INJECTION | ||
|
||
#include <linux/types.h> | ||
#include <linux/debugfs.h> | ||
#include <asm/atomic.h> | ||
|
||
/* | ||
* For explanation of the elements of this struct, see | ||
* Documentation/fault-injection/fault-injection.txt | ||
*/ | ||
struct fault_attr { | ||
unsigned long probability; | ||
unsigned long interval; | ||
atomic_t times; | ||
atomic_t space; | ||
unsigned long verbose; | ||
|
||
unsigned long count; | ||
|
||
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
|
||
struct { | ||
struct dentry *dir; | ||
|
||
struct dentry *probability_file; | ||
struct dentry *interval_file; | ||
struct dentry *times_file; | ||
struct dentry *space_file; | ||
struct dentry *verbose_file; | ||
} dentries; | ||
|
||
#endif | ||
}; | ||
|
||
#define FAULT_ATTR_INITIALIZER { \ | ||
.interval = 1, \ | ||
.times = ATOMIC_INIT(1), \ | ||
} | ||
|
||
#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER | ||
int setup_fault_attr(struct fault_attr *attr, char *str); | ||
void should_fail_srandom(unsigned long entropy); | ||
int should_fail(struct fault_attr *attr, ssize_t size); | ||
|
||
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
|
||
int init_fault_attr_dentries(struct fault_attr *attr, const char *name); | ||
void cleanup_fault_attr_dentries(struct fault_attr *attr); | ||
|
||
#else /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
|
||
static inline int init_fault_attr_dentries(struct fault_attr *attr, | ||
const char *name) | ||
{ | ||
return -ENODEV; | ||
} | ||
|
||
static inline void cleanup_fault_attr_dentries(struct fault_attr *attr) | ||
{ | ||
} | ||
|
||
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
|
||
#endif /* CONFIG_FAULT_INJECTION */ | ||
|
||
#endif /* _LINUX_FAULT_INJECT_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
#include <linux/kernel.h> | ||
#include <linux/init.h> | ||
#include <linux/random.h> | ||
#include <linux/stat.h> | ||
#include <linux/types.h> | ||
#include <linux/fs.h> | ||
#include <linux/module.h> | ||
#include <linux/fault-inject.h> | ||
|
||
/* | ||
* setup_fault_attr() is a helper function for various __setup handlers, so it | ||
* returns 0 on error, because that is what __setup handlers do. | ||
*/ | ||
int __init setup_fault_attr(struct fault_attr *attr, char *str) | ||
{ | ||
unsigned long probability; | ||
unsigned long interval; | ||
int times; | ||
int space; | ||
|
||
/* "<interval>,<probability>,<space>,<times>" */ | ||
if (sscanf(str, "%lu,%lu,%d,%d", | ||
&interval, &probability, &space, ×) < 4) { | ||
printk(KERN_WARNING | ||
"FAULT_INJECTION: failed to parse arguments\n"); | ||
return 0; | ||
} | ||
|
||
attr->probability = probability; | ||
attr->interval = interval; | ||
atomic_set(&attr->times, times); | ||
atomic_set(&attr->space, space); | ||
|
||
return 1; | ||
} | ||
|
||
static void fail_dump(struct fault_attr *attr) | ||
{ | ||
if (attr->verbose > 0) | ||
printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure\n"); | ||
if (attr->verbose > 1) | ||
dump_stack(); | ||
} | ||
|
||
#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) | ||
|
||
/* | ||
* This code is stolen from failmalloc-1.0 | ||
* http://www.nongnu.org/failmalloc/ | ||
*/ | ||
|
||
int should_fail(struct fault_attr *attr, ssize_t size) | ||
{ | ||
if (atomic_read(&attr->times) == 0) | ||
return 0; | ||
|
||
if (atomic_read(&attr->space) > size) { | ||
atomic_sub(size, &attr->space); | ||
return 0; | ||
} | ||
|
||
if (attr->interval > 1) { | ||
attr->count++; | ||
if (attr->count % attr->interval) | ||
return 0; | ||
} | ||
|
||
if (attr->probability > random32() % 100) | ||
goto fail; | ||
|
||
return 0; | ||
|
||
fail: | ||
fail_dump(attr); | ||
|
||
if (atomic_read(&attr->times) != -1) | ||
atomic_dec_not_zero(&attr->times); | ||
|
||
return 1; | ||
} | ||
|
||
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
|
||
static void debugfs_ul_set(void *data, u64 val) | ||
{ | ||
*(unsigned long *)data = val; | ||
} | ||
|
||
static u64 debugfs_ul_get(void *data) | ||
{ | ||
return *(unsigned long *)data; | ||
} | ||
|
||
DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n"); | ||
|
||
static struct dentry *debugfs_create_ul(const char *name, mode_t mode, | ||
struct dentry *parent, unsigned long *value) | ||
{ | ||
return debugfs_create_file(name, mode, parent, value, &fops_ul); | ||
} | ||
|
||
static void debugfs_atomic_t_set(void *data, u64 val) | ||
{ | ||
atomic_set((atomic_t *)data, val); | ||
} | ||
|
||
static u64 debugfs_atomic_t_get(void *data) | ||
{ | ||
return atomic_read((atomic_t *)data); | ||
} | ||
|
||
DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, | ||
debugfs_atomic_t_set, "%lld\n"); | ||
|
||
static struct dentry *debugfs_create_atomic_t(const char *name, mode_t mode, | ||
struct dentry *parent, atomic_t *value) | ||
{ | ||
return debugfs_create_file(name, mode, parent, value, &fops_atomic_t); | ||
} | ||
|
||
void cleanup_fault_attr_dentries(struct fault_attr *attr) | ||
{ | ||
debugfs_remove(attr->dentries.probability_file); | ||
attr->dentries.probability_file = NULL; | ||
|
||
debugfs_remove(attr->dentries.interval_file); | ||
attr->dentries.interval_file = NULL; | ||
|
||
debugfs_remove(attr->dentries.times_file); | ||
attr->dentries.times_file = NULL; | ||
|
||
debugfs_remove(attr->dentries.space_file); | ||
attr->dentries.space_file = NULL; | ||
|
||
debugfs_remove(attr->dentries.verbose_file); | ||
attr->dentries.verbose_file = NULL; | ||
|
||
if (attr->dentries.dir) | ||
WARN_ON(!simple_empty(attr->dentries.dir)); | ||
|
||
debugfs_remove(attr->dentries.dir); | ||
attr->dentries.dir = NULL; | ||
} | ||
|
||
int init_fault_attr_dentries(struct fault_attr *attr, const char *name) | ||
{ | ||
mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; | ||
struct dentry *dir; | ||
|
||
memset(&attr->dentries, 0, sizeof(attr->dentries)); | ||
|
||
dir = debugfs_create_dir(name, NULL); | ||
if (!dir) | ||
goto fail; | ||
attr->dentries.dir = dir; | ||
|
||
attr->dentries.probability_file = | ||
debugfs_create_ul("probability", mode, dir, &attr->probability); | ||
|
||
attr->dentries.interval_file = | ||
debugfs_create_ul("interval", mode, dir, &attr->interval); | ||
|
||
attr->dentries.times_file = | ||
debugfs_create_atomic_t("times", mode, dir, &attr->times); | ||
|
||
attr->dentries.space_file = | ||
debugfs_create_atomic_t("space", mode, dir, &attr->space); | ||
|
||
attr->dentries.verbose_file = | ||
debugfs_create_ul("verbose", mode, dir, &attr->verbose); | ||
|
||
if (!attr->dentries.probability_file || !attr->dentries.interval_file | ||
|| !attr->dentries.times_file || !attr->dentries.space_file | ||
|| !attr->dentries.verbose_file) | ||
goto fail; | ||
|
||
return 0; | ||
fail: | ||
cleanup_fault_attr_dentries(attr); | ||
return -ENOMEM; | ||
} | ||
|
||
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ |