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>
19 struct nfsd_fault_inject_op
{
23 u64 (*set_clnt
)(struct sockaddr_storage
*, size_t);
26 static struct dentry
*debug_dir
;
28 static ssize_t
fault_inject_read(struct file
*file
, char __user
*buf
,
29 size_t len
, loff_t
*ppos
)
35 struct nfsd_fault_inject_op
*op
= file_inode(file
)->i_private
;
39 size
= scnprintf(read_buf
, sizeof(read_buf
), "%llu\n", val
);
41 return simple_read_from_buffer(buf
, len
, ppos
, read_buf
, size
);
44 static ssize_t
fault_inject_write(struct file
*file
, const char __user
*buf
,
45 size_t len
, loff_t
*ppos
)
47 char write_buf
[INET6_ADDRSTRLEN
];
48 size_t size
= min(sizeof(write_buf
) - 1, len
);
49 struct net
*net
= current
->nsproxy
->net_ns
;
50 struct sockaddr_storage sa
;
51 struct nfsd_fault_inject_op
*op
= file_inode(file
)->i_private
;
55 if (copy_from_user(write_buf
, buf
, size
))
57 write_buf
[size
] = '\0';
59 /* Deal with any embedded newlines in the string */
60 nl
= strchr(write_buf
, '\n');
62 size
= nl
- write_buf
;
66 size
= rpc_pton(net
, write_buf
, size
, (struct sockaddr
*)&sa
, sizeof(sa
));
68 val
= op
->set_clnt(&sa
, size
);
70 pr_info("NFSD [%s]: Client %s had %llu state object(s)\n",
71 op
->file
, write_buf
, val
);
73 val
= simple_strtoll(write_buf
, NULL
, 0);
75 pr_info("NFSD Fault Injection: %s (all)", op
->file
);
77 pr_info("NFSD Fault Injection: %s (n = %llu)",
79 val
= op
->set_val(val
);
80 pr_info("NFSD: %s: found %llu", op
->file
, val
);
82 return len
; /* on success, claim we got the whole input */
85 static const struct file_operations fops_nfsd
= {
87 .read
= fault_inject_read
,
88 .write
= fault_inject_write
,
91 void nfsd_fault_inject_cleanup(void)
93 debugfs_remove_recursive(debug_dir
);
96 static struct nfsd_fault_inject_op inject_ops
[] = {
98 .file
= "forget_clients",
99 .get
= nfsd_inject_print_clients
,
100 .set_val
= nfsd_inject_forget_clients
,
101 .set_clnt
= nfsd_inject_forget_client
,
104 .file
= "forget_locks",
105 .get
= nfsd_inject_print_locks
,
106 .set_val
= nfsd_inject_forget_locks
,
107 .set_clnt
= nfsd_inject_forget_client_locks
,
110 .file
= "forget_openowners",
111 .get
= nfsd_inject_print_openowners
,
112 .set_val
= nfsd_inject_forget_openowners
,
113 .set_clnt
= nfsd_inject_forget_client_openowners
,
116 .file
= "forget_delegations",
117 .get
= nfsd_inject_print_delegations
,
118 .set_val
= nfsd_inject_forget_delegations
,
119 .set_clnt
= nfsd_inject_forget_client_delegations
,
122 .file
= "recall_delegations",
123 .get
= nfsd_inject_print_delegations
,
124 .set_val
= nfsd_inject_recall_delegations
,
125 .set_clnt
= nfsd_inject_recall_client_delegations
,
129 #define NUM_INJECT_OPS (sizeof(inject_ops)/sizeof(struct nfsd_fault_inject_op))
131 int nfsd_fault_inject_init(void)
134 struct nfsd_fault_inject_op
*op
;
135 umode_t mode
= S_IFREG
| S_IRUSR
| S_IWUSR
;
137 debug_dir
= debugfs_create_dir("nfsd", NULL
);
141 for (i
= 0; i
< NUM_INJECT_OPS
; i
++) {
143 if (!debugfs_create_file(op
->file
, mode
, debug_dir
, op
, &fops_nfsd
))
149 nfsd_fault_inject_cleanup();