Blame view

fs/nfs/nfs4state.c 58.3 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

05f4c350e   Chuck Lever   NFS: Discover NFS...
53
  #include <linux/sunrpc/clnt.h>
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
54
  #include "nfs4_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  #include "callback.h"
  #include "delegation.h"
24c8dbbb5   David Howells   NFS: Generalise t...
57
  #include "internal.h"
974cec8ca   Andy Adamson   NFS: client needs...
58
  #include "pnfs.h"
bbe0a3aa4   Stanislav Kinsbursky   NFS: make nfs_cal...
59
  #include "netns.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

e3c0fb7ef   Chuck Lever   NFS: Add NFSDBG_S...
61
  #define NFSDBG_FACILITY		NFSDBG_STATE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  #define OPENOWNER_POOL_SIZE	8
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
63
  const nfs4_stateid zero_stateid;
05f4c350e   Chuck Lever   NFS: Discover NFS...
64
  static DEFINE_MUTEX(nfs_clid_init_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  static LIST_HEAD(nfs4_clientid_list);
591d71cbd   Andy Adamson   nfs41: establish ...
66
  int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  {
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
68
69
70
71
  	struct nfs4_setclientid_res clid = {
  		.clientid = clp->cl_clientid,
  		.confirm = clp->cl_confirm,
  	};
f738f5170   Chuck Lever   NFS: Start PF_INE...
72
73
  	unsigned short port;
  	int status;
bbe0a3aa4   Stanislav Kinsbursky   NFS: make nfs_cal...
74
  	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
f738f5170   Chuck Lever   NFS: Start PF_INE...
75

fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
76
77
  	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
  		goto do_confirm;
bbe0a3aa4   Stanislav Kinsbursky   NFS: make nfs_cal...
78
  	port = nn->nfs_callback_tcpport;
f738f5170   Chuck Lever   NFS: Start PF_INE...
79
  	if (clp->cl_addr.ss_family == AF_INET6)
29dcc16a8   Stanislav Kinsbursky   NFS: make nfs_cal...
80
  		port = nn->nfs_callback_tcpport6;
f738f5170   Chuck Lever   NFS: Start PF_INE...
81

bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
82
83
84
  	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
85
86
87
88
  	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...
89
90
91
  	status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
92
  	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
93
94
  	nfs4_schedule_state_renewal(clp);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
  	return status;
  }
05f4c350e   Chuck Lever   NFS: Discover NFS...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  /**
   * nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
   *
   * @clp: nfs_client under test
   * @result: OUT: found nfs_client, or clp
   * @cred: credential to use for trunking test
   *
   * Returns zero, a negative errno, or a negative NFS4ERR status.
   * If zero is returned, an nfs_client pointer is planted in
   * "result".
   *
   * Note: The returned client may not yet be marked ready.
   */
  int nfs40_discover_server_trunking(struct nfs_client *clp,
  				   struct nfs_client **result,
  				   struct rpc_cred *cred)
  {
  	struct nfs4_setclientid_res clid = {
  		.clientid = clp->cl_clientid,
  		.confirm = clp->cl_confirm,
  	};
9f62387d6   Trond Myklebust   NFSv4: Fix up a m...
118
  	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
05f4c350e   Chuck Lever   NFS: Discover NFS...
119
120
  	unsigned short port;
  	int status;
9f62387d6   Trond Myklebust   NFSv4: Fix up a m...
121
  	port = nn->nfs_callback_tcpport;
05f4c350e   Chuck Lever   NFS: Discover NFS...
122
  	if (clp->cl_addr.ss_family == AF_INET6)
9f62387d6   Trond Myklebust   NFSv4: Fix up a m...
123
  		port = nn->nfs_callback_tcpport6;
05f4c350e   Chuck Lever   NFS: Discover NFS...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  
  	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
  	if (status != 0)
  		goto out;
  	clp->cl_clientid = clid.clientid;
  	clp->cl_confirm = clid.confirm;
  
  	status = nfs40_walk_client_list(clp, result, cred);
  	switch (status) {
  	case -NFS4ERR_STALE_CLIENTID:
  		set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  	case 0:
  		/* Sustain the lease, even if it's empty.  If the clientid4
  		 * goes stale it's of no use for trunking discovery. */
  		nfs4_schedule_state_renewal(*result);
  		break;
  	}
  
  out:
  	return status;
  }
a7b721037   Andy Adamson   nfs41: introduce ...
145
  struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
146
147
  {
  	struct rpc_cred *cred = NULL;
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
148
149
  	if (clp->cl_machine_cred != NULL)
  		cred = get_rpccred(clp->cl_machine_cred);
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  	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...
164
165
  static struct rpc_cred *
  nfs4_get_renew_cred_server_locked(struct nfs_server *server)
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
166
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
167
  	struct rpc_cred *cred = NULL;
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
168
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
169
  	struct rb_node *pos;
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
170

24d292b89   Chuck Lever   NFS: Move cl_stat...
171
172
173
174
  	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...
175
176
177
178
179
180
181
  		if (list_empty(&sp->so_states))
  			continue;
  		cred = get_rpccred(sp->so_cred);
  		break;
  	}
  	return cred;
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
182
183
184
185
186
187
188
189
190
191
192
  /**
   * 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;
e49a29bd0   Sachin Prabhu   Try using machine...
193
194
195
196
  	/* Use machine credentials if available */
  	cred = nfs4_get_machine_cred_locked(clp);
  	if (cred != NULL)
  		goto out;
24d292b89   Chuck Lever   NFS: Move cl_stat...
197
198
199
200
201
202
203
  	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();
e49a29bd0   Sachin Prabhu   Try using machine...
204
205
  
  out:
24d292b89   Chuck Lever   NFS: Move cl_stat...
206
207
  	return cred;
  }
b4b82607f   Andy Adamson   nfs41: get_clid_c...
208
  #if defined(CONFIG_NFS_V4_1)
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
209
210
211
212
  static int nfs41_setup_state_renewal(struct nfs_client *clp)
  {
  	int status;
  	struct nfs_fsinfo fsinfo;
d6fb79d43   Andy Adamson   NFSv4.1: new flag...
213
214
215
216
  	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...
217
218
219
220
221
222
223
224
225
226
227
228
229
  	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...
230
231
232
233
234
  /*
   * 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...
235
  static void nfs4_end_drain_session(struct nfs_client *clp)
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
236
  {
5601a00d6   Alexandros Batsakis   nfs: run state ma...
237
  	struct nfs4_session *ses = clp->cl_session;
961a828df   Trond Myklebust   SUNRPC: Fix poten...
238
  	struct nfs4_slot_table *tbl;
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
239
  	int max_slots;
a2118c33a   Trond Myklebust   NFSv41: Don't sto...
240
241
  	if (ses == NULL)
  		return;
961a828df   Trond Myklebust   SUNRPC: Fix poten...
242
  	tbl = &ses->fc_slot_table;
a2118c33a   Trond Myklebust   NFSv41: Don't sto...
243
  	if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
961a828df   Trond Myklebust   SUNRPC: Fix poten...
244
245
  		spin_lock(&tbl->slot_tbl_lock);
  		max_slots = tbl->max_slots;
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
246
  		while (max_slots--) {
961a828df   Trond Myklebust   SUNRPC: Fix poten...
247
248
249
  			if (rpc_wake_up_first(&tbl->slot_tbl_waitq,
  						nfs4_set_task_privileged,
  						NULL) == NULL)
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
250
  				break;
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
251
  		}
961a828df   Trond Myklebust   SUNRPC: Fix poten...
252
  		spin_unlock(&tbl->slot_tbl_lock);
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
253
  	}
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
254
  }
42acd0218   Andy Adamson   NFS add session b...
255
  static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
256
  {
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
257
  	spin_lock(&tbl->slot_tbl_lock);
b6bf6e7d6   Andy Adamson   NFSv4.1 set highe...
258
  	if (tbl->highest_used_slotid != NFS4_NO_SLOT) {
42acd0218   Andy Adamson   NFS add session b...
259
  		INIT_COMPLETION(tbl->complete);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
260
  		spin_unlock(&tbl->slot_tbl_lock);
42acd0218   Andy Adamson   NFS add session b...
261
  		return wait_for_completion_interruptible(&tbl->complete);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
262
263
264
265
  	}
  	spin_unlock(&tbl->slot_tbl_lock);
  	return 0;
  }
42acd0218   Andy Adamson   NFS add session b...
266
267
268
269
270
271
272
273
274
275
276
277
278
  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);
  }
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
279
280
281
282
283
284
285
286
287
  static void nfs41_finish_session_reset(struct nfs_client *clp)
  {
  	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  	clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
  	/* create_session negotiated new slot table */
  	clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
  	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
  	nfs41_setup_state_renewal(clp);
  }
4d643d1df   Andy Adamson   nfs41: add create...
288
289
290
  int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
  {
  	int status;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
291
292
  	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
  		goto do_confirm;
380454126   Trond Myklebust   NFSv4: Fix a regr...
293
  	nfs4_begin_drain_session(clp);
4d643d1df   Andy Adamson   nfs41: add create...
294
  	status = nfs4_proc_exchange_id(clp, cred);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
295
296
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
297
298
  	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  do_confirm:
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
299
  	status = nfs4_proc_create_session(clp, cred);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
300
301
  	if (status != 0)
  		goto out;
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
302
  	nfs41_finish_session_reset(clp);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
303
304
  	nfs_mark_client_ready(clp, NFS_CS_READY);
  out:
4d643d1df   Andy Adamson   nfs41: add create...
305
306
  	return status;
  }
