Blame view

fs/nfs/nfs4state.c 70.5 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
  #include <linux/nfs_fs.h>
5043e900f   Trond Myklebust   NFS: Convert inst...
44
45
  #include <linux/kthread.h>
  #include <linux/module.h>
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
46
  #include <linux/random.h>
8c7597f6c   Randy Dunlap   nfs: include rate...
47
  #include <linux/ratelimit.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
  #include <linux/workqueue.h>
  #include <linux/bitops.h>
0aaaf5c42   Chuck Lever   NFS: Cache state ...
50
  #include <linux/jiffies.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

05f4c350e   Chuck Lever   NFS: Discover NFS...
52
  #include <linux/sunrpc/clnt.h>
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
53
  #include "nfs4_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  #include "callback.h"
  #include "delegation.h"
24c8dbbb5   David Howells   NFS: Generalise t...
56
  #include "internal.h"
40c64c26a   Anna Schumaker   NFS: Move nfs_idm...
57
  #include "nfs4idmap.h"
76e697ba7   Trond Myklebust   NFSv4.1: Move slo...
58
  #include "nfs4session.h"
974cec8ca   Andy Adamson   NFS: client needs...
59
  #include "pnfs.h"
bbe0a3aa4   Stanislav Kinsbursky   NFS: make nfs_cal...
60
  #include "netns.h"
511ba52e4   Chuck Lever   NFS4: Trace state...
61
  #include "nfs4trace.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

e3c0fb7ef   Chuck Lever   NFS: Add NFSDBG_S...
63
  #define NFSDBG_FACILITY		NFSDBG_STATE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  #define OPENOWNER_POOL_SIZE	8
93b717fd8   Trond Myklebust   NFSv4: Label stat...
65
  const nfs4_stateid zero_stateid = {
e0714ec4f   Linus Torvalds   nfs: fix anonymou...
66
  	{ .data = { 0 } },
93b717fd8   Trond Myklebust   NFSv4: Label stat...
67
68
  	.type = NFS4_SPECIAL_STATEID_TYPE,
  };
fcd8843c4   Trond Myklebust   NFSv4: Replace cl...
69
70
  const nfs4_stateid invalid_stateid = {
  	{
445f288d7   Trond Myklebust   NFSv4: Ensure gcc...
71
72
  		/* Funky initialiser keeps older gcc versions happy */
  		.data = { 0xff, 0xff, 0xff, 0xff, 0 },
fcd8843c4   Trond Myklebust   NFSv4: Replace cl...
73
74
75
  	},
  	.type = NFS4_INVALID_STATEID_TYPE,
  };
2409a976a   Fred Isaman   pnfs: Add LAYOUTG...
76
77
78
79
80
81
82
  const nfs4_stateid current_stateid = {
  	{
  		/* Funky initialiser keeps older gcc versions happy */
  		.data = { 0x0, 0x0, 0x0, 0x1, 0 },
  	},
  	.type = NFS4_SPECIAL_STATEID_TYPE,
  };
05f4c350e   Chuck Lever   NFS: Discover NFS...
83
  static DEFINE_MUTEX(nfs_clid_init_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

5b596830d   Donald Buczek   nfs4.0: Refetch l...
85
86
87
88
  static int nfs4_setup_state_renewal(struct nfs_client *clp)
  {
  	int status;
  	struct nfs_fsinfo fsinfo;
5b596830d   Donald Buczek   nfs4.0: Refetch l...
89
90
91
92
93
  
  	if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
  		nfs4_schedule_state_renewal(clp);
  		return 0;
  	}
5b596830d   Donald Buczek   nfs4.0: Refetch l...
94
95
  	status = nfs4_proc_get_lease_time(clp, &fsinfo);
  	if (status == 0) {
7dc2993a9   Robert Milkowski   NFSv4.0: nfs4_do_...
96
  		nfs4_set_lease_period(clp, fsinfo.lease_time * HZ);
5b596830d   Donald Buczek   nfs4.0: Refetch l...
97
98
99
100
101
  		nfs4_schedule_state_renewal(clp);
  	}
  
  	return status;
  }
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
102
  int nfs4_init_clientid(struct nfs_client *clp, const struct cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  {
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
104
105
106
107
  	struct nfs4_setclientid_res clid = {
  		.clientid = clp->cl_clientid,
  		.confirm = clp->cl_confirm,
  	};
f738f5170   Chuck Lever   NFS: Start PF_INE...
108
109
  	unsigned short port;
  	int status;
bbe0a3aa4   Stanislav Kinsbursky   NFS: make nfs_cal...
110
  	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
f738f5170   Chuck Lever   NFS: Start PF_INE...
111

fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
112
113
  	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
  		goto do_confirm;
bbe0a3aa4   Stanislav Kinsbursky   NFS: make nfs_cal...
114
  	port = nn->nfs_callback_tcpport;
f738f5170   Chuck Lever   NFS: Start PF_INE...
115
  	if (clp->cl_addr.ss_family == AF_INET6)
29dcc16a8   Stanislav Kinsbursky   NFS: make nfs_cal...
116
  		port = nn->nfs_callback_tcpport6;
f738f5170   Chuck Lever   NFS: Start PF_INE...
117

bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
118
119
120
  	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
121
122
123
124
  	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...
125
126
127
  	status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
128
  	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
5b596830d   Donald Buczek   nfs4.0: Refetch l...
129
  	nfs4_setup_state_renewal(clp);
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
130
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
  	return status;
  }
05f4c350e   Chuck Lever   NFS: Discover NFS...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  /**
   * 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,
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
148
  				   const struct cred *cred)
05f4c350e   Chuck Lever   NFS: Discover NFS...
149
150
151
152
153
  {
  	struct nfs4_setclientid_res clid = {
  		.clientid = clp->cl_clientid,
  		.confirm = clp->cl_confirm,
  	};
9f62387d6   Trond Myklebust   NFSv4: Fix up a m...
154
  	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
05f4c350e   Chuck Lever   NFS: Discover NFS...
155
156
  	unsigned short port;
  	int status;
9f62387d6   Trond Myklebust   NFSv4: Fix up a m...
157
  	port = nn->nfs_callback_tcpport;
05f4c350e   Chuck Lever   NFS: Discover NFS...
158
  	if (clp->cl_addr.ss_family == AF_INET6)
9f62387d6   Trond Myklebust   NFSv4: Fix up a m...
159
  		port = nn->nfs_callback_tcpport6;
05f4c350e   Chuck Lever   NFS: Discover NFS...
160
161
162
163
164
165
166
167
  
  	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);
202c312db   Trond Myklebust   NFSv4: Fix NFSv4 ...
168
  	if (status == 0) {
05f4c350e   Chuck Lever   NFS: Discover NFS...
169
170
171
  		/* 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);
f02f3755d   ZhangXiaoxu   NFS4: Fix v4.0 cl...
172
173
174
175
  
  		/* If the client state need to recover, do it. */
  		if (clp->cl_state)
  			nfs4_schedule_state_manager(clp);
05f4c350e   Chuck Lever   NFS: Discover NFS...
176
  	}
05f4c350e   Chuck Lever   NFS: Discover NFS...
177
178
179
  out:
  	return status;
  }
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
180
  const struct cred *nfs4_get_machine_cred(struct nfs_client *clp)
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
181
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
182
  	return get_cred(rpc_machine_cred());
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
183
  }
d688f7b8f   Chuck Lever   NFS: Use root's c...
184
185
  static void nfs4_root_machine_cred(struct nfs_client *clp)
  {
d688f7b8f   Chuck Lever   NFS: Use root's c...
186

5e16923b4   NeilBrown   NFS/SUNRPC: don't...
187
188
189
  	/* Force root creds instead of machine */
  	clp->cl_principal = NULL;
  	clp->cl_rpcclient->cl_principal = NULL;
d688f7b8f   Chuck Lever   NFS: Use root's c...
190
  }
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
191
  static const struct cred *
24d292b89   Chuck Lever   NFS: Move cl_stat...
192
  nfs4_get_renew_cred_server_locked(struct nfs_server *server)
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
193
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
194
  	const struct cred *cred = NULL;
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
195
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
196
  	struct rb_node *pos;
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
197

24d292b89   Chuck Lever   NFS: Move cl_stat...
198
199
200
201
  	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...
202
203
  		if (list_empty(&sp->so_states))
  			continue;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
204
  		cred = get_cred(sp->so_cred);
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
205
206
207
208
  		break;
  	}
  	return cred;
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
209
  /**
f15e1e8bc   NeilBrown   NFSv4: don't requ...
210
   * nfs4_get_renew_cred - Acquire credential for a renew operation
24d292b89   Chuck Lever   NFS: Move cl_stat...
211
212
213
214
215
   * @clp: client state handle
   *
   * Returns an rpc_cred with reference count bumped, or NULL.
   * Caller must hold clp->cl_lock.
   */
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
216
  const struct cred *nfs4_get_renew_cred(struct nfs_client *clp)
24d292b89   Chuck Lever   NFS: Move cl_stat...
217
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
218
  	const struct cred *cred = NULL;
24d292b89   Chuck Lever   NFS: Move cl_stat...
219
  	struct nfs_server *server;
e49a29bd0   Sachin Prabhu   Try using machine...
220
  	/* Use machine credentials if available */
f15e1e8bc   NeilBrown   NFSv4: don't requ...
221
  	cred = nfs4_get_machine_cred(clp);
e49a29bd0   Sachin Prabhu   Try using machine...
222
223
  	if (cred != NULL)
  		goto out;
f15e1e8bc   NeilBrown   NFSv4: don't requ...
224
  	spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
225
226
227
228
229
230
231
  	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();
f15e1e8bc   NeilBrown   NFSv4: don't requ...
232
  	spin_unlock(&clp->cl_lock);
e49a29bd0   Sachin Prabhu   Try using machine...
233
234
  
  out:
24d292b89   Chuck Lever   NFS: Move cl_stat...
235
236
  	return cred;
  }
62f288a02   Andy Adamson   NFSv4.1 end back ...
237
  static void nfs4_end_drain_slot_table(struct nfs4_slot_table *tbl)
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
238
  {
774d5f14e   Andy Adamson   NFSv4.1 Fix a pNF...
239
  	if (test_and_clear_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
961a828df   Trond Myklebust   SUNRPC: Fix poten...
240
  		spin_lock(&tbl->slot_tbl_lock);
b75ad4cda   Trond Myklebust   NFSv4.1: Ensure s...
241
  		nfs41_wake_slot_table(tbl);
961a828df   Trond Myklebust   SUNRPC: Fix poten...
242
  		spin_unlock(&tbl->slot_tbl_lock);
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
243
  	}
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
244
  }
62f288a02   Andy Adamson   NFSv4.1 end back ...
245
246
247
  static void nfs4_end_drain_session(struct nfs_client *clp)
  {
  	struct nfs4_session *ses = clp->cl_session;
2cf8bca8b   Chuck Lever   NFS: Update sessi...
248
249
250
251
  	if (clp->cl_slot_tbl) {
  		nfs4_end_drain_slot_table(clp->cl_slot_tbl);
  		return;
  	}
62f288a02   Andy Adamson   NFSv4.1 end back ...
252
253
254
255
256
  	if (ses != NULL) {
  		nfs4_end_drain_slot_table(&ses->bc_slot_table);
  		nfs4_end_drain_slot_table(&ses->fc_slot_table);
  	}
  }
774d5f14e   Andy Adamson   NFSv4.1 Fix a pNF...
257
  static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl)
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
258
  {
774d5f14e   Andy Adamson   NFSv4.1 Fix a pNF...
259
  	set_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
260
  	spin_lock(&tbl->slot_tbl_lock);
b6bf6e7d6   Andy Adamson   NFSv4.1 set highe...
261
  	if (tbl->highest_used_slotid != NFS4_NO_SLOT) {
16735d022   Wolfram Sang   tree-wide: use re...
262
  		reinit_completion(&tbl->complete);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
263
  		spin_unlock(&tbl->slot_tbl_lock);
42acd0218   Andy Adamson   NFS add session b...
264
  		return wait_for_completion_interruptible(&tbl->complete);
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
265
266
267
268
  	}
  	spin_unlock(&tbl->slot_tbl_lock);
  	return 0;
  }
42acd0218   Andy Adamson   NFS add session b...
269
270
271
  static int nfs4_begin_drain_session(struct nfs_client *clp)
  {
  	struct nfs4_session *ses = clp->cl_session;
8aafd2fde   Trond Myklebust   NFSv4: Don't busy...
272
  	int ret;
42acd0218   Andy Adamson   NFS add session b...
273

2cf8bca8b   Chuck Lever   NFS: Update sessi...
274
275
  	if (clp->cl_slot_tbl)
  		return nfs4_drain_slot_tbl(clp->cl_slot_tbl);
42acd0218   Andy Adamson   NFS add session b...
276
  	/* back channel */
774d5f14e   Andy Adamson   NFSv4.1 Fix a pNF...
277
  	ret = nfs4_drain_slot_tbl(&ses->bc_slot_table);
42acd0218   Andy Adamson   NFS add session b...
278
279
280
  	if (ret)
  		return ret;
  	/* fore channel */
774d5f14e   Andy Adamson   NFSv4.1 Fix a pNF...
281
  	return nfs4_drain_slot_tbl(&ses->fc_slot_table);
42acd0218   Andy Adamson   NFS add session b...
282
  }
c9fdeb280   Chuck Lever   NFS: Add basic mi...
283
  #if defined(CONFIG_NFS_V4_1)
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
284
285
286
287
288
  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 */
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
289
  	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
ea51efaa9   Donald Buczek   nfs4: Rename nfs4...
290
  	nfs4_setup_state_renewal(clp);
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
291
  }
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
292
  int nfs41_init_clientid(struct nfs_client *clp, const struct cred *cred)
4d643d1df   Andy Adamson   nfs41: add create...
293
294
  {
  	int status;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
295
296
  	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
  		goto do_confirm;
4d643d1df   Andy Adamson   nfs41: add create...
297
  	status = nfs4_proc_exchange_id(clp, cred);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
298
299
  	if (status != 0)
  		goto out;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
300
301
  	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  do_confirm:
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
302
  	status = nfs4_proc_create_session(clp, cred);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
303
304
  	if (status != 0)
  		goto out;
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
305
  	nfs41_finish_session_reset(clp);
9430fb6b5   Ricardo Labiaga   nfs41: nfs41_setu...
306
307
  	nfs_mark_client_ready(clp, NFS_CS_READY);
  out:
4d643d1df   Andy Adamson   nfs41: add create...
308
309
  	return status;
  }
