aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-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
14 files changed, 433 insertions, 130 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/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}