notifier-error-inject.c 2.7 KB

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