05f4c350e   Chuck Lever   NFS: Discover NFS...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  /**
   * 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,
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
325
  				   const struct cred *cred)
05f4c350e   Chuck Lever   NFS: Discover NFS...
326
327
328
329
330
331
  {
  	int status;
  
  	status = nfs4_proc_exchange_id(clp, cred);
  	if (status != NFS4_OK)
  		return status;
48d66b974   Trond Myklebust   NFSv4: Fix a race...
332
333
334
335
336
  	status = nfs41_walk_client_list(clp, result, cred);
  	if (status < 0)
  		return status;
  	if (clp != *result)
  		return 0;
8dcbec6d2   Chuck Lever   NFSv4.1: Handle E...
337
338
339
340
341
342
343
344
345
346
347
  	/*
  	 * Purge state if the client id was established in a prior
  	 * instance and the client id could not have arrived on the
  	 * server via Transparent State Migration.
  	 */
  	if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) {
  		if (!test_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags))
  			set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
  		else
  			set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  	}
48d66b974   Trond Myklebust   NFSv4: Fix a race...
348
349
350
351
352
  	nfs4_schedule_state_manager(clp);
  	status = nfs_wait_client_init_complete(clp);
  	if (status < 0)
  		nfs_put_client(clp);
  	return status;
05f4c350e   Chuck Lever   NFS: Discover NFS...
353
  }
b4b82607f   Andy Adamson   nfs41: get_clid_c...
354
  #endif /* CONFIG_NFS_V4_1 */
24d292b89   Chuck Lever   NFS: Move cl_stat...
355
  /**
73d8bde5e   Chuck Lever   NFS: Never use us...
356
   * nfs4_get_clid_cred - Acquire credential for a setclientid operation
24d292b89   Chuck Lever   NFS: Move cl_stat...
357
358
   * @clp: client state handle
   *
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
359
   * Returns a cred with reference count bumped, or NULL.
24d292b89   Chuck Lever   NFS: Move cl_stat...
360
   */
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
361
  const struct cred *nfs4_get_clid_cred(struct nfs_client *clp)
24d292b89   Chuck Lever   NFS: Move cl_stat...
362
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
363
  	const struct cred *cred;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
364

f15e1e8bc   NeilBrown   NFSv4: don't requ...
365
  	cred = nfs4_get_machine_cred(clp);
a2b2bb882   Trond Myklebust   NFSv4: Attempt to...
366
  	return cred;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
367
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  static struct nfs4_state_owner *
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
369
  nfs4_find_state_owner_locked(struct nfs_server *server, const struct cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
371
  	struct rb_node **p = &server->state_owners.rb_node,
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
372
  		       *parent = NULL;
414adf14c   Chuck Lever   NFS: Clean up nfs...
373
  	struct nfs4_state_owner *sp;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
374
  	int cmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375

9f958ab88   Trond Myklebust   NFSv4: Reduce the...
376
377
  	while (*p != NULL) {
  		parent = *p;
24d292b89   Chuck Lever   NFS: Move cl_stat...
378
  		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
379
  		cmp = cred_fscmp(cred, sp->so_cred);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
380

a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
381
  		if (cmp < 0)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
382
  			p = &parent->rb_left;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
383
  		else if (cmp > 0)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
384
385
  			p = &parent->rb_right;
  		else {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
386
387
  			if (!list_empty(&sp->so_lru))
  				list_del_init(&sp->so_lru);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
388
  			atomic_inc(&sp->so_count);
414adf14c   Chuck Lever   NFS: Clean up nfs...
389
  			return sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
390
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	}
414adf14c   Chuck Lever   NFS: Clean up nfs...
392
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  }
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
394
  static struct nfs4_state_owner *
24d292b89   Chuck Lever   NFS: Move cl_stat...
395
  nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
396
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
397
398
  	struct nfs_server *server = new->so_server;
  	struct rb_node **p = &server->state_owners.rb_node,
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
399
400
  		       *parent = NULL;
  	struct nfs4_state_owner *sp;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
401
  	int cmp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
402
403
404
  
  	while (*p != NULL) {
  		parent = *p;
24d292b89   Chuck Lever   NFS: Move cl_stat...
405
  		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
406
  		cmp = cred_fscmp(new->so_cred, sp->so_cred);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
407

a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
408
  		if (cmp < 0)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
409
  			p = &parent->rb_left;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
410
  		else if (cmp > 0)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
411
412
  			p = &parent->rb_right;
  		else {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
413
414
  			if (!list_empty(&sp->so_lru))
  				list_del_init(&sp->so_lru);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
415
416
417
418
  			atomic_inc(&sp->so_count);
  			return sp;
  		}
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
419
420
  	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...
421
422
423
424
  	return new;
  }
  
  static void
24d292b89   Chuck Lever   NFS: Move cl_stat...
425
  nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
426
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
427
428
429
430
  	struct nfs_server *server = sp->so_server;
  
  	if (!RB_EMPTY_NODE(&sp->so_server_node))
  		rb_erase(&sp->so_server_node, &server->state_owners);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
431
  }
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
432
433
434
  static void
  nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
  {
95b72eb0b   Trond Myklebust   NFSv4: Ensure we ...
435
  	sc->create_time = ktime_get();
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
436
437
438
439
440
441
442
443
444
445
446
447
  	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
448
449
450
451
452
453
  /*
   * 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...
454
  nfs4_alloc_state_owner(struct nfs_server *server,
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
455
  		const struct cred *cred,
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
456
  		gfp_t gfp_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
  {
  	struct nfs4_state_owner *sp;
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
459
  	sp = kzalloc(sizeof(*sp), gfp_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
  	if (!sp)
  		return NULL;
aae5730e2   Matthew Wilcox   nfs: Use ida_simp...
462
463
464
465
466
467
  	sp->so_seqid.owner_id = ida_simple_get(&server->openowner_id, 0, 0,
  						gfp_flags);
  	if (sp->so_seqid.owner_id < 0) {
  		kfree(sp);
  		return NULL;
  	}
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
468
  	sp->so_server = server;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
469
  	sp->so_cred = get_cred(cred);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
470
  	spin_lock_init(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  	INIT_LIST_HEAD(&sp->so_states);
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
472
  	nfs4_init_seqid_counter(&sp->so_seqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  	atomic_set(&sp->so_count, 1);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
474
  	INIT_LIST_HEAD(&sp->so_lru);
76246c921   Ahmed S. Darwish   NFSv4: Use sequen...
475
  	seqcount_spinlock_init(&sp->so_reclaim_seqcount, &sp->so_lock);
65b62a29f   Trond Myklebust   NFSv4: Ensure del...
476
  	mutex_init(&sp->so_delegreturn_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  	return sp;
  }
1d2e88e73   Adrian Bunk   nfs: make nfs4_dr...
479
  static void
86cfb0418   NeilBrown   NFS: Don't discon...
480
  nfs4_reset_state_owner(struct nfs4_state_owner *sp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  {
86cfb0418   NeilBrown   NFS: Don't discon...
482
483
484
485
486
487
488
489
490
491
  	/* This state_owner is no longer usable, but must
  	 * remain in place so that state recovery can find it
  	 * and the opens associated with it.
  	 * It may also be used for new 'open' request to
  	 * return a delegation to the server.
  	 * So update the 'create_time' so that it looks like
  	 * a new state_owner.  This will cause the server to
  	 * request an OPEN_CONFIRM to start a new sequence.
  	 */
  	sp->so_seqid.create_time = ktime_get();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  }
