fault_inject.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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 <linux/nsproxy.h>
  11. #include <linux/sunrpc/addr.h>
  12. #include <asm/uaccess.h>
  13. #include "state.h"
  14. #include "netns.h"
  15. struct nfsd_fault_inject_op {
  16. char *file;
  17. u64 (*forget)(struct nfs4_client *, u64);
  18. u64 (*print)(struct nfs4_client *, u64);
  19. };
  20. static struct nfsd_fault_inject_op inject_ops[] = {
  21. {
  22. .file = "forget_clients",
  23. .forget = nfsd_forget_client,
  24. .print = nfsd_print_client,
  25. },
  26. {
  27. .file = "forget_locks",
  28. .forget = nfsd_forget_client_locks,
  29. .print = nfsd_print_client_locks,
  30. },
  31. {
  32. .file = "forget_openowners",
  33. .forget = nfsd_forget_client_openowners,
  34. .print = nfsd_print_client_openowners,
  35. },
  36. {
  37. .file = "forget_delegations",
  38. .forget = nfsd_forget_client_delegations,
  39. .print = nfsd_print_client_delegations,
  40. },
  41. {
  42. .file = "recall_delegations",
  43. .forget = nfsd_recall_client_delegations,
  44. .print = nfsd_print_client_delegations,
  45. },
  46. };
  47. static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
  48. static struct dentry *debug_dir;
  49. static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
  50. {
  51. u64 count = 0;
  52. if (val == 0)
  53. printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
  54. else
  55. printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
  56. nfs4_lock_state();
  57. count = nfsd_for_n_state(val, op->forget);
  58. nfs4_unlock_state();
  59. printk(KERN_INFO "NFSD: %s: found %llu", op->file, count);
  60. }
  61. static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op,
  62. struct sockaddr_storage *addr,
  63. size_t addr_size)
  64. {
  65. char buf[INET6_ADDRSTRLEN];
  66. struct nfs4_client *clp;
  67. u64 count;
  68. nfs4_lock_state();
  69. clp = nfsd_find_client(addr, addr_size);
  70. if (clp) {
  71. count = op->forget(clp, 0);
  72. rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
  73. printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count);
  74. }
  75. nfs4_unlock_state();
  76. }
  77. static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val)
  78. {
  79. nfs4_lock_state();
  80. *val = nfsd_for_n_state(0, op->print);
  81. nfs4_unlock_state();
  82. }
  83. static ssize_t fault_inject_read(struct file *file, char __user *buf,
  84. size_t len, loff_t *ppos)
  85. {
  86. static u64 val;
  87. char read_buf[25];
  88. size_t size, ret;
  89. loff_t pos = *ppos;
  90. if (!pos)
  91. nfsd_inject_get(file_inode(file)->i_private, &val);
  92. size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);
  93. if (pos < 0)
  94. return -EINVAL;
  95. if (pos >= size || !len)
  96. return 0;
  97. if (len > size - pos)
  98. len = size - pos;
  99. ret = copy_to_user(buf, read_buf + pos, len);
  100. if (ret == len)
  101. return -EFAULT;
  102. len -= ret;
  103. *ppos = pos + len;
  104. return len;
  105. }
  106. static ssize_t fault_inject_write(struct file *file, const char __user *buf,
  107. size_t len, loff_t *ppos)
  108. {
  109. char write_buf[INET6_ADDRSTRLEN];
  110. size_t size = min(sizeof(write_buf) - 1, len);
  111. struct net *net = current->nsproxy->net_ns;
  112. struct sockaddr_storage sa;
  113. u64 val;
  114. if (copy_from_user(write_buf, buf, size))
  115. return -EFAULT;
  116. write_buf[size] = '\0';
  117. size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
  118. if (size > 0)
  119. nfsd_inject_set_client(file_inode(file)->i_private, &sa, size);
  120. else {
  121. val = simple_strtoll(write_buf, NULL, 0);
  122. nfsd_inject_set(file_inode(file)->i_private, val);
  123. }
  124. return len; /* on success, claim we got the whole input */
  125. }
  126. static const struct file_operations fops_nfsd = {
  127. .owner = THIS_MODULE,
  128. .read = fault_inject_read,
  129. .write = fault_inject_write,
  130. };
  131. void nfsd_fault_inject_cleanup(void)
  132. {
  133. debugfs_remove_recursive(debug_dir);
  134. }
  135. int nfsd_fault_inject_init(void)
  136. {
  137. unsigned int i;
  138. struct nfsd_fault_inject_op *op;
  139. umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
  140. debug_dir = debugfs_create_dir("nfsd", NULL);
  141. if (!debug_dir)
  142. goto fail;
  143. for (i = 0; i < NUM_INJECT_OPS; i++) {
  144. op = &inject_ops[i];
  145. if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
  146. goto fail;
  147. }
  148. return 0;
  149. fail:
  150. nfsd_fault_inject_cleanup();
  151. return -ENOMEM;
  152. }