fault_inject.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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;
  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. return simple_read_from_buffer(buf, len, ppos, read_buf, size);
  94. }
  95. static ssize_t fault_inject_write(struct file *file, const char __user *buf,
  96. size_t len, loff_t *ppos)
  97. {
  98. char write_buf[INET6_ADDRSTRLEN];
  99. size_t size = min(sizeof(write_buf) - 1, len);
  100. struct net *net = current->nsproxy->net_ns;
  101. struct sockaddr_storage sa;
  102. u64 val;
  103. if (copy_from_user(write_buf, buf, size))
  104. return -EFAULT;
  105. write_buf[size] = '\0';
  106. size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
  107. if (size > 0)
  108. nfsd_inject_set_client(file_inode(file)->i_private, &sa, size);
  109. else {
  110. val = simple_strtoll(write_buf, NULL, 0);
  111. nfsd_inject_set(file_inode(file)->i_private, val);
  112. }
  113. return len; /* on success, claim we got the whole input */
  114. }
  115. static const struct file_operations fops_nfsd = {
  116. .owner = THIS_MODULE,
  117. .read = fault_inject_read,
  118. .write = fault_inject_write,
  119. };
  120. void nfsd_fault_inject_cleanup(void)
  121. {
  122. debugfs_remove_recursive(debug_dir);
  123. }
  124. int nfsd_fault_inject_init(void)
  125. {
  126. unsigned int i;
  127. struct nfsd_fault_inject_op *op;
  128. umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
  129. debug_dir = debugfs_create_dir("nfsd", NULL);
  130. if (!debug_dir)
  131. goto fail;
  132. for (i = 0; i < NUM_INJECT_OPS; i++) {
  133. op = &inject_ops[i];
  134. if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
  135. goto fail;
  136. }
  137. return 0;
  138. fail:
  139. nfsd_fault_inject_cleanup();
  140. return -ENOMEM;
  141. }