0aaaf5c42   Chuck Lever   NFS: Cache state ...
493
494
  static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
  {
7ba127ab9   Trond Myklebust   NFSv4: Move conte...
495
  	nfs4_destroy_seqid_counter(&sp->so_seqid);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
496
  	put_cred(sp->so_cred);
aae5730e2   Matthew Wilcox   nfs: Use ida_simp...
497
  	ida_simple_remove(&sp->so_server->openowner_id, sp->so_seqid.owner_id);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  	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...
525
526
527
528
  /**
   * nfs4_get_state_owner - Look up a state owner given a credential
   * @server: nfs_server to search
   * @cred: RPC credential to match
302fad7bd   Trond Myklebust   NFS: Fix up docum...
529
   * @gfp_flags: allocation mode
24d292b89   Chuck Lever   NFS: Move cl_stat...
530
531
532
533
   *
   * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
   */
  struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
534
  					      const struct cred *cred,
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
535
  					      gfp_t gfp_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  {
7539bbab8   David Howells   NFS: Rename nfs_s...
537
  	struct nfs_client *clp = server->nfs_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
  	struct nfs4_state_owner *sp, *new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	spin_lock(&clp->cl_lock);
24d292b89   Chuck Lever   NFS: Move cl_stat...
540
  	sp = nfs4_find_state_owner_locked(server, cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  	spin_unlock(&clp->cl_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  	if (sp != NULL)
0aaaf5c42   Chuck Lever   NFS: Cache state ...
543
  		goto out;
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
544
  	new = nfs4_alloc_state_owner(server, cred, gfp_flags);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
545
  	if (new == NULL)
0aaaf5c42   Chuck Lever   NFS: Cache state ...
546
  		goto out;
aae5730e2   Matthew Wilcox   nfs: Use ida_simp...
547
548
549
  	spin_lock(&clp->cl_lock);
  	sp = nfs4_insert_state_owner_locked(new);
  	spin_unlock(&clp->cl_lock);
d1e284d50   Trond Myklebust   NFSv4: Clean up n...
550
551
  	if (sp != new)
  		nfs4_free_state_owner(new);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
552
553
  out:
  	nfs4_gc_state_owners(server);
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
554
  	return sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
556
557
558
  /**
   * nfs4_put_state_owner - Release a nfs4_state_owner
   * @sp: state owner data to release
7bf97bc27   Trond Myklebust   NFSv4: Keep dropp...
559
560
561
562
563
564
565
566
   *
   * 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...
567
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  void nfs4_put_state_owner(struct nfs4_state_owner *sp)
  {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
570
571
  	struct nfs_server *server = sp->so_server;
  	struct nfs_client *clp = server->nfs_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
574
  
  	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
  		return;
0aaaf5c42   Chuck Lever   NFS: Cache state ...
575

7bf97bc27   Trond Myklebust   NFSv4: Keep dropp...
576
577
578
  	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 ...
579
580
581
582
583
  }
  
  /**
   * nfs4_purge_state_owners - Release all cached state owners
   * @server: nfs_server with cached state owners to release
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
584
   * @head: resulting list of state owners
0aaaf5c42   Chuck Lever   NFS: Cache state ...
585
586
587
   *
   * Called at umount time.  Remaining state owners will be on
   * the LRU with ref count of zero.
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
588
589
590
   * Note that the state owners are not freed, but are added
   * to the list @head, which can later be used as an argument
   * to nfs4_free_state_owners.
0aaaf5c42   Chuck Lever   NFS: Cache state ...
591
   */
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
592
  void nfs4_purge_state_owners(struct nfs_server *server, struct list_head *head)
0aaaf5c42   Chuck Lever   NFS: Cache state ...
593
594
595
  {
  	struct nfs_client *clp = server->nfs_client;
  	struct nfs4_state_owner *sp, *tmp;
0aaaf5c42   Chuck Lever   NFS: Cache state ...
596
597
598
  
  	spin_lock(&clp->cl_lock);
  	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
599
  		list_move(&sp->so_lru, head);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
600
601
  		nfs4_remove_state_owner_locked(sp);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  	spin_unlock(&clp->cl_lock);
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
603
  }
0aaaf5c42   Chuck Lever   NFS: Cache state ...
604

c77e22834   Trond Myklebust   NFSv4: Fix a pote...
605
606
607
608
609
610
611
612
613
614
615
616
  /**
   * nfs4_purge_state_owners - Release all cached state owners
   * @head: resulting list of state owners
   *
   * Frees a list of state owners that was generated by
   * nfs4_purge_state_owners
   */
  void nfs4_free_state_owners(struct list_head *head)
  {
  	struct nfs4_state_owner *sp, *tmp;
  
  	list_for_each_entry_safe(sp, tmp, head, so_lru) {
0aaaf5c42   Chuck Lever   NFS: Cache state ...
617
618
619
  		list_del(&sp->so_lru);
  		nfs4_free_state_owner(sp);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
625
  }
  
  static struct nfs4_state *
  nfs4_alloc_open_state(void)
  {
  	struct nfs4_state *state;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
626
  	state = kzalloc(sizeof(*state), GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
  	if (!state)
  		return NULL;
ace9fad43   Trond Myklebust   NFSv4: Convert st...
629
  	refcount_set(&state->count, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  	INIT_LIST_HEAD(&state->lock_states);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
631
  	spin_lock_init(&state->state_lock);
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
632
  	seqlock_init(&state->seqlock);
c9399f21c   Trond Myklebust   NFSv4: Fix OPEN /...
633
  	init_waitqueue_head(&state->waitq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
  	return state;
  }
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
636
  void
dc0b027df   Trond Myklebust   NFSv4: Convert th...
637
  nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
638
  {
dc0b027df   Trond Myklebust   NFSv4: Convert th...
639
  	if (state->state == fmode)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
640
641
  		return;
  	/* NB! List reordering - see the reclaim code for why.  */
dc0b027df   Trond Myklebust   NFSv4: Convert th...
642
643
  	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
  		if (fmode & FMODE_WRITE)
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
644
645
646
647
  			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...
648
  	state->state = fmode;
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
649
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  static struct nfs4_state *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
  __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	struct nfs4_state *state;
9ae075fdd   Trond Myklebust   NFSv4: Convert op...
655
  	list_for_each_entry_rcu(state, &nfsi->open_states, inode_states) {
1c816efa2   Trond Myklebust   NFSv4: Fix a bug ...
656
  		if (state->owner != owner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  			continue;
5d422301f   Trond Myklebust   NFSv4: Fail I/O i...
658
659
  		if (!nfs4_valid_open_stateid(state))
  			continue;
ace9fad43   Trond Myklebust   NFSv4: Convert st...
660
  		if (refcount_inc_not_zero(&state->count))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  			return state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
  	}
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
  static void
  nfs4_free_open_state(struct nfs4_state *state)
  {
9ae075fdd   Trond Myklebust   NFSv4: Convert op...
668
  	kfree_rcu(state, rcu_head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
675
  }
  
  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);
9ae075fdd   Trond Myklebust   NFSv4: Convert op...
676
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  	state = __nfs4_find_state_byowner(inode, owner);
9ae075fdd   Trond Myklebust   NFSv4: Convert op...
678
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
  	if (state)
  		goto out;
  	new = nfs4_alloc_open_state();
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
682
  	spin_lock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
  	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
687
688
  		state->owner = owner;
  		atomic_inc(&owner->so_count);
0444d76ae   Dave Chinner   fs: don't use igr...
689
690
  		ihold(inode);
  		state->inode = inode;
29fe83997   J. Bruce Fields   nfs: fix NULL def...
691
  		list_add_rcu(&state->inode_states, &nfsi->open_states);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  		spin_unlock(&inode->i_lock);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
693
694
695
696
  		/* 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
697
698
  	} else {
  		spin_unlock(&inode->i_lock);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
699
  		spin_unlock(&owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
705
  		if (new)
  			nfs4_free_open_state(new);
  	}
  out:
  	return state;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
708
709
  void nfs4_put_open_state(struct nfs4_state *state)
  {
  	struct inode *inode = state->inode;
  	struct nfs4_state_owner *owner = state->owner;
ace9fad43   Trond Myklebust   NFSv4: Convert st...
710
  	if (!refcount_dec_and_lock(&state->count, &owner->so_lock))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  		return;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
712
  	spin_lock(&inode->i_lock);
9ae075fdd   Trond Myklebust   NFSv4: Convert op...
713
  	list_del_rcu(&state->inode_states);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  	list_del(&state->open_states);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
715
716
  	spin_unlock(&inode->i_lock);
  	spin_unlock(&owner->so_lock);
b7b7dac68   Trond Myklebust   NFSv4: Try to ret...
717
  	nfs4_inode_return_delegation_on_close(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
  	iput(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
723
  	nfs4_free_open_state(state);
  	nfs4_put_state_owner(owner);
  }
  
  /*
83c9d41e4   Trond Myklebust   NFSv4: Remove nfs...
724
   * Close the current file.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
   */
643168c2d   Al Viro   nfs4_closedata do...
726
  static void __nfs4_close(struct nfs4_state *state,
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
727
  		fmode_t fmode, gfp_t gfp_mask, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  	struct nfs4_state_owner *owner = state->owner;
003707c72   Trond Myklebust   NFSv4: Always use...
730
  	int call_close = 0;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
731
  	fmode_t newstate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
  
  	atomic_inc(&owner->so_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  	/* Protect against nfs4_find_state() */
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
735
  	spin_lock(&owner->so_lock);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
736
  	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
737
738
739
740
741
742
743
744
745
  		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...
746
  	newstate = FMODE_READ|FMODE_WRITE;
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
747
  	if (state->n_rdwr == 0) {
003707c72   Trond Myklebust   NFSv4: Always use...
748
  		if (state->n_rdonly == 0) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
749
  			newstate &= ~FMODE_READ;
003707c72   Trond Myklebust   NFSv4: Always use...
750
751
752
753
  			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_...
754
  			newstate &= ~FMODE_WRITE;
003707c72   Trond Myklebust   NFSv4: Always use...
755
756
757
758
759
  			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_...
760
  	}
003707c72   Trond Myklebust   NFSv4: Always use...
761
  	nfs4_state_set_mode_locked(state, newstate);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
762
  	spin_unlock(&owner->so_lock);
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
763

003707c72   Trond Myklebust   NFSv4: Always use...
764
  	if (!call_close) {
b39e625b6   Trond Myklebust   NFSv4: Clean up n...
765
766
  		nfs4_put_open_state(state);
  		nfs4_put_state_owner(owner);
1f7977c13   Trond Myklebust   NFSv4.1: Simplify...
767
768
  	} else
  		nfs4_do_close(state, gfp_mask, wait);
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
769
  }
643168c2d   Al Viro   nfs4_closedata do...
770
  void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
771
  {
643168c2d   Al Viro   nfs4_closedata do...
772
  	__nfs4_close(state, fmode, GFP_NOFS, 0);
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
773
  }
643168c2d   Al Viro   nfs4_closedata do...
774
  void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
775
  {
643168c2d   Al Viro   nfs4_closedata do...
776
  	__nfs4_close(state, fmode, GFP_KERNEL, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
  }
  
  /*
   * Search the state->lock_states for an existing lock_owner
3f8f25489   NeilBrown   NFSv4: ensure __n...
781
782
783
784
785
786
787
788
789
790
   * that is compatible with either of the given owners.
   * If the second is non-zero, then the first refers to a Posix-lock
   * owner (current->files) and the second refers to a flock/OFD
   * owner (struct file*).  In that case, prefer a match for the first
   * owner.
   * If both sorts of locks are held on the one file we cannot know
   * which stateid was intended to be used, so a "correct" choice cannot
   * be made.  Failing that, a "consistent" choice is preferable.  The
   * consistent choice we make is to prefer the first owner, that of a
   * Posix lock.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
   */
  static struct nfs4_lock_state *
8d4244316   NeilBrown   NFSv4: enhance nf...
793
794
  __nfs4_find_lock_state(struct nfs4_state *state,
  		       fl_owner_t fl_owner, fl_owner_t fl_owner2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  {
3f8f25489   NeilBrown   NFSv4: ensure __n...
796
  	struct nfs4_lock_state *pos, *ret = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  	list_for_each_entry(pos, &state->lock_states, ls_locks) {
3f8f25489   NeilBrown   NFSv4: ensure __n...
798
799
800
801
802
803
  		if (pos->ls_owner == fl_owner) {
  			ret = pos;
  			break;
  		}
  		if (pos->ls_owner == fl_owner2)
  			ret = pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  	}
3f8f25489   NeilBrown   NFSv4: ensure __n...
805
  	if (ret)
194bc1f48   Elena Reshetova   fs, nfs: convert ...
806
  		refcount_inc(&ret->ls_count);
3f8f25489   NeilBrown   NFSv4: ensure __n...
807
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
812
  /*
   * Return a compatible lock_state. If no initialized lock_state structure
   * exists, return an uninitialized one.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
   */
8003d3c4a   Jeff Layton   nfs4: treat lock ...
814
  static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  {
  	struct nfs4_lock_state *lsp;
24d292b89   Chuck Lever   NFS: Move cl_stat...
817
  	struct nfs_server *server = state->owner->so_server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818

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

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
882
883
884
  	if (lsp == NULL)
  		return;
  	state = lsp->ls_state;
194bc1f48   Elena Reshetova   fs, nfs: convert ...
885
  	if (!refcount_dec_and_lock(&lsp->ls_count, &state->state_lock))
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
886
887
888
889
890
  		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);
0c0e0d3c0   Jeff Layton   nfs: revert "nfs4...
891
892
893
894
895
896
  	server = state->owner->so_server;
  	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
  		struct nfs_client *clp = server->nfs_client;
  
  		clp->cl_mvops->free_lock_state(server, lsp);
  	} else
c8b2d0bfd   Trond Myklebust   NFSv4.1: Ensure t...
897
  		nfs4_free_lock_state(server, lsp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
  }
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
899
  static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
901
  	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
903
  	dst->fl_u.nfs4_fl.owner = lsp;
194bc1f48   Elena Reshetova   fs, nfs: convert ...
904
  	refcount_inc(&lsp->ls_count);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
905
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
907
  static void nfs4_fl_release_lock(struct file_lock *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
909
  	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  }
6aed62853   Alexey Dobriyan   const: make file_...
911
  static const struct file_lock_operations nfs4_fl_lock_ops = {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
912
913
914
915
916
  	.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
917
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
918
919
920
921
  	struct nfs4_lock_state *lsp;
  
  	if (fl->fl_ops != NULL)
  		return 0;
8003d3c4a   Jeff Layton   nfs4: treat lock ...
922
  	lsp = nfs4_get_lock_state(state, fl->fl_owner);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
923
924
925
926
927
  	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
928
  }
5521abfdc   Trond Myklebust   NFSv4: Resend the...
929
930
  static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
  		struct nfs4_state *state,
173934754   NeilBrown   NFSv4: change nfs...
931
  		const struct nfs_lock_context *l_ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  {
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
933
  	struct nfs4_lock_state *lsp;
8d4244316   NeilBrown   NFSv4: enhance nf...
934
  	fl_owner_t fl_owner, fl_flock_owner;
5521abfdc   Trond Myklebust   NFSv4: Resend the...
935
  	int ret = -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936

173934754   NeilBrown   NFSv4: change nfs...
937
  	if (l_ctx == NULL)
2a369153c   Trond Myklebust   NFS: Clean up hel...
938
  		goto out;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
939
  	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
940
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941

d51fdb87a   NeilBrown   NFS: discard nfs_...
942
  	fl_owner = l_ctx->lockowner;
8d4244316   NeilBrown   NFSv4: enhance nf...
943
  	fl_flock_owner = l_ctx->open_context->flock_owner;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
944
  	spin_lock(&state->state_lock);
8d4244316   NeilBrown   NFSv4: enhance nf...
945
  	lsp = __nfs4_find_lock_state(state, fl_owner, fl_flock_owner);
ef1820f9b   NeilBrown   NFSv4: Don't try ...
946
947
948
  	if (lsp && test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
  		ret = -EIO;
  	else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
f597c5379   Trond Myklebust   NFSv4: Add helper...
949
  		nfs4_stateid_copy(dst, &lsp->ls_stateid);
5521abfdc   Trond Myklebust   NFSv4: Resend the...
950
  		ret = 0;
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
951
  	}
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
952
  	spin_unlock(&state->state_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
  	nfs4_put_lock_state(lsp);
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
954
955
956
  out:
  	return ret;
  }
c82bac6f4   Trond Myklebust   NFSv4: Don't try ...
957
  bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
958
  {
c82bac6f4   Trond Myklebust   NFSv4: Don't try ...
959
  	bool ret;
92b40e938   Trond Myklebust   NFSv4: Use the op...
960
  	const nfs4_stateid *src;
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
961
962
963
  	int seq;
  
  	do {
c82bac6f4   Trond Myklebust   NFSv4: Don't try ...
964
  		ret = false;
92b40e938   Trond Myklebust   NFSv4: Use the op...
965
  		src = &zero_stateid;
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
966
  		seq = read_seqbegin(&state->seqlock);
c82bac6f4   Trond Myklebust   NFSv4: Don't try ...
967
  		if (test_bit(NFS_OPEN_STATE, &state->flags)) {
92b40e938   Trond Myklebust   NFSv4: Use the op...
968
  			src = &state->open_stateid;
c82bac6f4   Trond Myklebust   NFSv4: Don't try ...
969
970
  			ret = true;
  		}
92b40e938   Trond Myklebust   NFSv4: Use the op...
971
  		nfs4_stateid_copy(dst, src);
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
972
  	} while (read_seqretry(&state->seqlock, seq));
c82bac6f4   Trond Myklebust   NFSv4: Don't try ...
973
  	return ret;
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
974
975
976
977
978
979
  }
  
  /*
   * Byte-range lock aware utility to initialize the stateid of read/write
   * requests.
   */
abf4e13cc   Trond Myklebust   NFSv4: Use the ri...
980
  int nfs4_select_rw_stateid(struct nfs4_state *state,
173934754   NeilBrown   NFSv4: change nfs...
981
  		fmode_t fmode, const struct nfs_lock_context *l_ctx,
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
982
  		nfs4_stateid *dst, const struct cred **cred)
4fc8796d2   Trond Myklebust   NFSv4: Clean up n...
983
  {
abf4e13cc   Trond Myklebust   NFSv4: Use the ri...
984
  	int ret;
7ebeb7fe7   Trond Myklebust   NFSv4: If recover...
985
986
  	if (!nfs4_valid_open_stateid(state))
  		return -EIO;
abf4e13cc   Trond Myklebust   NFSv4: Use the ri...
987
988
  	if (cred != NULL)
  		*cred = NULL;
173934754   NeilBrown   NFSv4: change nfs...
989
  	ret = nfs4_copy_lock_stateid(dst, state, l_ctx);
ef1820f9b   NeilBrown   NFSv4: Don't try ...
990
991
992
  	if (ret == -EIO)
  		/* A lost lock - don't even consider delegations */
  		goto out;
146d70caa   Andy Adamson   NFS fix error ret...
993
  	/* returns true if delegation stateid found and copied */
abf4e13cc   Trond Myklebust   NFSv4: Use the ri...
994
  	if (nfs4_copy_delegation_stateid(state->inode, fmode, dst, cred)) {
146d70caa   Andy Adamson   NFS fix error ret...
995
  		ret = 0;
5521abfdc   Trond Myklebust   NFSv4: Resend the...
996
  		goto out;
146d70caa   Andy Adamson   NFS fix error ret...
997
  	}
5521abfdc   Trond Myklebust   NFSv4: Resend the...
998
  	if (ret != -ENOENT)
ef1820f9b   NeilBrown   NFSv4: Don't try ...
999
1000
1001
1002
  		/* nfs4_copy_delegation_stateid() didn't over-write
  		 * dst, so it still has the lock stateid which we now
  		 * choose to use.
  		 */
5521abfdc   Trond Myklebust   NFSv4: Resend the...
1003
  		goto out;
d9aba2b40   Trond Myklebust   NFSv4: Don't use ...
1004
  	ret = nfs4_copy_open_stateid(dst, state) ? 0 : -EAGAIN;
5521abfdc   Trond Myklebust   NFSv4: Resend the...
1005
  out:
3b66486c4   Trond Myklebust   NFSv4.1: Select t...
1006
1007
  	if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
  		dst->seqid = 0;
5521abfdc   Trond Myklebust   NFSv4: Resend the...
1008
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
  }
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
1010
  struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1011
  {
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1012
  	struct nfs_seqid *new;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
1013
  	new = kmalloc(sizeof(*new), gfp_mask);
badc76dd0   Trond Myklebust   NFSv4: Convert nf...
1014
1015
1016
1017
1018
  	if (new == NULL)
  		return ERR_PTR(-ENOMEM);
  	new->sequence = counter;
  	INIT_LIST_HEAD(&new->list);
  	new->task = NULL;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1019
1020
  	return new;
  }
72211dbe7   Trond Myklebust   NFSv4: Release th...
1021
  void nfs_release_seqid(struct nfs_seqid *seqid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  {
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1023
  	struct nfs_seqid_counter *sequence;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1024

a67964197   Trond Myklebust   NFSv4: Check for ...
1025
  	if (seqid == NULL || list_empty(&seqid->list))
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
  		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...
1036
  	}
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1037
  	spin_unlock(&sequence->lock);
72211dbe7   Trond Myklebust   NFSv4: Release th...
1038
1039
1040
1041
1042
  }
  
  void nfs_free_seqid(struct nfs_seqid *seqid)
  {
  	nfs_release_seqid(seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1043
  	kfree(seqid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
  }
  
  /*
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1047
1048
   * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
   * failed with a seqid incrementing error -
16a6ddc70   Toralf Förster   point to the righ...
1049
   * see comments nfs4.h:seqid_mutating_error()
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1050
   */
88d909399   Trond Myklebust   NFSv4: nfs_increm...
1051
  static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1052
1053
1054
1055
1056
  {
  	switch (status) {
  		case 0:
  			break;
  		case -NFS4ERR_BAD_SEQID:
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
1057
1058
  			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
  				return;
9a3ba4323   Trond Myklebust   NFSv4: Rate limit...
1059
  			pr_warn_ratelimited("NFS: v4 server returned a bad"
497799e7c   Dan Muntz   NFS: missing spac...
1060
1061
1062
  					" sequence-id error on an"
  					" unconfirmed sequence %p!
  ",
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
1063
  					seqid->sequence);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1064
1065
1066
1067
1068
1069
  		case -NFS4ERR_STALE_CLIENTID:
  		case -NFS4ERR_STALE_STATEID:
  		case -NFS4ERR_BAD_STATEID:
  		case -NFS4ERR_BADXDR:
  		case -NFS4ERR_RESOURCE:
  		case -NFS4ERR_NOFILEHANDLE:
406dab845   Chuck Lever   nfs: Fix "Don't i...
1070
  		case -NFS4ERR_MOVED:
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1071
1072
  			/* Non-seqid mutating errors */
  			return;
8b98a5324   zhengbin   NFS4: Remove unne...
1073
  	}
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1074
1075
1076
1077
1078
1079
1080
1081
1082
  	/*
  	 * 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)
  {
a67964197   Trond Myklebust   NFSv4: Check for ...
1083
1084
1085
1086
  	struct nfs4_state_owner *sp;
  
  	if (seqid == NULL)
  		return;
34dc1ad75   Benny Halevy   nfs41: increment_...
1087

a67964197   Trond Myklebust   NFSv4: Check for ...
1088
  	sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid);
34dc1ad75   Benny Halevy   nfs41: increment_...
1089
  	if (status == -NFS4ERR_BAD_SEQID)
86cfb0418   NeilBrown   NFS: Don't discon...
1090
  		nfs4_reset_state_owner(sp);
a67964197   Trond Myklebust   NFSv4: Check for ...
1091
  	if (!nfs4_has_session(sp->so_server->nfs_client))
34dc1ad75   Benny Halevy   nfs41: increment_...
1092
  		nfs_increment_seqid(status, seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1093
1094
1095
  }
  
  /*
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1096
1097
   * Increment the seqid if the LOCK/LOCKU succeeded, or
   * failed with a seqid incrementing error -
16a6ddc70   Toralf Förster   point to the righ...
1098
   * see comments nfs4.h:seqid_mutating_error()
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1099
1100
1101
   */
  void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
  {
a67964197   Trond Myklebust   NFSv4: Check for ...
1102
1103
  	if (seqid != NULL)
  		nfs_increment_seqid(status, seqid);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1104
1105
1106
1107
  }
  
  int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
  {
a67964197   Trond Myklebust   NFSv4: Check for ...
1108
  	struct nfs_seqid_counter *sequence;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1109
  	int status = 0;
a67964197   Trond Myklebust   NFSv4: Check for ...
1110
1111
1112
  	if (seqid == NULL)
  		goto out;
  	sequence = seqid->sequence;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1113
  	spin_lock(&sequence->lock);
4601df20f   Trond Myklebust   NFSv4: Avoid thun...
1114
  	seqid->task = task;
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
1115
1116
1117
1118
  	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...
1119
  	rpc_sleep_on(&sequence->wait, task, NULL);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
1120
1121
  	status = -EAGAIN;
  unlock:
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1122
  	spin_unlock(&sequence->lock);
a67964197   Trond Myklebust   NFSv4: Check for ...
1123
  out:
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1124
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
  }
e005e8041   Trond Myklebust   NFSv4: Rename the...
1126
  static int nfs4_run_state_manager(void *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127

e005e8041   Trond Myklebust   NFSv4: Rename the...
1128
  static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1129
  {
4e857c58e   Peter Zijlstra   arch: Mass conver...
1130
  	smp_mb__before_atomic();
e005e8041   Trond Myklebust   NFSv4: Rename the...
1131
  	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
4e857c58e   Peter Zijlstra   arch: Mass conver...
1132
  	smp_mb__after_atomic();
e005e8041   Trond Myklebust   NFSv4: Rename the...
1133
  	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
433fbe4c8   Trond Myklebust   NFSv4: State reco...
1134
1135
  	rpc_wake_up(&clp->cl_rpcwaitq);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
  /*
e005e8041   Trond Myklebust   NFSv4: Rename the...
1137
   * Schedule the nfs_client asynchronous state management routine
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
   */
b0d3ded1a   Trond Myklebust   NFSv4: Clean up n...
1139
  void nfs4_schedule_state_manager(struct nfs_client *clp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
  {
5043e900f   Trond Myklebust   NFS: Convert inst...
1141
  	struct task_struct *task;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1142
  	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143

aeabb3c96   Trond Myklebust   NFSv4: Fix a NFSv...
1144
  	set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
e005e8041   Trond Myklebust   NFSv4: Rename the...
1145
1146
  	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
  		return;
5043e900f   Trond Myklebust   NFS: Convert inst...
1147
  	__module_get(THIS_MODULE);
212bf41d8   Elena Reshetova   fs, nfs: convert ...
1148
  	refcount_inc(&clp->cl_count);
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1149
1150
1151
1152
1153
1154
1155
1156
  
  	/* 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();
f170168b9   Kees Cook   drivers: avoid pa...
1157
  	task = kthread_run(nfs4_run_state_manager, clp, "%s", buf);
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1158
1159
1160
1161
1162
1163
1164
1165
  	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
1166
1167
1168
  }
  
  /*
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1169
   * Schedule a lease recovery attempt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
   */
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1171
  void nfs4_schedule_lease_recovery(struct nfs_client *clp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
  {
  	if (!clp)
  		return;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1175
1176
  	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1177
1178
1179
  	dprintk("%s: scheduling lease recovery for server %s
  ", __func__,
  			clp->cl_hostname);
e005e8041   Trond Myklebust   NFSv4: Rename the...
1180
  	nfs4_schedule_state_manager(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
  }
9cb819683   Andy Adamson   NFSv4.1 handle DS...
1182
  EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183

c9fdeb280   Chuck Lever   NFS: Add basic mi...
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
  /**
   * nfs4_schedule_migration_recovery - trigger migration recovery
   *
   * @server: FSID that is migrating
   *
   * Returns zero if recovery has started, otherwise a negative NFS4ERR
   * value is returned.
   */
  int nfs4_schedule_migration_recovery(const struct nfs_server *server)
  {
  	struct nfs_client *clp = server->nfs_client;
  
  	if (server->fh_expire_type != NFS4_FH_PERSISTENT) {
  		pr_err("NFS: volatile file handles not supported (server %s)
  ",
  				clp->cl_hostname);
  		return -NFS4ERR_IO;
  	}
  
  	if (test_bit(NFS_MIG_FAILED, &server->mig_status))
  		return -NFS4ERR_IO;
  
  	dprintk("%s: scheduling migration recovery for (%llx:%llx) on %s
  ",
  			__func__,
  			(unsigned long long)server->fsid.major,
  			(unsigned long long)server->fsid.minor,
  			clp->cl_hostname);
  
  	set_bit(NFS_MIG_IN_TRANSITION,
  			&((struct nfs_server *)server)->mig_status);
  	set_bit(NFS4CLNT_MOVED, &clp->cl_state);
  
  	nfs4_schedule_state_manager(clp);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(nfs4_schedule_migration_recovery);
b7f7a66e4   Chuck Lever   NFS: Support NFS4...
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  /**
   * nfs4_schedule_lease_moved_recovery - start lease-moved recovery
   *
   * @clp: server to check for moved leases
   *
   */
  void nfs4_schedule_lease_moved_recovery(struct nfs_client *clp)
  {
  	dprintk("%s: scheduling lease-moved recovery for client ID %llx on %s
  ",
  		__func__, clp->cl_clientid, clp->cl_hostname);
  
  	set_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state);
  	nfs4_schedule_state_manager(clp);
  }
  EXPORT_SYMBOL_GPL(nfs4_schedule_lease_moved_recovery);
330212796   Trond Myklebust   NFSv4: Move nfs4_...
1237
1238
1239
1240
1241
  int nfs4_wait_clnt_recover(struct nfs_client *clp)
  {
  	int res;
  
  	might_sleep();
212bf41d8   Elena Reshetova   fs, nfs: convert ...
1242
  	refcount_inc(&clp->cl_count);
743162013   NeilBrown   sched: Remove pro...
1243
1244
  	res = wait_on_bit_action(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
  				 nfs_wait_bit_killable, TASK_KILLABLE);
330212796   Trond Myklebust   NFSv4: Move nfs4_...
1245
  	if (res)
0625c2dd6   Chuck Lever   NFS: Fix possible...
1246
  		goto out;
330212796   Trond Myklebust   NFSv4: Move nfs4_...
1247
  	if (clp->cl_cons_state < 0)
0625c2dd6   Chuck Lever   NFS: Fix possible...
1248
1249
1250
1251
  		res = clp->cl_cons_state;
  out:
  	nfs_put_client(clp);
  	return res;
330212796   Trond Myklebust   NFSv4: Move nfs4_...
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
  }
  
  int nfs4_client_recover_expired_lease(struct nfs_client *clp)
  {
  	unsigned int loop;
  	int ret;
  
  	for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
  		ret = nfs4_wait_clnt_recover(clp);
  		if (ret != 0)
  			break;
  		if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
  		    !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
  			break;
  		nfs4_schedule_state_manager(clp);
  		ret = -EIO;
  	}
  	return ret;
  }
ad1e39682   Trond Myklebust   NFSv4.0: Re-estab...
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  /*
   * 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...
1283
1284
1285
  	dprintk("%s: handling CB_PATHDOWN recovery for server %s
  ", __func__,
  			clp->cl_hostname);
ad1e39682   Trond Myklebust   NFSv4.0: Re-estab...
1286
  }
042b60beb   Trond Myklebust   NFSv4: renewd nee...
1287
1288
  void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
  {
ad1e39682   Trond Myklebust   NFSv4.0: Re-estab...
1289
  	nfs40_handle_cb_pathdown(clp);
042b60beb   Trond Myklebust   NFSv4: renewd nee...
1290
1291
  	nfs4_schedule_state_manager(clp);
  }
f9feab1e1   Trond Myklebust   NFSv4: nfs4_state...
1292
  static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1293
  {
7ebeb7fe7   Trond Myklebust   NFSv4: If recover...
1294
1295
  	if (!nfs4_valid_open_stateid(state))
  		return 0;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1296
1297
1298
1299
1300
1301
  	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...
1302
  	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1303
1304
1305
  	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
  	return 1;
  }
4f14c194a   Trond Myklebust   NFSv4: Clear the ...
1306
  int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1307
  {
7ebeb7fe7   Trond Myklebust   NFSv4: If recover...
1308
1309
  	if (!nfs4_valid_open_stateid(state))
  		return 0;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1310
1311
  	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
  	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1312
  	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1313
1314
1315
  	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
  	return 1;
  }
5d422301f   Trond Myklebust   NFSv4: Fail I/O i...
1316
  int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1317
1318
  {
  	struct nfs_client *clp = server->nfs_client;
7ebeb7fe7   Trond Myklebust   NFSv4: If recover...
1319
  	if (!nfs4_state_mark_reclaim_nograce(clp, state))
5d422301f   Trond Myklebust   NFSv4: Fail I/O i...
1320
  		return -EBADF;
994b15b98   Trond Myklebust   NFSv4.1 fix infin...
1321
1322
  	nfs_inode_find_delegation_state_and_recover(state->inode,
  			&state->stateid);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1323
1324
1325
  	dprintk("%s: scheduling stateid recovery for server %s
  ", __func__,
  			clp->cl_hostname);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1326
  	nfs4_schedule_state_manager(clp);
5d422301f   Trond Myklebust   NFSv4: Fail I/O i...
1327
  	return 0;
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1328
  }
9cb819683   Andy Adamson   NFSv4.1 handle DS...
1329
  EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1330

6c2d8f8d3   Trond Myklebust   NFSv4: nfs_inode_...
1331
1332
1333
1334
1335
1336
1337
1338
1339
  static struct nfs4_lock_state *
  nfs_state_find_lock_state_by_stateid(struct nfs4_state *state,
  		const nfs4_stateid *stateid)
  {
  	struct nfs4_lock_state *pos;
  
  	list_for_each_entry(pos, &state->lock_states, ls_locks) {
  		if (!test_bit(NFS_LOCK_INITIALIZED, &pos->ls_flags))
  			continue;
42c304c34   Trond Myklebust   NFS: nfs_inode_fi...
1340
  		if (nfs4_stateid_match_or_older(&pos->ls_stateid, stateid))
6c2d8f8d3   Trond Myklebust   NFSv4: nfs_inode_...
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
  			return pos;
  	}
  	return NULL;
  }
  
  static bool nfs_state_lock_state_matches_stateid(struct nfs4_state *state,
  		const nfs4_stateid *stateid)
  {
  	bool found = false;
  
  	if (test_bit(LK_STATE_IN_USE, &state->flags)) {
  		spin_lock(&state->state_lock);
  		if (nfs_state_find_lock_state_by_stateid(state, stateid))
  			found = true;
  		spin_unlock(&state->state_lock);
  	}
  	return found;
  }
a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1359
1360
1361
1362
1363
1364
1365
1366
  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;
0de43976f   Trond Myklebust   NFS: Convert look...
1367
1368
  	rcu_read_lock();
  	list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1369
1370
1371
  		state = ctx->state;
  		if (state == NULL)
  			continue;
42c304c34   Trond Myklebust   NFS: nfs_inode_fi...
1372
  		if (nfs4_stateid_match_or_older(&state->stateid, stateid) &&
7ebeb7fe7   Trond Myklebust   NFSv4: If recover...
1373
  		    nfs4_state_mark_reclaim_nograce(clp, state)) {
6c2d8f8d3   Trond Myklebust   NFSv4: nfs_inode_...
1374
  			found = true;
a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1375
  			continue;
6c2d8f8d3   Trond Myklebust   NFSv4: nfs_inode_...
1376
  		}
42c304c34   Trond Myklebust   NFS: nfs_inode_fi...
1377
1378
  		if (test_bit(NFS_OPEN_STATE, &state->flags) &&
  		    nfs4_stateid_match_or_older(&state->open_stateid, stateid) &&
46280d9d3   Trond Myklebust   NFSv4: Check the ...
1379
1380
1381
1382
  		    nfs4_state_mark_reclaim_nograce(clp, state)) {
  			found = true;
  			continue;
  		}
7ebeb7fe7   Trond Myklebust   NFSv4: If recover...
1383
1384
  		if (nfs_state_lock_state_matches_stateid(state, stateid) &&
  		    nfs4_state_mark_reclaim_nograce(clp, state))
6c2d8f8d3   Trond Myklebust   NFSv4: nfs_inode_...
1385
  			found = true;
a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1386
  	}
0de43976f   Trond Myklebust   NFS: Convert look...
1387
  	rcu_read_unlock();
6c2d8f8d3   Trond Myklebust   NFSv4: nfs_inode_...
1388
1389
  
  	nfs_inode_find_delegation_state_and_recover(inode, stateid);
a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1390
1391
1392
  	if (found)
  		nfs4_schedule_state_manager(clp);
  }
86dbd08b3   Trond Myklebust   NFSv4: Print an e...
1393
  static void nfs4_state_mark_open_context_bad(struct nfs4_state *state, int err)
c58c84418   Trond Myklebust   NFS: Don't accept...
1394
1395
1396
1397
  {
  	struct inode *inode = state->inode;
  	struct nfs_inode *nfsi = NFS_I(inode);
  	struct nfs_open_context *ctx;
0de43976f   Trond Myklebust   NFS: Convert look...
1398
1399
  	rcu_read_lock();
  	list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
c58c84418   Trond Myklebust   NFS: Don't accept...
1400
1401
1402
  		if (ctx->state != state)
  			continue;
  		set_bit(NFS_CONTEXT_BAD, &ctx->flags);
86dbd08b3   Trond Myklebust   NFSv4: Print an e...
1403
1404
1405
  		pr_warn("NFSv4: state recovery failed for open file %pd2, "
  				"error = %d
  ", ctx->dentry, err);
c58c84418   Trond Myklebust   NFS: Don't accept...
1406
  	}
0de43976f   Trond Myklebust   NFS: Convert look...
1407
  	rcu_read_unlock();
c58c84418   Trond Myklebust   NFS: Don't accept...
1408
  }
5d422301f   Trond Myklebust   NFSv4: Fail I/O i...
1409
1410
1411
  static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
  {
  	set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags);
86dbd08b3   Trond Myklebust   NFSv4: Print an e...
1412
  	nfs4_state_mark_open_context_bad(state, error);
5d422301f   Trond Myklebust   NFSv4: Fail I/O i...
1413
  }
a1d0b5eeb   Trond Myklebust   NFS: Properly han...
1414

028600143   Trond Myklebust   NFSv4: Clean up f...
1415
  static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
1417
  {
  	struct inode *inode = state->inode;
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1418
  	struct nfs_inode *nfsi = NFS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
  	struct file_lock *fl;
dce2630c7   NeilBrown   NFSv4: always set...
1420
  	struct nfs4_lock_state *lsp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
  	int status = 0;
5263e31e4   Jeff Layton   locks: move flock...
1422
  	struct file_lock_context *flctx = inode->i_flctx;
bd61e0a9c   Jeff Layton   locks: convert po...
1423
  	struct list_head *list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1424

bd61e0a9c   Jeff Layton   locks: convert po...
1425
  	if (flctx == NULL)
3f09df70e   Trond Myklebust   NFS: Ensure we al...
1426
  		return 0;
bd61e0a9c   Jeff Layton   locks: convert po...
1427
  	list = &flctx->flc_posix;
3f09df70e   Trond Myklebust   NFS: Ensure we al...
1428
  	/* Guard against delegation returns and new lock/unlock calls */
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1429
  	down_write(&nfsi->rwsem);
6109c8503   Jeff Layton   locks: add a dedi...
1430
  	spin_lock(&flctx->flc_lock);
bd61e0a9c   Jeff Layton   locks: convert po...
1431
1432
  restart:
  	list_for_each_entry(fl, list, fl_list) {
5263e31e4   Jeff Layton   locks: move flock...
1433
1434
  		if (nfs_file_open_context(fl->fl_file)->state != state)
  			continue;
6109c8503   Jeff Layton   locks: add a dedi...
1435
  		spin_unlock(&flctx->flc_lock);
5263e31e4   Jeff Layton   locks: move flock...
1436
1437
1438
1439
  		status = ops->recover_lock(state, fl);
  		switch (status) {
  		case 0:
  			break;
67e7b52d4   Trond Myklebust   NFSv4: Ensure sta...
1440
  		case -ETIMEDOUT:
5263e31e4   Jeff Layton   locks: move flock...
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
  		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:
  		case -NFS4ERR_BADSESSION:
  		case -NFS4ERR_BADSLOT:
  		case -NFS4ERR_BAD_HIGH_SLOT:
  		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  			goto out;
  		default:
  			pr_err("NFS: %s: unhandled error %d
  ",
  					__func__, status);
df561f668   Gustavo A. R. Silva   treewide: Use fal...
1457
  			fallthrough;
5263e31e4   Jeff Layton   locks: move flock...
1458
1459
1460
1461
  		case -ENOMEM:
  		case -NFS4ERR_DENIED:
  		case -NFS4ERR_RECLAIM_BAD:
  		case -NFS4ERR_RECLAIM_CONFLICT:
dce2630c7   NeilBrown   NFSv4: always set...
1462
1463
1464
  			lsp = fl->fl_u.nfs4_fl.owner;
  			if (lsp)
  				set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
5263e31e4   Jeff Layton   locks: move flock...
1465
1466
  			status = 0;
  		}
6109c8503   Jeff Layton   locks: add a dedi...
1467
  		spin_lock(&flctx->flc_lock);
5263e31e4   Jeff Layton   locks: move flock...
1468
  	}
bd61e0a9c   Jeff Layton   locks: convert po...
1469
1470
1471
1472
  	if (list == &flctx->flc_posix) {
  		list = &flctx->flc_flock;
  		goto restart;
  	}
6109c8503   Jeff Layton   locks: add a dedi...
1473
  	spin_unlock(&flctx->flc_lock);
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1474
  out:
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
1475
  	up_write(&nfsi->rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
1477
  	return status;
  }
80f423688   Anna Schumaker   NFSv4: Split out ...
1478
1479
1480
1481
  #ifdef CONFIG_NFS_V4_2
  static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state *state)
  {
  	struct nfs4_copy_state *copy;
0e65a32c8   Olga Kornievskaia   NFS: handle sourc...
1482
1483
  	if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
  		!test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags))
80f423688   Anna Schumaker   NFSv4: Split out ...
1484
1485
1486
1487
  		return;
  
  	spin_lock(&sp->so_server->nfs_client->cl_lock);
  	list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
0e65a32c8   Olga Kornievskaia   NFS: handle sourc...
1488
1489
1490
1491
  		if ((test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
  				!nfs4_stateid_match_other(&state->stateid,
  				&copy->parent_dst_state->stateid)))
  				continue;
80f423688   Anna Schumaker   NFSv4: Split out ...
1492
  		copy->flags = 1;
0e65a32c8   Olga Kornievskaia   NFS: handle sourc...
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  		if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
  				&state->flags)) {
  			clear_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags);
  			complete(&copy->completion);
  		}
  	}
  	list_for_each_entry(copy, &sp->so_server->ss_copies, src_copies) {
  		if ((test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags) &&
  				!nfs4_stateid_match_other(&state->stateid,
  				&copy->parent_src_state->stateid)))
  				continue;
  		copy->flags = 1;
  		if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
  				&state->flags))
  			complete(&copy->completion);
80f423688   Anna Schumaker   NFSv4: Split out ...
1508
1509
1510
1511
1512
1513
1514
1515
1516
  	}
  	spin_unlock(&sp->so_server->nfs_client->cl_lock);
  }
  #else /* !CONFIG_NFS_V4_2 */
  static inline void nfs42_complete_copies(struct nfs4_state_owner *sp,
  					 struct nfs4_state *state)
  {
  }
  #endif /* CONFIG_NFS_V4_2 */
cb7a8384d   Anna Schumaker   NFS: Split out th...
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
  static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_state *state,
  				     const struct nfs4_state_recovery_ops *ops)
  {
  	struct nfs4_lock_state *lock;
  	int status;
  
  	status = ops->recover_open(sp, state);
  	if (status < 0)
  		return status;
  
  	status = nfs4_reclaim_locks(state, ops);
  	if (status < 0)
  		return status;
  
  	if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) {
  		spin_lock(&state->state_lock);
  		list_for_each_entry(lock, &state->lock_states, ls_locks) {
21f86d2d6   Chuck Lever   NFS4: Trace lock ...
1534
  			trace_nfs4_state_lock_reclaim(state, lock);
cb7a8384d   Anna Schumaker   NFS: Split out th...
1535
1536
1537
1538
1539
1540
  			if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
  				pr_warn_ratelimited("NFS: %s: Lock reclaim failed!
  ", __func__);
  		}
  		spin_unlock(&state->state_lock);
  	}
80f423688   Anna Schumaker   NFSv4: Split out ...
1541
  	nfs42_complete_copies(sp, state);
cb7a8384d   Anna Schumaker   NFS: Split out th...
1542
1543
1544
  	clear_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
  	return status;
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1545
  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
1546
1547
  {
  	struct nfs4_state *state;
c34fae003   Trond Myklebust   NFSv4: When recov...
1548
  	unsigned int loop = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
  	int status = 0;
0b9018b9c   Olga Kornievskaia   NFS: skip recover...
1550
1551
1552
  #ifdef CONFIG_NFS_V4_2
  	bool found_ssc_copy_state = false;
  #endif /* CONFIG_NFS_V4_2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
1554
1555
1556
1557
1558
1559
1560
1561
  
  	/* 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...
1562
  	spin_lock(&sp->so_lock);
abbec2da1   Trond Myklebust   NFS: Use raw_writ...
1563
  	raw_write_seqcount_begin(&sp->so_reclaim_seqcount);
c137afabe   Trond Myklebust   NFSv4: Allow the ...
1564
  restart:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
  	list_for_each_entry(state, &sp->so_states, open_states) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1566
1567
  		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
  			continue;
5d422301f   Trond Myklebust   NFSv4: Fail I/O i...
1568
1569
  		if (!nfs4_valid_open_stateid(state))
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
1571
  		if (state->state == 0)
  			continue;
0b9018b9c   Olga Kornievskaia   NFS: skip recover...
1572
1573
1574
1575
1576
1577
1578
  #ifdef CONFIG_NFS_V4_2
  		if (test_bit(NFS_SRV_SSC_COPY_STATE, &state->flags)) {
  			nfs4_state_mark_recovery_failed(state, -EIO);
  			found_ssc_copy_state = true;
  			continue;
  		}
  #endif /* CONFIG_NFS_V4_2 */
ace9fad43   Trond Myklebust   NFSv4: Convert st...
1579
  		refcount_inc(&state->count);
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1580
  		spin_unlock(&sp->so_lock);
cb7a8384d   Anna Schumaker   NFS: Split out th...
1581
  		status = __nfs4_reclaim_open_state(sp, state, ops);
cb7a8384d   Anna Schumaker   NFS: Split out th...
1582

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
  		switch (status) {
35a61606a   Anna Schumaker   NFS: Reduce inden...
1584
  		default:
c34fae003   Trond Myklebust   NFSv4: When recov...
1585
1586
  			if (status >= 0) {
  				loop = 0;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1587
  				break;
c34fae003   Trond Myklebust   NFSv4: When recov...
1588
  			}
35a61606a   Anna Schumaker   NFS: Reduce inden...
1589
1590
  			printk(KERN_ERR "NFS: %s: unhandled error %d
  ", __func__, status);
df561f668   Gustavo A. R. Silva   treewide: Use fal...
1591
  			fallthrough;
35a61606a   Anna Schumaker   NFS: Reduce inden...
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
  		case -ENOENT:
  		case -ENOMEM:
  		case -EACCES:
  		case -EROFS:
  		case -EIO:
  		case -ESTALE:
  			/* Open state on this file cannot be recovered */
  			nfs4_state_mark_recovery_failed(state, status);
  			break;
  		case -EAGAIN:
  			ssleep(1);
c34fae003   Trond Myklebust   NFSv4: When recov...
1603
1604
1605
1606
  			if (loop++ < 10) {
  				set_bit(ops->state_flag_bit, &state->flags);
  				break;
  			}
df561f668   Gustavo A. R. Silva   treewide: Use fal...
1607
  			fallthrough;
35a61606a   Anna Schumaker   NFS: Reduce inden...
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
  		case -NFS4ERR_ADMIN_REVOKED:
  		case -NFS4ERR_STALE_STATEID:
  		case -NFS4ERR_OLD_STATEID:
  		case -NFS4ERR_BAD_STATEID:
  		case -NFS4ERR_RECLAIM_BAD:
  		case -NFS4ERR_RECLAIM_CONFLICT:
  			nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
  			break;
  		case -NFS4ERR_EXPIRED:
  		case -NFS4ERR_NO_GRACE:
  			nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
df561f668   Gustavo A. R. Silva   treewide: Use fal...
1619
  			fallthrough;
35a61606a   Anna Schumaker   NFS: Reduce inden...
1620
1621
1622
1623
1624
  		case -NFS4ERR_STALE_CLIENTID:
  		case -NFS4ERR_BADSESSION:
  		case -NFS4ERR_BADSLOT:
  		case -NFS4ERR_BAD_HIGH_SLOT:
  		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
67e7b52d4   Trond Myklebust   NFSv4: Ensure sta...
1625
  		case -ETIMEDOUT:
35a61606a   Anna Schumaker   NFS: Reduce inden...
1626
  			goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1627
  		}
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1628
  		nfs4_put_open_state(state);
c137afabe   Trond Myklebust   NFSv4: Allow the ...
1629
  		spin_lock(&sp->so_lock);
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1630
  		goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631
  	}
abbec2da1   Trond Myklebust   NFS: Use raw_writ...
1632
  	raw_write_seqcount_end(&sp->so_reclaim_seqcount);
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1633
  	spin_unlock(&sp->so_lock);
0b9018b9c   Olga Kornievskaia   NFS: skip recover...
1634
1635
1636
1637
  #ifdef CONFIG_NFS_V4_2
  	if (found_ssc_copy_state)
  		return -EIO;
  #endif /* CONFIG_NFS_V4_2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1638
1639
  	return 0;
  out_err:
fe1d81952   Trond Myklebust   NFSv4: Ensure tha...
1640
  	nfs4_put_open_state(state);
c137afabe   Trond Myklebust   NFSv4: Allow the ...
1641
  	spin_lock(&sp->so_lock);
abbec2da1   Trond Myklebust   NFS: Use raw_writ...
1642
  	raw_write_seqcount_end(&sp->so_reclaim_seqcount);
c137afabe   Trond Myklebust   NFSv4: Allow the ...
1643
  	spin_unlock(&sp->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
  	return status;
  }
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1646
1647
1648
1649
1650
1651
1652
1653
  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...
1654
  	spin_lock(&state->state_lock);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1655
  	list_for_each_entry(lock, &state->lock_states, ls_locks) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1656
  		lock->ls_seqid.flags = 0;
795a88c96   Trond Myklebust   NFSv4: Convert th...
1657
  		clear_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1658
  	}
4b44b40e0   Trond Myklebust   NFSv4: Ensure cor...
1659
  	spin_unlock(&state->state_lock);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1660
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
1661
1662
  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...
1663
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1664
  	struct nfs_client *clp = server->nfs_client;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1665
  	struct nfs4_state_owner *sp;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
1666
  	struct rb_node *pos;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1667
  	struct nfs4_state *state;
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1668

24d292b89   Chuck Lever   NFS: Move cl_stat...
1669
1670
1671
1672
1673
  	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...
1674
  		sp->so_seqid.flags = 0;
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
1675
  		spin_lock(&sp->so_lock);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1676
  		list_for_each_entry(state, &sp->so_states, open_states) {
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1677
1678
  			if (mark_reclaim(clp, state))
  				nfs4_clear_open_state(state);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1679
  		}
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
1680
  		spin_unlock(&sp->so_lock);
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1681
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
  	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...
1694
  }
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1695
1696
1697
1698
1699
1700
  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);
  }
0048fdd06   Trond Myklebust   NFSv4.1: RECLAIM_...
1701
  static int nfs4_reclaim_complete(struct nfs_client *clp,
965e9c23d   Trond Myklebust   NFSv4.1: Ensure t...
1702
  				 const struct nfs4_state_recovery_ops *ops,
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1703
  				 const struct cred *cred)
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
1704
1705
1706
  {
  	/* Notify the server we're done reclaiming our state */
  	if (ops->reclaim_complete)
0048fdd06   Trond Myklebust   NFSv4.1: RECLAIM_...
1707
1708
  		return ops->reclaim_complete(clp, cred);
  	return 0;
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
1709
  }
24d292b89   Chuck Lever   NFS: Move cl_stat...
1710
  static void nfs4_clear_reclaim_server(struct nfs_server *server)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1711
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1712
  	struct nfs_client *clp = server->nfs_client;
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1713
1714
1715
  	struct nfs4_state_owner *sp;
  	struct rb_node *pos;
  	struct nfs4_state *state;
24d292b89   Chuck Lever   NFS: Move cl_stat...
1716
1717
1718
1719
1720
  	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 ...
1721
1722
  		spin_lock(&sp->so_lock);
  		list_for_each_entry(state, &sp->so_states, open_states) {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1723
1724
  			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT,
  						&state->flags))
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1725
1726
1727
1728
1729
  				continue;
  			nfs4_state_mark_reclaim_nograce(clp, state);
  		}
  		spin_unlock(&sp->so_lock);
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
  	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 ...
1744
1745
  
  	nfs_delegation_reap_unclaimed(clp);
6eaa61496   Trond Myklebust   NFSv4: Don't call...
1746
1747
1748
1749
1750
  	return 1;
  }
  
  static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
  {
965e9c23d   Trond Myklebust   NFSv4.1: Ensure t...
1751
  	const struct nfs4_state_recovery_ops *ops;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1752
  	const struct cred *cred;
0048fdd06   Trond Myklebust   NFSv4.1: RECLAIM_...
1753
  	int err;
965e9c23d   Trond Myklebust   NFSv4.1: Ensure t...
1754

6eaa61496   Trond Myklebust   NFSv4: Don't call...
1755
1756
  	if (!nfs4_state_clear_reclaim_reboot(clp))
  		return;
965e9c23d   Trond Myklebust   NFSv4.1: Ensure t...
1757
  	ops = clp->cl_mvops->reboot_recovery_ops;
73d8bde5e   Chuck Lever   NFS: Never use us...
1758
  	cred = nfs4_get_clid_cred(clp);
0048fdd06   Trond Myklebust   NFSv4.1: RECLAIM_...
1759
  	err = nfs4_reclaim_complete(clp, ops, cred);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1760
  	put_cred(cred);
0048fdd06   Trond Myklebust   NFSv4.1: RECLAIM_...
1761
1762
  	if (err == -NFS4ERR_CONN_NOT_BOUND_TO_SESSION)
  		set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1763
  }
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1764
1765
  static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
  {
45870d690   Trond Myklebust   NFSv4.1: Test del...
1766
  	nfs_mark_test_expired_all_delegations(clp);
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
1767
1768
  	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
  }
4f7cdf18e   Trond Myklebust   NFSv4: The state ...
1769
  static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
e598d843c   Trond Myklebust   NFSv4: Remove red...
1770
1771
  {
  	switch (error) {
000d3f956   Anna Schumaker   NFS: Reduce inden...
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
  	case 0:
  		break;
  	case -NFS4ERR_CB_PATH_DOWN:
  		nfs40_handle_cb_pathdown(clp);
  		break;
  	case -NFS4ERR_NO_GRACE:
  		nfs4_state_end_reclaim_reboot(clp);
  		break;
  	case -NFS4ERR_STALE_CLIENTID:
  		set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
  		nfs4_state_start_reclaim_reboot(clp);
  		break;
  	case -NFS4ERR_EXPIRED:
  		set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
  		nfs4_state_start_reclaim_nograce(clp);
  		break;
  	case -NFS4ERR_BADSESSION:
  	case -NFS4ERR_BADSLOT:
  	case -NFS4ERR_BAD_HIGH_SLOT:
  	case -NFS4ERR_DEADSESSION:
  	case -NFS4ERR_SEQ_FALSE_RETRY:
  	case -NFS4ERR_SEQ_MISORDERED:
  		set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
  		/* Zero session reset errors */
  		break;
  	case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
  		break;
  	default:
  		dprintk("%s: failed to handle error %d for server %s
  ",
  				__func__, error, clp->cl_hostname);
  		return error;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1805
  	}
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1806
1807
1808
  	dprintk("%s: handled error %d for server %s
  ", __func__, error,
  			clp->cl_hostname);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1809
  	return 0;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1810
  }
028600143   Trond Myklebust   NFSv4: Clean up f...
1811
  static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1812
  {
24d292b89   Chuck Lever   NFS: Move cl_stat...
1813
1814
  	struct nfs4_state_owner *sp;
  	struct nfs_server *server;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
1815
  	struct rb_node *pos;
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
1816
  	LIST_HEAD(freeme);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
  	int status = 0;
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1818
  restart:
24d292b89   Chuck Lever   NFS: Move cl_stat...
1819
1820
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
1821
  		nfs4_purge_state_owners(server, &freeme);
24d292b89   Chuck Lever   NFS: Move cl_stat...
1822
1823
1824
1825
1826
1827
1828
1829
1830
  		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;
4a0954ef3   Trond Myklebust   NFSv4: Don't try ...
1831
1832
  			if (!atomic_inc_not_zero(&sp->so_count))
  				continue;
24d292b89   Chuck Lever   NFS: Move cl_stat...
1833
1834
1835
1836
1837
1838
1839
  			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);
df817ba35   Trond Myklebust   NFSv4: fix open/l...
1840
1841
  				status = nfs4_recovery_handle_error(clp, status);
  				return (status != 0) ? status : -EAGAIN;
24d292b89   Chuck Lever   NFS: Move cl_stat...
1842
  			}
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1843
  			nfs4_put_state_owner(sp);
24d292b89   Chuck Lever   NFS: Move cl_stat...
1844
  			goto restart;
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
1845
  		}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1846
  		spin_unlock(&clp->cl_lock);
028600143   Trond Myklebust   NFSv4: Clean up f...
1847
  	}
24d292b89   Chuck Lever   NFS: Move cl_stat...
1848
  	rcu_read_unlock();
c77e22834   Trond Myklebust   NFSv4: Fix a pote...
1849
  	nfs4_free_state_owners(&freeme);
df817ba35   Trond Myklebust   NFSv4: fix open/l...
1850
  	return 0;
028600143   Trond Myklebust   NFSv4: Clean up f...
1851
1852
1853
1854
  }
  
  static int nfs4_check_lease(struct nfs_client *clp)
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1855
  	const struct cred *cred;
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1856
1857
  	const struct nfs4_state_maintenance_ops *ops =
  		clp->cl_mvops->state_renewal_ops;
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1858
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859

0f605b560   Trond Myklebust   NFSv4: Don't tell...
1860
1861
1862
  	/* Is the client already known to have an expired lease? */
  	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  		return 0;
f15e1e8bc   NeilBrown   NFSv4: don't requ...
1863
  	cred = ops->get_state_renewal_cred(clp);
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1864
  	if (cred == NULL) {
73d8bde5e   Chuck Lever   NFS: Never use us...
1865
  		cred = nfs4_get_clid_cred(clp);
4f38e4aad   Trond Myklebust   NFSv4: Don't erro...
1866
  		status = -ENOKEY;
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1867
1868
  		if (cred == NULL)
  			goto out;
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
1869
  	}
8e69514f2   Benny Halevy   nfs41: support mi...
1870
  	status = ops->renew_lease(clp, cred);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1871
  	put_cred(cred);
bc7a05ca5   Trond Myklebust   NFSv4: Handle tim...
1872
1873
1874
1875
  	if (status == -ETIMEDOUT) {
  		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
  		return 0;
  	}
0f605b560   Trond Myklebust   NFSv4: Don't tell...
1876
  out:
4f7cdf18e   Trond Myklebust   NFSv4: The state ...
1877
  	return nfs4_recovery_handle_error(clp, status);
028600143   Trond Myklebust   NFSv4: Clean up f...
1878
  }
47b803c8d   Andy Adamson   NFSv4.0 reclaim r...
1879
1880
  /* 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...
1881
1882
1883
1884
   */
  static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
  {
  	switch (status) {
89a217360   Trond Myklebust   NFSv4.1: Handle N...
1885
1886
1887
1888
1889
  	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...
1890
1891
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
  		break;
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1892
1893
  	case -NFS4ERR_STALE_CLIENTID:
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
47b803c8d   Andy Adamson   NFSv4.0 reclaim r...
1894
  		nfs4_state_start_reclaim_reboot(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1895
  		break;
de7348312   Chuck Lever   NFS: Treat NFS4ER...
1896
1897
1898
1899
1900
1901
1902
  	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...
1903
  	case -EACCES:
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1904
  	case -NFS4ERR_DELAY:
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1905
1906
1907
1908
1909
1910
1911
  	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...
1912
1913
1914
  		dprintk("%s: exit with error %d for server %s
  ",
  				__func__, -EPROTONOSUPPORT, clp->cl_hostname);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1915
  		return -EPROTONOSUPPORT;
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1916
1917
1918
  	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
  				 * in nfs4_exchange_id */
  	default:
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1919
1920
1921
  		dprintk("%s: exit with error %d for server %s
  ", __func__,
  				status, clp->cl_hostname);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1922
1923
1924
  		return status;
  	}
  	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
1925
1926
1927
  	dprintk("%s: handled error %d for server %s
  ", __func__, status,
  			clp->cl_hostname);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1928
1929
  	return 0;
  }
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1930
  static int nfs4_establish_lease(struct nfs_client *clp)
028600143   Trond Myklebust   NFSv4: Clean up f...
1931
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1932
  	const struct cred *cred;
c48f4f354   Trond Myklebust   NFSv41: Convert t...
1933
1934
  	const struct nfs4_state_recovery_ops *ops =
  		clp->cl_mvops->reboot_recovery_ops;
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1935
  	int status;
028600143   Trond Myklebust   NFSv4: Clean up f...
1936

8aafd2fde   Trond Myklebust   NFSv4: Don't busy...
1937
1938
1939
  	status = nfs4_begin_drain_session(clp);
  	if (status != 0)
  		return status;
73d8bde5e   Chuck Lever   NFS: Never use us...
1940
  	cred = nfs4_get_clid_cred(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1941
1942
1943
  	if (cred == NULL)
  		return -ENOENT;
  	status = ops->establish_clid(clp, cred);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1944
  	put_cred(cred);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
1945
  	if (status != 0)
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1946
1947
1948
1949
  		return status;
  	pnfs_destroy_all_layouts(clp);
  	return 0;
  }
6bbb4ae8f   Chuck Lever   NFS: Clean up nfs...
1950
1951
1952
1953
  /*
   * Returns zero or a negative errno.  NFS4ERR values are converted
   * to local errno values.
   */
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
  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...
1976
  		return nfs4_handle_reclaim_lease_error(clp, status);
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
1977
1978
1979
  	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...
1980
  	return 0;
028600143   Trond Myklebust   NFSv4: Clean up f...
1981
  }
c9fdeb280   Chuck Lever   NFS: Add basic mi...
1982
1983
1984
1985
1986
1987
1988
  /*
   * Try remote migration of one FSID from a source server to a
   * destination server.  The source server provides a list of
   * potential destinations.
   *
   * Returns zero or a negative NFS4ERR status code.
   */
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
1989
  static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred)
