fault_inject.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
  3. *
  4. * Uses debugfs to create fault injection points for client testing
  5. */
  6. #include <linux/types.h>
  7. #include <linux/fs.h>
  8. #include <linux/debugfs.h>
  9. #include <linux/module.h>
  10. #include <asm/uaccess.h>
  11. #include "state.h"
  12. struct nfsd_fault_inject_op {
  13. char *file;
  14. u64 (*forget)(struct nfs4_client *, u64);
  15. u64 (*print)(struct nfs4_client *, u64);
  16. };
  17. static struct nfsd_fault_inject_op inject_ops[] = {
  18. {
  19. .file = "forget_clients",
  20. .forget = nfsd_forget_client,
  21. .print = nfsd_print_client,
  22. },
  23. {
  24. .file = "forget_locks",
  25. .forget = nfsd_forget_client_locks,
  26. .print = nfsd_print_client_locks,
  27. },
  28. {
  29. .file = "forget_openowners",
  30. .forget = nfsd_forget_client_openowners,
  31. .print = nfsd_print_client_openowners,
  32. },
  33. {
  34. .file = "forget_delegations",
  35. .forget = nfsd_forget_client_delegations,
  36. .print = nfsd_print_client_delegations,
  37. },
  38. {
  39. .file = "recall_delegations",
  40. .forget = nfsd_recall_client_delegations,
  41. .print = nfsd_print_client_delegations,
  42. },
  43. };
  44. static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
  45. static struct dentry *debug_dir;
  46. static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
  47. {
  48. u64 count = 0;
  49. if (val == 0)
  50. printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
  51. else
  52. printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
  53. nfs4_lock_state();
  54. count = nfsd_for_n_state(val, op->forget);
  55. nfs4_unlock_state();
  56. printk(KERN_INFO "NFSD: %s: found %llu", op->file, count);
  57. }
  58. static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val)
  59. {
  60. nfs4_lock_state();
  61. *val = nfsd_for_n_state(0, op->print);
  62. nfs4_unlock_state();
  63. }
  64. static ssize_t fault_inject_read(struct file *file, char __user *buf,
  65. size_t len, loff_t *ppos)
  66. {
  67. static u64 val;
  68. char read_buf[25];
  69. size_t size, ret;
  70. loff_t pos = *ppos;
  71. if (!pos)
  72. nfsd_inject_get(file->f_dentry->d_inode->i_private, &val);
  73. size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);
  74. if (pos < 0)
  75. return -EINVAL;
  76. if (pos >= size || !len)
  77. return 0;
  78. if (len > size - pos)
  79. len = size - pos;
  80. ret = copy_to_user(buf, read_buf + pos, len);
  81. if (ret == len)
  82. return -EFAULT;
  83. len -= ret;
  84. *ppos = pos + len;
  85. return len;
  86. }
  87. static ssize_t fault_inject_write(struct file *file, const char __user *buf,
  88. size_t len, loff_t *ppos)
  89. {
  90. char write_buf[24];
  91. size_t size = min(sizeof(write_buf), len) - 1;
  92. u64 val;
  93. if (copy_from_user(write_buf, buf, size))
  94. return -EFAULT;
  95. val = simple_strtoll(write_buf, NULL, 0);
  96. nfsd_inject_set(file->f_dentry->d_inode->i_private, val);
  97. return len; /* on success, claim we got the whole input */
  98. }
  99. static const struct file_operations fops_nfsd = {
  100. .owner = THIS_MODULE,
  101. .read = fault_inject_read,
  102. .write = fault_inject_write,
  103. };
  104. void nfsd_fault_inject_cleanup(void)
  105. {
  106. debugfs_remove_recursive(debug_dir);
  107. }
  108. int nfsd_fault_inject_init(void)
  109. {
  110. unsigned int i;
  111. struct nfsd_fault_inject_op *op;
  112. umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
  113. debug_dir = debugfs_create_dir("nfsd", NULL);
  114. if (!debug_dir)
  115. goto fail;
  116. for (i = 0; i < NUM_INJECT_OPS; i++) {
  117. op = &inject_ops[i];
  118. if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
  119. goto fail;
  120. }
  121. return 0;
  122. fail:
  123. nfsd_fault_inject_cleanup();
  124. return -ENOMEM;
  125. }