aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBryan Schumaker <bjschuma@netapp.com>2011-11-01 13:35:21 -0400
committerJ. Bruce Fields <bfields@redhat.com>2011-11-07 21:10:47 -0500
commit65178db42a02c7984f711614546e97e9952d8e01 (patch)
treebab2974af726bb7be58e9cc7045cdf7c63b041b7 /fs
parent64a284d07c7d84299a90826950079a8ef11e8204 (diff)
NFSD: Added fault injection
Fault injection on the NFS server makes it easier to test the client's state manager and recovery threads. Simulating errors on the server is easier than finding the right conditions that cause them naturally. This patch uses debugfs to add a simple framework for fault injection to the server. This framework is a config option, and can be enabled through CONFIG_NFSD_FAULT_INJECTION. Assuming you have debugfs mounted to /sys/debug, a set of files will be created in /sys/debug/nfsd/. Writing to any of these files will cause the corresponding action and write a log entry to dmesg. Signed-off-by: Bryan Schumaker <bjschuma@netapp.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/Kconfig10
-rw-r--r--fs/nfsd/Makefile1
-rw-r--r--fs/nfsd/fault_inject.c91
-rw-r--r--fs/nfsd/fault_inject.h28
-rw-r--r--fs/nfsd/nfs4state.c115
-rw-r--r--fs/nfsd/nfsctl.c7
6 files changed, 252 insertions, 0 deletions
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 10e6366608f2..8df1ea4a6ff9 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -80,3 +80,13 @@ config NFSD_V4
80 available from http://linux-nfs.org/. 80 available from http://linux-nfs.org/.
81 81
82 If unsure, say N. 82 If unsure, say N.
83
84config NFSD_FAULT_INJECTION
85 bool "NFS server manual fault injection"
86 depends on NFSD_V4 && DEBUG_KERNEL
87 help
88 This option enables support for manually injecting faults
89 into the NFS server. This is intended to be used for
90 testing error recovery on the NFS client.
91
92 If unsure, say N.
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index 9b118ee20193..af32ef06b4fe 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_NFSD) += nfsd.o
6 6
7nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ 7nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
8 export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o 8 export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
9nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o
9nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o 10nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
10nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o 11nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
11nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o 12nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
new file mode 100644
index 000000000000..ce7f0758d84c
--- /dev/null
+++ b/fs/nfsd/fault_inject.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
3 *
4 * Uses debugfs to create fault injection points for client testing
5 */
6
7#include <linux/types.h>
8#include <linux/fs.h>
9#include <linux/debugfs.h>
10#include <linux/module.h>
11
12#include "state.h"
13#include "fault_inject.h"
14
15struct nfsd_fault_inject_op {
16 char *file;
17 void (*func)(u64);
18};
19
20static struct nfsd_fault_inject_op inject_ops[] = {
21 {
22 .file = "forget_clients",
23 .func = nfsd_forget_clients,
24 },
25 {
26 .file = "forget_locks",
27 .func = nfsd_forget_locks,
28 },
29 {
30 .file = "forget_openowners",
31 .func = nfsd_forget_openowners,
32 },
33 {
34 .file = "forget_delegations",
35 .func = nfsd_forget_delegations,
36 },
37 {
38 .file = "recall_delegations",
39 .func = nfsd_recall_delegations,
40 },
41};
42
43static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
44static struct dentry *debug_dir;
45
46static int nfsd_inject_set(void *op_ptr, u64 val)
47{
48 struct nfsd_fault_inject_op *op = op_ptr;
49
50 if (val == 0)
51 printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
52 else
53 printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
54
55 op->func(val);
56 return 0;
57}
58
59static int nfsd_inject_get(void *data, u64 *val)
60{
61 return 0;
62}
63
64DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n");
65
66void nfsd_fault_inject_cleanup(void)
67{
68 debugfs_remove_recursive(debug_dir);
69}
70
71int nfsd_fault_inject_init(void)
72{
73 unsigned int i;
74 struct nfsd_fault_inject_op *op;
75 mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
76
77 debug_dir = debugfs_create_dir("nfsd", NULL);
78 if (!debug_dir)
79 goto fail;
80
81 for (i = 0; i < NUM_INJECT_OPS; i++) {
82 op = &inject_ops[i];
83 if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
84 goto fail;
85 }
86 return 0;
87
88fail:
89 nfsd_fault_inject_cleanup();
90 return -ENOMEM;
91}
diff --git a/fs/nfsd/fault_inject.h b/fs/nfsd/fault_inject.h
new file mode 100644
index 000000000000..90bd0570956c
--- /dev/null
+++ b/fs/nfsd/fault_inject.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
3 *
4 * Function definitions for fault injection
5 */
6
7#ifndef LINUX_NFSD_FAULT_INJECT_H
8#define LINUX_NFSD_FAULT_INJECT_H
9
10#ifdef CONFIG_NFSD_FAULT_INJECTION
11int nfsd_fault_inject_init(void);
12void nfsd_fault_inject_cleanup(void);
13void nfsd_forget_clients(u64);
14void nfsd_forget_locks(u64);
15void nfsd_forget_openowners(u64);
16void nfsd_forget_delegations(u64);
17void nfsd_recall_delegations(u64);
18#else /* CONFIG_NFSD_FAULT_INJECTION */
19static inline int nfsd_fault_inject_init(void) { return 0; }
20static inline void nfsd_fault_inject_cleanup(void) {}
21static inline void nfsd_forget_clients(u64 num) {}
22static inline void nfsd_forget_locks(u64 num) {}
23static inline void nfsd_forget_openowners(u64 num) {}
24static inline void nfsd_forget_delegations(u64 num) {}
25static inline void nfsd_recall_delegations(u64 num) {}
26#endif /* CONFIG_NFSD_FAULT_INJECTION */
27
28#endif /* LINUX_NFSD_FAULT_INJECT_H */
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d09d5242c088..a511eff05698 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4429,6 +4429,121 @@ nfs4_check_open_reclaim(clientid_t *clid)
4429 return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; 4429 return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
4430} 4430}
4431 4431
4432#ifdef CONFIG_NFSD_FAULT_INJECTION
4433
4434void nfsd_forget_clients(u64 num)
4435{
4436 struct nfs4_client *clp, *next;
4437 int count = 0;
4438
4439 nfs4_lock_state();
4440 list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
4441 nfsd4_remove_clid_dir(clp);
4442 expire_client(clp);
4443 if (++count == num)
4444 break;
4445 }
4446 nfs4_unlock_state();
4447
4448 printk(KERN_INFO "NFSD: Forgot %d clients", count);
4449}
4450
4451static void release_lockowner_sop(struct nfs4_stateowner *sop)
4452{
4453 release_lockowner(lockowner(sop));
4454}
4455
4456static void release_openowner_sop(struct nfs4_stateowner *sop)
4457{
4458 release_openowner(openowner(sop));
4459}
4460
4461static int nfsd_release_n_owners(u64 num,
4462 struct list_head hashtbl[],
4463 unsigned int hashtbl_size,
4464 void (*release_sop)(struct nfs4_stateowner *))
4465{
4466 int i, count = 0;
4467 struct nfs4_stateowner *sop, *next;
4468
4469 for (i = 0; i < hashtbl_size; i++) {
4470 list_for_each_entry_safe(sop, next, &hashtbl[i], so_strhash) {
4471 release_sop(sop);
4472 if (++count == num)
4473 return count;
4474 }
4475 }
4476 return count;
4477}
4478
4479void nfsd_forget_locks(u64 num)
4480{
4481 int count;
4482
4483 nfs4_lock_state();
4484 count = nfsd_release_n_owners(num, lock_ownerstr_hashtbl,
4485 LOCK_HASH_SIZE, release_lockowner_sop);
4486 nfs4_unlock_state();
4487
4488 printk(KERN_INFO "NFSD: Forgot %d locks", count);
4489}
4490
4491void nfsd_forget_openowners(u64 num)
4492{
4493 int count;
4494
4495 nfs4_lock_state();
4496 count = nfsd_release_n_owners(num, open_ownerstr_hashtbl,
4497 OPEN_OWNER_HASH_SIZE, release_openowner_sop);
4498 nfs4_unlock_state();
4499
4500 printk(KERN_INFO "NFSD: Forgot %d open owners", count);
4501}
4502
4503int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *))
4504{
4505 int i, count = 0;
4506 struct nfs4_file *fp;
4507 struct nfs4_delegation *dp, *next;
4508
4509 for (i = 0; i < FILE_HASH_SIZE; i++) {
4510 list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
4511 list_for_each_entry_safe(dp, next, &fp->fi_delegations, dl_perfile) {
4512 deleg_func(dp);
4513 if (++count == num)
4514 return count;
4515 }
4516 }
4517 }
4518 return count;
4519}
4520
4521void nfsd_forget_delegations(u64 num)
4522{
4523 unsigned int count;
4524
4525 nfs4_lock_state();
4526 count = nfsd_process_n_delegations(num, unhash_delegation);
4527 nfs4_unlock_state();
4528
4529 printk(KERN_INFO "NFSD: Forgot %d delegations", count);
4530}
4531
4532void nfsd_recall_delegations(u64 num)
4533{
4534 unsigned int count;
4535
4536 nfs4_lock_state();
4537 spin_lock(&recall_lock);
4538 count = nfsd_process_n_delegations(num, nfsd_break_one_deleg);
4539 spin_unlock(&recall_lock);
4540 nfs4_unlock_state();
4541
4542 printk(KERN_INFO "NFSD: Recalled %d delegations", count);
4543}
4544
4545#endif /* CONFIG_NFSD_FAULT_INJECTION */
4546
4432/* initialization to perform at module load time: */ 4547/* initialization to perform at module load time: */
4433 4548
4434int 4549int
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c45a2ea4a090..b2e8093ebc21 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -18,6 +18,7 @@
18#include "idmap.h" 18#include "idmap.h"
19#include "nfsd.h" 19#include "nfsd.h"
20#include "cache.h" 20#include "cache.h"
21#include "fault_inject.h"
21 22
22/* 23/*
23 * We have a single directory with several nodes in it. 24 * We have a single directory with several nodes in it.
@@ -1131,6 +1132,9 @@ static int __init init_nfsd(void)
1131 retval = nfs4_state_init(); /* nfs4 locking state */ 1132 retval = nfs4_state_init(); /* nfs4 locking state */
1132 if (retval) 1133 if (retval)
1133 return retval; 1134 return retval;
1135 retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
1136 if (retval)
1137 goto out_free_slabs;
1134 nfsd_stat_init(); /* Statistics */ 1138 nfsd_stat_init(); /* Statistics */
1135 retval = nfsd_reply_cache_init(); 1139 retval = nfsd_reply_cache_init();
1136 if (retval) 1140 if (retval)
@@ -1161,6 +1165,8 @@ out_free_cache:
1161 nfsd_reply_cache_shutdown(); 1165 nfsd_reply_cache_shutdown();
1162out_free_stat: 1166out_free_stat:
1163 nfsd_stat_shutdown(); 1167 nfsd_stat_shutdown();
1168 nfsd_fault_inject_cleanup();
1169out_free_slabs:
1164 nfsd4_free_slabs(); 1170 nfsd4_free_slabs();
1165 return retval; 1171 return retval;
1166} 1172}
@@ -1175,6 +1181,7 @@ static void __exit exit_nfsd(void)
1175 nfsd_lockd_shutdown(); 1181 nfsd_lockd_shutdown();
1176 nfsd_idmap_shutdown(); 1182 nfsd_idmap_shutdown();
1177 nfsd4_free_slabs(); 1183 nfsd4_free_slabs();
1184 nfsd_fault_inject_cleanup();
1178 unregister_filesystem(&nfsd_fs_type); 1185 unregister_filesystem(&nfsd_fs_type);
1179} 1186}
1180 1187