c9fdeb280   Chuck Lever   NFS: Add basic mi...
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
  {
  	struct nfs_client *clp = server->nfs_client;
  	struct nfs4_fs_locations *locations = NULL;
  	struct inode *inode;
  	struct page *page;
  	int status, result;
  
  	dprintk("--> %s: FSID %llx:%llx on \"%s\"
  ", __func__,
  			(unsigned long long)server->fsid.major,
  			(unsigned long long)server->fsid.minor,
  			clp->cl_hostname);
  
  	result = 0;
  	page = alloc_page(GFP_KERNEL);
  	locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
  	if (page == NULL || locations == NULL) {
  		dprintk("<-- %s: no memory
  ", __func__);
  		goto out;
  	}
2b0143b5c   David Howells   VFS: normal files...
2011
  	inode = d_inode(server->super->s_root);
c9fdeb280   Chuck Lever   NFS: Add basic mi...
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
  	result = nfs4_proc_get_locations(inode, locations, page, cred);
  	if (result) {
  		dprintk("<-- %s: failed to retrieve fs_locations: %d
  ",
  			__func__, result);
  		goto out;
  	}
  
  	result = -NFS4ERR_NXIO;
  	if (!(locations->fattr.valid & NFS_ATTR_FATTR_V4_LOCATIONS)) {
  		dprintk("<-- %s: No fs_locations data, migration skipped
  ",
  			__func__);
  		goto out;
  	}
8aafd2fde   Trond Myklebust   NFSv4: Don't busy...
2027
  	status = nfs4_begin_drain_session(clp);
1e672e364   Wenwen Wang   NFSv4: Fix a memo...
2028
2029
2030
2031
  	if (status != 0) {
  		result = status;
  		goto out;
  	}
c9fdeb280   Chuck Lever   NFS: Add basic mi...
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
  
  	status = nfs4_replace_transport(server, locations);
  	if (status != 0) {
  		dprintk("<-- %s: failed to replace transport: %d
  ",
  			__func__, status);
  		goto out;
  	}
  
  	result = 0;
  	dprintk("<-- %s: migration succeeded
  ", __func__);
  
  out:
  	if (page != NULL)
  		__free_page(page);
  	kfree(locations);
  	if (result) {
  		pr_err("NFS: migration recovery failed (server %s)
  ",
  				clp->cl_hostname);
  		set_bit(NFS_MIG_FAILED, &server->mig_status);
  	}
  	return result;
  }
  
  /*
   * Returns zero or a negative NFS4ERR status code.
   */
  static int nfs4_handle_migration(struct nfs_client *clp)
  {
  	const struct nfs4_state_maintenance_ops *ops =
  				clp->cl_mvops->state_renewal_ops;
  	struct nfs_server *server;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2066
  	const struct cred *cred;
c9fdeb280   Chuck Lever   NFS: Add basic mi...
2067
2068
2069
2070
  
  	dprintk("%s: migration reported on \"%s\"
  ", __func__,
  			clp->cl_hostname);
f15e1e8bc   NeilBrown   NFSv4: don't requ...
2071
  	cred = ops->get_state_renewal_cred(clp);
c9fdeb280   Chuck Lever   NFS: Add basic mi...
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
  	if (cred == NULL)
  		return -NFS4ERR_NOENT;
  
  	clp->cl_mig_gen++;
  restart:
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
  		int status;
  
  		if (server->mig_gen == clp->cl_mig_gen)
  			continue;
  		server->mig_gen = clp->cl_mig_gen;
  
  		if (!test_and_clear_bit(NFS_MIG_IN_TRANSITION,
  						&server->mig_status))
  			continue;
  
  		rcu_read_unlock();
  		status = nfs4_try_migration(server, cred);
  		if (status < 0) {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2092
  			put_cred(cred);
c9fdeb280   Chuck Lever   NFS: Add basic mi...
2093
2094
2095
2096
2097
  			return status;
  		}
  		goto restart;
  	}
  	rcu_read_unlock();
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2098
  	put_cred(cred);
c9fdeb280   Chuck Lever   NFS: Add basic mi...
2099
2100
  	return 0;
  }
b7f7a66e4   Chuck Lever   NFS: Support NFS4...
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
  /*
   * Test each nfs_server on the clp's cl_superblocks list to see
   * if it's moved to another server.  Stop when the server no longer
   * returns NFS4ERR_LEASE_MOVED.
   */
  static int nfs4_handle_lease_moved(struct nfs_client *clp)
  {
  	const struct nfs4_state_maintenance_ops *ops =
  				clp->cl_mvops->state_renewal_ops;
  	struct nfs_server *server;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2111
  	const struct cred *cred;
b7f7a66e4   Chuck Lever   NFS: Support NFS4...
2112
2113
2114
2115
  
  	dprintk("%s: lease moved reported on \"%s\"
  ", __func__,
  			clp->cl_hostname);
f15e1e8bc   NeilBrown   NFSv4: don't requ...
2116
  	cred = ops->get_state_renewal_cred(clp);
b7f7a66e4   Chuck Lever   NFS: Support NFS4...
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
  	if (cred == NULL)
  		return -NFS4ERR_NOENT;
  
  	clp->cl_mig_gen++;
  restart:
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
  		struct inode *inode;
  		int status;
  
  		if (server->mig_gen == clp->cl_mig_gen)
  			continue;
  		server->mig_gen = clp->cl_mig_gen;
  
  		rcu_read_unlock();
2b0143b5c   David Howells   VFS: normal files...
2132
  		inode = d_inode(server->super->s_root);
b7f7a66e4   Chuck Lever   NFS: Support NFS4...
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
  		status = nfs4_proc_fsid_present(inode, cred);
  		if (status != -NFS4ERR_MOVED)
  			goto restart;	/* wasn't this one */
  		if (nfs4_try_migration(server, cred) == -NFS4ERR_LEASE_MOVED)
  			goto restart;	/* there are more */
  		goto out;
  	}
  	rcu_read_unlock();
  
  out:
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2143
  	put_cred(cred);
b7f7a66e4   Chuck Lever   NFS: Support NFS4...
2144
2145
  	return 0;
  }
