diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/Kconfig | 10 | ||||
-rw-r--r-- | fs/nfsd/Makefile | 1 | ||||
-rw-r--r-- | fs/nfsd/fault_inject.c | 91 | ||||
-rw-r--r-- | fs/nfsd/fault_inject.h | 28 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 115 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 7 |
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 | |||
84 | config 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 | ||
7 | nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ | 7 | nfsd-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 |
9 | nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o | ||
9 | nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o | 10 | nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o |
10 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o | 11 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o |
11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o | 12 | nfsd-$(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 | |||
15 | struct nfsd_fault_inject_op { | ||
16 | char *file; | ||
17 | void (*func)(u64); | ||
18 | }; | ||
19 | |||
20 | static 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 | |||
43 | static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op); | ||
44 | static struct dentry *debug_dir; | ||
45 | |||
46 | static 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 | |||
59 | static int nfsd_inject_get(void *data, u64 *val) | ||
60 | { | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n"); | ||
65 | |||
66 | void nfsd_fault_inject_cleanup(void) | ||
67 | { | ||
68 | debugfs_remove_recursive(debug_dir); | ||
69 | } | ||
70 | |||
71 | int 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 | |||
88 | fail: | ||
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 | ||
11 | int nfsd_fault_inject_init(void); | ||
12 | void nfsd_fault_inject_cleanup(void); | ||
13 | void nfsd_forget_clients(u64); | ||
14 | void nfsd_forget_locks(u64); | ||
15 | void nfsd_forget_openowners(u64); | ||
16 | void nfsd_forget_delegations(u64); | ||
17 | void nfsd_recall_delegations(u64); | ||
18 | #else /* CONFIG_NFSD_FAULT_INJECTION */ | ||
19 | static inline int nfsd_fault_inject_init(void) { return 0; } | ||
20 | static inline void nfsd_fault_inject_cleanup(void) {} | ||
21 | static inline void nfsd_forget_clients(u64 num) {} | ||
22 | static inline void nfsd_forget_locks(u64 num) {} | ||
23 | static inline void nfsd_forget_openowners(u64 num) {} | ||
24 | static inline void nfsd_forget_delegations(u64 num) {} | ||
25 | static 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 | |||
4434 | void 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 | |||
4451 | static void release_lockowner_sop(struct nfs4_stateowner *sop) | ||
4452 | { | ||
4453 | release_lockowner(lockowner(sop)); | ||
4454 | } | ||
4455 | |||
4456 | static void release_openowner_sop(struct nfs4_stateowner *sop) | ||
4457 | { | ||
4458 | release_openowner(openowner(sop)); | ||
4459 | } | ||
4460 | |||
4461 | static 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 | |||
4479 | void 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 | |||
4491 | void 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 | |||
4503 | int 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 | |||
4521 | void 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 | |||
4532 | void 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 | ||
4434 | int | 4549 | int |
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(); |
1162 | out_free_stat: | 1166 | out_free_stat: |
1163 | nfsd_stat_shutdown(); | 1167 | nfsd_stat_shutdown(); |
1168 | nfsd_fault_inject_cleanup(); | ||
1169 | out_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 | ||