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