]>
Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
8d438288 AM |
2 | #include <linux/module.h> |
3 | ||
4 | #include "notifier-error-inject.h" | |
5 | ||
6 | static int debugfs_errno_set(void *data, u64 val) | |
7 | { | |
8 | *(int *)data = clamp_t(int, val, -MAX_ERRNO, 0); | |
9 | return 0; | |
10 | } | |
11 | ||
12 | static int debugfs_errno_get(void *data, u64 *val) | |
13 | { | |
14 | *val = *(int *)data; | |
15 | return 0; | |
16 | } | |
17 | ||
f883c3ed | 18 | DEFINE_SIMPLE_ATTRIBUTE_SIGNED(fops_errno, debugfs_errno_get, debugfs_errno_set, |
8d438288 AM |
19 | "%lld\n"); |
20 | ||
0ecc833b | 21 | static struct dentry *debugfs_create_errno(const char *name, umode_t mode, |
8d438288 AM |
22 | struct dentry *parent, int *value) |
23 | { | |
24 | return debugfs_create_file(name, mode, parent, value, &fops_errno); | |
25 | } | |
26 | ||
27 | static int notifier_err_inject_callback(struct notifier_block *nb, | |
28 | unsigned long val, void *p) | |
29 | { | |
30 | int err = 0; | |
31 | struct notifier_err_inject *err_inject = | |
32 | container_of(nb, struct notifier_err_inject, nb); | |
33 | struct notifier_err_inject_action *action; | |
34 | ||
35 | for (action = err_inject->actions; action->name; action++) { | |
36 | if (action->val == val) { | |
37 | err = action->error; | |
38 | break; | |
39 | } | |
40 | } | |
41 | if (err) | |
42 | pr_info("Injecting error (%d) to %s\n", err, action->name); | |
43 | ||
44 | return notifier_from_errno(err); | |
45 | } | |
46 | ||
47 | struct dentry *notifier_err_inject_dir; | |
48 | EXPORT_SYMBOL_GPL(notifier_err_inject_dir); | |
49 | ||
50 | struct dentry *notifier_err_inject_init(const char *name, struct dentry *parent, | |
51 | struct notifier_err_inject *err_inject, int priority) | |
52 | { | |
53 | struct notifier_err_inject_action *action; | |
0ecc833b | 54 | umode_t mode = S_IFREG | S_IRUSR | S_IWUSR; |
8d438288 AM |
55 | struct dentry *dir; |
56 | struct dentry *actions_dir; | |
57 | ||
58 | err_inject->nb.notifier_call = notifier_err_inject_callback; | |
59 | err_inject->nb.priority = priority; | |
60 | ||
61 | dir = debugfs_create_dir(name, parent); | |
8d438288 AM |
62 | |
63 | actions_dir = debugfs_create_dir("actions", dir); | |
8d438288 AM |
64 | |
65 | for (action = err_inject->actions; action->name; action++) { | |
66 | struct dentry *action_dir; | |
67 | ||
68 | action_dir = debugfs_create_dir(action->name, actions_dir); | |
8d438288 AM |
69 | |
70 | /* | |
71 | * Create debugfs r/w file containing action->error. If | |
72 | * notifier call chain is called with action->val, it will | |
73 | * fail with the error code | |
74 | */ | |
56f3364a | 75 | debugfs_create_errno("error", mode, action_dir, &action->error); |
8d438288 AM |
76 | } |
77 | return dir; | |
8d438288 AM |
78 | } |
79 | EXPORT_SYMBOL_GPL(notifier_err_inject_init); | |
80 | ||
81 | static int __init err_inject_init(void) | |
82 | { | |
83 | notifier_err_inject_dir = | |
84 | debugfs_create_dir("notifier-error-inject", NULL); | |
85 | ||
86 | if (!notifier_err_inject_dir) | |
87 | return -ENOMEM; | |
88 | ||
89 | return 0; | |
90 | } | |
91 | ||
92 | static void __exit err_inject_exit(void) | |
93 | { | |
94 | debugfs_remove_recursive(notifier_err_inject_dir); | |
95 | } | |
96 | ||
97 | module_init(err_inject_init); | |
98 | module_exit(err_inject_exit); | |
99 | ||
100 | MODULE_DESCRIPTION("Notifier error injection module"); | |
101 | MODULE_LICENSE("GPL"); | |
102 | MODULE_AUTHOR("Akinobu Mita <[email protected]>"); |