05f4c350e   Chuck Lever   NFS: Discover NFS...
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
  /**
   * 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;
05f4c350e   Chuck Lever   NFS: Discover NFS...
2164
  	struct rpc_clnt *clnt;
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2165
  	const struct cred *cred;
4edaa3088   Chuck Lever   NFS: Use "krb5i" ...
2166
  	int i, status;
05f4c350e   Chuck Lever   NFS: Discover NFS...
2167
2168
2169
  
  	dprintk("NFS: %s: testing '%s'
  ", __func__, clp->cl_hostname);
05f4c350e   Chuck Lever   NFS: Discover NFS...
2170
  	clnt = clp->cl_rpcclient;
05f4c350e   Chuck Lever   NFS: Discover NFS...
2171
2172
2173
  	i = 0;
  
  	mutex_lock(&nfs_clid_init_mutex);
05f4c350e   Chuck Lever   NFS: Discover NFS...
2174
  again:
ea33e6c3e   Trond Myklebust   NFSv4: Fix issues...
2175
  	status  = -ENOENT;
73d8bde5e   Chuck Lever   NFS: Never use us...
2176
  	cred = nfs4_get_clid_cred(clp);
05f4c350e   Chuck Lever   NFS: Discover NFS...
2177
2178
2179
2180
  	if (cred == NULL)
  		goto out_unlock;
  
  	status = ops->detect_trunking(clp, result, cred);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2181
  	put_cred(cred);
05f4c350e   Chuck Lever   NFS: Discover NFS...
2182
2183
  	switch (status) {
  	case 0:
898fc11bb   Trond Myklebust   NFS: Trunking det...
2184
2185
  	case -EINTR:
  	case -ERESTARTSYS:
05f4c350e   Chuck Lever   NFS: Discover NFS...
2186
  		break;
05f4c350e   Chuck Lever   NFS: Discover NFS...
2187
  	case -ETIMEDOUT:
150e7260f   Trond Myklebust   NFSv4: Ensure we ...
2188
2189
  		if (clnt->cl_softrtry)
  			break;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
2190
  		fallthrough;
150e7260f   Trond Myklebust   NFSv4: Ensure we ...
2191
  	case -NFS4ERR_DELAY:
05f4c350e   Chuck Lever   NFS: Discover NFS...
2192
2193
  	case -EAGAIN:
  		ssleep(1);
df561f668   Gustavo A. R. Silva   treewide: Use fal...
2194
  		fallthrough;
202c312db   Trond Myklebust   NFSv4: Fix NFSv4 ...
2195
  	case -NFS4ERR_STALE_CLIENTID:
05f4c350e   Chuck Lever   NFS: Discover NFS...
2196
2197
2198
2199
  		dprintk("NFS: %s after status %d, retrying
  ",
  			__func__, status);
  		goto again;
4edaa3088   Chuck Lever   NFS: Use "krb5i" ...
2200
  	case -EACCES:
d688f7b8f   Chuck Lever   NFS: Use root's c...
2201
2202
2203
2204
  		if (i++ == 0) {
  			nfs4_root_machine_cred(clp);
  			goto again;
  		}
6d769f1e1   Jeff Layton   nfs: don't retry ...
2205
  		if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX)
4edaa3088   Chuck Lever   NFS: Use "krb5i" ...
2206
  			break;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
2207
  		fallthrough;
05f4c350e   Chuck Lever   NFS: Discover NFS...
2208
2209
  	case -NFS4ERR_CLID_INUSE:
  	case -NFS4ERR_WRONGSEC:
6d769f1e1   Jeff Layton   nfs: don't retry ...
2210
2211
2212
2213
2214
  		/* No point in retrying if we already used RPC_AUTH_UNIX */
  		if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX) {
  			status = -EPERM;
  			break;
  		}
