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
{
20 u64 (*forget
)(struct nfs4_client
*, u64
);
21 u64 (*print
)(struct nfs4_client
*, u64
);
24 static struct nfsd_fault_inject_op inject_ops
[] = {
26 .file
= "forget_clients",
27 .forget
= nfsd_forget_client
,
28 .print
= nfsd_print_client
,
31 .file
= "forget_locks",
32 .forget
= nfsd_forget_client_locks
,
33 .print
= nfsd_print_client_locks
,
36 .file
= "forget_openowners",
37 .forget
= nfsd_forget_client_openowners
,
38 .print
= nfsd_print_client_openowners
,
41 .file
= "forget_delegations",
42 .forget
= nfsd_forget_client_delegations
,
43 .print
= nfsd_print_client_delegations
,
46 .file
= "recall_delegations",
47 .forget
= nfsd_recall_client_delegations
,
48 .print
= nfsd_print_client_delegations
,
52 static long int NUM_INJECT_OPS
= sizeof(inject_ops
) / sizeof(struct nfsd_fault_inject_op
);
53 static struct dentry
*debug_dir
;
55 static void nfsd_inject_set(struct nfsd_fault_inject_op
*op
, u64 val
)
60 printk(KERN_INFO
"NFSD Fault Injection: %s (all)", op
->file
);
62 printk(KERN_INFO
"NFSD Fault Injection: %s (n = %llu)", op
->file
, val
);
65 count
= nfsd_for_n_state(val
, op
->forget
);
67 printk(KERN_INFO
"NFSD: %s: found %llu", op
->file
, count
);
70 static void nfsd_inject_set_client(struct nfsd_fault_inject_op
*op
,
71 struct sockaddr_storage
*addr
,
74 char buf
[INET6_ADDRSTRLEN
];
75 struct nfs4_client
*clp
;
79 clp
= nfsd_find_client(addr
, addr_size
);
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
);
88 static void nfsd_inject_get(struct nfsd_fault_inject_op
*op
, u64
*val
)
91 *val
= nfsd_for_n_state(0, op
->print
);
95 static ssize_t
fault_inject_read(struct file
*file
, char __user
*buf
,
96 size_t len
, loff_t
*ppos
)
104 nfsd_inject_get(file
->f_dentry
->d_inode
->i_private
, &val
);
105 size
= scnprintf(read_buf
, sizeof(read_buf
), "%llu\n", val
);
109 if (pos
>= size
|| !len
)
111 if (len
> size
- pos
)
113 ret
= copy_to_user(buf
, read_buf
+ pos
, len
);
121 static ssize_t
fault_inject_write(struct file
*file
, const char __user
*buf
,
122 size_t len
, loff_t
*ppos
)
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
;
130 if (copy_from_user(write_buf
, buf
, size
))
132 write_buf
[size
] = '\0';
134 size
= rpc_pton(net
, write_buf
, size
, (struct sockaddr
*)&sa
, sizeof(sa
));
136 nfsd_inject_set_client(file
->f_dentry
->d_inode
->i_private
, &sa
, size
);
138 val
= simple_strtoll(write_buf
, NULL
, 0);
139 nfsd_inject_set(file
->f_dentry
->d_inode
->i_private
, val
);
141 return len
; /* on success, claim we got the whole input */
144 static const struct file_operations fops_nfsd
= {
145 .owner
= THIS_MODULE
,
146 .read
= fault_inject_read
,
147 .write
= fault_inject_write
,
150 void nfsd_fault_inject_cleanup(void)
152 debugfs_remove_recursive(debug_dir
);
155 int nfsd_fault_inject_init(void)
158 struct nfsd_fault_inject_op
*op
;
159 umode_t mode
= S_IFREG
| S_IRUSR
| S_IWUSR
;
161 debug_dir
= debugfs_create_dir("nfsd", NULL
);
165 for (i
= 0; i
< NUM_INJECT_OPS
; i
++) {
167 if (!debugfs_create_file(op
->file
, mode
, debug_dir
, op
, &fops_nfsd
))
173 nfsd_fault_inject_cleanup();