2 * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
4 * Uses debugfs to create fault injection points for client testing
7 #include <linux/types.h>
9 #include <linux/debugfs.h>
10 #include <linux/module.h>
11 #include <linux/nsproxy.h>
12 #include <linux/sunrpc/addr.h>
13 #include <asm/uaccess.h>
18 struct nfsd_fault_inject_op
{
22 u64 (*set_clnt
)(struct sockaddr_storage
*, size_t);
25 static struct dentry
*debug_dir
;
27 static ssize_t
fault_inject_read(struct file
*file
, char __user
*buf
,
28 size_t len
, loff_t
*ppos
)
34 struct nfsd_fault_inject_op
*op
= file_inode(file
)->i_private
;
38 size
= scnprintf(read_buf
, sizeof(read_buf
), "%llu\n", val
);
40 return simple_read_from_buffer(buf
, len
, ppos
, read_buf
, size
);
43 static ssize_t
fault_inject_write(struct file
*file
, const char __user
*buf
,
44 size_t len
, loff_t
*ppos
)
46 char write_buf
[INET6_ADDRSTRLEN
];
47 size_t size
= min(sizeof(write_buf
) - 1, len
);
48 struct net
*net
= current
->nsproxy
->net_ns
;
49 struct sockaddr_storage sa
;
50 struct nfsd_fault_inject_op
*op
= file_inode(file
)->i_private
;
54 if (copy_from_user(write_buf
, buf
, size
))
56 write_buf
[size
] = '\0';
58 /* Deal with any embedded newlines in the string */
59 nl
= strchr(write_buf
, '\n');
61 size
= nl
- write_buf
;
65 size
= rpc_pton(net
, write_buf
, size
, (struct sockaddr
*)&sa
, sizeof(sa
));
67 val
= op
->set_clnt(&sa
, size
);
69 pr_info("NFSD [%s]: Client %s had %llu state object(s)\n",
70 op
->file
, write_buf
, val
);
72 val
= simple_strtoll(write_buf
, NULL
, 0);
74 pr_info("NFSD Fault Injection: %s (all)", op
->file
);
76 pr_info("NFSD Fault Injection: %s (n = %llu)",
78 val
= op
->set_val(val
);
79 pr_info("NFSD: %s: found %llu", op
->file
, val
);
81 return len
; /* on success, claim we got the whole input */
84 static const struct file_operations fops_nfsd
= {
86 .read
= fault_inject_read
,
87 .write
= fault_inject_write
,
90 void nfsd_fault_inject_cleanup(void)
92 debugfs_remove_recursive(debug_dir
);
95 static struct nfsd_fault_inject_op inject_ops
[] = {
97 .file
= "forget_clients",
98 .get
= nfsd_inject_print_clients
,
99 .set_val
= nfsd_inject_forget_clients
,
100 .set_clnt
= nfsd_inject_forget_client
,
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
,
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
,
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
,
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
,
128 #define NUM_INJECT_OPS (sizeof(inject_ops)/sizeof(struct nfsd_fault_inject_op))
130 int nfsd_fault_inject_init(void)
133 struct nfsd_fault_inject_op
*op
;
134 umode_t mode
= S_IFREG
| S_IRUSR
| S_IWUSR
;
136 debug_dir
= debugfs_create_dir("nfsd", NULL
);
140 for (i
= 0; i
< NUM_INJECT_OPS
; i
++) {
142 if (!debugfs_create_file(op
->file
, mode
, debug_dir
, op
, &fops_nfsd
))
148 nfsd_fault_inject_cleanup();