05f4c350e   Chuck Lever   NFS: Discover NFS...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
  /**
   * nfs41_discover_server_trunking - Detect server IP address trunking (mv1)
   *
   * @clp: nfs_client under test
   * @result: OUT: found nfs_client, or clp
   * @cred: credential to use for trunking test
   *
   * Returns NFS4_OK, a negative errno, or a negative NFS4ERR status.
   * If NFS4_OK is returned, an nfs_client pointer is planted in
   * "result".
   *
   * Note: The returned client may not yet be marked ready.
   */
  int nfs41_discover_server_trunking(struct nfs_client *clp,
  				   struct nfs_client **result,
  				   struct rpc_cred *cred)
  {
  	int status;
  
  	status = nfs4_proc_exchange_id(clp, cred);
  	if (status != NFS4_OK)
  		return status;
fd4835708   Weston Andros Adamson   NFSv4.1: don't do...
329
  	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
05f4c350e   Chuck Lever   NFS: Discover NFS...
330
331
332
  
  	return nfs41_walk_client_list(clp, result, cred);
  }
b4b82607f   Andy Adamson   nfs41: get_clid_c...
333
334
335
336
337
338
339
340
341
342
343
  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...
344
345
  static struct rpc_cred *
  nfs4_get_setclientid_cred_server(struct nfs_server *server)
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
346
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
347
348
  	struct nfs_client *clp = server->nfs_client;
  	struct rpc_cred *cred = NULL;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
349
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
350
  	struct rb_node *pos;
24d292b89   Chuck Lever   NFS: Move cl_stat...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
  
  	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...
371
  	struct rpc_cred *cred;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
372

6dc9d57af   Trond Myklebust   NFSv4: Callers to...
373
374
  	spin_lock(&clp->cl_lock);
  	cred = nfs4_get_machine_cred_locked(clp);
24d292b89   Chuck Lever   NFS: Move cl_stat...
375
  	spin_unlock(&clp->cl_lock);
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
376
377
  	if (cred != NULL)
  		goto out;
24d292b89   Chuck Lever   NFS: Move cl_stat...
378
379
380
381
382
383
  
  	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...
384
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
385
  	rcu_read_unlock();
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
386
387
  out:
  	return cred;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
388
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  static struct nfs4_state_owner *
24d292b89   Chuck Lever   NFS: Move cl_stat...
390
  nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
392
  	struct rb_node **p = &server->state_owners.rb_node,
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
393
  		       *parent = NULL;
414adf14c   Chuck Lever   NFS: Clean up nfs...
394
  	struct nfs4_state_owner *sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395

9f958ab88   Trond Myklebust   NFSv4: Reduce the...
396
397
  	while (*p != NULL) {
  		parent = *p;
24d292b89   Chuck Lever   NFS: Move cl_stat...
398
  		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
399
400
401
402
403
404
  
  		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 ...
405
406
  			if (!list_empty(&sp->so_lru))
  				list_del_init(&sp->so_lru);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
407
  			atomic_inc(&sp->so_count);
414adf14c   Chuck Lever   NFS: Clean up nfs...
408
  			return sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
409
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  	}
414adf14c   Chuck Lever   NFS: Clean up nfs...
411
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  }
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
413
  static struct nfs4_state_owner *
24d292b89   Chuck Lever   NFS: Move cl_stat...
414
  nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
415
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
416
417
  	struct nfs_server *server = new->so_server;
  	struct rb_node **p = &server->state_owners.rb_node,
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
418
419
  		       *parent = NULL;
  	struct nfs4_state_owner *sp;
9157c31dd   Trond Myklebust   NFSv4: Replace st...
420
  	int err;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
421
422
423
  
  	while (*p != NULL) {
  		parent = *p;
24d292b89   Chuck Lever   NFS: Move cl_stat...
424
  		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
425
426
427
428
429
430
  
  		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 ...
431
432
  			if (!list_empty(&sp->so_lru))
  				list_del_init(&sp->so_lru);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
433
434
435
436
  			atomic_inc(&sp->so_count);
  			return sp;
  		}
  	}
48c22eb21   Trond Myklebust   NFS: Move struct ...
437
  	err = ida_get_new(&server->openowner_id, &new->so_seqid.owner_id);
9157c31dd   Trond Myklebust   NFSv4: Replace st...
438
439
  	if (err)
  		return ERR_PTR(err);
24d292b89   Chuck Lever   NFS: Move cl_stat...
440
441
  	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...
442
443
444
445
  	return new;
  }
  
  static void
24d292b89   Chuck Lever   NFS: Move cl_stat...
446
  nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
447
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
448
449
450
451
  	struct nfs_server *server = sp->so_server;
  
  	if (!RB_EMPTY_NODE(&sp->so_server_node))
  		rb_erase(&sp->so_server_node, &server->state_owners);
48c22eb21   Trond Myklebust   NFS: Move struct ...
452
  	ida_remove(&server->openowner_id, sp->so_seqid.owner_id);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
