Blame view

fs/nfs/nfs4state.c 47.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
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
34
35
36
37
38
39
  /*
   *  fs/nfs/nfs4state.c
   *
   *  Client-side XDR for NFSv4.
   *
   *  Copyright (c) 2002 The Regents of the University of Michigan.
   *  All rights reserved.
   *
   *  Kendrick Smith <kmsmith@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.
   *
   * Implementation of the NFSv4 state model.  For the time being,
   * this is minimal, but will be made much more complex in a
   * subsequent patch.
   */
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
40
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  #include <linux/slab.h>
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
42
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  #include <linux/nfs_fs.h>
  #include <linux/nfs_idmap.h>
5043e900f   Trond Myklebust   NFS: Convert inst...
45
46
  #include <linux/kthread.h>
  #include <linux/module.h>
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
47
  #include <linux/random.h>
8c7597f6c   Randy Dunlap   nfs: include rate...
48
  #include <linux/ratelimit.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
  #include <linux/workqueue.h>
  #include <linux/bitops.h>
0aaaf5c42   Chuck Lever   NFS: Cache state ...
51
  #include <linux/jiffies.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
53
  #include "nfs4_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  #include "callback.h"
  #include "delegation.h"
24c8dbbb5   David Howells   NFS: Generalise t...
56
  #include "internal.h"
974cec8ca   Andy Adamson   NFS: client needs...
57
  #include "pnfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  
  #define OPENOWNER_POOL_SIZE	8
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
60
  const nfs4_stateid zero_stateid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  
  static LIST_HEAD(nfs4_clientid_list);
591d71cbd   Andy Adamson   nfs41: establish ...
63
  int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  {
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
65
66
67
68
  	struct nfs4_setclientid_res clid = {
  		.clientid = clp->cl_clientid,
  		.confirm = clp->cl_confirm,
  	};
f738f5170   Chuck Lever   NFS: Start PF_INE...
69
70
  	unsigned short port;
  	int status;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
71
72
  	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
  		goto do_confirm;
f738f5170   Chuck Lever   NFS: Start PF_INE...
73
74
75
  	port = nfs_callback_tcpport;
  	if (clp->cl_addr.ss_family == AF_INET6)
  		port = nfs_callback_tcpport6;
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
76
77
78
  	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
79
80
81
82
  	clp->cl_clientid = clid.clientid;
  	clp->cl_confirm = clid.confirm;
  	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  do_confirm:
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
83
84
85
  	status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
86
  	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
87
88
  	nfs4_schedule_state_renewal(clp);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  	return status;
  }
a7b721037   Andy Adamson   nfs41: introduce ...
91
  struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
92
93
  {
  	struct rpc_cred *cred = NULL;
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
94
95
  	if (clp->cl_machine_cred != NULL)
  		cred = get_rpccred(clp->cl_machine_cred);
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  	return cred;
  }
  
  static void nfs4_clear_machine_cred(struct nfs_client *clp)
  {
  	struct rpc_cred *cred;
  
  	spin_lock(&clp->cl_lock);
  	cred = clp->cl_machine_cred;
  	clp->cl_machine_cred = NULL;
  	spin_unlock(&clp->cl_lock);
  	if (cred != NULL)
  		put_rpccred(cred);
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
110
111
  static struct rpc_cred *
  nfs4_get_renew_cred_server_locked(struct nfs_server *server)
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
112
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
113
  	struct rpc_cred *cred = NULL;
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
114
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
115
  	struct rb_node *pos;
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
116

24d292b89   Chuck Lever   NFS: Move cl_stat...
117
118
119
120
  	for (pos = rb_first(&server->state_owners);
  	     pos != NULL;
  	     pos = rb_next(pos)) {
  		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
121
122
123
124
125
126
127
  		if (list_empty(&sp->so_states))
  			continue;
  		cred = get_rpccred(sp->so_cred);
  		break;
  	}
  	return cred;
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  /**
   * nfs4_get_renew_cred_locked - Acquire credential for a renew operation
   * @clp: client state handle
   *
   * Returns an rpc_cred with reference count bumped, or NULL.
   * Caller must hold clp->cl_lock.
   */
  struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
  {
  	struct rpc_cred *cred = NULL;
  	struct nfs_server *server;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
  		cred = nfs4_get_renew_cred_server_locked(server);
  		if (cred != NULL)
  			break;
  	}
  	rcu_read_unlock();
  	return cred;
  }
b4b82607f   Andy Adamson   nfs41: get_clid_c...
149
  #if defined(CONFIG_NFS_V4_1)
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
150
151
152
153
  static int nfs41_setup_state_renewal(struct nfs_client *clp)
  {
  	int status;
  	struct nfs_fsinfo fsinfo;
d6fb79d43   Andy Adamson   NFSv4.1: new flag...
154
155
156
157
  	if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
  		nfs4_schedule_state_renewal(clp);
  		return 0;
  	}
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
158
159
160
161
162
163
164
165
166
167
168
169
170
  	status = nfs4_proc_get_lease_time(clp, &fsinfo);
  	if (status == 0) {
  		/* Update lease time and schedule renewal */
  		spin_lock(&clp->cl_lock);
  		clp->cl_lease_time = fsinfo.lease_time * HZ;
  		clp->cl_last_renewal = jiffies;
  		spin_unlock(&clp->cl_lock);
  
  		nfs4_schedule_state_renewal(clp);
  	}
  
  	return status;
  }
42acd0218   Andy Adamson   NFS add session b...
171
172
173
174
175
  /*
   * Back channel returns NFS4ERR_DELAY for new requests when
   * NFS4_SESSION_DRAINING is set so there is no work to be done when draining
   * is ended.
   */
5601a00d6   Alexandros Batsakis   nfs: run state ma...
176
  static void nfs4_end_drain_session(struct nfs_client *clp)
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
177
  {
5601a00d6   Alexandros Batsakis   nfs: run state ma...
178
  	struct nfs4_session *ses = clp->cl_session;
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
179
  	int max_slots;
a2118c33a   Trond Myklebust   NFSv41: Don't sto...
180
181
182
  	if (ses == NULL)
  		return;
  	if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
183
184
185
186
187
188
189
190
191
192
193
194
195
  		spin_lock(&ses->fc_slot_table.slot_tbl_lock);
  		max_slots = ses->fc_slot_table.max_slots;
  		while (max_slots--) {
  			struct rpc_task *task;
  
  			task = rpc_wake_up_next(&ses->fc_slot_table.
  						slot_tbl_waitq);
  			if (!task)
  				break;
  			rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
  		}
  		spin_unlock(&ses->fc_slot_table.slot_tbl_lock);
  	}
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
196
  }
42acd0218   Andy Adamson   NFS add session b...
197
  static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
198
  {
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
199
  	spin_lock(&tbl->slot_tbl_lock);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
200
  	if (tbl->highest_used_slotid != -1) {
42acd0218   Andy Adamson   NFS add session b...
201
  		INIT_COMPLETION(tbl->complete);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
202
  		spin_unlock(&tbl->slot_tbl_lock);
42acd0218   Andy Adamson   NFS add session b...
203
  		return wait_for_completion_interruptible(&tbl->complete);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
204
205
206
207
  	}
  	spin_unlock(&tbl->slot_tbl_lock);
  	return 0;
  }
42acd0218   Andy Adamson   NFS add session b...
208
209
210
211
212
213
214
215
216
217
218
219
220
  static int nfs4_begin_drain_session(struct nfs_client *clp)
  {
  	struct nfs4_session *ses = clp->cl_session;
  	int ret = 0;
  
  	set_bit(NFS4_SESSION_DRAINING, &ses->session_state);
  	/* back channel */
  	ret = nfs4_wait_on_slot_tbl(&ses->bc_slot_table);
  	if (ret)
  		return ret;
  	/* fore channel */
  	return nfs4_wait_on_slot_tbl(&ses->fc_slot_table);
  }
4d643d1df   Andy Adamson   nfs41: add create...
221
222
223
  int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
  {
  	int status;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
224
225
  	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
  		goto do_confirm;
380454126   Trond Myklebust   NFSv4: Fix a regr...
226
  	nfs4_begin_drain_session(clp);
4d643d1df   Andy Adamson   nfs41: add create...
227
  	status = nfs4_proc_exchange_id(clp, cred);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
228
229
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
230
231
  	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  do_confirm:
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
232
233
234
  	status = nfs4_proc_create_session(clp);
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
235
  	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
236
237
238
  	nfs41_setup_state_renewal(clp);
  	nfs_mark_client_ready(clp, NFS_CS_READY);
  out:
4d643d1df   Andy Adamson   nfs41: add create...
239
240
  	return status;
  }
b4b82607f   Andy Adamson   nfs41: get_clid_c...
241
242
243
244
245
246
247
248
249
250
251
  struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
  {
  	struct rpc_cred *cred;
  
  	spin_lock(&clp->cl_lock);
  	cred = nfs4_get_machine_cred_locked(clp);
  	spin_unlock(&clp->cl_lock);
  	return cred;
  }
  
  #endif /* CONFIG_NFS_V4_1 */
