Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/module.h>
0003 
0004 #include "notifier-error-inject.h"
0005 
0006 static int debugfs_errno_set(void *data, u64 val)
0007 {
0008     *(int *)data = clamp_t(int, val, -MAX_ERRNO, 0);
0009     return 0;
0010 }
0011 
0012 static int debugfs_errno_get(void *data, u64 *val)
0013 {
0014     *val = *(int *)data;
0015     return 0;
0016 }
0017 
0018 DEFINE_SIMPLE_ATTRIBUTE(fops_errno, debugfs_errno_get, debugfs_errno_set,
0019             "%lld\n");
0020 
0021 static struct dentry *debugfs_create_errno(const char *name, umode_t mode,
0022                 struct dentry *parent, int *value)
0023 {
0024     return debugfs_create_file(name, mode, parent, value, &fops_errno);
0025 }
0026 
0027 static int notifier_err_inject_callback(struct notifier_block *nb,
0028                 unsigned long val, void *p)
0029 {
0030     int err = 0;
0031     struct notifier_err_inject *err_inject =
0032         container_of(nb, struct notifier_err_inject, nb);
0033     struct notifier_err_inject_action *action;
0034 
0035     for (action = err_inject->actions; action->name; action++) {
0036         if (action->val == val) {
0037             err = action->error;
0038             break;
0039         }
0040     }
0041     if (err)
0042         pr_info("Injecting error (%d) to %s\n", err, action->name);
0043 
0044     return notifier_from_errno(err);
0045 }
0046 
0047 struct dentry *notifier_err_inject_dir;
0048 EXPORT_SYMBOL_GPL(notifier_err_inject_dir);
0049 
0050 struct dentry *notifier_err_inject_init(const char *name, struct dentry *parent,
0051             struct notifier_err_inject *err_inject, int priority)
0052 {
0053     struct notifier_err_inject_action *action;
0054     umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
0055     struct dentry *dir;
0056     struct dentry *actions_dir;
0057 
0058     err_inject->nb.notifier_call = notifier_err_inject_callback;
0059     err_inject->nb.priority = priority;
0060 
0061     dir = debugfs_create_dir(name, parent);
0062 
0063     actions_dir = debugfs_create_dir("actions", dir);
0064 
0065     for (action = err_inject->actions; action->name; action++) {
0066         struct dentry *action_dir;
0067 
0068         action_dir = debugfs_create_dir(action->name, actions_dir);
0069 
0070         /*
0071          * Create debugfs r/w file containing action->error. If
0072          * notifier call chain is called with action->val, it will
0073          * fail with the error code
0074          */
0075         debugfs_create_errno("error", mode, action_dir, &action->error);
0076     }
0077     return dir;
0078 }
0079 EXPORT_SYMBOL_GPL(notifier_err_inject_init);
0080 
0081 static int __init err_inject_init(void)
0082 {
0083     notifier_err_inject_dir =
0084         debugfs_create_dir("notifier-error-inject", NULL);
0085 
0086     if (!notifier_err_inject_dir)
0087         return -ENOMEM;
0088 
0089     return 0;
0090 }
0091 
0092 static void __exit err_inject_exit(void)
0093 {
0094     debugfs_remove_recursive(notifier_err_inject_dir);
0095 }
0096 
0097 module_init(err_inject_init);
0098 module_exit(err_inject_exit);
0099 
0100 MODULE_DESCRIPTION("Notifier error injection module");
0101 MODULE_LICENSE("GPL");
0102 MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");