Blame view

fs/nfsd/nfs4state.c 121 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  *  Copyright (c) 2001 The Regents of the University of Michigan.
  *  All rights reserved.
  *
  *  Kendrick Smith <kmsmith@umich.edu>
  *  Andy Adamson <kandros@umich.edu>
  *
  *  Redistribution and use in source and binary forms, with or without
  *  modification, are permitted provided that the following conditions
  *  are met:
  *
  *  1. Redistributions of source code must retain the above copyright
  *     notice, this list of conditions and the following disclaimer.
  *  2. Redistributions in binary form must reproduce the above copyright
  *     notice, this list of conditions and the following disclaimer in the
  *     documentation and/or other materials provided with the distribution.
  *  3. Neither the name of the University nor the names of its
  *     contributors may be used to endorse or promote products derived
  *     from this software without specific prior written permission.
  *
  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
aceaf78da   Dave Hansen   [PATCH] r/o bind ...
34
  #include <linux/file.h>
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
35
  #include <linux/fs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
36
  #include <linux/slab.h>
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
37
  #include <linux/namei.h>
c2f1a551d   Meelap Shah   knfsd: nfsd4: var...
38
  #include <linux/swap.h>
174568045   Bryan Schumaker   NFSD: Added TEST_...
39
  #include <linux/pagemap.h>
68e76ad0b   Olga Kornievskaia   nfsd: pass client...
40
  #include <linux/sunrpc/svcauth_gss.h>
363168b4e   Jeff Layton   nfsd: make nfs4_c...
41
  #include <linux/sunrpc/clnt.h>
9a74af213   Boaz Harrosh   nfsd: Move privat...
42
  #include "xdr4.h"
0a3adadee   J. Bruce Fields   nfsd: make fs/nfs...
43
  #include "vfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
  
  #define NFSDDBG_FACILITY                NFSDDBG_PROC
  
  /* Globals */
cf07d2ea4   J. Bruce Fields   nfsd4: simplify r...
48
  time_t nfsd4_lease = 90;     /* default lease time */
efc4bb4fd   J. Bruce Fields   nfsd4: allow sett...
49
  time_t nfsd4_grace = 90;
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
50
  static time_t boot_time;
f32f3c2d3   J. Bruce Fields   nfsd4: initialize...
51
52
53
54
55
56
57
58
59
  
  #define all_ones {{~0,~0},~0}
  static const stateid_t one_stateid = {
  	.si_generation = ~0,
  	.si_opaque = all_ones,
  };
  static const stateid_t zero_stateid = {
  	/* all fields zero */
  };
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
60
  static u64 current_sessionid = 1;
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
61

f32f3c2d3   J. Bruce Fields   nfsd4: initialize...
62
63
  #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
  #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  /* forward declarations */
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
66
  static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67