453
  }
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
454
455
456
  static void
  nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
  {
95b72eb0b   Trond Myklebust   NFSv4: Ensure we ...
457
  	sc->create_time = ktime_get();
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
458
459
460
461
462
463
464
465
466
467
468
469
  	sc->flags = 0;
  	sc->counter = 0;
  	spin_lock_init(&sc->lock);
  	INIT_LIST_HEAD(&sc->list);
  	rpc_init_wait_queue(&sc->wait, "Seqid_waitqueue");
  }
  
  static void
  nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc)
  {
  	rpc_destroy_wait_queue(&sc->wait);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
  /*
   * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
   * create a new state_owner.
   *
   */
  static struct nfs4_state_owner *
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
476
477
478
  nfs4_alloc_state_owner(struct nfs_server *server,
  		struct rpc_cred *cred,
  		gfp_t gfp_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
  {
  	struct nfs4_state_owner *sp;
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
481
  	sp = kzalloc(sizeof(*sp), gfp_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  	if (!sp)
  		return NULL;
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
484
485
  	sp->so_server = server;
  	sp->so_cred = get_rpccred(cred);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
486
  	spin_lock_init(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  	INIT_LIST_HEAD(&sp->so_states);
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
488
  	nfs4_init_seqid_counter(&sp->so_seqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	atomic_set(&sp->so_count, 1);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
490
  	INIT_LIST_HEAD(&sp->so_lru);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
  	return sp;
  }
1d2e88e73   Adrian Bunk   nfs: make nfs4_dr...
493
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
  nfs4_drop_state_owner(struct nfs4_state_owner *sp)
  {
c77365c96   Trond Myklebust   NFSv4: Ensure tha...
496
497
498
  	struct rb_node *rb_node = &sp->so_server_node;
  
  	if (!RB_EMPTY_NODE(rb_node)) {
24d292b89   Chuck Lever   NFS: Move cl_stat...
499
500
  		struct nfs_server *server = sp->so_server;
  		struct nfs_client *clp = server->nfs_client;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
501
502
  
  		spin_lock(&clp->cl_lock);
c77365c96   Trond Myklebust   NFSv4: Ensure tha...
503
504
505
506
  		if (!RB_EMPTY_NODE(rb_node)) {
  			rb_erase(rb_node, &server->state_owners);
  			RB_CLEAR_NODE(rb_node);
  		}
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
507
508
  		spin_unlock(&clp->cl_lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  }
0aaaf5c42   Chuck Lever   NFS: Cache state ...
510
511
  static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
  {
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
512
  	nfs4_destroy_seqid_counter(&sp->so_seqid);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  	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...
541
542
543
544
545
546
547
548
  /**
   * 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,
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
549
550
  					      struct rpc_cred *cred,
  					      gfp_t gfp_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  {
7539bbab8   David Howells   NFS: Rename nfs_s...
552
  	struct nfs_client *clp = server->nfs_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	struct nfs4_state_owner *sp, *new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  	spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
555
  	sp = nfs4_find_state_owner_locked(server, cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  	spin_unlock(&clp->cl_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  	if (sp != NULL)
0aaaf5c42   Chuck Lever   NFS: Cache state ...
558
  		goto out;
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
559
  	new = nfs4_alloc_state_owner(server, cred, gfp_flags);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
560
  	if (new == NULL)
0aaaf5c42   Chuck Lever   NFS: Cache state ...
561
  		goto out;
9157c31dd   Trond Myklebust   NFSv4: Replace st...
562
563
564
565
566
567
568
  	do {
  		if (ida_pre_get(&server->openowner_id, gfp_flags) == 0)
  			break;
  		spin_lock(&clp->cl_lock);
  		sp = nfs4_insert_state_owner_locked(new);
  		spin_unlock(&clp->cl_lock);
  	} while (sp == ERR_PTR(-EAGAIN));
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
569
570
  	if (sp != new)
  		nfs4_free_state_owner(new);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
571
572
  out:
  	nfs4_gc_state_owners(server);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
573
  	return sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
575
576
577
  /**
   * nfs4_put_state_owner - Release a nfs4_state_owner
   * @sp: state owner data to release
7bf97bc27   Trond Myklebust   NFSv4: Keep dropp...
578
579
580
581
582
583
584
585
   *
   * Note that we keep released state owners on an LRU
   * list.
   * This caches valid state owners so that they can be
   * reused, to avoid the OPEN_CONFIRM on minor version 0.
   * It also pins the uniquifier of dropped state owners for
   * a while, to ensure that those state owner names are
   * never reused.
24d292b89   Chuck Lever   NFS: Move cl_stat...
586
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
  void nfs4_put_state_owner(struct nfs4_state_owner *sp)
  {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
589
590
  	struct nfs_server *server = sp->so_server;
  	struct nfs_client *clp = server->nfs_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
  
  	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
  		return;
0aaaf5c42   Chuck Lever   NFS: Cache state ...
594

7bf97bc27   Trond Myklebust   NFSv4: Keep dropp...
595
596
597
  	sp->so_expires = jiffies;
  	list_add_tail(&sp->so_lru, &server->state_owners_lru);
  	spin_unlock(&clp->cl_lock);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  }
  
  /**
   * 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
618
  	spin_unlock(&clp->cl_lock);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
619
620
621
622
623
  
  	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
624
625
626
627
628
629
  }
  
  static struct nfs4_state *
  nfs4_alloc_open_state(void)
  {
  	struct nfs4_state *state;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
630
  	state = kzalloc(sizeof(*state), GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
  	if (!state)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
  	atomic_set(&state->count, 1);
  	INIT_LIST_HEAD(&state->lock_states);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
635
  	spin_lock_init(&state->state_lock);
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
636
  	seqlock_init(&state->seqlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  	return state;
  }
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
639
  void
dc0b027df   Trond Myklebust   NFSv4: Convert th...
640
  nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
641
  {
dc0b027df   Trond Myklebust   NFSv4: Convert th...
642
  	if (state->state == fmode)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
643
644
  		return;
  	/* NB! List reordering - see the reclaim code for why.  */
dc0b027df   Trond Myklebust   NFSv4: Convert th...
645
646
  	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
  		if (fmode & FMODE_WRITE)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
647
648
649
650
  			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...
651
  	state->state = fmode;
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
652
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  static struct nfs4_state *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
659
  __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 ...
660
  		if (state->owner != owner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  			continue;
1c816efa2   Trond Myklebust   NFSv4: Fix a bug ...
662
  		if (atomic_inc_not_zero(&state->count))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  			return state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
  	}
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  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...
685
  	spin_lock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
  	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
690
691
692
  		state->owner = owner;
  		atomic_inc(&owner->so_count);
  		list_add(&state->inode_states, &nfsi->open_states);
0444d76ae   Dave Chinner   fs: don't use igr...
693
694
  		ihold(inode);
  		state->inode = inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  		spin_unlock(&inode->i_lock);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
696
697
698
699
  		/* 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
700
701
  	} else {
  		spin_unlock(&inode->i_lock);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
702
  		spin_unlock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
706
707
708
  		if (new)
  			nfs4_free_open_state(new);
  	}
  out:
  	return state;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
712
  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...
713
  	if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  		return;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
715
  	spin_lock(&inode->i_lock);
ba683031f   Trond Myklebust   NFSv4: Fix a lock...
716
  	list_del(&state->inode_states);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  	list_del(&state->open_states);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
718
719
  	spin_unlock(&inode->i_lock);
  	spin_unlock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  	iput(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
  	nfs4_free_open_state(state);
  	nfs4_put_state_owner(owner);
  }
  
  /*
83c9d41e4   Trond Myklebust   NFSv4: Remove nfs...
726
   * Close the current file.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
   */
643168c2d   Al Viro   nfs4_closedata do...
728
  static void __nfs4_close(struct nfs4_state *state,
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
729
  		fmode_t fmode, gfp_t gfp_mask, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
  	struct nfs4_state_owner *owner = state->owner;
003707c72   Trond Myklebust   NFSv4: Always use...
732
  	int call_close = 0;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
733
  	fmode_t newstate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
  
  	atomic_inc(&owner->so_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
  	/* Protect against nfs4_find_state() */
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
737
  	spin_lock(&owner->so_lock);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
738
  	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
739
740
741
742
743
744
745
746
747
  		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...
748
  	newstate = FMODE_READ|FMODE_WRITE;
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
749
  	if (state->n_rdwr == 0) {
003707c72   Trond Myklebust   NFSv4: Always use...
750
  		if (state->n_rdonly == 0) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
751
  			newstate &= ~FMODE_READ;
003707c72   Trond Myklebust   NFSv4: Always use...
752
753
754
755
  			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_...
756
  			newstate &= ~FMODE_WRITE;
003707c72   Trond Myklebust   NFSv4: Always use...
757
758
759
760
761
  			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_...
762
  	}
003707c72   Trond Myklebust   NFSv4: Always use...
763
  	nfs4_state_set_mode_locked(state, newstate);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
764
  	spin_unlock(&owner->so_lock);
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
765

003707c72   Trond Myklebust   NFSv4: Always use...
766
  	if (!call_close) {
b39e625b6   Trond Myklebust   NFSv4: Clean up n...
767
768
  		nfs4_put_open_state(state);
  		nfs4_put_state_owner(owner);
1f7977c13   Trond Myklebust   NFSv4.1: Simplify...
769
770
  	} else
  		nfs4_do_close(state, gfp_mask, wait);
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
771
  }
643168c2d   Al Viro   nfs4_closedata do...
772
  void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
773
  {
643168c2d   Al Viro   nfs4_closedata do...
774
  	__nfs4_close(state, fmode, GFP_NOFS, 0);
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
775
  }
643168c2d   Al Viro   nfs4_closedata do...
776
  void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
777
  {
643168c2d   Al Viro   nfs4_closedata do...
778
  	__nfs4_close(state, fmode, GFP_KERNEL, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
783
784
785
  }
  
  /*
   * 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...
786
  __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
787
788
789
  {
  	struct nfs4_lock_state *pos;
  	list_for_each_entry(pos, &state->lock_states, ls_locks) {
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
790
  		if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
  			continue;
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
792
793
794
795
796
797
798
799
800
  		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
801
802
803
804
805
  		atomic_inc(&pos->ls_count);
  		return pos;
  	}
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
  /*
   * Return a compatible lock_state. If no initialized lock_state structure
   * exists, return an uninitialized one.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
   */
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
811
  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
812
813
  {
  	struct nfs4_lock_state *lsp;
24d292b89   Chuck Lever   NFS: Move cl_stat...
814
  	struct nfs_server *server = state->owner->so_server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815

8535b2be5   Trond Myklebust   NFSv4: Don't use ...
816
  	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
  	if (lsp == NULL)
  		return NULL;
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
819
  	nfs4_init_seqid_counter(&lsp->ls_seqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
  	atomic_set(&lsp->ls_count, 1);
b64aec8d1   Trond Myklebust   NFSv4: Fix an Oop...
821
  	lsp->ls_state = state;
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
822
823
824
825
826
827
828
829
830
  	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:
d2d7ce28a   Trond Myklebust   NFSv4: Replace lo...
831
  		goto out_free;
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
832
  	}
48c22eb21   Trond Myklebust   NFS: Move struct ...
833
834
  	lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
  	if (lsp->ls_seqid.owner_id < 0)
d2d7ce28a   Trond Myklebust   NFSv4: Replace lo...
835
  		goto out_free;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
836
  	INIT_LIST_HEAD(&lsp->ls_locks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  	return lsp;
d2d7ce28a   Trond Myklebust   NFSv4: Replace lo...
838
839
840
  out_free:
  	kfree(lsp);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  }
5ae67c4fe   Trond Myklebust   NFSv4: It is not ...
842
  void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
843
  {
48c22eb21   Trond Myklebust   NFS: Move struct ...
844
  	ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id);
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
845
  	nfs4_destroy_seqid_counter(&lsp->ls_seqid);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
846
847
  	kfree(lsp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
851
  /*
   * Return a compatible lock_state. If no initialized lock_state structure
   * exists, return an uninitialized one.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
   */
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
853
  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
854
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
855
  	struct nfs4_lock_state *lsp, *new = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  	
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
857
858
  	for(;;) {
  		spin_lock(&state->state_lock);
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
859
  		lsp = __nfs4_find_lock_state(state, owner, pid, type);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
860
861
862
  		if (lsp != NULL)
  			break;
  		if (new != NULL) {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
863
864
865
866
867
868
869
  			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...
870
  		new = nfs4_alloc_lock_state(state, owner, pid, type);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
871
872
873
874
  		if (new == NULL)
  			return NULL;
  	}
  	spin_unlock(&state->state_lock);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
875
  	if (new != NULL)
5ae67c4fe   Trond Myklebust   NFSv4: It is not ...
876
  		nfs4_free_lock_state(state->owner->so_server, new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
879
880
  	return lsp;
  }
  
  /*
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
881
882
   * 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
883
   */
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
884
  void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
886
  	struct nfs4_state *state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
888
889
890
891
892
893
894
895
896
  	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);
795a88c96   Trond Myklebust   NFSv4: Convert th...
897
  	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
cf470c3e0   Trond Myklebust   NFSv4: Don't free...
898
899
900
  		if (nfs4_release_lockowner(lsp) == 0)
  			return;
  	}
5ae67c4fe   Trond Myklebust   NFSv4: It is not ...
901
  	nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
  }
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
903
  static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
905
  	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906

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

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
911
  static void nfs4_fl_release_lock(struct file_lock *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
913
  	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
  }
6aed62853   Alexey Dobriyan   const: make file_...
915
  static const struct file_lock_operations nfs4_fl_lock_ops = {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
916
917
918
919
920
  	.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
921
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
922
923
924
925
  	struct nfs4_lock_state *lsp;
  
  	if (fl->fl_ops != NULL)
  		return 0;
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
926
927
928
  	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)
17280175c   Trond Myklebust   NFS: Fix a number...
929
930
  		lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid,
  				NFS4_FLOCK_LOCK_TYPE);
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
931
932
  	else
  		return -EINVAL;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
933
934
935
936
937
  	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
938
  }
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
939
  static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
2a369153c   Trond Myklebust   NFS: Clean up hel...
940
  		const struct nfs_lockowner *lockowner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
942
  	struct nfs4_lock_state *lsp;
2a369153c   Trond Myklebust   NFS: Clean up hel...
943
944
  	fl_owner_t fl_owner;
  	pid_t fl_pid;
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
945
  	bool ret = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946

2a369153c   Trond Myklebust   NFS: Clean up hel...
947
948
949
  
  	if (lockowner == NULL)
  		goto out;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
950
  	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
951
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952

2a369153c   Trond Myklebust   NFS: Clean up hel...
953
954
  	fl_owner = lockowner->l_owner;
  	fl_pid = lockowner->l_pid;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
955
  	spin_lock(&state->state_lock);
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
956
  	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
795a88c96   Trond Myklebust   NFSv4: Convert th...
957
  	if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
f597c5379   Trond Myklebust   NFSv4: Add helper...
958
  		nfs4_stateid_copy(dst, &lsp->ls_stateid);
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
959
960
  		ret = true;
  	}
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
961
  	spin_unlock(&state->state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
  	nfs4_put_lock_state(lsp);
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
  out:
  	return ret;
  }
  
  static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
  {
  	int seq;
  
  	do {
  		seq = read_seqbegin(&state->seqlock);
  		nfs4_stateid_copy(dst, &state->stateid);
  	} while (read_seqretry(&state->seqlock, seq));
  }
  
  /*
   * Byte-range lock aware utility to initialize the stateid of read/write
   * requests.
   */
  void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
2a369153c   Trond Myklebust   NFS: Clean up hel...
982
  		fmode_t fmode, const struct nfs_lockowner *lockowner)
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
983
984
985
  {
  	if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
  		return;
2a369153c   Trond Myklebust   NFS: Clean up hel...
986
  	if (nfs4_copy_lock_stateid(dst, state, lockowner))
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
987
988
  		return;
  	nfs4_copy_open_stateid(dst, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  }
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
990
  struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
cee54fc94   Trond Myklebust   NFSv4: Add functi...
991
  {
cee54fc94   Trond Myklebust   NFSv4: Add functi...
992
  	struct nfs_seqid *new;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
993
  	new = kmalloc(sizeof(*new), gfp_mask);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
994
995
  	if (new != NULL) {
  		new->sequence = counter;
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
996
  		INIT_LIST_HEAD(&new->list);
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
997
  		new->task = NULL;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
998
999
1000
  	}
  	return new;
  }
72211dbe7   Trond Myklebust   NFSv4: Release th...
1001
  void nfs_release_seqid(struct nfs_seqid *seqid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
  {
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1003
  	struct nfs_seqid_counter *sequence;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1004

4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  	if (list_empty(&seqid->list))
  		return;
  	sequence = seqid->sequence;
  	spin_lock(&sequence->lock);
  	list_del_init(&seqid->list);
  	if (!list_empty(&sequence->list)) {
  		struct nfs_seqid *next;
  
  		next = list_first_entry(&sequence->list,
  				struct nfs_seqid, list);
  		rpc_wake_up_queued_task(&sequence->wait, next->task);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
1016
  	}
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1017
  	spin_unlock(&sequence->lock);
72211dbe7   Trond Myklebust   NFSv4: Release th...
1018
1019
1020
1021
1022
  }
  
  void nfs_free_seqid(struct nfs_seqid *seqid)
  {
  	nfs_release_seqid(seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1023
  	kfree(seqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
1026
  }
  
  /*
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1027
1028
1029
1030
   * 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...
1031
  static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1032
  {
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
1033
  	BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1034
1035
1036
1037
  	switch (status) {
  		case 0:
  			break;
  		case -NFS4ERR_BAD_SEQID:
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
1038
1039
  			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
  				return;
9a3ba4323   Trond Myklebust   NFSv4: Rate limit...
1040
  			pr_warn_ratelimited("NFS: v4 server returned a bad"
497799e7c   Dan Muntz   NFS: missing spac...
1041
1042
1043
  					" sequence-id error on an"
  					" unconfirmed sequence %p!
  ",
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
1044
  					seqid->sequence);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  		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_...
1063
1064
1065
1066
1067
  	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
1068
  		nfs4_drop_state_owner(sp);
34dc1ad75   Benny Halevy   nfs41: increment_...
1069
1070
  	if (!nfs4_has_session(server->nfs_client))
  		nfs_increment_seqid(status, seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1071
1072
1073
  }
  
  /*
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1074
1075
1076
1077
1078
1079
   * 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...
1080
  	nfs_increment_seqid(status, seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1081
1082
1083
1084
  }
  
  int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
  {
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
1085
  	struct nfs_seqid_counter *sequence = seqid->sequence;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1086
1087
1088
  	int status = 0;
  
  	spin_lock(&sequence->lock);
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1089
  	seqid->task = task;
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
1090
1091
1092
1093
  	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...
1094
  	rpc_sleep_on(&sequence->wait, task, NULL);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
1095
1096
  	status = -EAGAIN;
  unlock:
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1097
1098
  	spin_unlock(&sequence->lock);
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
  }
e005e8041   Trond Myklebust   NFSv4: Rename the...
1100
  static int nfs4_run_state_manager(void *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101

e005e8041   Trond Myklebust   NFSv4: Rename the...
1102
  static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1103
1104
  {
  	smp_mb__before_clear_bit();
e005e8041   Trond Myklebust   NFSv4: Rename the...
1105
  	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1106
  	smp_mb__after_clear_bit();
e005e8041   Trond Myklebust   NFSv4: Rename the...
1107
  	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1108
1109
  	rpc_wake_up(&clp->cl_rpcwaitq);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
  /*
e005e8041   Trond Myklebust   NFSv4: Rename the...
1111
   * Schedule the nfs_client asynchronous state management routine
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
   */
b0d3ded1a   Trond Myklebust   NFSv4: Clean up n...
1113
  void nfs4_schedule_state_manager(struct nfs_client *clp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
  {
5043e900f   Trond Myklebust   NFS: Convert inst...
1115
  	struct task_struct *task;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1116
  	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117

e005e8041   Trond Myklebust   NFSv4: Rename the...
1118
1119
  	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
  		return;
5043e900f   Trond Myklebust   NFS: Convert inst...
1120
1121
  	__module_get(THIS_MODULE);
  	atomic_inc(&clp->cl_count);
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  
  	/* The rcu_read_lock() is not strictly necessary, as the state
  	 * manager is the only thread that ever changes the rpc_xprt
  	 * after it's initialized.  At this point, we're single threaded. */
  	rcu_read_lock();
  	snprintf(buf, sizeof(buf), "%s-manager",
  			rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
  	rcu_read_unlock();
  	task = kthread_run(nfs4_run_state_manager, clp, buf);
  	if (IS_ERR(task)) {
  		printk(KERN_ERR "%s: kthread_run: %ld
  ",
  			__func__, PTR_ERR(task));
  		nfs4_clear_state_manager_bit(clp);
  		nfs_put_client(clp);
  		module_put(THIS_MODULE);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
1141
  }
  
  /*
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1142
   * Schedule a lease recovery attempt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
   */
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1144
  void nfs4_schedule_lease_recovery(struct nfs_client *clp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
1146
1147
  {
  	if (!clp)
  		return;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1148
1149
  	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1150
1151
1152
  	dprintk("%s: scheduling lease recovery for server %s
  ", __func__,
  			clp->cl_hostname);
e005e8041   Trond Myklebust   NFSv4: Rename the...
1153
  	nfs4_schedule_state_manager(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
  }
9cb819683   Andy Adamson   NFSv4.1 handle DS...
1155
  EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156

ad1e39682   Trond Myklebust   NFSv4.0: Re-estab...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
  /*
   * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
   * @clp: client to process
   *
   * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
   * resend of the SETCLIENTID and hence re-establish the
   * callback channel. Then return all existing delegations.
   */
  static void nfs40_handle_cb_pathdown(struct nfs_client *clp)
  {
  	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
  	nfs_expire_all_delegations(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1169
1170
1171
  	dprintk("%s: handling CB_PATHDOWN recovery for server %s
  ", __func__,
  			clp->cl_hostname);
ad1e39682   Trond Myklebust   NFSv4.0: Re-estab...
1172
  }
042b60beb   Trond Myklebust   NFSv4: renewd nee...
1173
1174
  void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
  {
ad1e39682   Trond Myklebust   NFSv4.0: Re-estab...
1175
  	nfs40_handle_cb_pathdown(clp);
042b60beb   Trond Myklebust   NFSv4: renewd nee...
1176
1177
  	nfs4_schedule_state_manager(clp);
  }
f9feab1e1   Trond Myklebust   NFSv4: nfs4_state...
1178
  static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1179
1180
1181
1182
1183
1184
1185
1186
  {
  
  	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...
1187
  	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1188
1189
1190
  	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
  	return 1;
  }
f9feab1e1   Trond Myklebust   NFSv4: nfs4_state...
1191
  static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1192
1193
1194
  {
  	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
  	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1195
  	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1196
1197
1198
  	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
  	return 1;
  }
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1199
1200
1201
1202
1203
  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);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1204
1205
1206
  	dprintk("%s: scheduling stateid recovery for server %s
  ", __func__,
  			clp->cl_hostname);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1207
1208
  	nfs4_schedule_state_manager(clp);
  }
9cb819683   Andy Adamson   NFSv4.1 handle DS...
1209
  EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1210

a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
  void nfs_inode_find_state_and_recover(struct inode *inode,
  		const nfs4_stateid *stateid)
  {
  	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
  	struct nfs_inode *nfsi = NFS_I(inode);
  	struct nfs_open_context *ctx;
  	struct nfs4_state *state;
  	bool found = false;
  
  	spin_lock(&inode->i_lock);
  	list_for_each_entry(ctx, &nfsi->open_files, list) {
  		state = ctx->state;
  		if (state == NULL)
  			continue;
  		if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
  			continue;
f597c5379   Trond Myklebust   NFSv4: Add helper...
1227
  		if (!nfs4_stateid_match(&state->stateid, stateid))
a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1228
1229
1230
1231
1232
1233
1234
1235
  			continue;
  		nfs4_state_mark_reclaim_nograce(clp, state);
  		found = true;
  	}
  	spin_unlock(&inode->i_lock);
  	if (found)
  		nfs4_schedule_state_manager(clp);
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1236
  static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
  {
  	struct inode *inode = state->inode;
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1239
  	struct nfs_inode *nfsi = NFS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240
1241
  	struct file_lock *fl;
  	int status = 0;
3f09df70e   Trond Myklebust   NFS: Ensure we al...
1242
1243
1244
1245
  	if (inode->i_flock == NULL)
  		return 0;
  
  	/* Guard against delegation returns and new lock/unlock calls */
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1246
  	down_write(&nfsi->rwsem);
3f09df70e   Trond Myklebust   NFS: Ensure we al...
1247
  	/* Protect inode->i_flock using the BKL */
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1248
  	lock_flocks();
90dc7d279   Harvey Harrison   nfs: fix sparse w...
1249
  	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
43b2a33aa   Trond Myklebust   NFSv4: Fix recove...
1250
  		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
  			continue;
cd3758e37   Trond Myklebust   NFS: Replace file...
1252
  		if (nfs_file_open_context(fl->fl_file)->state != state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
  			continue;
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1254
  		unlock_flocks();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255
  		status = ops->recover_lock(state, fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
  		switch (status) {
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1257
1258
1259
1260
1261
1262
1263
1264
1265
  			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...
1266
1267
1268
1269
  			case -NFS4ERR_BADSESSION:
  			case -NFS4ERR_BADSLOT:
  			case -NFS4ERR_BAD_HIGH_SLOT:
  			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1270
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
  			default:
a030889a0   Weston Andros Adamson   NFS: start printk...
1272
1273
1274
  				printk(KERN_ERR "NFS: %s: unhandled error %d. "
  					"Zeroing state
  ", __func__, status);
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1275
1276
  			case -ENOMEM:
  			case -NFS4ERR_DENIED:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
1278
  			case -NFS4ERR_RECLAIM_BAD:
  			case -NFS4ERR_RECLAIM_CONFLICT:
43b2a33aa   Trond Myklebust   NFSv4: Fix recove...
1279
  				/* kill_proc(fl->fl_pid, SIGLOST, 1); */
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1280
  				status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
  		}
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1282
  		lock_flocks();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
  	}
b89f43213   Arnd Bergmann   fs/locks.c: prepa...
1284
  	unlock_flocks();
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1285
  out:
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1286
  	up_write(&nfsi->rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
  	return status;
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1289
  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
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  {
  	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...
1303
1304
  restart:
  	spin_lock(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
  	list_for_each_entry(state, &sp->so_states, open_states) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1306
1307
  		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
  		if (state->state == 0)
  			continue;
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1310
1311
  		atomic_inc(&state->count);
  		spin_unlock(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1312
  		status = ops->recover_open(sp, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
  		if (status >= 0) {
028600143   Trond Myklebust   NFSv4: Clean up f...
1314
1315
  			status = nfs4_reclaim_locks(state, ops);
  			if (status >= 0) {
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1316
  				spin_lock(&state->state_lock);
028600143   Trond Myklebust   NFSv4: Clean up f...
1317
  				list_for_each_entry(lock, &state->lock_states, ls_locks) {
795a88c96   Trond Myklebust   NFSv4: Convert th...
1318
  					if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
96dcadc2f   William Dauchy   NFSv4: Rate limit...
1319
1320
  						pr_warn_ratelimited("NFS: "
  							"%s: Lock reclaim "
a030889a0   Weston Andros Adamson   NFS: start printk...
1321
1322
  							"failed!
  ", __func__);
028600143   Trond Myklebust   NFSv4: Clean up f...
1323
  				}
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1324
  				spin_unlock(&state->state_lock);
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1325
1326
  				nfs4_put_open_state(state);
  				goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
1330
  		}
  		switch (status) {
  			default:
a030889a0   Weston Andros Adamson   NFS: start printk...
1331
1332
1333
  				printk(KERN_ERR "NFS: %s: unhandled error %d. "
  					"Zeroing state
  ", __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
  			case -ENOENT:
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1335
  			case -ENOMEM:
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1336
  			case -ESTALE:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
1338
1339
1340
  				/*
  				 * Open state on this file cannot be recovered
  				 * All we can do is revert to using the zero stateid.
  				 */
2d2f24add   Trond Myklebust   NFSv4: Simplify t...
1341
1342
  				memset(&state->stateid, 0,
  					sizeof(state->stateid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
1344
1345
  				/* Mark the file as being 'closed' */
  				state->state = 0;
  				break;
168667c43   Trond Myklebust   NFSv4: The state ...
1346
1347
1348
1349
1350
1351
1352
1353
  			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...
1354
1355
1356
  			case -NFS4ERR_ADMIN_REVOKED:
  			case -NFS4ERR_STALE_STATEID:
  			case -NFS4ERR_BAD_STATEID:
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1357
1358
  			case -NFS4ERR_RECLAIM_BAD:
  			case -NFS4ERR_RECLAIM_CONFLICT:
1f0e890db   Trond Myklebust   NFSv4: Clean up s...
1359
  				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1360
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
  			case -NFS4ERR_EXPIRED:
  			case -NFS4ERR_NO_GRACE:
1f0e890db   Trond Myklebust   NFSv4: Clean up s...
1363
  				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
  			case -NFS4ERR_STALE_CLIENTID:
9c4c761a6   Trond Myklebust   NFSv4.1: Handle N...
1365
1366
1367
1368
  			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
1369
1370
  				goto out_err;
  		}
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1371
1372
  		nfs4_put_open_state(state);
  		goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
  	}
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1374
  	spin_unlock(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
1376
  	return 0;
  out_err:
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1377
  	nfs4_put_open_state(state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
1379
  	return status;
  }
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1380
1381
1382
1383
1384
1385
1386
1387
  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...
1388
  	spin_lock(&state->state_lock);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1389
  	list_for_each_entry(lock, &state->lock_states, ls_locks) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1390
  		lock->ls_seqid.flags = 0;
795a88c96   Trond Myklebust   NFSv4: Convert th...
1391
  		clear_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1392
  	}
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1393
  	spin_unlock(&state->state_lock);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1394
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
1395
1396
  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...
1397
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1398
  	struct nfs_client *clp = server->nfs_client;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1399
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
1400
  	struct rb_node *pos;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1401
  	struct nfs4_state *state;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1402

24d292b89   Chuck Lever   NFS: Move cl_stat...
1403
1404
1405
1406
1407
  	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...
1408
  		sp->so_seqid.flags = 0;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
1409
  		spin_lock(&sp->so_lock);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1410
  		list_for_each_entry(state, &sp->so_states, open_states) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1411
1412
  			if (mark_reclaim(clp, state))
  				nfs4_clear_open_state(state);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1413
  		}
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
1414
  		spin_unlock(&sp->so_lock);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1415
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
  	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...
1428
  }
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1429
1430
1431
1432
1433
1434
  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...
1435
1436
1437
1438
1439
1440
1441
  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...
1442
  static void nfs4_clear_reclaim_server(struct nfs_server *server)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1443
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1444
  	struct nfs_client *clp = server->nfs_client;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1445
1446
1447
  	struct nfs4_state_owner *sp;
  	struct rb_node *pos;
  	struct nfs4_state *state;
24d292b89   Chuck Lever   NFS: Move cl_stat...
1448
1449
1450
1451
1452
  	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 ...
1453
1454
  		spin_lock(&sp->so_lock);
  		list_for_each_entry(state, &sp->so_states, open_states) {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1455
1456
  			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT,
  						&state->flags))
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1457
1458
1459
1460
1461
  				continue;
  			nfs4_state_mark_reclaim_nograce(clp, state);
  		}
  		spin_unlock(&sp->so_lock);
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
  	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 ...
1476
1477
  
  	nfs_delegation_reap_unclaimed(clp);
6eaa61496   Trond Myklebust   NFSv4: Don't call...
1478
1479
1480
1481
1482
1483
1484
1485
  	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 ...
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
  }
  
  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 ...
1499
1500
1501
1502
1503
1504
1505
1506
  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 ...
1507
  static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
e598d843c   Trond Myklebust   NFSv4: Remove red...
1508
1509
  {
  	switch (error) {
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1510
1511
  		case 0:
  			break;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1512
  		case -NFS4ERR_CB_PATH_DOWN:
ad1e39682   Trond Myklebust   NFSv4.0: Re-estab...
1513
  			nfs40_handle_cb_pathdown(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1514
  			break;
c8b7ae3d3   Trond Myklebust   NFSv4: Ensure the...
1515
1516
  		case -NFS4ERR_NO_GRACE:
  			nfs4_state_end_reclaim_reboot(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1517
  			break;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1518
1519
1520
  		case -NFS4ERR_STALE_CLIENTID:
  		case -NFS4ERR_LEASE_MOVED:
  			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
6eaa61496   Trond Myklebust   NFSv4: Don't call...
1521
  			nfs4_state_clear_reclaim_reboot(clp);
e598d843c   Trond Myklebust   NFSv4: Remove red...
1522
1523
1524
1525
1526
  			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...
1527
  			break;
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1528
1529
1530
1531
  		case -NFS4ERR_BADSESSION:
  		case -NFS4ERR_BADSLOT:
  		case -NFS4ERR_BAD_HIGH_SLOT:
  		case -NFS4ERR_DEADSESSION:
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1532
1533
  		case -NFS4ERR_SEQ_FALSE_RETRY:
  		case -NFS4ERR_SEQ_MISORDERED:
6df08189f   Andy Adamson   nfs41: rename cl_...
1534
  			set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
0b9e2d41f   Andy Adamson   nfs41: only state...
1535
  			/* Zero session reset errors */
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1536
  			break;
7c5d72568   Trond Myklebust   NFSv4.1: Handle N...
1537
1538
1539
  		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  			set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
  			break;
168667c43   Trond Myklebust   NFSv4: The state ...
1540
1541
1542
  		case -EKEYEXPIRED:
  			/* Nothing we can do */
  			nfs4_warn_keyexpired(clp->cl_hostname);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1543
1544
  			break;
  		default:
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1545
1546
1547
  			dprintk("%s: failed to handle error %d for server %s
  ",
  					__func__, error, clp->cl_hostname);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1548
  			return error;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1549
  	}
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1550
1551
1552
  	dprintk("%s: handled error %d for server %s
  ", __func__, error,
  			clp->cl_hostname);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1553
  	return 0;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1554
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1555
  static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1557
1558
  	struct nfs4_state_owner *sp;
  	struct nfs_server *server;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
1559
  	struct rb_node *pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1560
  	int status = 0;
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1561
  restart:
24d292b89   Chuck Lever   NFS: Move cl_stat...
1562
1563
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
1564
  		nfs4_purge_state_owners(server);
24d292b89   Chuck Lever   NFS: Move cl_stat...
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
  		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...
1584
  			nfs4_put_state_owner(sp);
24d292b89   Chuck Lever   NFS: Move cl_stat...
1585
  			goto restart;
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1586
  		}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1587
  		spin_unlock(&clp->cl_lock);
028600143   Trond Myklebust   NFSv4: Clean up f...
1588
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1589
  	rcu_read_unlock();
028600143   Trond Myklebust   NFSv4: Clean up f...
1590
1591
1592
1593
1594
1595
  	return status;
  }
  
  static int nfs4_check_lease(struct nfs_client *clp)
  {
  	struct rpc_cred *cred;
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1596
1597
  	const struct nfs4_state_maintenance_ops *ops =
  		clp->cl_mvops->state_renewal_ops;
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1598
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599

0f605b560   Trond Myklebust   NFSv4: Don't tell...
1600
1601
1602
  	/* 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 ...
1603
1604
1605
  	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...
1606
1607
  	if (cred == NULL) {
  		cred = nfs4_get_setclientid_cred(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1608
  		status = -ENOKEY;
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1609
1610
  		if (cred == NULL)
  			goto out;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
1611
  	}
8e69514f2   Benny Halevy   nfs41: support mi...
1612
  	status = ops->renew_lease(clp, cred);
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1613
1614
  	put_rpccred(cred);
  out:
4f7cdf18e   Trond Myklebust   NFSv4: The state ...
1615
  	return nfs4_recovery_handle_error(clp, status);
028600143   Trond Myklebust   NFSv4: Clean up f...
1616
  }
47b803c8d   Andy Adamson   NFSv4.0 reclaim r...
1617
1618
  /* Set NFS4CLNT_LEASE_EXPIRED and reclaim reboot state for all v4.0 errors
   * and for recoverable errors on EXCHANGE_ID for v4.1
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1619
1620
1621
1622
   */
  static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
  {
  	switch (status) {
89a217360   Trond Myklebust   NFSv4.1: Handle N...
1623
1624
1625
1626
1627
  	case -NFS4ERR_SEQ_MISORDERED:
  		if (test_and_set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state))
  			return -ESERVERFAULT;
  		/* Lease confirmation error: retry after purging the lease */
  		ssleep(1);
47b803c8d   Andy Adamson   NFSv4.0 reclaim r...
1628
1629
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  		break;
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1630
1631
  	case -NFS4ERR_STALE_CLIENTID:
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
47b803c8d   Andy Adamson   NFSv4.0 reclaim r...
1632
1633
  		nfs4_state_clear_reclaim_reboot(clp);
  		nfs4_state_start_reclaim_reboot(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1634
  		break;
de7348312   Chuck Lever   NFS: Treat NFS4ER...
1635
1636
1637
1638
1639
1640
1641
  	case -NFS4ERR_CLID_INUSE:
  		pr_err("NFS: Server %s reports our clientid is in use
  ",
  			clp->cl_hostname);
  		nfs_mark_client_ready(clp, -EPERM);
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  		return -EPERM;
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
  	case -EACCES:
  		if (clp->cl_machine_cred == NULL)
  			return -EACCES;
  		/* Handle case where the user hasn't set up machine creds */
  		nfs4_clear_machine_cred(clp);
  	case -NFS4ERR_DELAY:
  	case -ETIMEDOUT:
  	case -EAGAIN:
  		ssleep(1);
  		break;
  
  	case -NFS4ERR_MINOR_VERS_MISMATCH:
  		if (clp->cl_cons_state == NFS_CS_SESSION_INITING)
  			nfs_mark_client_ready(clp, -EPROTONOSUPPORT);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1656
1657
1658
  		dprintk("%s: exit with error %d for server %s
  ",
  				__func__, -EPROTONOSUPPORT, clp->cl_hostname);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1659
1660
1661
1662
1663
1664
  		return -EPROTONOSUPPORT;
  	case -EKEYEXPIRED:
  		nfs4_warn_keyexpired(clp->cl_hostname);
  	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
  				 * in nfs4_exchange_id */
  	default:
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1665
1666
1667
  		dprintk("%s: exit with error %d for server %s
  ", __func__,
  				status, clp->cl_hostname);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1668
1669
1670
  		return status;
  	}
  	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1671
1672
1673
  	dprintk("%s: handled error %d for server %s
  ", __func__, status,
  			clp->cl_hostname);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1674
1675
  	return 0;
  }
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1676
  static int nfs4_establish_lease(struct nfs_client *clp)
028600143   Trond Myklebust   NFSv4: Clean up f...
1677
1678
  {
  	struct rpc_cred *cred;
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1679
1680
  	const struct nfs4_state_recovery_ops *ops =
  		clp->cl_mvops->reboot_recovery_ops;
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1681
  	int status;
028600143   Trond Myklebust   NFSv4: Clean up f...
1682

90a16617e   Andy Adamson   nfs41: add a get_...
1683
  	cred = ops->get_clid_cred(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1684
1685
1686
1687
1688
  	if (cred == NULL)
  		return -ENOENT;
  	status = ops->establish_clid(clp, cred);
  	put_rpccred(cred);
  	if (status != 0)
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1689
1690
1691
1692
  		return status;
  	pnfs_destroy_all_layouts(clp);
  	return 0;
  }
6bbb4ae8f   Chuck Lever   NFS: Clean up nfs...
1693
1694
1695
1696
  /*
   * Returns zero or a negative errno.  NFS4ERR values are converted
   * to local errno values.
   */
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
  static int nfs4_reclaim_lease(struct nfs_client *clp)
  {
  	int status;
  
  	status = nfs4_establish_lease(clp);
  	if (status < 0)
  		return nfs4_handle_reclaim_lease_error(clp, status);
  	if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state))
  		nfs4_state_start_reclaim_nograce(clp);
  	if (!test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
  		set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
  	clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
  	clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
  	return 0;
  }
  
  static int nfs4_purge_lease(struct nfs_client *clp)
  {
  	int status;
  
  	status = nfs4_establish_lease(clp);
  	if (status < 0)
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1719
  		return nfs4_handle_reclaim_lease_error(clp, status);
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1720
1721
1722
  	clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
  	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
  	nfs4_state_start_reclaim_nograce(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1723
  	return 0;
028600143   Trond Myklebust   NFSv4: Clean up f...
1724
  }
05f4c350e   Chuck Lever   NFS: Discover NFS...
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
  /**
   * nfs4_discover_server_trunking - Detect server IP address trunking
   *
   * @clp: nfs_client under test
   * @result: OUT: found nfs_client, or clp
   *
   * Returns zero or a negative errno.  If zero is returned,
   * an nfs_client pointer is planted in "result".
   *
   * Note: since we are invoked in process context, and
   * not from inside the state manager, we cannot use
   * nfs4_handle_reclaim_lease_error().
   */
  int nfs4_discover_server_trunking(struct nfs_client *clp,
  				  struct nfs_client **result)
  {
  	const struct nfs4_state_recovery_ops *ops =
  				clp->cl_mvops->reboot_recovery_ops;
  	rpc_authflavor_t *flavors, flav, save;
  	struct rpc_clnt *clnt;
  	struct rpc_cred *cred;
  	int i, len, status;
  
  	dprintk("NFS: %s: testing '%s'
  ", __func__, clp->cl_hostname);
  
  	len = NFS_MAX_SECFLAVORS;
  	flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
  	if (flavors == NULL) {
  		status = -ENOMEM;
  		goto out;
  	}
  	len = rpcauth_list_flavors(flavors, len);
  	if (len < 0) {
  		status = len;
  		goto out_free;
  	}
  	clnt = clp->cl_rpcclient;
  	save = clnt->cl_auth->au_flavor;
  	i = 0;
  
  	mutex_lock(&nfs_clid_init_mutex);
  	status  = -ENOENT;
  again:
  	cred = ops->get_clid_cred(clp);
  	if (cred == NULL)
  		goto out_unlock;
  
  	status = ops->detect_trunking(clp, result, cred);
  	put_rpccred(cred);
  	switch (status) {
  	case 0:
  		break;
  
  	case -EACCES:
  		if (clp->cl_machine_cred == NULL)
  			break;
  		/* Handle case where the user hasn't set up machine creds */
  		nfs4_clear_machine_cred(clp);
  	case -NFS4ERR_DELAY:
  	case -ETIMEDOUT:
  	case -EAGAIN:
  		ssleep(1);
  		dprintk("NFS: %s after status %d, retrying
  ",
  			__func__, status);
  		goto again;
  
  	case -NFS4ERR_CLID_INUSE:
  	case -NFS4ERR_WRONGSEC:
  		status = -EPERM;
  		if (i >= len)
  			break;
  
  		flav = flavors[i++];
  		if (flav == save)
  			flav = flavors[i++];
  		clnt = rpc_clone_client_set_auth(clnt, flav);
  		if (IS_ERR(clnt)) {
  			status = PTR_ERR(clnt);
  			break;
  		}
  		clp->cl_rpcclient = clnt;
  		goto again;
  
  	case -NFS4ERR_MINOR_VERS_MISMATCH:
  		status = -EPROTONOSUPPORT;
  		break;
  
  	case -EKEYEXPIRED:
  		nfs4_warn_keyexpired(clp->cl_hostname);
  	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
  				 * in nfs4_exchange_id */
  		status = -EKEYEXPIRED;
  	}
  
  out_unlock:
  	mutex_unlock(&nfs_clid_init_mutex);
  out_free:
  	kfree(flavors);
  out:
  	dprintk("NFS: %s: status = %d
  ", __func__, status);
  	return status;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
1830
  #ifdef CONFIG_NFS_V4_1
9f594791d   Trond Myklebust   NFSv4.1: Handle o...
1831
  void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1832
  {
444f72fe7   Trond Myklebust   NFSv4.1: Fix the ...
1833
  	struct nfs_client *clp = session->clp;
9f594791d   Trond Myklebust   NFSv4.1: Handle o...
1834
1835
1836
1837
1838
1839
1840
  	switch (err) {
  	default:
  		set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
  		break;
  	case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
  	}
444f72fe7   Trond Myklebust   NFSv4.1: Fix the ...
1841
  	nfs4_schedule_lease_recovery(clp);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1842
  }
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
1843
  EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1844

b9efa1b27   Andy Adamson   nfs41: implement ...
1845
1846
1847
  void nfs41_handle_recall_slot(struct nfs_client *clp)
  {
  	set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1848
1849
1850
  	dprintk("%s: scheduling slot recall for server %s
  ", __func__,
  			clp->cl_hostname);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1851
  	nfs4_schedule_state_manager(clp);
b9efa1b27   Andy Adamson   nfs41: implement ...
1852
  }
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1853
1854
1855
  static void nfs4_reset_all_state(struct nfs_client *clp)
  {
  	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
2c820d9a9   Chuck Lever   NFS: Force server...
1856
  		set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
be0bfed00   Trond Myklebust   NFSv4: When purgi...
1857
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1858
  		nfs4_state_start_reclaim_nograce(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1859
1860
1861
  		dprintk("%s: scheduling reset of all state for server %s!
  ",
  				__func__, clp->cl_hostname);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1862
  		nfs4_schedule_state_manager(clp);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1863
1864
1865
1866
1867
1868
1869
  	}
  }
  
  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);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1870
1871
1872
  		dprintk("%s: server %s rebooted!
  ", __func__,
  				clp->cl_hostname);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1873
  		nfs4_schedule_state_manager(clp);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1874
1875
1876
1877
1878
  	}
  }
  
  static void nfs41_handle_state_revoked(struct nfs_client *clp)
  {
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1879
  	nfs4_reset_all_state(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1880
1881
  	dprintk("%s: state revoked on server %s
  ", __func__, clp->cl_hostname);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1882
1883
1884
1885
1886
1887
  }
  
  static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
  {
  	/* This will need to handle layouts too */
  	nfs_expire_all_delegations(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1888
1889
1890
  	dprintk("%s: Recallable state revoked on server %s!
  ", __func__,
  			clp->cl_hostname);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1891
  }
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
1892
  static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1893
1894
1895
  {
  	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...
1896
  		nfs4_schedule_state_manager(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1897
1898
1899
  	dprintk("%s: server %s declared a backchannel fault
  ", __func__,
  			clp->cl_hostname);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1900
  }
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
1901
1902
1903
1904
1905
1906
  static void nfs41_handle_cb_path_down(struct nfs_client *clp)
  {
  	if (test_and_set_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
  		&clp->cl_state) == 0)
  		nfs4_schedule_state_manager(clp);
  }
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
1907
1908
1909
1910
  void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
  {
  	if (!flags)
  		return;
2c820d9a9   Chuck Lever   NFS: Force server...
1911
1912
1913
1914
  
  	dprintk("%s: \"%s\" (client ID %llx) flags=0x%08x
  ",
  		__func__, clp->cl_hostname, clp->cl_clientid, flags);
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
1915
  	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1916
  		nfs41_handle_server_reboot(clp);
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
1917
  	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
1918
1919
  			    SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
  			    SEQ4_STATUS_ADMIN_STATE_REVOKED |
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1920
1921
  			    SEQ4_STATUS_LEASE_MOVED))
  		nfs41_handle_state_revoked(clp);
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
1922
  	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1923
  		nfs41_handle_recallable_state_revoked(clp);
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
1924
1925
1926
1927
  	if (flags & SEQ4_STATUS_BACKCHANNEL_FAULT)
  		nfs41_handle_backchannel_fault(clp);
  	else if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
  				SEQ4_STATUS_CB_PATH_DOWN_SESSION))
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
1928
  		nfs41_handle_cb_path_down(clp);
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
1929
  }
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1930
1931
  static int nfs4_reset_session(struct nfs_client *clp)
  {
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
1932
  	struct rpc_cred *cred;
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1933
  	int status;
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
1934
1935
  	if (!nfs4_has_session(clp))
  		return 0;
380454126   Trond Myklebust   NFSv4: Fix a regr...
1936
  	nfs4_begin_drain_session(clp);
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
1937
1938
  	cred = nfs4_get_exchange_id_cred(clp);
  	status = nfs4_proc_destroy_session(clp->cl_session, cred);
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1939
1940
  	if (status && status != -NFS4ERR_BADSESSION &&
  	    status != -NFS4ERR_DEADSESSION) {
f455848a1   Ricardo Labiaga   nfs41: Mark state...
1941
  		status = nfs4_recovery_handle_error(clp, status);
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1942
1943
1944
1945
  		goto out;
  	}
  
  	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
1946
  	status = nfs4_proc_create_session(clp, cred);
41f54a554   Andy Adamson   nfs41: clear NFS4...
1947
  	if (status) {
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1948
1949
1950
  		dprintk("%s: session reset failed with status %d for server %s!
  ",
  			__func__, status, clp->cl_hostname);
f2c1b5100   Trond Myklebust   NFSv4.1: nfs4_res...
1951
  		status = nfs4_handle_reclaim_lease_error(clp, status);
41f54a554   Andy Adamson   nfs41: clear NFS4...
1952
1953
  		goto out;
  	}
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
1954
  	nfs41_finish_session_reset(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1955
1956
1957
  	dprintk("%s: session reset was successful for server %s!
  ",
  			__func__, clp->cl_hostname);
41f54a554   Andy Adamson   nfs41: clear NFS4...
1958
  out:
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
1959
1960
  	if (cred)
  		put_rpccred(cred);
c3fad1b1a   Andy Adamson   nfs41: add sessio...
1961
1962
  	return status;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
1963

b9efa1b27   Andy Adamson   nfs41: implement ...
1964
1965
  static int nfs4_recall_slot(struct nfs_client *clp)
  {
60f00153d   Trond Myklebust   NFSv4.1: Clean up...
1966
  	struct nfs4_slot_table *fc_tbl;
b9efa1b27   Andy Adamson   nfs41: implement ...
1967
1968
  	struct nfs4_slot *new, *old;
  	int i;
60f00153d   Trond Myklebust   NFSv4.1: Clean up...
1969
1970
  	if (!nfs4_has_session(clp))
  		return 0;
b9efa1b27   Andy Adamson   nfs41: implement ...
1971
  	nfs4_begin_drain_session(clp);
60f00153d   Trond Myklebust   NFSv4.1: Clean up...
1972
  	fc_tbl = &clp->cl_session->fc_slot_table;
b9efa1b27   Andy Adamson   nfs41: implement ...
1973
  	new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot),
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
1974
  		      GFP_NOFS);
b9efa1b27   Andy Adamson   nfs41: implement ...
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
          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;
60f00153d   Trond Myklebust   NFSv4.1: Clean up...
1985
  	clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots;
b9efa1b27   Andy Adamson   nfs41: implement ...
1986
1987
1988
  	spin_unlock(&fc_tbl->slot_tbl_lock);
  
  	kfree(old);
b9efa1b27   Andy Adamson   nfs41: implement ...
1989
1990
  	return 0;
  }
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
1991
1992
  static int nfs4_bind_conn_to_session(struct nfs_client *clp)
  {
2cf047c99   Trond Myklebust   NFSv4.1: Ensure w...
1993
1994
  	struct rpc_cred *cred;
  	int ret;
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
1995
1996
  	if (!nfs4_has_session(clp))
  		return 0;
43ac544cb   Trond Myklebust   NFSv4.1: nfs4_bin...
1997
  	nfs4_begin_drain_session(clp);
2cf047c99   Trond Myklebust   NFSv4.1: Ensure w...
1998
1999
2000
2001
  	cred = nfs4_get_exchange_id_cred(clp);
  	ret = nfs4_proc_bind_conn_to_session(clp, cred);
  	if (cred)
  		put_rpccred(cred);
43ac544cb   Trond Myklebust   NFSv4.1: nfs4_bin...
2002
  	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
bf674c822   Trond Myklebust   NFSv4.1: Handle e...
2003
2004
  	switch (ret) {
  	case 0:
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2005
2006
2007
  		dprintk("%s: bind_conn_to_session was successful for server %s!
  ",
  			__func__, clp->cl_hostname);
bf674c822   Trond Myklebust   NFSv4.1: Handle e...
2008
2009
2010
2011
2012
2013
2014
2015
2016
  		break;
  	case -NFS4ERR_DELAY:
  		ssleep(1);
  		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
  		break;
  	default:
  		return nfs4_recovery_handle_error(clp, ret);
  	}
  	return 0;
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2017
  }
76db6d950   Andy Adamson   nfs41: add sessio...
2018
  #else /* CONFIG_NFS_V4_1 */
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2019
  static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
5601a00d6   Alexandros Batsakis   nfs: run state ma...
2020
  static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
b9efa1b27   Andy Adamson   nfs41: implement ...
2021
  static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2022
2023
2024
2025
2026
  
  static int nfs4_bind_conn_to_session(struct nfs_client *clp)
  {
  	return 0;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
2027
  #endif /* CONFIG_NFS_V4_1 */
e005e8041   Trond Myklebust   NFSv4: Rename the...
2028
  static void nfs4_state_manager(struct nfs_client *clp)
028600143   Trond Myklebust   NFSv4: Clean up f...
2029
  {
028600143   Trond Myklebust   NFSv4: Clean up f...
2030
  	int status = 0;
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2031
  	const char *section = "", *section_sep = "";
028600143   Trond Myklebust   NFSv4: Clean up f...
2032

028600143   Trond Myklebust   NFSv4: Clean up f...
2033
  	/* Ensure exclusive access to NFSv4 state */
47c2199b6   Trond Myklebust   NFSv4.1: Ensure s...
2034
  	do {
2c820d9a9   Chuck Lever   NFS: Force server...
2035
  		if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2036
  			section = "purge state";
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2037
  			status = nfs4_purge_lease(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
2038
2039
  			if (status < 0)
  				goto out_error;
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2040
  			continue;
2c820d9a9   Chuck Lever   NFS: Force server...
2041
  		}
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2042
  		if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2043
  			section = "lease expired";
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2044
2045
  			/* We're going to have to re-establish a clientid */
  			status = nfs4_reclaim_lease(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
2046
  			if (status < 0)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2047
  				goto out_error;
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2048
  			continue;
e598d843c   Trond Myklebust   NFSv4: Remove red...
2049
2050
2051
  		}
  
  		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2052
  			section = "check lease";
e598d843c   Trond Myklebust   NFSv4: Remove red...
2053
  			status = nfs4_check_lease(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
2054
2055
  			if (status < 0)
  				goto out_error;
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2056
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
e598d843c   Trond Myklebust   NFSv4: Remove red...
2057
  				continue;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2058
  		}
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2059

c3fad1b1a   Andy Adamson   nfs41: add sessio...
2060
  		/* Initialize or reset the session */
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
2061
  		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2062
  			section = "reset session";
4d643d1df   Andy Adamson   nfs41: add create...
2063
  			status = nfs4_reset_session(clp);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2064
2065
2066
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  				continue;
  			if (status < 0)
76db6d950   Andy Adamson   nfs41: add sessio...
2067
  				goto out_error;
76db6d950   Andy Adamson   nfs41: add sessio...
2068
  		}
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2069

a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2070
2071
  		/* Send BIND_CONN_TO_SESSION */
  		if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
2072
  				&clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2073
  			section = "bind conn to session";
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2074
2075
2076
  			status = nfs4_bind_conn_to_session(clp);
  			if (status < 0)
  				goto out_error;
bf674c822   Trond Myklebust   NFSv4.1: Handle e...
2077
  			continue;
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2078
  		}
1a2dd948e   Trond Myklebust   NFSv4.1: Handle s...
2079
  		/* Recall session slots */
60f00153d   Trond Myklebust   NFSv4.1: Clean up...
2080
  		if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) {
1a2dd948e   Trond Myklebust   NFSv4.1: Handle s...
2081
2082
2083
2084
2085
2086
  			section = "recall slot";
  			status = nfs4_recall_slot(clp);
  			if (status < 0)
  				goto out_error;
  			continue;
  		}
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2087
  		/* First recover reboot state... */
e345e88a7   Trond Myklebust   NFSv4: Fix up the...
2088
  		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2089
  			section = "reclaim reboot";
591d71cbd   Andy Adamson   nfs41: establish ...
2090
  			status = nfs4_do_reclaim(clp,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
2091
  				clp->cl_mvops->reboot_recovery_ops);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2092
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
6df08189f   Andy Adamson   nfs41: rename cl_...
2093
  			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2094
  				continue;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2095
  			nfs4_state_end_reclaim_reboot(clp);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2096
2097
2098
2099
  			if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
  				continue;
  			if (status < 0)
  				goto out_error;
028600143   Trond Myklebust   NFSv4: Clean up f...
2100
  		}
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2101
2102
  		/* Now recover expired state... */
  		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2103
  			section = "reclaim nograce";
591d71cbd   Andy Adamson   nfs41: establish ...
2104
  			status = nfs4_do_reclaim(clp,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
2105
  				clp->cl_mvops->nograce_recovery_ops);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2106
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
6df08189f   Andy Adamson   nfs41: rename cl_...
2107
  			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2108
2109
2110
  			    test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
  				continue;
  			if (status < 0)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2111
  				goto out_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2112
  		}
707fb4b32   Trond Myklebust   NFSv4: Clean up N...
2113

5601a00d6   Alexandros Batsakis   nfs: run state ma...
2114
  		nfs4_end_drain_session(clp);
707fb4b32   Trond Myklebust   NFSv4: Clean up N...
2115
2116
2117
2118
  		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
  			nfs_client_return_marked_delegations(clp);
  			continue;
  		}
e005e8041   Trond Myklebust   NFSv4: Rename the...
2119
2120
  
  		nfs4_clear_state_manager_bit(clp);
f3c76491e   Trond Myklebust   NFSv4: Don't exit...
2121
2122
2123
2124
2125
  		/* 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...
2126
  	} while (atomic_read(&clp->cl_count) > 1);
e005e8041   Trond Myklebust   NFSv4: Rename the...
2127
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2128
  out_error:
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2129
2130
2131
2132
2133
2134
  	if (strlen(section))
  		section_sep = ": ";
  	pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
  			" with error %d
  ", section_sep, section,
  			clp->cl_hostname, -status);
ffe5a8300   Chuck Lever   NFS: Slow down st...
2135
  	ssleep(1);
5601a00d6   Alexandros Batsakis   nfs: run state ma...
2136
  	nfs4_end_drain_session(clp);
e005e8041   Trond Myklebust   NFSv4: Rename the...
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
  	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
2149
2150
2151
2152
2153
2154
2155
  }
  
  /*
   * Local variables:
   *  c-basic-offset: 8
   * End:
   */