79d852bf5   Chuck Lever   NFS: Retry SETCLI...
2215
  		clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
05f4c350e   Chuck Lever   NFS: Discover NFS...
2216
2217
2218
2219
  		if (IS_ERR(clnt)) {
  			status = PTR_ERR(clnt);
  			break;
  		}
b193d59a4   Trond Myklebust   NFSv4: Fix a memo...
2220
2221
2222
2223
2224
2225
2226
  		/* Note: this is safe because we haven't yet marked the
  		 * client as ready, so we are the only user of
  		 * clp->cl_rpcclient
  		 */
  		clnt = xchg(&clp->cl_rpcclient, clnt);
  		rpc_shutdown_client(clnt);
  		clnt = clp->cl_rpcclient;
05f4c350e   Chuck Lever   NFS: Discover NFS...
2227
2228
2229
2230
2231
2232
2233
  		goto again;
  
  	case -NFS4ERR_MINOR_VERS_MISMATCH:
  		status = -EPROTONOSUPPORT;
  		break;
  
  	case -EKEYEXPIRED:
05f4c350e   Chuck Lever   NFS: Discover NFS...
2234
2235
2236
  	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
  				 * in nfs4_exchange_id */
  		status = -EKEYEXPIRED;
ea33e6c3e   Trond Myklebust   NFSv4: Fix issues...
2237
2238
2239
2240
2241
2242
  		break;
  	default:
  		pr_warn("NFS: %s unhandled error %d. Exiting with error EIO
  ",
  				__func__, status);
  		status = -EIO;