8b671b807   J. Bruce Fields   nfsd4: remove use...
68
69
70
  /* Locking: */
  
  /* Currently used for almost all code touching nfsv4 state: */
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
71
  static DEFINE_MUTEX(client_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

8b671b807   J. Bruce Fields   nfsd4: remove use...
73
74
75
76
77
78
  /*
   * Currently used for the del_recall_lru and file hash table.  In an
   * effort to decrease the scope of the client_mutex, this spinlock may
   * eventually cover more:
   */
  static DEFINE_SPINLOCK(recall_lock);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
79
80
  static struct kmem_cache *openowner_slab = NULL;
  static struct kmem_cache *lockowner_slab = NULL;
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
81
82
83
  static struct kmem_cache *file_slab = NULL;
  static struct kmem_cache *stateid_slab = NULL;
  static struct kmem_cache *deleg_slab = NULL;
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
84

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
  void
  nfs4_lock_state(void)
  {
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
88
  	mutex_lock(&client_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
  }
  
  void
  nfs4_unlock_state(void)
  {
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
94
  	mutex_unlock(&client_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  }
  
  static inline u32
  opaque_hashval(const void *ptr, int nbytes)
  {
  	unsigned char *cptr = (unsigned char *) ptr;
  
  	u32 x = 0;
  	while (nbytes--) {
  		x *= 37;
  		x += *cptr++;
  	}
  	return x;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  static struct list_head del_recall_lru;
32513b40e   J. Bruce Fields   nfsd4: preallocat...
110
111
112
113
  static void nfsd4_free_file(struct nfs4_file *f)
  {
  	kmem_cache_free(file_slab, f);
  }
13cd21845   NeilBrown   [PATCH] nfsd4: re...
114
115
116
  static inline void
  put_nfs4_file(struct nfs4_file *fi)
  {
8b671b807   J. Bruce Fields   nfsd4: remove use...
117
118
119
120
  	if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) {
  		list_del(&fi->fi_hash);
  		spin_unlock(&recall_lock);
  		iput(fi->fi_inode);
32513b40e   J. Bruce Fields   nfsd4: preallocat...
121
  		nfsd4_free_file(fi);
8b671b807   J. Bruce Fields   nfsd4: remove use...
122
  	}
13cd21845   NeilBrown   [PATCH] nfsd4: re...
123
124
125
126
127
  }
  
  static inline void
  get_nfs4_file(struct nfs4_file *fi)
  {
8b671b807   J. Bruce Fields   nfsd4: remove use...
128
  	atomic_inc(&fi->fi_ref);
13cd21845   NeilBrown   [PATCH] nfsd4: re...
129
  }
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
130
  static int num_delegations;
c2f1a551d   Meelap Shah   knfsd: nfsd4: var...
131
  unsigned int max_delegations;
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
132
133
134
135
  
  /*
   * Open owner state (share locks)
   */
16bfdaafa   J. Bruce Fields   nfsd4: share open...
136
137
138
139
  /* hash tables for lock and open owners */
  #define OWNER_HASH_BITS              8
  #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
  #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
140

16bfdaafa   J. Bruce Fields   nfsd4: share open...
141
  static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
ddc04c416   J. Bruce Fields   nfsd4: replace so...
142
143
144
145
146
  {
  	unsigned int ret;
  
  	ret = opaque_hashval(ownername->data, ownername->len);
  	ret += clientid;
16bfdaafa   J. Bruce Fields   nfsd4: share open...
147
  	return ret & OWNER_HASH_MASK;
ddc04c416   J. Bruce Fields   nfsd4: replace so...
148
  }
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
149

16bfdaafa   J. Bruce Fields   nfsd4: share open...
150
  static struct list_head	ownerstr_hashtbl[OWNER_HASH_SIZE];
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
151
152
153
154
  
  /* hash table for nfs4_file */
  #define FILE_HASH_BITS                   8
  #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
35079582e   Shan Wei   nfsd: kill unused...
155

ddc04c416   J. Bruce Fields   nfsd4: replace so...
156
157
158
159
160
  static unsigned int file_hashval(struct inode *ino)
  {
  	/* XXX: why are we hashing on inode pointer, anyway? */
  	return hash_ptr(ino, FILE_HASH_BITS);
  }
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
161
  static struct list_head file_hashtbl[FILE_HASH_SIZE];
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
162

998db52c0   J. Bruce Fields   nfsd4: fix file o...
163
  static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
f9d7562fd   J. Bruce Fields   nfsd4: share file...
164
165
166
167
  {
  	BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
  	atomic_inc(&fp->fi_access[oflag]);
  }
998db52c0   J. Bruce Fields   nfsd4: fix file o...
168
169
170
171
172
173
174
175
176
177
  static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
  {
  	if (oflag == O_RDWR) {
  		__nfs4_file_get_access(fp, O_RDONLY);
  		__nfs4_file_get_access(fp, O_WRONLY);
  	} else
  		__nfs4_file_get_access(fp, oflag);
  }
  
  static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
f9d7562fd   J. Bruce Fields   nfsd4: share file...
178
179
180
181
182
183
  {
  	if (fp->fi_fds[oflag]) {
  		fput(fp->fi_fds[oflag]);
  		fp->fi_fds[oflag] = NULL;
  	}
  }
998db52c0   J. Bruce Fields   nfsd4: fix file o...
184
  static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
f9d7562fd   J. Bruce Fields   nfsd4: share file...
185
186
  {
  	if (atomic_dec_and_test(&fp->fi_access[oflag])) {
f9d7562fd   J. Bruce Fields   nfsd4: share file...
187
  		nfs4_file_put_fd(fp, oflag);
3d02fa29d   J. Bruce Fields   nfsd4: fix open d...
188
189
190
191
192
193
194
195
  		/*
  		 * It's also safe to get rid of the RDWR open *if*
  		 * we no longer have need of the other kind of access
  		 * or if we already have the other kind of open:
  		 */
  		if (fp->fi_fds[1-oflag]
  			|| atomic_read(&fp->fi_access[1 - oflag]) == 0)
  			nfs4_file_put_fd(fp, O_RDWR);
f9d7562fd   J. Bruce Fields   nfsd4: share file...
196
197
  	}
  }
998db52c0   J. Bruce Fields   nfsd4: fix file o...
198
199
200
201
202
203
204
205
  static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
  {
  	if (oflag == O_RDWR) {
  		__nfs4_file_put_access(fp, O_RDONLY);
  		__nfs4_file_put_access(fp, O_WRONLY);
  	} else
  		__nfs4_file_put_access(fp, oflag);
  }
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
206
  static inline int get_new_stid(struct nfs4_stid *stid)
36d44c603   J. Bruce Fields   nfsd4: share comm...
207
  {
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
208
  	static int min_stateid = 0;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
209
  	struct idr *stateids = &stid->sc_client->cl_stateids;
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
210
211
  	int new_stid;
  	int error;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
212
  	error = idr_get_new_above(stateids, stid, min_stateid, &new_stid);
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
213
  	/*
996e09385   J. Bruce Fields   nfsd4: do idr pre...
214
215
216
217
  	 * Note: the necessary preallocation was done in
  	 * nfs4_alloc_stateid().  The idr code caps the number of
  	 * preallocations that can exist at a time, but the state lock
  	 * prevents anyone from using ours before we get here:
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
218
219
220
221
222
223
224
225
226
227
228
  	 */
  	BUG_ON(error);
  	/*
  	 * It shouldn't be a problem to reuse an opaque stateid value.
  	 * I don't think it is for 4.1.  But with 4.0 I worry that, for
  	 * example, a stray write retransmission could be accepted by
  	 * the server when it should have been rejected.  Therefore,
  	 * adopt a trick from the sctp code to attempt to maximize the
  	 * amount of time until an id is reused, by ensuring they always
  	 * "increase" (mod INT_MAX):
  	 */
36d44c603   J. Bruce Fields   nfsd4: share comm...
229

6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
230
231
232
233
  	min_stateid = new_stid+1;
  	if (min_stateid == INT_MAX)
  		min_stateid = 0;
  	return new_stid;
36d44c603   J. Bruce Fields   nfsd4: share comm...
234
  }
996e09385   J. Bruce Fields   nfsd4: do idr pre...
235
  static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type)
2a74aba79   J. Bruce Fields   nfsd4: move clien...
236
237
  {
  	stateid_t *s = &stid->sc_stateid;
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
238
  	int new_id;
2a74aba79   J. Bruce Fields   nfsd4: move clien...
239
240
241
242
  
  	stid->sc_type = type;
  	stid->sc_client = cl;
  	s->si_opaque.so_clid = cl->cl_clientid;
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
243
  	new_id = get_new_stid(stid);
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
244
  	s->si_opaque.so_id = (u32)new_id;
2a74aba79   J. Bruce Fields   nfsd4: move clien...
245
246
  	/* Will be incremented before return to client: */
  	s->si_generation = 0;
996e09385   J. Bruce Fields   nfsd4: do idr pre...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  }
  
  static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab)
  {
  	struct idr *stateids = &cl->cl_stateids;
  
  	if (!idr_pre_get(stateids, GFP_KERNEL))
  		return NULL;
  	/*
  	 * Note: if we fail here (or any time between now and the time
  	 * we actually get the new idr), we won't need to undo the idr
  	 * preallocation, since the idr code caps the number of
  	 * preallocated entries.
  	 */
  	return kmem_cache_alloc(slab, GFP_KERNEL);
2a74aba79   J. Bruce Fields   nfsd4: move clien...
262
  }
4cdc951b8   J. Bruce Fields   nfsd4: preallocat...
263
264
265
266
  static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
  {
  	return openlockstateid(nfs4_alloc_stid(clp, stateid_slab));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  static struct nfs4_delegation *
dcef0413d   J. Bruce Fields   nfsd4: move some ...
268
  alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
  {
  	struct nfs4_delegation *dp;
  	struct nfs4_file *fp = stp->st_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
  
  	dprintk("NFSD alloc_init_deleg
  ");
c3e480808   J. Bruce Fields   nfsd4: don't pret...
275
276
277
278
279
280
281
  	/*
  	 * Major work on the lease subsystem (for example, to support
  	 * calbacks on stat) will be required before we can support
  	 * write delegations properly.
  	 */
  	if (type != NFS4_OPEN_DELEGATE_READ)
  		return NULL;
47f9940c5   Meelap Shah   knfsd: nfsd4: don...
282
283
  	if (fp->fi_had_conflict)
  		return NULL;
c2f1a551d   Meelap Shah   knfsd: nfsd4: var...
284
  	if (num_delegations > max_delegations)
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
285
  		return NULL;
996e09385   J. Bruce Fields   nfsd4: do idr pre...
286
  	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
5b2d21c19   NeilBrown   [PATCH] nfsd4: sl...
287
  	if (dp == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  		return dp;
996e09385   J. Bruce Fields   nfsd4: do idr pre...
289
  	init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID);
2a74aba79   J. Bruce Fields   nfsd4: move clien...
290
291
  	/*
  	 * delegation seqid's are never incremented.  The 4.1 special
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
292
293
  	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
  	 * 0 anyway just for consistency and use 1:
2a74aba79   J. Bruce Fields   nfsd4: move clien...
294
295
  	 */
  	dp->dl_stid.sc_stateid.si_generation = 1;
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
296
  	num_delegations++;
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
297
298
  	INIT_LIST_HEAD(&dp->dl_perfile);
  	INIT_LIST_HEAD(&dp->dl_perclnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  	INIT_LIST_HEAD(&dp->dl_recall_lru);
13cd21845   NeilBrown   [PATCH] nfsd4: re...
300
  	get_nfs4_file(fp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  	dp->dl_file = fp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  	dp->dl_type = type;
6c02eaa1d   J. Bruce Fields   nfsd4: use helper...
303
  	fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  	dp->dl_time = 0;
  	atomic_set(&dp->dl_count, 1);
b5a1a81e5   J. Bruce Fields   nfsd4: don't slee...
306
  	INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
  	return dp;
  }
  
  void
  nfs4_put_delegation(struct nfs4_delegation *dp)
  {
  	if (atomic_dec_and_test(&dp->dl_count)) {
  		dprintk("NFSD: freeing dp %p
  ",dp);
13cd21845   NeilBrown   [PATCH] nfsd4: re...
316
  		put_nfs4_file(dp->dl_file);
5b2d21c19   NeilBrown   [PATCH] nfsd4: sl...
317
  		kmem_cache_free(deleg_slab, dp);
ef0f3390e   NeilBrown   [PATCH] knfsd: nf...
318
  		num_delegations--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	}
  }
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
321
  static void nfs4_put_deleg_lease(struct nfs4_file *fp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  {
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
323
324
325
  	if (atomic_dec_and_test(&fp->fi_delegees)) {
  		vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
  		fp->fi_lease = NULL;
4ee63624f   J. Bruce Fields   nfsd4: fix struct...
326
  		fput(fp->fi_deleg_file);
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
327
328
  		fp->fi_deleg_file = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  }
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
330
331
  static void unhash_stid(struct nfs4_stid *s)
  {
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
332
333
334
  	struct idr *stateids = &s->sc_client->cl_stateids;
  
  	idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
335
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
  /* Called under the state lock. */
  static void
  unhash_delegation(struct nfs4_delegation *dp)
  {
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
340
  	unhash_stid(&dp->dl_stid);
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
341
  	list_del_init(&dp->dl_perclnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  	spin_lock(&recall_lock);
5d926e8c2   J. Bruce Fields   nfsd4: modify fi_...
343
  	list_del_init(&dp->dl_perfile);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
  	list_del_init(&dp->dl_recall_lru);
  	spin_unlock(&recall_lock);
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
346
  	nfs4_put_deleg_lease(dp->dl_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
351
352
  	nfs4_put_delegation(dp);
  }
  
  /* 
   * SETCLIENTID state 
   */
36acb66bd   Benny Halevy   nfsd4: extend the...
353
  /* client_lock protects the client lru list and session hash table */
9089f1b47   Benny Halevy   nfsd4: rename ses...
354
  static DEFINE_SPINLOCK(client_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
  /* Hash tables for nfs4_clientid state */
  #define CLIENT_HASH_BITS                 4
  #define CLIENT_HASH_SIZE                (1 << CLIENT_HASH_BITS)
  #define CLIENT_HASH_MASK                (CLIENT_HASH_SIZE - 1)
ddc04c416   J. Bruce Fields   nfsd4: replace so...
359
360
361
362
363
364
365
366
367
  static unsigned int clientid_hashval(u32 id)
  {
  	return id & CLIENT_HASH_MASK;
  }
  
  static unsigned int clientstr_hashval(const char *name)
  {
  	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  /*
   * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
   * used in reboot/reset lease grace period processing
   *
   * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
   * setclientid_confirmed info. 
   *
   * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed 
   * setclientid info.
   *
   * client_lru holds client queue ordered by nfs4_client.cl_time
   * for lease renewal.
   *
   * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
   * for last close replay.
   */
  static struct list_head	reclaim_str_hashtbl[CLIENT_HASH_SIZE];
  static int reclaim_str_hashtbl_size = 0;
  static struct list_head	conf_id_hashtbl[CLIENT_HASH_SIZE];
  static struct list_head	conf_str_hashtbl[CLIENT_HASH_SIZE];
  static struct list_head	unconf_str_hashtbl[CLIENT_HASH_SIZE];
  static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
  static struct list_head client_lru;
  static struct list_head close_lru;
f9d7562fd   J. Bruce Fields   nfsd4: share file...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  /*
   * We store the NONE, READ, WRITE, and BOTH bits separately in the
   * st_{access,deny}_bmap field of the stateid, in order to track not
   * only what share bits are currently in force, but also what
   * combinations of share bits previous opens have used.  This allows us
   * to enforce the recommendation of rfc 3530 14.2.19 that the server
   * return an error if the client attempt to downgrade to a combination
   * of share bits not explicable by closing some of its previous opens.
   *
   * XXX: This enforcement is actually incomplete, since we don't keep
   * track of access/deny bit combinations; so, e.g., we allow:
   *
   *	OPEN allow read, deny write
   *	OPEN allow both, deny none
   *	DOWNGRADE allow read, deny none
   *
   * which we should reject.
   */
  static void
  set_access(unsigned int *access, unsigned long bmap) {
  	int i;
  
  	*access = 0;
  	for (i = 1; i < 4; i++) {
  		if (test_bit(i, &bmap))
  			*access |= i;
  	}
  }
  
  static void
  set_deny(unsigned int *deny, unsigned long bmap) {
  	int i;
  
  	*deny = 0;
  	for (i = 0; i < 4; i++) {
  		if (test_bit(i, &bmap))
  			*deny |= i ;
  	}
  }
  
  static int
dcef0413d   J. Bruce Fields   nfsd4: move some ...
433
  test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
f9d7562fd   J. Bruce Fields   nfsd4: share file...
434
435
436
437
438
439
440
441
442
443
444
  	unsigned int access, deny;
  
  	set_access(&access, stp->st_access_bmap);
  	set_deny(&deny, stp->st_deny_bmap);
  	if ((access & open->op_share_deny) || (deny & open->op_share_access))
  		return 0;
  	return 1;
  }
  
  static int nfs4_access_to_omode(u32 access)
  {
8f34a430a   J. Bruce Fields   nfsd4: mask out n...
445
  	switch (access & NFS4_SHARE_ACCESS_BOTH) {
f9d7562fd   J. Bruce Fields   nfsd4: share file...
446
447
448
449
450
451
452
453
454
  	case NFS4_SHARE_ACCESS_READ:
  		return O_RDONLY;
  	case NFS4_SHARE_ACCESS_WRITE:
  		return O_WRONLY;
  	case NFS4_SHARE_ACCESS_BOTH:
  		return O_RDWR;
  	}
  	BUG();
  }
dcef0413d   J. Bruce Fields   nfsd4: move some ...
455
  static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
456
  {
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
457
458
459
  	list_del(&stp->st_perfile);
  	list_del(&stp->st_perstateowner);
  }
dcef0413d   J. Bruce Fields   nfsd4: move some ...
460
  static void close_generic_stateid(struct nfs4_ol_stateid *stp)
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
461
  {
499f3edc2   J. Bruce Fields   nfsd4: remember t...
462
  	int i;
0997b1736   J. Bruce Fields   nfsd4: fix struct...
463

23fcf2ec9   J. Bruce Fields   nfsd4: fix oops o...
464
  	if (stp->st_access_bmap) {
499f3edc2   J. Bruce Fields   nfsd4: remember t...
465
466
467
468
  		for (i = 1; i < 4; i++) {
  			if (test_bit(i, &stp->st_access_bmap))
  				nfs4_file_put_access(stp->st_file,
  						nfs4_access_to_omode(i));
4665e2bac   J. Bruce Fields   nfsd4: split out ...
469
  			__clear_bit(i, &stp->st_access_bmap);
499f3edc2   J. Bruce Fields   nfsd4: remember t...
470
  		}
23fcf2ec9   J. Bruce Fields   nfsd4: fix oops o...
471
  	}
a96e5b908   OGAWA Hirofumi   nfsd4: Fix filp leak
472
  	put_nfs4_file(stp->st_file);
4665e2bac   J. Bruce Fields   nfsd4: split out ...
473
474
  	stp->st_file = NULL;
  }
dcef0413d   J. Bruce Fields   nfsd4: move some ...
475
  static void free_generic_stateid(struct nfs4_ol_stateid *stp)
4665e2bac   J. Bruce Fields   nfsd4: split out ...
476
  {
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
477
478
  	kmem_cache_free(stateid_slab, stp);
  }
dcef0413d   J. Bruce Fields   nfsd4: move some ...
479
  static void release_lock_stateid(struct nfs4_ol_stateid *stp)
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
480
481
482
483
  {
  	struct file *file;
  
  	unhash_generic_stateid(stp);
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
484
  	unhash_stid(&stp->st_stid);
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
485
486
  	file = find_any_file(stp->st_file);
  	if (file)
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
487
  		locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
38c387b52   J. Bruce Fields   nfsd4: match clos...
488
  	close_generic_stateid(stp);
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
489
490
  	free_generic_stateid(stp);
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
491
  static void unhash_lockowner(struct nfs4_lockowner *lo)
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
492
  {
dcef0413d   J. Bruce Fields   nfsd4: move some ...
493
  	struct nfs4_ol_stateid *stp;
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
494

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
495
496
  	list_del(&lo->lo_owner.so_strhash);
  	list_del(&lo->lo_perstateid);
009673b43   J. Bruce Fields   nfsd4: add a sepa...
497
  	list_del(&lo->lo_owner_ino_hash);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
498
499
  	while (!list_empty(&lo->lo_owner.so_stateids)) {
  		stp = list_first_entry(&lo->lo_owner.so_stateids,
dcef0413d   J. Bruce Fields   nfsd4: move some ...
500
  				struct nfs4_ol_stateid, st_perstateowner);
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
501
502
503
  		release_lock_stateid(stp);
  	}
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
504
  static void release_lockowner(struct nfs4_lockowner *lo)
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
505
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
506
507
  	unhash_lockowner(lo);
  	nfs4_free_lockowner(lo);
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
508
509
510
  }
  
  static void
dcef0413d   J. Bruce Fields   nfsd4: move some ...
511
  release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
512
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
513
  	struct nfs4_lockowner *lo;
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
514
515
  
  	while (!list_empty(&open_stp->st_lockowners)) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
516
517
518
  		lo = list_entry(open_stp->st_lockowners.next,
  				struct nfs4_lockowner, lo_perstateid);
  		release_lockowner(lo);
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
519
520
  	}
  }
38c387b52   J. Bruce Fields   nfsd4: match clos...
521
  static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
2283963f2   J. Bruce Fields   nfsd4: split lock...
522
523
524
  {
  	unhash_generic_stateid(stp);
  	release_stateid_lockowners(stp);
38c387b52   J. Bruce Fields   nfsd4: match clos...
525
526
527
528
529
530
  	close_generic_stateid(stp);
  }
  
  static void release_open_stateid(struct nfs4_ol_stateid *stp)
  {
  	unhash_open_stateid(stp);
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
531
  	unhash_stid(&stp->st_stid);
2283963f2   J. Bruce Fields   nfsd4: split lock...
532
533
  	free_generic_stateid(stp);
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
534
  static void unhash_openowner(struct nfs4_openowner *oo)
f1d110caf   J. Bruce Fields   nfsd4: remove a f...
535
  {
dcef0413d   J. Bruce Fields   nfsd4: move some ...
536
  	struct nfs4_ol_stateid *stp;
f1d110caf   J. Bruce Fields   nfsd4: remove a f...
537

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
538
539
540
541
  	list_del(&oo->oo_owner.so_strhash);
  	list_del(&oo->oo_perclient);
  	while (!list_empty(&oo->oo_owner.so_stateids)) {
  		stp = list_first_entry(&oo->oo_owner.so_stateids,
dcef0413d   J. Bruce Fields   nfsd4: move some ...
542
  				struct nfs4_ol_stateid, st_perstateowner);
f044ff830   J. Bruce Fields   nfsd4: split open...
543
  		release_open_stateid(stp);
f1d110caf   J. Bruce Fields   nfsd4: remove a f...
544
545
  	}
  }
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
546
547
548
549
550
  static void release_last_closed_stateid(struct nfs4_openowner *oo)
  {
  	struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
  
  	if (s) {
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
551
  		unhash_stid(&s->st_stid);
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
552
553
554
555
  		free_generic_stateid(s);
  		oo->oo_last_closed_stid = NULL;
  	}
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
556
  static void release_openowner(struct nfs4_openowner *oo)
f1d110caf   J. Bruce Fields   nfsd4: remove a f...
557
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
558
559
  	unhash_openowner(oo);
  	list_del(&oo->oo_close_lru);
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
560
  	release_last_closed_stateid(oo);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
561
  	nfs4_free_openowner(oo);
f1d110caf   J. Bruce Fields   nfsd4: remove a f...
562
  }
5282fd724   Marc Eshel   nfsd41: sessionid...
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  #define SESSION_HASH_SIZE	512
  static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE];
  
  static inline int
  hash_sessionid(struct nfs4_sessionid *sessionid)
  {
  	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
  
  	return sid->sequence % SESSION_HASH_SIZE;
  }
  
  static inline void
  dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
  {
  	u32 *ptr = (u32 *)(&sessionid->data[0]);
  	dprintk("%s: %u:%u:%u:%u
  ", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
581
582
583
584
585
586
587
588
589
590
591
592
593
  static void
  gen_sessionid(struct nfsd4_session *ses)
  {
  	struct nfs4_client *clp = ses->se_client;
  	struct nfsd4_sessionid *sid;
  
  	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
  	sid->clientid = clp->cl_clientid;
  	sid->sequence = current_sessionid++;
  	sid->reserved = 0;
  }
  
  /*
a649637c7   Andy Adamson   nfsd41: bound for...
594
595
596
597
598
599
600
601
602
603
604
605
   * The protocol defines ca_maxresponssize_cached to include the size of
   * the rpc header, but all we need to cache is the data starting after
   * the end of the initial SEQUENCE operation--the rest we regenerate
   * each time.  Therefore we can advertise a ca_maxresponssize_cached
   * value that is the number of bytes in our cache plus a few additional
   * bytes.  In order to stay on the safe side, and not promise more than
   * we can cache, those additional bytes must be the minimum possible: 24
   * bytes of rpc header (xid through accept state, with AUTH_NULL
   * verifier), 12 for the compound header (with zero-length tag), and 44
   * for the SEQUENCE op response:
   */
  #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
557ce2646   Andy Adamson   nfsd41: replace p...
606
607
608
609
610
611
612
613
  static void
  free_session_slots(struct nfsd4_session *ses)
  {
  	int i;
  
  	for (i = 0; i < ses->se_fchannel.maxreqs; i++)
  		kfree(ses->se_slots[i]);
  }
a649637c7   Andy Adamson   nfsd41: bound for...
614
  /*
efe0cb6d5   J. Bruce Fields   nfsd4.1: common s...
615
616
617
618
619
620
621
   * We don't actually need to cache the rpc and session headers, so we
   * can allocate a little less for each slot:
   */
  static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
  {
  	return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
  }
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
622
  static int nfsd4_sanitize_slot_size(u32 size)
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
623
  {
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
624
625
  	size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
  	size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
626

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
627
628
  	return size;
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
629

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
630
631
  /*
   * XXX: If we run out of reserved DRC memory we could (up to a point)
a649637c7   Andy Adamson   nfsd41: bound for...
632
   * re-negotiate active sessions and reduce their slot usage to make
42b2aa86c   Justin P. Mattock   treewide: Fix typ...
633
   * room for new connections. For now we just fail the create session.
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
634
   */
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
635
  static int nfsd4_get_drc_mem(int slotsize, u32 num)
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
636
  {
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
637
  	int avail;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
638

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
639
  	num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
5d77ddfbc   Andy Adamson   nfsd41: sanity ch...
640

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
641
642
643
644
645
646
  	spin_lock(&nfsd_drc_lock);
  	avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
  			nfsd_drc_max_mem - nfsd_drc_mem_used);
  	num = min_t(int, num, avail / slotsize);
  	nfsd_drc_mem_used += num * slotsize;
  	spin_unlock(&nfsd_drc_lock);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
647

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
648
649
  	return num;
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
650

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
651
652
  static void nfsd4_put_drc_mem(int slotsize, int num)
  {
4bd9b0f4a   Andy Adamson   nfsd41: use globa...
653
  	spin_lock(&nfsd_drc_lock);
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
654
  	nfsd_drc_mem_used -= slotsize * num;
4bd9b0f4a   Andy Adamson   nfsd41: use globa...
655
  	spin_unlock(&nfsd_drc_lock);
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
656
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
657

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
658
659
660
661
  static struct nfsd4_session *alloc_session(int slotsize, int numslots)
  {
  	struct nfsd4_session *new;
  	int mem, i;
a649637c7   Andy Adamson   nfsd41: bound for...
662

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
663
664
665
  	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
  			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
  	mem = numslots * sizeof(struct nfsd4_slot *);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
666

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
667
668
669
  	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
  	if (!new)
  		return NULL;
557ce2646   Andy Adamson   nfsd41: replace p...
670
  	/* allocate each struct nfsd4_slot and data cache in one piece */
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
671
672
673
674
  	for (i = 0; i < numslots; i++) {
  		mem = sizeof(struct nfsd4_slot) + slotsize;
  		new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
  		if (!new->se_slots[i])
557ce2646   Andy Adamson   nfsd41: replace p...
675
  			goto out_free;
557ce2646   Andy Adamson   nfsd41: replace p...
676
  	}
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
677
678
679
680
681
682
  	return new;
  out_free:
  	while (i--)
  		kfree(new->se_slots[i]);
  	kfree(new);
  	return NULL;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
683
  }
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
684
  static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
685
  {
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
686
  	u32 maxrpc = nfsd_serv->sv_max_mesg;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
687

5b6feee96   J. Bruce Fields   nfsd4: clean up s...
688
  	new->maxreqs = numslots;
d2b217439   Mi Jinlong   nfs41: make sure ...
689
690
  	new->maxresp_cached = min_t(u32, req->maxresp_cached,
  					slotsize + NFSD_MIN_HDR_SEQ_SZ);
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
691
692
693
694
  	new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
  	new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
  	new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
695

19cf5c026   J. Bruce Fields   nfsd4: use callba...
696
697
698
699
700
  static void free_conn(struct nfsd4_conn *c)
  {
  	svc_xprt_put(c->cn_xprt);
  	kfree(c);
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
701

19cf5c026   J. Bruce Fields   nfsd4: use callba...
702
703
704
705
  static void nfsd4_conn_lost(struct svc_xpt_user *u)
  {
  	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
  	struct nfs4_client *clp = c->cn_session->se_client;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
706

19cf5c026   J. Bruce Fields   nfsd4: use callba...
707
708
709
710
711
712
  	spin_lock(&clp->cl_lock);
  	if (!list_empty(&c->cn_persession)) {
  		list_del(&c->cn_persession);
  		free_conn(c);
  	}
  	spin_unlock(&clp->cl_lock);
eea498066   J. Bruce Fields   nfsd4: re-probe c...
713
  	nfsd4_probe_callback(clp);
19cf5c026   J. Bruce Fields   nfsd4: use callba...
714
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
715

d29c374cd   J. Bruce Fields   nfsd4: track back...
716
  static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
717
  {
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
718
  	struct nfsd4_conn *conn;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
719

c7662518c   J. Bruce Fields   nfsd4: keep per-s...
720
721
  	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
  	if (!conn)
db90681d6   J. Bruce Fields   nfsd4: refactor c...
722
  		return NULL;
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
723
724
  	svc_xprt_get(rqstp->rq_xprt);
  	conn->cn_xprt = rqstp->rq_xprt;
d29c374cd   J. Bruce Fields   nfsd4: track back...
725
  	conn->cn_flags = flags;
db90681d6   J. Bruce Fields   nfsd4: refactor c...
726
727
728
  	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
  	return conn;
  }
a649637c7   Andy Adamson   nfsd41: bound for...
729

328ead287   J. Bruce Fields   nfsd4: add new co...
730
731
732
733
  static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
  {
  	conn->cn_session = ses;
  	list_add(&conn->cn_persession, &ses->se_conns);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
734
  }
db90681d6   J. Bruce Fields   nfsd4: refactor c...
735
  static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
557ce2646   Andy Adamson   nfsd41: replace p...
736
  {
db90681d6   J. Bruce Fields   nfsd4: refactor c...
737
  	struct nfs4_client *clp = ses->se_client;
557ce2646   Andy Adamson   nfsd41: replace p...
738

c7662518c   J. Bruce Fields   nfsd4: keep per-s...
739
  	spin_lock(&clp->cl_lock);
328ead287   J. Bruce Fields   nfsd4: add new co...
740
  	__nfsd4_hash_conn(conn, ses);
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
741
  	spin_unlock(&clp->cl_lock);
557ce2646   Andy Adamson   nfsd41: replace p...
742
  }
21b75b019   J. Bruce Fields   nfsd4: fix 4.1 co...
743
  static int nfsd4_register_conn(struct nfsd4_conn *conn)
efe0cb6d5   J. Bruce Fields   nfsd4.1: common s...
744
  {
19cf5c026   J. Bruce Fields   nfsd4: use callba...
745
  	conn->cn_xpt_user.callback = nfsd4_conn_lost;
21b75b019   J. Bruce Fields   nfsd4: fix 4.1 co...
746
  	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
efe0cb6d5   J. Bruce Fields   nfsd4.1: common s...
747
  }
1d1bc8f20   J. Bruce Fields   nfsd4: support BI...
748
  static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
749
  {
db90681d6   J. Bruce Fields   nfsd4: refactor c...
750
  	struct nfsd4_conn *conn;
21b75b019   J. Bruce Fields   nfsd4: fix 4.1 co...
751
  	int ret;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
752

1d1bc8f20   J. Bruce Fields   nfsd4: support BI...
753
  	conn = alloc_conn(rqstp, dir);
db90681d6   J. Bruce Fields   nfsd4: refactor c...
754
755
756
  	if (!conn)
  		return nfserr_jukebox;
  	nfsd4_hash_conn(conn, ses);
21b75b019   J. Bruce Fields   nfsd4: fix 4.1 co...
757
758
759
760
  	ret = nfsd4_register_conn(conn);
  	if (ret)
  		/* oops; xprt is already down: */
  		nfsd4_conn_lost(&conn->cn_xpt_user);
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
761
762
  	return nfs_ok;
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
763

1d1bc8f20   J. Bruce Fields   nfsd4: support BI...
764
765
766
767
768
769
770
771
772
773
774
  static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
  {
  	u32 dir = NFS4_CDFC4_FORE;
  
  	if (ses->se_flags & SESSION4_BACK_CHAN)
  		dir |= NFS4_CDFC4_BACK;
  
  	return nfsd4_new_conn(rqstp, ses, dir);
  }
  
  /* must be called under client_lock */
19cf5c026   J. Bruce Fields   nfsd4: use callba...
775
  static void nfsd4_del_conns(struct nfsd4_session *s)
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
776
  {
19cf5c026   J. Bruce Fields   nfsd4: use callba...
777
778
  	struct nfs4_client *clp = s->se_client;
  	struct nfsd4_conn *c;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
779

19cf5c026   J. Bruce Fields   nfsd4: use callba...
780
781
782
783
784
  	spin_lock(&clp->cl_lock);
  	while (!list_empty(&s->se_conns)) {
  		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
  		list_del_init(&c->cn_persession);
  		spin_unlock(&clp->cl_lock);
557ce2646   Andy Adamson   nfsd41: replace p...
785

19cf5c026   J. Bruce Fields   nfsd4: use callba...
786
787
  		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
  		free_conn(c);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
788

19cf5c026   J. Bruce Fields   nfsd4: use callba...
789
790
791
  		spin_lock(&clp->cl_lock);
  	}
  	spin_unlock(&clp->cl_lock);
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
792
  }
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
793

c7662518c   J. Bruce Fields   nfsd4: keep per-s...
794
795
796
797
798
799
  void free_session(struct kref *kref)
  {
  	struct nfsd4_session *ses;
  	int mem;
  
  	ses = container_of(kref, struct nfsd4_session, se_ref);
19cf5c026   J. Bruce Fields   nfsd4: use callba...
800
  	nfsd4_del_conns(ses);
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
801
802
803
804
805
806
807
  	spin_lock(&nfsd_drc_lock);
  	mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
  	nfsd_drc_mem_used -= mem;
  	spin_unlock(&nfsd_drc_lock);
  	free_session_slots(ses);
  	kfree(ses);
  }
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
808
  static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
809
810
811
812
  {
  	struct nfsd4_session *new;
  	struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
  	int numslots, slotsize;
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
813
  	int status;
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
814
815
816
817
818
819
820
821
822
823
824
  	int idx;
  
  	/*
  	 * Note decreasing slot size below client's request may
  	 * make it difficult for client to function correctly, whereas
  	 * decreasing the number of slots will (just?) affect
  	 * performance.  When short on memory we therefore prefer to
  	 * decrease number of slots instead of their size.
  	 */
  	slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
  	numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
ced6dfe9f   Mi Jinlong   NFS4.1: server ge...
825
826
  	if (numslots < 1)
  		return NULL;
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
827
828
829
830
  
  	new = alloc_session(slotsize, numslots);
  	if (!new) {
  		nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
831
  		return NULL;
557ce2646   Andy Adamson   nfsd41: replace p...
832
  	}
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
833
  	init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
557ce2646   Andy Adamson   nfsd41: replace p...
834

ec6b5d7b5   Andy Adamson   nfsd41: create_se...
835
836
  	new->se_client = clp;
  	gen_sessionid(new);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
837

c7662518c   J. Bruce Fields   nfsd4: keep per-s...
838
  	INIT_LIST_HEAD(&new->se_conns);
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
839
  	new->se_cb_seq_nr = 1;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
840
  	new->se_flags = cses->flags;
8b5ce5cd4   J. Bruce Fields   nfsd4: callback p...
841
  	new->se_cb_prog = cses->callback_prog;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
842
  	kref_init(&new->se_ref);
5b6feee96   J. Bruce Fields   nfsd4: clean up s...
843
  	idx = hash_sessionid(&new->se_sessionid);
9089f1b47   Benny Halevy   nfsd4: rename ses...
844
  	spin_lock(&client_lock);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
845
  	list_add(&new->se_hash, &sessionid_hashtbl[idx]);
4c6493785   J. Bruce Fields   nfsd4: modify ses...
846
  	spin_lock(&clp->cl_lock);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
847
  	list_add(&new->se_perclnt, &clp->cl_sessions);
4c6493785   J. Bruce Fields   nfsd4: modify ses...
848
  	spin_unlock(&clp->cl_lock);
9089f1b47   Benny Halevy   nfsd4: rename ses...
849
  	spin_unlock(&client_lock);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
850

1d1bc8f20   J. Bruce Fields   nfsd4: support BI...
851
  	status = nfsd4_new_conn_from_crses(rqstp, new);
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
852
  	/* whoops: benny points out, status is ignored! (err, or bogus) */
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
853
854
  	if (status) {
  		free_session(&new->se_ref);
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
855
  		return NULL;
c7662518c   J. Bruce Fields   nfsd4: keep per-s...
856
  	}
dcbeaa68d   J. Bruce Fields   nfsd4: allow back...
857
  	if (cses->flags & SESSION4_BACK_CHAN) {
edd767866   J. Bruce Fields   nfsd4: move callb...
858
  		struct sockaddr *sa = svc_addr(rqstp);
dcbeaa68d   J. Bruce Fields   nfsd4: allow back...
859
860
861
862
863
864
865
  		/*
  		 * This is a little silly; with sessions there's no real
  		 * use for the callback address.  Use the peer address
  		 * as a reasonable default for now, but consider fixing
  		 * the rpc client not to require an address in the
  		 * future:
  		 */
edd767866   J. Bruce Fields   nfsd4: move callb...
866
867
  		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
  		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
edd767866   J. Bruce Fields   nfsd4: move callb...
868
  	}
dcbeaa68d   J. Bruce Fields   nfsd4: allow back...
869
  	nfsd4_probe_callback(clp);
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
870
  	return new;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
871
  }
9089f1b47   Benny Halevy   nfsd4: rename ses...
872
  /* caller must hold client_lock */
5282fd724   Marc Eshel   nfsd41: sessionid...
873
874
875
876
877
878
879
880
  static struct nfsd4_session *
  find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid)
  {
  	struct nfsd4_session *elem;
  	int idx;
  
  	dump_sessionid(__func__, sessionid);
  	idx = hash_sessionid(sessionid);
5282fd724   Marc Eshel   nfsd41: sessionid...
881
882
  	/* Search in the appropriate list */
  	list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
5282fd724   Marc Eshel   nfsd41: sessionid...
883
884
885
886
887
888
889
890
891
892
  		if (!memcmp(elem->se_sessionid.data, sessionid->data,
  			    NFS4_MAX_SESSIONID_LEN)) {
  			return elem;
  		}
  	}
  
  	dprintk("%s: session not found
  ", __func__);
  	return NULL;
  }
9089f1b47   Benny Halevy   nfsd4: rename ses...
893
  /* caller must hold client_lock */
7116ed6b9   Andy Adamson   nfsd41: sessions ...
894
  static void
5282fd724   Marc Eshel   nfsd41: sessionid...
895
  unhash_session(struct nfsd4_session *ses)
7116ed6b9   Andy Adamson   nfsd41: sessions ...
896
897
  {
  	list_del(&ses->se_hash);
4c6493785   J. Bruce Fields   nfsd4: modify ses...
898
  	spin_lock(&ses->se_client->cl_lock);
7116ed6b9   Andy Adamson   nfsd41: sessions ...
899
  	list_del(&ses->se_perclnt);
4c6493785   J. Bruce Fields   nfsd4: modify ses...
900
  	spin_unlock(&ses->se_client->cl_lock);
5282fd724   Marc Eshel   nfsd41: sessionid...
901
  }
36acb66bd   Benny Halevy   nfsd4: extend the...
902
  /* must be called under the client_lock */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  static inline void
36acb66bd   Benny Halevy   nfsd4: extend the...
904
  renew_client_locked(struct nfs4_client *clp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  {
07cd4909a   Benny Halevy   nfsd4: mark_clien...
906
907
908
909
910
911
912
913
  	if (is_client_expired(clp)) {
  		dprintk("%s: client (clientid %08x/%08x) already expired
  ",
  			__func__,
  			clp->cl_clientid.cl_boot,
  			clp->cl_clientid.cl_id);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
918
919
920
  	dprintk("renewing client (clientid %08x/%08x)
  ", 
  			clp->cl_clientid.cl_boot, 
  			clp->cl_clientid.cl_id);
  	list_move_tail(&clp->cl_lru, &client_lru);
  	clp->cl_time = get_seconds();
  }
36acb66bd   Benny Halevy   nfsd4: extend the...
921
922
923
924
925
926
927
  static inline void
  renew_client(struct nfs4_client *clp)
  {
  	spin_lock(&client_lock);
  	renew_client_locked(clp);
  	spin_unlock(&client_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
931
932
933
  /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
  static int
  STALE_CLIENTID(clientid_t *clid)
  {
  	if (clid->cl_boot == boot_time)
  		return 0;
60adfc50d   Andy Adamson   nfsd41: clientid ...
934
935
936
  	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx
  ",
  		clid->cl_boot, clid->cl_id, boot_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
939
940
941
942
943
944
  	return 1;
  }
  
  /* 
   * XXX Should we use a slab cache ?
   * This type of memory management is somewhat inefficient, but we use it
   * anyway since SETCLIENTID is not a common operation.
   */
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
945
  static struct nfs4_client *alloc_client(struct xdr_netobj name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
  {
  	struct nfs4_client *clp;
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
948
949
950
  	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
  	if (clp == NULL)
  		return NULL;
67114fe61   Thomas Meyer   nfsd4: Use kmemdu...
951
  	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
952
953
954
  	if (clp->cl_name.data == NULL) {
  		kfree(clp);
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
  	}
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
956
  	clp->cl_name.len = name.len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
961
962
  	return clp;
  }
  
  static inline void
  free_client(struct nfs4_client *clp)
  {
792c95dd5   J. Bruce Fields   nfsd4: delay sess...
963
964
965
966
967
968
969
  	while (!list_empty(&clp->cl_sessions)) {
  		struct nfsd4_session *ses;
  		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
  				se_perclnt);
  		list_del(&ses->se_perclnt);
  		nfsd4_put_session(ses);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
  	if (clp->cl_cred.cr_group_info)
  		put_group_info(clp->cl_cred.cr_group_info);
68e76ad0b   Olga Kornievskaia   nfsd: pass client...
972
  	kfree(clp->cl_principal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
974
975
  	kfree(clp->cl_name.data);
  	kfree(clp);
  }
d76829889   Benny Halevy   nfsd4: keep a ref...
976
977
978
979
980
981
982
983
984
985
986
987
988
  void
  release_session_client(struct nfsd4_session *session)
  {
  	struct nfs4_client *clp = session->se_client;
  
  	if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock))
  		return;
  	if (is_client_expired(clp)) {
  		free_client(clp);
  		session->se_client = NULL;
  	} else
  		renew_client_locked(clp);
  	spin_unlock(&client_lock);
d76829889   Benny Halevy   nfsd4: keep a ref...
989
  }
84d38ac9a   Benny Halevy   nfsd4: refactor e...
990
991
992
993
  /* must be called under the client_lock */
  static inline void
  unhash_client_locked(struct nfs4_client *clp)
  {
792c95dd5   J. Bruce Fields   nfsd4: delay sess...
994
  	struct nfsd4_session *ses;
07cd4909a   Benny Halevy   nfsd4: mark_clien...
995
  	mark_client_expired(clp);
84d38ac9a   Benny Halevy   nfsd4: refactor e...
996
  	list_del(&clp->cl_lru);
4c6493785   J. Bruce Fields   nfsd4: modify ses...
997
  	spin_lock(&clp->cl_lock);
792c95dd5   J. Bruce Fields   nfsd4: delay sess...
998
999
  	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
  		list_del_init(&ses->se_hash);
4c6493785   J. Bruce Fields   nfsd4: modify ses...
1000
  	spin_unlock(&clp->cl_lock);
84d38ac9a   Benny Halevy   nfsd4: refactor e...
1001
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
  static void
  expire_client(struct nfs4_client *clp)
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
1005
  	struct nfs4_openowner *oo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  	struct nfs4_delegation *dp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  	struct list_head reaplist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  	INIT_LIST_HEAD(&reaplist);
  	spin_lock(&recall_lock);
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
1010
1011
  	while (!list_empty(&clp->cl_delegations)) {
  		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
1012
  		list_del_init(&dp->dl_perclnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
1016
1017
  		list_move(&dp->dl_recall_lru, &reaplist);
  	}
  	spin_unlock(&recall_lock);
  	while (!list_empty(&reaplist)) {
  		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
  		unhash_delegation(dp);
  	}
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
1020
  	while (!list_empty(&clp->cl_openowners)) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
1021
1022
  		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
  		release_openowner(oo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
  	}
6ff8da088   J. Bruce Fields   nfsd4: Move callb...
1024
  	nfsd4_shutdown_callback(clp);
84d38ac9a   Benny Halevy   nfsd4: refactor e...
1025
1026
  	if (clp->cl_cb_conn.cb_xprt)
  		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
36acb66bd   Benny Halevy   nfsd4: extend the...
1027
1028
  	list_del(&clp->cl_idhash);
  	list_del(&clp->cl_strhash);
be1fdf6c4   Benny Halevy   nfsd4: fold relea...
1029
  	spin_lock(&client_lock);
84d38ac9a   Benny Halevy   nfsd4: refactor e...
1030
  	unhash_client_locked(clp);
46583e259   Benny Halevy   nfsd4: introduce ...
1031
1032
  	if (atomic_read(&clp->cl_refcount) == 0)
  		free_client(clp);
be1fdf6c4   Benny Halevy   nfsd4: fold relea...
1033
  	spin_unlock(&client_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
  }
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
1035
1036
1037
1038
  static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
  {
  	memcpy(target->cl_verifier.data, source->data,
  			sizeof(target->cl_verifier.data));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
  }
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
1040
1041
  static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
  	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 
  	target->cl_clientid.cl_id = source->cl_clientid.cl_id; 
  }
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
1045
1046
  static void copy_cred(struct svc_cred *target, struct svc_cred *source)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
1049
1050
1051
  	target->cr_uid = source->cr_uid;
  	target->cr_gid = source->cr_gid;
  	target->cr_group_info = source->cr_group_info;
  	get_group_info(target->cr_group_info);
  }
35bba9a37   J. Bruce Fields   nfsd4: miscellane...
1052
  static int same_name(const char *n1, const char *n2)
599e0a229   J. Bruce Fields   knfsd: cleanup of...
1053
  {
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
1054
  	return 0 == memcmp(n1, n2, HEXDIR_LEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
1057
  }
  
  static int
599e0a229   J. Bruce Fields   knfsd: cleanup of...
1058
1059
1060
  same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
  {
  	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
1063
  }
  
  static int
599e0a229   J. Bruce Fields   knfsd: cleanup of...
1064
1065
1066
  same_clid(clientid_t *cl1, clientid_t *cl2)
  {
  	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
  }
  
  /* XXX what about NGROUP */
  static int
599e0a229   J. Bruce Fields   knfsd: cleanup of...
1071
1072
1073
  same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
  {
  	return cr1->cr_uid == cr2->cr_uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
  }
5ec7b46c2   J. Bruce Fields   nfsd4: make curre...
1075
1076
1077
  static void gen_clid(struct nfs4_client *clp)
  {
  	static u32 current_clientid = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
1080
  	clp->cl_clientid.cl_boot = boot_time;
  	clp->cl_clientid.cl_id = current_clientid++; 
  }
deda2faa8   J. Bruce Fields   nfsd: uniquify cl...
1081
1082
1083
1084
  static void gen_confirm(struct nfs4_client *clp)
  {
  	static u32 i;
  	u32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
  	p = (u32 *)clp->cl_confirm.data;
deda2faa8   J. Bruce Fields   nfsd: uniquify cl...
1087
1088
  	*p++ = get_seconds();
  	*p++ = i++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
  }
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
1090
  static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
4581d1409   J. Bruce Fields   nfsd4: rearrange ...
1091
  {
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
1092
  	return idr_find(&cl->cl_stateids, t->si_opaque.so_id);
4d71ab875   J. Bruce Fields   nfsd4: split up f...
1093
  }
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
1094
  static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
f459e4535   J. Bruce Fields   nfsd4: hash deleg...
1095
1096
  {
  	struct nfs4_stid *s;
4d71ab875   J. Bruce Fields   nfsd4: split up f...
1097

38c2f4b12   J. Bruce Fields   nfsd4: look up st...
1098
  	s = find_stateid(cl, t);
4d71ab875   J. Bruce Fields   nfsd4: split up f...
1099
1100
  	if (!s)
  		return NULL;
f459e4535   J. Bruce Fields   nfsd4: hash deleg...
1101
  	if (typemask & s->sc_type)
4581d1409   J. Bruce Fields   nfsd4: rearrange ...
1102
  		return s;
4581d1409   J. Bruce Fields   nfsd4: rearrange ...
1103
1104
  	return NULL;
  }
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
  static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
  		struct svc_rqst *rqstp, nfs4_verifier *verf)
  {
  	struct nfs4_client *clp;
  	struct sockaddr *sa = svc_addr(rqstp);
  	char *princ;
  
  	clp = alloc_client(name);
  	if (clp == NULL)
  		return NULL;
792c95dd5   J. Bruce Fields   nfsd4: delay sess...
1115
  	INIT_LIST_HEAD(&clp->cl_sessions);
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1116
1117
1118
1119
1120
1121
1122
1123
  	princ = svc_gss_principal(rqstp);
  	if (princ) {
  		clp->cl_principal = kstrdup(princ, GFP_KERNEL);
  		if (clp->cl_principal == NULL) {
  			free_client(clp);
  			return NULL;
  		}
  	}
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
1124
  	idr_init(&clp->cl_stateids);
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1125
  	memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
46583e259   Benny Halevy   nfsd4: introduce ...
1126
  	atomic_set(&clp->cl_refcount, 0);
77a3569d6   J. Bruce Fields   nfsd4: keep finer...
1127
  	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1128
1129
1130
1131
  	INIT_LIST_HEAD(&clp->cl_idhash);
  	INIT_LIST_HEAD(&clp->cl_strhash);
  	INIT_LIST_HEAD(&clp->cl_openowners);
  	INIT_LIST_HEAD(&clp->cl_delegations);
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1132
  	INIT_LIST_HEAD(&clp->cl_lru);
5ce8ba25d   J. Bruce Fields   nfsd4: allow rest...
1133
  	INIT_LIST_HEAD(&clp->cl_callbacks);
6ff8da088   J. Bruce Fields   nfsd4: Move callb...
1134
  	spin_lock_init(&clp->cl_lock);
cee277d92   J. Bruce Fields   nfsd4: use generi...
1135
  	INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
07cd4909a   Benny Halevy   nfsd4: mark_clien...
1136
  	clp->cl_time = get_seconds();
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1137
1138
1139
1140
1141
1142
1143
  	clear_bit(0, &clp->cl_cb_slot_busy);
  	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
  	copy_verf(clp, verf);
  	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
  	clp->cl_flavor = rqstp->rq_flavor;
  	copy_cred(&clp->cl_cred, &rqstp->rq_cred);
  	gen_confirm(clp);
edd767866   J. Bruce Fields   nfsd4: move callb...
1144
  	clp->cl_cb_session = NULL;
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1145
1146
  	return clp;
  }
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
1147
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
1150
1151
1152
1153
1154
  add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
  {
  	unsigned int idhashval;
  
  	list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]);
  	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
  	list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);
36acb66bd   Benny Halevy   nfsd4: extend the...
1155
  	renew_client(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
  }
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
1157
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
1162
1163
1164
  move_to_confirmed(struct nfs4_client *clp)
  {
  	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
  	unsigned int strhashval;
  
  	dprintk("NFSD: move_to_confirm nfs4_client %p
  ", clp);
f116629d0   Akinobu Mita   [PATCH] fs: use l...
1165
  	list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
1166
  	strhashval = clientstr_hashval(clp->cl_recdir);
328efbab0   Benny Halevy   nfsd4: use list_m...
1167
  	list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
  	renew_client(clp);
  }
  
  static struct nfs4_client *
  find_confirmed_client(clientid_t *clid)
  {
  	struct nfs4_client *clp;
  	unsigned int idhashval = clientid_hashval(clid->cl_id);
  
  	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
a50d2ad17   J. Bruce Fields   nfsd4: centralize...
1178
1179
  		if (same_clid(&clp->cl_clientid, clid)) {
  			renew_client(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  			return clp;
a50d2ad17   J. Bruce Fields   nfsd4: centralize...
1181
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
  	}
  	return NULL;
  }
  
  static struct nfs4_client *
  find_unconfirmed_client(clientid_t *clid)
  {
  	struct nfs4_client *clp;
  	unsigned int idhashval = clientid_hashval(clid->cl_id);
  
  	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
599e0a229   J. Bruce Fields   knfsd: cleanup of...
1193
  		if (same_clid(&clp->cl_clientid, clid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
1196
1197
  			return clp;
  	}
  	return NULL;
  }
6e5f15c93   J. Bruce Fields   nfsd4: replace un...
1198
  static bool clp_used_exchangeid(struct nfs4_client *clp)
a1bcecd29   Andy Adamson   nfsd41: match cli...
1199
  {
6e5f15c93   J. Bruce Fields   nfsd4: replace un...
1200
  	return clp->cl_exchange_flags != 0;
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1201
  } 
a1bcecd29   Andy Adamson   nfsd41: match cli...
1202

28ce6054f   NeilBrown   [PATCH] knfsd: nf...
1203
  static struct nfs4_client *
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1204
  find_confirmed_client_by_str(const char *dname, unsigned int hashval)
28ce6054f   NeilBrown   [PATCH] knfsd: nf...
1205
1206
1207
1208
  {
  	struct nfs4_client *clp;
  
  	list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1209
  		if (same_name(clp->cl_recdir, dname))
28ce6054f   NeilBrown   [PATCH] knfsd: nf...
1210
1211
1212
1213
1214
1215
  			return clp;
  	}
  	return NULL;
  }
  
  static struct nfs4_client *
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1216
  find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
28ce6054f   NeilBrown   [PATCH] knfsd: nf...
1217
1218
1219
1220
  {
  	struct nfs4_client *clp;
  
  	list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1221
  		if (same_name(clp->cl_recdir, dname))
28ce6054f   NeilBrown   [PATCH] knfsd: nf...
1222
1223
1224
1225
  			return clp;
  	}
  	return NULL;
  }
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
1226
  static void
6f3d772fb   Takuma Umeya   nfs4: set source ...
1227
  gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
  {
07263f1ef   J. Bruce Fields   nfsd4: minor vari...
1229
  	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
6f3d772fb   Takuma Umeya   nfs4: set source ...
1230
1231
  	struct sockaddr	*sa = svc_addr(rqstp);
  	u32 scopeid = rpc_get_scope_id(sa);
7077ecbab   Jeff Layton   nfsd: add support...
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  	unsigned short expected_family;
  
  	/* Currently, we only support tcp and tcp6 for the callback channel */
  	if (se->se_callback_netid_len == 3 &&
  	    !memcmp(se->se_callback_netid_val, "tcp", 3))
  		expected_family = AF_INET;
  	else if (se->se_callback_netid_len == 4 &&
  		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
  		expected_family = AF_INET6;
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
  		goto out_err;
07263f1ef   J. Bruce Fields   nfsd4: minor vari...
1243
  	conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
aa9a4ec77   Jeff Layton   nfsd: convert nfs...
1244
  					    se->se_callback_addr_len,
07263f1ef   J. Bruce Fields   nfsd4: minor vari...
1245
1246
  					    (struct sockaddr *)&conn->cb_addr,
  					    sizeof(conn->cb_addr));
aa9a4ec77   Jeff Layton   nfsd: convert nfs...
1247

07263f1ef   J. Bruce Fields   nfsd4: minor vari...
1248
  	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
  		goto out_err;
aa9a4ec77   Jeff Layton   nfsd: convert nfs...
1250

07263f1ef   J. Bruce Fields   nfsd4: minor vari...
1251
1252
  	if (conn->cb_addr.ss_family == AF_INET6)
  		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
fbf4665f4   Jeff Layton   nfsd: populate si...
1253

07263f1ef   J. Bruce Fields   nfsd4: minor vari...
1254
1255
  	conn->cb_prog = se->se_callback_prog;
  	conn->cb_ident = se->se_callback_ident;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
1256
  	memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
1258
  	return;
  out_err:
07263f1ef   J. Bruce Fields   nfsd4: minor vari...
1259
1260
  	conn->cb_addr.ss_family = AF_UNSPEC;
  	conn->cb_addrlen = 0;
849823c52   Neil Brown   [PATCH] nfsd4: pr...
1261
  	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
1264
  		"will not receive delegations
  ",
  		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
1266
  	return;
  }
074fe8975   Andy Adamson   nfsd41: DRC save,...
1267
  /*
557ce2646   Andy Adamson   nfsd41: replace p...
1268
   * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size.
074fe8975   Andy Adamson   nfsd41: DRC save,...
1269
   */
074fe8975   Andy Adamson   nfsd41: DRC save,...
1270
1271
  void
  nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
074fe8975   Andy Adamson   nfsd41: DRC save,...
1272
  {
557ce2646   Andy Adamson   nfsd41: replace p...
1273
1274
  	struct nfsd4_slot *slot = resp->cstate.slot;
  	unsigned int base;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1275

557ce2646   Andy Adamson   nfsd41: replace p...
1276
1277
  	dprintk("--> %s slot %p
  ", __func__, slot);
074fe8975   Andy Adamson   nfsd41: DRC save,...
1278

557ce2646   Andy Adamson   nfsd41: replace p...
1279
1280
  	slot->sl_opcnt = resp->opcnt;
  	slot->sl_status = resp->cstate.status;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1281

bf864a31d   Andy Adamson   nfsd41: non-page ...
1282
  	if (nfsd4_not_cached(resp)) {
557ce2646   Andy Adamson   nfsd41: replace p...
1283
  		slot->sl_datalen = 0;
bf864a31d   Andy Adamson   nfsd41: non-page ...
1284
  		return;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1285
  	}
557ce2646   Andy Adamson   nfsd41: replace p...
1286
1287
1288
1289
1290
1291
1292
1293
  	slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap;
  	base = (char *)resp->cstate.datap -
  					(char *)resp->xbuf->head[0].iov_base;
  	if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data,
  				    slot->sl_datalen))
  		WARN("%s: sessions DRC could not cache compound
  ", __func__);
  	return;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1294
1295
1296
  }
  
  /*
abfabf8ca   Andy Adamson   nfsd41: encode re...
1297
1298
1299
1300
   * Encode the replay sequence operation from the slot values.
   * If cachethis is FALSE encode the uncached rep error on the next
   * operation which sets resp->p and increments resp->opcnt for
   * nfs4svc_encode_compoundres.
074fe8975   Andy Adamson   nfsd41: DRC save,...
1301
   *
074fe8975   Andy Adamson   nfsd41: DRC save,...
1302
   */
abfabf8ca   Andy Adamson   nfsd41: encode re...
1303
1304
1305
  static __be32
  nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
  			  struct nfsd4_compoundres *resp)
074fe8975   Andy Adamson   nfsd41: DRC save,...
1306
  {
abfabf8ca   Andy Adamson   nfsd41: encode re...
1307
1308
  	struct nfsd4_op *op;
  	struct nfsd4_slot *slot = resp->cstate.slot;
bf864a31d   Andy Adamson   nfsd41: non-page ...
1309

abfabf8ca   Andy Adamson   nfsd41: encode re...
1310
1311
  	dprintk("--> %s resp->opcnt %d cachethis %u 
  ", __func__,
557ce2646   Andy Adamson   nfsd41: replace p...
1312
  		resp->opcnt, resp->cstate.slot->sl_cachethis);
bf864a31d   Andy Adamson   nfsd41: non-page ...
1313

abfabf8ca   Andy Adamson   nfsd41: encode re...
1314
1315
1316
  	/* Encode the replayed sequence operation */
  	op = &args->ops[resp->opcnt - 1];
  	nfsd4_encode_operation(resp, op);
bf864a31d   Andy Adamson   nfsd41: non-page ...
1317

abfabf8ca   Andy Adamson   nfsd41: encode re...
1318
  	/* Return nfserr_retry_uncached_rep in next operation. */
557ce2646   Andy Adamson   nfsd41: replace p...
1319
  	if (args->opcnt > 1 && slot->sl_cachethis == 0) {
abfabf8ca   Andy Adamson   nfsd41: encode re...
1320
1321
1322
  		op = &args->ops[resp->opcnt++];
  		op->status = nfserr_retry_uncached_rep;
  		nfsd4_encode_operation(resp, op);
074fe8975   Andy Adamson   nfsd41: DRC save,...
1323
  	}
abfabf8ca   Andy Adamson   nfsd41: encode re...
1324
  	return op->status;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1325
1326
1327
  }
  
  /*
557ce2646   Andy Adamson   nfsd41: replace p...
1328
1329
   * The sequence operation is not cached because we can use the slot and
   * session values.
074fe8975   Andy Adamson   nfsd41: DRC save,...
1330
1331
   */
  __be32
bf864a31d   Andy Adamson   nfsd41: non-page ...
1332
1333
  nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
  			 struct nfsd4_sequence *seq)
074fe8975   Andy Adamson   nfsd41: DRC save,...
1334
  {
557ce2646   Andy Adamson   nfsd41: replace p...
1335
  	struct nfsd4_slot *slot = resp->cstate.slot;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1336
  	__be32 status;
557ce2646   Andy Adamson   nfsd41: replace p...
1337
1338
  	dprintk("--> %s slot %p
  ", __func__, slot);
074fe8975   Andy Adamson   nfsd41: DRC save,...
1339

abfabf8ca   Andy Adamson   nfsd41: encode re...
1340
1341
1342
1343
  	/* Either returns 0 or nfserr_retry_uncached */
  	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
  	if (status == nfserr_retry_uncached_rep)
  		return status;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1344

557ce2646   Andy Adamson   nfsd41: replace p...
1345
1346
  	/* The sequence operation has been encoded, cstate->datap set. */
  	memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen);
074fe8975   Andy Adamson   nfsd41: DRC save,...
1347

557ce2646   Andy Adamson   nfsd41: replace p...
1348
1349
1350
  	resp->opcnt = slot->sl_opcnt;
  	resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen);
  	status = slot->sl_status;
074fe8975   Andy Adamson   nfsd41: DRC save,...
1351
1352
1353
  
  	return status;
  }
0733d2133   Andy Adamson   nfsd41: exchange_...
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  /*
   * Set the exchange_id flags returned by the server.
   */
  static void
  nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
  {
  	/* pNFS is not supported */
  	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
  
  	/* Referrals are supported, Migration is not. */
  	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
  
  	/* set the wire flags to return to client. */
  	clid->flags = new->cl_exchange_flags;
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
1369
  __be32
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1370
1371
1372
1373
  nfsd4_exchange_id(struct svc_rqst *rqstp,
  		  struct nfsd4_compound_state *cstate,
  		  struct nfsd4_exchange_id *exid)
  {
0733d2133   Andy Adamson   nfsd41: exchange_...
1374
1375
1376
1377
  	struct nfs4_client *unconf, *conf, *new;
  	int status;
  	unsigned int		strhashval;
  	char			dname[HEXDIR_LEN];
363168b4e   Jeff Layton   nfsd: make nfs4_c...
1378
  	char			addr_str[INET6_ADDRSTRLEN];
0733d2133   Andy Adamson   nfsd41: exchange_...
1379
  	nfs4_verifier		verf = exid->verifier;
363168b4e   Jeff Layton   nfsd: make nfs4_c...
1380
  	struct sockaddr		*sa = svc_addr(rqstp);
0733d2133   Andy Adamson   nfsd41: exchange_...
1381

363168b4e   Jeff Layton   nfsd: make nfs4_c...
1382
  	rpc_ntop(sa, addr_str, sizeof(addr_str));
0733d2133   Andy Adamson   nfsd41: exchange_...
1383
  	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
363168b4e   Jeff Layton   nfsd: make nfs4_c...
1384
1385
  		"ip_addr=%s flags %x, spa_how %d
  ",
0733d2133   Andy Adamson   nfsd41: exchange_...
1386
  		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
363168b4e   Jeff Layton   nfsd: make nfs4_c...
1387
  		addr_str, exid->flags, exid->spa_how);
0733d2133   Andy Adamson   nfsd41: exchange_...
1388

a084daf51   J. Bruce Fields   nfsd4: move name-...
1389
  	if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
0733d2133   Andy Adamson   nfsd41: exchange_...
1390
1391
1392
1393
1394
1395
1396
  		return nfserr_inval;
  
  	/* Currently only support SP4_NONE */
  	switch (exid->spa_how) {
  	case SP4_NONE:
  		break;
  	case SP4_SSV:
044bc1d43   J. Bruce Fields   nfsd4: return ser...
1397
  		return nfserr_serverfault;
0733d2133   Andy Adamson   nfsd41: exchange_...
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
  	default:
  		BUG();				/* checked by xdr code */
  	case SP4_MACH_CRED:
  		return nfserr_serverfault;	/* no excuse :-/ */
  	}
  
  	status = nfs4_make_rec_clidname(dname, &exid->clname);
  
  	if (status)
  		goto error;
  
  	strhashval = clientstr_hashval(dname);
  
  	nfs4_lock_state();
  	status = nfs_ok;
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1413
  	conf = find_confirmed_client_by_str(dname, strhashval);
0733d2133   Andy Adamson   nfsd41: exchange_...
1414
  	if (conf) {
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1415
1416
1417
1418
  		if (!clp_used_exchangeid(conf)) {
  			status = nfserr_clid_inuse; /* XXX: ? */
  			goto out;
  		}
0733d2133   Andy Adamson   nfsd41: exchange_...
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
  		if (!same_verf(&verf, &conf->cl_verifier)) {
  			/* 18.35.4 case 8 */
  			if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
  				status = nfserr_not_same;
  				goto out;
  			}
  			/* Client reboot: destroy old state */
  			expire_client(conf);
  			goto out_new;
  		}
  		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
  			/* 18.35.4 case 9 */
  			if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
  				status = nfserr_perm;
  				goto out;
  			}
  			expire_client(conf);
  			goto out_new;
  		}
0733d2133   Andy Adamson   nfsd41: exchange_...
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  		/*
  		 * Set bit when the owner id and verifier map to an already
  		 * confirmed client id (18.35.3).
  		 */
  		exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
  
  		/*
  		 * Falling into 18.35.4 case 2, possible router replay.
  		 * Leave confirmed record intact and return same result.
  		 */
  		copy_verf(conf, &verf);
  		new = conf;
  		goto out_copy;
6ddbbbfe5   Mike Sager   nfsd41: Remove ip...
1451
1452
1453
1454
1455
1456
  	}
  
  	/* 18.35.4 case 7 */
  	if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
  		status = nfserr_noent;
  		goto out;
0733d2133   Andy Adamson   nfsd41: exchange_...
1457
  	}
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1458
  	unconf  = find_unconfirmed_client_by_str(dname, strhashval);
0733d2133   Andy Adamson   nfsd41: exchange_...
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
  	if (unconf) {
  		/*
  		 * Possible retry or client restart.  Per 18.35.4 case 4,
  		 * a new unconfirmed record should be generated regardless
  		 * of whether any properties have changed.
  		 */
  		expire_client(unconf);
  	}
  
  out_new:
  	/* Normal case */
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
1470
  	new = create_client(exid->clname, dname, rqstp, &verf);
0733d2133   Andy Adamson   nfsd41: exchange_...
1471
  	if (new == NULL) {
4731030d5   J. Bruce Fields   nfsd4: translate ...
1472
  		status = nfserr_jukebox;
0733d2133   Andy Adamson   nfsd41: exchange_...
1473
1474
  		goto out;
  	}
0733d2133   Andy Adamson   nfsd41: exchange_...
1475
  	gen_clid(new);
0733d2133   Andy Adamson   nfsd41: exchange_...
1476
1477
1478
1479
  	add_to_unconfirmed(new, strhashval);
  out_copy:
  	exid->clientid.cl_boot = new->cl_clientid.cl_boot;
  	exid->clientid.cl_id = new->cl_clientid.cl_id;
38eb76a54   Andy Adamson   nfsd41: Add a cre...
1480
  	exid->seqid = 1;
0733d2133   Andy Adamson   nfsd41: exchange_...
1481
1482
1483
1484
  	nfsd4_set_ex_flags(new, exid);
  
  	dprintk("nfsd4_exchange_id seqid %d flags %x
  ",
49557cc74   Andy Adamson   nfsd41: Use separ...
1485
  		new->cl_cs_slot.sl_seqid, new->cl_exchange_flags);
0733d2133   Andy Adamson   nfsd41: exchange_...
1486
1487
1488
1489
1490
1491
1492
1493
  	status = nfs_ok;
  
  out:
  	nfs4_unlock_state();
  error:
  	dprintk("nfsd4_exchange_id returns %d
  ", ntohl(status));
  	return status;
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1494
  }
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1495
  static int
88e588d56   Andy Adamson   nfsd41: change ch...
1496
  check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1497
  {
88e588d56   Andy Adamson   nfsd41: change ch...
1498
1499
1500
  	dprintk("%s enter. seqid %d slot_seqid %d
  ", __func__, seqid,
  		slot_seqid);
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1501
1502
  
  	/* The slot is in use, and no response has been sent. */
88e588d56   Andy Adamson   nfsd41: change ch...
1503
1504
  	if (slot_inuse) {
  		if (seqid == slot_seqid)
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1505
1506
1507
1508
1509
  			return nfserr_jukebox;
  		else
  			return nfserr_seq_misordered;
  	}
  	/* Normal */
88e588d56   Andy Adamson   nfsd41: change ch...
1510
  	if (likely(seqid == slot_seqid + 1))
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1511
1512
  		return nfs_ok;
  	/* Replay */
88e588d56   Andy Adamson   nfsd41: change ch...
1513
  	if (seqid == slot_seqid)
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1514
1515
  		return nfserr_replay_cache;
  	/* Wraparound */
88e588d56   Andy Adamson   nfsd41: change ch...
1516
  	if (seqid == 1 && (slot_seqid + 1) == 0)
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1517
1518
1519
1520
  		return nfs_ok;
  	/* Misordered replay or misordered new request */
  	return nfserr_seq_misordered;
  }
49557cc74   Andy Adamson   nfsd41: Use separ...
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
  /*
   * Cache the create session result into the create session single DRC
   * slot cache by saving the xdr structure. sl_seqid has been set.
   * Do this for solo or embedded create session operations.
   */
  static void
  nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
  			   struct nfsd4_clid_slot *slot, int nfserr)
  {
  	slot->sl_status = nfserr;
  	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
  }
  
  static __be32
  nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
  			    struct nfsd4_clid_slot *slot)
  {
  	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
  	return slot->sl_status;
  }
1b74c25bc   Mi Jinlong   nfsd41: error out...
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
  #define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
  			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
  			1 +	/* MIN tag is length with zero, only length */ \
  			3 +	/* version, opcount, opcode */ \
  			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
  				/* seqid, slotID, slotID, cache */ \
  			4 ) * sizeof(__be32))
  
  #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
  			2 +	/* verifier: AUTH_NULL, length 0 */\
  			1 +	/* status */ \
  			1 +	/* MIN tag is length with zero, only length */ \
  			3 +	/* opcount, opcode, opstatus*/ \
  			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
  				/* seqid, slotID, slotID, slotID, status */ \
  			5 ) * sizeof(__be32))
  
  static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel)
  {
  	return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ
  		|| fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ;
  }
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1563
1564
1565
1566
1567
  __be32
  nfsd4_create_session(struct svc_rqst *rqstp,
  		     struct nfsd4_compound_state *cstate,
  		     struct nfsd4_create_session *cr_ses)
  {
363168b4e   Jeff Layton   nfsd: make nfs4_c...
1568
  	struct sockaddr *sa = svc_addr(rqstp);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1569
  	struct nfs4_client *conf, *unconf;
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
1570
  	struct nfsd4_session *new;
49557cc74   Andy Adamson   nfsd41: Use separ...
1571
  	struct nfsd4_clid_slot *cs_slot = NULL;
86c3e16cc   J. Bruce Fields   nfsd4: confirm on...
1572
  	bool confirm_me = false;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1573
  	int status = 0;
a62573dc3   Mi Jinlong   nfsd41: add flag ...
1574
1575
  	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
  		return nfserr_inval;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1576
1577
1578
1579
1580
  	nfs4_lock_state();
  	unconf = find_unconfirmed_client(&cr_ses->clientid);
  	conf = find_confirmed_client(&cr_ses->clientid);
  
  	if (conf) {
49557cc74   Andy Adamson   nfsd41: Use separ...
1581
1582
  		cs_slot = &conf->cl_cs_slot;
  		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
38eb76a54   Andy Adamson   nfsd41: Add a cre...
1583
  		if (status == nfserr_replay_cache) {
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1584
1585
  			dprintk("Got a create_session replay! seqid= %d
  ",
49557cc74   Andy Adamson   nfsd41: Use separ...
1586
  				cs_slot->sl_seqid);
38eb76a54   Andy Adamson   nfsd41: Add a cre...
1587
  			/* Return the cached reply status */
49557cc74   Andy Adamson   nfsd41: Use separ...
1588
  			status = nfsd4_replay_create_session(cr_ses, cs_slot);
38eb76a54   Andy Adamson   nfsd41: Add a cre...
1589
  			goto out;
49557cc74   Andy Adamson   nfsd41: Use separ...
1590
  		} else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1591
1592
1593
1594
1595
  			status = nfserr_seq_misordered;
  			dprintk("Sequence misordered!
  ");
  			dprintk("Expected seqid= %d but got seqid= %d
  ",
49557cc74   Andy Adamson   nfsd41: Use separ...
1596
  				cs_slot->sl_seqid, cr_ses->seqid);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1597
1598
  			goto out;
  		}
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1599
1600
  	} else if (unconf) {
  		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
363168b4e   Jeff Layton   nfsd: make nfs4_c...
1601
  		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1602
1603
1604
  			status = nfserr_clid_inuse;
  			goto out;
  		}
49557cc74   Andy Adamson   nfsd41: Use separ...
1605
1606
  		cs_slot = &unconf->cl_cs_slot;
  		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
38eb76a54   Andy Adamson   nfsd41: Add a cre...
1607
1608
  		if (status) {
  			/* an unconfirmed replay returns misordered */
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1609
  			status = nfserr_seq_misordered;
cd5b81445   J. Bruce Fields   nfsd4: don't cach...
1610
  			goto out;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1611
  		}
86c3e16cc   J. Bruce Fields   nfsd4: confirm on...
1612
  		confirm_me = true;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1613
1614
1615
1616
1617
  		conf = unconf;
  	} else {
  		status = nfserr_stale_clientid;
  		goto out;
  	}
408b79bcc   J. Bruce Fields   nfsd4: consistent...
1618
  	/*
8323c3b2a   J. Bruce Fields   nfsd4: move minor...
1619
1620
1621
1622
1623
  	 * XXX: we should probably set this at creation time, and check
  	 * for consistent minorversion use throughout:
  	 */
  	conf->cl_minorversion = 1;
  	/*
408b79bcc   J. Bruce Fields   nfsd4: consistent...
1624
1625
1626
1627
  	 * We do not support RDMA or persistent sessions
  	 */
  	cr_ses->flags &= ~SESSION4_PERSIST;
  	cr_ses->flags &= ~SESSION4_RDMA;
1b74c25bc   Mi Jinlong   nfsd41: error out...
1628
1629
1630
  	status = nfserr_toosmall;
  	if (check_forechannel_attrs(cr_ses->fore_channel))
  		goto out;
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
1631
1632
1633
  	status = nfserr_jukebox;
  	new = alloc_init_session(rqstp, conf, cr_ses);
  	if (!new)
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1634
  		goto out;
ac7c46f29   J. Bruce Fields   nfsd4: make backc...
1635
1636
  	status = nfs_ok;
  	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1637
  	       NFS4_MAX_SESSIONID_LEN);
120506576   Mi Jinlong   NFS4.1: Fix bug s...
1638
1639
  	memcpy(&cr_ses->fore_channel, &new->se_fchannel,
  		sizeof(struct nfsd4_channel_attrs));
86c3e16cc   J. Bruce Fields   nfsd4: confirm on...
1640
  	cs_slot->sl_seqid++;
49557cc74   Andy Adamson   nfsd41: Use separ...
1641
  	cr_ses->seqid = cs_slot->sl_seqid;
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1642

49557cc74   Andy Adamson   nfsd41: Use separ...
1643
1644
  	/* cache solo and embedded create sessions under the state lock */
  	nfsd4_cache_create_session(cr_ses, cs_slot, status);
86c3e16cc   J. Bruce Fields   nfsd4: confirm on...
1645
1646
  	if (confirm_me)
  		move_to_confirmed(conf);
ec6b5d7b5   Andy Adamson   nfsd41: create_se...
1647
1648
1649
1650
1651
  out:
  	nfs4_unlock_state();
  	dprintk("%s returns %d
  ", __func__, ntohl(status));
  	return status;
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1652
  }
577163559   J. Bruce Fields   nfsd4: complete e...
1653
1654
1655
1656
1657
1658
1659
  static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
  {
  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
  	struct nfsd4_compoundargs *argp = rqstp->rq_argp;
  
  	return argp->opcnt == resp->opcnt;
  }
1d1bc8f20   J. Bruce Fields   nfsd4: support BI...
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
  static __be32 nfsd4_map_bcts_dir(u32 *dir)
  {
  	switch (*dir) {
  	case NFS4_CDFC4_FORE:
  	case NFS4_CDFC4_BACK:
  		return nfs_ok;
  	case NFS4_CDFC4_FORE_OR_BOTH:
  	case NFS4_CDFC4_BACK_OR_BOTH:
  		*dir = NFS4_CDFC4_BOTH;
  		return nfs_ok;
  	};
  	return nfserr_inval;
  }
  
  __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
  		     struct nfsd4_compound_state *cstate,
  		     struct nfsd4_bind_conn_to_session *bcts)
  {
  	__be32 status;
  
  	if (!nfsd4_last_compound_op(rqstp))
  		return nfserr_not_only_op;
  	spin_lock(&client_lock);
  	cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
  	/* Sorta weird: we only need the refcnt'ing because new_conn acquires
  	 * client_lock iself: */
  	if (cstate->session) {
  		nfsd4_get_session(cstate->session);
  		atomic_inc(&cstate->session->se_client->cl_refcount);
  	}
  	spin_unlock(&client_lock);
  	if (!cstate->session)
  		return nfserr_badsession;
  
  	status = nfsd4_map_bcts_dir(&bcts->dir);
1db2b9dde   Bryan Schumaker   NFSD: Check statu...
1695
1696
1697
  	if (!status)
  		nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
  	return status;
1d1bc8f20   J. Bruce Fields   nfsd4: support BI...
1698
  }
5d4cec2f2   J. Bruce Fields   nfsd4: fix bare d...
1699
1700
1701
1702
1703
1704
  static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
  {
  	if (!session)
  		return 0;
  	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
  }
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1705
1706
1707
1708
1709
  __be32
  nfsd4_destroy_session(struct svc_rqst *r,
  		      struct nfsd4_compound_state *cstate,
  		      struct nfsd4_destroy_session *sessionid)
  {
e10e0cfc2   Benny Halevy   nfsd41: destroy_s...
1710
1711
1712
1713
1714
1715
1716
1717
1718
  	struct nfsd4_session *ses;
  	u32 status = nfserr_badsession;
  
  	/* Notes:
  	 * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid
  	 * - Should we return nfserr_back_chan_busy if waiting for
  	 *   callbacks on to-be-destroyed session?
  	 * - Do we need to clear any callback info from previous session?
  	 */
5d4cec2f2   J. Bruce Fields   nfsd4: fix bare d...
1719
  	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
577163559   J. Bruce Fields   nfsd4: complete e...
1720
1721
1722
  		if (!nfsd4_last_compound_op(r))
  			return nfserr_not_only_op;
  	}
e10e0cfc2   Benny Halevy   nfsd41: destroy_s...
1723
  	dump_sessionid(__func__, &sessionid->sessionid);
9089f1b47   Benny Halevy   nfsd4: rename ses...
1724
  	spin_lock(&client_lock);
e10e0cfc2   Benny Halevy   nfsd41: destroy_s...
1725
1726
  	ses = find_in_sessionid_hashtbl(&sessionid->sessionid);
  	if (!ses) {
9089f1b47   Benny Halevy   nfsd4: rename ses...
1727
  		spin_unlock(&client_lock);
e10e0cfc2   Benny Halevy   nfsd41: destroy_s...
1728
1729
1730
1731
  		goto out;
  	}
  
  	unhash_session(ses);
9089f1b47   Benny Halevy   nfsd4: rename ses...
1732
  	spin_unlock(&client_lock);
e10e0cfc2   Benny Halevy   nfsd41: destroy_s...
1733

ab707e156   Benny Halevy   nfsd4: nfsd4_dest...
1734
  	nfs4_lock_state();
84f5f7ccc   J. Bruce Fields   nfsd4: make sure ...
1735
  	nfsd4_probe_callback_sync(ses->se_client);
ab707e156   Benny Halevy   nfsd4: nfsd4_dest...
1736
  	nfs4_unlock_state();
19cf5c026   J. Bruce Fields   nfsd4: use callba...
1737
1738
  
  	nfsd4_del_conns(ses);
e10e0cfc2   Benny Halevy   nfsd41: destroy_s...
1739
1740
1741
1742
1743
1744
  	nfsd4_put_session(ses);
  	status = nfs_ok;
  out:
  	dprintk("%s returns %d
  ", __func__, ntohl(status));
  	return status;
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1745
  }
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1746
  static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
328ead287   J. Bruce Fields   nfsd4: add new co...
1747
1748
1749
1750
  {
  	struct nfsd4_conn *c;
  
  	list_for_each_entry(c, &s->se_conns, cn_persession) {
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1751
  		if (c->cn_xprt == xpt) {
328ead287   J. Bruce Fields   nfsd4: add new co...
1752
1753
1754
1755
1756
  			return c;
  		}
  	}
  	return NULL;
  }
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1757
  static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
328ead287   J. Bruce Fields   nfsd4: add new co...
1758
1759
  {
  	struct nfs4_client *clp = ses->se_client;
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1760
  	struct nfsd4_conn *c;
21b75b019   J. Bruce Fields   nfsd4: fix 4.1 co...
1761
  	int ret;
328ead287   J. Bruce Fields   nfsd4: add new co...
1762
1763
  
  	spin_lock(&clp->cl_lock);
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1764
  	c = __nfsd4_find_conn(new->cn_xprt, ses);
328ead287   J. Bruce Fields   nfsd4: add new co...
1765
1766
1767
1768
1769
1770
1771
  	if (c) {
  		spin_unlock(&clp->cl_lock);
  		free_conn(new);
  		return;
  	}
  	__nfsd4_hash_conn(new, ses);
  	spin_unlock(&clp->cl_lock);
21b75b019   J. Bruce Fields   nfsd4: fix 4.1 co...
1772
1773
1774
1775
  	ret = nfsd4_register_conn(new);
  	if (ret)
  		/* oops; xprt is already down: */
  		nfsd4_conn_lost(&new->cn_xpt_user);
328ead287   J. Bruce Fields   nfsd4: add new co...
1776
1777
  	return;
  }
868b89c3d   Mi Jinlong   nfsd41: compare r...
1778
1779
1780
1781
1782
1783
  static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
  {
  	struct nfsd4_compoundargs *args = rqstp->rq_argp;
  
  	return args->opcnt > session->se_fchannel.maxops;
  }
ae82a8d06   Mi Jinlong   nfsd41: check the...
1784
1785
1786
1787
1788
1789
1790
  static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
  				  struct nfsd4_session *session)
  {
  	struct xdr_buf *xb = &rqstp->rq_arg;
  
  	return xb->len > session->se_fchannel.maxreq_sz;
  }
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1791
  __be32
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1792
  nfsd4_sequence(struct svc_rqst *rqstp,
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1793
1794
1795
  	       struct nfsd4_compound_state *cstate,
  	       struct nfsd4_sequence *seq)
  {
f9bb94c4c   Andy Adamson   nfsd41: enforce N...
1796
  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1797
1798
  	struct nfsd4_session *session;
  	struct nfsd4_slot *slot;
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1799
  	struct nfsd4_conn *conn;
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1800
  	int status;
f9bb94c4c   Andy Adamson   nfsd41: enforce N...
1801
1802
  	if (resp->opcnt != 1)
  		return nfserr_sequence_pos;
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1803
1804
1805
1806
1807
1808
1809
  	/*
  	 * Will be either used or freed by nfsd4_sequence_check_conn
  	 * below.
  	 */
  	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
  	if (!conn)
  		return nfserr_jukebox;
9089f1b47   Benny Halevy   nfsd4: rename ses...
1810
  	spin_lock(&client_lock);
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1811
1812
1813
1814
  	status = nfserr_badsession;
  	session = find_in_sessionid_hashtbl(&seq->sessionid);
  	if (!session)
  		goto out;
868b89c3d   Mi Jinlong   nfsd41: compare r...
1815
1816
1817
  	status = nfserr_too_many_ops;
  	if (nfsd4_session_too_many_ops(rqstp, session))
  		goto out;
ae82a8d06   Mi Jinlong   nfsd41: check the...
1818
1819
1820
  	status = nfserr_req_too_big;
  	if (nfsd4_request_too_big(rqstp, session))
  		goto out;
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1821
  	status = nfserr_badslot;
6c18ba9f5   Alexandros Batsakis   nfsd41: move chan...
1822
  	if (seq->slotid >= session->se_fchannel.maxreqs)
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1823
  		goto out;
557ce2646   Andy Adamson   nfsd41: replace p...
1824
  	slot = session->se_slots[seq->slotid];
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1825
1826
  	dprintk("%s: slotid %d
  ", __func__, seq->slotid);
a8dfdaeb7   Andy Adamson   nfsd41: use sessi...
1827
1828
1829
1830
  	/* We do not negotiate the number of slots yet, so set the
  	 * maxslots to the session maxreqs which is used to encode
  	 * sr_highest_slotid and the sr_target_slot id to maxslots */
  	seq->maxslots = session->se_fchannel.maxreqs;
88e588d56   Andy Adamson   nfsd41: change ch...
1831
  	status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse);
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1832
1833
1834
  	if (status == nfserr_replay_cache) {
  		cstate->slot = slot;
  		cstate->session = session;
da3846a28   Andy Adamson   nfsd41: nfsd DRC ...
1835
  		/* Return the cached reply status and set cstate->status
557ce2646   Andy Adamson   nfsd41: replace p...
1836
  		 * for nfsd4_proc_compound processing */
bf864a31d   Andy Adamson   nfsd41: non-page ...
1837
  		status = nfsd4_replay_cache_entry(resp, seq);
da3846a28   Andy Adamson   nfsd41: nfsd DRC ...
1838
  		cstate->status = nfserr_replay_cache;
aaf84eb95   Benny Halevy   nfsd41: renew_cli...
1839
  		goto out;
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1840
1841
1842
  	}
  	if (status)
  		goto out;
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1843
1844
  	nfsd4_sequence_check_conn(conn, session);
  	conn = NULL;
328ead287   J. Bruce Fields   nfsd4: add new co...
1845

b85d4c01b   Benny Halevy   nfsd41: sequence ...
1846
1847
1848
  	/* Success! bump slot seqid */
  	slot->sl_inuse = true;
  	slot->sl_seqid = seq->seqid;
557ce2646   Andy Adamson   nfsd41: replace p...
1849
  	slot->sl_cachethis = seq->cachethis;
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1850
1851
1852
  
  	cstate->slot = slot;
  	cstate->session = session;
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1853
  out:
26c0c75e6   J. Bruce Fields   nfsd4: fix unlike...
1854
  	/* Hold a session reference until done processing the compound. */
aaf84eb95   Benny Halevy   nfsd41: renew_cli...
1855
  	if (cstate->session) {
0d7bb7190   J. Bruce Fields   nfsd4: set sequen...
1856
  		struct nfs4_client *clp = session->se_client;
36acb66bd   Benny Halevy   nfsd4: extend the...
1857
  		nfsd4_get_session(cstate->session);
0d7bb7190   J. Bruce Fields   nfsd4: set sequen...
1858
  		atomic_inc(&clp->cl_refcount);
5423732a7   Benny Halevy   nfsd41: use SEQ4_...
1859
1860
  		switch (clp->cl_cb_state) {
  		case NFSD4_CB_DOWN:
fc0c3dd13   Benny Halevy   nfsd4: seq->statu...
1861
  			seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
5423732a7   Benny Halevy   nfsd41: use SEQ4_...
1862
1863
  			break;
  		case NFSD4_CB_FAULT:
fc0c3dd13   Benny Halevy   nfsd4: seq->statu...
1864
  			seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
5423732a7   Benny Halevy   nfsd41: use SEQ4_...
1865
  			break;
fc0c3dd13   Benny Halevy   nfsd4: seq->statu...
1866
1867
  		default:
  			seq->status_flags = 0;
5423732a7   Benny Halevy   nfsd41: use SEQ4_...
1868
  		}
aaf84eb95   Benny Halevy   nfsd41: renew_cli...
1869
  	}
a663bdd8c   J. Bruce Fields   nfsd4: fix connec...
1870
  	kfree(conn);
36acb66bd   Benny Halevy   nfsd4: extend the...
1871
  	spin_unlock(&client_lock);
b85d4c01b   Benny Halevy   nfsd41: sequence ...
1872
1873
1874
  	dprintk("%s: return %d
  ", __func__, ntohl(status));
  	return status;
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1875
  }
345c28429   Mi Jinlong   nfs41: implement ...
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
  static inline bool has_resources(struct nfs4_client *clp)
  {
  	return !list_empty(&clp->cl_openowners)
  		|| !list_empty(&clp->cl_delegations)
  		|| !list_empty(&clp->cl_sessions);
  }
  
  __be32
  nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
  {
  	struct nfs4_client *conf, *unconf, *clp;
  	int status = 0;
  
  	nfs4_lock_state();
  	unconf = find_unconfirmed_client(&dc->clientid);
  	conf = find_confirmed_client(&dc->clientid);
  
  	if (conf) {
  		clp = conf;
  
  		if (!is_client_expired(conf) && has_resources(conf)) {
  			status = nfserr_clientid_busy;
  			goto out;
  		}
  
  		/* rfc5661 18.50.3 */
  		if (cstate->session && conf == cstate->session->se_client) {
  			status = nfserr_clientid_busy;
  			goto out;
  		}
  	} else if (unconf)
  		clp = unconf;
  	else {
  		status = nfserr_stale_clientid;
  		goto out;
  	}
  
  	expire_client(clp);
  out:
  	nfs4_unlock_state();
  	dprintk("%s return %d
  ", __func__, ntohl(status));
  	return status;
  }
069b6ad4b   Andy Adamson   nfsd41: proc stubs
1920
  __be32
4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
1921
1922
  nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
  {
bcecf1ccc   Mi Jinlong   nfsd41: error out...
1923
  	int status = 0;
4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
1924
1925
1926
1927
1928
1929
1930
1931
1932
  	if (rc->rca_one_fs) {
  		if (!cstate->current_fh.fh_dentry)
  			return nfserr_nofilehandle;
  		/*
  		 * We don't take advantage of the rca_one_fs case.
  		 * That's OK, it's optional, we can safely ignore it.
  		 */
  		 return nfs_ok;
  	}
bcecf1ccc   Mi Jinlong   nfsd41: error out...
1933

4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
1934
  	nfs4_lock_state();
bcecf1ccc   Mi Jinlong   nfsd41: error out...
1935
1936
1937
1938
1939
1940
  	status = nfserr_complete_already;
  	if (cstate->session->se_client->cl_firststate)
  		goto out;
  
  	status = nfserr_stale_clientid;
  	if (is_client_expired(cstate->session->se_client))
4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
1941
1942
1943
1944
1945
1946
1947
  		/*
  		 * The following error isn't really legal.
  		 * But we only get here if the client just explicitly
  		 * destroyed the client.  Surely it no longer cares what
  		 * error it gets back on an operation for the dead
  		 * client.
  		 */
bcecf1ccc   Mi Jinlong   nfsd41: error out...
1948
1949
1950
  		goto out;
  
  	status = nfs_ok;
4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
1951
  	nfsd4_create_clid_dir(cstate->session->se_client);
bcecf1ccc   Mi Jinlong   nfsd41: error out...
1952
  out:
4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
1953
  	nfs4_unlock_state();
bcecf1ccc   Mi Jinlong   nfsd41: error out...
1954
  	return status;
4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
1955
1956
1957
  }
  
  __be32
b591480bb   J.Bruce Fields   [PATCH] knfsd: nf...
1958
1959
  nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
  		  struct nfsd4_setclientid *setclid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1960
  {
a084daf51   J. Bruce Fields   nfsd4: move name-...
1961
  	struct xdr_netobj 	clname = setclid->se_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
1963
  	nfs4_verifier		clverifier = setclid->se_verf;
  	unsigned int 		strhashval;
28ce6054f   NeilBrown   [PATCH] knfsd: nf...
1964
  	struct nfs4_client	*conf, *unconf, *new;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
1965
  	__be32 			status;
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
1966
  	char                    dname[HEXDIR_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1967
  	
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
1968
1969
  	status = nfs4_make_rec_clidname(dname, &clname);
  	if (status)
73aea4ecd   Neil Brown   [PATCH] nfsd4: fi...
1970
  		return status;
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
1971

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
1973
1974
1975
  	/* 
  	 * XXX The Duplicate Request Cache (DRC) has been checked (??)
  	 * We get here on a DRC miss.
  	 */
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
1976
  	strhashval = clientstr_hashval(dname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1977

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978
  	nfs4_lock_state();
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1979
  	conf = find_confirmed_client_by_str(dname, strhashval);
28ce6054f   NeilBrown   [PATCH] knfsd: nf...
1980
  	if (conf) {
a186e7674   J. Bruce Fields   nfsd4: kill some ...
1981
  		/* RFC 3530 14.2.33 CASE 0: */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1982
  		status = nfserr_clid_inuse;
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
1983
1984
  		if (clp_used_exchangeid(conf))
  			goto out;
026722c25   J. Bruce Fields   nfsd4: don't chec...
1985
  		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
363168b4e   Jeff Layton   nfsd: make nfs4_c...
1986
1987
1988
1989
1990
1991
  			char addr_str[INET6_ADDRSTRLEN];
  			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
  				 sizeof(addr_str));
  			dprintk("NFSD: setclientid: string in use by client "
  				"at %s
  ", addr_str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
1993
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1994
  	}
a186e7674   J. Bruce Fields   nfsd4: kill some ...
1995
1996
1997
1998
1999
  	/*
  	 * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
  	 * has a description of SETCLIENTID request processing consisting
  	 * of 5 bullet points, labeled as CASE0 - CASE4 below.
  	 */
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
2000
  	unconf = find_unconfirmed_client_by_str(dname, strhashval);
3e7724639   J. Bruce Fields   nfsd4: stop using...
2001
  	status = nfserr_jukebox;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2002
  	if (!conf) {
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2003
2004
2005
  		/*
  		 * RFC 3530 14.2.33 CASE 4:
  		 * placed first, because it is the normal case
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2006
2007
2008
  		 */
  		if (unconf)
  			expire_client(unconf);
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
2009
  		new = create_client(clname, dname, rqstp, &clverifier);
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
2010
  		if (new == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2011
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2012
  		gen_clid(new);
599e0a229   J. Bruce Fields   knfsd: cleanup of...
2013
  	} else if (same_verf(&conf->cl_verifier, &clverifier)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2014
  		/*
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2015
2016
  		 * RFC 3530 14.2.33 CASE 1:
  		 * probable callback update
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2017
  		 */
31f4a6c12   NeilBrown   [PATCH] knfsd: nf...
2018
2019
2020
2021
2022
2023
2024
  		if (unconf) {
  			/* Note this is removing unconfirmed {*x***},
  			 * which is stronger than RFC recommended {vxc**}.
  			 * This has the advantage that there is at most
  			 * one {*x***} in either list at any time.
  			 */
  			expire_client(unconf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2025
  		}
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
2026
  		new = create_client(clname, dname, rqstp, &clverifier);
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
2027
  		if (new == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2028
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
  		copy_clid(new, conf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2030
2031
  	} else if (!unconf) {
  		/*
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2032
2033
2034
  		 * RFC 3530 14.2.33 CASE 2:
  		 * probable client reboot; state will be removed if
  		 * confirmed.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2035
  		 */
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
2036
  		new = create_client(clname, dname, rqstp, &clverifier);
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
2037
  		if (new == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2038
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
  		gen_clid(new);
49ba87811   J. Bruce Fields   nfsd: eliminate f...
2040
  	} else {
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2041
2042
2043
2044
  		/*
  		 * RFC 3530 14.2.33 CASE 3:
  		 * probable client reboot; state will be removed if
  		 * confirmed.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2045
2046
  		 */
  		expire_client(unconf);
b09333c46   Ricardo Labiaga   nfsd41: Refactor ...
2047
  		new = create_client(clname, dname, rqstp, &clverifier);
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
2048
  		if (new == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2050
  		gen_clid(new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2051
  	}
8323c3b2a   J. Bruce Fields   nfsd4: move minor...
2052
2053
2054
2055
2056
  	/*
  	 * XXX: we should probably set this at creation time, and check
  	 * for consistent minorversion use throughout:
  	 */
  	new->cl_minorversion = 0;
6f3d772fb   Takuma Umeya   nfs4: set source ...
2057
  	gen_callback(new, setclid, rqstp);
c175b83c4   J. Bruce Fields   knfsd: remove cod...
2058
  	add_to_unconfirmed(new, strhashval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
  	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
  	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
  	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
  	status = nfs_ok;
  out:
  	nfs4_unlock_state();
  	return status;
  }
  
  
  /*
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2070
2071
2072
   * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
   * a description of SETCLIENTID_CONFIRM request processing consisting of 4
   * bullets, labeled as CASE1 - CASE4 below.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
   */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2074
  __be32
b591480bb   J.Bruce Fields   [PATCH] knfsd: nf...
2075
2076
2077
  nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
  			 struct nfsd4_compound_state *cstate,
  			 struct nfsd4_setclientid_confirm *setclientid_confirm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2078
  {
363168b4e   Jeff Layton   nfsd: make nfs4_c...
2079
  	struct sockaddr *sa = svc_addr(rqstp);
21ab45a48   NeilBrown   [PATCH] knfsd: nf...
2080
  	struct nfs4_client *conf, *unconf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2081
2082
  	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
  	clientid_t * clid = &setclientid_confirm->sc_clientid;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2083
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084
2085
2086
2087
2088
2089
2090
2091
2092
  
  	if (STALE_CLIENTID(clid))
  		return nfserr_stale_clientid;
  	/* 
  	 * XXX The Duplicate Request Cache (DRC) has been checked (??)
  	 * We get here on a DRC miss.
  	 */
  
  	nfs4_lock_state();
21ab45a48   NeilBrown   [PATCH] knfsd: nf...
2093
2094
2095
2096
2097
  
  	conf = find_confirmed_client(clid);
  	unconf = find_unconfirmed_client(clid);
  
  	status = nfserr_clid_inuse;
363168b4e   Jeff Layton   nfsd: make nfs4_c...
2098
  	if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa))
21ab45a48   NeilBrown   [PATCH] knfsd: nf...
2099
  		goto out;
363168b4e   Jeff Layton   nfsd: make nfs4_c...
2100
  	if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa))
21ab45a48   NeilBrown   [PATCH] knfsd: nf...
2101
  		goto out;
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2102
2103
2104
2105
2106
  	/*
  	 * section 14.2.34 of RFC 3530 has a description of
  	 * SETCLIENTID_CONFIRM request processing consisting
  	 * of 4 bullet points, labeled as CASE1 - CASE4 below.
  	 */
366e0c1d9   J. Bruce Fields   nfsd4: kill unnee...
2107
  	if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) {
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2108
2109
2110
2111
  		/*
  		 * RFC 3530 14.2.34 CASE 1:
  		 * callback update
  		 */
599e0a229   J. Bruce Fields   knfsd: cleanup of...
2112
  		if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
2114
  			status = nfserr_clid_inuse;
  		else {
5a3c9d713   J. Bruce Fields   nfsd4: separate c...
2115
2116
  			nfsd4_change_callback(conf, &unconf->cl_cb_conn);
  			nfsd4_probe_callback(conf);
1a69c179a   NeilBrown   [PATCH] knfsd: nf...
2117
  			expire_client(unconf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
  			status = nfs_ok;
1a69c179a   NeilBrown   [PATCH] knfsd: nf...
2119

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2120
  		}
f3aba4e5a   J. Bruce Fields   nfsd4: remove unn...
2121
  	} else if (conf && !unconf) {
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2122
2123
2124
2125
  		/*
  		 * RFC 3530 14.2.34 CASE 2:
  		 * probable retransmitted request; play it safe and
  		 * do nothing.
7c79f7377   NeilBrown   [PATCH] knfsd: nf...
2126
  		 */
599e0a229   J. Bruce Fields   knfsd: cleanup of...
2127
  		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2128
  			status = nfserr_clid_inuse;
21ab45a48   NeilBrown   [PATCH] knfsd: nf...
2129
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2130
  			status = nfs_ok;
7c79f7377   NeilBrown   [PATCH] knfsd: nf...
2131
  	} else if (!conf && unconf
599e0a229   J. Bruce Fields   knfsd: cleanup of...
2132
  			&& same_verf(&unconf->cl_confirm, &confirm)) {
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2133
2134
2135
  		/*
  		 * RFC 3530 14.2.34 CASE 3:
  		 * Normal case; new or rebooted client:
7c79f7377   NeilBrown   [PATCH] knfsd: nf...
2136
  		 */
599e0a229   J. Bruce Fields   knfsd: cleanup of...
2137
  		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2138
2139
  			status = nfserr_clid_inuse;
  		} else {
1a69c179a   NeilBrown   [PATCH] knfsd: nf...
2140
2141
2142
  			unsigned int hash =
  				clientstr_hashval(unconf->cl_recdir);
  			conf = find_confirmed_client_by_str(unconf->cl_recdir,
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
2143
  							    hash);
1a69c179a   NeilBrown   [PATCH] knfsd: nf...
2144
  			if (conf) {
c7b9a4592   NeilBrown   [PATCH] knfsd: nf...
2145
  				nfsd4_remove_clid_dir(conf);
1a69c179a   NeilBrown   [PATCH] knfsd: nf...
2146
2147
  				expire_client(conf);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2148
  			move_to_confirmed(unconf);
21ab45a48   NeilBrown   [PATCH] knfsd: nf...
2149
  			conf = unconf;
5a3c9d713   J. Bruce Fields   nfsd4: separate c...
2150
  			nfsd4_probe_callback(conf);
1a69c179a   NeilBrown   [PATCH] knfsd: nf...
2151
  			status = nfs_ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
  		}
599e0a229   J. Bruce Fields   knfsd: cleanup of...
2153
2154
  	} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
  	    && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
7c79f7377   NeilBrown   [PATCH] knfsd: nf...
2155
  				    				&confirm)))) {
a186e7674   J. Bruce Fields   nfsd4: kill some ...
2156
2157
2158
  		/*
  		 * RFC 3530 14.2.34 CASE 4:
  		 * Client probably hasn't noticed that we rebooted yet.
7c79f7377   NeilBrown   [PATCH] knfsd: nf...
2159
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
  		status = nfserr_stale_clientid;
7c79f7377   NeilBrown   [PATCH] knfsd: nf...
2161
  	} else {
08e8987c3   NeilBrown   [PATCH] knfsd: nf...
2162
2163
2164
  		/* check that we have hit one of the cases...*/
  		status = nfserr_clid_inuse;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2165
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
2167
2168
  	nfs4_unlock_state();
  	return status;
  }
32513b40e   J. Bruce Fields   nfsd4: preallocat...
2169
2170
2171
2172
  static struct nfs4_file *nfsd4_alloc_file(void)
  {
  	return kmem_cache_alloc(file_slab, GFP_KERNEL);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
  /* OPEN Share state helper functions */
32513b40e   J. Bruce Fields   nfsd4: preallocat...
2174
  static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
  	unsigned int hashval = file_hashval(ino);
32513b40e   J. Bruce Fields   nfsd4: preallocat...
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
  	atomic_set(&fp->fi_ref, 1);
  	INIT_LIST_HEAD(&fp->fi_hash);
  	INIT_LIST_HEAD(&fp->fi_stateids);
  	INIT_LIST_HEAD(&fp->fi_delegations);
  	fp->fi_inode = igrab(ino);
  	fp->fi_had_conflict = false;
  	fp->fi_lease = NULL;
  	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
  	memset(fp->fi_access, 0, sizeof(fp->fi_access));
  	spin_lock(&recall_lock);
  	list_add(&fp->fi_hash, &file_hashtbl[hashval]);
  	spin_unlock(&recall_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
2190
2191
  }
  
  static void
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
2192
  nfsd4_free_slab(struct kmem_cache **slab)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193
  {
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2194
2195
  	if (*slab == NULL)
  		return;
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
2196
  	kmem_cache_destroy(*slab);
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2197
  	*slab = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2198
  }
e8ff2a845   J. Bruce Fields   knfsd: move nfsv4...
2199
  void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2200
2201
  nfsd4_free_slabs(void)
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2202
2203
  	nfsd4_free_slab(&openowner_slab);
  	nfsd4_free_slab(&lockowner_slab);
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2204
  	nfsd4_free_slab(&file_slab);
5ac049ac6   NeilBrown   [PATCH] nfsd4: sl...
2205
  	nfsd4_free_slab(&stateid_slab);
5b2d21c19   NeilBrown   [PATCH] nfsd4: sl...
2206
  	nfsd4_free_slab(&deleg_slab);
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2207
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208

720833960   Bryan Schumaker   NFSD: Call nfsd4_...
2209
  int
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2210
2211
  nfsd4_init_slabs(void)
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2212
2213
2214
2215
2216
2217
2218
  	openowner_slab = kmem_cache_create("nfsd4_openowners",
  			sizeof(struct nfs4_openowner), 0, 0, NULL);
  	if (openowner_slab == NULL)
  		goto out_nomem;
  	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
  			sizeof(struct nfs4_openowner), 0, 0, NULL);
  	if (lockowner_slab == NULL)
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2219
2220
  		goto out_nomem;
  	file_slab = kmem_cache_create("nfsd4_files",
20c2df83d   Paul Mundt   mm: Remove slab d...
2221
  			sizeof(struct nfs4_file), 0, 0, NULL);
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2222
2223
  	if (file_slab == NULL)
  		goto out_nomem;
5ac049ac6   NeilBrown   [PATCH] nfsd4: sl...
2224
  	stateid_slab = kmem_cache_create("nfsd4_stateids",
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2225
  			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
5ac049ac6   NeilBrown   [PATCH] nfsd4: sl...
2226
2227
  	if (stateid_slab == NULL)
  		goto out_nomem;
5b2d21c19   NeilBrown   [PATCH] nfsd4: sl...
2228
  	deleg_slab = kmem_cache_create("nfsd4_delegations",
20c2df83d   Paul Mundt   mm: Remove slab d...
2229
  			sizeof(struct nfs4_delegation), 0, 0, NULL);
5b2d21c19   NeilBrown   [PATCH] nfsd4: sl...
2230
2231
  	if (deleg_slab == NULL)
  		goto out_nomem;
e60d4398a   NeilBrown   [PATCH] nfsd4: sl...
2232
2233
2234
2235
2236
2237
  	return 0;
  out_nomem:
  	nfsd4_free_slabs();
  	dprintk("nfsd4: out of memory while initializing nfsv4
  ");
  	return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2238
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2239
2240
2241
2242
2243
2244
2245
  void nfs4_free_openowner(struct nfs4_openowner *oo)
  {
  	kfree(oo->oo_owner.so_owner.data);
  	kmem_cache_free(openowner_slab, oo);
  }
  
  void nfs4_free_lockowner(struct nfs4_lockowner *lo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2246
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2247
2248
  	kfree(lo->lo_owner.so_owner.data);
  	kmem_cache_free(lockowner_slab, lo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2249
  }
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2250
  static void init_nfs4_replay(struct nfs4_replay *rp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
  {
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2252
2253
2254
  	rp->rp_status = nfserr_serverfault;
  	rp->rp_buflen = 0;
  	rp->rp_buf = rp->rp_ibuf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2255
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2256
  static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2257
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2258
  	struct nfs4_stateowner *sop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2260
  	sop = kmem_cache_alloc(slab, GFP_KERNEL);
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2261
2262
2263
2264
2265
  	if (!sop)
  		return NULL;
  
  	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
  	if (!sop->so_owner.data) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2266
  		kmem_cache_free(slab, sop);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2267
  		return NULL;
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2268
2269
  	}
  	sop->so_owner.len = owner->len;
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
2270
  	INIT_LIST_HEAD(&sop->so_stateids);
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2271
2272
2273
2274
  	sop->so_client = clp;
  	init_nfs4_replay(&sop->so_replay);
  	return sop;
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2275
  static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2276
  {
16bfdaafa   J. Bruce Fields   nfsd4: share open...
2277
  	list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2278
  	list_add(&oo->oo_perclient, &clp->cl_openowners);
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2279
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2280
  static struct nfs4_openowner *
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2281
  alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2282
  	struct nfs4_openowner *oo;
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2283

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2284
2285
  	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
  	if (!oo)
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
2286
  		return NULL;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2287
2288
  	oo->oo_owner.so_is_open_owner = 1;
  	oo->oo_owner.so_seqid = open->op_seqid;
d29b20cd5   J. Bruce Fields   nfsd4: clean up o...
2289
  	oo->oo_flags = NFS4_OO_NEW;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2290
  	oo->oo_time = 0;
38c387b52   J. Bruce Fields   nfsd4: match clos...
2291
  	oo->oo_last_closed_stid = NULL;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2292
2293
2294
  	INIT_LIST_HEAD(&oo->oo_close_lru);
  	hash_openowner(oo, clp, strhashval);
  	return oo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
  }
996e09385   J. Bruce Fields   nfsd4: do idr pre...
2296
  static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2297
  	struct nfs4_openowner *oo = open->op_openowner;
d3b313a46   J. Bruce Fields   nfsd4: construct ...
2298
  	struct nfs4_client *clp = oo->oo_owner.so_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2299

996e09385   J. Bruce Fields   nfsd4: do idr pre...
2300
  	init_stid(&stp->st_stid, clp, NFS4_OPEN_STID);
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
2301
  	INIT_LIST_HEAD(&stp->st_lockowners);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2302
  	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
8beefa249   NeilBrown   [PATCH] nfsd4: re...
2303
  	list_add(&stp->st_perfile, &fp->fi_stateids);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2304
  	stp->st_stateowner = &oo->oo_owner;
13cd21845   NeilBrown   [PATCH] nfsd4: re...
2305
  	get_nfs4_file(fp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2306
  	stp->st_file = fp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
  	stp->st_access_bmap = 0;
  	stp->st_deny_bmap = 0;
b6d2f1ca3   J. Bruce Fields   nfsd4: more robus...
2309
  	__set_bit(open->op_share_access, &stp->st_access_bmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
  	__set_bit(open->op_share_deny, &stp->st_deny_bmap);
4c4cd222e   NeilBrown   [PATCH] nfsd4: ch...
2311
  	stp->st_openstp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2312
2313
2314
  }
  
  static void
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2315
  move_to_close_lru(struct nfs4_openowner *oo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2316
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2317
2318
  	dprintk("NFSD: move_to_close_lru nfs4_openowner %p
  ", oo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2319

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2320
2321
  	list_move_tail(&oo->oo_close_lru, &close_lru);
  	oo->oo_time = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2322
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323
  static int
599e0a229   J. Bruce Fields   knfsd: cleanup of...
2324
2325
2326
2327
2328
2329
  same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
  							clientid_t *clid)
  {
  	return (sop->so_owner.len == owner->len) &&
  		0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
  		(sop->so_client->cl_clientid.cl_id == clid->cl_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2330
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2331
  static struct nfs4_openowner *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2332
2333
  find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
  {
a50d2ad17   J. Bruce Fields   nfsd4: centralize...
2334
2335
  	struct nfs4_stateowner *so;
  	struct nfs4_openowner *oo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2336

16bfdaafa   J. Bruce Fields   nfsd4: share open...
2337
2338
2339
  	list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
  		if (!so->so_is_open_owner)
  			continue;
a50d2ad17   J. Bruce Fields   nfsd4: centralize...
2340
2341
2342
2343
2344
  		if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
  			oo = openowner(so);
  			renew_client(oo->oo_owner.so_client);
  			return oo;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
  	}
  	return NULL;
  }
  
  /* search file_hashtbl[] for file */
  static struct nfs4_file *
  find_file(struct inode *ino)
  {
  	unsigned int hashval = file_hashval(ino);
  	struct nfs4_file *fp;
8b671b807   J. Bruce Fields   nfsd4: remove use...
2355
  	spin_lock(&recall_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2356
  	list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
13cd21845   NeilBrown   [PATCH] nfsd4: re...
2357
2358
  		if (fp->fi_inode == ino) {
  			get_nfs4_file(fp);
8b671b807   J. Bruce Fields   nfsd4: remove use...
2359
  			spin_unlock(&recall_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2360
  			return fp;
13cd21845   NeilBrown   [PATCH] nfsd4: re...
2361
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2362
  	}
8b671b807   J. Bruce Fields   nfsd4: remove use...
2363
  	spin_unlock(&recall_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
2365
  	return NULL;
  }
4f83aa302   J. Bruce Fields   nfsd: document op...
2366
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2367
2368
2369
   * Called to check deny when READ with all zero stateid or
   * WRITE with all zero or all one stateid
   */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2370
  static __be32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2371
2372
2373
2374
  nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
  {
  	struct inode *ino = current_fh->fh_dentry->d_inode;
  	struct nfs4_file *fp;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2375
  	struct nfs4_ol_stateid *stp;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2376
  	__be32 ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2377
2378
2379
2380
2381
  
  	dprintk("NFSD: nfs4_share_conflict
  ");
  
  	fp = find_file(ino);
13cd21845   NeilBrown   [PATCH] nfsd4: re...
2382
2383
  	if (!fp)
  		return nfs_ok;
b700949b7   NeilBrown   [PATCH] nfsd4: re...
2384
  	ret = nfserr_locked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2385
  	/* Search for conflicting share reservations */
13cd21845   NeilBrown   [PATCH] nfsd4: re...
2386
2387
2388
2389
  	list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
  		if (test_bit(deny_type, &stp->st_deny_bmap) ||
  		    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2390
  	}
13cd21845   NeilBrown   [PATCH] nfsd4: re...
2391
2392
2393
2394
  	ret = nfs_ok;
  out:
  	put_nfs4_file(fp);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2395
  }
6b57d9c86   J. Bruce Fields   nfsd4: split up n...
2396
  static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2397
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2398
2399
2400
2401
2402
2403
  	/* We're assuming the state code never drops its reference
  	 * without first removing the lease.  Since we're in this lease
  	 * callback (and since the lease code is serialized by the kernel
  	 * lock) we know the server hasn't removed the lease yet, we know
  	 * it's safe to take a reference: */
  	atomic_inc(&dp->dl_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2404
  	list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405

460781b54   Arnd Bergmann   BKL: remove refer...
2406
  	/* only place dl_time is set. protected by lock_flocks*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2407
  	dp->dl_time = get_seconds();
6b57d9c86   J. Bruce Fields   nfsd4: split up n...
2408
2409
  	nfsd4_cb_recall(dp);
  }
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2410
  /* Called from break_lease() with lock_flocks() held. */
6b57d9c86   J. Bruce Fields   nfsd4: split up n...
2411
2412
  static void nfsd_break_deleg_cb(struct file_lock *fl)
  {
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2413
2414
  	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
  	struct nfs4_delegation *dp;
6b57d9c86   J. Bruce Fields   nfsd4: split up n...
2415

acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2416
2417
2418
  	BUG_ON(!fp);
  	/* We assume break_lease is only called once per lease: */
  	BUG_ON(fp->fi_had_conflict);
0272e1fd9   J. Bruce Fields   knfsd: let nfsd m...
2419
2420
  	/*
  	 * We don't want the locks code to timeout the lease for us;
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2421
  	 * we'll remove it ourself if a delegation isn't returned
6b57d9c86   J. Bruce Fields   nfsd4: split up n...
2422
  	 * in time:
0272e1fd9   J. Bruce Fields   knfsd: let nfsd m...
2423
2424
  	 */
  	fl->fl_break_time = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425

5d926e8c2   J. Bruce Fields   nfsd4: modify fi_...
2426
  	spin_lock(&recall_lock);
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2427
2428
2429
  	fp->fi_had_conflict = true;
  	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
  		nfsd_break_one_deleg(dp);
5d926e8c2   J. Bruce Fields   nfsd4: modify fi_...
2430
  	spin_unlock(&recall_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2431
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2432
2433
2434
2435
2436
2437
2438
2439
  static
  int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
  {
  	if (arg & F_UNLCK)
  		return lease_modify(onlist, arg);
  	else
  		return -EAGAIN;
  }
7b021967c   Alexey Dobriyan   const: make lock_...
2440
  static const struct lock_manager_operations nfsd_lease_mng_ops = {
8fb47a4fb   J. Bruce Fields   locks: rename loc...
2441
2442
  	.lm_break = nfsd_break_deleg_cb,
  	.lm_change = nfsd_change_deleg_cb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2443
  };
7a8711c9a   J. Bruce Fields   nfsd4: share comm...
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
  static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
  {
  	if (nfsd4_has_session(cstate))
  		return nfs_ok;
  	if (seqid == so->so_seqid - 1)
  		return nfserr_replay_me;
  	if (seqid == so->so_seqid)
  		return nfs_ok;
  	return nfserr_bad_seqid;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2454

b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2455
  __be32
6668958fa   Andy Adamson   nfsd41: stateid h...
2456
2457
  nfsd4_process_open1(struct nfsd4_compound_state *cstate,
  		    struct nfsd4_open *open)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2458
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2459
2460
2461
  	clientid_t *clientid = &open->op_clientid;
  	struct nfs4_client *clp = NULL;
  	unsigned int strhashval;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2462
  	struct nfs4_openowner *oo = NULL;
4cdc951b8   J. Bruce Fields   nfsd4: preallocat...
2463
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2464

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2465
2466
  	if (STALE_CLIENTID(&open->op_clientid))
  		return nfserr_stale_clientid;
32513b40e   J. Bruce Fields   nfsd4: preallocat...
2467
2468
2469
2470
2471
2472
2473
  	/*
  	 * In case we need it later, after we've already created the
  	 * file and don't want to risk a further failure:
  	 */
  	open->op_file = nfsd4_alloc_file();
  	if (open->op_file == NULL)
  		return nfserr_jukebox;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2474

16bfdaafa   J. Bruce Fields   nfsd4: share open...
2475
  	strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2476
2477
2478
  	oo = find_openstateowner_str(strhashval, open);
  	open->op_openowner = oo;
  	if (!oo) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2479
2480
  		clp = find_confirmed_client(clientid);
  		if (clp == NULL)
0f442aa29   J. Bruce Fields   [PATCH] nfsd4: si...
2481
  			return nfserr_expired;
bcf130f9d   J. Bruce Fields   nfsd4: simplify p...
2482
  		goto new_owner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2483
  	}
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
2484
  	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
0f442aa29   J. Bruce Fields   [PATCH] nfsd4: si...
2485
  		/* Replace unconfirmed owners without checking for replay. */
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2486
2487
2488
  		clp = oo->oo_owner.so_client;
  		release_openowner(oo);
  		open->op_openowner = NULL;
bcf130f9d   J. Bruce Fields   nfsd4: simplify p...
2489
  		goto new_owner;
0f442aa29   J. Bruce Fields   [PATCH] nfsd4: si...
2490
  	}
4cdc951b8   J. Bruce Fields   nfsd4: preallocat...
2491
2492
2493
2494
2495
  	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
  	if (status)
  		return status;
  	clp = oo->oo_owner.so_client;
  	goto alloc_stateid;
bcf130f9d   J. Bruce Fields   nfsd4: simplify p...
2496
2497
2498
2499
2500
  new_owner:
  	oo = alloc_init_open_stateowner(strhashval, clp, open);
  	if (oo == NULL)
  		return nfserr_jukebox;
  	open->op_openowner = oo;
4cdc951b8   J. Bruce Fields   nfsd4: preallocat...
2501
2502
2503
2504
  alloc_stateid:
  	open->op_stp = nfs4_alloc_stateid(clp);
  	if (!open->op_stp)
  		return nfserr_jukebox;
0f442aa29   J. Bruce Fields   [PATCH] nfsd4: si...
2505
  	return nfs_ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2506
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2507
  static inline __be32
4a6e43e6d   NeilBrown   [PATCH] nfsd4: nf...
2508
2509
2510
2511
2512
2513
2514
  nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
  {
  	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
  		return nfserr_openmode;
  	else
  		return nfs_ok;
  }
f459e4535   J. Bruce Fields   nfsd4: hash deleg...
2515
  static int share_access_to_flags(u32 share_access)
52f4fb430   NeilBrown   [PATCH] nfsd4: fi...
2516
  {
f459e4535   J. Bruce Fields   nfsd4: hash deleg...
2517
  	share_access &= ~NFS4_SHARE_WANT_MASK;
52f4fb430   NeilBrown   [PATCH] nfsd4: fi...
2518

f459e4535   J. Bruce Fields   nfsd4: hash deleg...
2519
  	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
52f4fb430   NeilBrown   [PATCH] nfsd4: fi...
2520
  }
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
2521
  static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
24a0111e4   J. Bruce Fields   nfsd4: fix use of...
2522
  {
f459e4535   J. Bruce Fields   nfsd4: hash deleg...
2523
  	struct nfs4_stid *ret;
24a0111e4   J. Bruce Fields   nfsd4: fix use of...
2524

38c2f4b12   J. Bruce Fields   nfsd4: look up st...
2525
  	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
f459e4535   J. Bruce Fields   nfsd4: hash deleg...
2526
2527
2528
  	if (!ret)
  		return NULL;
  	return delegstateid(ret);
24a0111e4   J. Bruce Fields   nfsd4: fix use of...
2529
  }
8b289b2c2   J. Bruce Fields   nfsd4: implement ...
2530
2531
2532
2533
2534
  static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
  {
  	return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
  	       open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2535
  static __be32
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
2536
  nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open,
567d98292   NeilBrown   [PATCH] nfsd4: do...
2537
2538
2539
  		struct nfs4_delegation **dp)
  {
  	int flags;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2540
  	__be32 status = nfserr_bad_stateid;
567d98292   NeilBrown   [PATCH] nfsd4: do...
2541

38c2f4b12   J. Bruce Fields   nfsd4: look up st...
2542
  	*dp = find_deleg_stateid(cl, &open->op_delegate_stateid);
567d98292   NeilBrown   [PATCH] nfsd4: do...
2543
  	if (*dp == NULL)
c44c5eeb2   NeilBrown   [PATCH] nfsd4: ad...
2544
  		goto out;
24a0111e4   J. Bruce Fields   nfsd4: fix use of...
2545
  	flags = share_access_to_flags(open->op_share_access);
567d98292   NeilBrown   [PATCH] nfsd4: do...
2546
2547
2548
  	status = nfs4_check_delegmode(*dp, flags);
  	if (status)
  		*dp = NULL;
c44c5eeb2   NeilBrown   [PATCH] nfsd4: ad...
2549
  out:
8b289b2c2   J. Bruce Fields   nfsd4: implement ...
2550
  	if (!nfsd4_is_deleg_cur(open))
c44c5eeb2   NeilBrown   [PATCH] nfsd4: ad...
2551
2552
2553
  		return nfs_ok;
  	if (status)
  		return status;
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
2554
  	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
c44c5eeb2   NeilBrown   [PATCH] nfsd4: ad...
2555
  	return nfs_ok;
567d98292   NeilBrown   [PATCH] nfsd4: do...
2556
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2557
  static __be32
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2558
  nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2559
  {
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2560
  	struct nfs4_ol_stateid *local;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2561
  	struct nfs4_openowner *oo = open->op_openowner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2562

8beefa249   NeilBrown   [PATCH] nfsd4: re...
2563
  	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2564
2565
2566
2567
  		/* ignore lock owners */
  		if (local->st_stateowner->so_is_open_owner == 0)
  			continue;
  		/* remember if we have seen this open owner */
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2568
  		if (local->st_stateowner == &oo->oo_owner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2569
2570
2571
  			*stpp = local;
  		/* check for conflicting share reservations */
  		if (!test_share(local, open))
77eaae8d4   J. Bruce Fields   nfsd4: simplify c...
2572
  			return nfserr_share_denied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2573
  	}
77eaae8d4   J. Bruce Fields   nfsd4: simplify c...
2574
  	return nfs_ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2575
  }
996e09385   J. Bruce Fields   nfsd4: do idr pre...
2576
2577
2578
  static void nfs4_free_stateid(struct nfs4_ol_stateid *s)
  {
  	kmem_cache_free(stateid_slab, s);
5ac049ac6   NeilBrown   [PATCH] nfsd4: sl...
2579
  }
21fb4016b   J. Bruce Fields   nfsd4: miscellane...
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
  static inline int nfs4_access_to_access(u32 nfs4_access)
  {
  	int flags = 0;
  
  	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
  		flags |= NFSD_MAY_READ;
  	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
  		flags |= NFSD_MAY_WRITE;
  	return flags;
  }
0c12eaffd   Casey Bodley   nfsd: don't break...
2590
2591
  static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
  		struct svc_fh *cur_fh, struct nfsd4_open *open)
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2592
2593
  {
  	__be32 status;
0c12eaffd   Casey Bodley   nfsd: don't break...
2594
2595
  	int oflag = nfs4_access_to_omode(open->op_share_access);
  	int access = nfs4_access_to_access(open->op_share_access);
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2596
2597
2598
  	if (!fp->fi_fds[oflag]) {
  		status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
  			&fp->fi_fds[oflag]);
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2599
2600
2601
2602
2603
2604
2605
  		if (status)
  			return status;
  	}
  	nfs4_file_get_access(fp, oflag);
  
  	return nfs_ok;
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2606
  static inline __be32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
  nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
  		struct nfsd4_open *open)
  {
  	struct iattr iattr = {
  		.ia_valid = ATTR_SIZE,
  		.ia_size = 0,
  	};
  	if (!open->op_truncate)
  		return 0;
  	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
9246585a1   Al Viro   [PATCH] nfsd4_tru...
2617
  		return nfserr_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2618
2619
  	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2620
  static __be32
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2621
  nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2622
  {
b6d2f1ca3   J. Bruce Fields   nfsd4: more robus...
2623
  	u32 op_share_access = open->op_share_access;
7d9478429   J. Bruce Fields   nfsd4: fix downgr...
2624
  	bool new_access;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2625
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2626

7d9478429   J. Bruce Fields   nfsd4: fix downgr...
2627
  	new_access = !test_bit(op_share_access, &stp->st_access_bmap);
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2628
  	if (new_access) {
0c12eaffd   Casey Bodley   nfsd: don't break...
2629
  		status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2630
2631
  		if (status)
  			return status;
6c26d08f0   J. Bruce Fields   [PATCH] nfsd4: fi...
2632
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2633
2634
  	status = nfsd4_truncate(rqstp, cur_fh, open);
  	if (status) {
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2635
  		if (new_access) {
f197c2719   J. Bruce Fields   nfsd4: fix file l...
2636
  			int oflag = nfs4_access_to_omode(op_share_access);
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2637
2638
  			nfs4_file_put_access(fp, oflag);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2639
2640
2641
  		return status;
  	}
  	/* remember the open */
24a0111e4   J. Bruce Fields   nfsd4: fix use of...
2642
  	__set_bit(op_share_access, &stp->st_access_bmap);
b55e0ba19   J. Bruce Fields   nfsd: remove unne...
2643
  	__set_bit(open->op_share_deny, &stp->st_deny_bmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2644
2645
2646
  
  	return nfs_ok;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2647
  static void
375151773   NeilBrown   [PATCH] nfsd4: st...
2648
  nfs4_set_claim_prev(struct nfsd4_open *open)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2649
  {
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
2650
  	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2651
  	open->op_openowner->oo_owner.so_client->cl_firststate = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2652
  }
14a24e99f   J. Bruce Fields   nfsd4: give out d...
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
  /* Should we give out recallable state?: */
  static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
  {
  	if (clp->cl_cb_state == NFSD4_CB_UP)
  		return true;
  	/*
  	 * In the sessions case, since we don't have to establish a
  	 * separate connection for callbacks, we assume it's OK
  	 * until we hear otherwise:
  	 */
  	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
  }
22d38c4c1   J. Bruce Fields   nfsd4: add helper...
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
  static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag)
  {
  	struct file_lock *fl;
  
  	fl = locks_alloc_lock();
  	if (!fl)
  		return NULL;
  	locks_init_lock(fl);
  	fl->fl_lmops = &nfsd_lease_mng_ops;
  	fl->fl_flags = FL_LEASE;
  	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
  	fl->fl_end = OFFSET_MAX;
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2677
  	fl->fl_owner = (fl_owner_t)(dp->dl_file);
22d38c4c1   J. Bruce Fields   nfsd4: add helper...
2678
  	fl->fl_pid = current->tgid;
22d38c4c1   J. Bruce Fields   nfsd4: add helper...
2679
2680
  	return fl;
  }
edab9782b   J. Bruce Fields   nfsd4: split leas...
2681
2682
  static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
  {
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2683
  	struct nfs4_file *fp = dp->dl_file;
edab9782b   J. Bruce Fields   nfsd4: split leas...
2684
2685
2686
2687
2688
2689
  	struct file_lock *fl;
  	int status;
  
  	fl = nfs4_alloc_init_lease(dp, flag);
  	if (!fl)
  		return -ENOMEM;
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2690
  	fl->fl_file = find_readable_file(fp);
2a74aba79   J. Bruce Fields   nfsd4: move clien...
2691
  	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2692
  	status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
edab9782b   J. Bruce Fields   nfsd4: split leas...
2693
  	if (status) {
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2694
  		list_del_init(&dp->dl_perclnt);
edab9782b   J. Bruce Fields   nfsd4: split leas...
2695
2696
2697
  		locks_free_lock(fl);
  		return -ENOMEM;
  	}
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
  	fp->fi_lease = fl;
  	fp->fi_deleg_file = fl->fl_file;
  	get_file(fp->fi_deleg_file);
  	atomic_set(&fp->fi_delegees, 1);
  	list_add(&dp->dl_perfile, &fp->fi_delegations);
  	return 0;
  }
  
  static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
  {
  	struct nfs4_file *fp = dp->dl_file;
  
  	if (!fp->fi_lease)
  		return nfs4_setlease(dp, flag);
  	spin_lock(&recall_lock);
  	if (fp->fi_had_conflict) {
  		spin_unlock(&recall_lock);
  		return -EAGAIN;
  	}
  	atomic_inc(&fp->fi_delegees);
  	list_add(&dp->dl_perfile, &fp->fi_delegations);
  	spin_unlock(&recall_lock);
2a74aba79   J. Bruce Fields   nfsd4: move clien...
2720
  	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
edab9782b   J. Bruce Fields   nfsd4: split leas...
2721
2722
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2723
2724
2725
2726
  /*
   * Attempt to hand out a delegation.
   */
  static void
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2727
  nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2728
2729
  {
  	struct nfs4_delegation *dp;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2730
  	struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
14a24e99f   J. Bruce Fields   nfsd4: give out d...
2731
  	int cb_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2732
  	int status, flag = 0;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2733
  	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2734
  	flag = NFS4_OPEN_DELEGATE_NONE;
7b190fecf   NeilBrown   [PATCH] knfsd: nf...
2735
2736
2737
  	open->op_recall = 0;
  	switch (open->op_claim_type) {
  		case NFS4_OPEN_CLAIM_PREVIOUS:
2bf23875f   J. Bruce Fields   nfsd4: rearrange ...
2738
  			if (!cb_up)
7b190fecf   NeilBrown   [PATCH] knfsd: nf...
2739
2740
2741
2742
2743
2744
2745
2746
  				open->op_recall = 1;
  			flag = open->op_delegate_type;
  			if (flag == NFS4_OPEN_DELEGATE_NONE)
  				goto out;
  			break;
  		case NFS4_OPEN_CLAIM_NULL:
  			/* Let's not give out any delegations till everyone's
  			 * had the chance to reclaim theirs.... */
af558e33b   J. Bruce Fields   nfsd: common grac...
2747
  			if (locks_in_grace())
7b190fecf   NeilBrown   [PATCH] knfsd: nf...
2748
  				goto out;
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
2749
  			if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
7b190fecf   NeilBrown   [PATCH] knfsd: nf...
2750
2751
2752
2753
2754
2755
2756
2757
2758
  				goto out;
  			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
  				flag = NFS4_OPEN_DELEGATE_WRITE;
  			else
  				flag = NFS4_OPEN_DELEGATE_READ;
  			break;
  		default:
  			goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2759

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2760
  	dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
dd239cc05   J. Bruce Fields   nfsd4: fix leak o...
2761
2762
  	if (dp == NULL)
  		goto out_no_deleg;
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2763
  	status = nfs4_set_delegation(dp, flag);
edab9782b   J. Bruce Fields   nfsd4: split leas...
2764
  	if (status)
dd239cc05   J. Bruce Fields   nfsd4: fix leak o...
2765
  		goto out_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2766

d5477a8db   J. Bruce Fields   nfsd4: add common...
2767
  	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2768

8c10cbdb4   Benny Halevy   nfsd: use STATEID...
2769
2770
  	dprintk("NFSD: delegation stateid=" STATEID_FMT "
  ",
d5477a8db   J. Bruce Fields   nfsd4: add common...
2771
  		STATEID_VAL(&dp->dl_stid.sc_stateid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2772
  out:
7b190fecf   NeilBrown   [PATCH] knfsd: nf...
2773
2774
2775
  	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
  			&& flag == NFS4_OPEN_DELEGATE_NONE
  			&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
2fdada03b   J. Bruce Fields   knfsd: demote som...
2776
2777
  		dprintk("NFSD: WARNING: refusing delegation reclaim
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2778
  	open->op_delegate_type = flag;
dd239cc05   J. Bruce Fields   nfsd4: fix leak o...
2779
2780
  	return;
  out_free:
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
2781
  	nfs4_put_delegation(dp);
dd239cc05   J. Bruce Fields   nfsd4: fix leak o...
2782
2783
2784
  out_no_deleg:
  	flag = NFS4_OPEN_DELEGATE_NONE;
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2785
2786
2787
2788
2789
  }
  
  /*
   * called with nfs4_lock_state() held.
   */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2790
  __be32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2791
2792
  nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
  {
6668958fa   Andy Adamson   nfsd41: stateid h...
2793
  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
2794
  	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2795
2796
  	struct nfs4_file *fp = NULL;
  	struct inode *ino = current_fh->fh_dentry->d_inode;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2797
  	struct nfs4_ol_stateid *stp = NULL;
567d98292   NeilBrown   [PATCH] nfsd4: do...
2798
  	struct nfs4_delegation *dp = NULL;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2799
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2800

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2801
2802
2803
2804
2805
2806
2807
2808
2809
  	/*
  	 * Lookup file; if found, lookup stateid and check open request,
  	 * and check for delegations in the process of being recalled.
  	 * If not found, create the nfs4_file struct
  	 */
  	fp = find_file(ino);
  	if (fp) {
  		if ((status = nfs4_check_open(fp, open, &stp)))
  			goto out;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
2810
  		status = nfs4_check_deleg(cl, fp, open, &dp);
c44c5eeb2   NeilBrown   [PATCH] nfsd4: ad...
2811
2812
  		if (status)
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2813
  	} else {
c44c5eeb2   NeilBrown   [PATCH] nfsd4: ad...
2814
  		status = nfserr_bad_stateid;
8b289b2c2   J. Bruce Fields   nfsd4: implement ...
2815
  		if (nfsd4_is_deleg_cur(open))
c44c5eeb2   NeilBrown   [PATCH] nfsd4: ad...
2816
  			goto out;
3e7724639   J. Bruce Fields   nfsd4: stop using...
2817
  		status = nfserr_jukebox;
32513b40e   J. Bruce Fields   nfsd4: preallocat...
2818
2819
2820
  		fp = open->op_file;
  		open->op_file = NULL;
  		nfsd4_init_file(fp, ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2821
2822
2823
2824
2825
2826
2827
2828
  	}
  
  	/*
  	 * OPEN the file, or upgrade an existing OPEN.
  	 * If truncate fails, the OPEN fails.
  	 */
  	if (stp) {
  		/* Stateid was found, this is an OPEN upgrade */
f9d7562fd   J. Bruce Fields   nfsd4: share file...
2829
  		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2830
2831
2832
  		if (status)
  			goto out;
  	} else {
4cdc951b8   J. Bruce Fields   nfsd4: preallocat...
2833
  		status = nfs4_get_vfs_file(rqstp, fp, current_fh, open);
567d98292   NeilBrown   [PATCH] nfsd4: do...
2834
  		if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2835
  			goto out;
4cdc951b8   J. Bruce Fields   nfsd4: preallocat...
2836
2837
  		stp = open->op_stp;
  		open->op_stp = NULL;
996e09385   J. Bruce Fields   nfsd4: do idr pre...
2838
  		init_open_stateid(stp, fp, open);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2839
2840
  		status = nfsd4_truncate(rqstp, current_fh, open);
  		if (status) {
2283963f2   J. Bruce Fields   nfsd4: split lock...
2841
  			release_open_stateid(stp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2842
2843
2844
  			goto out;
  		}
  	}
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2845
2846
  	update_stateid(&stp->st_stid.sc_stateid);
  	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2847

4dc6ec00f   J. Bruce Fields   nfsd4: implement ...
2848
  	if (nfsd4_has_session(&resp->cstate))
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
2849
  		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
6668958fa   Andy Adamson   nfsd41: stateid h...
2850

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2851
2852
2853
2854
2855
2856
2857
  	/*
  	* Attempt to hand out a delegation. No error return, because the
  	* OPEN succeeds even if we fail.
  	*/
  	nfs4_open_delegation(current_fh, open, stp);
  
  	status = nfs_ok;
8c10cbdb4   Benny Halevy   nfsd: use STATEID...
2858
2859
  	dprintk("%s: stateid=" STATEID_FMT "
  ", __func__,
dcef0413d   J. Bruce Fields   nfsd4: move some ...
2860
  		STATEID_VAL(&stp->st_stid.sc_stateid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2861
  out:
13cd21845   NeilBrown   [PATCH] nfsd4: re...
2862
2863
  	if (fp)
  		put_nfs4_file(fp);
375151773   NeilBrown   [PATCH] nfsd4: st...
2864
2865
  	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
  		nfs4_set_claim_prev(open);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2866
2867
2868
2869
  	/*
  	* To finish the open response, we just need to set the rflags.
  	*/
  	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
2870
  	if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
6668958fa   Andy Adamson   nfsd41: stateid h...
2871
  	    !nfsd4_has_session(&resp->cstate))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2872
2873
2874
2875
  		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
  
  	return status;
  }
d29b20cd5   J. Bruce Fields   nfsd4: clean up o...
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
  void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
  {
  	if (open->op_openowner) {
  		struct nfs4_openowner *oo = open->op_openowner;
  
  		if (!list_empty(&oo->oo_owner.so_stateids))
  			list_del_init(&oo->oo_close_lru);
  		if (oo->oo_flags & NFS4_OO_NEW) {
  			if (status) {
  				release_openowner(oo);
  				open->op_openowner = NULL;
  			} else
  				oo->oo_flags &= ~NFS4_OO_NEW;
  		}
  	}
32513b40e   J. Bruce Fields   nfsd4: preallocat...
2891
2892
  	if (open->op_file)
  		nfsd4_free_file(open->op_file);
4cdc951b8   J. Bruce Fields   nfsd4: preallocat...
2893
2894
  	if (open->op_stp)
  		nfs4_free_stateid(open->op_stp);
d29b20cd5   J. Bruce Fields   nfsd4: clean up o...
2895
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2896
  __be32
b591480bb   J.Bruce Fields   [PATCH] knfsd: nf...
2897
2898
  nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
  	    clientid_t *clid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2899
2900
  {
  	struct nfs4_client *clp;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
2901
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
  
  	nfs4_lock_state();
  	dprintk("process_renew(%08x/%08x): starting
  ", 
  			clid->cl_boot, clid->cl_id);
  	status = nfserr_stale_clientid;
  	if (STALE_CLIENTID(clid))
  		goto out;
  	clp = find_confirmed_client(clid);
  	status = nfserr_expired;
  	if (clp == NULL) {
  		/* We assume the client took too long to RENEW. */
  		dprintk("nfsd4_renew: clientid not found!
  ");
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2918
  	status = nfserr_cb_path_down;
ea1da636e   NeilBrown   [PATCH] knfsd: nf...
2919
  	if (!list_empty(&clp->cl_delegations)
77a3569d6   J. Bruce Fields   nfsd4: keep finer...
2920
  			&& clp->cl_cb_state != NFSD4_CB_UP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2921
2922
2923
2924
2925
2926
  		goto out;
  	status = nfs_ok;
  out:
  	nfs4_unlock_state();
  	return status;
  }
c47d832bc   Daniel Mack   nfsd: make local ...
2927
  static struct lock_manager nfsd4_manager = {
af558e33b   J. Bruce Fields   nfsd: common grac...
2928
  };
a76b4319c   NeilBrown   [PATCH] knfsd: nf...
2929
  static void
af558e33b   J. Bruce Fields   nfsd: common grac...
2930
  nfsd4_end_grace(void)
a76b4319c   NeilBrown   [PATCH] knfsd: nf...
2931
2932
2933
  {
  	dprintk("NFSD: end of grace period
  ");
c7b9a4592   NeilBrown   [PATCH] knfsd: nf...
2934
  	nfsd4_recdir_purge_old();
af558e33b   J. Bruce Fields   nfsd: common grac...
2935
  	locks_end_grace(&nfsd4_manager);
e46b498c8   J. Bruce Fields   nfsd4: simplify l...
2936
2937
2938
2939
2940
2941
  	/*
  	 * Now that every NFSv4 client has had the chance to recover and
  	 * to see the (possibly new, possibly shorter) lease time, we
  	 * can safely set the next grace time to the current lease time:
  	 */
  	nfsd4_grace = nfsd4_lease;
a76b4319c   NeilBrown   [PATCH] knfsd: nf...
2942
  }
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
2943
  static time_t
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2944
2945
2946
  nfs4_laundromat(void)
  {
  	struct nfs4_client *clp;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
2947
  	struct nfs4_openowner *oo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2948
2949
  	struct nfs4_delegation *dp;
  	struct list_head *pos, *next, reaplist;
cf07d2ea4   J. Bruce Fields   nfsd4: simplify r...
2950
2951
2952
  	time_t cutoff = get_seconds() - nfsd4_lease;
  	time_t t, clientid_val = nfsd4_lease;
  	time_t u, test_val = nfsd4_lease;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2953
2954
2955
2956
2957
  
  	nfs4_lock_state();
  
  	dprintk("NFSD: laundromat service - starting
  ");
af558e33b   J. Bruce Fields   nfsd: common grac...
2958
2959
  	if (locks_in_grace())
  		nfsd4_end_grace();
36acb66bd   Benny Halevy   nfsd4: extend the...
2960
2961
  	INIT_LIST_HEAD(&reaplist);
  	spin_lock(&client_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2962
2963
2964
2965
2966
2967
2968
2969
  	list_for_each_safe(pos, next, &client_lru) {
  		clp = list_entry(pos, struct nfs4_client, cl_lru);
  		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
  			t = clp->cl_time - cutoff;
  			if (clientid_val > t)
  				clientid_val = t;
  			break;
  		}
d76829889   Benny Halevy   nfsd4: keep a ref...
2970
2971
2972
2973
2974
2975
2976
2977
  		if (atomic_read(&clp->cl_refcount)) {
  			dprintk("NFSD: client in use (clientid %08x)
  ",
  				clp->cl_clientid.cl_id);
  			continue;
  		}
  		unhash_client_locked(clp);
  		list_add(&clp->cl_lru, &reaplist);
36acb66bd   Benny Halevy   nfsd4: extend the...
2978
2979
2980
2981
  	}
  	spin_unlock(&client_lock);
  	list_for_each_safe(pos, next, &reaplist) {
  		clp = list_entry(pos, struct nfs4_client, cl_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2982
2983
2984
  		dprintk("NFSD: purging unused client (clientid %08x)
  ",
  			clp->cl_clientid.cl_id);
c7b9a4592   NeilBrown   [PATCH] knfsd: nf...
2985
  		nfsd4_remove_clid_dir(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2986
2987
  		expire_client(clp);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2988
2989
2990
2991
2992
2993
2994
2995
2996
  	spin_lock(&recall_lock);
  	list_for_each_safe(pos, next, &del_recall_lru) {
  		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
  		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
  			u = dp->dl_time - cutoff;
  			if (test_val > u)
  				test_val = u;
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2997
2998
2999
3000
3001
  		list_move(&dp->dl_recall_lru, &reaplist);
  	}
  	spin_unlock(&recall_lock);
  	list_for_each_safe(pos, next, &reaplist) {
  		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3002
3003
  		unhash_delegation(dp);
  	}
cf07d2ea4   J. Bruce Fields   nfsd4: simplify r...
3004
  	test_val = nfsd4_lease;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3005
  	list_for_each_safe(pos, next, &close_lru) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3006
3007
3008
  		oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
  		if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
  			u = oo->oo_time - cutoff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3009
3010
3011
3012
  			if (test_val > u)
  				test_val = u;
  			break;
  		}
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3013
  		release_openowner(oo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3014
3015
3016
3017
3018
3019
  	}
  	if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
  		clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
  	nfs4_unlock_state();
  	return clientid_val;
  }
a254b246e   Harvey Harrison   nfsd: fix sparse ...
3020
3021
3022
3023
3024
  static struct workqueue_struct *laundry_wq;
  static void laundromat_main(struct work_struct *);
  static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
  
  static void
c4028958b   David Howells   WorkStruct: make ...
3025
  laundromat_main(struct work_struct *not_used)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3026
3027
3028
3029
3030
3031
  {
  	time_t t;
  
  	t = nfs4_laundromat();
  	dprintk("NFSD: laundromat_main - sleeping for %ld seconds
  ", t);
58da282b7   NeilBrown   [PATCH] knfsd: nf...
3032
  	queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3033
  }
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3034
  static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3035
  {
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3036
3037
3038
  	if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode)
  		return nfserr_bad_stateid;
  	return nfs_ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3039
3040
3041
3042
3043
  }
  
  static int
  STALE_STATEID(stateid_t *stateid)
  {
d3b313a46   J. Bruce Fields   nfsd4: construct ...
3044
  	if (stateid->si_opaque.so_clid.cl_boot == boot_time)
e4e83ea47   J. Bruce Fields   Revert "nfsd4: di...
3045
3046
3047
  		return 0;
  	dprintk("NFSD: stale stateid " STATEID_FMT "!
  ",
8c10cbdb4   Benny Halevy   nfsd: use STATEID...
3048
  		STATEID_VAL(stateid));
e4e83ea47   J. Bruce Fields   Revert "nfsd4: di...
3049
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
  }
  
  static inline int
  access_permit_read(unsigned long access_bmap)
  {
  	return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) ||
  		test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) ||
  		test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap);
  }
  
  static inline int
  access_permit_write(unsigned long access_bmap)
  {
  	return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) ||
  		test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
  }
  
  static
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3068
  __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3069
  {
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3070
          __be32 status = nfserr_openmode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3071

029219141   J. Bruce Fields   nfsd4: fix openmo...
3072
3073
3074
  	/* For lock stateid's, we test the parent open, not the lock: */
  	if (stp->st_openstp)
  		stp = stp->st_openstp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3075
3076
3077
3078
3079
3080
3081
3082
  	if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
                  goto out;
  	if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap)))
                  goto out;
  	status = nfs_ok;
  out:
  	return status;
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3083
  static inline __be32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3084
3085
  check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
  {
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3086
  	if (ONE_STATEID(stateid) && (flags & RD_STATE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3087
  		return nfs_ok;
af558e33b   J. Bruce Fields   nfsd: common grac...
3088
  	else if (locks_in_grace()) {
25985edce   Lucas De Marchi   Fix common misspe...
3089
  		/* Answer in remaining cases depends on existence of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
  		 * conflicting state; so we must wait out the grace period. */
  		return nfserr_grace;
  	} else if (flags & WR_STATE)
  		return nfs4_share_conflict(current_fh,
  				NFS4_SHARE_DENY_WRITE);
  	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
  		return nfs4_share_conflict(current_fh,
  				NFS4_SHARE_DENY_READ);
  }
  
  /*
   * Allow READ/WRITE during grace period on recovered state only for files
   * that are not able to provide mandatory locking.
   */
  static inline int
18f82731b   J. Bruce Fields   nfsd4: rename io_...
3105
  grace_disallows_io(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3106
  {
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3107
  	return locks_in_grace() && mandatory_lock(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3108
  }
81b829655   J. Bruce Fields   nfsd4: simplify s...
3109
3110
3111
3112
3113
  /* Returns true iff a is later than b: */
  static bool stateid_generation_after(stateid_t *a, stateid_t *b)
  {
  	return (s32)a->si_generation - (s32)b->si_generation > 0;
  }
28dde241c   J. Bruce Fields   nfsd4: remove HAS...
3114
  static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
0836f5872   J. Bruce Fields   nfsd4: simplify s...
3115
  {
6668958fa   Andy Adamson   nfsd41: stateid h...
3116
3117
3118
3119
  	/*
  	 * When sessions are used the stateid generation number is ignored
  	 * when it is zero.
  	 */
28dde241c   J. Bruce Fields   nfsd4: remove HAS...
3120
  	if (has_session && in->si_generation == 0)
81b829655   J. Bruce Fields   nfsd4: simplify s...
3121
3122
3123
3124
  		return nfs_ok;
  
  	if (in->si_generation == ref->si_generation)
  		return nfs_ok;
6668958fa   Andy Adamson   nfsd41: stateid h...
3125

0836f5872   J. Bruce Fields   nfsd4: simplify s...
3126
  	/* If the client sends us a stateid from the future, it's buggy: */
81b829655   J. Bruce Fields   nfsd4: simplify s...
3127
  	if (stateid_generation_after(in, ref))
0836f5872   J. Bruce Fields   nfsd4: simplify s...
3128
3129
  		return nfserr_bad_stateid;
  	/*
81b829655   J. Bruce Fields   nfsd4: simplify s...
3130
3131
3132
3133
3134
3135
3136
3137
  	 * However, we could see a stateid from the past, even from a
  	 * non-buggy client.  For example, if the client sends a lock
  	 * while some IO is outstanding, the lock may bump si_generation
  	 * while the IO is still in flight.  The client could avoid that
  	 * situation by waiting for responses on all the IO requests,
  	 * but better performance may result in retrying IO that
  	 * receives an old_stateid error if requests are rarely
  	 * reordered in flight:
0836f5872   J. Bruce Fields   nfsd4: simplify s...
3138
  	 */
81b829655   J. Bruce Fields   nfsd4: simplify s...
3139
  	return nfserr_old_stateid;
0836f5872   J. Bruce Fields   nfsd4: simplify s...
3140
  }
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3141
  __be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
174568045   Bryan Schumaker   NFSD: Added TEST_...
3142
  {
97b7e3b6d   J. Bruce Fields   nfsd4: fix test_s...
3143
3144
3145
  	struct nfs4_stid *s;
  	struct nfs4_ol_stateid *ols;
  	__be32 status;
174568045   Bryan Schumaker   NFSD: Added TEST_...
3146
3147
  
  	if (STALE_STATEID(stateid))
97b7e3b6d   J. Bruce Fields   nfsd4: fix test_s...
3148
  		return nfserr_stale_stateid;
174568045   Bryan Schumaker   NFSD: Added TEST_...
3149

38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3150
  	s = find_stateid(cl, stateid);
97b7e3b6d   J. Bruce Fields   nfsd4: fix test_s...
3151
3152
  	if (!s)
  		 return nfserr_stale_stateid;
36279ac10   J. Bruce Fields   nfsd4: assume tes...
3153
  	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
174568045   Bryan Schumaker   NFSD: Added TEST_...
3154
  	if (status)
97b7e3b6d   J. Bruce Fields   nfsd4: fix test_s...
3155
3156
3157
3158
3159
  		return status;
  	if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID)))
  		return nfs_ok;
  	ols = openlockstateid(s);
  	if (ols->st_stateowner->so_is_open_owner
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
3160
  	    && !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
97b7e3b6d   J. Bruce Fields   nfsd4: fix test_s...
3161
3162
  		return nfserr_bad_stateid;
  	return nfs_ok;
174568045   Bryan Schumaker   NFSD: Added TEST_...
3163
  }
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
  static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
  {
  	struct nfs4_client *cl;
  
  	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
  		return nfserr_bad_stateid;
  	if (STALE_STATEID(stateid))
  		return nfserr_stale_stateid;
  	cl = find_confirmed_client(&stateid->si_opaque.so_clid);
  	if (!cl)
  		return nfserr_expired;
  	*s = find_stateid_by_type(cl, stateid, typemask);
  	if (!*s)
  		return nfserr_bad_stateid;
  	return nfs_ok;
  
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3181
3182
3183
  /*
  * Checks for stateid operations
  */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3184
  __be32
dd453dfd7   Benny Halevy   nfsd: pass nfsd4_...
3185
3186
  nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
  			   stateid_t *stateid, int flags, struct file **filpp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3187
  {
69064a276   J. Bruce Fields   nfsd4: use deleg ...
3188
  	struct nfs4_stid *s;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3189
  	struct nfs4_ol_stateid *stp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3190
  	struct nfs4_delegation *dp = NULL;
dd453dfd7   Benny Halevy   nfsd: pass nfsd4_...
3191
  	struct svc_fh *current_fh = &cstate->current_fh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3192
  	struct inode *ino = current_fh->fh_dentry->d_inode;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3193
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3194

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3195
3196
  	if (filpp)
  		*filpp = NULL;
18f82731b   J. Bruce Fields   nfsd4: rename io_...
3197
  	if (grace_disallows_io(ino))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3198
3199
3200
3201
  		return nfserr_grace;
  
  	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
  		return check_special_stateids(current_fh, stateid, flags);
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3202
3203
3204
  	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
  	if (status)
  		return status;
69064a276   J. Bruce Fields   nfsd4: use deleg ...
3205
3206
3207
  	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
  	if (status)
  		goto out;
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3208
3209
  	switch (s->sc_type) {
  	case NFS4_DELEG_STID:
69064a276   J. Bruce Fields   nfsd4: use deleg ...
3210
  		dp = delegstateid(s);
dc9bf700e   J. Bruce Fields   nfsd4: remove red...
3211
3212
3213
  		status = nfs4_check_delegmode(dp, flags);
  		if (status)
  			goto out;
43b0178ed   Dan Carpenter   nfsd: fix NULL de...
3214
  		if (filpp) {
acfdf5c38   J. Bruce Fields   nfsd4: acquire on...
3215
  			*filpp = dp->dl_file->fi_deleg_file;
43b0178ed   Dan Carpenter   nfsd: fix NULL de...
3216
3217
  			BUG_ON(!*filpp);
  		}
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3218
3219
3220
  		break;
  	case NFS4_OPEN_STID:
  	case NFS4_LOCK_STID:
69064a276   J. Bruce Fields   nfsd4: use deleg ...
3221
  		stp = openlockstateid(s);
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3222
3223
  		status = nfs4_check_fh(current_fh, stp);
  		if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3224
  			goto out;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3225
  		if (stp->st_stateowner->so_is_open_owner
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
3226
  		    && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3227
  			goto out;
a4455be08   J. Bruce Fields   nfsd4: trivial pr...
3228
3229
  		status = nfs4_check_openmode(stp, flags);
  		if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3230
  			goto out;
f9d7562fd   J. Bruce Fields   nfsd4: share file...
3231
3232
3233
3234
3235
  		if (filpp) {
  			if (flags & RD_STATE)
  				*filpp = find_readable_file(stp->st_file);
  			else
  				*filpp = find_writeable_file(stp->st_file);
f9d7562fd   J. Bruce Fields   nfsd4: share file...
3236
  		}
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3237
3238
3239
  		break;
  	default:
  		return nfserr_bad_stateid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3240
3241
3242
3243
3244
  	}
  	status = nfs_ok;
  out:
  	return status;
  }
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3245
  static __be32
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3246
  nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3247
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3248
  	if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3249
3250
3251
3252
3253
3254
  		return nfserr_locks_held;
  	release_lock_stateid(stp);
  	return nfs_ok;
  }
  
  /*
174568045   Bryan Schumaker   NFSD: Added TEST_...
3255
3256
3257
3258
3259
3260
   * Test if the stateid is valid
   */
  __be32
  nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
  		   struct nfsd4_test_stateid *test_stateid)
  {
36279ac10   J. Bruce Fields   nfsd4: assume tes...
3261
  	/* real work is done during encoding */
174568045   Bryan Schumaker   NFSD: Added TEST_...
3262
3263
  	return nfs_ok;
  }
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3264
3265
3266
3267
3268
  __be32
  nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
  		   struct nfsd4_free_stateid *free_stateid)
  {
  	stateid_t *stateid = &free_stateid->fr_stateid;
2da1cec71   J. Bruce Fields   nfsd4: simplify f...
3269
  	struct nfs4_stid *s;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3270
  	struct nfs4_client *cl = cstate->session->se_client;
2da1cec71   J. Bruce Fields   nfsd4: simplify f...
3271
  	__be32 ret = nfserr_bad_stateid;
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3272
3273
  
  	nfs4_lock_state();
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3274
  	s = find_stateid(cl, stateid);
2da1cec71   J. Bruce Fields   nfsd4: simplify f...
3275
  	if (!s)
81b829655   J. Bruce Fields   nfsd4: simplify s...
3276
  		goto out;
2da1cec71   J. Bruce Fields   nfsd4: simplify f...
3277
3278
  	switch (s->sc_type) {
  	case NFS4_DELEG_STID:
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3279
3280
  		ret = nfserr_locks_held;
  		goto out;
2da1cec71   J. Bruce Fields   nfsd4: simplify f...
3281
3282
3283
3284
3285
3286
3287
3288
3289
  	case NFS4_OPEN_STID:
  	case NFS4_LOCK_STID:
  		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
  		if (ret)
  			goto out;
  		if (s->sc_type == NFS4_LOCK_STID)
  			ret = nfsd4_free_lock_stateid(openlockstateid(s));
  		else
  			ret = nfserr_locks_held;
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3290
3291
3292
  		break;
  	default:
  		ret = nfserr_bad_stateid;
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3293
  	}
e1ca12dfb   Bryan Schumaker   NFSD: added FREE_...
3294
3295
3296
3297
  out:
  	nfs4_unlock_state();
  	return ret;
  }
4c4cd222e   NeilBrown   [PATCH] nfsd4: ch...
3298
3299
3300
3301
3302
3303
  static inline int
  setlkflg (int type)
  {
  	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
  		RD_STATE : WR_STATE;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3304

dcef0413d   J. Bruce Fields   nfsd4: move some ...
3305
  static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3306
3307
3308
3309
  {
  	struct svc_fh *current_fh = &cstate->current_fh;
  	struct nfs4_stateowner *sop = stp->st_stateowner;
  	__be32 status;
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3310
3311
3312
  	status = nfsd4_check_seqid(cstate, sop, seqid);
  	if (status)
  		return status;
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
  	if (stp->st_stid.sc_type == NFS4_CLOSED_STID)
  		/*
  		 * "Closed" stateid's exist *only* to return
  		 * nfserr_replay_me from the previous step.
  		 */
  		return nfserr_bad_stateid;
  	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
  	if (status)
  		return status;
  	return nfs4_check_fh(current_fh, stp);
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3323
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3324
3325
3326
  /* 
   * Checks for sequence id mutating operations. 
   */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3327
  static __be32
dd453dfd7   Benny Halevy   nfsd: pass nfsd4_...
3328
  nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
2288d0e39   J. Bruce Fields   nfsd4: pass aroun...
3329
  			 stateid_t *stateid, char typemask,
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3330
  			 struct nfs4_ol_stateid **stpp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3331
  {
0836f5872   J. Bruce Fields   nfsd4: simplify s...
3332
  	__be32 status;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3333
  	struct nfs4_stid *s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3334

8c10cbdb4   Benny Halevy   nfsd: use STATEID...
3335
3336
3337
  	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "
  ", __func__,
  		seqid, STATEID_VAL(stateid));
3a4f98bbf   NeilBrown   [PATCH] nfsd4: cl...
3338

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3339
  	*stpp = NULL;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3340
  	status = nfsd4_lookup_stateid(stateid, typemask, &s);
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3341
3342
  	if (status)
  		return status;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3343
  	*stpp = openlockstateid(s);
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3344
  	cstate->replay_owner = (*stpp)->st_stateowner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3345

c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3346
3347
  	return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
  }
39325bd03   J. Bruce Fields   nfsd4: fix bad se...
3348

dcef0413d   J. Bruce Fields   nfsd4: move some ...
3349
  static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp)
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3350
3351
3352
  {
  	__be32 status;
  	struct nfs4_openowner *oo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3353

c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3354
  	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
2288d0e39   J. Bruce Fields   nfsd4: pass aroun...
3355
  						NFS4_OPEN_STID, stpp);
7a8711c9a   J. Bruce Fields   nfsd4: share comm...
3356
3357
  	if (status)
  		return status;
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3358
  	oo = openowner((*stpp)->st_stateowner);
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
3359
  	if (!(oo->oo_flags & NFS4_OO_CONFIRMED))
3a4f98bbf   NeilBrown   [PATCH] nfsd4: cl...
3360
  		return nfserr_bad_stateid;
3a4f98bbf   NeilBrown   [PATCH] nfsd4: cl...
3361
  	return nfs_ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3362
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3363
  __be32
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3364
  nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
a4f1706a9   J.Bruce Fields   [PATCH] knfsd: nf...
3365
  		   struct nfsd4_open_confirm *oc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3366
  {
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3367
  	__be32 status;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3368
  	struct nfs4_openowner *oo;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3369
  	struct nfs4_ol_stateid *stp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3370
3371
3372
  
  	dprintk("NFSD: nfsd4_open_confirm on file %.*s
  ",
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3373
3374
  			(int)cstate->current_fh.fh_dentry->d_name.len,
  			cstate->current_fh.fh_dentry->d_name.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3375

ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3376
  	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
a8cddc5df   J. Bruce Fields   [PATCH] knfsd: nf...
3377
3378
  	if (status)
  		return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3379
3380
  
  	nfs4_lock_state();
9072d5c66   J. Bruce Fields   nfsd4: cleanup se...
3381
  	status = nfs4_preprocess_seqid_op(cstate,
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3382
  					oc->oc_seqid, &oc->oc_req_stateid,
2288d0e39   J. Bruce Fields   nfsd4: pass aroun...
3383
  					NFS4_OPEN_STID, &stp);
9072d5c66   J. Bruce Fields   nfsd4: cleanup se...
3384
  	if (status)
68b66e827   J. Bruce Fields   nfsd4: move doubl...
3385
  		goto out;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3386
  	oo = openowner(stp->st_stateowner);
68b66e827   J. Bruce Fields   nfsd4: move doubl...
3387
  	status = nfserr_bad_stateid;
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
3388
  	if (oo->oo_flags & NFS4_OO_CONFIRMED)
68b66e827   J. Bruce Fields   nfsd4: move doubl...
3389
  		goto out;
dad1c067e   J. Bruce Fields   nfsd4: replace oo...
3390
  	oo->oo_flags |= NFS4_OO_CONFIRMED;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3391
3392
  	update_stateid(&stp->st_stid.sc_stateid);
  	memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
8c10cbdb4   Benny Halevy   nfsd: use STATEID...
3393
3394
  	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "
  ",
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3395
  		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
c7b9a4592   NeilBrown   [PATCH] knfsd: nf...
3396

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3397
  	nfsd4_create_clid_dir(oo->oo_owner.so_client);
68b66e827   J. Bruce Fields   nfsd4: move doubl...
3398
  	status = nfs_ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3399
  out:
5ec094c10   J. Bruce Fields   nfsd4: extend sta...
3400
3401
  	if (!cstate->replay_owner)
  		nfs4_unlock_state();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3402
3403
  	return status;
  }
6409a5a65   J. Bruce Fields   nfsd4: clean up d...
3404
  static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3405
  {
6409a5a65   J. Bruce Fields   nfsd4: clean up d...
3406
3407
3408
3409
3410
  	if (!test_bit(access, &stp->st_access_bmap))
  		return;
  	nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access));
  	__clear_bit(access, &stp->st_access_bmap);
  }
f197c2719   J. Bruce Fields   nfsd4: fix file l...
3411

6409a5a65   J. Bruce Fields   nfsd4: clean up d...
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
  static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
  {
  	switch (to_access) {
  	case NFS4_SHARE_ACCESS_READ:
  		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
  		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
  		break;
  	case NFS4_SHARE_ACCESS_WRITE:
  		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
  		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
  		break;
  	case NFS4_SHARE_ACCESS_BOTH:
  		break;
  	default:
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
  	}
  }
  
  static void
  reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
  {
  	int i;
  	for (i = 0; i < 4; i++) {
  		if ((i & deny) != i)
  			__clear_bit(i, bmap);
  	}
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3439
  __be32
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3440
3441
  nfsd4_open_downgrade(struct svc_rqst *rqstp,
  		     struct nfsd4_compound_state *cstate,
a4f1706a9   J.Bruce Fields   [PATCH] knfsd: nf...
3442
  		     struct nfsd4_open_downgrade *od)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3443
  {
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3444
  	__be32 status;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3445
  	struct nfs4_ol_stateid *stp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3446
3447
3448
  
  	dprintk("NFSD: nfsd4_open_downgrade on file %.*s
  ", 
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3449
3450
  			(int)cstate->current_fh.fh_dentry->d_name.len,
  			cstate->current_fh.fh_dentry->d_name.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3451

c30e92df3   J. Bruce Fields   nfsd4: ignore WAN...
3452
3453
  	/* We don't yet support WANT bits: */
  	od->od_share_access &= NFS4_SHARE_ACCESS_MASK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3454
3455
  
  	nfs4_lock_state();
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3456
3457
  	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
  					&od->od_stateid, &stp);
9072d5c66   J. Bruce Fields   nfsd4: cleanup se...
3458
  	if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3459
  		goto out; 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
  	status = nfserr_inval;
  	if (!test_bit(od->od_share_access, &stp->st_access_bmap)) {
  		dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x
  ",
  			stp->st_access_bmap, od->od_share_access);
  		goto out;
  	}
  	if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) {
  		dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x
  ",
  			stp->st_deny_bmap, od->od_share_deny);
  		goto out;
  	}
6409a5a65   J. Bruce Fields   nfsd4: clean up d...
3473
  	nfs4_stateid_downgrade(stp, od->od_share_access);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3474

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3475
  	reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3476
3477
  	update_stateid(&stp->st_stid.sc_stateid);
  	memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3478
3479
  	status = nfs_ok;
  out:
5ec094c10   J. Bruce Fields   nfsd4: extend sta...
3480
3481
  	if (!cstate->replay_owner)
  		nfs4_unlock_state();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3482
3483
  	return status;
  }
38c387b52   J. Bruce Fields   nfsd4: match clos...
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
  void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so)
  {
  	struct nfs4_openowner *oo;
  	struct nfs4_ol_stateid *s;
  
  	if (!so->so_is_open_owner)
  		return;
  	oo = openowner(so);
  	s = oo->oo_last_closed_stid;
  	if (!s)
  		return;
  	if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) {
  		/* Release the last_closed_stid on the next seqid bump: */
  		oo->oo_flags |= NFS4_OO_PURGE_CLOSE;
  		return;
  	}
  	oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE;
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3501
3502
3503
3504
3505
3506
3507
  	release_last_closed_stateid(oo);
  }
  
  static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
  {
  	unhash_open_stateid(s);
  	s->st_stid.sc_type = NFS4_CLOSED_STID;
38c387b52   J. Bruce Fields   nfsd4: match clos...
3508
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3509
3510
3511
  /*
   * nfs4_unlock_state() called after encode
   */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3512
  __be32
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3513
  nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
a4f1706a9   J.Bruce Fields   [PATCH] knfsd: nf...
3514
  	    struct nfsd4_close *close)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3515
  {
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3516
  	__be32 status;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3517
  	struct nfs4_openowner *oo;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3518
  	struct nfs4_ol_stateid *stp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3519
3520
3521
  
  	dprintk("NFSD: nfsd4_close on file %.*s
  ", 
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3522
3523
  			(int)cstate->current_fh.fh_dentry->d_name.len,
  			cstate->current_fh.fh_dentry->d_name.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3524
3525
  
  	nfs4_lock_state();
f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3526
3527
3528
3529
  	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
  					&close->cl_stateid,
  					NFS4_OPEN_STID|NFS4_CLOSED_STID,
  					&stp);
9072d5c66   J. Bruce Fields   nfsd4: cleanup se...
3530
  	if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3531
  		goto out; 
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3532
  	oo = openowner(stp->st_stateowner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3533
  	status = nfs_ok;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3534
3535
  	update_stateid(&stp->st_stid.sc_stateid);
  	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3536

f7a4d8720   J. Bruce Fields   nfsd4: hash close...
3537
  	nfsd4_close_open_stateid(stp);
38c387b52   J. Bruce Fields   nfsd4: match clos...
3538
  	oo->oo_last_closed_stid = stp;
04ef59548   J. Bruce Fields   [PATCH] nfsd4: re...
3539
3540
3541
3542
3543
  
  	/* place unused nfs4_stateowners on so_close_lru list to be
  	 * released by the laundromat service after the lease period
  	 * to enable us to handle CLOSE replay
  	 */
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3544
3545
  	if (list_empty(&oo->oo_owner.so_stateids))
  		move_to_close_lru(oo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3546
  out:
5ec094c10   J. Bruce Fields   nfsd4: extend sta...
3547
3548
  	if (!cstate->replay_owner)
  		nfs4_unlock_state();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3549
3550
  	return status;
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3551
  __be32
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3552
3553
  nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
  		  struct nfsd4_delegreturn *dr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3554
  {
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3555
3556
  	struct nfs4_delegation *dp;
  	stateid_t *stateid = &dr->dr_stateid;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3557
  	struct nfs4_stid *s;
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3558
  	struct inode *inode;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3559
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3560

ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3561
  	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3562
3563
  		return status;
  	inode = cstate->current_fh.fh_dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3564
3565
  
  	nfs4_lock_state();
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3566
3567
  	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s);
  	if (status)
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3568
  		goto out;
38c2f4b12   J. Bruce Fields   nfsd4: look up st...
3569
  	dp = delegstateid(s);
d5477a8db   J. Bruce Fields   nfsd4: add common...
3570
  	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3571
3572
  	if (status)
  		goto out;
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3573
3574
  
  	unhash_delegation(dp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3575
  out:
203a8c8e6   J. Bruce Fields   nfsd4: separate d...
3576
  	nfs4_unlock_state();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3577
3578
  	return status;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3579
  #define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3580

009673b43   J. Bruce Fields   nfsd4: add a sepa...
3581
3582
3583
  #define LOCKOWNER_INO_HASH_BITS 8
  #define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS)
  #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3584

87df4de80   Benny Halevy   nfsd: last_byte_o...
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
  static inline u64
  end_offset(u64 start, u64 len)
  {
  	u64 end;
  
  	end = start + len;
  	return end >= start ? end: NFS4_MAX_UINT64;
  }
  
  /* last octet in a range */
  static inline u64
  last_byte_offset(u64 start, u64 len)
  {
  	u64 end;
  
  	BUG_ON(!len);
  	end = start + len;
  	return end > start ? end - 1: NFS4_MAX_UINT64;
  }
009673b43   J. Bruce Fields   nfsd4: add a sepa...
3604
  static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3605
3606
3607
  {
  	return (file_hashval(inode) + cl_id
  			+ opaque_hashval(ownername->data, ownername->len))
009673b43   J. Bruce Fields   nfsd4: add a sepa...
3608
  		& LOCKOWNER_INO_HASH_MASK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3609
  }
009673b43   J. Bruce Fields   nfsd4: add a sepa...
3610
  static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3611

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
  /*
   * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
   * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
   * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
   * locking, this prevents us from being completely protocol-compliant.  The
   * real solution to this problem is to start using unsigned file offsets in
   * the VFS, but this is a very deep change!
   */
  static inline void
  nfs4_transform_lock_offset(struct file_lock *lock)
  {
  	if (lock->fl_start < 0)
  		lock->fl_start = OFFSET_MAX;
  	if (lock->fl_end < 0)
  		lock->fl_end = OFFSET_MAX;
  }
d5b9026a6   NeilBrown   [PATCH] knfsd: lo...
3628
3629
  /* Hack!: For now, we're defining this just so we can use a pointer to it
   * as a unique cookie to identify our (NFSv4's) posix locks. */
7b021967c   Alexey Dobriyan   const: make lock_...
3630
  static const struct lock_manager_operations nfsd_posix_mng_ops  = {
d5b9026a6   NeilBrown   [PATCH] knfsd: lo...
3631
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3632
3633
3634
3635
  
  static inline void
  nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3636
  	struct nfs4_lockowner *lo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3637

d5b9026a6   NeilBrown   [PATCH] knfsd: lo...
3638
  	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3639
3640
3641
  		lo = (struct nfs4_lockowner *) fl->fl_owner;
  		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
  					lo->lo_owner.so_owner.len, GFP_KERNEL);
7c13f344c   J. Bruce Fields   nfsd4: drop most ...
3642
3643
3644
  		if (!deny->ld_owner.data)
  			/* We just don't care that much */
  			goto nevermind;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3645
3646
  		deny->ld_owner.len = lo->lo_owner.so_owner.len;
  		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
d5b9026a6   NeilBrown   [PATCH] knfsd: lo...
3647
  	} else {
7c13f344c   J. Bruce Fields   nfsd4: drop most ...
3648
3649
3650
  nevermind:
  		deny->ld_owner.len = 0;
  		deny->ld_owner.data = NULL;
d5b9026a6   NeilBrown   [PATCH] knfsd: lo...
3651
3652
  		deny->ld_clientid.cl_boot = 0;
  		deny->ld_clientid.cl_id = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3653
3654
  	}
  	deny->ld_start = fl->fl_start;
87df4de80   Benny Halevy   nfsd: last_byte_o...
3655
3656
  	deny->ld_length = NFS4_MAX_UINT64;
  	if (fl->fl_end != NFS4_MAX_UINT64)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3657
3658
3659
3660
3661
  		deny->ld_length = fl->fl_end - fl->fl_start + 1;        
  	deny->ld_type = NFS4_READ_LT;
  	if (fl->fl_type != F_RDLCK)
  		deny->ld_type = NFS4_WRITE_LT;
  }
b93d87c19   J. Bruce Fields   nfsd4: fix lockow...
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
  static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner)
  {
  	struct nfs4_ol_stateid *lst;
  
  	if (!same_owner_str(&lo->lo_owner, owner, clid))
  		return false;
  	lst = list_first_entry(&lo->lo_owner.so_stateids,
  			       struct nfs4_ol_stateid, st_perstateowner);
  	return lst->st_file->fi_inode == inode;
  }
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3672
3673
  static struct nfs4_lockowner *
  find_lockowner_str(struct inode *inode, clientid_t *clid,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3674
3675
  		struct xdr_netobj *owner)
  {
009673b43   J. Bruce Fields   nfsd4: add a sepa...
3676
  	unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
b93d87c19   J. Bruce Fields   nfsd4: fix lockow...
3677
  	struct nfs4_lockowner *lo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3678

009673b43   J. Bruce Fields   nfsd4: add a sepa...
3679
  	list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
b93d87c19   J. Bruce Fields   nfsd4: fix lockow...
3680
3681
  		if (same_lockowner_ino(lo, inode, clid, owner))
  			return lo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3682
3683
3684
  	}
  	return NULL;
  }
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3685
  static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
3686
  {
009673b43   J. Bruce Fields   nfsd4: add a sepa...
3687
3688
3689
  	struct inode *inode = open_stp->st_file->fi_inode;
  	unsigned int inohash = lockowner_ino_hashval(inode,
  			clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
16bfdaafa   J. Bruce Fields   nfsd4: share open...
3690
  	list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
009673b43   J. Bruce Fields   nfsd4: add a sepa...
3691
  	list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3692
  	list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
ff194bd95   J. Bruce Fields   nfsd4: cleanup lo...
3693
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3694
3695
3696
  /*
   * Alloc a lock owner structure.
   * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 
25985edce   Lucas De Marchi   Fix common misspe...
3697
   * occurred. 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3698
   *
16bfdaafa   J. Bruce Fields   nfsd4: share open...
3699
   * strhashval = ownerstr_hashval
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3700
   */
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3701
  static struct nfs4_lockowner *
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3702
  alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3703
  	struct nfs4_lockowner *lo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3704

fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3705
3706
  	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
  	if (!lo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3707
  		return NULL;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3708
3709
  	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
  	lo->lo_owner.so_is_open_owner = 0;
b59e3c0e1   Neil Brown   [PATCH] nfsd4: fi...
3710
3711
  	/* It is the openowner seqid that will be incremented in encode in the
  	 * case of new lockowners; so increment the lock seqid manually: */
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3712
3713
3714
  	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
  	hash_lockowner(lo, strhashval, clp, open_stp);
  	return lo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3715
  }
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3716
3717
  static struct nfs4_ol_stateid *
  alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3718
  {
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3719
  	struct nfs4_ol_stateid *stp;
d3b313a46   J. Bruce Fields   nfsd4: construct ...
3720
  	struct nfs4_client *clp = lo->lo_owner.so_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3721

996e09385   J. Bruce Fields   nfsd4: do idr pre...
3722
  	stp = nfs4_alloc_stateid(clp);
5ac049ac6   NeilBrown   [PATCH] nfsd4: sl...
3723
  	if (stp == NULL)
6136d2b40   J. Bruce Fields   nfsd4: use idr fo...
3724
  		return NULL;
996e09385   J. Bruce Fields   nfsd4: do idr pre...
3725
  	init_stid(&stp->st_stid, clp, NFS4_LOCK_STID);
8beefa249   NeilBrown   [PATCH] nfsd4: re...
3726
  	list_add(&stp->st_perfile, &fp->fi_stateids);
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3727
3728
  	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
  	stp->st_stateowner = &lo->lo_owner;
13cd21845   NeilBrown   [PATCH] nfsd4: re...
3729
  	get_nfs4_file(fp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3730
  	stp->st_file = fp;
0997b1736   J. Bruce Fields   nfsd4: fix struct...
3731
  	stp->st_access_bmap = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3732
  	stp->st_deny_bmap = open_stp->st_deny_bmap;
4c4cd222e   NeilBrown   [PATCH] nfsd4: ch...
3733
  	stp->st_openstp = open_stp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3734
3735
  	return stp;
  }
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
3736
  static int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3737
3738
  check_lock_length(u64 offset, u64 length)
  {
87df4de80   Benny Halevy   nfsd: last_byte_o...
3739
  	return ((length == 0)  || ((length != NFS4_MAX_UINT64) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3740
3741
  	     LOFF_OVERFLOW(offset, length)));
  }
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3742
  static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
0997b1736   J. Bruce Fields   nfsd4: fix struct...
3743
3744
3745
3746
3747
3748
3749
3750
3751
  {
  	struct nfs4_file *fp = lock_stp->st_file;
  	int oflag = nfs4_access_to_omode(access);
  
  	if (test_bit(access, &lock_stp->st_access_bmap))
  		return;
  	nfs4_file_get_access(fp, oflag);
  	__set_bit(access, &lock_stp->st_access_bmap);
  }
64a284d07   J. Bruce Fields   nfsd4: maintain o...
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
  __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)
  {
  	struct nfs4_file *fi = ost->st_file;
  	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
  	struct nfs4_client *cl = oo->oo_owner.so_client;
  	struct nfs4_lockowner *lo;
  	unsigned int strhashval;
  
  	lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner);
  	if (lo) {
  		if (!cstate->minorversion)
  			return nfserr_bad_seqid;
  		/* XXX: a lockowner always has exactly one stateid: */
  		*lst = list_first_entry(&lo->lo_owner.so_stateids,
  				struct nfs4_ol_stateid, st_perstateowner);
  		return nfs_ok;
  	}
16bfdaafa   J. Bruce Fields   nfsd4: share open...
3769
  	strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
64a284d07   J. Bruce Fields   nfsd4: maintain o...
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
  			&lock->v.new.owner);
  	lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
  	if (lo == NULL)
  		return nfserr_jukebox;
  	*lst = alloc_init_lock_stateid(lo, fi, ost);
  	if (*lst == NULL) {
  		release_lockowner(lo);
  		return nfserr_jukebox;
  	}
  	*new = true;
  	return nfs_ok;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3782
3783
3784
  /*
   *  LOCK operation 
   */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3785
  __be32
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3786
  nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
a4f1706a9   J.Bruce Fields   [PATCH] knfsd: nf...
3787
  	   struct nfsd4_lock *lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3788
  {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3789
3790
  	struct nfs4_openowner *open_sop = NULL;
  	struct nfs4_lockowner *lock_sop = NULL;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3791
  	struct nfs4_ol_stateid *lock_stp;
7d9478429   J. Bruce Fields   nfsd4: fix downgr...
3792
3793
  	struct nfs4_file *fp;
  	struct file *filp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3794
  	struct file_lock file_lock;
8dc7c3115   Andy Adamson   locks,lockd: fix ...
3795
  	struct file_lock conflock;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3796
  	__be32 status = 0;
64a284d07   J. Bruce Fields   nfsd4: maintain o...
3797
  	bool new_state = false;
b34f27aa5   J. Bruce Fields   nfsd4: get lock c...
3798
  	int lkflg;
b8dd7b9ab   Al Viro   [PATCH] nfsd: NFS...
3799
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3800
3801
3802
3803
3804
  
  	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld
  ",
  		(long long) lock->lk_offset,
  		(long long) lock->lk_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3805
3806
  	if (check_lock_length(lock->lk_offset, lock->lk_length))
  		 return nfserr_inval;
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3807
  	if ((status = fh_verify(rqstp, &cstate->current_fh,
8837abcab   Miklos Szeredi   nfsd: rename MAY_...
3808
  				S_IFREG, NFSD_MAY_LOCK))) {
a6f6ef2f1   Andy Adamson   [PATCH] nfsd4: mi...
3809
3810
3811
3812
  		dprintk("NFSD: nfsd4_lock: permission denied!
  ");
  		return status;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3813
3814
3815
  	nfs4_lock_state();
  
  	if (lock->lk_is_new) {
893f87701   NeilBrown   [PATCH] nfsd4: co...
3816
3817
3818
3819
3820
  		/*
  		 * Client indicates that this is a new lockowner.
  		 * Use open owner and open stateid to create lock owner and
  		 * lock stateid.
  		 */
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3821
  		struct nfs4_ol_stateid *open_stp = NULL;
684e56385   J. Bruce Fields   nfsd4: cleanup lo...
3822
3823
3824
3825
3826
3827
  
  		if (nfsd4_has_session(cstate))
  			/* See rfc 5661 18.10.3: given clientid is ignored: */
  			memcpy(&lock->v.new.clientid,
  				&cstate->session->se_client->cl_clientid,
  				sizeof(clientid_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3828
  		status = nfserr_stale_clientid;
684e56385   J. Bruce Fields   nfsd4: cleanup lo...
3829
  		if (STALE_CLIENTID(&lock->lk_new_clientid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3830
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3831

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3832
  		/* validate and update open stateid and open seqid */
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3833
  		status = nfs4_preprocess_confirmed_seqid_op(cstate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3834
3835
  				        lock->lk_new_open_seqid,
  		                        &lock->lk_new_open_stateid,
c0a5d93ef   J. Bruce Fields   nfsd4: split prep...
3836
  					&open_stp);
375151773   NeilBrown   [PATCH] nfsd4: st...
3837
  		if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3838
  			goto out;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3839
  		open_sop = openowner(open_stp->st_stateowner);
b34f27aa5   J. Bruce Fields   nfsd4: get lock c...
3840
  		status = nfserr_bad_stateid;
684e56385   J. Bruce Fields   nfsd4: cleanup lo...
3841
  		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
b34f27aa5   J. Bruce Fields   nfsd4: get lock c...
3842
3843
  						&lock->v.new.clientid))
  			goto out;
64a284d07   J. Bruce Fields   nfsd4: maintain o...
3844
3845
3846
  		status = lookup_or_create_lock_state(cstate, open_stp, lock,
  							&lock_stp, &new_state);
  		if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3847
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3848
3849
  	} else {
  		/* lock (lock owner + lock stateid) already exists */
dd453dfd7   Benny Halevy   nfsd: pass nfsd4_...
3850
  		status = nfs4_preprocess_seqid_op(cstate,
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3851
3852
  				       lock->lk_old_lock_seqid,
  				       &lock->lk_old_lock_stateid,
2288d0e39   J. Bruce Fields   nfsd4: pass aroun...
3853
  				       NFS4_LOCK_STID, &lock_stp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3854
3855
3856
  		if (status)
  			goto out;
  	}
64a284d07   J. Bruce Fields   nfsd4: maintain o...
3857
3858
  	lock_sop = lockowner(lock_stp->st_stateowner);
  	fp = lock_stp->st_file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3859

b34f27aa5   J. Bruce Fields   nfsd4: get lock c...
3860
3861
3862
3863
  	lkflg = setlkflg(lock->lk_type);
  	status = nfs4_check_openmode(lock_stp, lkflg);
  	if (status)
  		goto out;
0dd395dc7   NeilBrown   [PATCH] nfsd4: ER...
3864
  	status = nfserr_grace;
af558e33b   J. Bruce Fields   nfsd: common grac...
3865
  	if (locks_in_grace() && !lock->lk_reclaim)
0dd395dc7   NeilBrown   [PATCH] nfsd4: ER...
3866
3867
  		goto out;
  	status = nfserr_no_grace;
af558e33b   J. Bruce Fields   nfsd: common grac...
3868
  	if (!locks_in_grace() && lock->lk_reclaim)
0dd395dc7   NeilBrown   [PATCH] nfsd4: ER...
3869
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3870
3871
3872
3873
  	locks_init_lock(&file_lock);
  	switch (lock->lk_type) {
  		case NFS4_READ_LT:
  		case NFS4_READW_LT:
0997b1736   J. Bruce Fields   nfsd4: fix struct...
3874
3875
3876
  			filp = find_readable_file(lock_stp->st_file);
  			if (filp)
  				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3877
  			file_lock.fl_type = F_RDLCK;
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
3878
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3879
3880
  		case NFS4_WRITE_LT:
  		case NFS4_WRITEW_LT:
0997b1736   J. Bruce Fields   nfsd4: fix struct...
3881
3882
3883
  			filp = find_writeable_file(lock_stp->st_file);
  			if (filp)
  				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3884
  			file_lock.fl_type = F_WRLCK;
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
3885
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3886
3887
3888
3889
  		default:
  			status = nfserr_inval;
  		goto out;
  	}
f9d7562fd   J. Bruce Fields   nfsd4: share file...
3890
3891
3892
3893
  	if (!filp) {
  		status = nfserr_openmode;
  		goto out;
  	}
b59e3c0e1   Neil Brown   [PATCH] nfsd4: fi...
3894
  	file_lock.fl_owner = (fl_owner_t)lock_sop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3895
3896
3897
  	file_lock.fl_pid = current->tgid;
  	file_lock.fl_file = filp;
  	file_lock.fl_flags = FL_POSIX;
d5b9026a6   NeilBrown   [PATCH] knfsd: lo...
3898
  	file_lock.fl_lmops = &nfsd_posix_mng_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3899
3900
  
  	file_lock.fl_start = lock->lk_offset;
87df4de80   Benny Halevy   nfsd: last_byte_o...
3901
  	file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3902
3903
3904
3905
3906
3907
  	nfs4_transform_lock_offset(&file_lock);
  
  	/*
  	* Try to lock the file in the VFS.
  	* Note: locks.c uses the BKL to protect the inode's lock list.
  	*/
529d7b2a7   J. Bruce Fields   nfsd4: minor nfs4...
3908
  	err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
b8dd7b9ab   Al Viro   [PATCH] nfsd: NFS...
3909
  	switch (-err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3910
  	case 0: /* success! */
dcef0413d   J. Bruce Fields   nfsd4: move some ...
3911
3912
  		update_stateid(&lock_stp->st_stid.sc_stateid);
  		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3913
  				sizeof(stateid_t));
b8dd7b9ab   Al Viro   [PATCH] nfsd: NFS...
3914
  		status = 0;
eb76b3fda   Andy Adamson   [PATCH] NFSD4: re...
3915
3916
3917
3918
3919
3920
3921
  		break;
  	case (EAGAIN):		/* conflock holds conflicting lock */
  		status = nfserr_denied;
  		dprintk("NFSD: nfsd4_lock: conflicting lock found!
  ");
  		nfs4_set_lock_denied(&conflock, &lock->lk_denied);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3922
3923
  	case (EDEADLK):
  		status = nfserr_deadlock;
eb76b3fda   Andy Adamson   [PATCH] NFSD4: re...
3924
  		break;
3e7724639   J. Bruce Fields   nfsd4: stop using...
3925
  	default:
fd85b8170   Marc Eshel   nfsd4: Convert NF...
3926
3927
  		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d
  ",err);
3e7724639   J. Bruce Fields   nfsd4: stop using...
3928
  		status = nfserrno(err);
eb76b3fda   Andy Adamson   [PATCH] NFSD4: re...
3929
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3930
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3931
  out:
64a284d07   J. Bruce Fields   nfsd4: maintain o...
3932
  	if (status && new_state)
f044ff830   J. Bruce Fields   nfsd4: split open...
3933
  		release_lockowner(lock_sop);
5ec094c10   J. Bruce Fields   nfsd4: extend sta...
3934
3935
  	if (!cstate->replay_owner)
  		nfs4_unlock_state();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3936
3937
3938
3939
  	return status;
  }
  
  /*
55ef1274d   J. Bruce Fields   nfsd: Ensure nfsv...
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
   * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
   * so we do a temporary open here just to get an open file to pass to
   * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
   * inode operation.)
   */
  static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
  {
  	struct file *file;
  	int err;
  
  	err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
  	if (err)
  		return err;
  	err = vfs_test_lock(file, lock);
  	nfsd_close(file);
  	return err;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3959
3960
   * LOCKT operation
   */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3961
  __be32
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3962
3963
  nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
  	    struct nfsd4_lockt *lockt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3964
3965
  {
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3966
  	struct file_lock file_lock;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
3967
  	struct nfs4_lockowner *lo;
fd85b8170   Marc Eshel   nfsd4: Convert NF...
3968
  	int error;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
3969
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3970

af558e33b   J. Bruce Fields   nfsd: common grac...
3971
  	if (locks_in_grace())
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3972
3973
3974
3975
  		return nfserr_grace;
  
  	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
  		 return nfserr_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3976
3977
3978
  	nfs4_lock_state();
  
  	status = nfserr_stale_clientid;
60adfc50d   Andy Adamson   nfsd41: clientid ...
3979
  	if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3980
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3981

75c096f75   J. Bruce Fields   nfsd4: it's OK to...
3982
  	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3983
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3984

ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
3985
  	inode = cstate->current_fh.fh_dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
  	locks_init_lock(&file_lock);
  	switch (lockt->lt_type) {
  		case NFS4_READ_LT:
  		case NFS4_READW_LT:
  			file_lock.fl_type = F_RDLCK;
  		break;
  		case NFS4_WRITE_LT:
  		case NFS4_WRITEW_LT:
  			file_lock.fl_type = F_WRLCK;
  		break;
  		default:
2fdada03b   J. Bruce Fields   knfsd: demote som...
3997
3998
  			dprintk("NFSD: nfs4_lockt: bad lock type!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3999
4000
4001
  			status = nfserr_inval;
  		goto out;
  	}
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
4002
4003
4004
  	lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
  	if (lo)
  		file_lock.fl_owner = (fl_owner_t)lo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4005
4006
4007
4008
  	file_lock.fl_pid = current->tgid;
  	file_lock.fl_flags = FL_POSIX;
  
  	file_lock.fl_start = lockt->lt_offset;
87df4de80   Benny Halevy   nfsd: last_byte_o...
4009
  	file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4010
4011
  
  	nfs4_transform_lock_offset(&file_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4012
  	status = nfs_ok;
55ef1274d   J. Bruce Fields   nfsd: Ensure nfsv...
4013
  	error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
fd85b8170   Marc Eshel   nfsd4: Convert NF...
4014
4015
4016
4017
  	if (error) {
  		status = nfserrno(error);
  		goto out;
  	}
9d6a8c5c2   Marc Eshel   locks: give posix...
4018
  	if (file_lock.fl_type != F_UNLCK) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4019
  		status = nfserr_denied;
9d6a8c5c2   Marc Eshel   locks: give posix...
4020
  		nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4021
4022
4023
4024
4025
  	}
  out:
  	nfs4_unlock_state();
  	return status;
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
4026
  __be32
ca3643171   J.Bruce Fields   [PATCH] knfsd: nf...
4027
  nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
a4f1706a9   J.Bruce Fields   [PATCH] knfsd: nf...
4028
  	    struct nfsd4_locku *locku)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4029
  {
dcef0413d   J. Bruce Fields   nfsd4: move some ...
4030
  	struct nfs4_ol_stateid *stp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4031
4032
  	struct file *filp = NULL;
  	struct file_lock file_lock;
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
4033
  	__be32 status;
b8dd7b9ab   Al Viro   [PATCH] nfsd: NFS...
4034
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
  						        
  	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld
  ",
  		(long long) locku->lu_offset,
  		(long long) locku->lu_length);
  
  	if (check_lock_length(locku->lu_offset, locku->lu_length))
  		 return nfserr_inval;
  
  	nfs4_lock_state();
  									        
9072d5c66   J. Bruce Fields   nfsd4: cleanup se...
4046
  	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
2288d0e39   J. Bruce Fields   nfsd4: pass aroun...
4047
  					&locku->lu_stateid, NFS4_LOCK_STID, &stp);
9072d5c66   J. Bruce Fields   nfsd4: cleanup se...
4048
  	if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4049
  		goto out;
f9d7562fd   J. Bruce Fields   nfsd4: share file...
4050
4051
4052
4053
4054
  	filp = find_any_file(stp->st_file);
  	if (!filp) {
  		status = nfserr_lock_range;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4055
4056
4057
  	BUG_ON(!filp);
  	locks_init_lock(&file_lock);
  	file_lock.fl_type = F_UNLCK;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
4058
  	file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4059
4060
4061
  	file_lock.fl_pid = current->tgid;
  	file_lock.fl_file = filp;
  	file_lock.fl_flags = FL_POSIX; 
d5b9026a6   NeilBrown   [PATCH] knfsd: lo...
4062
  	file_lock.fl_lmops = &nfsd_posix_mng_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4063
  	file_lock.fl_start = locku->lu_offset;
87df4de80   Benny Halevy   nfsd: last_byte_o...
4064
  	file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4065
4066
4067
4068
4069
  	nfs4_transform_lock_offset(&file_lock);
  
  	/*
  	*  Try to unlock the file in the VFS.
  	*/
fd85b8170   Marc Eshel   nfsd4: Convert NF...
4070
  	err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
b8dd7b9ab   Al Viro   [PATCH] nfsd: NFS...
4071
  	if (err) {
fd85b8170   Marc Eshel   nfsd4: Convert NF...
4072
4073
  		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4074
4075
4076
4077
4078
  		goto out_nfserr;
  	}
  	/*
  	* OK, unlock succeeded; the only thing left to do is update the stateid.
  	*/
dcef0413d   J. Bruce Fields   nfsd4: move some ...
4079
4080
  	update_stateid(&stp->st_stid.sc_stateid);
  	memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4081
4082
  
  out:
71c3bcd71   J. Bruce Fields   nfsd4: fix state ...
4083
4084
  	if (!cstate->replay_owner)
  		nfs4_unlock_state();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4085
4086
4087
  	return status;
  
  out_nfserr:
b8dd7b9ab   Al Viro   [PATCH] nfsd: NFS...
4088
  	status = nfserrno(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4089
4090
4091
4092
4093
4094
4095
4096
4097
  	goto out;
  }
  
  /*
   * returns
   * 	1: locks held by lockowner
   * 	0: no locks held by lockowner
   */
  static int
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
4098
  check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4099
4100
  {
  	struct file_lock **flpp;
f9d7562fd   J. Bruce Fields   nfsd4: share file...
4101
  	struct inode *inode = filp->fi_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4102
  	int status = 0;
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
4103
  	lock_flocks();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4104
  	for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
796dadfd0   J. Bruce Fields   [PATCH] nfsd4: fi...
4105
  		if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4106
4107
  			status = 1;
  			goto out;
796dadfd0   J. Bruce Fields   [PATCH] nfsd4: fi...
4108
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4109
4110
  	}
  out:
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
4111
  	unlock_flocks();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4112
4113
  	return status;
  }
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
4114
  __be32
b591480bb   J.Bruce Fields   [PATCH] knfsd: nf...
4115
4116
4117
  nfsd4_release_lockowner(struct svc_rqst *rqstp,
  			struct nfsd4_compound_state *cstate,
  			struct nfsd4_release_lockowner *rlockowner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4118
4119
  {
  	clientid_t *clid = &rlockowner->rl_clientid;
3e9e3dbe0   NeilBrown   [PATCH] knfsd: nf...
4120
  	struct nfs4_stateowner *sop;
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
4121
  	struct nfs4_lockowner *lo;
dcef0413d   J. Bruce Fields   nfsd4: move some ...
4122
  	struct nfs4_ol_stateid *stp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4123
  	struct xdr_netobj *owner = &rlockowner->rl_owner;
3e9e3dbe0   NeilBrown   [PATCH] knfsd: nf...
4124
  	struct list_head matches;
16bfdaafa   J. Bruce Fields   nfsd4: share open...
4125
  	unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
4126
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4127
4128
4129
4130
4131
4132
4133
4134
  
  	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):
  ",
  		clid->cl_boot, clid->cl_id);
  
  	/* XXX check for lease expiration */
  
  	status = nfserr_stale_clientid;
849823c52   Neil Brown   [PATCH] nfsd4: pr...
4135
  	if (STALE_CLIENTID(clid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4136
  		return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4137
4138
  
  	nfs4_lock_state();
3e9e3dbe0   NeilBrown   [PATCH] knfsd: nf...
4139
  	status = nfserr_locks_held;
3e9e3dbe0   NeilBrown   [PATCH] knfsd: nf...
4140
  	INIT_LIST_HEAD(&matches);
06f1f864d   J. Bruce Fields   nfsd4: hash locko...
4141

16bfdaafa   J. Bruce Fields   nfsd4: share open...
4142
4143
4144
  	list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) {
  		if (sop->so_is_open_owner)
  			continue;
06f1f864d   J. Bruce Fields   nfsd4: hash locko...
4145
4146
4147
4148
4149
4150
4151
4152
  		if (!same_owner_str(sop, owner, clid))
  			continue;
  		list_for_each_entry(stp, &sop->so_stateids,
  				st_perstateowner) {
  			lo = lockowner(sop);
  			if (check_for_locks(stp->st_file, lo))
  				goto out;
  			list_add(&lo->lo_list, &matches);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4153
  		}
3e9e3dbe0   NeilBrown   [PATCH] knfsd: nf...
4154
4155
4156
4157
4158
  	}
  	/* Clients probably won't expect us to return with some (but not all)
  	 * of the lockowner state released; so don't release any until all
  	 * have been checked. */
  	status = nfs_ok;
0fa822e45   NeilBrown   [PATCH] nfsd4: fi...
4159
  	while (!list_empty(&matches)) {
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
4160
4161
  		lo = list_entry(matches.next, struct nfs4_lockowner,
  								lo_list);
0fa822e45   NeilBrown   [PATCH] nfsd4: fi...
4162
4163
  		/* unhash_stateowner deletes so_perclient only
  		 * for openowners. */
fe0750e5c   J. Bruce Fields   nfsd4: split stat...
4164
4165
  		list_del(&lo->lo_list);
  		release_lockowner(lo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4166
4167
4168
4169
4170
4171
4172
  	}
  out:
  	nfs4_unlock_state();
  	return status;
  }
  
  static inline struct nfs4_client_reclaim *
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4173
  alloc_reclaim(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4174
  {
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4175
  	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4176
  }
c7b9a4592   NeilBrown   [PATCH] knfsd: nf...
4177
  int
a1bcecd29   Andy Adamson   nfsd41: match cli...
4178
  nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
c7b9a4592   NeilBrown   [PATCH] knfsd: nf...
4179
4180
4181
  {
  	unsigned int strhashval = clientstr_hashval(name);
  	struct nfs4_client *clp;
e203d506b   J. Bruce Fields   nfsd4: fix mixed ...
4182
  	clp = find_confirmed_client_by_str(name, strhashval);
c7b9a4592   NeilBrown   [PATCH] knfsd: nf...
4183
4184
  	return clp ? 1 : 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4185
4186
4187
  /*
   * failure => all reset bets are off, nfserr_no_grace...
   */
190e4fbf9   NeilBrown   [PATCH] knfsd: nf...
4188
4189
  int
  nfs4_client_to_reclaim(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4190
4191
4192
  {
  	unsigned int strhashval;
  	struct nfs4_client_reclaim *crp = NULL;
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4193
4194
4195
  	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s
  ", HEXDIR_LEN, name);
  	crp = alloc_reclaim();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4196
4197
  	if (!crp)
  		return 0;
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4198
  	strhashval = clientstr_hashval(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4199
4200
  	INIT_LIST_HEAD(&crp->cr_strhash);
  	list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4201
  	memcpy(crp->cr_recdir, name, HEXDIR_LEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4202
4203
4204
4205
4206
4207
4208
4209
4210
  	reclaim_str_hashtbl_size++;
  	return 1;
  }
  
  static void
  nfs4_release_reclaim(void)
  {
  	struct nfs4_client_reclaim *crp = NULL;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4211
4212
4213
4214
4215
  	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
  		while (!list_empty(&reclaim_str_hashtbl[i])) {
  			crp = list_entry(reclaim_str_hashtbl[i].next,
  			                struct nfs4_client_reclaim, cr_strhash);
  			list_del(&crp->cr_strhash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4216
4217
4218
4219
4220
4221
4222
4223
4224
  			kfree(crp);
  			reclaim_str_hashtbl_size--;
  		}
  	}
  	BUG_ON(reclaim_str_hashtbl_size);
  }
  
  /*
   * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
fd39ca9a8   NeilBrown   [PATCH] knfsd: nf...
4225
  static struct nfs4_client_reclaim *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
  nfs4_find_reclaim_client(clientid_t *clid)
  {
  	unsigned int strhashval;
  	struct nfs4_client *clp;
  	struct nfs4_client_reclaim *crp = NULL;
  
  
  	/* find clientid in conf_id_hashtbl */
  	clp = find_confirmed_client(clid);
  	if (clp == NULL)
  		return NULL;
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4237
4238
4239
4240
  	dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s
  ",
  		            clp->cl_name.len, clp->cl_name.data,
  			    clp->cl_recdir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4241
4242
  
  	/* find clp->cl_name in reclaim_str_hashtbl */
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4243
  	strhashval = clientstr_hashval(clp->cl_recdir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4244
  	list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
a55370a3c   NeilBrown   [PATCH] knfsd: nf...
4245
  		if (same_name(crp->cr_recdir, clp->cl_recdir)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4246
4247
4248
4249
4250
4251
4252
4253
4254
  			return crp;
  		}
  	}
  	return NULL;
  }
  
  /*
  * Called from OPEN. Look for clientid in reclaim list.
  */
b37ad28bc   Al Viro   [PATCH] nfsd: nfs...
4255
  __be32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4256
4257
  nfs4_check_open_reclaim(clientid_t *clid)
  {
dfc835657   NeilBrown   [PATCH] knfsd: nf...
4258
  	return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4259
  }
65178db42   Bryan Schumaker   NFSD: Added fault...
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
  #ifdef CONFIG_NFSD_FAULT_INJECTION
  
  void nfsd_forget_clients(u64 num)
  {
  	struct nfs4_client *clp, *next;
  	int count = 0;
  
  	nfs4_lock_state();
  	list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
  		nfsd4_remove_clid_dir(clp);
  		expire_client(clp);
  		if (++count == num)
  			break;
  	}
  	nfs4_unlock_state();
  
  	printk(KERN_INFO "NFSD: Forgot %d clients", count);
  }
  
  static void release_lockowner_sop(struct nfs4_stateowner *sop)
  {
  	release_lockowner(lockowner(sop));
  }
  
  static void release_openowner_sop(struct nfs4_stateowner *sop)
  {
  	release_openowner(openowner(sop));
  }
353de31b8   J. Bruce Fields   nfsd4: fix CONFIG...
4288
  static int nfsd_release_n_owners(u64 num, bool is_open_owner,
65178db42   Bryan Schumaker   NFSD: Added fault...
4289
4290
4291
4292
  				void (*release_sop)(struct nfs4_stateowner *))
  {
  	int i, count = 0;
  	struct nfs4_stateowner *sop, *next;
16bfdaafa   J. Bruce Fields   nfsd4: share open...
4293
4294
4295
4296
  	for (i = 0; i < OWNER_HASH_SIZE; i++) {
  		list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) {
  			if (sop->so_is_open_owner != is_open_owner)
  				continue;
65178db42   Bryan Schumaker   NFSD: Added fault...
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
  			release_sop(sop);
  			if (++count == num)
  				return count;
  		}
  	}
  	return count;
  }
  
  void nfsd_forget_locks(u64 num)
  {
  	int count;
  
  	nfs4_lock_state();
16bfdaafa   J. Bruce Fields   nfsd4: share open...
4310
  	count = nfsd_release_n_owners(num, false, release_lockowner_sop);
65178db42   Bryan Schumaker   NFSD: Added fault...
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
  	nfs4_unlock_state();
  
  	printk(KERN_INFO "NFSD: Forgot %d locks", count);
  }
  
  void nfsd_forget_openowners(u64 num)
  {
  	int count;
  
  	nfs4_lock_state();
16bfdaafa   J. Bruce Fields   nfsd4: share open...
4321
  	count = nfsd_release_n_owners(num, true, release_openowner_sop);
65178db42   Bryan Schumaker   NFSD: Added fault...
4322
4323
4324
4325
4326
4327
4328
4329
  	nfs4_unlock_state();
  
  	printk(KERN_INFO "NFSD: Forgot %d open owners", count);
  }
  
  int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *))
  {
  	int i, count = 0;
2d3475c0a   Bryan Schumaker   NFSD: forget_dele...
4330
4331
  	struct nfs4_file *fp, *fnext;
  	struct nfs4_delegation *dp, *dnext;
65178db42   Bryan Schumaker   NFSD: Added fault...
4332
4333
  
  	for (i = 0; i < FILE_HASH_SIZE; i++) {
2d3475c0a   Bryan Schumaker   NFSD: forget_dele...
4334
4335
  		list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) {
  			list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) {
65178db42   Bryan Schumaker   NFSD: Added fault...
4336
4337
4338
4339
4340
4341
  				deleg_func(dp);
  				if (++count == num)
  					return count;
  			}
  		}
  	}
2d3475c0a   Bryan Schumaker   NFSD: forget_dele...
4342

65178db42   Bryan Schumaker   NFSD: Added fault...
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
  	return count;
  }
  
  void nfsd_forget_delegations(u64 num)
  {
  	unsigned int count;
  
  	nfs4_lock_state();
  	count = nfsd_process_n_delegations(num, unhash_delegation);
  	nfs4_unlock_state();
  
  	printk(KERN_INFO "NFSD: Forgot %d delegations", count);
  }
  
  void nfsd_recall_delegations(u64 num)
  {
  	unsigned int count;
  
  	nfs4_lock_state();
  	spin_lock(&recall_lock);
  	count = nfsd_process_n_delegations(num, nfsd_break_one_deleg);
  	spin_unlock(&recall_lock);
  	nfs4_unlock_state();
  
  	printk(KERN_INFO "NFSD: Recalled %d delegations", count);
  }
  
  #endif /* CONFIG_NFSD_FAULT_INJECTION */
ac4d8ff2a   NeilBrown   [PATCH] knfsd: nf...
4371
  /* initialization to perform at module load time: */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4372

720833960   Bryan Schumaker   NFSD: Call nfsd4_...
4373
  void
ac4d8ff2a   NeilBrown   [PATCH] knfsd: nf...
4374
  nfs4_state_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4375
  {
720833960   Bryan Schumaker   NFSD: Call nfsd4_...
4376
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4377

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4378
4379
4380
4381
4382
  	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
  		INIT_LIST_HEAD(&conf_id_hashtbl[i]);
  		INIT_LIST_HEAD(&conf_str_hashtbl[i]);
  		INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
  		INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
02cb2858d   Wang Chen   nfsd: nfs4_stat_i...
4383
  		INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4384
  	}
5282fd724   Marc Eshel   nfsd41: sessionid...
4385
4386
  	for (i = 0; i < SESSION_HASH_SIZE; i++)
  		INIT_LIST_HEAD(&sessionid_hashtbl[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4387
4388
4389
  	for (i = 0; i < FILE_HASH_SIZE; i++) {
  		INIT_LIST_HEAD(&file_hashtbl[i]);
  	}
16bfdaafa   J. Bruce Fields   nfsd4: share open...
4390
4391
  	for (i = 0; i < OWNER_HASH_SIZE; i++) {
  		INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4392
  	}
009673b43   J. Bruce Fields   nfsd4: add a sepa...
4393
4394
  	for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
  		INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4395
4396
4397
  	INIT_LIST_HEAD(&close_lru);
  	INIT_LIST_HEAD(&client_lru);
  	INIT_LIST_HEAD(&del_recall_lru);
ac4d8ff2a   NeilBrown   [PATCH] knfsd: nf...
4398
  	reclaim_str_hashtbl_size = 0;
ac4d8ff2a   NeilBrown   [PATCH] knfsd: nf...
4399
  }
190e4fbf9   NeilBrown   [PATCH] knfsd: nf...
4400
4401
4402
4403
  static void
  nfsd4_load_reboot_recovery_data(void)
  {
  	int status;
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
4404
  	nfs4_lock_state();
48483bf23   J. Bruce Fields   nfsd4: simplify r...
4405
  	nfsd4_init_recdir();
190e4fbf9   NeilBrown   [PATCH] knfsd: nf...
4406
  	status = nfsd4_recdir_load();
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
4407
  	nfs4_unlock_state();
190e4fbf9   NeilBrown   [PATCH] knfsd: nf...
4408
4409
4410
4411
  	if (status)
  		printk("NFSD: Failure reading reboot recovery data
  ");
  }
c2f1a551d   Meelap Shah   knfsd: nfsd4: var...
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
  /*
   * Since the lifetime of a delegation isn't limited to that of an open, a
   * client may quite reasonably hang on to a delegation as long as it has
   * the inode cached.  This becomes an obvious problem the first time a
   * client's inode cache approaches the size of the server's total memory.
   *
   * For now we avoid this problem by imposing a hard limit on the number
   * of delegations, which varies according to the server's memory size.
   */
  static void
  set_max_delegations(void)
  {
  	/*
  	 * Allow at most 4 delegations per megabyte of RAM.  Quick
  	 * estimates suggest that in the worst case (where every delegation
  	 * is for a different inode), a delegation could take about 1.5K,
  	 * giving a worst case usage of about 6% of memory.
  	 */
  	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
  }
ac4d8ff2a   NeilBrown   [PATCH] knfsd: nf...
4432
  /* initialization to perform when the nfsd service is started: */
29ab23cc5   J. Bruce Fields   nfsd4: allow nfs4...
4433
  static int
ac4d8ff2a   NeilBrown   [PATCH] knfsd: nf...
4434
4435
  __nfs4_state_start(void)
  {
b5a1a81e5   J. Bruce Fields   nfsd4: don't slee...
4436
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4437
  	boot_time = get_seconds();
af558e33b   J. Bruce Fields   nfsd: common grac...
4438
  	locks_start_grace(&nfsd4_manager);
9a8db97e7   Marc Eshel   knfsd: lockd: nfs...
4439
4440
  	printk(KERN_INFO "NFSD: starting %ld-second grace period
  ",
e46b498c8   J. Bruce Fields   nfsd4: simplify l...
4441
  	       nfsd4_grace);
b5a1a81e5   J. Bruce Fields   nfsd4: don't slee...
4442
4443
4444
  	ret = set_callback_cred();
  	if (ret)
  		return -ENOMEM;
58da282b7   NeilBrown   [PATCH] knfsd: nf...
4445
  	laundry_wq = create_singlethread_workqueue("nfsd4");
29ab23cc5   J. Bruce Fields   nfsd4: allow nfs4...
4446
4447
  	if (laundry_wq == NULL)
  		return -ENOMEM;
b5a1a81e5   J. Bruce Fields   nfsd4: don't slee...
4448
4449
4450
  	ret = nfsd4_create_callback_queue();
  	if (ret)
  		goto out_free_laundry;
e46b498c8   J. Bruce Fields   nfsd4: simplify l...
4451
  	queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ);
c2f1a551d   Meelap Shah   knfsd: nfsd4: var...
4452
  	set_max_delegations();
b5a1a81e5   J. Bruce Fields   nfsd4: don't slee...
4453
4454
4455
4456
  	return 0;
  out_free_laundry:
  	destroy_workqueue(laundry_wq);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4457
  }
29ab23cc5   J. Bruce Fields   nfsd4: allow nfs4...
4458
  int
76a3550ec   NeilBrown   [PATCH] knfsd: nf...
4459
  nfs4_state_start(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4460
  {
190e4fbf9   NeilBrown   [PATCH] knfsd: nf...
4461
  	nfsd4_load_reboot_recovery_data();
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
4462
  	return __nfs4_state_start();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4463
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4464
4465
4466
4467
4468
4469
  static void
  __nfs4_state_shutdown(void)
  {
  	int i;
  	struct nfs4_client *clp = NULL;
  	struct nfs4_delegation *dp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4470
  	struct list_head *pos, *next, reaplist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
  	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
  		while (!list_empty(&conf_id_hashtbl[i])) {
  			clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
  			expire_client(clp);
  		}
  		while (!list_empty(&unconf_str_hashtbl[i])) {
  			clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
  			expire_client(clp);
  		}
  	}
  	INIT_LIST_HEAD(&reaplist);
  	spin_lock(&recall_lock);
  	list_for_each_safe(pos, next, &del_recall_lru) {
  		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
  		list_move(&dp->dl_recall_lru, &reaplist);
  	}
  	spin_unlock(&recall_lock);
  	list_for_each_safe(pos, next, &reaplist) {
  		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4490
4491
  		unhash_delegation(dp);
  	}
190e4fbf9   NeilBrown   [PATCH] knfsd: nf...
4492
  	nfsd4_shutdown_recdir();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4493
4494
4495
4496
4497
  }
  
  void
  nfs4_state_shutdown(void)
  {
afe2c511f   Tejun Heo   workqueue: conver...
4498
  	cancel_delayed_work_sync(&laundromat_work);
5e8d5c294   NeilBrown   [PATCH] knfsd: nf...
4499
  	destroy_workqueue(laundry_wq);
2c5e76158   J. Bruce Fields   nfsd: clean up gr...
4500
  	locks_end_grace(&nfsd4_manager);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4501
4502
4503
  	nfs4_lock_state();
  	nfs4_release_reclaim();
  	__nfs4_state_shutdown();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4504
  	nfs4_unlock_state();
c3935e304   J. Bruce Fields   nfsd4: shut down ...
4505
  	nfsd4_destroy_callback_queue();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4506
  }