diff options
Diffstat (limited to 'fs/nfsd/fault_inject.c')
-rw-r--r-- | fs/nfsd/fault_inject.c | 138 |
1 files changed, 62 insertions, 76 deletions
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 2ed05c3cd43d..c16bf5af6831 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c | |||
@@ -17,81 +17,13 @@ | |||
17 | 17 | ||
18 | struct nfsd_fault_inject_op { | 18 | struct nfsd_fault_inject_op { |
19 | char *file; | 19 | char *file; |
20 | u64 (*forget)(struct nfs4_client *, u64); | 20 | u64 (*get)(void); |
21 | u64 (*print)(struct nfs4_client *, u64); | 21 | u64 (*set_val)(u64); |
22 | u64 (*set_clnt)(struct sockaddr_storage *, size_t); | ||
22 | }; | 23 | }; |
23 | 24 | ||
24 | static struct nfsd_fault_inject_op inject_ops[] = { | ||
25 | { | ||
26 | .file = "forget_clients", | ||
27 | .forget = nfsd_forget_client, | ||
28 | .print = nfsd_print_client, | ||
29 | }, | ||
30 | { | ||
31 | .file = "forget_locks", | ||
32 | .forget = nfsd_forget_client_locks, | ||
33 | .print = nfsd_print_client_locks, | ||
34 | }, | ||
35 | { | ||
36 | .file = "forget_openowners", | ||
37 | .forget = nfsd_forget_client_openowners, | ||
38 | .print = nfsd_print_client_openowners, | ||
39 | }, | ||
40 | { | ||
41 | .file = "forget_delegations", | ||
42 | .forget = nfsd_forget_client_delegations, | ||
43 | .print = nfsd_print_client_delegations, | ||
44 | }, | ||
45 | { | ||
46 | .file = "recall_delegations", | ||
47 | .forget = nfsd_recall_client_delegations, | ||
48 | .print = nfsd_print_client_delegations, | ||
49 | }, | ||
50 | }; | ||
51 | |||
52 | static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op); | ||
53 | static struct dentry *debug_dir; | 25 | static struct dentry *debug_dir; |
54 | 26 | ||
55 | static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val) | ||
56 | { | ||
57 | u64 count = 0; | ||
58 | |||
59 | if (val == 0) | ||
60 | printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file); | ||
61 | else | ||
62 | printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); | ||
63 | |||
64 | nfs4_lock_state(); | ||
65 | count = nfsd_for_n_state(val, op->forget); | ||
66 | nfs4_unlock_state(); | ||
67 | printk(KERN_INFO "NFSD: %s: found %llu", op->file, count); | ||
68 | } | ||
69 | |||
70 | static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op, | ||
71 | struct sockaddr_storage *addr, | ||
72 | size_t addr_size) | ||
73 | { | ||
74 | char buf[INET6_ADDRSTRLEN]; | ||
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 | |||
88 | static 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(); | ||
93 | } | ||
94 | |||
95 | static ssize_t fault_inject_read(struct file *file, char __user *buf, | 27 | static ssize_t fault_inject_read(struct file *file, char __user *buf, |
96 | size_t len, loff_t *ppos) | 28 | size_t len, loff_t *ppos) |
97 | { | 29 | { |
@@ -99,9 +31,10 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf, | |||
99 | char read_buf[25]; | 31 | char read_buf[25]; |
100 | size_t size; | 32 | size_t size; |
101 | loff_t pos = *ppos; | 33 | loff_t pos = *ppos; |
34 | struct nfsd_fault_inject_op *op = file_inode(file)->i_private; | ||
102 | 35 | ||
103 | if (!pos) | 36 | if (!pos) |
104 | nfsd_inject_get(file_inode(file)->i_private, &val); | 37 | val = op->get(); |
105 | size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val); | 38 | size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val); |
106 | 39 | ||
107 | return simple_read_from_buffer(buf, len, ppos, read_buf, size); | 40 | return simple_read_from_buffer(buf, len, ppos, read_buf, size); |
@@ -114,18 +47,36 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf, | |||
114 | size_t size = min(sizeof(write_buf) - 1, len); | 47 | size_t size = min(sizeof(write_buf) - 1, len); |
115 | struct net *net = current->nsproxy->net_ns; | 48 | struct net *net = current->nsproxy->net_ns; |
116 | struct sockaddr_storage sa; | 49 | struct sockaddr_storage sa; |
50 | struct nfsd_fault_inject_op *op = file_inode(file)->i_private; | ||
117 | u64 val; | 51 | u64 val; |
52 | char *nl; | ||
118 | 53 | ||
119 | if (copy_from_user(write_buf, buf, size)) | 54 | if (copy_from_user(write_buf, buf, size)) |
120 | return -EFAULT; | 55 | return -EFAULT; |
121 | write_buf[size] = '\0'; | 56 | write_buf[size] = '\0'; |
122 | 57 | ||
58 | /* Deal with any embedded newlines in the string */ | ||
59 | nl = strchr(write_buf, '\n'); | ||
60 | if (nl) { | ||
61 | size = nl - write_buf; | ||
62 | *nl = '\0'; | ||
63 | } | ||
64 | |||
123 | size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa)); | 65 | size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa)); |
124 | if (size > 0) | 66 | if (size > 0) { |
125 | nfsd_inject_set_client(file_inode(file)->i_private, &sa, size); | 67 | val = op->set_clnt(&sa, size); |
126 | else { | 68 | if (val) |
69 | pr_info("NFSD [%s]: Client %s had %llu state object(s)\n", | ||
70 | op->file, write_buf, val); | ||
71 | } else { | ||
127 | val = simple_strtoll(write_buf, NULL, 0); | 72 | val = simple_strtoll(write_buf, NULL, 0); |
128 | nfsd_inject_set(file_inode(file)->i_private, val); | 73 | if (val == 0) |
74 | pr_info("NFSD Fault Injection: %s (all)", op->file); | ||
75 | else | ||
76 | pr_info("NFSD Fault Injection: %s (n = %llu)", | ||
77 | op->file, val); | ||
78 | val = op->set_val(val); | ||
79 | pr_info("NFSD: %s: found %llu", op->file, val); | ||
129 | } | 80 | } |
130 | return len; /* on success, claim we got the whole input */ | 81 | return len; /* on success, claim we got the whole input */ |
131 | } | 82 | } |
@@ -141,6 +92,41 @@ void nfsd_fault_inject_cleanup(void) | |||
141 | debugfs_remove_recursive(debug_dir); | 92 | debugfs_remove_recursive(debug_dir); |
142 | } | 93 | } |
143 | 94 | ||
95 | static struct nfsd_fault_inject_op inject_ops[] = { | ||
96 | { | ||
97 | .file = "forget_clients", | ||
98 | .get = nfsd_inject_print_clients, | ||
99 | .set_val = nfsd_inject_forget_clients, | ||
100 | .set_clnt = nfsd_inject_forget_client, | ||
101 | }, | ||
102 | { | ||
103 | .file = "forget_locks", | ||
104 | .get = nfsd_inject_print_locks, | ||
105 | .set_val = nfsd_inject_forget_locks, | ||
106 | .set_clnt = nfsd_inject_forget_client_locks, | ||
107 | }, | ||
108 | { | ||
109 | .file = "forget_openowners", | ||
110 | .get = nfsd_inject_print_openowners, | ||
111 | .set_val = nfsd_inject_forget_openowners, | ||
112 | .set_clnt = nfsd_inject_forget_client_openowners, | ||
113 | }, | ||
114 | { | ||
115 | .file = "forget_delegations", | ||
116 | .get = nfsd_inject_print_delegations, | ||
117 | .set_val = nfsd_inject_forget_delegations, | ||
118 | .set_clnt = nfsd_inject_forget_client_delegations, | ||
119 | }, | ||
120 | { | ||
121 | .file = "recall_delegations", | ||
122 | .get = nfsd_inject_print_delegations, | ||
123 | .set_val = nfsd_inject_recall_delegations, | ||
124 | .set_clnt = nfsd_inject_recall_client_delegations, | ||
125 | }, | ||
126 | }; | ||
127 | |||
128 | #define NUM_INJECT_OPS (sizeof(inject_ops)/sizeof(struct nfsd_fault_inject_op)) | ||
129 | |||
144 | int nfsd_fault_inject_init(void) | 130 | int nfsd_fault_inject_init(void) |
145 | { | 131 | { |
146 | unsigned int i; | 132 | unsigned int i; |