1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
5 * Uses debugfs to create fault injection points for client testing
8 #include <linux/types.h>
10 #include <linux/debugfs.h>
11 #include <linux/module.h>
12 #include <linux/nsproxy.h>
13 #include <linux/sunrpc/addr.h>
14 #include <linux/uaccess.h>
15 #include <linux/kernel.h>
20 struct nfsd_fault_inject_op
{
24 u64 (*set_clnt
)(struct sockaddr_storage
*, size_t);
27 static struct dentry
*debug_dir
;
29 static ssize_t
fault_inject_read(struct file
*file
, char __user
*buf
,
30 size_t len
, loff_t
*ppos
)
36 struct nfsd_fault_inject_op
*op
= file_inode(file
)->i_private
;
40 size
= scnprintf(read_buf
, sizeof(read_buf
), "%llu\n", val
);
42 return simple_read_from_buffer(buf
, len
, ppos
, read_buf
, size
);
45 static ssize_t
fault_inject_write(struct file
*file
, const char __user
*buf
,
46 size_t len
, loff_t
*ppos
)
48 char write_buf
[INET6_ADDRSTRLEN
];
49 size_t size
= min(sizeof(write_buf
) - 1, len
);
50 struct net
*net
= current
->nsproxy
->net_ns
;
51 struct sockaddr_storage sa
;
52 struct nfsd_fault_inject_op
*op
= file_inode(file
)->i_private
;
56 if (copy_from_user(write_buf
, buf
, size
))
58 write_buf
[size
] = '\0';
60 /* Deal with any embedded newlines in the string */
61 nl
= strchr(write_buf
, '\n');
63 size
= nl
- write_buf
;
67 size
= rpc_pton(net
, write_buf
, size
, (struct sockaddr
*)&sa
, sizeof(sa
));
69 val
= op
->set_clnt(&sa
, size
);
71 pr_info("NFSD [%s]: Client %s had %llu state object(s)\n",
72 op
->file
, write_buf
, val
);
74 val
= simple_strtoll(write_buf
, NULL
, 0);
76 pr_info("NFSD Fault Injection: %s (all)", op
->file
);
78 pr_info("NFSD Fault Injection: %s (n = %llu)",
80 val
= op
->set_val(val
);
81 pr_info("NFSD: %s: found %llu", op
->file
, val
);
83 return len
; /* on success, claim we got the whole input */
86 static const struct file_operations fops_nfsd
= {
88 .read
= fault_inject_read
,
89 .write
= fault_inject_write
,
92 void nfsd_fault_inject_cleanup(void)
94 debugfs_remove_recursive(debug_dir
);
97 static struct nfsd_fault_inject_op inject_ops
[] = {
99 .file
= "forget_clients",
100 .get
= nfsd_inject_print_clients
,
101 .set_val
= nfsd_inject_forget_clients
,
102 .set_clnt
= nfsd_inject_forget_client
,
105 .file
= "forget_locks",
106 .get
= nfsd_inject_print_locks
,
107 .set_val
= nfsd_inject_forget_locks
,
108 .set_clnt
= nfsd_inject_forget_client_locks
,
111 .file
= "forget_openowners",
112 .get
= nfsd_inject_print_openowners
,
113 .set_val
= nfsd_inject_forget_openowners
,
114 .set_clnt
= nfsd_inject_forget_client_openowners
,
117 .file
= "forget_delegations",
118 .get
= nfsd_inject_print_delegations
,
119 .set_val
= nfsd_inject_forget_delegations
,
120 .set_clnt
= nfsd_inject_forget_client_delegations
,
123 .file
= "recall_delegations",
124 .get
= nfsd_inject_print_delegations
,
125 .set_val
= nfsd_inject_recall_delegations
,
126 .set_clnt
= nfsd_inject_recall_client_delegations
,
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
< ARRAY_SIZE(inject_ops
); i
++) {
142 if (!debugfs_create_file(op
->file
, mode
, debug_dir
, op
, &fops_nfsd
))
148 nfsd_fault_inject_cleanup();