05f4c350e   Chuck Lever   NFS: Discover NFS...
2243
2244
2245
2246
  	}
  
  out_unlock:
  	mutex_unlock(&nfs_clid_init_mutex);
05f4c350e   Chuck Lever   NFS: Discover NFS...
2247
2248
2249
2250
  	dprintk("NFS: %s: status = %d
  ", __func__, status);
  	return status;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
2251
  #ifdef CONFIG_NFS_V4_1
9f594791d   Trond Myklebust   NFSv4.1: Handle o...
2252
  void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
2253
  {
444f72fe7   Trond Myklebust   NFSv4.1: Fix the ...
2254
  	struct nfs_client *clp = session->clp;
9f594791d   Trond Myklebust   NFSv4.1: Handle o...
2255
2256
2257
2258
2259
2260
2261
  	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);
  	}
d94cbf6c7   Trond Myklebust   NFSv4.1: Don't sc...
2262
  	nfs4_schedule_state_manager(clp);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
2263
  }
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
2264
  EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
2265

3f10a6af4   Anna Schumaker   NFS: Remove nfs41...
2266
  void nfs41_notify_server(struct nfs_client *clp)
ac0748359   Trond Myklebust   NFSv4.1: CB_RECAL...
2267
2268
2269
2270
2271
  {
  	/* Use CHECK_LEASE to ping the server with a SEQUENCE */
  	set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
  	nfs4_schedule_state_manager(clp);
  }
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2272
2273
2274
  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...
2275
  		set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
be0bfed00   Trond Myklebust   NFSv4: When purgi...
2276
  		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2277
  		nfs4_state_start_reclaim_nograce(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2278
2279
2280
  		dprintk("%s: scheduling reset of all state for server %s!
  ",
  				__func__, clp->cl_hostname);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
2281
  		nfs4_schedule_state_manager(clp);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2282
2283
2284
2285
2286
2287
2288
  	}
  }
  
  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...
2289
2290
2291
  		dprintk("%s: server %s rebooted!
  ", __func__,
  				clp->cl_hostname);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
2292
  		nfs4_schedule_state_manager(clp);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2293
2294
  	}
  }
8b895ce65   Trond Myklebust   NFSv4.1: Handle S...
2295
  static void nfs41_handle_all_state_revoked(struct nfs_client *clp)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2296
  {
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2297
  	nfs4_reset_all_state(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2298
2299
  	dprintk("%s: state revoked on server %s
  ", __func__, clp->cl_hostname);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2300
  }
8b895ce65   Trond Myklebust   NFSv4.1: Handle S...
2301
2302
  static void nfs41_handle_some_state_revoked(struct nfs_client *clp)
  {
45870d690   Trond Myklebust   NFSv4.1: Test del...
2303
  	nfs4_state_start_reclaim_nograce(clp);
8b895ce65   Trond Myklebust   NFSv4.1: Handle S...
2304
2305
2306
2307
2308
  	nfs4_schedule_state_manager(clp);
  
  	dprintk("%s: state revoked on server %s
  ", __func__, clp->cl_hostname);
  }
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2309
2310
  static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
  {
4099287fe   Trond Myklebust   NFSv4.1: Handle S...
2311
2312
  	/* FIXME: For now, we destroy all layouts. */
  	pnfs_destroy_all_layouts(clp);
8ca017c8c   Scott Mayhew   NFSv4: don't mark...
2313
  	nfs_test_expired_all_delegations(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2314
2315
2316
  	dprintk("%s: Recallable state revoked on server %s!
  ", __func__,
  			clp->cl_hostname);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2317
  }
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2318
  static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2319
  {
b13529059   Trond Myklebust   NFSv4.1: Handle S...
2320
2321
  	set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
  	nfs4_schedule_state_manager(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2322
2323
2324
  	dprintk("%s: server %s declared a backchannel fault
  ", __func__,
  			clp->cl_hostname);
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2325
  }
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2326
2327
2328
2329
2330
2331
  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);
  }
0a014a44a   Trond Myklebust   NFSv4.1: Don't de...
2332
2333
  void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags,
  		bool recovery)
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
2334
2335
2336
  {
  	if (!flags)
  		return;
2c820d9a9   Chuck Lever   NFS: Force server...
2337
2338
2339
2340
  
  	dprintk("%s: \"%s\" (client ID %llx) flags=0x%08x
  ",
  		__func__, clp->cl_hostname, clp->cl_clientid, flags);
0a014a44a   Trond Myklebust   NFSv4.1: Don't de...
2341
2342
2343
2344
2345
2346
2347
2348
  	/*
  	 * If we're called from the state manager thread, then assume we're
  	 * already handling the RECLAIM_NEEDED and/or STATE_REVOKED.
  	 * Those flags are expected to remain set until we're done
  	 * recovering (see RFC5661, section 18.46.3).
  	 */
  	if (recovery)
  		goto out_recovery;
2c820d9a9   Chuck Lever   NFS: Force server...
2349

111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
2350
  	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2351
  		nfs41_handle_server_reboot(clp);
8b895ce65   Trond Myklebust   NFSv4.1: Handle S...
2352
2353
2354
  	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED))
  		nfs41_handle_all_state_revoked(clp);
  	if (flags & (SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
d1c2331e7   Chuck Lever   NFS: Handle SEQ4_...
2355
  			    SEQ4_STATUS_ADMIN_STATE_REVOKED))
8b895ce65   Trond Myklebust   NFSv4.1: Handle S...
2356
  		nfs41_handle_some_state_revoked(clp);
d1c2331e7   Chuck Lever   NFS: Handle SEQ4_...
2357
2358
  	if (flags & SEQ4_STATUS_LEASE_MOVED)
  		nfs4_schedule_lease_moved_recovery(clp);
111d489f0   Trond Myklebust   NFSv4.1: Ensure t...
2359
  	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
0f79fd6f5   Trond Myklebust   NFSv4.1: Various ...
2360
  		nfs41_handle_recallable_state_revoked(clp);
0a014a44a   Trond Myklebust   NFSv4.1: Don't de...
2361
  out_recovery:
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2362
2363
2364
2365
  	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 ...
2366
  		nfs41_handle_cb_path_down(clp);
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
2367
  }
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2368
2369
  static int nfs4_reset_session(struct nfs_client *clp)
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2370
  	const struct cred *cred;
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2371
  	int status;
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
2372
2373
  	if (!nfs4_has_session(clp))
  		return 0;