24d292b89   Chuck Lever   NFS: Move cl_stat...
252
253
  static struct rpc_cred *
  nfs4_get_setclientid_cred_server(struct nfs_server *server)
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
254
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
255
256
  	struct nfs_client *clp = server->nfs_client;
  	struct rpc_cred *cred = NULL;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
257
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
258
  	struct rb_node *pos;
24d292b89   Chuck Lever   NFS: Move cl_stat...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  
  	spin_lock(&clp->cl_lock);
  	pos = rb_first(&server->state_owners);
  	if (pos != NULL) {
  		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
  		cred = get_rpccred(sp->so_cred);
  	}
  	spin_unlock(&clp->cl_lock);
  	return cred;
  }
  
  /**
   * nfs4_get_setclientid_cred - Acquire credential for a setclientid operation
   * @clp: client state handle
   *
   * Returns an rpc_cred with reference count bumped, or NULL.
   */
  struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
  {
  	struct nfs_server *server;
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
279
  	struct rpc_cred *cred;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
280

6dc9d57af   Trond Myklebust   NFSv4: Callers to...
281
282
  	spin_lock(&clp->cl_lock);
  	cred = nfs4_get_machine_cred_locked(clp);
24d292b89   Chuck Lever   NFS: Move cl_stat...
283
  	spin_unlock(&clp->cl_lock);
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
284
285
  	if (cred != NULL)
  		goto out;
24d292b89   Chuck Lever   NFS: Move cl_stat...
286
287
288
289
290
291
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
  		cred = nfs4_get_setclientid_cred_server(server);
  		if (cred != NULL)
  			break;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
292
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
293
  	rcu_read_unlock();
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
294
295
  out:
  	return cred;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
296
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
297
298
299
  static void nfs_alloc_unique_id_locked(struct rb_root *root,
  				       struct nfs_unique_id *new,
  				       __u64 minval, int maxbits)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  {
  	struct rb_node **p, *parent;
  	struct nfs_unique_id *pos;
  	__u64 mask = ~0ULL;
  
  	if (maxbits < 64)
  		mask = (1ULL << maxbits) - 1ULL;
  
  	/* Ensure distribution is more or less flat */
  	get_random_bytes(&new->id, sizeof(new->id));
  	new->id &= mask;
  	if (new->id < minval)
  		new->id += minval;
  retry:
  	p = &root->rb_node;
  	parent = NULL;
  
  	while (*p != NULL) {
  		parent = *p;
  		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
  
  		if (new->id < pos->id)
  			p = &(*p)->rb_left;
  		else if (new->id > pos->id)
  			p = &(*p)->rb_right;
  		else
  			goto id_exists;
  	}
  	rb_link_node(&new->rb_node, parent, p);
  	rb_insert_color(&new->rb_node, root);
  	return;
  id_exists:
  	for (;;) {
  		new->id++;
  		if (new->id < minval || (new->id & mask) != new->id) {
  			new->id = minval;
  			break;
  		}
  		parent = rb_next(parent);
  		if (parent == NULL)
  			break;
  		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
  		if (new->id < pos->id)
  			break;
  	}
  	goto retry;
  }
  
  static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id)
  {
  	rb_erase(&id->rb_node, root);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  static struct nfs4_state_owner *
24d292b89   Chuck Lever   NFS: Move cl_stat...
353
  nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
355
  	struct rb_node **p = &server->state_owners.rb_node,
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
356
  		       *parent = NULL;
414adf14c   Chuck Lever   NFS: Clean up nfs...
357
  	struct nfs4_state_owner *sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358

9f958ab88   Trond Myklebust   NFSv4: Reduce the...
359
360
  	while (*p != NULL) {
  		parent = *p;
24d292b89   Chuck Lever   NFS: Move cl_stat...
361
  		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
362
363
364
365
366
367
  
  		if (cred < sp->so_cred)
  			p = &parent->rb_left;
  		else if (cred > sp->so_cred)
  			p = &parent->rb_right;
  		else {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
368
369
  			if (!list_empty(&sp->so_lru))
  				list_del_init(&sp->so_lru);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
370
  			atomic_inc(&sp->so_count);
414adf14c   Chuck Lever   NFS: Clean up nfs...
371
  			return sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
372
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  	}
414adf14c   Chuck Lever   NFS: Clean up nfs...
374
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  }
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
376
  static struct nfs4_state_owner *
24d292b89   Chuck Lever   NFS: Move cl_stat...
377
  nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
378
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
379
380
  	struct nfs_server *server = new->so_server;
  	struct rb_node **p = &server->state_owners.rb_node,
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
381
382
383
384
385
  		       *parent = NULL;
  	struct nfs4_state_owner *sp;
  
  	while (*p != NULL) {
  		parent = *p;
24d292b89   Chuck Lever   NFS: Move cl_stat...
386
  		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
387
388
389
390
391
392
  
  		if (new->so_cred < sp->so_cred)
  			p = &parent->rb_left;
  		else if (new->so_cred > sp->so_cred)
  			p = &parent->rb_right;
  		else {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
393
394
  			if (!list_empty(&sp->so_lru))
  				list_del_init(&sp->so_lru);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
395
396
397
398
  			atomic_inc(&sp->so_count);
  			return sp;
  		}
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
399
400
401
402
  	nfs_alloc_unique_id_locked(&server->openowner_id,
  					&new->so_owner_id, 1, 64);
  	rb_link_node(&new->so_server_node, parent, p);
  	rb_insert_color(&new->so_server_node, &server->state_owners);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
403
404
405
406
  	return new;
  }
  
  static void
24d292b89   Chuck Lever   NFS: Move cl_stat...
407
  nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
408
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
409
410
411
412
413
  	struct nfs_server *server = sp->so_server;
  
  	if (!RB_EMPTY_NODE(&sp->so_server_node))
  		rb_erase(&sp->so_server_node, &server->state_owners);
  	nfs_free_unique_id(&server->openowner_id, &sp->so_owner_id);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
414
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
421
422
423
  /*
   * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
   * create a new state_owner.
   *
   */
  static struct nfs4_state_owner *
  nfs4_alloc_state_owner(void)
  {
  	struct nfs4_state_owner *sp;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
424
  	sp = kzalloc(sizeof(*sp),GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  	if (!sp)
  		return NULL;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
427
  	spin_lock_init(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  	INIT_LIST_HEAD(&sp->so_states);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
429
430
431
432
  	rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");
  	sp->so_seqid.sequence = &sp->so_sequence;
  	spin_lock_init(&sp->so_sequence.lock);
  	INIT_LIST_HEAD(&sp->so_sequence.list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  	atomic_set(&sp->so_count, 1);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
434
  	INIT_LIST_HEAD(&sp->so_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
  	return sp;
  }
1d2e88e73   Adrian Bunk   nfs: make nfs4_dr...
437
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  nfs4_drop_state_owner(struct nfs4_state_owner *sp)
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
440
441
442
  	if (!RB_EMPTY_NODE(&sp->so_server_node)) {
  		struct nfs_server *server = sp->so_server;
  		struct nfs_client *clp = server->nfs_client;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
443
444
  
  		spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
445
446
  		rb_erase(&sp->so_server_node, &server->state_owners);
  		RB_CLEAR_NODE(&sp->so_server_node);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
447
448
  		spin_unlock(&clp->cl_lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  }
0aaaf5c42   Chuck Lever   NFS: Cache state ...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
  {
  	rpc_destroy_wait_queue(&sp->so_sequence.wait);
  	put_rpccred(sp->so_cred);
  	kfree(sp);
  }
  
  static void nfs4_gc_state_owners(struct nfs_server *server)
  {
  	struct nfs_client *clp = server->nfs_client;
  	struct nfs4_state_owner *sp, *tmp;
  	unsigned long time_min, time_max;
  	LIST_HEAD(doomed);
  
  	spin_lock(&clp->cl_lock);
  	time_max = jiffies;
  	time_min = (long)time_max - (long)clp->cl_lease_time;
  	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
  		/* NB: LRU is sorted so that oldest is at the head */
  		if (time_in_range(sp->so_expires, time_min, time_max))
  			break;
  		list_move(&sp->so_lru, &doomed);
  		nfs4_remove_state_owner_locked(sp);
  	}
  	spin_unlock(&clp->cl_lock);
  
  	list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
  		list_del(&sp->so_lru);
  		nfs4_free_state_owner(sp);
  	}
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
481
482
483
484
485
486
487
488
489
  /**
   * nfs4_get_state_owner - Look up a state owner given a credential
   * @server: nfs_server to search
   * @cred: RPC credential to match
   *
   * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
   */
  struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
  					      struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  {
7539bbab8   David Howells   NFS: Rename nfs_s...
491
  	struct nfs_client *clp = server->nfs_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  	struct nfs4_state_owner *sp, *new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  	spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
494
  	sp = nfs4_find_state_owner_locked(server, cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  	spin_unlock(&clp->cl_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  	if (sp != NULL)
0aaaf5c42   Chuck Lever   NFS: Cache state ...
497
  		goto out;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
498
499
  	new = nfs4_alloc_state_owner();
  	if (new == NULL)
0aaaf5c42   Chuck Lever   NFS: Cache state ...
500
  		goto out;
6f2e64d3e   Trond Myklebust   NFSv4: Make the N...
501
  	new->so_server = server;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
502
503
  	new->so_cred = cred;
  	spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
504
  	sp = nfs4_insert_state_owner_locked(new);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
505
506
507
  	spin_unlock(&clp->cl_lock);
  	if (sp == new)
  		get_rpccred(cred);
f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
508
509
  	else {
  		rpc_destroy_wait_queue(&new->so_sequence.wait);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
510
  		kfree(new);
f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
511
  	}
0aaaf5c42   Chuck Lever   NFS: Cache state ...
512
513
  out:
  	nfs4_gc_state_owners(server);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
514
  	return sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
516
517
518
  /**
   * nfs4_put_state_owner - Release a nfs4_state_owner
   * @sp: state owner data to release
24d292b89   Chuck Lever   NFS: Move cl_stat...
519
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  void nfs4_put_state_owner(struct nfs4_state_owner *sp)
  {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
522
523
  	struct nfs_server *server = sp->so_server;
  	struct nfs_client *clp = server->nfs_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
  
  	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
  		return;
0aaaf5c42   Chuck Lever   NFS: Cache state ...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
  
  	if (!RB_EMPTY_NODE(&sp->so_server_node)) {
  		sp->so_expires = jiffies;
  		list_add_tail(&sp->so_lru, &server->state_owners_lru);
  		spin_unlock(&clp->cl_lock);
  	} else {
  		nfs4_remove_state_owner_locked(sp);
  		spin_unlock(&clp->cl_lock);
  		nfs4_free_state_owner(sp);
  	}
  }
  
  /**
   * nfs4_purge_state_owners - Release all cached state owners
   * @server: nfs_server with cached state owners to release
   *
   * Called at umount time.  Remaining state owners will be on
   * the LRU with ref count of zero.
   */
  void nfs4_purge_state_owners(struct nfs_server *server)
  {
  	struct nfs_client *clp = server->nfs_client;
  	struct nfs4_state_owner *sp, *tmp;
  	LIST_HEAD(doomed);
  
  	spin_lock(&clp->cl_lock);
  	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
  		list_move(&sp->so_lru, &doomed);
  		nfs4_remove_state_owner_locked(sp);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  	spin_unlock(&clp->cl_lock);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
558
559
560
561
562
  
  	list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
  		list_del(&sp->so_lru);
  		nfs4_free_state_owner(sp);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
567
568
  }
  
  static struct nfs4_state *
  nfs4_alloc_open_state(void)
  {
  	struct nfs4_state *state;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
569
  	state = kzalloc(sizeof(*state), GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
  	if (!state)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  	atomic_set(&state->count, 1);
  	INIT_LIST_HEAD(&state->lock_states);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
574
  	spin_lock_init(&state->state_lock);
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
575
  	seqlock_init(&state->seqlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
  	return state;
  }
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
578
  void
dc0b027df   Trond Myklebust   NFSv4: Convert th...
579
  nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
580
  {
dc0b027df   Trond Myklebust   NFSv4: Convert th...
581
  	if (state->state == fmode)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
582
583
  		return;
  	/* NB! List reordering - see the reclaim code for why.  */
dc0b027df   Trond Myklebust   NFSv4: Convert th...
584
585
  	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
  		if (fmode & FMODE_WRITE)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
586
587
588
589
  			list_move(&state->open_states, &state->owner->so_states);
  		else
  			list_move_tail(&state->open_states, &state->owner->so_states);
  	}
dc0b027df   Trond Myklebust   NFSv4: Convert th...
590
  	state->state = fmode;
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
591
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  static struct nfs4_state *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
598
  __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	struct nfs4_state *state;
  
  	list_for_each_entry(state, &nfsi->open_states, inode_states) {
1c816efa2   Trond Myklebust   NFSv4: Fix a bug ...
599
  		if (state->owner != owner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  			continue;
1c816efa2   Trond Myklebust   NFSv4: Fix a bug ...
601
  		if (atomic_inc_not_zero(&state->count))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  			return state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
  	}
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  static void
  nfs4_free_open_state(struct nfs4_state *state)
  {
  	kfree(state);
  }
  
  struct nfs4_state *
  nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
  {
  	struct nfs4_state *state, *new;
  	struct nfs_inode *nfsi = NFS_I(inode);
  
  	spin_lock(&inode->i_lock);
  	state = __nfs4_find_state_byowner(inode, owner);
  	spin_unlock(&inode->i_lock);
  	if (state)
  		goto out;
  	new = nfs4_alloc_open_state();
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
624
  	spin_lock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
  	spin_lock(&inode->i_lock);
  	state = __nfs4_find_state_byowner(inode, owner);
  	if (state == NULL && new != NULL) {
  		state = new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
631
  		state->owner = owner;
  		atomic_inc(&owner->so_count);
  		list_add(&state->inode_states, &nfsi->open_states);
0444d76ae   Dave Chinner   fs: don't use igr...
632
633
  		ihold(inode);
  		state->inode = inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
  		spin_unlock(&inode->i_lock);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
635
636
637
638
  		/* Note: The reclaim code dictates that we add stateless
  		 * and read-only stateids to the end of the list */
  		list_add_tail(&state->open_states, &owner->so_states);
  		spin_unlock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
  	} else {
  		spin_unlock(&inode->i_lock);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
641
  		spin_unlock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
644
645
646
647
  		if (new)
  			nfs4_free_open_state(new);
  	}
  out:
  	return state;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
  void nfs4_put_open_state(struct nfs4_state *state)
  {
  	struct inode *inode = state->inode;
  	struct nfs4_state_owner *owner = state->owner;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
652
  	if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  		return;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
654
  	spin_lock(&inode->i_lock);
ba683031f   Trond Myklebust   NFSv4: Fix a lock...
655
  	list_del(&state->inode_states);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  	list_del(&state->open_states);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
657
658
  	spin_unlock(&inode->i_lock);
  	spin_unlock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  	iput(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
663
664
  	nfs4_free_open_state(state);
  	nfs4_put_state_owner(owner);
  }
  
  /*
83c9d41e4   Trond Myklebust   NFSv4: Remove nfs...
665
   * Close the current file.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
   */
643168c2d   Al Viro   nfs4_closedata do...
667
  static void __nfs4_close(struct nfs4_state *state,
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
668
  		fmode_t fmode, gfp_t gfp_mask, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  	struct nfs4_state_owner *owner = state->owner;
003707c72   Trond Myklebust   NFSv4: Always use...
671
  	int call_close = 0;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
672
  	fmode_t newstate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  
  	atomic_inc(&owner->so_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  	/* Protect against nfs4_find_state() */
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
676
  	spin_lock(&owner->so_lock);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
677
  	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
678
679
680
681
682
683
684
685
686
  		case FMODE_READ:
  			state->n_rdonly--;
  			break;
  		case FMODE_WRITE:
  			state->n_wronly--;
  			break;
  		case FMODE_READ|FMODE_WRITE:
  			state->n_rdwr--;
  	}
003707c72   Trond Myklebust   NFSv4: Always use...
687
  	newstate = FMODE_READ|FMODE_WRITE;
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
688
  	if (state->n_rdwr == 0) {
003707c72   Trond Myklebust   NFSv4: Always use...
689
  		if (state->n_rdonly == 0) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
690
  			newstate &= ~FMODE_READ;
003707c72   Trond Myklebust   NFSv4: Always use...
691
692
693
694
  			call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
  			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
  		}
  		if (state->n_wronly == 0) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
695
  			newstate &= ~FMODE_WRITE;
003707c72   Trond Myklebust   NFSv4: Always use...
696
697
698
699
700
  			call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
  			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
  		}
  		if (newstate == 0)
  			clear_bit(NFS_DELEGATED_STATE, &state->flags);
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
701
  	}
003707c72   Trond Myklebust   NFSv4: Always use...
702
  	nfs4_state_set_mode_locked(state, newstate);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
703
  	spin_unlock(&owner->so_lock);
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
704

003707c72   Trond Myklebust   NFSv4: Always use...
705
  	if (!call_close) {
b39e625b6   Trond Myklebust   NFSv4: Clean up n...
706
707
  		nfs4_put_open_state(state);
  		nfs4_put_state_owner(owner);
f7e8917a6   Fred Isaman   pnfs: layout roc ...
708
709
  	} else {
  		bool roc = pnfs_roc(state->inode);
643168c2d   Al Viro   nfs4_closedata do...
710
  		nfs4_do_close(state, gfp_mask, wait, roc);
f7e8917a6   Fred Isaman   pnfs: layout roc ...
711
  	}
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
712
  }
643168c2d   Al Viro   nfs4_closedata do...
713
  void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
714
  {
643168c2d   Al Viro   nfs4_closedata do...
715
  	__nfs4_close(state, fmode, GFP_NOFS, 0);
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
716
  }
643168c2d   Al Viro   nfs4_closedata do...
717
  void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
718
  {
643168c2d   Al Viro   nfs4_closedata do...
719
  	__nfs4_close(state, fmode, GFP_KERNEL, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
  }
  
  /*
   * Search the state->lock_states for an existing lock_owner
   * that is compatible with current->files
   */
  static struct nfs4_lock_state *
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
727
  __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
  {
  	struct nfs4_lock_state *pos;
  	list_for_each_entry(pos, &state->lock_states, ls_locks) {
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
731
  		if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  			continue;
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
733
734
735
736
737
738
739
740
741
  		switch (pos->ls_owner.lo_type) {
  		case NFS4_POSIX_LOCK_TYPE:
  			if (pos->ls_owner.lo_u.posix_owner != fl_owner)
  				continue;
  			break;
  		case NFS4_FLOCK_LOCK_TYPE:
  			if (pos->ls_owner.lo_u.flock_owner != fl_pid)
  				continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
745
746
  		atomic_inc(&pos->ls_count);
  		return pos;
  	}
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
  /*
   * Return a compatible lock_state. If no initialized lock_state structure
   * exists, return an uninitialized one.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
   */
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
752
  static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
  {
  	struct nfs4_lock_state *lsp;
24d292b89   Chuck Lever   NFS: Move cl_stat...
755
756
  	struct nfs_server *server = state->owner->so_server;
  	struct nfs_client *clp = server->nfs_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757

8535b2be5   Trond Myklebust   NFSv4: Don't use ...
758
  	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
  	if (lsp == NULL)
  		return NULL;
d0dc3701c   Trond Myklebust   NFSv4: Give the l...
761
762
763
764
  	rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue");
  	spin_lock_init(&lsp->ls_sequence.lock);
  	INIT_LIST_HEAD(&lsp->ls_sequence.list);
  	lsp->ls_seqid.sequence = &lsp->ls_sequence;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  	atomic_set(&lsp->ls_count, 1);
b64aec8d1   Trond Myklebust   NFSv4: Fix an Oop...
766
  	lsp->ls_state = state;
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
767
768
769
770
771
772
773
774
775
776
777
778
  	lsp->ls_owner.lo_type = type;
  	switch (lsp->ls_owner.lo_type) {
  	case NFS4_FLOCK_LOCK_TYPE:
  		lsp->ls_owner.lo_u.flock_owner = fl_pid;
  		break;
  	case NFS4_POSIX_LOCK_TYPE:
  		lsp->ls_owner.lo_u.posix_owner = fl_owner;
  		break;
  	default:
  		kfree(lsp);
  		return NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  	spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
780
  	nfs_alloc_unique_id_locked(&server->lockowner_id, &lsp->ls_id, 1, 64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  	spin_unlock(&clp->cl_lock);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
782
  	INIT_LIST_HEAD(&lsp->ls_locks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  	return lsp;
  }
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
785
786
  static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
787
788
  	struct nfs_server *server = lsp->ls_state->owner->so_server;
  	struct nfs_client *clp = server->nfs_client;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
789
790
  
  	spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
791
  	nfs_free_unique_id(&server->lockowner_id, &lsp->ls_id);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
792
  	spin_unlock(&clp->cl_lock);
f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
793
  	rpc_destroy_wait_queue(&lsp->ls_sequence.wait);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
794
795
  	kfree(lsp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
  /*
   * Return a compatible lock_state. If no initialized lock_state structure
   * exists, return an uninitialized one.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
   */
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
801
  static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid, unsigned int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
803
  	struct nfs4_lock_state *lsp, *new = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  	
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
805
806
  	for(;;) {
  		spin_lock(&state->state_lock);
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
807
  		lsp = __nfs4_find_lock_state(state, owner, pid, type);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
808
809
810
  		if (lsp != NULL)
  			break;
  		if (new != NULL) {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
811
812
813
814
815
816
817
  			list_add(&new->ls_locks, &state->lock_states);
  			set_bit(LK_STATE_IN_USE, &state->flags);
  			lsp = new;
  			new = NULL;
  			break;
  		}
  		spin_unlock(&state->state_lock);
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
818
  		new = nfs4_alloc_lock_state(state, owner, pid, type);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
819
820
821
822
  		if (new == NULL)
  			return NULL;
  	}
  	spin_unlock(&state->state_lock);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
823
824
  	if (new != NULL)
  		nfs4_free_lock_state(new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
  	return lsp;
  }
  
  /*
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
829
830
   * Release reference to lock_state, and free it if we see that
   * it is no longer in use
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
   */
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
832
  void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
834
  	struct nfs4_state *state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
836
837
838
839
840
841
842
843
844
  	if (lsp == NULL)
  		return;
  	state = lsp->ls_state;
  	if (!atomic_dec_and_lock(&lsp->ls_count, &state->state_lock))
  		return;
  	list_del(&lsp->ls_locks);
  	if (list_empty(&state->lock_states))
  		clear_bit(LK_STATE_IN_USE, &state->flags);
  	spin_unlock(&state->state_lock);
d3c7b7ccc   Trond Myklebust   NFSv4: Add suppor...
845
846
  	if (lsp->ls_flags & NFS_LOCK_INITIALIZED)
  		nfs4_release_lockowner(lsp);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
847
  	nfs4_free_lock_state(lsp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  }
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
849
  static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
851
  	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
853
854
855
  	dst->fl_u.nfs4_fl.owner = lsp;
  	atomic_inc(&lsp->ls_count);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
857
  static void nfs4_fl_release_lock(struct file_lock *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
859
  	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
  }
6aed62853   Alexey Dobriyan   const: make file_...
861
  static const struct file_lock_operations nfs4_fl_lock_ops = {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
862
863
864
865
866
  	.fl_copy_lock = nfs4_fl_copy_lock,
  	.fl_release_private = nfs4_fl_release_lock,
  };
  
  int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
868
869
870
871
  	struct nfs4_lock_state *lsp;
  
  	if (fl->fl_ops != NULL)
  		return 0;
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
872
873
874
875
876
877
  	if (fl->fl_flags & FL_POSIX)
  		lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
  	else if (fl->fl_flags & FL_FLOCK)
  		lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE);
  	else
  		return -EINVAL;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
878
879
880
881
882
  	if (lsp == NULL)
  		return -ENOMEM;
  	fl->fl_u.nfs4_fl.owner = lsp;
  	fl->fl_ops = &nfs4_fl_lock_ops;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  }
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
884
885
886
  /*
   * Byte-range lock aware utility to initialize the stateid of read/write
   * requests.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
   */
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
888
  void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
890
  	struct nfs4_lock_state *lsp;
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
891
  	int seq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892

8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
893
894
895
896
  	do {
  		seq = read_seqbegin(&state->seqlock);
  		memcpy(dst, &state->stateid, sizeof(*dst));
  	} while (read_seqretry(&state->seqlock, seq));
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
897
898
  	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
900
  	spin_lock(&state->state_lock);
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
901
  	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
902
903
904
  	if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
  		memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
  	spin_unlock(&state->state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
  	nfs4_put_lock_state(lsp);
  }
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
907
  struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
cee54fc94   Trond Myklebust   NFSv4: Add functi...
908
  {
cee54fc94   Trond Myklebust   NFSv4: Add functi...
909
  	struct nfs_seqid *new;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
910
  	new = kmalloc(sizeof(*new), gfp_mask);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
911
912
  	if (new != NULL) {
  		new->sequence = counter;
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
913
  		INIT_LIST_HEAD(&new->list);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
914
915
916
  	}
  	return new;
  }
72211dbe7   Trond Myklebust   NFSv4: Release th...
917
  void nfs_release_seqid(struct nfs_seqid *seqid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
  {
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
919
920
  	if (!list_empty(&seqid->list)) {
  		struct rpc_sequence *sequence = seqid->sequence->sequence;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
921

2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
922
  		spin_lock(&sequence->lock);
72211dbe7   Trond Myklebust   NFSv4: Release th...
923
  		list_del_init(&seqid->list);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
924
925
926
  		spin_unlock(&sequence->lock);
  		rpc_wake_up(&sequence->wait);
  	}
72211dbe7   Trond Myklebust   NFSv4: Release th...
927
928
929
930
931
  }
  
  void nfs_free_seqid(struct nfs_seqid *seqid)
  {
  	nfs_release_seqid(seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
932
  	kfree(seqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
  }
  
  /*
cee54fc94   Trond Myklebust   NFSv4: Add functi...
936
937
938
939
   * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
   * failed with a seqid incrementing error -
   * see comments nfs_fs.h:seqid_mutating_error()
   */
88d909399   Trond Myklebust   NFSv4: nfs_increm...
940
  static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
cee54fc94   Trond Myklebust   NFSv4: Add functi...
941
  {
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
942
  	BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
943
944
945
946
  	switch (status) {
  		case 0:
  			break;
  		case -NFS4ERR_BAD_SEQID:
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
947
948
949
  			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
  				return;
  			printk(KERN_WARNING "NFS: v4 server returned a bad"
497799e7c   Dan Muntz   NFS: missing spac...
950
951
952
  					" sequence-id error on an"
  					" unconfirmed sequence %p!
  ",
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
953
  					seqid->sequence);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
  		case -NFS4ERR_STALE_CLIENTID:
  		case -NFS4ERR_STALE_STATEID:
  		case -NFS4ERR_BAD_STATEID:
  		case -NFS4ERR_BADXDR:
  		case -NFS4ERR_RESOURCE:
  		case -NFS4ERR_NOFILEHANDLE:
  			/* Non-seqid mutating errors */
  			return;
  	};
  	/*
  	 * Note: no locking needed as we are guaranteed to be first
  	 * on the sequence list
  	 */
  	seqid->sequence->counter++;
  }
  
  void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
  {
34dc1ad75   Benny Halevy   nfs41: increment_...
972
973
974
975
976
  	struct nfs4_state_owner *sp = container_of(seqid->sequence,
  					struct nfs4_state_owner, so_seqid);
  	struct nfs_server *server = sp->so_server;
  
  	if (status == -NFS4ERR_BAD_SEQID)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
  		nfs4_drop_state_owner(sp);
34dc1ad75   Benny Halevy   nfs41: increment_...
978
979
  	if (!nfs4_has_session(server->nfs_client))
  		nfs_increment_seqid(status, seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
980
981
982
  }
  
  /*
cee54fc94   Trond Myklebust   NFSv4: Add functi...
983
984
985
986
987
988
   * Increment the seqid if the LOCK/LOCKU succeeded, or
   * failed with a seqid incrementing error -
   * see comments nfs_fs.h:seqid_mutating_error()
   */
  void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
  {
88d909399   Trond Myklebust   NFSv4: nfs_increm...
989
  	nfs_increment_seqid(status, seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
990
991
992
993
994
995
996
997
  }
  
  int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
  {
  	struct rpc_sequence *sequence = seqid->sequence->sequence;
  	int status = 0;
  
  	spin_lock(&sequence->lock);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
998
999
1000
1001
  	if (list_empty(&seqid->list))
  		list_add_tail(&seqid->list, &sequence->list);
  	if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)
  		goto unlock;
5d00837b9   Trond Myklebust   SUNRPC: Run rpc t...
1002
  	rpc_sleep_on(&sequence->wait, task, NULL);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
1003
1004
  	status = -EAGAIN;
  unlock:
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1005
1006
  	spin_unlock(&sequence->lock);
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  }
e005e8041   Trond Myklebust   NFSv4: Rename the...
1008
  static int nfs4_run_state_manager(void *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009

e005e8041   Trond Myklebust   NFSv4: Rename the...
1010
  static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1011
1012
  {
  	smp_mb__before_clear_bit();
e005e8041   Trond Myklebust   NFSv4: Rename the...
1013
  	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1014
  	smp_mb__after_clear_bit();
e005e8041   Trond Myklebust   NFSv4: Rename the...
1015
  	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1016
1017
  	rpc_wake_up(&clp->cl_rpcwaitq);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
  /*
e005e8041   Trond Myklebust   NFSv4: Rename the...
1019
   * Schedule the nfs_client asynchronous state management routine
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
   */
b0d3ded1a   Trond Myklebust   NFSv4: Clean up n...
1021
  void nfs4_schedule_state_manager(struct nfs_client *clp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  {
5043e900f   Trond Myklebust   NFS: Convert inst...
1023
  	struct task_struct *task;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024

e005e8041   Trond Myklebust   NFSv4: Rename the...
1025
1026
  	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
  		return;
5043e900f   Trond Myklebust   NFS: Convert inst...
1027
1028
  	__module_get(THIS_MODULE);
  	atomic_inc(&clp->cl_count);
e005e8041   Trond Myklebust   NFSv4: Rename the...
1029
  	task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
5d8515cae   Chuck Lever   NFS: eliminate NI...
1030
1031
  				rpc_peeraddr2str(clp->cl_rpcclient,
  							RPC_DISPLAY_ADDR));
5043e900f   Trond Myklebust   NFS: Convert inst...
1032
1033
  	if (!IS_ERR(task))
  		return;
e005e8041   Trond Myklebust   NFSv4: Rename the...
1034
  	nfs4_clear_state_manager_bit(clp);
24c8dbbb5   David Howells   NFS: Generalise t...
1035
  	nfs_put_client(clp);
5043e900f   Trond Myklebust   NFS: Convert inst...
1036
  	module_put(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
  }
  
  /*
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1040
   * Schedule a lease recovery attempt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
   */
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1042
  void nfs4_schedule_lease_recovery(struct nfs_client *clp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
1045
  {
  	if (!clp)
  		return;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1046
1047
  	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
e005e8041   Trond Myklebust   NFSv4: Rename the...
1048
  	nfs4_schedule_state_manager(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
  }
042b60beb   Trond Myklebust   NFSv4: renewd nee...
1050
1051
1052
1053
1054
  void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
  {
  	nfs_handle_cb_pathdown(clp);
  	nfs4_schedule_state_manager(clp);
  }
f9feab1e1   Trond Myklebust   NFSv4: nfs4_state...
1055
  static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1056
1057
1058
1059
1060
1061
1062
1063
  {
  
  	set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
  	/* Don't recover state that expired before the reboot */
  	if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) {
  		clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
  		return 0;
  	}
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1064
  	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1065
1066
1067
  	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
  	return 1;
  }
f9feab1e1   Trond Myklebust   NFSv4: nfs4_state...
1068
  static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1069
1070
1071
  {
  	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
  	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1072
  	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1073
1074
1075
  	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
  	return 1;
  }
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1076
1077
1078
1079
1080
1081
1082
  void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
  {
  	struct nfs_client *clp = server->nfs_client;
  
  	nfs4_state_mark_reclaim_nograce(clp, state);
  	nfs4_schedule_state_manager(clp);
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1083
  static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
  {
  	struct inode *inode = state->inode;
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1086
  	struct nfs_inode *nfsi = NFS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
  	struct file_lock *fl;
  	int status = 0;
3f09df70e   Trond Myklebust   NFS: Ensure we al...
1089
1090
1091
1092
  	if (inode->i_flock == NULL)
  		return 0;
  
  	/* Guard against delegation returns and new lock/unlock calls */
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1093
  	down_write(&nfsi->rwsem);
3f09df70e   Trond Myklebust   NFS: Ensure we al...
1094
  	/* Protect inode->i_flock using the BKL */
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1095
  	lock_flocks();
90dc7d279   Harvey Harrison   nfs: fix sparse w...
1096
  	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
43b2a33aa   Trond Myklebust   NFSv4: Fix recove...
1097
  		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
  			continue;
cd3758e37   Trond Myklebust   NFS: Replace file...
1099
  		if (nfs_file_open_context(fl->fl_file)->state != state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  			continue;
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1101
  		unlock_flocks();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
  		status = ops->recover_lock(state, fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  		switch (status) {
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1104
1105
1106
1107
1108
1109
1110
1111
1112
  			case 0:
  				break;
  			case -ESTALE:
  			case -NFS4ERR_ADMIN_REVOKED:
  			case -NFS4ERR_STALE_STATEID:
  			case -NFS4ERR_BAD_STATEID:
  			case -NFS4ERR_EXPIRED:
  			case -NFS4ERR_NO_GRACE:
  			case -NFS4ERR_STALE_CLIENTID:
9c4c761a6   Trond Myklebust   NFSv4.1: Handle N...
1113
1114
1115
1116
  			case -NFS4ERR_BADSESSION:
  			case -NFS4ERR_BADSLOT:
  			case -NFS4ERR_BAD_HIGH_SLOT:
  			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1117
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
  			default:
  				printk(KERN_ERR "%s: unhandled error %d. Zeroing state
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
1121
  						__func__, status);
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1122
1123
  			case -ENOMEM:
  			case -NFS4ERR_DENIED:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
1125
  			case -NFS4ERR_RECLAIM_BAD:
  			case -NFS4ERR_RECLAIM_CONFLICT:
43b2a33aa   Trond Myklebust   NFSv4: Fix recove...
1126
  				/* kill_proc(fl->fl_pid, SIGLOST, 1); */
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1127
  				status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  		}
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1129
  		lock_flocks();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
  	}
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1131
  	unlock_flocks();
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1132
  out:
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1133
  	up_write(&nfsi->rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
  	return status;
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1136
  static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
  {
  	struct nfs4_state *state;
  	struct nfs4_lock_state *lock;
  	int status = 0;
  
  	/* Note: we rely on the sp->so_states list being ordered 
  	 * so that we always reclaim open(O_RDWR) and/or open(O_WRITE)
  	 * states first.
  	 * This is needed to ensure that the server won't give us any
  	 * read delegations that we have to return if, say, we are
  	 * recovering after a network partition or a reboot from a
  	 * server that doesn't support a grace period.
  	 */
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1150
1151
  restart:
  	spin_lock(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
  	list_for_each_entry(state, &sp->so_states, open_states) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1153
1154
  		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
  		if (state->state == 0)
  			continue;
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1157
1158
  		atomic_inc(&state->count);
  		spin_unlock(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  		status = ops->recover_open(sp, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  		if (status >= 0) {
028600143   Trond Myklebust   NFSv4: Clean up f...
1161
1162
  			status = nfs4_reclaim_locks(state, ops);
  			if (status >= 0) {
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1163
  				spin_lock(&state->state_lock);
028600143   Trond Myklebust   NFSv4: Clean up f...
1164
1165
1166
1167
  				list_for_each_entry(lock, &state->lock_states, ls_locks) {
  					if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
  						printk("%s: Lock reclaim failed!
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
1168
  							__func__);
028600143   Trond Myklebust   NFSv4: Clean up f...
1169
  				}
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1170
  				spin_unlock(&state->state_lock);
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1171
1172
  				nfs4_put_open_state(state);
  				goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
1177
1178
  		}
  		switch (status) {
  			default:
  				printk(KERN_ERR "%s: unhandled error %d. Zeroing state
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
1179
  						__func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  			case -ENOENT:
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1181
  			case -ENOMEM:
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1182
  			case -ESTALE:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
1184
1185
1186
1187
1188
1189
1190
1191
  				/*
  				 * Open state on this file cannot be recovered
  				 * All we can do is revert to using the zero stateid.
  				 */
  				memset(state->stateid.data, 0,
  					sizeof(state->stateid.data));
  				/* Mark the file as being 'closed' */
  				state->state = 0;
  				break;
168667c43   Trond Myklebust   NFSv4: The state ...
1192
1193
1194
1195
1196
1197
1198
1199
  			case -EKEYEXPIRED:
  				/*
  				 * User RPCSEC_GSS context has expired.
  				 * We cannot recover this stateid now, so
  				 * skip it and allow recovery thread to
  				 * proceed.
  				 */
  				break;
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1200
1201
1202
  			case -NFS4ERR_ADMIN_REVOKED:
  			case -NFS4ERR_STALE_STATEID:
  			case -NFS4ERR_BAD_STATEID:
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1203
1204
  			case -NFS4ERR_RECLAIM_BAD:
  			case -NFS4ERR_RECLAIM_CONFLICT:
1f0e890db   Trond Myklebust   NFSv4: Clean up s...
1205
  				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1206
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
  			case -NFS4ERR_EXPIRED:
  			case -NFS4ERR_NO_GRACE:
1f0e890db   Trond Myklebust   NFSv4: Clean up s...
1209
  				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
  			case -NFS4ERR_STALE_CLIENTID:
9c4c761a6   Trond Myklebust   NFSv4.1: Handle N...
1211
1212
1213
1214
  			case -NFS4ERR_BADSESSION:
  			case -NFS4ERR_BADSLOT:
  			case -NFS4ERR_BAD_HIGH_SLOT:
  			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
1216
  				goto out_err;
  		}
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1217
1218
  		nfs4_put_open_state(state);
  		goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
  	}
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1220
  	spin_unlock(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
  	return 0;
  out_err:
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1223
  	nfs4_put_open_state(state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
  	return status;
  }
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1226
1227
1228
1229
1230
1231
1232
1233
  static void nfs4_clear_open_state(struct nfs4_state *state)
  {
  	struct nfs4_lock_state *lock;
  
  	clear_bit(NFS_DELEGATED_STATE, &state->flags);
  	clear_bit(NFS_O_RDONLY_STATE, &state->flags);
  	clear_bit(NFS_O_WRONLY_STATE, &state->flags);
  	clear_bit(NFS_O_RDWR_STATE, &state->flags);
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1234
  	spin_lock(&state->state_lock);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1235
  	list_for_each_entry(lock, &state->lock_states, ls_locks) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1236
1237
1238
  		lock->ls_seqid.flags = 0;
  		lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
  	}
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1239
  	spin_unlock(&state->state_lock);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1240
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
1241
1242
  static void nfs4_reset_seqids(struct nfs_server *server,
  	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1243
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1244
  	struct nfs_client *clp = server->nfs_client;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1245
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
1246
  	struct rb_node *pos;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1247
  	struct nfs4_state *state;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1248

24d292b89   Chuck Lever   NFS: Move cl_stat...
1249
1250
1251
1252
1253
  	spin_lock(&clp->cl_lock);
  	for (pos = rb_first(&server->state_owners);
  	     pos != NULL;
  	     pos = rb_next(pos)) {
  		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1254
  		sp->so_seqid.flags = 0;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
1255
  		spin_lock(&sp->so_lock);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1256
  		list_for_each_entry(state, &sp->so_states, open_states) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1257
1258
  			if (mark_reclaim(clp, state))
  				nfs4_clear_open_state(state);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1259
  		}
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
1260
  		spin_unlock(&sp->so_lock);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1261
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
  	spin_unlock(&clp->cl_lock);
  }
  
  static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp,
  	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
  {
  	struct nfs_server *server;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
  		nfs4_reset_seqids(server, mark_reclaim);
  	rcu_read_unlock();
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1274
  }
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1275
1276
1277
1278
1279
1280
  static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
  {
  	/* Mark all delegations for reclaim */
  	nfs_delegation_mark_reclaim(clp);
  	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
  }
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
1281
1282
1283
1284
1285
1286
1287
  static void nfs4_reclaim_complete(struct nfs_client *clp,
  				 const struct nfs4_state_recovery_ops *ops)
  {
  	/* Notify the server we're done reclaiming our state */
  	if (ops->reclaim_complete)
  		(void)ops->reclaim_complete(clp);
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
1288
  static void nfs4_clear_reclaim_server(struct nfs_server *server)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1289
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1290
  	struct nfs_client *clp = server->nfs_client;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1291
1292
1293
  	struct nfs4_state_owner *sp;
  	struct rb_node *pos;
  	struct nfs4_state *state;
24d292b89   Chuck Lever   NFS: Move cl_stat...
1294
1295
1296
1297
1298
  	spin_lock(&clp->cl_lock);
  	for (pos = rb_first(&server->state_owners);
  	     pos != NULL;
  	     pos = rb_next(pos)) {
  		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1299
1300
  		spin_lock(&sp->so_lock);
  		list_for_each_entry(state, &sp->so_states, open_states) {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1301
1302
  			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT,
  						&state->flags))
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1303
1304
1305
1306
1307
  				continue;
  			nfs4_state_mark_reclaim_nograce(clp, state);
  		}
  		spin_unlock(&sp->so_lock);
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
  	spin_unlock(&clp->cl_lock);
  }
  
  static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp)
  {
  	struct nfs_server *server;
  
  	if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
  		return 0;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
  		nfs4_clear_reclaim_server(server);
  	rcu_read_unlock();
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1322
1323
  
  	nfs_delegation_reap_unclaimed(clp);
6eaa61496   Trond Myklebust   NFSv4: Don't call...
1324
1325
1326
1327
1328
1329
1330
1331
  	return 1;
  }
  
  static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
  {
  	if (!nfs4_state_clear_reclaim_reboot(clp))
  		return;
  	nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
  }
  
  static void nfs_delegation_clear_all(struct nfs_client *clp)
  {
  	nfs_delegation_mark_reclaim(clp);
  	nfs_delegation_reap_unclaimed(clp);
  }
  
  static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
  {
  	nfs_delegation_clear_all(clp);
  	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
  }
168667c43   Trond Myklebust   NFSv4: The state ...
1345
1346
1347
1348
1349
1350
1351
1352
  static void nfs4_warn_keyexpired(const char *s)
  {
  	printk_ratelimited(KERN_WARNING "Error: state manager"
  			" encountered RPCSEC_GSS session"
  			" expired against NFSv4 server %s.
  ",
  			s);
  }
4f7cdf18e   Trond Myklebust   NFSv4: The state ...
1353
  static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
e598d843c   Trond Myklebust   NFSv4: Remove red...
1354
1355
  {
  	switch (error) {
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1356
1357
  		case 0:
  			break;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1358
  		case -NFS4ERR_CB_PATH_DOWN:
707fb4b32   Trond Myklebust   NFSv4: Clean up N...
1359
  			nfs_handle_cb_pathdown(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1360
  			break;
c8b7ae3d3   Trond Myklebust   NFSv4: Ensure the...
1361
1362
  		case -NFS4ERR_NO_GRACE:
  			nfs4_state_end_reclaim_reboot(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1363
  			break;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1364
1365
1366
  		case -NFS4ERR_STALE_CLIENTID:
  		case -NFS4ERR_LEASE_MOVED:
  			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
6eaa61496   Trond Myklebust   NFSv4: Don't call...
1367
  			nfs4_state_clear_reclaim_reboot(clp);
e598d843c   Trond Myklebust   NFSv4: Remove red...
1368
1369
1370
1371
1372
  			nfs4_state_start_reclaim_reboot(clp);
  			break;
  		case -NFS4ERR_EXPIRED:
  			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
  			nfs4_state_start_reclaim_nograce(clp);
8ba9bf8e5   Andy Adamson   nfs41: fix switch...
1373
  			break;
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1374
1375
1376
1377
1378
1379
1380
  		case -NFS4ERR_BADSESSION:
  		case -NFS4ERR_BADSLOT:
  		case -NFS4ERR_BAD_HIGH_SLOT:
  		case -NFS4ERR_DEADSESSION:
  		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  		case -NFS4ERR_SEQ_FALSE_RETRY:
  		case -NFS4ERR_SEQ_MISORDERED:
6df08189f   Andy Adamson   nfs41: rename cl_...
1381
  			set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
0b9e2d41f   Andy Adamson   nfs41: only state...
1382
  			/* Zero session reset errors */
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1383
  			break;
168667c43   Trond Myklebust   NFSv4: The state ...
1384
1385
1386
  		case -EKEYEXPIRED:
  			/* Nothing we can do */
  			nfs4_warn_keyexpired(clp->cl_hostname);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1387
1388
1389
  			break;
  		default:
  			return error;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1390
  	}
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1391
  	return 0;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1392
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1393
  static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1395
1396
  	struct nfs4_state_owner *sp;
  	struct nfs_server *server;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
1397
  	struct rb_node *pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
  	int status = 0;
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1399
  restart:
24d292b89   Chuck Lever   NFS: Move cl_stat...
1400
1401
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
1402
  		nfs4_purge_state_owners(server);
24d292b89   Chuck Lever   NFS: Move cl_stat...
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
  		spin_lock(&clp->cl_lock);
  		for (pos = rb_first(&server->state_owners);
  		     pos != NULL;
  		     pos = rb_next(pos)) {
  			sp = rb_entry(pos,
  				struct nfs4_state_owner, so_server_node);
  			if (!test_and_clear_bit(ops->owner_flag_bit,
  							&sp->so_flags))
  				continue;
  			atomic_inc(&sp->so_count);
  			spin_unlock(&clp->cl_lock);
  			rcu_read_unlock();
  
  			status = nfs4_reclaim_open_state(sp, ops);
  			if (status < 0) {
  				set_bit(ops->owner_flag_bit, &sp->so_flags);
  				nfs4_put_state_owner(sp);
  				return nfs4_recovery_handle_error(clp, status);
  			}
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1422
  			nfs4_put_state_owner(sp);
24d292b89   Chuck Lever   NFS: Move cl_stat...
1423
  			goto restart;
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1424
  		}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1425
  		spin_unlock(&clp->cl_lock);
028600143   Trond Myklebust   NFSv4: Clean up f...
1426
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1427
  	rcu_read_unlock();
028600143   Trond Myklebust   NFSv4: Clean up f...
1428
1429
1430
1431
1432
1433
  	return status;
  }
  
  static int nfs4_check_lease(struct nfs_client *clp)
  {
  	struct rpc_cred *cred;
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1434
1435
  	const struct nfs4_state_maintenance_ops *ops =
  		clp->cl_mvops->state_renewal_ops;
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1436
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1437

0f605b560   Trond Myklebust   NFSv4: Don't tell...
1438
1439
1440
  	/* Is the client already known to have an expired lease? */
  	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  		return 0;
a7b721037   Andy Adamson   nfs41: introduce ...
1441
1442
1443
  	spin_lock(&clp->cl_lock);
  	cred = ops->get_state_renewal_cred_locked(clp);
  	spin_unlock(&clp->cl_lock);
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1444
1445
  	if (cred == NULL) {
  		cred = nfs4_get_setclientid_cred(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1446
  		status = -ENOKEY;
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1447
1448
  		if (cred == NULL)
  			goto out;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
1449
  	}
8e69514f2   Benny Halevy   nfs41: support mi...
1450
  	status = ops->renew_lease(clp, cred);
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1451
1452
  	put_rpccred(cred);
  out:
4f7cdf18e   Trond Myklebust   NFSv4: The state ...
1453
  	return nfs4_recovery_handle_error(clp, status);
028600143   Trond Myklebust   NFSv4: Clean up f...
1454
1455
1456
1457
1458
  }
  
  static int nfs4_reclaim_lease(struct nfs_client *clp)
  {
  	struct rpc_cred *cred;
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1459
1460
  	const struct nfs4_state_recovery_ops *ops =
  		clp->cl_mvops->reboot_recovery_ops;
028600143   Trond Myklebust   NFSv4: Clean up f...
1461
  	int status = -ENOENT;
90a16617e   Andy Adamson   nfs41: add a get_...
1462
  	cred = ops->get_clid_cred(clp);
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
1463
  	if (cred != NULL) {
591d71cbd   Andy Adamson   nfs41: establish ...
1464
  		status = ops->establish_clid(clp, cred);
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
1465
  		put_rpccred(cred);
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
1466
1467
1468
  		/* Handle case where the user hasn't set up machine creds */
  		if (status == -EACCES && cred == clp->cl_machine_cred) {
  			nfs4_clear_machine_cred(clp);
028600143   Trond Myklebust   NFSv4: Clean up f...
1469
  			status = -EAGAIN;
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
1470
  		}
c2e713dd8   Benny Halevy   nfs41: translate ...
1471
1472
  		if (status == -NFS4ERR_MINOR_VERS_MISMATCH)
  			status = -EPROTONOSUPPORT;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
1473
  	}
028600143   Trond Myklebust   NFSv4: Clean up f...
1474
1475
  	return status;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
1476
  #ifdef CONFIG_NFS_V4_1
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1477
1478
  void nfs4_schedule_session_recovery(struct nfs4_session *session)
  {
444f72fe7   Trond Myklebust   NFSv4.1: Fix the ...
1479
1480
1481
1482
  	struct nfs_client *clp = session->clp;
  
  	set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
  	nfs4_schedule_lease_recovery(clp);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1483
  }
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
1484
  EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1485

b9efa1b27   Andy Adamson   nfs41: implement ...
1486
1487
1488
  void nfs41_handle_recall_slot(struct nfs_client *clp)
  {
  	set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1489
  	nfs4_schedule_state_manager(clp);
b9efa1b27   Andy Adamson   nfs41: implement ...
1490
  }
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1491
1492
1493
1494
1495
  static void nfs4_reset_all_state(struct nfs_client *clp)
  {
  	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
  		clp->cl_boot_time = CURRENT_TIME;
  		nfs4_state_start_reclaim_nograce(clp);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1496
  		nfs4_schedule_state_manager(clp);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1497
1498
1499
1500
1501
1502
1503
  	}
  }
  
  static void nfs41_handle_server_reboot(struct nfs_client *clp)
  {
  	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
  		nfs4_state_start_reclaim_reboot(clp);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1504
  		nfs4_schedule_state_manager(clp);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
  	}
  }
  
  static void nfs41_handle_state_revoked(struct nfs_client *clp)
  {
  	/* Temporary */
  	nfs4_reset_all_state(clp);
  }
  
  static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
  {
  	/* This will need to handle layouts too */
  	nfs_expire_all_delegations(clp);
  }
  
  static void nfs41_handle_cb_path_down(struct nfs_client *clp)
  {
  	nfs_expire_all_delegations(clp);
  	if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0)
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1524
  		nfs4_schedule_state_manager(clp);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1525
  }
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
1526
1527
1528
1529
  void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
  {
  	if (!flags)
  		return;
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
1530
  	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1531
  		nfs41_handle_server_reboot(clp);
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
1532
  	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
1533
1534
  			    SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
  			    SEQ4_STATUS_ADMIN_STATE_REVOKED |
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1535
1536
  			    SEQ4_STATUS_LEASE_MOVED))
  		nfs41_handle_state_revoked(clp);
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
1537
  	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1538
  		nfs41_handle_recallable_state_revoked(clp);
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
1539
  	if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
1540
1541
  			    SEQ4_STATUS_BACKCHANNEL_FAULT |
  			    SEQ4_STATUS_CB_PATH_DOWN_SESSION))
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1542
  		nfs41_handle_cb_path_down(clp);
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
1543
  }
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1544
1545
1546
  static int nfs4_reset_session(struct nfs_client *clp)
  {
  	int status;
380454126   Trond Myklebust   NFSv4: Fix a regr...
1547
  	nfs4_begin_drain_session(clp);
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1548
1549
1550
  	status = nfs4_proc_destroy_session(clp->cl_session);
  	if (status && status != -NFS4ERR_BADSESSION &&
  	    status != -NFS4ERR_DEADSESSION) {
f455848a1   Ricardo Labiaga   nfs41: Mark state...
1551
  		status = nfs4_recovery_handle_error(clp, status);
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1552
1553
1554
1555
  		goto out;
  	}
  
  	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
f26468fb9   Trond Myklebust   NFSv41: Fix nfs4_...
1556
  	status = nfs4_proc_create_session(clp);
41f54a554   Andy Adamson   nfs41: clear NFS4...
1557
  	if (status) {
f455848a1   Ricardo Labiaga   nfs41: Mark state...
1558
  		status = nfs4_recovery_handle_error(clp, status);
41f54a554   Andy Adamson   nfs41: clear NFS4...
1559
1560
  		goto out;
  	}
444f72fe7   Trond Myklebust   NFSv4.1: Fix the ...
1561
  	clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
41f54a554   Andy Adamson   nfs41: clear NFS4...
1562
1563
  	/* create_session negotiated new slot table */
  	clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
1564

41f54a554   Andy Adamson   nfs41: clear NFS4...
1565
1566
  	 /* Let the state manager reestablish state */
  	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
5601a00d6   Alexandros Batsakis   nfs: run state ma...
1567
  		nfs41_setup_state_renewal(clp);
41f54a554   Andy Adamson   nfs41: clear NFS4...
1568
  out:
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1569
1570
  	return status;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
1571

b9efa1b27   Andy Adamson   nfs41: implement ...
1572
1573
1574
1575
1576
1577
1578
1579
1580
  static int nfs4_recall_slot(struct nfs_client *clp)
  {
  	struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table;
  	struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs;
  	struct nfs4_slot *new, *old;
  	int i;
  
  	nfs4_begin_drain_session(clp);
  	new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot),
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
1581
  		      GFP_NOFS);
b9efa1b27   Andy Adamson   nfs41: implement ...
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
          if (!new)
  		return -ENOMEM;
  
  	spin_lock(&fc_tbl->slot_tbl_lock);
  	for (i = 0; i < fc_tbl->target_max_slots; i++)
  		new[i].seq_nr = fc_tbl->slots[i].seq_nr;
  	old = fc_tbl->slots;
  	fc_tbl->slots = new;
  	fc_tbl->max_slots = fc_tbl->target_max_slots;
  	fc_tbl->target_max_slots = 0;
  	fc_attrs->max_reqs = fc_tbl->max_slots;
  	spin_unlock(&fc_tbl->slot_tbl_lock);
  
  	kfree(old);
  	nfs4_end_drain_session(clp);
  	return 0;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
1599
  #else /* CONFIG_NFS_V4_1 */
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1600
  static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
5601a00d6   Alexandros Batsakis   nfs: run state ma...
1601
  static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
b9efa1b27   Andy Adamson   nfs41: implement ...
1602
  static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
76db6d950   Andy Adamson   nfs41: add sessio...
1603
  #endif /* CONFIG_NFS_V4_1 */
78722e9c9   Andy Adamson   nfs41: only retry...
1604
1605
1606
1607
1608
  /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
   * on EXCHANGE_ID for v4.1
   */
  static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
  {
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
1609
1610
1611
1612
1613
1614
  	switch (status) {
  	case -NFS4ERR_CLID_INUSE:
  	case -NFS4ERR_STALE_CLIENTID:
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  		break;
  	case -NFS4ERR_DELAY:
1bd714f2a   Trond Myklebust   NFSv4: Ensure tha...
1615
  	case -ETIMEDOUT:
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
1616
1617
1618
  	case -EAGAIN:
  		ssleep(1);
  		break;
78722e9c9   Andy Adamson   nfs41: only retry...
1619

fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
1620
1621
1622
1623
1624
1625
  	case -EKEYEXPIRED:
  		nfs4_warn_keyexpired(clp->cl_hostname);
  	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
  				 * in nfs4_exchange_id */
  	default:
  		return;
78722e9c9   Andy Adamson   nfs41: only retry...
1626
1627
1628
  	}
  	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
  }
e005e8041   Trond Myklebust   NFSv4: Rename the...
1629
  static void nfs4_state_manager(struct nfs_client *clp)
028600143   Trond Myklebust   NFSv4: Clean up f...
1630
  {
028600143   Trond Myklebust   NFSv4: Clean up f...
1631
  	int status = 0;
028600143   Trond Myklebust   NFSv4: Clean up f...
1632
  	/* Ensure exclusive access to NFSv4 state */
47c2199b6   Trond Myklebust   NFSv4.1: Ensure s...
1633
  	do {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1634
1635
1636
1637
  		if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
  			/* We're going to have to re-establish a clientid */
  			status = nfs4_reclaim_lease(clp);
  			if (status) {
78722e9c9   Andy Adamson   nfs41: only retry...
1638
  				nfs4_set_lease_expired(clp, status);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1639
1640
  				if (test_bit(NFS4CLNT_LEASE_EXPIRED,
  							&clp->cl_state))
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1641
  					continue;
76db6d950   Andy Adamson   nfs41: add sessio...
1642
1643
1644
  				if (clp->cl_cons_state ==
  							NFS_CS_SESSION_INITING)
  					nfs_mark_client_ready(clp, status);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1645
1646
  				goto out_error;
  			}
e598d843c   Trond Myklebust   NFSv4: Remove red...
1647
  			clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
78fe0f41d   Weston Andros Adamson   NFS: use scope fr...
1648
1649
1650
1651
1652
1653
1654
  
  			if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH,
  					       &clp->cl_state))
  				nfs4_state_start_reclaim_nograce(clp);
  			else
  				set_bit(NFS4CLNT_RECLAIM_REBOOT,
  					&clp->cl_state);
974cec8ca   Andy Adamson   NFS: client needs...
1655
  			pnfs_destroy_all_layouts(clp);
e598d843c   Trond Myklebust   NFSv4: Remove red...
1656
1657
1658
1659
  		}
  
  		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
  			status = nfs4_check_lease(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1660
1661
  			if (status < 0)
  				goto out_error;
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1662
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
e598d843c   Trond Myklebust   NFSv4: Remove red...
1663
  				continue;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1664
  		}
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1665

c3fad1b1a   Andy Adamson   nfs41: add sessio...
1666
  		/* Initialize or reset the session */
6df08189f   Andy Adamson   nfs41: rename cl_...
1667
  		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)
7111dc739   Trond Myklebust   NFSv4: Fix an inf...
1668
  		   && nfs4_has_session(clp)) {
4d643d1df   Andy Adamson   nfs41: add create...
1669
  			status = nfs4_reset_session(clp);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1670
1671
1672
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  				continue;
  			if (status < 0)
76db6d950   Andy Adamson   nfs41: add sessio...
1673
  				goto out_error;
76db6d950   Andy Adamson   nfs41: add sessio...
1674
  		}
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1675

b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1676
  		/* First recover reboot state... */
e345e88a7   Trond Myklebust   NFSv4: Fix up the...
1677
  		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
591d71cbd   Andy Adamson   nfs41: establish ...
1678
  			status = nfs4_do_reclaim(clp,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1679
  				clp->cl_mvops->reboot_recovery_ops);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1680
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
6df08189f   Andy Adamson   nfs41: rename cl_...
1681
  			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1682
  				continue;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1683
  			nfs4_state_end_reclaim_reboot(clp);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1684
1685
1686
1687
  			if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
  				continue;
  			if (status < 0)
  				goto out_error;
028600143   Trond Myklebust   NFSv4: Clean up f...
1688
  		}
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1689
1690
  		/* Now recover expired state... */
  		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
591d71cbd   Andy Adamson   nfs41: establish ...
1691
  			status = nfs4_do_reclaim(clp,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1692
  				clp->cl_mvops->nograce_recovery_ops);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1693
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
6df08189f   Andy Adamson   nfs41: rename cl_...
1694
  			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
1695
1696
1697
  			    test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
  				continue;
  			if (status < 0)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1698
  				goto out_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699
  		}
707fb4b32   Trond Myklebust   NFSv4: Clean up N...
1700

5601a00d6   Alexandros Batsakis   nfs: run state ma...
1701
  		nfs4_end_drain_session(clp);
707fb4b32   Trond Myklebust   NFSv4: Clean up N...
1702
1703
1704
1705
  		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
  			nfs_client_return_marked_delegations(clp);
  			continue;
  		}
b9efa1b27   Andy Adamson   nfs41: implement ...
1706
1707
1708
1709
1710
1711
1712
1713
  		/* Recall session slots */
  		if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)
  		   && nfs4_has_session(clp)) {
  			status = nfs4_recall_slot(clp);
  			if (status < 0)
  				goto out_error;
  			continue;
  		}
e005e8041   Trond Myklebust   NFSv4: Rename the...
1714
1715
  
  		nfs4_clear_state_manager_bit(clp);
f3c76491e   Trond Myklebust   NFSv4: Don't exit...
1716
1717
1718
1719
1720
  		/* Did we race with an attempt to give us more work? */
  		if (clp->cl_state == 0)
  			break;
  		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
  			break;
47c2199b6   Trond Myklebust   NFSv4.1: Ensure s...
1721
  	} while (atomic_read(&clp->cl_count) > 1);
e005e8041   Trond Myklebust   NFSv4: Rename the...
1722
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1723
  out_error:
e005e8041   Trond Myklebust   NFSv4: Rename the...
1724
  	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
5d8515cae   Chuck Lever   NFS: eliminate NI...
1725
1726
  			" with error %d
  ", clp->cl_hostname, -status);
5601a00d6   Alexandros Batsakis   nfs: run state ma...
1727
  	nfs4_end_drain_session(clp);
e005e8041   Trond Myklebust   NFSv4: Rename the...
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
  	nfs4_clear_state_manager_bit(clp);
  }
  
  static int nfs4_run_state_manager(void *ptr)
  {
  	struct nfs_client *clp = ptr;
  
  	allow_signal(SIGKILL);
  	nfs4_state_manager(clp);
  	nfs_put_client(clp);
  	module_put_and_exit(0);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1740
1741
1742
1743
1744
1745
1746
  }
  
  /*
   * Local variables:
   *  c-basic-offset: 8
   * End:
   */