aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS5
-rw-r--r--Documentation/filesystems/nfs/00-INDEX2
-rw-r--r--Documentation/filesystems/nfs/fault_injection.txt69
-rw-r--r--MAINTAINERS1
-rw-r--r--fs/nfsd/Kconfig10
-rw-r--r--fs/nfsd/Makefile1
-rw-r--r--fs/nfsd/export.c12
-rw-r--r--fs/nfsd/fault_inject.c91
-rw-r--r--fs/nfsd/fault_inject.h28
-rw-r--r--fs/nfsd/nfs4idmap.c11
-rw-r--r--fs/nfsd/nfs4proc.c7
-rw-r--r--fs/nfsd/nfs4recover.c22
-rw-r--r--fs/nfsd/nfs4state.c328
-rw-r--r--fs/nfsd/nfs4xdr.c3
-rw-r--r--fs/nfsd/nfsctl.c10
-rw-r--r--fs/nfsd/nfsd.h20
-rw-r--r--fs/nfsd/state.h3
-rw-r--r--fs/nfsd/vfs.c17
-rw-r--r--include/linux/sunrpc/svc_xprt.h3
-rw-r--r--include/linux/sunrpc/svcsock.h2
-rw-r--r--net/sunrpc/cache.c2
-rw-r--r--net/sunrpc/svc.c25
-rw-r--r--net/sunrpc/svc_xprt.c62
-rw-r--r--net/sunrpc/svcsock.c8
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c2
-rwxr-xr-xtools/nfsd/inject_fault.sh49
26 files changed, 624 insertions, 169 deletions
diff --git a/CREDITS b/CREDITS
index 44fce988eaac..370b4c7da39b 100644
--- a/CREDITS
+++ b/CREDITS
@@ -514,6 +514,11 @@ S: Bessemerstraat 21
514S: Amsterdam 514S: Amsterdam
515S: The Netherlands 515S: The Netherlands
516 516
517N: NeilBrown
518E: neil@brown.name
519P: 4096R/566281B9 1BC6 29EB D390 D870 7B5F 497A 39EC 9EDD 5662 81B9
520D: NFSD Maintainer 2000-2007
521
517N: Zach Brown 522N: Zach Brown
518E: zab@zabbo.net 523E: zab@zabbo.net
519D: maestro pci sound 524D: maestro pci sound
diff --git a/Documentation/filesystems/nfs/00-INDEX b/Documentation/filesystems/nfs/00-INDEX
index a57e12411d2a..1716874a651e 100644
--- a/Documentation/filesystems/nfs/00-INDEX
+++ b/Documentation/filesystems/nfs/00-INDEX
@@ -2,6 +2,8 @@
2 - this file (nfs-related documentation). 2 - this file (nfs-related documentation).
3Exporting 3Exporting
4 - explanation of how to make filesystems exportable. 4 - explanation of how to make filesystems exportable.
5fault_injection.txt
6 - information for using fault injection on the server
5knfsd-stats.txt 7knfsd-stats.txt
6 - statistics which the NFS server makes available to user space. 8 - statistics which the NFS server makes available to user space.
7nfs.txt 9nfs.txt
diff --git a/Documentation/filesystems/nfs/fault_injection.txt b/Documentation/filesystems/nfs/fault_injection.txt
new file mode 100644
index 000000000000..426d166089a3
--- /dev/null
+++ b/Documentation/filesystems/nfs/fault_injection.txt
@@ -0,0 +1,69 @@
1
2Fault Injection
3===============
4Fault injection is a method for forcing errors that may not normally occur, or
5may be difficult to reproduce. Forcing these errors in a controlled environment
6can help the developer find and fix bugs before their code is shipped in a
7production system. Injecting an error on the Linux NFS server will allow us to
8observe how the client reacts and if it manages to recover its state correctly.
9
10NFSD_FAULT_INJECTION must be selected when configuring the kernel to use this
11feature.
12
13
14Using Fault Injection
15=====================
16On the client, mount the fault injection server through NFS v4.0+ and do some
17work over NFS (open files, take locks, ...).
18
19On the server, mount the debugfs filesystem to <debug_dir> and ls
20<debug_dir>/nfsd. This will show a list of files that will be used for
21injecting faults on the NFS server. As root, write a number n to the file
22corresponding to the action you want the server to take. The server will then
23process the first n items it finds. So if you want to forget 5 locks, echo '5'
24to <debug_dir>/nfsd/forget_locks. A value of 0 will tell the server to forget
25all corresponding items. A log message will be created containing the number
26of items forgotten (check dmesg).
27
28Go back to work on the client and check if the client recovered from the error
29correctly.
30
31
32Available Faults
33================
34forget_clients:
35 The NFS server keeps a list of clients that have placed a mount call. If
36 this list is cleared, the server will have no knowledge of who the client
37 is, forcing the client to reauthenticate with the server.
38
39forget_openowners:
40 The NFS server keeps a list of what files are currently opened and who
41 they were opened by. Clearing this list will force the client to reopen
42 its files.
43
44forget_locks:
45 The NFS server keeps a list of what files are currently locked in the VFS.
46 Clearing this list will force the client to reclaim its locks (files are
47 unlocked through the VFS as they are cleared from this list).
48
49forget_delegations:
50 A delegation is used to assure the client that a file, or part of a file,
51 has not changed since the delegation was awarded. Clearing this list will
52 force the client to reaquire its delegation before accessing the file
53 again.
54
55recall_delegations:
56 Delegations can be recalled by the server when another client attempts to
57 access a file. This test will notify the client that its delegation has
58 been revoked, forcing the client to reaquire the delegation before using
59 the file again.
60
61
62tools/nfs/inject_faults.sh script
63=================================
64This script has been created to ease the fault injection process. This script
65will detect the mounted debugfs directory and write to the files located there
66based on the arguments passed by the user. For example, running
67`inject_faults.sh forget_locks 1` as root will instruct the server to forget
68one lock. Running `inject_faults forget_locks` will instruct the server to
69forgetall locks.
diff --git a/MAINTAINERS b/MAINTAINERS
index 7559c1ca56ba..4d1ba2022a95 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3775,7 +3775,6 @@ S: Odd Fixes
3775 3775
3776KERNEL NFSD, SUNRPC, AND LOCKD SERVERS 3776KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
3777M: "J. Bruce Fields" <bfields@fieldses.org> 3777M: "J. Bruce Fields" <bfields@fieldses.org>
3778M: Neil Brown <neilb@suse.de>
3779L: linux-nfs@vger.kernel.org 3778L: linux-nfs@vger.kernel.org
3780W: http://nfs.sourceforge.net/ 3779W: http://nfs.sourceforge.net/
3781S: Supported 3780S: Supported
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/export.c b/fs/nfsd/export.c
index 62f3b9074e84..cf8a6bd062fa 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -87,7 +87,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
87 struct svc_expkey key; 87 struct svc_expkey key;
88 struct svc_expkey *ek = NULL; 88 struct svc_expkey *ek = NULL;
89 89
90 if (mesg[mlen-1] != '\n') 90 if (mlen < 1 || mesg[mlen-1] != '\n')
91 return -EINVAL; 91 return -EINVAL;
92 mesg[mlen-1] = 0; 92 mesg[mlen-1] = 0;
93 93
@@ -1226,12 +1226,12 @@ nfsd_export_init(void)
1226 int rv; 1226 int rv;
1227 dprintk("nfsd: initializing export module.\n"); 1227 dprintk("nfsd: initializing export module.\n");
1228 1228
1229 rv = cache_register(&svc_export_cache); 1229 rv = cache_register_net(&svc_export_cache, &init_net);
1230 if (rv) 1230 if (rv)
1231 return rv; 1231 return rv;
1232 rv = cache_register(&svc_expkey_cache); 1232 rv = cache_register_net(&svc_expkey_cache, &init_net);
1233 if (rv) 1233 if (rv)
1234 cache_unregister(&svc_export_cache); 1234 cache_unregister_net(&svc_export_cache, &init_net);
1235 return rv; 1235 return rv;
1236 1236
1237} 1237}
@@ -1255,8 +1255,8 @@ nfsd_export_shutdown(void)
1255 1255
1256 dprintk("nfsd: shutting down export module.\n"); 1256 dprintk("nfsd: shutting down export module.\n");
1257 1257
1258 cache_unregister(&svc_expkey_cache); 1258 cache_unregister_net(&svc_expkey_cache, &init_net);
1259 cache_unregister(&svc_export_cache); 1259 cache_unregister_net(&svc_export_cache, &init_net);
1260 svcauth_unix_purge(); 1260 svcauth_unix_purge();
1261 1261
1262 dprintk("nfsd: export shutdown complete.\n"); 1262 dprintk("nfsd: export shutdown complete.\n");
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/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 55780a22fdbd..94096273cd6c 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -36,6 +36,7 @@
36#include <linux/seq_file.h> 36#include <linux/seq_file.h>
37#include <linux/sched.h> 37#include <linux/sched.h>
38#include <linux/slab.h> 38#include <linux/slab.h>
39#include <net/net_namespace.h>
39#include "idmap.h" 40#include "idmap.h"
40#include "nfsd.h" 41#include "nfsd.h"
41 42
@@ -466,20 +467,20 @@ nfsd_idmap_init(void)
466{ 467{
467 int rv; 468 int rv;
468 469
469 rv = cache_register(&idtoname_cache); 470 rv = cache_register_net(&idtoname_cache, &init_net);
470 if (rv) 471 if (rv)
471 return rv; 472 return rv;
472 rv = cache_register(&nametoid_cache); 473 rv = cache_register_net(&nametoid_cache, &init_net);
473 if (rv) 474 if (rv)
474 cache_unregister(&idtoname_cache); 475 cache_unregister_net(&idtoname_cache, &init_net);
475 return rv; 476 return rv;
476} 477}
477 478
478void 479void
479nfsd_idmap_shutdown(void) 480nfsd_idmap_shutdown(void)
480{ 481{
481 cache_unregister(&idtoname_cache); 482 cache_unregister_net(&idtoname_cache, &init_net);
482 cache_unregister(&nametoid_cache); 483 cache_unregister_net(&nametoid_cache, &init_net);
483} 484}
484 485
485static int 486static int
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index c5e28ed8bca0..896da74ec563 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -266,10 +266,6 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
266{ 266{
267 __be32 status; 267 __be32 status;
268 268
269 /* Only reclaims from previously confirmed clients are valid */
270 if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
271 return status;
272
273 /* We don't know the target directory, and therefore can not 269 /* We don't know the target directory, and therefore can not
274 * set the change info 270 * set the change info
275 */ 271 */
@@ -373,6 +369,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
373 break; 369 break;
374 case NFS4_OPEN_CLAIM_PREVIOUS: 370 case NFS4_OPEN_CLAIM_PREVIOUS:
375 open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 371 open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
372 status = nfs4_check_open_reclaim(&open->op_clientid);
373 if (status)
374 goto out;
376 case NFS4_OPEN_CLAIM_FH: 375 case NFS4_OPEN_CLAIM_FH:
377 case NFS4_OPEN_CLAIM_DELEG_CUR_FH: 376 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
378 status = do_open_fhandle(rqstp, &cstate->current_fh, 377 status = do_open_fhandle(rqstp, &cstate->current_fh,
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 80a0be9ed008..0b3e875d1abd 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -117,8 +117,7 @@ out_no_tfm:
117 return status; 117 return status;
118} 118}
119 119
120int 120void nfsd4_create_clid_dir(struct nfs4_client *clp)
121nfsd4_create_clid_dir(struct nfs4_client *clp)
122{ 121{
123 const struct cred *original_cred; 122 const struct cred *original_cred;
124 char *dname = clp->cl_recdir; 123 char *dname = clp->cl_recdir;
@@ -127,13 +126,14 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
127 126
128 dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); 127 dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
129 128
130 if (!rec_file || clp->cl_firststate) 129 if (clp->cl_firststate)
131 return 0; 130 return;
132
133 clp->cl_firststate = 1; 131 clp->cl_firststate = 1;
132 if (!rec_file)
133 return;
134 status = nfs4_save_creds(&original_cred); 134 status = nfs4_save_creds(&original_cred);
135 if (status < 0) 135 if (status < 0)
136 return status; 136 return;
137 137
138 dir = rec_file->f_path.dentry; 138 dir = rec_file->f_path.dentry;
139 /* lock the parent */ 139 /* lock the parent */
@@ -144,8 +144,15 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
144 status = PTR_ERR(dentry); 144 status = PTR_ERR(dentry);
145 goto out_unlock; 145 goto out_unlock;
146 } 146 }
147 status = -EEXIST;
148 if (dentry->d_inode) 147 if (dentry->d_inode)
148 /*
149 * In the 4.1 case, where we're called from
150 * reclaim_complete(), records from the previous reboot
151 * may still be left, so this is OK.
152 *
153 * In the 4.0 case, we should never get here; but we may
154 * as well be forgiving and just succeed silently.
155 */
149 goto out_put; 156 goto out_put;
150 status = mnt_want_write_file(rec_file); 157 status = mnt_want_write_file(rec_file);
151 if (status) 158 if (status)
@@ -164,7 +171,6 @@ out_unlock:
164 " and is writeable", status, 171 " and is writeable", status,
165 user_recovery_dirname); 172 user_recovery_dirname);
166 nfs4_reset_creds(original_cred); 173 nfs4_reset_creds(original_cred);
167 return status;
168} 174}
169 175
170typedef int (recdir_func)(struct dentry *, struct dentry *); 176typedef int (recdir_func)(struct dentry *, struct dentry *);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9ca16dc09e04..e8c98f009670 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -49,12 +49,20 @@
49time_t nfsd4_lease = 90; /* default lease time */ 49time_t nfsd4_lease = 90; /* default lease time */
50time_t nfsd4_grace = 90; 50time_t nfsd4_grace = 90;
51static time_t boot_time; 51static time_t boot_time;
52static stateid_t zerostateid; /* bits all 0 */ 52
53static stateid_t onestateid; /* bits all 1 */ 53#define all_ones {{~0,~0},~0}
54static const stateid_t one_stateid = {
55 .si_generation = ~0,
56 .si_opaque = all_ones,
57};
58static const stateid_t zero_stateid = {
59 /* all fields zero */
60};
61
54static u64 current_sessionid = 1; 62static u64 current_sessionid = 1;
55 63
56#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) 64#define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
57#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) 65#define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
58 66
59/* forward declarations */ 67/* forward declarations */
60static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); 68static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
@@ -133,21 +141,21 @@ unsigned int max_delegations;
133 * Open owner state (share locks) 141 * Open owner state (share locks)
134 */ 142 */
135 143
136/* hash tables for open owners */ 144/* hash tables for lock and open owners */
137#define OPEN_OWNER_HASH_BITS 8 145#define OWNER_HASH_BITS 8
138#define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS) 146#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
139#define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1) 147#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
140 148
141static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) 149static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
142{ 150{
143 unsigned int ret; 151 unsigned int ret;
144 152
145 ret = opaque_hashval(ownername->data, ownername->len); 153 ret = opaque_hashval(ownername->data, ownername->len);
146 ret += clientid; 154 ret += clientid;
147 return ret & OPEN_OWNER_HASH_MASK; 155 return ret & OWNER_HASH_MASK;
148} 156}
149 157
150static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE]; 158static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
151 159
152/* hash table for nfs4_file */ 160/* hash table for nfs4_file */
153#define FILE_HASH_BITS 8 161#define FILE_HASH_BITS 8
@@ -514,6 +522,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
514 522
515 list_del(&lo->lo_owner.so_strhash); 523 list_del(&lo->lo_owner.so_strhash);
516 list_del(&lo->lo_perstateid); 524 list_del(&lo->lo_perstateid);
525 list_del(&lo->lo_owner_ino_hash);
517 while (!list_empty(&lo->lo_owner.so_stateids)) { 526 while (!list_empty(&lo->lo_owner.so_stateids)) {
518 stp = list_first_entry(&lo->lo_owner.so_stateids, 527 stp = list_first_entry(&lo->lo_owner.so_stateids,
519 struct nfs4_ol_stateid, st_perstateowner); 528 struct nfs4_ol_stateid, st_perstateowner);
@@ -985,12 +994,11 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
985 clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); 994 clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
986 if (clp == NULL) 995 if (clp == NULL)
987 return NULL; 996 return NULL;
988 clp->cl_name.data = kmalloc(name.len, GFP_KERNEL); 997 clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
989 if (clp->cl_name.data == NULL) { 998 if (clp->cl_name.data == NULL) {
990 kfree(clp); 999 kfree(clp);
991 return NULL; 1000 return NULL;
992 } 1001 }
993 memcpy(clp->cl_name.data, name.data, name.len);
994 clp->cl_name.len = name.len; 1002 clp->cl_name.len = name.len;
995 return clp; 1003 return clp;
996} 1004}
@@ -1058,7 +1066,6 @@ expire_client(struct nfs4_client *clp)
1058 spin_unlock(&recall_lock); 1066 spin_unlock(&recall_lock);
1059 while (!list_empty(&reaplist)) { 1067 while (!list_empty(&reaplist)) {
1060 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 1068 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
1061 list_del_init(&dp->dl_recall_lru);
1062 unhash_delegation(dp); 1069 unhash_delegation(dp);
1063 } 1070 }
1064 while (!list_empty(&clp->cl_openowners)) { 1071 while (!list_empty(&clp->cl_openowners)) {
@@ -2301,7 +2308,7 @@ nfsd4_free_slabs(void)
2301 nfsd4_free_slab(&deleg_slab); 2308 nfsd4_free_slab(&deleg_slab);
2302} 2309}
2303 2310
2304static int 2311int
2305nfsd4_init_slabs(void) 2312nfsd4_init_slabs(void)
2306{ 2313{
2307 openowner_slab = kmem_cache_create("nfsd4_openowners", 2314 openowner_slab = kmem_cache_create("nfsd4_openowners",
@@ -2373,7 +2380,7 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
2373 2380
2374static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 2381static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
2375{ 2382{
2376 list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]); 2383 list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
2377 list_add(&oo->oo_perclient, &clp->cl_openowners); 2384 list_add(&oo->oo_perclient, &clp->cl_openowners);
2378} 2385}
2379 2386
@@ -2436,7 +2443,9 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
2436 struct nfs4_stateowner *so; 2443 struct nfs4_stateowner *so;
2437 struct nfs4_openowner *oo; 2444 struct nfs4_openowner *oo;
2438 2445
2439 list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) { 2446 list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
2447 if (!so->so_is_open_owner)
2448 continue;
2440 if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { 2449 if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
2441 oo = openowner(so); 2450 oo = openowner(so);
2442 renew_client(oo->oo_owner.so_client); 2451 renew_client(oo->oo_owner.so_client);
@@ -2580,7 +2589,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
2580 if (open->op_file == NULL) 2589 if (open->op_file == NULL)
2581 return nfserr_jukebox; 2590 return nfserr_jukebox;
2582 2591
2583 strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner); 2592 strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
2584 oo = find_openstateowner_str(strhashval, open); 2593 oo = find_openstateowner_str(strhashval, open);
2585 open->op_openowner = oo; 2594 open->op_openowner = oo;
2586 if (!oo) { 2595 if (!oo) {
@@ -3123,7 +3132,6 @@ nfs4_laundromat(void)
3123 spin_unlock(&recall_lock); 3132 spin_unlock(&recall_lock);
3124 list_for_each_safe(pos, next, &reaplist) { 3133 list_for_each_safe(pos, next, &reaplist) {
3125 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 3134 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
3126 list_del_init(&dp->dl_recall_lru);
3127 unhash_delegation(dp); 3135 unhash_delegation(dp);
3128 } 3136 }
3129 test_val = nfsd4_lease; 3137 test_val = nfsd4_lease;
@@ -3718,13 +3726,11 @@ out:
3718} 3726}
3719 3727
3720 3728
3721/*
3722 * Lock owner state (byte-range locks)
3723 */
3724#define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) 3729#define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start))
3725#define LOCK_HASH_BITS 8 3730
3726#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS) 3731#define LOCKOWNER_INO_HASH_BITS 8
3727#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1) 3732#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS)
3733#define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
3728 3734
3729static inline u64 3735static inline u64
3730end_offset(u64 start, u64 len) 3736end_offset(u64 start, u64 len)
@@ -3746,16 +3752,14 @@ last_byte_offset(u64 start, u64 len)
3746 return end > start ? end - 1: NFS4_MAX_UINT64; 3752 return end > start ? end - 1: NFS4_MAX_UINT64;
3747} 3753}
3748 3754
3749static inline unsigned int 3755static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
3750lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
3751 struct xdr_netobj *ownername)
3752{ 3756{
3753 return (file_hashval(inode) + cl_id 3757 return (file_hashval(inode) + cl_id
3754 + opaque_hashval(ownername->data, ownername->len)) 3758 + opaque_hashval(ownername->data, ownername->len))
3755 & LOCK_HASH_MASK; 3759 & LOCKOWNER_INO_HASH_MASK;
3756} 3760}
3757 3761
3758static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; 3762static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE];
3759 3763
3760/* 3764/*
3761 * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 3765 * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
@@ -3809,23 +3813,39 @@ nevermind:
3809 deny->ld_type = NFS4_WRITE_LT; 3813 deny->ld_type = NFS4_WRITE_LT;
3810} 3814}
3811 3815
3816static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner)
3817{
3818 struct nfs4_ol_stateid *lst;
3819
3820 if (!same_owner_str(&lo->lo_owner, owner, clid))
3821 return false;
3822 lst = list_first_entry(&lo->lo_owner.so_stateids,
3823 struct nfs4_ol_stateid, st_perstateowner);
3824 return lst->st_file->fi_inode == inode;
3825}
3826
3812static struct nfs4_lockowner * 3827static struct nfs4_lockowner *
3813find_lockowner_str(struct inode *inode, clientid_t *clid, 3828find_lockowner_str(struct inode *inode, clientid_t *clid,
3814 struct xdr_netobj *owner) 3829 struct xdr_netobj *owner)
3815{ 3830{
3816 unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner); 3831 unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
3817 struct nfs4_stateowner *op; 3832 struct nfs4_lockowner *lo;
3818 3833
3819 list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { 3834 list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
3820 if (same_owner_str(op, owner, clid)) 3835 if (same_lockowner_ino(lo, inode, clid, owner))
3821 return lockowner(op); 3836 return lo;
3822 } 3837 }
3823 return NULL; 3838 return NULL;
3824} 3839}
3825 3840
3826static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp) 3841static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
3827{ 3842{
3828 list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]); 3843 struct inode *inode = open_stp->st_file->fi_inode;
3844 unsigned int inohash = lockowner_ino_hashval(inode,
3845 clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
3846
3847 list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
3848 list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]);
3829 list_add(&lo->lo_perstateid, &open_stp->st_lockowners); 3849 list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
3830} 3850}
3831 3851
@@ -3834,7 +3854,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
3834 * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 3854 * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
3835 * occurred. 3855 * occurred.
3836 * 3856 *
3837 * strhashval = lock_ownerstr_hashval 3857 * strhashval = ownerstr_hashval
3838 */ 3858 */
3839 3859
3840static struct nfs4_lockowner * 3860static struct nfs4_lockowner *
@@ -3892,6 +3912,37 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
3892 __set_bit(access, &lock_stp->st_access_bmap); 3912 __set_bit(access, &lock_stp->st_access_bmap);
3893} 3913}
3894 3914
3915__be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new)
3916{
3917 struct nfs4_file *fi = ost->st_file;
3918 struct nfs4_openowner *oo = openowner(ost->st_stateowner);
3919 struct nfs4_client *cl = oo->oo_owner.so_client;
3920 struct nfs4_lockowner *lo;
3921 unsigned int strhashval;
3922
3923 lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner);
3924 if (lo) {
3925 if (!cstate->minorversion)
3926 return nfserr_bad_seqid;
3927 /* XXX: a lockowner always has exactly one stateid: */
3928 *lst = list_first_entry(&lo->lo_owner.so_stateids,
3929 struct nfs4_ol_stateid, st_perstateowner);
3930 return nfs_ok;
3931 }
3932 strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
3933 &lock->v.new.owner);
3934 lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
3935 if (lo == NULL)
3936 return nfserr_jukebox;
3937 *lst = alloc_init_lock_stateid(lo, fi, ost);
3938 if (*lst == NULL) {
3939 release_lockowner(lo);
3940 return nfserr_jukebox;
3941 }
3942 *new = true;
3943 return nfs_ok;
3944}
3945
3895/* 3946/*
3896 * LOCK operation 3947 * LOCK operation
3897 */ 3948 */
@@ -3907,7 +3958,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3907 struct file_lock file_lock; 3958 struct file_lock file_lock;
3908 struct file_lock conflock; 3959 struct file_lock conflock;
3909 __be32 status = 0; 3960 __be32 status = 0;
3910 unsigned int strhashval; 3961 bool new_state = false;
3911 int lkflg; 3962 int lkflg;
3912 int err; 3963 int err;
3913 3964
@@ -3933,10 +3984,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3933 * lock stateid. 3984 * lock stateid.
3934 */ 3985 */
3935 struct nfs4_ol_stateid *open_stp = NULL; 3986 struct nfs4_ol_stateid *open_stp = NULL;
3936 3987
3988 if (nfsd4_has_session(cstate))
3989 /* See rfc 5661 18.10.3: given clientid is ignored: */
3990 memcpy(&lock->v.new.clientid,
3991 &cstate->session->se_client->cl_clientid,
3992 sizeof(clientid_t));
3993
3937 status = nfserr_stale_clientid; 3994 status = nfserr_stale_clientid;
3938 if (!nfsd4_has_session(cstate) && 3995 if (STALE_CLIENTID(&lock->lk_new_clientid))
3939 STALE_CLIENTID(&lock->lk_new_clientid))
3940 goto out; 3996 goto out;
3941 3997
3942 /* validate and update open stateid and open seqid */ 3998 /* validate and update open stateid and open seqid */
@@ -3948,25 +4004,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3948 goto out; 4004 goto out;
3949 open_sop = openowner(open_stp->st_stateowner); 4005 open_sop = openowner(open_stp->st_stateowner);
3950 status = nfserr_bad_stateid; 4006 status = nfserr_bad_stateid;
3951 if (!nfsd4_has_session(cstate) && 4007 if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
3952 !same_clid(&open_sop->oo_owner.so_client->cl_clientid,
3953 &lock->v.new.clientid)) 4008 &lock->v.new.clientid))
3954 goto out; 4009 goto out;
3955 /* create lockowner and lock stateid */ 4010 status = lookup_or_create_lock_state(cstate, open_stp, lock,
3956 fp = open_stp->st_file; 4011 &lock_stp, &new_state);
3957 strhashval = lock_ownerstr_hashval(fp->fi_inode, 4012 if (status)
3958 open_sop->oo_owner.so_client->cl_clientid.cl_id,
3959 &lock->v.new.owner);
3960 /* XXX: Do we need to check for duplicate stateowners on
3961 * the same file, or should they just be allowed (and
3962 * create new stateids)? */
3963 status = nfserr_jukebox;
3964 lock_sop = alloc_init_lock_stateowner(strhashval,
3965 open_sop->oo_owner.so_client, open_stp, lock);
3966 if (lock_sop == NULL)
3967 goto out;
3968 lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
3969 if (lock_stp == NULL)
3970 goto out; 4013 goto out;
3971 } else { 4014 } else {
3972 /* lock (lock owner + lock stateid) already exists */ 4015 /* lock (lock owner + lock stateid) already exists */
@@ -3976,10 +4019,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3976 NFS4_LOCK_STID, &lock_stp); 4019 NFS4_LOCK_STID, &lock_stp);
3977 if (status) 4020 if (status)
3978 goto out; 4021 goto out;
3979 lock_sop = lockowner(lock_stp->st_stateowner);
3980 fp = lock_stp->st_file;
3981 } 4022 }
3982 /* lock_sop and lock_stp have been created or found */ 4023 lock_sop = lockowner(lock_stp->st_stateowner);
4024 fp = lock_stp->st_file;
3983 4025
3984 lkflg = setlkflg(lock->lk_type); 4026 lkflg = setlkflg(lock->lk_type);
3985 status = nfs4_check_openmode(lock_stp, lkflg); 4027 status = nfs4_check_openmode(lock_stp, lkflg);
@@ -4054,7 +4096,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4054 break; 4096 break;
4055 } 4097 }
4056out: 4098out:
4057 if (status && lock->lk_is_new && lock_sop) 4099 if (status && new_state)
4058 release_lockowner(lock_sop); 4100 release_lockowner(lock_sop);
4059 if (!cstate->replay_owner) 4101 if (!cstate->replay_owner)
4060 nfs4_unlock_state(); 4102 nfs4_unlock_state();
@@ -4251,7 +4293,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
4251 struct nfs4_ol_stateid *stp; 4293 struct nfs4_ol_stateid *stp;
4252 struct xdr_netobj *owner = &rlockowner->rl_owner; 4294 struct xdr_netobj *owner = &rlockowner->rl_owner;
4253 struct list_head matches; 4295 struct list_head matches;
4254 int i; 4296 unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
4255 __be32 status; 4297 __be32 status;
4256 4298
4257 dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 4299 dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
@@ -4266,22 +4308,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
4266 nfs4_lock_state(); 4308 nfs4_lock_state();
4267 4309
4268 status = nfserr_locks_held; 4310 status = nfserr_locks_held;
4269 /* XXX: we're doing a linear search through all the lockowners.
4270 * Yipes! For now we'll just hope clients aren't really using
4271 * release_lockowner much, but eventually we have to fix these
4272 * data structures. */
4273 INIT_LIST_HEAD(&matches); 4311 INIT_LIST_HEAD(&matches);
4274 for (i = 0; i < LOCK_HASH_SIZE; i++) { 4312
4275 list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) { 4313 list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) {
4276 if (!same_owner_str(sop, owner, clid)) 4314 if (sop->so_is_open_owner)
4277 continue; 4315 continue;
4278 list_for_each_entry(stp, &sop->so_stateids, 4316 if (!same_owner_str(sop, owner, clid))
4279 st_perstateowner) { 4317 continue;
4280 lo = lockowner(sop); 4318 list_for_each_entry(stp, &sop->so_stateids,
4281 if (check_for_locks(stp->st_file, lo)) 4319 st_perstateowner) {
4282 goto out; 4320 lo = lockowner(sop);
4283 list_add(&lo->lo_list, &matches); 4321 if (check_for_locks(stp->st_file, lo))
4284 } 4322 goto out;
4323 list_add(&lo->lo_list, &matches);
4285 } 4324 }
4286 } 4325 }
4287 /* Clients probably won't expect us to return with some (but not all) 4326 /* Clients probably won't expect us to return with some (but not all)
@@ -4394,16 +4433,127 @@ nfs4_check_open_reclaim(clientid_t *clid)
4394 return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; 4433 return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
4395} 4434}
4396 4435
4436#ifdef CONFIG_NFSD_FAULT_INJECTION
4437
4438void nfsd_forget_clients(u64 num)
4439{
4440 struct nfs4_client *clp, *next;
4441 int count = 0;
4442
4443 nfs4_lock_state();
4444 list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
4445 nfsd4_remove_clid_dir(clp);
4446 expire_client(clp);
4447 if (++count == num)
4448 break;
4449 }
4450 nfs4_unlock_state();
4451
4452 printk(KERN_INFO "NFSD: Forgot %d clients", count);
4453}
4454
4455static void release_lockowner_sop(struct nfs4_stateowner *sop)
4456{
4457 release_lockowner(lockowner(sop));
4458}
4459
4460static void release_openowner_sop(struct nfs4_stateowner *sop)
4461{
4462 release_openowner(openowner(sop));
4463}
4464
4465static int nfsd_release_n_owners(u64 num, bool is_open_owner,
4466 void (*release_sop)(struct nfs4_stateowner *))
4467{
4468 int i, count = 0;
4469 struct nfs4_stateowner *sop, *next;
4470
4471 for (i = 0; i < OWNER_HASH_SIZE; i++) {
4472 list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) {
4473 if (sop->so_is_open_owner != is_open_owner)
4474 continue;
4475 release_sop(sop);
4476 if (++count == num)
4477 return count;
4478 }
4479 }
4480 return count;
4481}
4482
4483void nfsd_forget_locks(u64 num)
4484{
4485 int count;
4486
4487 nfs4_lock_state();
4488 count = nfsd_release_n_owners(num, false, release_lockowner_sop);
4489 nfs4_unlock_state();
4490
4491 printk(KERN_INFO "NFSD: Forgot %d locks", count);
4492}
4493
4494void nfsd_forget_openowners(u64 num)
4495{
4496 int count;
4497
4498 nfs4_lock_state();
4499 count = nfsd_release_n_owners(num, true, release_openowner_sop);
4500 nfs4_unlock_state();
4501
4502 printk(KERN_INFO "NFSD: Forgot %d open owners", count);
4503}
4504
4505int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *))
4506{
4507 int i, count = 0;
4508 struct nfs4_file *fp, *fnext;
4509 struct nfs4_delegation *dp, *dnext;
4510
4511 for (i = 0; i < FILE_HASH_SIZE; i++) {
4512 list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) {
4513 list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) {
4514 deleg_func(dp);
4515 if (++count == num)
4516 return count;
4517 }
4518 }
4519 }
4520
4521 return count;
4522}
4523
4524void nfsd_forget_delegations(u64 num)
4525{
4526 unsigned int count;
4527
4528 nfs4_lock_state();
4529 count = nfsd_process_n_delegations(num, unhash_delegation);
4530 nfs4_unlock_state();
4531
4532 printk(KERN_INFO "NFSD: Forgot %d delegations", count);
4533}
4534
4535void nfsd_recall_delegations(u64 num)
4536{
4537 unsigned int count;
4538
4539 nfs4_lock_state();
4540 spin_lock(&recall_lock);
4541 count = nfsd_process_n_delegations(num, nfsd_break_one_deleg);
4542 spin_unlock(&recall_lock);
4543 nfs4_unlock_state();
4544
4545 printk(KERN_INFO "NFSD: Recalled %d delegations", count);
4546}
4547
4548#endif /* CONFIG_NFSD_FAULT_INJECTION */
4549
4397/* initialization to perform at module load time: */ 4550/* initialization to perform at module load time: */
4398 4551
4399int 4552void
4400nfs4_state_init(void) 4553nfs4_state_init(void)
4401{ 4554{
4402 int i, status; 4555 int i;
4403 4556
4404 status = nfsd4_init_slabs();
4405 if (status)
4406 return status;
4407 for (i = 0; i < CLIENT_HASH_SIZE; i++) { 4557 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
4408 INIT_LIST_HEAD(&conf_id_hashtbl[i]); 4558 INIT_LIST_HEAD(&conf_id_hashtbl[i]);
4409 INIT_LIST_HEAD(&conf_str_hashtbl[i]); 4559 INIT_LIST_HEAD(&conf_str_hashtbl[i]);
@@ -4416,18 +4566,15 @@ nfs4_state_init(void)
4416 for (i = 0; i < FILE_HASH_SIZE; i++) { 4566 for (i = 0; i < FILE_HASH_SIZE; i++) {
4417 INIT_LIST_HEAD(&file_hashtbl[i]); 4567 INIT_LIST_HEAD(&file_hashtbl[i]);
4418 } 4568 }
4419 for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) { 4569 for (i = 0; i < OWNER_HASH_SIZE; i++) {
4420 INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]); 4570 INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
4421 }
4422 for (i = 0; i < LOCK_HASH_SIZE; i++) {
4423 INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
4424 } 4571 }
4425 memset(&onestateid, ~0, sizeof(stateid_t)); 4572 for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
4573 INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]);
4426 INIT_LIST_HEAD(&close_lru); 4574 INIT_LIST_HEAD(&close_lru);
4427 INIT_LIST_HEAD(&client_lru); 4575 INIT_LIST_HEAD(&client_lru);
4428 INIT_LIST_HEAD(&del_recall_lru); 4576 INIT_LIST_HEAD(&del_recall_lru);
4429 reclaim_str_hashtbl_size = 0; 4577 reclaim_str_hashtbl_size = 0;
4430 return 0;
4431} 4578}
4432 4579
4433static void 4580static void
@@ -4526,7 +4673,6 @@ __nfs4_state_shutdown(void)
4526 spin_unlock(&recall_lock); 4673 spin_unlock(&recall_lock);
4527 list_for_each_safe(pos, next, &reaplist) { 4674 list_for_each_safe(pos, next, &reaplist) {
4528 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 4675 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
4529 list_del_init(&dp->dl_recall_lru);
4530 unhash_delegation(dp); 4676 unhash_delegation(dp);
4531 } 4677 }
4532 4678
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index b6fa792d6b85..0ec5a1b9700e 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -215,10 +215,9 @@ defer_free(struct nfsd4_compoundargs *argp,
215static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) 215static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
216{ 216{
217 if (p == argp->tmp) { 217 if (p == argp->tmp) {
218 p = kmalloc(nbytes, GFP_KERNEL); 218 p = kmemdup(argp->tmp, nbytes, GFP_KERNEL);
219 if (!p) 219 if (!p)
220 return NULL; 220 return NULL;
221 memcpy(p, argp->tmp, nbytes);
222 } else { 221 } else {
223 BUG_ON(p != argp->tmpp); 222 BUG_ON(p != argp->tmpp);
224 argp->tmpp = NULL; 223 argp->tmpp = NULL;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index bb4a11d58a5a..748eda93ce59 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.
@@ -1128,9 +1129,13 @@ static int __init init_nfsd(void)
1128 int retval; 1129 int retval;
1129 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); 1130 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1130 1131
1131 retval = nfs4_state_init(); /* nfs4 locking state */ 1132 retval = nfsd4_init_slabs();
1132 if (retval) 1133 if (retval)
1133 return retval; 1134 return retval;
1135 nfs4_state_init();
1136 retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
1137 if (retval)
1138 goto out_free_slabs;
1134 nfsd_stat_init(); /* Statistics */ 1139 nfsd_stat_init(); /* Statistics */
1135 retval = nfsd_reply_cache_init(); 1140 retval = nfsd_reply_cache_init();
1136 if (retval) 1141 if (retval)
@@ -1161,6 +1166,8 @@ out_free_cache:
1161 nfsd_reply_cache_shutdown(); 1166 nfsd_reply_cache_shutdown();
1162out_free_stat: 1167out_free_stat:
1163 nfsd_stat_shutdown(); 1168 nfsd_stat_shutdown();
1169 nfsd_fault_inject_cleanup();
1170out_free_slabs:
1164 nfsd4_free_slabs(); 1171 nfsd4_free_slabs();
1165 return retval; 1172 return retval;
1166} 1173}
@@ -1175,6 +1182,7 @@ static void __exit exit_nfsd(void)
1175 nfsd_lockd_shutdown(); 1182 nfsd_lockd_shutdown();
1176 nfsd_idmap_shutdown(); 1183 nfsd_idmap_shutdown();
1177 nfsd4_free_slabs(); 1184 nfsd4_free_slabs();
1185 nfsd_fault_inject_cleanup();
1178 unregister_filesystem(&nfsd_fs_type); 1186 unregister_filesystem(&nfsd_fs_type);
1179} 1187}
1180 1188
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 58134a23fdfb..1d1e8589b4ce 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -104,14 +104,16 @@ static inline int nfsd_v4client(struct svc_rqst *rq)
104 */ 104 */
105#ifdef CONFIG_NFSD_V4 105#ifdef CONFIG_NFSD_V4
106extern unsigned int max_delegations; 106extern unsigned int max_delegations;
107int nfs4_state_init(void); 107void nfs4_state_init(void);
108int nfsd4_init_slabs(void);
108void nfsd4_free_slabs(void); 109void nfsd4_free_slabs(void);
109int nfs4_state_start(void); 110int nfs4_state_start(void);
110void nfs4_state_shutdown(void); 111void nfs4_state_shutdown(void);
111void nfs4_reset_lease(time_t leasetime); 112void nfs4_reset_lease(time_t leasetime);
112int nfs4_reset_recoverydir(char *recdir); 113int nfs4_reset_recoverydir(char *recdir);
113#else 114#else
114static inline int nfs4_state_init(void) { return 0; } 115static inline void nfs4_state_init(void) { }
116static inline int nfsd4_init_slabs(void) { return 0; }
115static inline void nfsd4_free_slabs(void) { } 117static inline void nfsd4_free_slabs(void) { }
116static inline int nfs4_state_start(void) { return 0; } 118static inline int nfs4_state_start(void) { return 0; }
117static inline void nfs4_state_shutdown(void) { } 119static inline void nfs4_state_shutdown(void) { }
@@ -338,15 +340,15 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
338} 340}
339 341
340/* These will return ERR_INVAL if specified in GETATTR or READDIR. */ 342/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
341#define NFSD_WRITEONLY_ATTRS_WORD1 \ 343#define NFSD_WRITEONLY_ATTRS_WORD1 \
342(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) 344 (FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
343 345
344/* These are the only attrs allowed in CREATE/OPEN/SETATTR. */ 346/* These are the only attrs allowed in CREATE/OPEN/SETATTR. */
345#define NFSD_WRITEABLE_ATTRS_WORD0 \ 347#define NFSD_WRITEABLE_ATTRS_WORD0 \
346(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL ) 348 (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
347#define NFSD_WRITEABLE_ATTRS_WORD1 \ 349#define NFSD_WRITEABLE_ATTRS_WORD1 \
348(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ 350 (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
349 | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) 351 | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
350#define NFSD_WRITEABLE_ATTRS_WORD2 0 352#define NFSD_WRITEABLE_ATTRS_WORD2 0
351 353
352#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ 354#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index a3cf38476a1b..ffb5df1db94f 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -366,6 +366,7 @@ struct nfs4_openowner {
366 366
367struct nfs4_lockowner { 367struct nfs4_lockowner {
368 struct nfs4_stateowner lo_owner; /* must be first element */ 368 struct nfs4_stateowner lo_owner; /* must be first element */
369 struct list_head lo_owner_ino_hash; /* hash by owner,file */
369 struct list_head lo_perstateid; /* for lockowners only */ 370 struct list_head lo_perstateid; /* for lockowners only */
370 struct list_head lo_list; /* for temporary uses */ 371 struct list_head lo_list; /* for temporary uses */
371}; 372};
@@ -482,7 +483,7 @@ extern void nfsd4_shutdown_recdir(void);
482extern int nfs4_client_to_reclaim(const char *name); 483extern int nfs4_client_to_reclaim(const char *name);
483extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); 484extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
484extern void nfsd4_recdir_purge_old(void); 485extern void nfsd4_recdir_purge_old(void);
485extern int nfsd4_create_clid_dir(struct nfs4_client *clp); 486extern void nfsd4_create_clid_dir(struct nfs4_client *clp);
486extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); 487extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
487extern void release_session_client(struct nfsd4_session *); 488extern void release_session_client(struct nfsd4_session *);
488extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *); 489extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index d25a723b68ad..edf6d3ed8777 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -594,8 +594,19 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
594 return error; 594 return error;
595} 595}
596 596
597#define NFSD_XATTR_JUNCTION_PREFIX XATTR_TRUSTED_PREFIX "junction." 597/*
598#define NFSD_XATTR_JUNCTION_TYPE NFSD_XATTR_JUNCTION_PREFIX "type" 598 * NFS junction information is stored in an extended attribute.
599 */
600#define NFSD_JUNCTION_XATTR_NAME XATTR_TRUSTED_PREFIX "junction.nfs"
601
602/**
603 * nfsd4_is_junction - Test if an object could be an NFS junction
604 *
605 * @dentry: object to test
606 *
607 * Returns 1 if "dentry" appears to contain NFS junction information.
608 * Otherwise 0 is returned.
609 */
599int nfsd4_is_junction(struct dentry *dentry) 610int nfsd4_is_junction(struct dentry *dentry)
600{ 611{
601 struct inode *inode = dentry->d_inode; 612 struct inode *inode = dentry->d_inode;
@@ -606,7 +617,7 @@ int nfsd4_is_junction(struct dentry *dentry)
606 return 0; 617 return 0;
607 if (!(inode->i_mode & S_ISVTX)) 618 if (!(inode->i_mode & S_ISVTX))
608 return 0; 619 return 0;
609 if (vfs_getxattr(dentry, NFSD_XATTR_JUNCTION_TYPE, NULL, 0) <= 0) 620 if (vfs_getxattr(dentry, NFSD_JUNCTION_XATTR_NAME, NULL, 0) <= 0)
610 return 0; 621 return 0;
611 return 1; 622 return 1;
612} 623}
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 8620f79658d4..dfa900948af7 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -109,7 +109,7 @@ static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u
109 109
110int svc_reg_xprt_class(struct svc_xprt_class *); 110int svc_reg_xprt_class(struct svc_xprt_class *);
111void svc_unreg_xprt_class(struct svc_xprt_class *); 111void svc_unreg_xprt_class(struct svc_xprt_class *);
112void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *, 112void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *,
113 struct svc_serv *); 113 struct svc_serv *);
114int svc_create_xprt(struct svc_serv *, const char *, struct net *, 114int svc_create_xprt(struct svc_serv *, const char *, struct net *,
115 const int, const unsigned short, int); 115 const int, const unsigned short, int);
@@ -118,7 +118,6 @@ void svc_xprt_received(struct svc_xprt *);
118void svc_xprt_put(struct svc_xprt *xprt); 118void svc_xprt_put(struct svc_xprt *xprt);
119void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt); 119void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
120void svc_close_xprt(struct svc_xprt *xprt); 120void svc_close_xprt(struct svc_xprt *xprt);
121void svc_delete_xprt(struct svc_xprt *xprt);
122int svc_port_is_privileged(struct sockaddr *sin); 121int svc_port_is_privileged(struct sockaddr *sin);
123int svc_print_xprts(char *buf, int maxlen); 122int svc_print_xprts(char *buf, int maxlen);
124struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, 123struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 85c50b40759d..c84e9741cb2a 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -34,7 +34,7 @@ struct svc_sock {
34/* 34/*
35 * Function prototypes. 35 * Function prototypes.
36 */ 36 */
37void svc_close_all(struct list_head *); 37void svc_close_all(struct svc_serv *);
38int svc_recv(struct svc_rqst *, long); 38int svc_recv(struct svc_rqst *, long);
39int svc_send(struct svc_rqst *); 39int svc_send(struct svc_rqst *);
40void svc_drop(struct svc_rqst *); 40void svc_drop(struct svc_rqst *);
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 03b56bc3b659..465df9ae1046 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -1641,6 +1641,7 @@ int cache_register_net(struct cache_detail *cd, struct net *net)
1641 sunrpc_destroy_cache_detail(cd); 1641 sunrpc_destroy_cache_detail(cd);
1642 return ret; 1642 return ret;
1643} 1643}
1644EXPORT_SYMBOL_GPL(cache_register_net);
1644 1645
1645int cache_register(struct cache_detail *cd) 1646int cache_register(struct cache_detail *cd)
1646{ 1647{
@@ -1653,6 +1654,7 @@ void cache_unregister_net(struct cache_detail *cd, struct net *net)
1653 remove_cache_proc_entries(cd, net); 1654 remove_cache_proc_entries(cd, net);
1654 sunrpc_destroy_cache_detail(cd); 1655 sunrpc_destroy_cache_detail(cd);
1655} 1656}
1657EXPORT_SYMBOL_GPL(cache_unregister_net);
1656 1658
1657void cache_unregister(struct cache_detail *cd) 1659void cache_unregister(struct cache_detail *cd)
1658{ 1660{
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 9d01d46b05f3..e4aabc02368b 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -167,6 +167,7 @@ svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
167 167
168fail_free: 168fail_free:
169 kfree(m->to_pool); 169 kfree(m->to_pool);
170 m->to_pool = NULL;
170fail: 171fail:
171 return -ENOMEM; 172 return -ENOMEM;
172} 173}
@@ -285,9 +286,10 @@ svc_pool_map_put(void)
285 mutex_lock(&svc_pool_map_mutex); 286 mutex_lock(&svc_pool_map_mutex);
286 287
287 if (!--m->count) { 288 if (!--m->count) {
288 m->mode = SVC_POOL_DEFAULT;
289 kfree(m->to_pool); 289 kfree(m->to_pool);
290 m->to_pool = NULL;
290 kfree(m->pool_to); 291 kfree(m->pool_to);
292 m->pool_to = NULL;
291 m->npools = 0; 293 m->npools = 0;
292 } 294 }
293 295
@@ -527,17 +529,20 @@ svc_destroy(struct svc_serv *serv)
527 printk("svc_destroy: no threads for serv=%p!\n", serv); 529 printk("svc_destroy: no threads for serv=%p!\n", serv);
528 530
529 del_timer_sync(&serv->sv_temptimer); 531 del_timer_sync(&serv->sv_temptimer);
530 532 /*
531 svc_close_all(&serv->sv_tempsocks); 533 * The set of xprts (contained in the sv_tempsocks and
534 * sv_permsocks lists) is now constant, since it is modified
535 * only by accepting new sockets (done by service threads in
536 * svc_recv) or aging old ones (done by sv_temptimer), or
537 * configuration changes (excluded by whatever locking the
538 * caller is using--nfsd_mutex in the case of nfsd). So it's
539 * safe to traverse those lists and shut everything down:
540 */
541 svc_close_all(serv);
532 542
533 if (serv->sv_shutdown) 543 if (serv->sv_shutdown)
534 serv->sv_shutdown(serv); 544 serv->sv_shutdown(serv);
535 545
536 svc_close_all(&serv->sv_permsocks);
537
538 BUG_ON(!list_empty(&serv->sv_permsocks));
539 BUG_ON(!list_empty(&serv->sv_tempsocks));
540
541 cache_clean_deferred(serv); 546 cache_clean_deferred(serv);
542 547
543 if (svc_serv_is_pooled(serv)) 548 if (svc_serv_is_pooled(serv))
@@ -683,8 +688,8 @@ found_pool:
683 * Create or destroy enough new threads to make the number 688 * Create or destroy enough new threads to make the number
684 * of threads the given number. If `pool' is non-NULL, applies 689 * of threads the given number. If `pool' is non-NULL, applies
685 * only to threads in that pool, otherwise round-robins between 690 * only to threads in that pool, otherwise round-robins between
686 * all pools. Must be called with a svc_get() reference and 691 * all pools. Caller must ensure that mutual exclusion between this and
687 * the BKL or another lock to protect access to svc_serv fields. 692 * server startup or shutdown.
688 * 693 *
689 * Destroying threads relies on the service threads filling in 694 * Destroying threads relies on the service threads filling in
690 * rqstp->rq_task, which only the nfs ones do. Assumes the serv 695 * rqstp->rq_task, which only the nfs ones do. Assumes the serv
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 38649cfa4e81..74cb0d8e9ca1 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -22,6 +22,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
22static int svc_deferred_recv(struct svc_rqst *rqstp); 22static int svc_deferred_recv(struct svc_rqst *rqstp);
23static struct cache_deferred_req *svc_defer(struct cache_req *req); 23static struct cache_deferred_req *svc_defer(struct cache_req *req);
24static void svc_age_temp_xprts(unsigned long closure); 24static void svc_age_temp_xprts(unsigned long closure);
25static void svc_delete_xprt(struct svc_xprt *xprt);
25 26
26/* apparently the "standard" is that clients close 27/* apparently the "standard" is that clients close
27 * idle connections after 5 minutes, servers after 28 * idle connections after 5 minutes, servers after
@@ -147,8 +148,8 @@ EXPORT_SYMBOL_GPL(svc_xprt_put);
147 * Called by transport drivers to initialize the transport independent 148 * Called by transport drivers to initialize the transport independent
148 * portion of the transport instance. 149 * portion of the transport instance.
149 */ 150 */
150void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt, 151void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl,
151 struct svc_serv *serv) 152 struct svc_xprt *xprt, struct svc_serv *serv)
152{ 153{
153 memset(xprt, 0, sizeof(*xprt)); 154 memset(xprt, 0, sizeof(*xprt));
154 xprt->xpt_class = xcl; 155 xprt->xpt_class = xcl;
@@ -163,7 +164,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
163 spin_lock_init(&xprt->xpt_lock); 164 spin_lock_init(&xprt->xpt_lock);
164 set_bit(XPT_BUSY, &xprt->xpt_flags); 165 set_bit(XPT_BUSY, &xprt->xpt_flags);
165 rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending"); 166 rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending");
166 xprt->xpt_net = get_net(&init_net); 167 xprt->xpt_net = get_net(net);
167} 168}
168EXPORT_SYMBOL_GPL(svc_xprt_init); 169EXPORT_SYMBOL_GPL(svc_xprt_init);
169 170
@@ -878,7 +879,7 @@ static void call_xpt_users(struct svc_xprt *xprt)
878/* 879/*
879 * Remove a dead transport 880 * Remove a dead transport
880 */ 881 */
881void svc_delete_xprt(struct svc_xprt *xprt) 882static void svc_delete_xprt(struct svc_xprt *xprt)
882{ 883{
883 struct svc_serv *serv = xprt->xpt_server; 884 struct svc_serv *serv = xprt->xpt_server;
884 struct svc_deferred_req *dr; 885 struct svc_deferred_req *dr;
@@ -893,14 +894,7 @@ void svc_delete_xprt(struct svc_xprt *xprt)
893 spin_lock_bh(&serv->sv_lock); 894 spin_lock_bh(&serv->sv_lock);
894 if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags)) 895 if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
895 list_del_init(&xprt->xpt_list); 896 list_del_init(&xprt->xpt_list);
896 /* 897 BUG_ON(!list_empty(&xprt->xpt_ready));
897 * The only time we're called while xpt_ready is still on a list
898 * is while the list itself is about to be destroyed (in
899 * svc_destroy). BUT svc_xprt_enqueue could still be attempting
900 * to add new entries to the sp_sockets list, so we can't leave
901 * a freed xprt on it.
902 */
903 list_del_init(&xprt->xpt_ready);
904 if (test_bit(XPT_TEMP, &xprt->xpt_flags)) 898 if (test_bit(XPT_TEMP, &xprt->xpt_flags))
905 serv->sv_tmpcnt--; 899 serv->sv_tmpcnt--;
906 spin_unlock_bh(&serv->sv_lock); 900 spin_unlock_bh(&serv->sv_lock);
@@ -928,22 +922,48 @@ void svc_close_xprt(struct svc_xprt *xprt)
928} 922}
929EXPORT_SYMBOL_GPL(svc_close_xprt); 923EXPORT_SYMBOL_GPL(svc_close_xprt);
930 924
931void svc_close_all(struct list_head *xprt_list) 925static void svc_close_list(struct list_head *xprt_list)
926{
927 struct svc_xprt *xprt;
928
929 list_for_each_entry(xprt, xprt_list, xpt_list) {
930 set_bit(XPT_CLOSE, &xprt->xpt_flags);
931 set_bit(XPT_BUSY, &xprt->xpt_flags);
932 }
933}
934
935void svc_close_all(struct svc_serv *serv)
932{ 936{
937 struct svc_pool *pool;
933 struct svc_xprt *xprt; 938 struct svc_xprt *xprt;
934 struct svc_xprt *tmp; 939 struct svc_xprt *tmp;
940 int i;
941
942 svc_close_list(&serv->sv_tempsocks);
943 svc_close_list(&serv->sv_permsocks);
935 944
945 for (i = 0; i < serv->sv_nrpools; i++) {
946 pool = &serv->sv_pools[i];
947
948 spin_lock_bh(&pool->sp_lock);
949 while (!list_empty(&pool->sp_sockets)) {
950 xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready);
951 list_del_init(&xprt->xpt_ready);
952 }
953 spin_unlock_bh(&pool->sp_lock);
954 }
936 /* 955 /*
937 * The server is shutting down, and no more threads are running. 956 * At this point the sp_sockets lists will stay empty, since
938 * svc_xprt_enqueue() might still be running, but at worst it 957 * svc_enqueue will not add new entries without taking the
939 * will re-add the xprt to sp_sockets, which will soon get 958 * sp_lock and checking XPT_BUSY.
940 * freed. So we don't bother with any more locking, and don't
941 * leave the close to the (nonexistent) server threads:
942 */ 959 */
943 list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { 960 list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list)
944 set_bit(XPT_CLOSE, &xprt->xpt_flags);
945 svc_delete_xprt(xprt); 961 svc_delete_xprt(xprt);
946 } 962 list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list)
963 svc_delete_xprt(xprt);
964
965 BUG_ON(!list_empty(&serv->sv_permsocks));
966 BUG_ON(!list_empty(&serv->sv_tempsocks));
947} 967}
948 968
949/* 969/*
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 4653286fcc9e..464570906f80 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -739,7 +739,8 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
739{ 739{
740 int err, level, optname, one = 1; 740 int err, level, optname, one = 1;
741 741
742 svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv); 742 svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class,
743 &svsk->sk_xprt, serv);
743 clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); 744 clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
744 svsk->sk_sk->sk_data_ready = svc_udp_data_ready; 745 svsk->sk_sk->sk_data_ready = svc_udp_data_ready;
745 svsk->sk_sk->sk_write_space = svc_write_space; 746 svsk->sk_sk->sk_write_space = svc_write_space;
@@ -1343,7 +1344,8 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
1343{ 1344{
1344 struct sock *sk = svsk->sk_sk; 1345 struct sock *sk = svsk->sk_sk;
1345 1346
1346 svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv); 1347 svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_tcp_class,
1348 &svsk->sk_xprt, serv);
1347 set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); 1349 set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
1348 if (sk->sk_state == TCP_LISTEN) { 1350 if (sk->sk_state == TCP_LISTEN) {
1349 dprintk("setting up TCP socket for listening\n"); 1351 dprintk("setting up TCP socket for listening\n");
@@ -1659,7 +1661,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
1659 return ERR_PTR(-ENOMEM); 1661 return ERR_PTR(-ENOMEM);
1660 1662
1661 xprt = &svsk->sk_xprt; 1663 xprt = &svsk->sk_xprt;
1662 svc_xprt_init(&svc_tcp_bc_class, xprt, serv); 1664 svc_xprt_init(net, &svc_tcp_bc_class, xprt, serv);
1663 1665
1664 serv->sv_bc_xprt = xprt; 1666 serv->sv_bc_xprt = xprt;
1665 1667
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index ba1296d88de0..894cb42db91d 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -453,7 +453,7 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
453 453
454 if (!cma_xprt) 454 if (!cma_xprt)
455 return NULL; 455 return NULL;
456 svc_xprt_init(&svc_rdma_class, &cma_xprt->sc_xprt, serv); 456 svc_xprt_init(&init_net, &svc_rdma_class, &cma_xprt->sc_xprt, serv);
457 INIT_LIST_HEAD(&cma_xprt->sc_accept_q); 457 INIT_LIST_HEAD(&cma_xprt->sc_accept_q);
458 INIT_LIST_HEAD(&cma_xprt->sc_dto_q); 458 INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
459 INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q); 459 INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
diff --git a/tools/nfsd/inject_fault.sh b/tools/nfsd/inject_fault.sh
new file mode 100755
index 000000000000..06a399ac8b2f
--- /dev/null
+++ b/tools/nfsd/inject_fault.sh
@@ -0,0 +1,49 @@
1#!/bin/bash
2#
3# Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
4#
5# Script for easier NFSD fault injection
6
7# Check that debugfs has been mounted
8DEBUGFS=`cat /proc/mounts | grep debugfs`
9if [ "$DEBUGFS" == "" ]; then
10 echo "debugfs does not appear to be mounted!"
11 echo "Please mount debugfs and try again"
12 exit 1
13fi
14
15# Check that the fault injection directory exists
16DEBUGDIR=`echo $DEBUGFS | awk '{print $2}'`/nfsd
17if [ ! -d "$DEBUGDIR" ]; then
18 echo "$DEBUGDIR does not exist"
19 echo "Check that your .config selects CONFIG_NFSD_FAULT_INJECTION"
20 exit 1
21fi
22
23function help()
24{
25 echo "Usage $0 injection_type [count]"
26 echo ""
27 echo "Injection types are:"
28 ls $DEBUGDIR
29 exit 1
30}
31
32if [ $# == 0 ]; then
33 help
34elif [ ! -f $DEBUGDIR/$1 ]; then
35 help
36elif [ $# != 2 ]; then
37 COUNT=0
38else
39 COUNT=$2
40fi
41
42BEFORE=`mktemp`
43AFTER=`mktemp`
44dmesg > $BEFORE
45echo $COUNT > $DEBUGDIR/$1
46dmesg > $AFTER
47# Capture lines that only exist in the $AFTER file
48diff $BEFORE $AFTER | grep ">"
49rm -f $BEFORE $AFTER