8aafd2fde   Trond Myklebust   NFSv4: Don't busy...
2374
2375
2376
  	status = nfs4_begin_drain_session(clp);
  	if (status != 0)
  		return status;
73d8bde5e   Chuck Lever   NFS: Never use us...
2377
  	cred = nfs4_get_clid_cred(clp);
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
2378
  	status = nfs4_proc_destroy_session(clp->cl_session, cred);
c489ee290   Trond Myklebust   NFSv4.1: Handle N...
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
  	switch (status) {
  	case 0:
  	case -NFS4ERR_BADSESSION:
  	case -NFS4ERR_DEADSESSION:
  		break;
  	case -NFS4ERR_BACK_CHAN_BUSY:
  	case -NFS4ERR_DELAY:
  		set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
  		status = 0;
  		ssleep(1);
  		goto out;
  	default:
f455848a1   Ricardo Labiaga   nfs41: Mark state...
2391
  		status = nfs4_recovery_handle_error(clp, status);
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2392
2393
2394
2395
  		goto out;
  	}
  
  	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
848f5bda5   Trond Myklebust   NFSv4.1: Ensure w...
2396
  	status = nfs4_proc_create_session(clp, cred);
41f54a554   Andy Adamson   nfs41: clear NFS4...
2397
  	if (status) {
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2398
2399
2400
  		dprintk("%s: session reset failed with status %d for server %s!
  ",
  			__func__, status, clp->cl_hostname);
f2c1b5100   Trond Myklebust   NFSv4.1: nfs4_res...
2401
  		status = nfs4_handle_reclaim_lease_error(clp, status);
41f54a554   Andy Adamson   nfs41: clear NFS4...
2402
2403
  		goto out;
  	}
bda197f5d   Trond Myklebust   NFSv4.1: Ensure w...
2404
  	nfs41_finish_session_reset(clp);
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2405
2406
2407
  	dprintk("%s: session reset was successful for server %s!
  ",
  			__func__, clp->cl_hostname);
41f54a554   Andy Adamson   nfs41: clear NFS4...
2408
  out:
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2409
  	put_cred(cred);
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2410
2411
  	return status;
  }
76db6d950   Andy Adamson   nfs41: add sessio...
2412

a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2413
2414
  static int nfs4_bind_conn_to_session(struct nfs_client *clp)
  {
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2415
  	const struct cred *cred;
2cf047c99   Trond Myklebust   NFSv4.1: Ensure w...
2416
  	int ret;
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
2417
2418
  	if (!nfs4_has_session(clp))
  		return 0;
8aafd2fde   Trond Myklebust   NFSv4: Don't busy...
2419
2420
2421
  	ret = nfs4_begin_drain_session(clp);
  	if (ret != 0)
  		return ret;
73d8bde5e   Chuck Lever   NFS: Never use us...
2422
  	cred = nfs4_get_clid_cred(clp);
2cf047c99   Trond Myklebust   NFSv4.1: Ensure w...
2423
  	ret = nfs4_proc_bind_conn_to_session(clp, cred);
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
2424
  	put_cred(cred);
43ac544cb   Trond Myklebust   NFSv4.1: nfs4_bin...
2425
  	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
bf674c822   Trond Myklebust   NFSv4.1: Handle e...
2426
2427
  	switch (ret) {
  	case 0:
cc0a98436   Trond Myklebust   NFSv4: Add debugg...
2428
2429
2430
  		dprintk("%s: bind_conn_to_session was successful for server %s!
  ",
  			__func__, clp->cl_hostname);
bf674c822   Trond Myklebust   NFSv4.1: Handle e...
2431
2432
2433
2434
2435
2436
2437
2438
2439
  		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...
2440
  }
b5fdf8418   Trond Myklebust   NFSv4: Add suppor...
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
  
  static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
  {
  	int iomode = 0;
  
  	if (test_and_clear_bit(NFS4CLNT_RECALL_ANY_LAYOUT_READ, &clp->cl_state))
  		iomode += IOMODE_READ;
  	if (test_and_clear_bit(NFS4CLNT_RECALL_ANY_LAYOUT_RW, &clp->cl_state))
  		iomode += IOMODE_RW;
  	/* Note: IOMODE_READ + IOMODE_RW == IOMODE_ANY */
  	if (iomode) {
  		pnfs_layout_return_unused_byclid(clp, iomode);
  		set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
  	}
  }
76db6d950   Andy Adamson   nfs41: add sessio...
2456
  #else /* CONFIG_NFS_V4_1 */
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2457
  static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2458
2459
2460
2461
2462
  
  static int nfs4_bind_conn_to_session(struct nfs_client *clp)
  {
  	return 0;
  }
b5fdf8418   Trond Myklebust   NFSv4: Add suppor...
2463
2464
2465
2466
  
  static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
  {
  }
76db6d950   Andy Adamson   nfs41: add sessio...
2467
  #endif /* CONFIG_NFS_V4_1 */
e005e8041   Trond Myklebust   NFSv4: Rename the...
2468
  static void nfs4_state_manager(struct nfs_client *clp)
028600143   Trond Myklebust   NFSv4: Clean up f...
2469
  {
028600143   Trond Myklebust   NFSv4: Clean up f...
2470
  	int status = 0;
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2471
  	const char *section = "", *section_sep = "";
028600143   Trond Myklebust   NFSv4: Clean up f...
2472

028600143   Trond Myklebust   NFSv4: Clean up f...
2473
  	/* Ensure exclusive access to NFSv4 state */
47c2199b6   Trond Myklebust   NFSv4.1: Ensure s...
2474
  	do {
511ba52e4   Chuck Lever   NFS4: Trace state...
2475
  		trace_nfs4_state_mgr(clp);
aeabb3c96   Trond Myklebust   NFSv4: Fix a NFSv...
2476
  		clear_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
2c820d9a9   Chuck Lever   NFS: Force server...
2477
  		if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2478
  			section = "purge state";
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2479
  			status = nfs4_purge_lease(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
2480
2481
  			if (status < 0)
  				goto out_error;
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2482
  			continue;
2c820d9a9   Chuck Lever   NFS: Force server...
2483
  		}
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2484
  		if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2485
  			section = "lease expired";
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2486
2487
  			/* We're going to have to re-establish a clientid */
  			status = nfs4_reclaim_lease(clp);
2a6ee6aa2   Trond Myklebust   NFSv4: Clean up t...
2488
  			if (status < 0)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2489
  				goto out_error;
b42353ff8   Trond Myklebust   NFSv4.1: Clean up...
2490
  			continue;
e598d843c   Trond Myklebust   NFSv4: Remove red...
2491
  		}
c3fad1b1a   Andy Adamson   nfs41: add sessio...
2492
  		/* Initialize or reset the session */
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
2493
  		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2494
  			section = "reset session";
4d643d1df   Andy Adamson   nfs41: add create...
2495
  			status = nfs4_reset_session(clp);
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2496
2497
2498
  			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
  				continue;
  			if (status < 0)
76db6d950   Andy Adamson   nfs41: add sessio...
2499
  				goto out_error;
76db6d950   Andy Adamson   nfs41: add sessio...
2500
  		}
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2501

a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2502
2503
  		/* Send BIND_CONN_TO_SESSION */
  		if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
1a47e7a66   Trond Myklebust   NFSv4.1: Cleanup ...
2504
  				&clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2505
  			section = "bind conn to session";
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2506
2507
2508
  			status = nfs4_bind_conn_to_session(clp);
  			if (status < 0)
  				goto out_error;
bf674c822   Trond Myklebust   NFSv4.1: Handle e...
2509
  			continue;
a9e64442f   Weston Andros Adamson   nfs41: Use BIND_C...
2510
  		}
5df904aeb   Trond Myklebust   NFSv4.1: Handle s...
2511
2512
2513
2514
2515
  		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
  			section = "check lease";
  			status = nfs4_check_lease(clp);
  			if (status < 0)
  				goto out_error;
8faaa6d5d   Olga Kornievskaia   Fixing lease renewal
2516
  			continue;
c9fdeb280   Chuck Lever   NFS: Add basic mi...
2517
2518
2519
2520
2521
2522
2523
  		}
  
  		if (test_and_clear_bit(NFS4CLNT_MOVED, &clp->cl_state)) {
  			section = "migration";
  			status = nfs4_handle_migration(clp);
  			if (status < 0)
  				goto out_error;
5df904aeb   Trond Myklebust   NFSv4.1: Handle s...
2524
  		}
b7f7a66e4   Chuck Lever   NFS: Support NFS4...
2525
2526
2527
2528
2529
2530
  		if (test_and_clear_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state)) {
  			section = "lease moved";
  			status = nfs4_handle_lease_moved(clp);
  			if (status < 0)
  				goto out_error;
  		}
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2531
  		/* First recover reboot state... */
e345e88a7   Trond Myklebust   NFSv4: Fix up the...
2532
  		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2533
  			section = "reclaim reboot";
591d71cbd   Andy Adamson   nfs41: establish ...
2534
  			status = nfs4_do_reclaim(clp,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
2535
  				clp->cl_mvops->reboot_recovery_ops);
df817ba35   Trond Myklebust   NFSv4: fix open/l...
2536
  			if (status == -EAGAIN)
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2537
2538
2539
  				continue;
  			if (status < 0)
  				goto out_error;
df817ba35   Trond Myklebust   NFSv4: fix open/l...
2540
  			nfs4_state_end_reclaim_reboot(clp);
028600143   Trond Myklebust   NFSv4: Clean up f...
2541
  		}
45870d690   Trond Myklebust   NFSv4.1: Test del...
2542
2543
2544
2545
2546
2547
  		/* Detect expired delegations... */
  		if (test_and_clear_bit(NFS4CLNT_DELEGATION_EXPIRED, &clp->cl_state)) {
  			section = "detect expired delegations";
  			nfs_reap_expired_delegations(clp);
  			continue;
  		}
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2548
  		/* Now recover expired state... */
67e7b52d4   Trond Myklebust   NFSv4: Ensure sta...
2549
  		if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2550
  			section = "reclaim nograce";
591d71cbd   Andy Adamson   nfs41: establish ...
2551
  			status = nfs4_do_reclaim(clp,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
2552
  				clp->cl_mvops->nograce_recovery_ops);
df817ba35   Trond Myklebust   NFSv4: fix open/l...
2553
  			if (status == -EAGAIN)
b6d408ba8   Trond Myklebust   NFSv4: Fix up err...
2554
2555
  				continue;
  			if (status < 0)
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
2556
  				goto out_error;
67e7b52d4   Trond Myklebust   NFSv4: Ensure sta...
2557
  			clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2558
  		}
707fb4b32   Trond Myklebust   NFSv4: Clean up N...
2559

5601a00d6   Alexandros Batsakis   nfs: run state ma...
2560
  		nfs4_end_drain_session(clp);
aeabb3c96   Trond Myklebust   NFSv4: Fix a NFSv...
2561
  		nfs4_clear_state_manager_bit(clp);
b5fdf8418   Trond Myklebust   NFSv4: Add suppor...
2562
  		if (!test_and_set_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state)) {
aeabb3c96   Trond Myklebust   NFSv4: Fix a NFSv...
2563
2564
2565
2566
  			if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
  				nfs_client_return_marked_delegations(clp);
  				set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
  			}
b5fdf8418   Trond Myklebust   NFSv4: Add suppor...
2567
2568
  			nfs4_layoutreturn_any_run(clp);
  			clear_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state);
707fb4b32   Trond Myklebust   NFSv4: Clean up N...
2569
  		}
e005e8041   Trond Myklebust   NFSv4: Rename the...
2570

f3c76491e   Trond Myklebust   NFSv4: Don't exit...
2571
  		/* Did we race with an attempt to give us more work? */
aeabb3c96   Trond Myklebust   NFSv4: Fix a NFSv...
2572
  		if (!test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
21a446cf1   Trond Myklebust   NFSv4: Don't exit...
2573
  			return;
f3c76491e   Trond Myklebust   NFSv4: Don't exit...
2574
  		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
21a446cf1   Trond Myklebust   NFSv4: Don't exit...
2575
  			return;
a1aa09be2   Trond Myklebust   NFSv4: Ensure tha...
2576
  	} while (refcount_read(&clp->cl_count) > 1 && !signalled());
21a446cf1   Trond Myklebust   NFSv4: Don't exit...
2577
  	goto out_drain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2578
  out_error:
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2579
2580
  	if (strlen(section))
  		section_sep = ": ";
511ba52e4   Chuck Lever   NFS4: Trace state...
2581
  	trace_nfs4_state_mgr_failed(clp, section, status);
8ed27d4fb   Weston Andros Adamson   NFS: add more con...
2582
2583
2584
2585
  	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...
2586
  	ssleep(1);
21a446cf1   Trond Myklebust   NFSv4: Don't exit...
2587
  out_drain:
5601a00d6   Alexandros Batsakis   nfs: run state ma...
2588
  	nfs4_end_drain_session(clp);
e005e8041   Trond Myklebust   NFSv4: Rename the...
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
  	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
2601
2602
2603
2604
2605
2606
2607
  }
  
  /*
   * Local variables:
   *  c-basic-offset: 8
   * End:
   */