xref: /OK3568_Linux_fs/kernel/fs/nfs/nfs4state.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *  fs/nfs/nfs4state.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  Client-side XDR for NFSv4.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  Copyright (c) 2002 The Regents of the University of Michigan.
7*4882a593Smuzhiyun  *  All rights reserved.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *  Kendrick Smith <kmsmith@umich.edu>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *  Redistribution and use in source and binary forms, with or without
12*4882a593Smuzhiyun  *  modification, are permitted provided that the following conditions
13*4882a593Smuzhiyun  *  are met:
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *  1. Redistributions of source code must retain the above copyright
16*4882a593Smuzhiyun  *     notice, this list of conditions and the following disclaimer.
17*4882a593Smuzhiyun  *  2. Redistributions in binary form must reproduce the above copyright
18*4882a593Smuzhiyun  *     notice, this list of conditions and the following disclaimer in the
19*4882a593Smuzhiyun  *     documentation and/or other materials provided with the distribution.
20*4882a593Smuzhiyun  *  3. Neither the name of the University nor the names of its
21*4882a593Smuzhiyun  *     contributors may be used to endorse or promote products derived
22*4882a593Smuzhiyun  *     from this software without specific prior written permission.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25*4882a593Smuzhiyun  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26*4882a593Smuzhiyun  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27*4882a593Smuzhiyun  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28*4882a593Smuzhiyun  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29*4882a593Smuzhiyun  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30*4882a593Smuzhiyun  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31*4882a593Smuzhiyun  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32*4882a593Smuzhiyun  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33*4882a593Smuzhiyun  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34*4882a593Smuzhiyun  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * Implementation of the NFSv4 state model.  For the time being,
37*4882a593Smuzhiyun  * this is minimal, but will be made much more complex in a
38*4882a593Smuzhiyun  * subsequent patch.
39*4882a593Smuzhiyun  */
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #include <linux/kernel.h>
42*4882a593Smuzhiyun #include <linux/slab.h>
43*4882a593Smuzhiyun #include <linux/fs.h>
44*4882a593Smuzhiyun #include <linux/nfs_fs.h>
45*4882a593Smuzhiyun #include <linux/kthread.h>
46*4882a593Smuzhiyun #include <linux/module.h>
47*4882a593Smuzhiyun #include <linux/random.h>
48*4882a593Smuzhiyun #include <linux/ratelimit.h>
49*4882a593Smuzhiyun #include <linux/workqueue.h>
50*4882a593Smuzhiyun #include <linux/bitops.h>
51*4882a593Smuzhiyun #include <linux/jiffies.h>
52*4882a593Smuzhiyun #include <linux/sched/mm.h>
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #include <linux/sunrpc/clnt.h>
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #include "nfs4_fs.h"
57*4882a593Smuzhiyun #include "callback.h"
58*4882a593Smuzhiyun #include "delegation.h"
59*4882a593Smuzhiyun #include "internal.h"
60*4882a593Smuzhiyun #include "nfs4idmap.h"
61*4882a593Smuzhiyun #include "nfs4session.h"
62*4882a593Smuzhiyun #include "pnfs.h"
63*4882a593Smuzhiyun #include "netns.h"
64*4882a593Smuzhiyun #include "nfs4trace.h"
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define NFSDBG_FACILITY		NFSDBG_STATE
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define OPENOWNER_POOL_SIZE	8
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun const nfs4_stateid zero_stateid = {
71*4882a593Smuzhiyun 	{ .data = { 0 } },
72*4882a593Smuzhiyun 	.type = NFS4_SPECIAL_STATEID_TYPE,
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun const nfs4_stateid invalid_stateid = {
75*4882a593Smuzhiyun 	{
76*4882a593Smuzhiyun 		/* Funky initialiser keeps older gcc versions happy */
77*4882a593Smuzhiyun 		.data = { 0xff, 0xff, 0xff, 0xff, 0 },
78*4882a593Smuzhiyun 	},
79*4882a593Smuzhiyun 	.type = NFS4_INVALID_STATEID_TYPE,
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun const nfs4_stateid current_stateid = {
83*4882a593Smuzhiyun 	{
84*4882a593Smuzhiyun 		/* Funky initialiser keeps older gcc versions happy */
85*4882a593Smuzhiyun 		.data = { 0x0, 0x0, 0x0, 0x1, 0 },
86*4882a593Smuzhiyun 	},
87*4882a593Smuzhiyun 	.type = NFS4_SPECIAL_STATEID_TYPE,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static DEFINE_MUTEX(nfs_clid_init_mutex);
91*4882a593Smuzhiyun 
nfs4_setup_state_renewal(struct nfs_client * clp)92*4882a593Smuzhiyun static int nfs4_setup_state_renewal(struct nfs_client *clp)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	int status;
95*4882a593Smuzhiyun 	struct nfs_fsinfo fsinfo;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
98*4882a593Smuzhiyun 		nfs4_schedule_state_renewal(clp);
99*4882a593Smuzhiyun 		return 0;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	status = nfs4_proc_get_lease_time(clp, &fsinfo);
103*4882a593Smuzhiyun 	if (status == 0) {
104*4882a593Smuzhiyun 		nfs4_set_lease_period(clp, fsinfo.lease_time * HZ);
105*4882a593Smuzhiyun 		nfs4_schedule_state_renewal(clp);
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return status;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
nfs4_init_clientid(struct nfs_client * clp,const struct cred * cred)111*4882a593Smuzhiyun int nfs4_init_clientid(struct nfs_client *clp, const struct cred *cred)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	struct nfs4_setclientid_res clid = {
114*4882a593Smuzhiyun 		.clientid = clp->cl_clientid,
115*4882a593Smuzhiyun 		.confirm = clp->cl_confirm,
116*4882a593Smuzhiyun 	};
117*4882a593Smuzhiyun 	unsigned short port;
118*4882a593Smuzhiyun 	int status;
119*4882a593Smuzhiyun 	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
122*4882a593Smuzhiyun 		goto do_confirm;
123*4882a593Smuzhiyun 	port = nn->nfs_callback_tcpport;
124*4882a593Smuzhiyun 	if (clp->cl_addr.ss_family == AF_INET6)
125*4882a593Smuzhiyun 		port = nn->nfs_callback_tcpport6;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
128*4882a593Smuzhiyun 	if (status != 0)
129*4882a593Smuzhiyun 		goto out;
130*4882a593Smuzhiyun 	clp->cl_clientid = clid.clientid;
131*4882a593Smuzhiyun 	clp->cl_confirm = clid.confirm;
132*4882a593Smuzhiyun 	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
133*4882a593Smuzhiyun do_confirm:
134*4882a593Smuzhiyun 	status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
135*4882a593Smuzhiyun 	if (status != 0)
136*4882a593Smuzhiyun 		goto out;
137*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
138*4882a593Smuzhiyun 	nfs4_setup_state_renewal(clp);
139*4882a593Smuzhiyun out:
140*4882a593Smuzhiyun 	return status;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun /**
144*4882a593Smuzhiyun  * nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
145*4882a593Smuzhiyun  *
146*4882a593Smuzhiyun  * @clp: nfs_client under test
147*4882a593Smuzhiyun  * @result: OUT: found nfs_client, or clp
148*4882a593Smuzhiyun  * @cred: credential to use for trunking test
149*4882a593Smuzhiyun  *
150*4882a593Smuzhiyun  * Returns zero, a negative errno, or a negative NFS4ERR status.
151*4882a593Smuzhiyun  * If zero is returned, an nfs_client pointer is planted in
152*4882a593Smuzhiyun  * "result".
153*4882a593Smuzhiyun  *
154*4882a593Smuzhiyun  * Note: The returned client may not yet be marked ready.
155*4882a593Smuzhiyun  */
nfs40_discover_server_trunking(struct nfs_client * clp,struct nfs_client ** result,const struct cred * cred)156*4882a593Smuzhiyun int nfs40_discover_server_trunking(struct nfs_client *clp,
157*4882a593Smuzhiyun 				   struct nfs_client **result,
158*4882a593Smuzhiyun 				   const struct cred *cred)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	struct nfs4_setclientid_res clid = {
161*4882a593Smuzhiyun 		.clientid = clp->cl_clientid,
162*4882a593Smuzhiyun 		.confirm = clp->cl_confirm,
163*4882a593Smuzhiyun 	};
164*4882a593Smuzhiyun 	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
165*4882a593Smuzhiyun 	unsigned short port;
166*4882a593Smuzhiyun 	int status;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	port = nn->nfs_callback_tcpport;
169*4882a593Smuzhiyun 	if (clp->cl_addr.ss_family == AF_INET6)
170*4882a593Smuzhiyun 		port = nn->nfs_callback_tcpport6;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
173*4882a593Smuzhiyun 	if (status != 0)
174*4882a593Smuzhiyun 		goto out;
175*4882a593Smuzhiyun 	clp->cl_clientid = clid.clientid;
176*4882a593Smuzhiyun 	clp->cl_confirm = clid.confirm;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	status = nfs40_walk_client_list(clp, result, cred);
179*4882a593Smuzhiyun 	if (status == 0) {
180*4882a593Smuzhiyun 		/* Sustain the lease, even if it's empty.  If the clientid4
181*4882a593Smuzhiyun 		 * goes stale it's of no use for trunking discovery. */
182*4882a593Smuzhiyun 		nfs4_schedule_state_renewal(*result);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 		/* If the client state need to recover, do it. */
185*4882a593Smuzhiyun 		if (clp->cl_state)
186*4882a593Smuzhiyun 			nfs4_schedule_state_manager(clp);
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun out:
189*4882a593Smuzhiyun 	return status;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
nfs4_get_machine_cred(struct nfs_client * clp)192*4882a593Smuzhiyun const struct cred *nfs4_get_machine_cred(struct nfs_client *clp)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	return get_cred(rpc_machine_cred());
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
nfs4_root_machine_cred(struct nfs_client * clp)197*4882a593Smuzhiyun static void nfs4_root_machine_cred(struct nfs_client *clp)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	/* Force root creds instead of machine */
201*4882a593Smuzhiyun 	clp->cl_principal = NULL;
202*4882a593Smuzhiyun 	clp->cl_rpcclient->cl_principal = NULL;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun static const struct cred *
nfs4_get_renew_cred_server_locked(struct nfs_server * server)206*4882a593Smuzhiyun nfs4_get_renew_cred_server_locked(struct nfs_server *server)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	const struct cred *cred = NULL;
209*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
210*4882a593Smuzhiyun 	struct rb_node *pos;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	for (pos = rb_first(&server->state_owners);
213*4882a593Smuzhiyun 	     pos != NULL;
214*4882a593Smuzhiyun 	     pos = rb_next(pos)) {
215*4882a593Smuzhiyun 		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
216*4882a593Smuzhiyun 		if (list_empty(&sp->so_states))
217*4882a593Smuzhiyun 			continue;
218*4882a593Smuzhiyun 		cred = get_cred(sp->so_cred);
219*4882a593Smuzhiyun 		break;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 	return cred;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun /**
225*4882a593Smuzhiyun  * nfs4_get_renew_cred - Acquire credential for a renew operation
226*4882a593Smuzhiyun  * @clp: client state handle
227*4882a593Smuzhiyun  *
228*4882a593Smuzhiyun  * Returns an rpc_cred with reference count bumped, or NULL.
229*4882a593Smuzhiyun  * Caller must hold clp->cl_lock.
230*4882a593Smuzhiyun  */
nfs4_get_renew_cred(struct nfs_client * clp)231*4882a593Smuzhiyun const struct cred *nfs4_get_renew_cred(struct nfs_client *clp)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	const struct cred *cred = NULL;
234*4882a593Smuzhiyun 	struct nfs_server *server;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	/* Use machine credentials if available */
237*4882a593Smuzhiyun 	cred = nfs4_get_machine_cred(clp);
238*4882a593Smuzhiyun 	if (cred != NULL)
239*4882a593Smuzhiyun 		goto out;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	spin_lock(&clp->cl_lock);
242*4882a593Smuzhiyun 	rcu_read_lock();
243*4882a593Smuzhiyun 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
244*4882a593Smuzhiyun 		cred = nfs4_get_renew_cred_server_locked(server);
245*4882a593Smuzhiyun 		if (cred != NULL)
246*4882a593Smuzhiyun 			break;
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 	rcu_read_unlock();
249*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun out:
252*4882a593Smuzhiyun 	return cred;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
nfs4_end_drain_slot_table(struct nfs4_slot_table * tbl)255*4882a593Smuzhiyun static void nfs4_end_drain_slot_table(struct nfs4_slot_table *tbl)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	if (test_and_clear_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
258*4882a593Smuzhiyun 		spin_lock(&tbl->slot_tbl_lock);
259*4882a593Smuzhiyun 		nfs41_wake_slot_table(tbl);
260*4882a593Smuzhiyun 		spin_unlock(&tbl->slot_tbl_lock);
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
nfs4_end_drain_session(struct nfs_client * clp)264*4882a593Smuzhiyun static void nfs4_end_drain_session(struct nfs_client *clp)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	struct nfs4_session *ses = clp->cl_session;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (clp->cl_slot_tbl) {
269*4882a593Smuzhiyun 		nfs4_end_drain_slot_table(clp->cl_slot_tbl);
270*4882a593Smuzhiyun 		return;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (ses != NULL) {
274*4882a593Smuzhiyun 		nfs4_end_drain_slot_table(&ses->bc_slot_table);
275*4882a593Smuzhiyun 		nfs4_end_drain_slot_table(&ses->fc_slot_table);
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
nfs4_drain_slot_tbl(struct nfs4_slot_table * tbl)279*4882a593Smuzhiyun static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	set_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state);
282*4882a593Smuzhiyun 	spin_lock(&tbl->slot_tbl_lock);
283*4882a593Smuzhiyun 	if (tbl->highest_used_slotid != NFS4_NO_SLOT) {
284*4882a593Smuzhiyun 		reinit_completion(&tbl->complete);
285*4882a593Smuzhiyun 		spin_unlock(&tbl->slot_tbl_lock);
286*4882a593Smuzhiyun 		return wait_for_completion_interruptible(&tbl->complete);
287*4882a593Smuzhiyun 	}
288*4882a593Smuzhiyun 	spin_unlock(&tbl->slot_tbl_lock);
289*4882a593Smuzhiyun 	return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
nfs4_begin_drain_session(struct nfs_client * clp)292*4882a593Smuzhiyun static int nfs4_begin_drain_session(struct nfs_client *clp)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	struct nfs4_session *ses = clp->cl_session;
295*4882a593Smuzhiyun 	int ret;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if (clp->cl_slot_tbl)
298*4882a593Smuzhiyun 		return nfs4_drain_slot_tbl(clp->cl_slot_tbl);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	/* back channel */
301*4882a593Smuzhiyun 	ret = nfs4_drain_slot_tbl(&ses->bc_slot_table);
302*4882a593Smuzhiyun 	if (ret)
303*4882a593Smuzhiyun 		return ret;
304*4882a593Smuzhiyun 	/* fore channel */
305*4882a593Smuzhiyun 	return nfs4_drain_slot_tbl(&ses->fc_slot_table);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun #if defined(CONFIG_NFS_V4_1)
309*4882a593Smuzhiyun 
nfs41_finish_session_reset(struct nfs_client * clp)310*4882a593Smuzhiyun static void nfs41_finish_session_reset(struct nfs_client *clp)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
313*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
314*4882a593Smuzhiyun 	/* create_session negotiated new slot table */
315*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
316*4882a593Smuzhiyun 	nfs4_setup_state_renewal(clp);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
nfs41_init_clientid(struct nfs_client * clp,const struct cred * cred)319*4882a593Smuzhiyun int nfs41_init_clientid(struct nfs_client *clp, const struct cred *cred)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	int status;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
324*4882a593Smuzhiyun 		goto do_confirm;
325*4882a593Smuzhiyun 	status = nfs4_proc_exchange_id(clp, cred);
326*4882a593Smuzhiyun 	if (status != 0)
327*4882a593Smuzhiyun 		goto out;
328*4882a593Smuzhiyun 	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
329*4882a593Smuzhiyun do_confirm:
330*4882a593Smuzhiyun 	status = nfs4_proc_create_session(clp, cred);
331*4882a593Smuzhiyun 	if (status != 0)
332*4882a593Smuzhiyun 		goto out;
333*4882a593Smuzhiyun 	nfs41_finish_session_reset(clp);
334*4882a593Smuzhiyun 	nfs_mark_client_ready(clp, NFS_CS_READY);
335*4882a593Smuzhiyun out:
336*4882a593Smuzhiyun 	return status;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun /**
340*4882a593Smuzhiyun  * nfs41_discover_server_trunking - Detect server IP address trunking (mv1)
341*4882a593Smuzhiyun  *
342*4882a593Smuzhiyun  * @clp: nfs_client under test
343*4882a593Smuzhiyun  * @result: OUT: found nfs_client, or clp
344*4882a593Smuzhiyun  * @cred: credential to use for trunking test
345*4882a593Smuzhiyun  *
346*4882a593Smuzhiyun  * Returns NFS4_OK, a negative errno, or a negative NFS4ERR status.
347*4882a593Smuzhiyun  * If NFS4_OK is returned, an nfs_client pointer is planted in
348*4882a593Smuzhiyun  * "result".
349*4882a593Smuzhiyun  *
350*4882a593Smuzhiyun  * Note: The returned client may not yet be marked ready.
351*4882a593Smuzhiyun  */
nfs41_discover_server_trunking(struct nfs_client * clp,struct nfs_client ** result,const struct cred * cred)352*4882a593Smuzhiyun int nfs41_discover_server_trunking(struct nfs_client *clp,
353*4882a593Smuzhiyun 				   struct nfs_client **result,
354*4882a593Smuzhiyun 				   const struct cred *cred)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	int status;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	status = nfs4_proc_exchange_id(clp, cred);
359*4882a593Smuzhiyun 	if (status != NFS4_OK)
360*4882a593Smuzhiyun 		return status;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	status = nfs41_walk_client_list(clp, result, cred);
363*4882a593Smuzhiyun 	if (status < 0)
364*4882a593Smuzhiyun 		return status;
365*4882a593Smuzhiyun 	if (clp != *result)
366*4882a593Smuzhiyun 		return 0;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/*
369*4882a593Smuzhiyun 	 * Purge state if the client id was established in a prior
370*4882a593Smuzhiyun 	 * instance and the client id could not have arrived on the
371*4882a593Smuzhiyun 	 * server via Transparent State Migration.
372*4882a593Smuzhiyun 	 */
373*4882a593Smuzhiyun 	if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) {
374*4882a593Smuzhiyun 		if (!test_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags))
375*4882a593Smuzhiyun 			set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
376*4882a593Smuzhiyun 		else
377*4882a593Smuzhiyun 			set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
380*4882a593Smuzhiyun 	status = nfs_wait_client_init_complete(clp);
381*4882a593Smuzhiyun 	if (status < 0)
382*4882a593Smuzhiyun 		nfs_put_client(clp);
383*4882a593Smuzhiyun 	return status;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun #endif /* CONFIG_NFS_V4_1 */
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun /**
389*4882a593Smuzhiyun  * nfs4_get_clid_cred - Acquire credential for a setclientid operation
390*4882a593Smuzhiyun  * @clp: client state handle
391*4882a593Smuzhiyun  *
392*4882a593Smuzhiyun  * Returns a cred with reference count bumped, or NULL.
393*4882a593Smuzhiyun  */
nfs4_get_clid_cred(struct nfs_client * clp)394*4882a593Smuzhiyun const struct cred *nfs4_get_clid_cred(struct nfs_client *clp)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun 	const struct cred *cred;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	cred = nfs4_get_machine_cred(clp);
399*4882a593Smuzhiyun 	return cred;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun static struct nfs4_state_owner *
nfs4_find_state_owner_locked(struct nfs_server * server,const struct cred * cred)403*4882a593Smuzhiyun nfs4_find_state_owner_locked(struct nfs_server *server, const struct cred *cred)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	struct rb_node **p = &server->state_owners.rb_node,
406*4882a593Smuzhiyun 		       *parent = NULL;
407*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
408*4882a593Smuzhiyun 	int cmp;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	while (*p != NULL) {
411*4882a593Smuzhiyun 		parent = *p;
412*4882a593Smuzhiyun 		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
413*4882a593Smuzhiyun 		cmp = cred_fscmp(cred, sp->so_cred);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 		if (cmp < 0)
416*4882a593Smuzhiyun 			p = &parent->rb_left;
417*4882a593Smuzhiyun 		else if (cmp > 0)
418*4882a593Smuzhiyun 			p = &parent->rb_right;
419*4882a593Smuzhiyun 		else {
420*4882a593Smuzhiyun 			if (!list_empty(&sp->so_lru))
421*4882a593Smuzhiyun 				list_del_init(&sp->so_lru);
422*4882a593Smuzhiyun 			atomic_inc(&sp->so_count);
423*4882a593Smuzhiyun 			return sp;
424*4882a593Smuzhiyun 		}
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 	return NULL;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun static struct nfs4_state_owner *
nfs4_insert_state_owner_locked(struct nfs4_state_owner * new)430*4882a593Smuzhiyun nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun 	struct nfs_server *server = new->so_server;
433*4882a593Smuzhiyun 	struct rb_node **p = &server->state_owners.rb_node,
434*4882a593Smuzhiyun 		       *parent = NULL;
435*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
436*4882a593Smuzhiyun 	int cmp;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	while (*p != NULL) {
439*4882a593Smuzhiyun 		parent = *p;
440*4882a593Smuzhiyun 		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
441*4882a593Smuzhiyun 		cmp = cred_fscmp(new->so_cred, sp->so_cred);
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 		if (cmp < 0)
444*4882a593Smuzhiyun 			p = &parent->rb_left;
445*4882a593Smuzhiyun 		else if (cmp > 0)
446*4882a593Smuzhiyun 			p = &parent->rb_right;
447*4882a593Smuzhiyun 		else {
448*4882a593Smuzhiyun 			if (!list_empty(&sp->so_lru))
449*4882a593Smuzhiyun 				list_del_init(&sp->so_lru);
450*4882a593Smuzhiyun 			atomic_inc(&sp->so_count);
451*4882a593Smuzhiyun 			return sp;
452*4882a593Smuzhiyun 		}
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun 	rb_link_node(&new->so_server_node, parent, p);
455*4882a593Smuzhiyun 	rb_insert_color(&new->so_server_node, &server->state_owners);
456*4882a593Smuzhiyun 	return new;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun static void
nfs4_remove_state_owner_locked(struct nfs4_state_owner * sp)460*4882a593Smuzhiyun nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun 	struct nfs_server *server = sp->so_server;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	if (!RB_EMPTY_NODE(&sp->so_server_node))
465*4882a593Smuzhiyun 		rb_erase(&sp->so_server_node, &server->state_owners);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun static void
nfs4_init_seqid_counter(struct nfs_seqid_counter * sc)469*4882a593Smuzhiyun nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun 	sc->create_time = ktime_get();
472*4882a593Smuzhiyun 	sc->flags = 0;
473*4882a593Smuzhiyun 	sc->counter = 0;
474*4882a593Smuzhiyun 	spin_lock_init(&sc->lock);
475*4882a593Smuzhiyun 	INIT_LIST_HEAD(&sc->list);
476*4882a593Smuzhiyun 	rpc_init_wait_queue(&sc->wait, "Seqid_waitqueue");
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun static void
nfs4_destroy_seqid_counter(struct nfs_seqid_counter * sc)480*4882a593Smuzhiyun nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	rpc_destroy_wait_queue(&sc->wait);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun  * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
487*4882a593Smuzhiyun  * create a new state_owner.
488*4882a593Smuzhiyun  *
489*4882a593Smuzhiyun  */
490*4882a593Smuzhiyun static struct nfs4_state_owner *
nfs4_alloc_state_owner(struct nfs_server * server,const struct cred * cred,gfp_t gfp_flags)491*4882a593Smuzhiyun nfs4_alloc_state_owner(struct nfs_server *server,
492*4882a593Smuzhiyun 		const struct cred *cred,
493*4882a593Smuzhiyun 		gfp_t gfp_flags)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	sp = kzalloc(sizeof(*sp), gfp_flags);
498*4882a593Smuzhiyun 	if (!sp)
499*4882a593Smuzhiyun 		return NULL;
500*4882a593Smuzhiyun 	sp->so_seqid.owner_id = ida_simple_get(&server->openowner_id, 0, 0,
501*4882a593Smuzhiyun 						gfp_flags);
502*4882a593Smuzhiyun 	if (sp->so_seqid.owner_id < 0) {
503*4882a593Smuzhiyun 		kfree(sp);
504*4882a593Smuzhiyun 		return NULL;
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun 	sp->so_server = server;
507*4882a593Smuzhiyun 	sp->so_cred = get_cred(cred);
508*4882a593Smuzhiyun 	spin_lock_init(&sp->so_lock);
509*4882a593Smuzhiyun 	INIT_LIST_HEAD(&sp->so_states);
510*4882a593Smuzhiyun 	nfs4_init_seqid_counter(&sp->so_seqid);
511*4882a593Smuzhiyun 	atomic_set(&sp->so_count, 1);
512*4882a593Smuzhiyun 	INIT_LIST_HEAD(&sp->so_lru);
513*4882a593Smuzhiyun 	seqcount_spinlock_init(&sp->so_reclaim_seqcount, &sp->so_lock);
514*4882a593Smuzhiyun 	mutex_init(&sp->so_delegreturn_mutex);
515*4882a593Smuzhiyun 	return sp;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun static void
nfs4_reset_state_owner(struct nfs4_state_owner * sp)519*4882a593Smuzhiyun nfs4_reset_state_owner(struct nfs4_state_owner *sp)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun 	/* This state_owner is no longer usable, but must
522*4882a593Smuzhiyun 	 * remain in place so that state recovery can find it
523*4882a593Smuzhiyun 	 * and the opens associated with it.
524*4882a593Smuzhiyun 	 * It may also be used for new 'open' request to
525*4882a593Smuzhiyun 	 * return a delegation to the server.
526*4882a593Smuzhiyun 	 * So update the 'create_time' so that it looks like
527*4882a593Smuzhiyun 	 * a new state_owner.  This will cause the server to
528*4882a593Smuzhiyun 	 * request an OPEN_CONFIRM to start a new sequence.
529*4882a593Smuzhiyun 	 */
530*4882a593Smuzhiyun 	sp->so_seqid.create_time = ktime_get();
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
nfs4_free_state_owner(struct nfs4_state_owner * sp)533*4882a593Smuzhiyun static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	nfs4_destroy_seqid_counter(&sp->so_seqid);
536*4882a593Smuzhiyun 	put_cred(sp->so_cred);
537*4882a593Smuzhiyun 	ida_simple_remove(&sp->so_server->openowner_id, sp->so_seqid.owner_id);
538*4882a593Smuzhiyun 	kfree(sp);
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
nfs4_gc_state_owners(struct nfs_server * server)541*4882a593Smuzhiyun static void nfs4_gc_state_owners(struct nfs_server *server)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
544*4882a593Smuzhiyun 	struct nfs4_state_owner *sp, *tmp;
545*4882a593Smuzhiyun 	unsigned long time_min, time_max;
546*4882a593Smuzhiyun 	LIST_HEAD(doomed);
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	spin_lock(&clp->cl_lock);
549*4882a593Smuzhiyun 	time_max = jiffies;
550*4882a593Smuzhiyun 	time_min = (long)time_max - (long)clp->cl_lease_time;
551*4882a593Smuzhiyun 	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
552*4882a593Smuzhiyun 		/* NB: LRU is sorted so that oldest is at the head */
553*4882a593Smuzhiyun 		if (time_in_range(sp->so_expires, time_min, time_max))
554*4882a593Smuzhiyun 			break;
555*4882a593Smuzhiyun 		list_move(&sp->so_lru, &doomed);
556*4882a593Smuzhiyun 		nfs4_remove_state_owner_locked(sp);
557*4882a593Smuzhiyun 	}
558*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
561*4882a593Smuzhiyun 		list_del(&sp->so_lru);
562*4882a593Smuzhiyun 		nfs4_free_state_owner(sp);
563*4882a593Smuzhiyun 	}
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun /**
567*4882a593Smuzhiyun  * nfs4_get_state_owner - Look up a state owner given a credential
568*4882a593Smuzhiyun  * @server: nfs_server to search
569*4882a593Smuzhiyun  * @cred: RPC credential to match
570*4882a593Smuzhiyun  * @gfp_flags: allocation mode
571*4882a593Smuzhiyun  *
572*4882a593Smuzhiyun  * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
573*4882a593Smuzhiyun  */
nfs4_get_state_owner(struct nfs_server * server,const struct cred * cred,gfp_t gfp_flags)574*4882a593Smuzhiyun struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
575*4882a593Smuzhiyun 					      const struct cred *cred,
576*4882a593Smuzhiyun 					      gfp_t gfp_flags)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
579*4882a593Smuzhiyun 	struct nfs4_state_owner *sp, *new;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	spin_lock(&clp->cl_lock);
582*4882a593Smuzhiyun 	sp = nfs4_find_state_owner_locked(server, cred);
583*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
584*4882a593Smuzhiyun 	if (sp != NULL)
585*4882a593Smuzhiyun 		goto out;
586*4882a593Smuzhiyun 	new = nfs4_alloc_state_owner(server, cred, gfp_flags);
587*4882a593Smuzhiyun 	if (new == NULL)
588*4882a593Smuzhiyun 		goto out;
589*4882a593Smuzhiyun 	spin_lock(&clp->cl_lock);
590*4882a593Smuzhiyun 	sp = nfs4_insert_state_owner_locked(new);
591*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
592*4882a593Smuzhiyun 	if (sp != new)
593*4882a593Smuzhiyun 		nfs4_free_state_owner(new);
594*4882a593Smuzhiyun out:
595*4882a593Smuzhiyun 	nfs4_gc_state_owners(server);
596*4882a593Smuzhiyun 	return sp;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun /**
600*4882a593Smuzhiyun  * nfs4_put_state_owner - Release a nfs4_state_owner
601*4882a593Smuzhiyun  * @sp: state owner data to release
602*4882a593Smuzhiyun  *
603*4882a593Smuzhiyun  * Note that we keep released state owners on an LRU
604*4882a593Smuzhiyun  * list.
605*4882a593Smuzhiyun  * This caches valid state owners so that they can be
606*4882a593Smuzhiyun  * reused, to avoid the OPEN_CONFIRM on minor version 0.
607*4882a593Smuzhiyun  * It also pins the uniquifier of dropped state owners for
608*4882a593Smuzhiyun  * a while, to ensure that those state owner names are
609*4882a593Smuzhiyun  * never reused.
610*4882a593Smuzhiyun  */
nfs4_put_state_owner(struct nfs4_state_owner * sp)611*4882a593Smuzhiyun void nfs4_put_state_owner(struct nfs4_state_owner *sp)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	struct nfs_server *server = sp->so_server;
614*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
617*4882a593Smuzhiyun 		return;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	sp->so_expires = jiffies;
620*4882a593Smuzhiyun 	list_add_tail(&sp->so_lru, &server->state_owners_lru);
621*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun /**
625*4882a593Smuzhiyun  * nfs4_purge_state_owners - Release all cached state owners
626*4882a593Smuzhiyun  * @server: nfs_server with cached state owners to release
627*4882a593Smuzhiyun  * @head: resulting list of state owners
628*4882a593Smuzhiyun  *
629*4882a593Smuzhiyun  * Called at umount time.  Remaining state owners will be on
630*4882a593Smuzhiyun  * the LRU with ref count of zero.
631*4882a593Smuzhiyun  * Note that the state owners are not freed, but are added
632*4882a593Smuzhiyun  * to the list @head, which can later be used as an argument
633*4882a593Smuzhiyun  * to nfs4_free_state_owners.
634*4882a593Smuzhiyun  */
nfs4_purge_state_owners(struct nfs_server * server,struct list_head * head)635*4882a593Smuzhiyun void nfs4_purge_state_owners(struct nfs_server *server, struct list_head *head)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
638*4882a593Smuzhiyun 	struct nfs4_state_owner *sp, *tmp;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	spin_lock(&clp->cl_lock);
641*4882a593Smuzhiyun 	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
642*4882a593Smuzhiyun 		list_move(&sp->so_lru, head);
643*4882a593Smuzhiyun 		nfs4_remove_state_owner_locked(sp);
644*4882a593Smuzhiyun 	}
645*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun /**
649*4882a593Smuzhiyun  * nfs4_purge_state_owners - Release all cached state owners
650*4882a593Smuzhiyun  * @head: resulting list of state owners
651*4882a593Smuzhiyun  *
652*4882a593Smuzhiyun  * Frees a list of state owners that was generated by
653*4882a593Smuzhiyun  * nfs4_purge_state_owners
654*4882a593Smuzhiyun  */
nfs4_free_state_owners(struct list_head * head)655*4882a593Smuzhiyun void nfs4_free_state_owners(struct list_head *head)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun 	struct nfs4_state_owner *sp, *tmp;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	list_for_each_entry_safe(sp, tmp, head, so_lru) {
660*4882a593Smuzhiyun 		list_del(&sp->so_lru);
661*4882a593Smuzhiyun 		nfs4_free_state_owner(sp);
662*4882a593Smuzhiyun 	}
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun static struct nfs4_state *
nfs4_alloc_open_state(void)666*4882a593Smuzhiyun nfs4_alloc_open_state(void)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun 	struct nfs4_state *state;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	state = kzalloc(sizeof(*state), GFP_NOFS);
671*4882a593Smuzhiyun 	if (!state)
672*4882a593Smuzhiyun 		return NULL;
673*4882a593Smuzhiyun 	refcount_set(&state->count, 1);
674*4882a593Smuzhiyun 	INIT_LIST_HEAD(&state->lock_states);
675*4882a593Smuzhiyun 	spin_lock_init(&state->state_lock);
676*4882a593Smuzhiyun 	seqlock_init(&state->seqlock);
677*4882a593Smuzhiyun 	init_waitqueue_head(&state->waitq);
678*4882a593Smuzhiyun 	return state;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun void
nfs4_state_set_mode_locked(struct nfs4_state * state,fmode_t fmode)682*4882a593Smuzhiyun nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	if (state->state == fmode)
685*4882a593Smuzhiyun 		return;
686*4882a593Smuzhiyun 	/* NB! List reordering - see the reclaim code for why.  */
687*4882a593Smuzhiyun 	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
688*4882a593Smuzhiyun 		if (fmode & FMODE_WRITE)
689*4882a593Smuzhiyun 			list_move(&state->open_states, &state->owner->so_states);
690*4882a593Smuzhiyun 		else
691*4882a593Smuzhiyun 			list_move_tail(&state->open_states, &state->owner->so_states);
692*4882a593Smuzhiyun 	}
693*4882a593Smuzhiyun 	state->state = fmode;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun static struct nfs4_state *
__nfs4_find_state_byowner(struct inode * inode,struct nfs4_state_owner * owner)697*4882a593Smuzhiyun __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	struct nfs_inode *nfsi = NFS_I(inode);
700*4882a593Smuzhiyun 	struct nfs4_state *state;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	list_for_each_entry_rcu(state, &nfsi->open_states, inode_states) {
703*4882a593Smuzhiyun 		if (state->owner != owner)
704*4882a593Smuzhiyun 			continue;
705*4882a593Smuzhiyun 		if (!nfs4_valid_open_stateid(state))
706*4882a593Smuzhiyun 			continue;
707*4882a593Smuzhiyun 		if (refcount_inc_not_zero(&state->count))
708*4882a593Smuzhiyun 			return state;
709*4882a593Smuzhiyun 	}
710*4882a593Smuzhiyun 	return NULL;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun static void
nfs4_free_open_state(struct nfs4_state * state)714*4882a593Smuzhiyun nfs4_free_open_state(struct nfs4_state *state)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun 	kfree_rcu(state, rcu_head);
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun struct nfs4_state *
nfs4_get_open_state(struct inode * inode,struct nfs4_state_owner * owner)720*4882a593Smuzhiyun nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	struct nfs4_state *state, *new;
723*4882a593Smuzhiyun 	struct nfs_inode *nfsi = NFS_I(inode);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	rcu_read_lock();
726*4882a593Smuzhiyun 	state = __nfs4_find_state_byowner(inode, owner);
727*4882a593Smuzhiyun 	rcu_read_unlock();
728*4882a593Smuzhiyun 	if (state)
729*4882a593Smuzhiyun 		goto out;
730*4882a593Smuzhiyun 	new = nfs4_alloc_open_state();
731*4882a593Smuzhiyun 	spin_lock(&owner->so_lock);
732*4882a593Smuzhiyun 	spin_lock(&inode->i_lock);
733*4882a593Smuzhiyun 	state = __nfs4_find_state_byowner(inode, owner);
734*4882a593Smuzhiyun 	if (state == NULL && new != NULL) {
735*4882a593Smuzhiyun 		state = new;
736*4882a593Smuzhiyun 		state->owner = owner;
737*4882a593Smuzhiyun 		atomic_inc(&owner->so_count);
738*4882a593Smuzhiyun 		ihold(inode);
739*4882a593Smuzhiyun 		state->inode = inode;
740*4882a593Smuzhiyun 		list_add_rcu(&state->inode_states, &nfsi->open_states);
741*4882a593Smuzhiyun 		spin_unlock(&inode->i_lock);
742*4882a593Smuzhiyun 		/* Note: The reclaim code dictates that we add stateless
743*4882a593Smuzhiyun 		 * and read-only stateids to the end of the list */
744*4882a593Smuzhiyun 		list_add_tail(&state->open_states, &owner->so_states);
745*4882a593Smuzhiyun 		spin_unlock(&owner->so_lock);
746*4882a593Smuzhiyun 	} else {
747*4882a593Smuzhiyun 		spin_unlock(&inode->i_lock);
748*4882a593Smuzhiyun 		spin_unlock(&owner->so_lock);
749*4882a593Smuzhiyun 		if (new)
750*4882a593Smuzhiyun 			nfs4_free_open_state(new);
751*4882a593Smuzhiyun 	}
752*4882a593Smuzhiyun out:
753*4882a593Smuzhiyun 	return state;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun 
nfs4_put_open_state(struct nfs4_state * state)756*4882a593Smuzhiyun void nfs4_put_open_state(struct nfs4_state *state)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun 	struct inode *inode = state->inode;
759*4882a593Smuzhiyun 	struct nfs4_state_owner *owner = state->owner;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	if (!refcount_dec_and_lock(&state->count, &owner->so_lock))
762*4882a593Smuzhiyun 		return;
763*4882a593Smuzhiyun 	spin_lock(&inode->i_lock);
764*4882a593Smuzhiyun 	list_del_rcu(&state->inode_states);
765*4882a593Smuzhiyun 	list_del(&state->open_states);
766*4882a593Smuzhiyun 	spin_unlock(&inode->i_lock);
767*4882a593Smuzhiyun 	spin_unlock(&owner->so_lock);
768*4882a593Smuzhiyun 	nfs4_inode_return_delegation_on_close(inode);
769*4882a593Smuzhiyun 	iput(inode);
770*4882a593Smuzhiyun 	nfs4_free_open_state(state);
771*4882a593Smuzhiyun 	nfs4_put_state_owner(owner);
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun /*
775*4882a593Smuzhiyun  * Close the current file.
776*4882a593Smuzhiyun  */
__nfs4_close(struct nfs4_state * state,fmode_t fmode,gfp_t gfp_mask,int wait)777*4882a593Smuzhiyun static void __nfs4_close(struct nfs4_state *state,
778*4882a593Smuzhiyun 		fmode_t fmode, gfp_t gfp_mask, int wait)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun 	struct nfs4_state_owner *owner = state->owner;
781*4882a593Smuzhiyun 	int call_close = 0;
782*4882a593Smuzhiyun 	fmode_t newstate;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	atomic_inc(&owner->so_count);
785*4882a593Smuzhiyun 	/* Protect against nfs4_find_state() */
786*4882a593Smuzhiyun 	spin_lock(&owner->so_lock);
787*4882a593Smuzhiyun 	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
788*4882a593Smuzhiyun 		case FMODE_READ:
789*4882a593Smuzhiyun 			state->n_rdonly--;
790*4882a593Smuzhiyun 			break;
791*4882a593Smuzhiyun 		case FMODE_WRITE:
792*4882a593Smuzhiyun 			state->n_wronly--;
793*4882a593Smuzhiyun 			break;
794*4882a593Smuzhiyun 		case FMODE_READ|FMODE_WRITE:
795*4882a593Smuzhiyun 			state->n_rdwr--;
796*4882a593Smuzhiyun 	}
797*4882a593Smuzhiyun 	newstate = FMODE_READ|FMODE_WRITE;
798*4882a593Smuzhiyun 	if (state->n_rdwr == 0) {
799*4882a593Smuzhiyun 		if (state->n_rdonly == 0) {
800*4882a593Smuzhiyun 			newstate &= ~FMODE_READ;
801*4882a593Smuzhiyun 			call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
802*4882a593Smuzhiyun 			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
803*4882a593Smuzhiyun 		}
804*4882a593Smuzhiyun 		if (state->n_wronly == 0) {
805*4882a593Smuzhiyun 			newstate &= ~FMODE_WRITE;
806*4882a593Smuzhiyun 			call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
807*4882a593Smuzhiyun 			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
808*4882a593Smuzhiyun 		}
809*4882a593Smuzhiyun 		if (newstate == 0)
810*4882a593Smuzhiyun 			clear_bit(NFS_DELEGATED_STATE, &state->flags);
811*4882a593Smuzhiyun 	}
812*4882a593Smuzhiyun 	nfs4_state_set_mode_locked(state, newstate);
813*4882a593Smuzhiyun 	spin_unlock(&owner->so_lock);
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	if (!call_close) {
816*4882a593Smuzhiyun 		nfs4_put_open_state(state);
817*4882a593Smuzhiyun 		nfs4_put_state_owner(owner);
818*4882a593Smuzhiyun 	} else
819*4882a593Smuzhiyun 		nfs4_do_close(state, gfp_mask, wait);
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun 
nfs4_close_state(struct nfs4_state * state,fmode_t fmode)822*4882a593Smuzhiyun void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun 	__nfs4_close(state, fmode, GFP_NOFS, 0);
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun 
nfs4_close_sync(struct nfs4_state * state,fmode_t fmode)827*4882a593Smuzhiyun void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	__nfs4_close(state, fmode, GFP_KERNEL, 1);
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun /*
833*4882a593Smuzhiyun  * Search the state->lock_states for an existing lock_owner
834*4882a593Smuzhiyun  * that is compatible with either of the given owners.
835*4882a593Smuzhiyun  * If the second is non-zero, then the first refers to a Posix-lock
836*4882a593Smuzhiyun  * owner (current->files) and the second refers to a flock/OFD
837*4882a593Smuzhiyun  * owner (struct file*).  In that case, prefer a match for the first
838*4882a593Smuzhiyun  * owner.
839*4882a593Smuzhiyun  * If both sorts of locks are held on the one file we cannot know
840*4882a593Smuzhiyun  * which stateid was intended to be used, so a "correct" choice cannot
841*4882a593Smuzhiyun  * be made.  Failing that, a "consistent" choice is preferable.  The
842*4882a593Smuzhiyun  * consistent choice we make is to prefer the first owner, that of a
843*4882a593Smuzhiyun  * Posix lock.
844*4882a593Smuzhiyun  */
845*4882a593Smuzhiyun static struct nfs4_lock_state *
__nfs4_find_lock_state(struct nfs4_state * state,fl_owner_t fl_owner,fl_owner_t fl_owner2)846*4882a593Smuzhiyun __nfs4_find_lock_state(struct nfs4_state *state,
847*4882a593Smuzhiyun 		       fl_owner_t fl_owner, fl_owner_t fl_owner2)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun 	struct nfs4_lock_state *pos, *ret = NULL;
850*4882a593Smuzhiyun 	list_for_each_entry(pos, &state->lock_states, ls_locks) {
851*4882a593Smuzhiyun 		if (pos->ls_owner == fl_owner) {
852*4882a593Smuzhiyun 			ret = pos;
853*4882a593Smuzhiyun 			break;
854*4882a593Smuzhiyun 		}
855*4882a593Smuzhiyun 		if (pos->ls_owner == fl_owner2)
856*4882a593Smuzhiyun 			ret = pos;
857*4882a593Smuzhiyun 	}
858*4882a593Smuzhiyun 	if (ret)
859*4882a593Smuzhiyun 		refcount_inc(&ret->ls_count);
860*4882a593Smuzhiyun 	return ret;
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun /*
864*4882a593Smuzhiyun  * Return a compatible lock_state. If no initialized lock_state structure
865*4882a593Smuzhiyun  * exists, return an uninitialized one.
866*4882a593Smuzhiyun  *
867*4882a593Smuzhiyun  */
nfs4_alloc_lock_state(struct nfs4_state * state,fl_owner_t fl_owner)868*4882a593Smuzhiyun static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun 	struct nfs4_lock_state *lsp;
871*4882a593Smuzhiyun 	struct nfs_server *server = state->owner->so_server;
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
874*4882a593Smuzhiyun 	if (lsp == NULL)
875*4882a593Smuzhiyun 		return NULL;
876*4882a593Smuzhiyun 	nfs4_init_seqid_counter(&lsp->ls_seqid);
877*4882a593Smuzhiyun 	refcount_set(&lsp->ls_count, 1);
878*4882a593Smuzhiyun 	lsp->ls_state = state;
879*4882a593Smuzhiyun 	lsp->ls_owner = fl_owner;
880*4882a593Smuzhiyun 	lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
881*4882a593Smuzhiyun 	if (lsp->ls_seqid.owner_id < 0)
882*4882a593Smuzhiyun 		goto out_free;
883*4882a593Smuzhiyun 	INIT_LIST_HEAD(&lsp->ls_locks);
884*4882a593Smuzhiyun 	return lsp;
885*4882a593Smuzhiyun out_free:
886*4882a593Smuzhiyun 	kfree(lsp);
887*4882a593Smuzhiyun 	return NULL;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun 
nfs4_free_lock_state(struct nfs_server * server,struct nfs4_lock_state * lsp)890*4882a593Smuzhiyun void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
891*4882a593Smuzhiyun {
892*4882a593Smuzhiyun 	ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id);
893*4882a593Smuzhiyun 	nfs4_destroy_seqid_counter(&lsp->ls_seqid);
894*4882a593Smuzhiyun 	kfree(lsp);
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun /*
898*4882a593Smuzhiyun  * Return a compatible lock_state. If no initialized lock_state structure
899*4882a593Smuzhiyun  * exists, return an uninitialized one.
900*4882a593Smuzhiyun  *
901*4882a593Smuzhiyun  */
nfs4_get_lock_state(struct nfs4_state * state,fl_owner_t owner)902*4882a593Smuzhiyun static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner)
903*4882a593Smuzhiyun {
904*4882a593Smuzhiyun 	struct nfs4_lock_state *lsp, *new = NULL;
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	for(;;) {
907*4882a593Smuzhiyun 		spin_lock(&state->state_lock);
908*4882a593Smuzhiyun 		lsp = __nfs4_find_lock_state(state, owner, NULL);
909*4882a593Smuzhiyun 		if (lsp != NULL)
910*4882a593Smuzhiyun 			break;
911*4882a593Smuzhiyun 		if (new != NULL) {
912*4882a593Smuzhiyun 			list_add(&new->ls_locks, &state->lock_states);
913*4882a593Smuzhiyun 			set_bit(LK_STATE_IN_USE, &state->flags);
914*4882a593Smuzhiyun 			lsp = new;
915*4882a593Smuzhiyun 			new = NULL;
916*4882a593Smuzhiyun 			break;
917*4882a593Smuzhiyun 		}
918*4882a593Smuzhiyun 		spin_unlock(&state->state_lock);
919*4882a593Smuzhiyun 		new = nfs4_alloc_lock_state(state, owner);
920*4882a593Smuzhiyun 		if (new == NULL)
921*4882a593Smuzhiyun 			return NULL;
922*4882a593Smuzhiyun 	}
923*4882a593Smuzhiyun 	spin_unlock(&state->state_lock);
924*4882a593Smuzhiyun 	if (new != NULL)
925*4882a593Smuzhiyun 		nfs4_free_lock_state(state->owner->so_server, new);
926*4882a593Smuzhiyun 	return lsp;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun /*
930*4882a593Smuzhiyun  * Release reference to lock_state, and free it if we see that
931*4882a593Smuzhiyun  * it is no longer in use
932*4882a593Smuzhiyun  */
nfs4_put_lock_state(struct nfs4_lock_state * lsp)933*4882a593Smuzhiyun void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun 	struct nfs_server *server;
936*4882a593Smuzhiyun 	struct nfs4_state *state;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	if (lsp == NULL)
939*4882a593Smuzhiyun 		return;
940*4882a593Smuzhiyun 	state = lsp->ls_state;
941*4882a593Smuzhiyun 	if (!refcount_dec_and_lock(&lsp->ls_count, &state->state_lock))
942*4882a593Smuzhiyun 		return;
943*4882a593Smuzhiyun 	list_del(&lsp->ls_locks);
944*4882a593Smuzhiyun 	if (list_empty(&state->lock_states))
945*4882a593Smuzhiyun 		clear_bit(LK_STATE_IN_USE, &state->flags);
946*4882a593Smuzhiyun 	spin_unlock(&state->state_lock);
947*4882a593Smuzhiyun 	server = state->owner->so_server;
948*4882a593Smuzhiyun 	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
949*4882a593Smuzhiyun 		struct nfs_client *clp = server->nfs_client;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 		clp->cl_mvops->free_lock_state(server, lsp);
952*4882a593Smuzhiyun 	} else
953*4882a593Smuzhiyun 		nfs4_free_lock_state(server, lsp);
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
nfs4_fl_copy_lock(struct file_lock * dst,struct file_lock * src)956*4882a593Smuzhiyun static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun 	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	dst->fl_u.nfs4_fl.owner = lsp;
961*4882a593Smuzhiyun 	refcount_inc(&lsp->ls_count);
962*4882a593Smuzhiyun }
963*4882a593Smuzhiyun 
nfs4_fl_release_lock(struct file_lock * fl)964*4882a593Smuzhiyun static void nfs4_fl_release_lock(struct file_lock *fl)
965*4882a593Smuzhiyun {
966*4882a593Smuzhiyun 	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun static const struct file_lock_operations nfs4_fl_lock_ops = {
970*4882a593Smuzhiyun 	.fl_copy_lock = nfs4_fl_copy_lock,
971*4882a593Smuzhiyun 	.fl_release_private = nfs4_fl_release_lock,
972*4882a593Smuzhiyun };
973*4882a593Smuzhiyun 
nfs4_set_lock_state(struct nfs4_state * state,struct file_lock * fl)974*4882a593Smuzhiyun int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
975*4882a593Smuzhiyun {
976*4882a593Smuzhiyun 	struct nfs4_lock_state *lsp;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	if (fl->fl_ops != NULL)
979*4882a593Smuzhiyun 		return 0;
980*4882a593Smuzhiyun 	lsp = nfs4_get_lock_state(state, fl->fl_owner);
981*4882a593Smuzhiyun 	if (lsp == NULL)
982*4882a593Smuzhiyun 		return -ENOMEM;
983*4882a593Smuzhiyun 	fl->fl_u.nfs4_fl.owner = lsp;
984*4882a593Smuzhiyun 	fl->fl_ops = &nfs4_fl_lock_ops;
985*4882a593Smuzhiyun 	return 0;
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun 
nfs4_copy_lock_stateid(nfs4_stateid * dst,struct nfs4_state * state,const struct nfs_lock_context * l_ctx)988*4882a593Smuzhiyun static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
989*4882a593Smuzhiyun 		struct nfs4_state *state,
990*4882a593Smuzhiyun 		const struct nfs_lock_context *l_ctx)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun 	struct nfs4_lock_state *lsp;
993*4882a593Smuzhiyun 	fl_owner_t fl_owner, fl_flock_owner;
994*4882a593Smuzhiyun 	int ret = -ENOENT;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	if (l_ctx == NULL)
997*4882a593Smuzhiyun 		goto out;
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
1000*4882a593Smuzhiyun 		goto out;
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	fl_owner = l_ctx->lockowner;
1003*4882a593Smuzhiyun 	fl_flock_owner = l_ctx->open_context->flock_owner;
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	spin_lock(&state->state_lock);
1006*4882a593Smuzhiyun 	lsp = __nfs4_find_lock_state(state, fl_owner, fl_flock_owner);
1007*4882a593Smuzhiyun 	if (lsp && test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
1008*4882a593Smuzhiyun 		ret = -EIO;
1009*4882a593Smuzhiyun 	else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
1010*4882a593Smuzhiyun 		nfs4_stateid_copy(dst, &lsp->ls_stateid);
1011*4882a593Smuzhiyun 		ret = 0;
1012*4882a593Smuzhiyun 	}
1013*4882a593Smuzhiyun 	spin_unlock(&state->state_lock);
1014*4882a593Smuzhiyun 	nfs4_put_lock_state(lsp);
1015*4882a593Smuzhiyun out:
1016*4882a593Smuzhiyun 	return ret;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun 
nfs4_copy_open_stateid(nfs4_stateid * dst,struct nfs4_state * state)1019*4882a593Smuzhiyun bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
1020*4882a593Smuzhiyun {
1021*4882a593Smuzhiyun 	bool ret;
1022*4882a593Smuzhiyun 	const nfs4_stateid *src;
1023*4882a593Smuzhiyun 	int seq;
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 	do {
1026*4882a593Smuzhiyun 		ret = false;
1027*4882a593Smuzhiyun 		src = &zero_stateid;
1028*4882a593Smuzhiyun 		seq = read_seqbegin(&state->seqlock);
1029*4882a593Smuzhiyun 		if (test_bit(NFS_OPEN_STATE, &state->flags)) {
1030*4882a593Smuzhiyun 			src = &state->open_stateid;
1031*4882a593Smuzhiyun 			ret = true;
1032*4882a593Smuzhiyun 		}
1033*4882a593Smuzhiyun 		nfs4_stateid_copy(dst, src);
1034*4882a593Smuzhiyun 	} while (read_seqretry(&state->seqlock, seq));
1035*4882a593Smuzhiyun 	return ret;
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun /*
1039*4882a593Smuzhiyun  * Byte-range lock aware utility to initialize the stateid of read/write
1040*4882a593Smuzhiyun  * requests.
1041*4882a593Smuzhiyun  */
nfs4_select_rw_stateid(struct nfs4_state * state,fmode_t fmode,const struct nfs_lock_context * l_ctx,nfs4_stateid * dst,const struct cred ** cred)1042*4882a593Smuzhiyun int nfs4_select_rw_stateid(struct nfs4_state *state,
1043*4882a593Smuzhiyun 		fmode_t fmode, const struct nfs_lock_context *l_ctx,
1044*4882a593Smuzhiyun 		nfs4_stateid *dst, const struct cred **cred)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun 	int ret;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	if (!nfs4_valid_open_stateid(state))
1049*4882a593Smuzhiyun 		return -EIO;
1050*4882a593Smuzhiyun 	if (cred != NULL)
1051*4882a593Smuzhiyun 		*cred = NULL;
1052*4882a593Smuzhiyun 	ret = nfs4_copy_lock_stateid(dst, state, l_ctx);
1053*4882a593Smuzhiyun 	if (ret == -EIO)
1054*4882a593Smuzhiyun 		/* A lost lock - don't even consider delegations */
1055*4882a593Smuzhiyun 		goto out;
1056*4882a593Smuzhiyun 	/* returns true if delegation stateid found and copied */
1057*4882a593Smuzhiyun 	if (nfs4_copy_delegation_stateid(state->inode, fmode, dst, cred)) {
1058*4882a593Smuzhiyun 		ret = 0;
1059*4882a593Smuzhiyun 		goto out;
1060*4882a593Smuzhiyun 	}
1061*4882a593Smuzhiyun 	if (ret != -ENOENT)
1062*4882a593Smuzhiyun 		/* nfs4_copy_delegation_stateid() didn't over-write
1063*4882a593Smuzhiyun 		 * dst, so it still has the lock stateid which we now
1064*4882a593Smuzhiyun 		 * choose to use.
1065*4882a593Smuzhiyun 		 */
1066*4882a593Smuzhiyun 		goto out;
1067*4882a593Smuzhiyun 	ret = nfs4_copy_open_stateid(dst, state) ? 0 : -EAGAIN;
1068*4882a593Smuzhiyun out:
1069*4882a593Smuzhiyun 	if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
1070*4882a593Smuzhiyun 		dst->seqid = 0;
1071*4882a593Smuzhiyun 	return ret;
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun 
nfs_alloc_seqid(struct nfs_seqid_counter * counter,gfp_t gfp_mask)1074*4882a593Smuzhiyun struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
1075*4882a593Smuzhiyun {
1076*4882a593Smuzhiyun 	struct nfs_seqid *new;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	new = kmalloc(sizeof(*new), gfp_mask);
1079*4882a593Smuzhiyun 	if (new == NULL)
1080*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
1081*4882a593Smuzhiyun 	new->sequence = counter;
1082*4882a593Smuzhiyun 	INIT_LIST_HEAD(&new->list);
1083*4882a593Smuzhiyun 	new->task = NULL;
1084*4882a593Smuzhiyun 	return new;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun 
nfs_release_seqid(struct nfs_seqid * seqid)1087*4882a593Smuzhiyun void nfs_release_seqid(struct nfs_seqid *seqid)
1088*4882a593Smuzhiyun {
1089*4882a593Smuzhiyun 	struct nfs_seqid_counter *sequence;
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	if (seqid == NULL || list_empty(&seqid->list))
1092*4882a593Smuzhiyun 		return;
1093*4882a593Smuzhiyun 	sequence = seqid->sequence;
1094*4882a593Smuzhiyun 	spin_lock(&sequence->lock);
1095*4882a593Smuzhiyun 	list_del_init(&seqid->list);
1096*4882a593Smuzhiyun 	if (!list_empty(&sequence->list)) {
1097*4882a593Smuzhiyun 		struct nfs_seqid *next;
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 		next = list_first_entry(&sequence->list,
1100*4882a593Smuzhiyun 				struct nfs_seqid, list);
1101*4882a593Smuzhiyun 		rpc_wake_up_queued_task(&sequence->wait, next->task);
1102*4882a593Smuzhiyun 	}
1103*4882a593Smuzhiyun 	spin_unlock(&sequence->lock);
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun 
nfs_free_seqid(struct nfs_seqid * seqid)1106*4882a593Smuzhiyun void nfs_free_seqid(struct nfs_seqid *seqid)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun 	nfs_release_seqid(seqid);
1109*4882a593Smuzhiyun 	kfree(seqid);
1110*4882a593Smuzhiyun }
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun /*
1113*4882a593Smuzhiyun  * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
1114*4882a593Smuzhiyun  * failed with a seqid incrementing error -
1115*4882a593Smuzhiyun  * see comments nfs4.h:seqid_mutating_error()
1116*4882a593Smuzhiyun  */
nfs_increment_seqid(int status,struct nfs_seqid * seqid)1117*4882a593Smuzhiyun static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
1118*4882a593Smuzhiyun {
1119*4882a593Smuzhiyun 	switch (status) {
1120*4882a593Smuzhiyun 		case 0:
1121*4882a593Smuzhiyun 			break;
1122*4882a593Smuzhiyun 		case -NFS4ERR_BAD_SEQID:
1123*4882a593Smuzhiyun 			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
1124*4882a593Smuzhiyun 				return;
1125*4882a593Smuzhiyun 			pr_warn_ratelimited("NFS: v4 server returned a bad"
1126*4882a593Smuzhiyun 					" sequence-id error on an"
1127*4882a593Smuzhiyun 					" unconfirmed sequence %p!\n",
1128*4882a593Smuzhiyun 					seqid->sequence);
1129*4882a593Smuzhiyun 		case -NFS4ERR_STALE_CLIENTID:
1130*4882a593Smuzhiyun 		case -NFS4ERR_STALE_STATEID:
1131*4882a593Smuzhiyun 		case -NFS4ERR_BAD_STATEID:
1132*4882a593Smuzhiyun 		case -NFS4ERR_BADXDR:
1133*4882a593Smuzhiyun 		case -NFS4ERR_RESOURCE:
1134*4882a593Smuzhiyun 		case -NFS4ERR_NOFILEHANDLE:
1135*4882a593Smuzhiyun 		case -NFS4ERR_MOVED:
1136*4882a593Smuzhiyun 			/* Non-seqid mutating errors */
1137*4882a593Smuzhiyun 			return;
1138*4882a593Smuzhiyun 	}
1139*4882a593Smuzhiyun 	/*
1140*4882a593Smuzhiyun 	 * Note: no locking needed as we are guaranteed to be first
1141*4882a593Smuzhiyun 	 * on the sequence list
1142*4882a593Smuzhiyun 	 */
1143*4882a593Smuzhiyun 	seqid->sequence->counter++;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun 
nfs_increment_open_seqid(int status,struct nfs_seqid * seqid)1146*4882a593Smuzhiyun void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	if (seqid == NULL)
1151*4882a593Smuzhiyun 		return;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid);
1154*4882a593Smuzhiyun 	if (status == -NFS4ERR_BAD_SEQID)
1155*4882a593Smuzhiyun 		nfs4_reset_state_owner(sp);
1156*4882a593Smuzhiyun 	if (!nfs4_has_session(sp->so_server->nfs_client))
1157*4882a593Smuzhiyun 		nfs_increment_seqid(status, seqid);
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun /*
1161*4882a593Smuzhiyun  * Increment the seqid if the LOCK/LOCKU succeeded, or
1162*4882a593Smuzhiyun  * failed with a seqid incrementing error -
1163*4882a593Smuzhiyun  * see comments nfs4.h:seqid_mutating_error()
1164*4882a593Smuzhiyun  */
nfs_increment_lock_seqid(int status,struct nfs_seqid * seqid)1165*4882a593Smuzhiyun void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun 	if (seqid != NULL)
1168*4882a593Smuzhiyun 		nfs_increment_seqid(status, seqid);
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun 
nfs_wait_on_sequence(struct nfs_seqid * seqid,struct rpc_task * task)1171*4882a593Smuzhiyun int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
1172*4882a593Smuzhiyun {
1173*4882a593Smuzhiyun 	struct nfs_seqid_counter *sequence;
1174*4882a593Smuzhiyun 	int status = 0;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	if (seqid == NULL)
1177*4882a593Smuzhiyun 		goto out;
1178*4882a593Smuzhiyun 	sequence = seqid->sequence;
1179*4882a593Smuzhiyun 	spin_lock(&sequence->lock);
1180*4882a593Smuzhiyun 	seqid->task = task;
1181*4882a593Smuzhiyun 	if (list_empty(&seqid->list))
1182*4882a593Smuzhiyun 		list_add_tail(&seqid->list, &sequence->list);
1183*4882a593Smuzhiyun 	if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)
1184*4882a593Smuzhiyun 		goto unlock;
1185*4882a593Smuzhiyun 	rpc_sleep_on(&sequence->wait, task, NULL);
1186*4882a593Smuzhiyun 	status = -EAGAIN;
1187*4882a593Smuzhiyun unlock:
1188*4882a593Smuzhiyun 	spin_unlock(&sequence->lock);
1189*4882a593Smuzhiyun out:
1190*4882a593Smuzhiyun 	return status;
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun static int nfs4_run_state_manager(void *);
1194*4882a593Smuzhiyun 
nfs4_clear_state_manager_bit(struct nfs_client * clp)1195*4882a593Smuzhiyun static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
1196*4882a593Smuzhiyun {
1197*4882a593Smuzhiyun 	smp_mb__before_atomic();
1198*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
1199*4882a593Smuzhiyun 	smp_mb__after_atomic();
1200*4882a593Smuzhiyun 	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
1201*4882a593Smuzhiyun 	rpc_wake_up(&clp->cl_rpcwaitq);
1202*4882a593Smuzhiyun }
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun /*
1205*4882a593Smuzhiyun  * Schedule the nfs_client asynchronous state management routine
1206*4882a593Smuzhiyun  */
nfs4_schedule_state_manager(struct nfs_client * clp)1207*4882a593Smuzhiyun void nfs4_schedule_state_manager(struct nfs_client *clp)
1208*4882a593Smuzhiyun {
1209*4882a593Smuzhiyun 	struct task_struct *task;
1210*4882a593Smuzhiyun 	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
1213*4882a593Smuzhiyun 	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
1214*4882a593Smuzhiyun 		return;
1215*4882a593Smuzhiyun 	__module_get(THIS_MODULE);
1216*4882a593Smuzhiyun 	refcount_inc(&clp->cl_count);
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	/* The rcu_read_lock() is not strictly necessary, as the state
1219*4882a593Smuzhiyun 	 * manager is the only thread that ever changes the rpc_xprt
1220*4882a593Smuzhiyun 	 * after it's initialized.  At this point, we're single threaded. */
1221*4882a593Smuzhiyun 	rcu_read_lock();
1222*4882a593Smuzhiyun 	snprintf(buf, sizeof(buf), "%s-manager",
1223*4882a593Smuzhiyun 			rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
1224*4882a593Smuzhiyun 	rcu_read_unlock();
1225*4882a593Smuzhiyun 	task = kthread_run(nfs4_run_state_manager, clp, "%s", buf);
1226*4882a593Smuzhiyun 	if (IS_ERR(task)) {
1227*4882a593Smuzhiyun 		printk(KERN_ERR "%s: kthread_run: %ld\n",
1228*4882a593Smuzhiyun 			__func__, PTR_ERR(task));
1229*4882a593Smuzhiyun 		nfs4_clear_state_manager_bit(clp);
1230*4882a593Smuzhiyun 		nfs_put_client(clp);
1231*4882a593Smuzhiyun 		module_put(THIS_MODULE);
1232*4882a593Smuzhiyun 	}
1233*4882a593Smuzhiyun }
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun /*
1236*4882a593Smuzhiyun  * Schedule a lease recovery attempt
1237*4882a593Smuzhiyun  */
nfs4_schedule_lease_recovery(struct nfs_client * clp)1238*4882a593Smuzhiyun void nfs4_schedule_lease_recovery(struct nfs_client *clp)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun 	if (!clp)
1241*4882a593Smuzhiyun 		return;
1242*4882a593Smuzhiyun 	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1243*4882a593Smuzhiyun 		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1244*4882a593Smuzhiyun 	dprintk("%s: scheduling lease recovery for server %s\n", __func__,
1245*4882a593Smuzhiyun 			clp->cl_hostname);
1246*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun /**
1251*4882a593Smuzhiyun  * nfs4_schedule_migration_recovery - trigger migration recovery
1252*4882a593Smuzhiyun  *
1253*4882a593Smuzhiyun  * @server: FSID that is migrating
1254*4882a593Smuzhiyun  *
1255*4882a593Smuzhiyun  * Returns zero if recovery has started, otherwise a negative NFS4ERR
1256*4882a593Smuzhiyun  * value is returned.
1257*4882a593Smuzhiyun  */
nfs4_schedule_migration_recovery(const struct nfs_server * server)1258*4882a593Smuzhiyun int nfs4_schedule_migration_recovery(const struct nfs_server *server)
1259*4882a593Smuzhiyun {
1260*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 	if (server->fh_expire_type != NFS4_FH_PERSISTENT) {
1263*4882a593Smuzhiyun 		pr_err("NFS: volatile file handles not supported (server %s)\n",
1264*4882a593Smuzhiyun 				clp->cl_hostname);
1265*4882a593Smuzhiyun 		return -NFS4ERR_IO;
1266*4882a593Smuzhiyun 	}
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	if (test_bit(NFS_MIG_FAILED, &server->mig_status))
1269*4882a593Smuzhiyun 		return -NFS4ERR_IO;
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	dprintk("%s: scheduling migration recovery for (%llx:%llx) on %s\n",
1272*4882a593Smuzhiyun 			__func__,
1273*4882a593Smuzhiyun 			(unsigned long long)server->fsid.major,
1274*4882a593Smuzhiyun 			(unsigned long long)server->fsid.minor,
1275*4882a593Smuzhiyun 			clp->cl_hostname);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	set_bit(NFS_MIG_IN_TRANSITION,
1278*4882a593Smuzhiyun 			&((struct nfs_server *)server)->mig_status);
1279*4882a593Smuzhiyun 	set_bit(NFS4CLNT_MOVED, &clp->cl_state);
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
1282*4882a593Smuzhiyun 	return 0;
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nfs4_schedule_migration_recovery);
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun /**
1287*4882a593Smuzhiyun  * nfs4_schedule_lease_moved_recovery - start lease-moved recovery
1288*4882a593Smuzhiyun  *
1289*4882a593Smuzhiyun  * @clp: server to check for moved leases
1290*4882a593Smuzhiyun  *
1291*4882a593Smuzhiyun  */
nfs4_schedule_lease_moved_recovery(struct nfs_client * clp)1292*4882a593Smuzhiyun void nfs4_schedule_lease_moved_recovery(struct nfs_client *clp)
1293*4882a593Smuzhiyun {
1294*4882a593Smuzhiyun 	dprintk("%s: scheduling lease-moved recovery for client ID %llx on %s\n",
1295*4882a593Smuzhiyun 		__func__, clp->cl_clientid, clp->cl_hostname);
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun 	set_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state);
1298*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
1299*4882a593Smuzhiyun }
1300*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nfs4_schedule_lease_moved_recovery);
1301*4882a593Smuzhiyun 
nfs4_wait_clnt_recover(struct nfs_client * clp)1302*4882a593Smuzhiyun int nfs4_wait_clnt_recover(struct nfs_client *clp)
1303*4882a593Smuzhiyun {
1304*4882a593Smuzhiyun 	int res;
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	might_sleep();
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	refcount_inc(&clp->cl_count);
1309*4882a593Smuzhiyun 	res = wait_on_bit_action(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
1310*4882a593Smuzhiyun 				 nfs_wait_bit_killable, TASK_KILLABLE);
1311*4882a593Smuzhiyun 	if (res)
1312*4882a593Smuzhiyun 		goto out;
1313*4882a593Smuzhiyun 	if (clp->cl_cons_state < 0)
1314*4882a593Smuzhiyun 		res = clp->cl_cons_state;
1315*4882a593Smuzhiyun out:
1316*4882a593Smuzhiyun 	nfs_put_client(clp);
1317*4882a593Smuzhiyun 	return res;
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun 
nfs4_client_recover_expired_lease(struct nfs_client * clp)1320*4882a593Smuzhiyun int nfs4_client_recover_expired_lease(struct nfs_client *clp)
1321*4882a593Smuzhiyun {
1322*4882a593Smuzhiyun 	unsigned int loop;
1323*4882a593Smuzhiyun 	int ret;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
1326*4882a593Smuzhiyun 		ret = nfs4_wait_clnt_recover(clp);
1327*4882a593Smuzhiyun 		if (ret != 0)
1328*4882a593Smuzhiyun 			break;
1329*4882a593Smuzhiyun 		if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
1330*4882a593Smuzhiyun 		    !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
1331*4882a593Smuzhiyun 			break;
1332*4882a593Smuzhiyun 		nfs4_schedule_state_manager(clp);
1333*4882a593Smuzhiyun 		ret = -EIO;
1334*4882a593Smuzhiyun 	}
1335*4882a593Smuzhiyun 	return ret;
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun /*
1339*4882a593Smuzhiyun  * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
1340*4882a593Smuzhiyun  * @clp: client to process
1341*4882a593Smuzhiyun  *
1342*4882a593Smuzhiyun  * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
1343*4882a593Smuzhiyun  * resend of the SETCLIENTID and hence re-establish the
1344*4882a593Smuzhiyun  * callback channel. Then return all existing delegations.
1345*4882a593Smuzhiyun  */
nfs40_handle_cb_pathdown(struct nfs_client * clp)1346*4882a593Smuzhiyun static void nfs40_handle_cb_pathdown(struct nfs_client *clp)
1347*4882a593Smuzhiyun {
1348*4882a593Smuzhiyun 	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1349*4882a593Smuzhiyun 	nfs_expire_all_delegations(clp);
1350*4882a593Smuzhiyun 	dprintk("%s: handling CB_PATHDOWN recovery for server %s\n", __func__,
1351*4882a593Smuzhiyun 			clp->cl_hostname);
1352*4882a593Smuzhiyun }
1353*4882a593Smuzhiyun 
nfs4_schedule_path_down_recovery(struct nfs_client * clp)1354*4882a593Smuzhiyun void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
1355*4882a593Smuzhiyun {
1356*4882a593Smuzhiyun 	nfs40_handle_cb_pathdown(clp);
1357*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
1358*4882a593Smuzhiyun }
1359*4882a593Smuzhiyun 
nfs4_state_mark_reclaim_reboot(struct nfs_client * clp,struct nfs4_state * state)1360*4882a593Smuzhiyun static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
1361*4882a593Smuzhiyun {
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 	if (!nfs4_valid_open_stateid(state))
1364*4882a593Smuzhiyun 		return 0;
1365*4882a593Smuzhiyun 	set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
1366*4882a593Smuzhiyun 	/* Don't recover state that expired before the reboot */
1367*4882a593Smuzhiyun 	if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) {
1368*4882a593Smuzhiyun 		clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
1369*4882a593Smuzhiyun 		return 0;
1370*4882a593Smuzhiyun 	}
1371*4882a593Smuzhiyun 	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
1372*4882a593Smuzhiyun 	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
1373*4882a593Smuzhiyun 	return 1;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun 
nfs4_state_mark_reclaim_nograce(struct nfs_client * clp,struct nfs4_state * state)1376*4882a593Smuzhiyun int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
1377*4882a593Smuzhiyun {
1378*4882a593Smuzhiyun 	if (!nfs4_valid_open_stateid(state))
1379*4882a593Smuzhiyun 		return 0;
1380*4882a593Smuzhiyun 	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
1381*4882a593Smuzhiyun 	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
1382*4882a593Smuzhiyun 	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
1383*4882a593Smuzhiyun 	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
1384*4882a593Smuzhiyun 	return 1;
1385*4882a593Smuzhiyun }
1386*4882a593Smuzhiyun 
nfs4_schedule_stateid_recovery(const struct nfs_server * server,struct nfs4_state * state)1387*4882a593Smuzhiyun int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
1388*4882a593Smuzhiyun {
1389*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
1390*4882a593Smuzhiyun 
1391*4882a593Smuzhiyun 	if (!nfs4_state_mark_reclaim_nograce(clp, state))
1392*4882a593Smuzhiyun 		return -EBADF;
1393*4882a593Smuzhiyun 	nfs_inode_find_delegation_state_and_recover(state->inode,
1394*4882a593Smuzhiyun 			&state->stateid);
1395*4882a593Smuzhiyun 	dprintk("%s: scheduling stateid recovery for server %s\n", __func__,
1396*4882a593Smuzhiyun 			clp->cl_hostname);
1397*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
1398*4882a593Smuzhiyun 	return 0;
1399*4882a593Smuzhiyun }
1400*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun static struct nfs4_lock_state *
nfs_state_find_lock_state_by_stateid(struct nfs4_state * state,const nfs4_stateid * stateid)1403*4882a593Smuzhiyun nfs_state_find_lock_state_by_stateid(struct nfs4_state *state,
1404*4882a593Smuzhiyun 		const nfs4_stateid *stateid)
1405*4882a593Smuzhiyun {
1406*4882a593Smuzhiyun 	struct nfs4_lock_state *pos;
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 	list_for_each_entry(pos, &state->lock_states, ls_locks) {
1409*4882a593Smuzhiyun 		if (!test_bit(NFS_LOCK_INITIALIZED, &pos->ls_flags))
1410*4882a593Smuzhiyun 			continue;
1411*4882a593Smuzhiyun 		if (nfs4_stateid_match_or_older(&pos->ls_stateid, stateid))
1412*4882a593Smuzhiyun 			return pos;
1413*4882a593Smuzhiyun 	}
1414*4882a593Smuzhiyun 	return NULL;
1415*4882a593Smuzhiyun }
1416*4882a593Smuzhiyun 
nfs_state_lock_state_matches_stateid(struct nfs4_state * state,const nfs4_stateid * stateid)1417*4882a593Smuzhiyun static bool nfs_state_lock_state_matches_stateid(struct nfs4_state *state,
1418*4882a593Smuzhiyun 		const nfs4_stateid *stateid)
1419*4882a593Smuzhiyun {
1420*4882a593Smuzhiyun 	bool found = false;
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	if (test_bit(LK_STATE_IN_USE, &state->flags)) {
1423*4882a593Smuzhiyun 		spin_lock(&state->state_lock);
1424*4882a593Smuzhiyun 		if (nfs_state_find_lock_state_by_stateid(state, stateid))
1425*4882a593Smuzhiyun 			found = true;
1426*4882a593Smuzhiyun 		spin_unlock(&state->state_lock);
1427*4882a593Smuzhiyun 	}
1428*4882a593Smuzhiyun 	return found;
1429*4882a593Smuzhiyun }
1430*4882a593Smuzhiyun 
nfs_inode_find_state_and_recover(struct inode * inode,const nfs4_stateid * stateid)1431*4882a593Smuzhiyun void nfs_inode_find_state_and_recover(struct inode *inode,
1432*4882a593Smuzhiyun 		const nfs4_stateid *stateid)
1433*4882a593Smuzhiyun {
1434*4882a593Smuzhiyun 	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
1435*4882a593Smuzhiyun 	struct nfs_inode *nfsi = NFS_I(inode);
1436*4882a593Smuzhiyun 	struct nfs_open_context *ctx;
1437*4882a593Smuzhiyun 	struct nfs4_state *state;
1438*4882a593Smuzhiyun 	bool found = false;
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun 	rcu_read_lock();
1441*4882a593Smuzhiyun 	list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
1442*4882a593Smuzhiyun 		state = ctx->state;
1443*4882a593Smuzhiyun 		if (state == NULL)
1444*4882a593Smuzhiyun 			continue;
1445*4882a593Smuzhiyun 		if (nfs4_stateid_match_or_older(&state->stateid, stateid) &&
1446*4882a593Smuzhiyun 		    nfs4_state_mark_reclaim_nograce(clp, state)) {
1447*4882a593Smuzhiyun 			found = true;
1448*4882a593Smuzhiyun 			continue;
1449*4882a593Smuzhiyun 		}
1450*4882a593Smuzhiyun 		if (test_bit(NFS_OPEN_STATE, &state->flags) &&
1451*4882a593Smuzhiyun 		    nfs4_stateid_match_or_older(&state->open_stateid, stateid) &&
1452*4882a593Smuzhiyun 		    nfs4_state_mark_reclaim_nograce(clp, state)) {
1453*4882a593Smuzhiyun 			found = true;
1454*4882a593Smuzhiyun 			continue;
1455*4882a593Smuzhiyun 		}
1456*4882a593Smuzhiyun 		if (nfs_state_lock_state_matches_stateid(state, stateid) &&
1457*4882a593Smuzhiyun 		    nfs4_state_mark_reclaim_nograce(clp, state))
1458*4882a593Smuzhiyun 			found = true;
1459*4882a593Smuzhiyun 	}
1460*4882a593Smuzhiyun 	rcu_read_unlock();
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun 	nfs_inode_find_delegation_state_and_recover(inode, stateid);
1463*4882a593Smuzhiyun 	if (found)
1464*4882a593Smuzhiyun 		nfs4_schedule_state_manager(clp);
1465*4882a593Smuzhiyun }
1466*4882a593Smuzhiyun 
nfs4_state_mark_open_context_bad(struct nfs4_state * state,int err)1467*4882a593Smuzhiyun static void nfs4_state_mark_open_context_bad(struct nfs4_state *state, int err)
1468*4882a593Smuzhiyun {
1469*4882a593Smuzhiyun 	struct inode *inode = state->inode;
1470*4882a593Smuzhiyun 	struct nfs_inode *nfsi = NFS_I(inode);
1471*4882a593Smuzhiyun 	struct nfs_open_context *ctx;
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	rcu_read_lock();
1474*4882a593Smuzhiyun 	list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
1475*4882a593Smuzhiyun 		if (ctx->state != state)
1476*4882a593Smuzhiyun 			continue;
1477*4882a593Smuzhiyun 		set_bit(NFS_CONTEXT_BAD, &ctx->flags);
1478*4882a593Smuzhiyun 		pr_warn("NFSv4: state recovery failed for open file %pd2, "
1479*4882a593Smuzhiyun 				"error = %d\n", ctx->dentry, err);
1480*4882a593Smuzhiyun 	}
1481*4882a593Smuzhiyun 	rcu_read_unlock();
1482*4882a593Smuzhiyun }
1483*4882a593Smuzhiyun 
nfs4_state_mark_recovery_failed(struct nfs4_state * state,int error)1484*4882a593Smuzhiyun static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
1485*4882a593Smuzhiyun {
1486*4882a593Smuzhiyun 	set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags);
1487*4882a593Smuzhiyun 	nfs4_state_mark_open_context_bad(state, error);
1488*4882a593Smuzhiyun }
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 
nfs4_reclaim_locks(struct nfs4_state * state,const struct nfs4_state_recovery_ops * ops)1491*4882a593Smuzhiyun static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
1492*4882a593Smuzhiyun {
1493*4882a593Smuzhiyun 	struct inode *inode = state->inode;
1494*4882a593Smuzhiyun 	struct nfs_inode *nfsi = NFS_I(inode);
1495*4882a593Smuzhiyun 	struct file_lock *fl;
1496*4882a593Smuzhiyun 	struct nfs4_lock_state *lsp;
1497*4882a593Smuzhiyun 	int status = 0;
1498*4882a593Smuzhiyun 	struct file_lock_context *flctx = inode->i_flctx;
1499*4882a593Smuzhiyun 	struct list_head *list;
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	if (flctx == NULL)
1502*4882a593Smuzhiyun 		return 0;
1503*4882a593Smuzhiyun 
1504*4882a593Smuzhiyun 	list = &flctx->flc_posix;
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	/* Guard against delegation returns and new lock/unlock calls */
1507*4882a593Smuzhiyun 	down_write(&nfsi->rwsem);
1508*4882a593Smuzhiyun 	spin_lock(&flctx->flc_lock);
1509*4882a593Smuzhiyun restart:
1510*4882a593Smuzhiyun 	list_for_each_entry(fl, list, fl_list) {
1511*4882a593Smuzhiyun 		if (nfs_file_open_context(fl->fl_file)->state != state)
1512*4882a593Smuzhiyun 			continue;
1513*4882a593Smuzhiyun 		spin_unlock(&flctx->flc_lock);
1514*4882a593Smuzhiyun 		status = ops->recover_lock(state, fl);
1515*4882a593Smuzhiyun 		switch (status) {
1516*4882a593Smuzhiyun 		case 0:
1517*4882a593Smuzhiyun 			break;
1518*4882a593Smuzhiyun 		case -ETIMEDOUT:
1519*4882a593Smuzhiyun 		case -ESTALE:
1520*4882a593Smuzhiyun 		case -NFS4ERR_ADMIN_REVOKED:
1521*4882a593Smuzhiyun 		case -NFS4ERR_STALE_STATEID:
1522*4882a593Smuzhiyun 		case -NFS4ERR_BAD_STATEID:
1523*4882a593Smuzhiyun 		case -NFS4ERR_EXPIRED:
1524*4882a593Smuzhiyun 		case -NFS4ERR_NO_GRACE:
1525*4882a593Smuzhiyun 		case -NFS4ERR_STALE_CLIENTID:
1526*4882a593Smuzhiyun 		case -NFS4ERR_BADSESSION:
1527*4882a593Smuzhiyun 		case -NFS4ERR_BADSLOT:
1528*4882a593Smuzhiyun 		case -NFS4ERR_BAD_HIGH_SLOT:
1529*4882a593Smuzhiyun 		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1530*4882a593Smuzhiyun 			goto out;
1531*4882a593Smuzhiyun 		default:
1532*4882a593Smuzhiyun 			pr_err("NFS: %s: unhandled error %d\n",
1533*4882a593Smuzhiyun 					__func__, status);
1534*4882a593Smuzhiyun 			fallthrough;
1535*4882a593Smuzhiyun 		case -ENOMEM:
1536*4882a593Smuzhiyun 		case -NFS4ERR_DENIED:
1537*4882a593Smuzhiyun 		case -NFS4ERR_RECLAIM_BAD:
1538*4882a593Smuzhiyun 		case -NFS4ERR_RECLAIM_CONFLICT:
1539*4882a593Smuzhiyun 			lsp = fl->fl_u.nfs4_fl.owner;
1540*4882a593Smuzhiyun 			if (lsp)
1541*4882a593Smuzhiyun 				set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
1542*4882a593Smuzhiyun 			status = 0;
1543*4882a593Smuzhiyun 		}
1544*4882a593Smuzhiyun 		spin_lock(&flctx->flc_lock);
1545*4882a593Smuzhiyun 	}
1546*4882a593Smuzhiyun 	if (list == &flctx->flc_posix) {
1547*4882a593Smuzhiyun 		list = &flctx->flc_flock;
1548*4882a593Smuzhiyun 		goto restart;
1549*4882a593Smuzhiyun 	}
1550*4882a593Smuzhiyun 	spin_unlock(&flctx->flc_lock);
1551*4882a593Smuzhiyun out:
1552*4882a593Smuzhiyun 	up_write(&nfsi->rwsem);
1553*4882a593Smuzhiyun 	return status;
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun #ifdef CONFIG_NFS_V4_2
nfs42_complete_copies(struct nfs4_state_owner * sp,struct nfs4_state * state)1557*4882a593Smuzhiyun static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state *state)
1558*4882a593Smuzhiyun {
1559*4882a593Smuzhiyun 	struct nfs4_copy_state *copy;
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
1562*4882a593Smuzhiyun 		!test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags))
1563*4882a593Smuzhiyun 		return;
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 	spin_lock(&sp->so_server->nfs_client->cl_lock);
1566*4882a593Smuzhiyun 	list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
1567*4882a593Smuzhiyun 		if ((test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
1568*4882a593Smuzhiyun 				!nfs4_stateid_match_other(&state->stateid,
1569*4882a593Smuzhiyun 				&copy->parent_dst_state->stateid)))
1570*4882a593Smuzhiyun 				continue;
1571*4882a593Smuzhiyun 		copy->flags = 1;
1572*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
1573*4882a593Smuzhiyun 				&state->flags)) {
1574*4882a593Smuzhiyun 			clear_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags);
1575*4882a593Smuzhiyun 			complete(&copy->completion);
1576*4882a593Smuzhiyun 		}
1577*4882a593Smuzhiyun 	}
1578*4882a593Smuzhiyun 	list_for_each_entry(copy, &sp->so_server->ss_copies, src_copies) {
1579*4882a593Smuzhiyun 		if ((test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags) &&
1580*4882a593Smuzhiyun 				!nfs4_stateid_match_other(&state->stateid,
1581*4882a593Smuzhiyun 				&copy->parent_src_state->stateid)))
1582*4882a593Smuzhiyun 				continue;
1583*4882a593Smuzhiyun 		copy->flags = 1;
1584*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
1585*4882a593Smuzhiyun 				&state->flags))
1586*4882a593Smuzhiyun 			complete(&copy->completion);
1587*4882a593Smuzhiyun 	}
1588*4882a593Smuzhiyun 	spin_unlock(&sp->so_server->nfs_client->cl_lock);
1589*4882a593Smuzhiyun }
1590*4882a593Smuzhiyun #else /* !CONFIG_NFS_V4_2 */
nfs42_complete_copies(struct nfs4_state_owner * sp,struct nfs4_state * state)1591*4882a593Smuzhiyun static inline void nfs42_complete_copies(struct nfs4_state_owner *sp,
1592*4882a593Smuzhiyun 					 struct nfs4_state *state)
1593*4882a593Smuzhiyun {
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun #endif /* CONFIG_NFS_V4_2 */
1596*4882a593Smuzhiyun 
__nfs4_reclaim_open_state(struct nfs4_state_owner * sp,struct nfs4_state * state,const struct nfs4_state_recovery_ops * ops)1597*4882a593Smuzhiyun static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_state *state,
1598*4882a593Smuzhiyun 				     const struct nfs4_state_recovery_ops *ops)
1599*4882a593Smuzhiyun {
1600*4882a593Smuzhiyun 	struct nfs4_lock_state *lock;
1601*4882a593Smuzhiyun 	int status;
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun 	status = ops->recover_open(sp, state);
1604*4882a593Smuzhiyun 	if (status < 0)
1605*4882a593Smuzhiyun 		return status;
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun 	status = nfs4_reclaim_locks(state, ops);
1608*4882a593Smuzhiyun 	if (status < 0)
1609*4882a593Smuzhiyun 		return status;
1610*4882a593Smuzhiyun 
1611*4882a593Smuzhiyun 	if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) {
1612*4882a593Smuzhiyun 		spin_lock(&state->state_lock);
1613*4882a593Smuzhiyun 		list_for_each_entry(lock, &state->lock_states, ls_locks) {
1614*4882a593Smuzhiyun 			trace_nfs4_state_lock_reclaim(state, lock);
1615*4882a593Smuzhiyun 			if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
1616*4882a593Smuzhiyun 				pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n", __func__);
1617*4882a593Smuzhiyun 		}
1618*4882a593Smuzhiyun 		spin_unlock(&state->state_lock);
1619*4882a593Smuzhiyun 	}
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 	nfs42_complete_copies(sp, state);
1622*4882a593Smuzhiyun 	clear_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
1623*4882a593Smuzhiyun 	return status;
1624*4882a593Smuzhiyun }
1625*4882a593Smuzhiyun 
nfs4_reclaim_open_state(struct nfs4_state_owner * sp,const struct nfs4_state_recovery_ops * ops)1626*4882a593Smuzhiyun static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
1627*4882a593Smuzhiyun {
1628*4882a593Smuzhiyun 	struct nfs4_state *state;
1629*4882a593Smuzhiyun 	unsigned int loop = 0;
1630*4882a593Smuzhiyun 	int status = 0;
1631*4882a593Smuzhiyun #ifdef CONFIG_NFS_V4_2
1632*4882a593Smuzhiyun 	bool found_ssc_copy_state = false;
1633*4882a593Smuzhiyun #endif /* CONFIG_NFS_V4_2 */
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	/* Note: we rely on the sp->so_states list being ordered
1636*4882a593Smuzhiyun 	 * so that we always reclaim open(O_RDWR) and/or open(O_WRITE)
1637*4882a593Smuzhiyun 	 * states first.
1638*4882a593Smuzhiyun 	 * This is needed to ensure that the server won't give us any
1639*4882a593Smuzhiyun 	 * read delegations that we have to return if, say, we are
1640*4882a593Smuzhiyun 	 * recovering after a network partition or a reboot from a
1641*4882a593Smuzhiyun 	 * server that doesn't support a grace period.
1642*4882a593Smuzhiyun 	 */
1643*4882a593Smuzhiyun 	spin_lock(&sp->so_lock);
1644*4882a593Smuzhiyun 	raw_write_seqcount_begin(&sp->so_reclaim_seqcount);
1645*4882a593Smuzhiyun restart:
1646*4882a593Smuzhiyun 	list_for_each_entry(state, &sp->so_states, open_states) {
1647*4882a593Smuzhiyun 		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
1648*4882a593Smuzhiyun 			continue;
1649*4882a593Smuzhiyun 		if (!nfs4_valid_open_stateid(state))
1650*4882a593Smuzhiyun 			continue;
1651*4882a593Smuzhiyun 		if (state->state == 0)
1652*4882a593Smuzhiyun 			continue;
1653*4882a593Smuzhiyun #ifdef CONFIG_NFS_V4_2
1654*4882a593Smuzhiyun 		if (test_bit(NFS_SRV_SSC_COPY_STATE, &state->flags)) {
1655*4882a593Smuzhiyun 			nfs4_state_mark_recovery_failed(state, -EIO);
1656*4882a593Smuzhiyun 			found_ssc_copy_state = true;
1657*4882a593Smuzhiyun 			continue;
1658*4882a593Smuzhiyun 		}
1659*4882a593Smuzhiyun #endif /* CONFIG_NFS_V4_2 */
1660*4882a593Smuzhiyun 		refcount_inc(&state->count);
1661*4882a593Smuzhiyun 		spin_unlock(&sp->so_lock);
1662*4882a593Smuzhiyun 		status = __nfs4_reclaim_open_state(sp, state, ops);
1663*4882a593Smuzhiyun 
1664*4882a593Smuzhiyun 		switch (status) {
1665*4882a593Smuzhiyun 		default:
1666*4882a593Smuzhiyun 			if (status >= 0) {
1667*4882a593Smuzhiyun 				loop = 0;
1668*4882a593Smuzhiyun 				break;
1669*4882a593Smuzhiyun 			}
1670*4882a593Smuzhiyun 			printk(KERN_ERR "NFS: %s: unhandled error %d\n", __func__, status);
1671*4882a593Smuzhiyun 			fallthrough;
1672*4882a593Smuzhiyun 		case -ENOENT:
1673*4882a593Smuzhiyun 		case -ENOMEM:
1674*4882a593Smuzhiyun 		case -EACCES:
1675*4882a593Smuzhiyun 		case -EROFS:
1676*4882a593Smuzhiyun 		case -EIO:
1677*4882a593Smuzhiyun 		case -ESTALE:
1678*4882a593Smuzhiyun 			/* Open state on this file cannot be recovered */
1679*4882a593Smuzhiyun 			nfs4_state_mark_recovery_failed(state, status);
1680*4882a593Smuzhiyun 			break;
1681*4882a593Smuzhiyun 		case -EAGAIN:
1682*4882a593Smuzhiyun 			ssleep(1);
1683*4882a593Smuzhiyun 			if (loop++ < 10) {
1684*4882a593Smuzhiyun 				set_bit(ops->state_flag_bit, &state->flags);
1685*4882a593Smuzhiyun 				break;
1686*4882a593Smuzhiyun 			}
1687*4882a593Smuzhiyun 			fallthrough;
1688*4882a593Smuzhiyun 		case -NFS4ERR_ADMIN_REVOKED:
1689*4882a593Smuzhiyun 		case -NFS4ERR_STALE_STATEID:
1690*4882a593Smuzhiyun 		case -NFS4ERR_OLD_STATEID:
1691*4882a593Smuzhiyun 		case -NFS4ERR_BAD_STATEID:
1692*4882a593Smuzhiyun 		case -NFS4ERR_RECLAIM_BAD:
1693*4882a593Smuzhiyun 		case -NFS4ERR_RECLAIM_CONFLICT:
1694*4882a593Smuzhiyun 			nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
1695*4882a593Smuzhiyun 			break;
1696*4882a593Smuzhiyun 		case -NFS4ERR_EXPIRED:
1697*4882a593Smuzhiyun 		case -NFS4ERR_NO_GRACE:
1698*4882a593Smuzhiyun 			nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
1699*4882a593Smuzhiyun 			fallthrough;
1700*4882a593Smuzhiyun 		case -NFS4ERR_STALE_CLIENTID:
1701*4882a593Smuzhiyun 		case -NFS4ERR_BADSESSION:
1702*4882a593Smuzhiyun 		case -NFS4ERR_BADSLOT:
1703*4882a593Smuzhiyun 		case -NFS4ERR_BAD_HIGH_SLOT:
1704*4882a593Smuzhiyun 		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1705*4882a593Smuzhiyun 		case -ETIMEDOUT:
1706*4882a593Smuzhiyun 			goto out_err;
1707*4882a593Smuzhiyun 		}
1708*4882a593Smuzhiyun 		nfs4_put_open_state(state);
1709*4882a593Smuzhiyun 		spin_lock(&sp->so_lock);
1710*4882a593Smuzhiyun 		goto restart;
1711*4882a593Smuzhiyun 	}
1712*4882a593Smuzhiyun 	raw_write_seqcount_end(&sp->so_reclaim_seqcount);
1713*4882a593Smuzhiyun 	spin_unlock(&sp->so_lock);
1714*4882a593Smuzhiyun #ifdef CONFIG_NFS_V4_2
1715*4882a593Smuzhiyun 	if (found_ssc_copy_state)
1716*4882a593Smuzhiyun 		return -EIO;
1717*4882a593Smuzhiyun #endif /* CONFIG_NFS_V4_2 */
1718*4882a593Smuzhiyun 	return 0;
1719*4882a593Smuzhiyun out_err:
1720*4882a593Smuzhiyun 	nfs4_put_open_state(state);
1721*4882a593Smuzhiyun 	spin_lock(&sp->so_lock);
1722*4882a593Smuzhiyun 	raw_write_seqcount_end(&sp->so_reclaim_seqcount);
1723*4882a593Smuzhiyun 	spin_unlock(&sp->so_lock);
1724*4882a593Smuzhiyun 	return status;
1725*4882a593Smuzhiyun }
1726*4882a593Smuzhiyun 
nfs4_clear_open_state(struct nfs4_state * state)1727*4882a593Smuzhiyun static void nfs4_clear_open_state(struct nfs4_state *state)
1728*4882a593Smuzhiyun {
1729*4882a593Smuzhiyun 	struct nfs4_lock_state *lock;
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun 	clear_bit(NFS_DELEGATED_STATE, &state->flags);
1732*4882a593Smuzhiyun 	clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1733*4882a593Smuzhiyun 	clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1734*4882a593Smuzhiyun 	clear_bit(NFS_O_RDWR_STATE, &state->flags);
1735*4882a593Smuzhiyun 	spin_lock(&state->state_lock);
1736*4882a593Smuzhiyun 	list_for_each_entry(lock, &state->lock_states, ls_locks) {
1737*4882a593Smuzhiyun 		lock->ls_seqid.flags = 0;
1738*4882a593Smuzhiyun 		clear_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags);
1739*4882a593Smuzhiyun 	}
1740*4882a593Smuzhiyun 	spin_unlock(&state->state_lock);
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun 
nfs4_reset_seqids(struct nfs_server * server,int (* mark_reclaim)(struct nfs_client * clp,struct nfs4_state * state))1743*4882a593Smuzhiyun static void nfs4_reset_seqids(struct nfs_server *server,
1744*4882a593Smuzhiyun 	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
1745*4882a593Smuzhiyun {
1746*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
1747*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
1748*4882a593Smuzhiyun 	struct rb_node *pos;
1749*4882a593Smuzhiyun 	struct nfs4_state *state;
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	spin_lock(&clp->cl_lock);
1752*4882a593Smuzhiyun 	for (pos = rb_first(&server->state_owners);
1753*4882a593Smuzhiyun 	     pos != NULL;
1754*4882a593Smuzhiyun 	     pos = rb_next(pos)) {
1755*4882a593Smuzhiyun 		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
1756*4882a593Smuzhiyun 		sp->so_seqid.flags = 0;
1757*4882a593Smuzhiyun 		spin_lock(&sp->so_lock);
1758*4882a593Smuzhiyun 		list_for_each_entry(state, &sp->so_states, open_states) {
1759*4882a593Smuzhiyun 			if (mark_reclaim(clp, state))
1760*4882a593Smuzhiyun 				nfs4_clear_open_state(state);
1761*4882a593Smuzhiyun 		}
1762*4882a593Smuzhiyun 		spin_unlock(&sp->so_lock);
1763*4882a593Smuzhiyun 	}
1764*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun 
nfs4_state_mark_reclaim_helper(struct nfs_client * clp,int (* mark_reclaim)(struct nfs_client * clp,struct nfs4_state * state))1767*4882a593Smuzhiyun static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp,
1768*4882a593Smuzhiyun 	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
1769*4882a593Smuzhiyun {
1770*4882a593Smuzhiyun 	struct nfs_server *server;
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun 	rcu_read_lock();
1773*4882a593Smuzhiyun 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
1774*4882a593Smuzhiyun 		nfs4_reset_seqids(server, mark_reclaim);
1775*4882a593Smuzhiyun 	rcu_read_unlock();
1776*4882a593Smuzhiyun }
1777*4882a593Smuzhiyun 
nfs4_state_start_reclaim_reboot(struct nfs_client * clp)1778*4882a593Smuzhiyun static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
1779*4882a593Smuzhiyun {
1780*4882a593Smuzhiyun 	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
1781*4882a593Smuzhiyun 	/* Mark all delegations for reclaim */
1782*4882a593Smuzhiyun 	nfs_delegation_mark_reclaim(clp);
1783*4882a593Smuzhiyun 	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
1784*4882a593Smuzhiyun }
1785*4882a593Smuzhiyun 
nfs4_reclaim_complete(struct nfs_client * clp,const struct nfs4_state_recovery_ops * ops,const struct cred * cred)1786*4882a593Smuzhiyun static int nfs4_reclaim_complete(struct nfs_client *clp,
1787*4882a593Smuzhiyun 				 const struct nfs4_state_recovery_ops *ops,
1788*4882a593Smuzhiyun 				 const struct cred *cred)
1789*4882a593Smuzhiyun {
1790*4882a593Smuzhiyun 	/* Notify the server we're done reclaiming our state */
1791*4882a593Smuzhiyun 	if (ops->reclaim_complete)
1792*4882a593Smuzhiyun 		return ops->reclaim_complete(clp, cred);
1793*4882a593Smuzhiyun 	return 0;
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun 
nfs4_clear_reclaim_server(struct nfs_server * server)1796*4882a593Smuzhiyun static void nfs4_clear_reclaim_server(struct nfs_server *server)
1797*4882a593Smuzhiyun {
1798*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
1799*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
1800*4882a593Smuzhiyun 	struct rb_node *pos;
1801*4882a593Smuzhiyun 	struct nfs4_state *state;
1802*4882a593Smuzhiyun 
1803*4882a593Smuzhiyun 	spin_lock(&clp->cl_lock);
1804*4882a593Smuzhiyun 	for (pos = rb_first(&server->state_owners);
1805*4882a593Smuzhiyun 	     pos != NULL;
1806*4882a593Smuzhiyun 	     pos = rb_next(pos)) {
1807*4882a593Smuzhiyun 		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
1808*4882a593Smuzhiyun 		spin_lock(&sp->so_lock);
1809*4882a593Smuzhiyun 		list_for_each_entry(state, &sp->so_states, open_states) {
1810*4882a593Smuzhiyun 			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT,
1811*4882a593Smuzhiyun 						&state->flags))
1812*4882a593Smuzhiyun 				continue;
1813*4882a593Smuzhiyun 			nfs4_state_mark_reclaim_nograce(clp, state);
1814*4882a593Smuzhiyun 		}
1815*4882a593Smuzhiyun 		spin_unlock(&sp->so_lock);
1816*4882a593Smuzhiyun 	}
1817*4882a593Smuzhiyun 	spin_unlock(&clp->cl_lock);
1818*4882a593Smuzhiyun }
1819*4882a593Smuzhiyun 
nfs4_state_clear_reclaim_reboot(struct nfs_client * clp)1820*4882a593Smuzhiyun static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp)
1821*4882a593Smuzhiyun {
1822*4882a593Smuzhiyun 	struct nfs_server *server;
1823*4882a593Smuzhiyun 
1824*4882a593Smuzhiyun 	if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
1825*4882a593Smuzhiyun 		return 0;
1826*4882a593Smuzhiyun 
1827*4882a593Smuzhiyun 	rcu_read_lock();
1828*4882a593Smuzhiyun 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
1829*4882a593Smuzhiyun 		nfs4_clear_reclaim_server(server);
1830*4882a593Smuzhiyun 	rcu_read_unlock();
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 	nfs_delegation_reap_unclaimed(clp);
1833*4882a593Smuzhiyun 	return 1;
1834*4882a593Smuzhiyun }
1835*4882a593Smuzhiyun 
nfs4_state_end_reclaim_reboot(struct nfs_client * clp)1836*4882a593Smuzhiyun static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
1837*4882a593Smuzhiyun {
1838*4882a593Smuzhiyun 	const struct nfs4_state_recovery_ops *ops;
1839*4882a593Smuzhiyun 	const struct cred *cred;
1840*4882a593Smuzhiyun 	int err;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	if (!nfs4_state_clear_reclaim_reboot(clp))
1843*4882a593Smuzhiyun 		return;
1844*4882a593Smuzhiyun 	ops = clp->cl_mvops->reboot_recovery_ops;
1845*4882a593Smuzhiyun 	cred = nfs4_get_clid_cred(clp);
1846*4882a593Smuzhiyun 	err = nfs4_reclaim_complete(clp, ops, cred);
1847*4882a593Smuzhiyun 	put_cred(cred);
1848*4882a593Smuzhiyun 	if (err == -NFS4ERR_CONN_NOT_BOUND_TO_SESSION)
1849*4882a593Smuzhiyun 		set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
1850*4882a593Smuzhiyun }
1851*4882a593Smuzhiyun 
nfs4_state_start_reclaim_nograce(struct nfs_client * clp)1852*4882a593Smuzhiyun static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
1853*4882a593Smuzhiyun {
1854*4882a593Smuzhiyun 	nfs_mark_test_expired_all_delegations(clp);
1855*4882a593Smuzhiyun 	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
1856*4882a593Smuzhiyun }
1857*4882a593Smuzhiyun 
nfs4_recovery_handle_error(struct nfs_client * clp,int error)1858*4882a593Smuzhiyun static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1859*4882a593Smuzhiyun {
1860*4882a593Smuzhiyun 	switch (error) {
1861*4882a593Smuzhiyun 	case 0:
1862*4882a593Smuzhiyun 		break;
1863*4882a593Smuzhiyun 	case -NFS4ERR_CB_PATH_DOWN:
1864*4882a593Smuzhiyun 		nfs40_handle_cb_pathdown(clp);
1865*4882a593Smuzhiyun 		break;
1866*4882a593Smuzhiyun 	case -NFS4ERR_NO_GRACE:
1867*4882a593Smuzhiyun 		nfs4_state_end_reclaim_reboot(clp);
1868*4882a593Smuzhiyun 		break;
1869*4882a593Smuzhiyun 	case -NFS4ERR_STALE_CLIENTID:
1870*4882a593Smuzhiyun 		set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1871*4882a593Smuzhiyun 		nfs4_state_start_reclaim_reboot(clp);
1872*4882a593Smuzhiyun 		break;
1873*4882a593Smuzhiyun 	case -NFS4ERR_EXPIRED:
1874*4882a593Smuzhiyun 		set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1875*4882a593Smuzhiyun 		nfs4_state_start_reclaim_nograce(clp);
1876*4882a593Smuzhiyun 		break;
1877*4882a593Smuzhiyun 	case -NFS4ERR_BADSESSION:
1878*4882a593Smuzhiyun 	case -NFS4ERR_BADSLOT:
1879*4882a593Smuzhiyun 	case -NFS4ERR_BAD_HIGH_SLOT:
1880*4882a593Smuzhiyun 	case -NFS4ERR_DEADSESSION:
1881*4882a593Smuzhiyun 	case -NFS4ERR_SEQ_FALSE_RETRY:
1882*4882a593Smuzhiyun 	case -NFS4ERR_SEQ_MISORDERED:
1883*4882a593Smuzhiyun 		set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
1884*4882a593Smuzhiyun 		/* Zero session reset errors */
1885*4882a593Smuzhiyun 		break;
1886*4882a593Smuzhiyun 	case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1887*4882a593Smuzhiyun 		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
1888*4882a593Smuzhiyun 		break;
1889*4882a593Smuzhiyun 	default:
1890*4882a593Smuzhiyun 		dprintk("%s: failed to handle error %d for server %s\n",
1891*4882a593Smuzhiyun 				__func__, error, clp->cl_hostname);
1892*4882a593Smuzhiyun 		return error;
1893*4882a593Smuzhiyun 	}
1894*4882a593Smuzhiyun 	dprintk("%s: handled error %d for server %s\n", __func__, error,
1895*4882a593Smuzhiyun 			clp->cl_hostname);
1896*4882a593Smuzhiyun 	return 0;
1897*4882a593Smuzhiyun }
1898*4882a593Smuzhiyun 
nfs4_do_reclaim(struct nfs_client * clp,const struct nfs4_state_recovery_ops * ops)1899*4882a593Smuzhiyun static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
1900*4882a593Smuzhiyun {
1901*4882a593Smuzhiyun 	struct nfs4_state_owner *sp;
1902*4882a593Smuzhiyun 	struct nfs_server *server;
1903*4882a593Smuzhiyun 	struct rb_node *pos;
1904*4882a593Smuzhiyun 	LIST_HEAD(freeme);
1905*4882a593Smuzhiyun 	int status = 0;
1906*4882a593Smuzhiyun 
1907*4882a593Smuzhiyun restart:
1908*4882a593Smuzhiyun 	rcu_read_lock();
1909*4882a593Smuzhiyun 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
1910*4882a593Smuzhiyun 		nfs4_purge_state_owners(server, &freeme);
1911*4882a593Smuzhiyun 		spin_lock(&clp->cl_lock);
1912*4882a593Smuzhiyun 		for (pos = rb_first(&server->state_owners);
1913*4882a593Smuzhiyun 		     pos != NULL;
1914*4882a593Smuzhiyun 		     pos = rb_next(pos)) {
1915*4882a593Smuzhiyun 			sp = rb_entry(pos,
1916*4882a593Smuzhiyun 				struct nfs4_state_owner, so_server_node);
1917*4882a593Smuzhiyun 			if (!test_and_clear_bit(ops->owner_flag_bit,
1918*4882a593Smuzhiyun 							&sp->so_flags))
1919*4882a593Smuzhiyun 				continue;
1920*4882a593Smuzhiyun 			if (!atomic_inc_not_zero(&sp->so_count))
1921*4882a593Smuzhiyun 				continue;
1922*4882a593Smuzhiyun 			spin_unlock(&clp->cl_lock);
1923*4882a593Smuzhiyun 			rcu_read_unlock();
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun 			status = nfs4_reclaim_open_state(sp, ops);
1926*4882a593Smuzhiyun 			if (status < 0) {
1927*4882a593Smuzhiyun 				set_bit(ops->owner_flag_bit, &sp->so_flags);
1928*4882a593Smuzhiyun 				nfs4_put_state_owner(sp);
1929*4882a593Smuzhiyun 				status = nfs4_recovery_handle_error(clp, status);
1930*4882a593Smuzhiyun 				return (status != 0) ? status : -EAGAIN;
1931*4882a593Smuzhiyun 			}
1932*4882a593Smuzhiyun 
1933*4882a593Smuzhiyun 			nfs4_put_state_owner(sp);
1934*4882a593Smuzhiyun 			goto restart;
1935*4882a593Smuzhiyun 		}
1936*4882a593Smuzhiyun 		spin_unlock(&clp->cl_lock);
1937*4882a593Smuzhiyun 	}
1938*4882a593Smuzhiyun 	rcu_read_unlock();
1939*4882a593Smuzhiyun 	nfs4_free_state_owners(&freeme);
1940*4882a593Smuzhiyun 	return 0;
1941*4882a593Smuzhiyun }
1942*4882a593Smuzhiyun 
nfs4_check_lease(struct nfs_client * clp)1943*4882a593Smuzhiyun static int nfs4_check_lease(struct nfs_client *clp)
1944*4882a593Smuzhiyun {
1945*4882a593Smuzhiyun 	const struct cred *cred;
1946*4882a593Smuzhiyun 	const struct nfs4_state_maintenance_ops *ops =
1947*4882a593Smuzhiyun 		clp->cl_mvops->state_renewal_ops;
1948*4882a593Smuzhiyun 	int status;
1949*4882a593Smuzhiyun 
1950*4882a593Smuzhiyun 	/* Is the client already known to have an expired lease? */
1951*4882a593Smuzhiyun 	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1952*4882a593Smuzhiyun 		return 0;
1953*4882a593Smuzhiyun 	cred = ops->get_state_renewal_cred(clp);
1954*4882a593Smuzhiyun 	if (cred == NULL) {
1955*4882a593Smuzhiyun 		cred = nfs4_get_clid_cred(clp);
1956*4882a593Smuzhiyun 		status = -ENOKEY;
1957*4882a593Smuzhiyun 		if (cred == NULL)
1958*4882a593Smuzhiyun 			goto out;
1959*4882a593Smuzhiyun 	}
1960*4882a593Smuzhiyun 	status = ops->renew_lease(clp, cred);
1961*4882a593Smuzhiyun 	put_cred(cred);
1962*4882a593Smuzhiyun 	if (status == -ETIMEDOUT) {
1963*4882a593Smuzhiyun 		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1964*4882a593Smuzhiyun 		return 0;
1965*4882a593Smuzhiyun 	}
1966*4882a593Smuzhiyun out:
1967*4882a593Smuzhiyun 	return nfs4_recovery_handle_error(clp, status);
1968*4882a593Smuzhiyun }
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun /* Set NFS4CLNT_LEASE_EXPIRED and reclaim reboot state for all v4.0 errors
1971*4882a593Smuzhiyun  * and for recoverable errors on EXCHANGE_ID for v4.1
1972*4882a593Smuzhiyun  */
nfs4_handle_reclaim_lease_error(struct nfs_client * clp,int status)1973*4882a593Smuzhiyun static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
1974*4882a593Smuzhiyun {
1975*4882a593Smuzhiyun 	switch (status) {
1976*4882a593Smuzhiyun 	case -NFS4ERR_SEQ_MISORDERED:
1977*4882a593Smuzhiyun 		if (test_and_set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state))
1978*4882a593Smuzhiyun 			return -ESERVERFAULT;
1979*4882a593Smuzhiyun 		/* Lease confirmation error: retry after purging the lease */
1980*4882a593Smuzhiyun 		ssleep(1);
1981*4882a593Smuzhiyun 		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
1982*4882a593Smuzhiyun 		break;
1983*4882a593Smuzhiyun 	case -NFS4ERR_STALE_CLIENTID:
1984*4882a593Smuzhiyun 		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
1985*4882a593Smuzhiyun 		nfs4_state_start_reclaim_reboot(clp);
1986*4882a593Smuzhiyun 		break;
1987*4882a593Smuzhiyun 	case -NFS4ERR_CLID_INUSE:
1988*4882a593Smuzhiyun 		pr_err("NFS: Server %s reports our clientid is in use\n",
1989*4882a593Smuzhiyun 			clp->cl_hostname);
1990*4882a593Smuzhiyun 		nfs_mark_client_ready(clp, -EPERM);
1991*4882a593Smuzhiyun 		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
1992*4882a593Smuzhiyun 		return -EPERM;
1993*4882a593Smuzhiyun 	case -EACCES:
1994*4882a593Smuzhiyun 	case -NFS4ERR_DELAY:
1995*4882a593Smuzhiyun 	case -EAGAIN:
1996*4882a593Smuzhiyun 		ssleep(1);
1997*4882a593Smuzhiyun 		break;
1998*4882a593Smuzhiyun 
1999*4882a593Smuzhiyun 	case -NFS4ERR_MINOR_VERS_MISMATCH:
2000*4882a593Smuzhiyun 		if (clp->cl_cons_state == NFS_CS_SESSION_INITING)
2001*4882a593Smuzhiyun 			nfs_mark_client_ready(clp, -EPROTONOSUPPORT);
2002*4882a593Smuzhiyun 		dprintk("%s: exit with error %d for server %s\n",
2003*4882a593Smuzhiyun 				__func__, -EPROTONOSUPPORT, clp->cl_hostname);
2004*4882a593Smuzhiyun 		return -EPROTONOSUPPORT;
2005*4882a593Smuzhiyun 	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
2006*4882a593Smuzhiyun 				 * in nfs4_exchange_id */
2007*4882a593Smuzhiyun 	default:
2008*4882a593Smuzhiyun 		dprintk("%s: exit with error %d for server %s\n", __func__,
2009*4882a593Smuzhiyun 				status, clp->cl_hostname);
2010*4882a593Smuzhiyun 		return status;
2011*4882a593Smuzhiyun 	}
2012*4882a593Smuzhiyun 	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
2013*4882a593Smuzhiyun 	dprintk("%s: handled error %d for server %s\n", __func__, status,
2014*4882a593Smuzhiyun 			clp->cl_hostname);
2015*4882a593Smuzhiyun 	return 0;
2016*4882a593Smuzhiyun }
2017*4882a593Smuzhiyun 
nfs4_establish_lease(struct nfs_client * clp)2018*4882a593Smuzhiyun static int nfs4_establish_lease(struct nfs_client *clp)
2019*4882a593Smuzhiyun {
2020*4882a593Smuzhiyun 	const struct cred *cred;
2021*4882a593Smuzhiyun 	const struct nfs4_state_recovery_ops *ops =
2022*4882a593Smuzhiyun 		clp->cl_mvops->reboot_recovery_ops;
2023*4882a593Smuzhiyun 	int status;
2024*4882a593Smuzhiyun 
2025*4882a593Smuzhiyun 	status = nfs4_begin_drain_session(clp);
2026*4882a593Smuzhiyun 	if (status != 0)
2027*4882a593Smuzhiyun 		return status;
2028*4882a593Smuzhiyun 	cred = nfs4_get_clid_cred(clp);
2029*4882a593Smuzhiyun 	if (cred == NULL)
2030*4882a593Smuzhiyun 		return -ENOENT;
2031*4882a593Smuzhiyun 	status = ops->establish_clid(clp, cred);
2032*4882a593Smuzhiyun 	put_cred(cred);
2033*4882a593Smuzhiyun 	if (status != 0)
2034*4882a593Smuzhiyun 		return status;
2035*4882a593Smuzhiyun 	pnfs_destroy_all_layouts(clp);
2036*4882a593Smuzhiyun 	return 0;
2037*4882a593Smuzhiyun }
2038*4882a593Smuzhiyun 
2039*4882a593Smuzhiyun /*
2040*4882a593Smuzhiyun  * Returns zero or a negative errno.  NFS4ERR values are converted
2041*4882a593Smuzhiyun  * to local errno values.
2042*4882a593Smuzhiyun  */
nfs4_reclaim_lease(struct nfs_client * clp)2043*4882a593Smuzhiyun static int nfs4_reclaim_lease(struct nfs_client *clp)
2044*4882a593Smuzhiyun {
2045*4882a593Smuzhiyun 	int status;
2046*4882a593Smuzhiyun 
2047*4882a593Smuzhiyun 	status = nfs4_establish_lease(clp);
2048*4882a593Smuzhiyun 	if (status < 0)
2049*4882a593Smuzhiyun 		return nfs4_handle_reclaim_lease_error(clp, status);
2050*4882a593Smuzhiyun 	if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state))
2051*4882a593Smuzhiyun 		nfs4_state_start_reclaim_nograce(clp);
2052*4882a593Smuzhiyun 	if (!test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
2053*4882a593Smuzhiyun 		set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
2054*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
2055*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
2056*4882a593Smuzhiyun 	return 0;
2057*4882a593Smuzhiyun }
2058*4882a593Smuzhiyun 
nfs4_purge_lease(struct nfs_client * clp)2059*4882a593Smuzhiyun static int nfs4_purge_lease(struct nfs_client *clp)
2060*4882a593Smuzhiyun {
2061*4882a593Smuzhiyun 	int status;
2062*4882a593Smuzhiyun 
2063*4882a593Smuzhiyun 	status = nfs4_establish_lease(clp);
2064*4882a593Smuzhiyun 	if (status < 0)
2065*4882a593Smuzhiyun 		return nfs4_handle_reclaim_lease_error(clp, status);
2066*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
2067*4882a593Smuzhiyun 	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
2068*4882a593Smuzhiyun 	nfs4_state_start_reclaim_nograce(clp);
2069*4882a593Smuzhiyun 	return 0;
2070*4882a593Smuzhiyun }
2071*4882a593Smuzhiyun 
2072*4882a593Smuzhiyun /*
2073*4882a593Smuzhiyun  * Try remote migration of one FSID from a source server to a
2074*4882a593Smuzhiyun  * destination server.  The source server provides a list of
2075*4882a593Smuzhiyun  * potential destinations.
2076*4882a593Smuzhiyun  *
2077*4882a593Smuzhiyun  * Returns zero or a negative NFS4ERR status code.
2078*4882a593Smuzhiyun  */
nfs4_try_migration(struct nfs_server * server,const struct cred * cred)2079*4882a593Smuzhiyun static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred)
2080*4882a593Smuzhiyun {
2081*4882a593Smuzhiyun 	struct nfs_client *clp = server->nfs_client;
2082*4882a593Smuzhiyun 	struct nfs4_fs_locations *locations = NULL;
2083*4882a593Smuzhiyun 	struct inode *inode;
2084*4882a593Smuzhiyun 	struct page *page;
2085*4882a593Smuzhiyun 	int status, result;
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun 	dprintk("--> %s: FSID %llx:%llx on \"%s\"\n", __func__,
2088*4882a593Smuzhiyun 			(unsigned long long)server->fsid.major,
2089*4882a593Smuzhiyun 			(unsigned long long)server->fsid.minor,
2090*4882a593Smuzhiyun 			clp->cl_hostname);
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 	result = 0;
2093*4882a593Smuzhiyun 	page = alloc_page(GFP_KERNEL);
2094*4882a593Smuzhiyun 	locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
2095*4882a593Smuzhiyun 	if (page == NULL || locations == NULL) {
2096*4882a593Smuzhiyun 		dprintk("<-- %s: no memory\n", __func__);
2097*4882a593Smuzhiyun 		goto out;
2098*4882a593Smuzhiyun 	}
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun 	inode = d_inode(server->super->s_root);
2101*4882a593Smuzhiyun 	result = nfs4_proc_get_locations(inode, locations, page, cred);
2102*4882a593Smuzhiyun 	if (result) {
2103*4882a593Smuzhiyun 		dprintk("<-- %s: failed to retrieve fs_locations: %d\n",
2104*4882a593Smuzhiyun 			__func__, result);
2105*4882a593Smuzhiyun 		goto out;
2106*4882a593Smuzhiyun 	}
2107*4882a593Smuzhiyun 
2108*4882a593Smuzhiyun 	result = -NFS4ERR_NXIO;
2109*4882a593Smuzhiyun 	if (!locations->nlocations)
2110*4882a593Smuzhiyun 		goto out;
2111*4882a593Smuzhiyun 
2112*4882a593Smuzhiyun 	if (!(locations->fattr.valid & NFS_ATTR_FATTR_V4_LOCATIONS)) {
2113*4882a593Smuzhiyun 		dprintk("<-- %s: No fs_locations data, migration skipped\n",
2114*4882a593Smuzhiyun 			__func__);
2115*4882a593Smuzhiyun 		goto out;
2116*4882a593Smuzhiyun 	}
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	status = nfs4_begin_drain_session(clp);
2119*4882a593Smuzhiyun 	if (status != 0) {
2120*4882a593Smuzhiyun 		result = status;
2121*4882a593Smuzhiyun 		goto out;
2122*4882a593Smuzhiyun 	}
2123*4882a593Smuzhiyun 
2124*4882a593Smuzhiyun 	status = nfs4_replace_transport(server, locations);
2125*4882a593Smuzhiyun 	if (status != 0) {
2126*4882a593Smuzhiyun 		dprintk("<-- %s: failed to replace transport: %d\n",
2127*4882a593Smuzhiyun 			__func__, status);
2128*4882a593Smuzhiyun 		goto out;
2129*4882a593Smuzhiyun 	}
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 	result = 0;
2132*4882a593Smuzhiyun 	dprintk("<-- %s: migration succeeded\n", __func__);
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun out:
2135*4882a593Smuzhiyun 	if (page != NULL)
2136*4882a593Smuzhiyun 		__free_page(page);
2137*4882a593Smuzhiyun 	kfree(locations);
2138*4882a593Smuzhiyun 	if (result) {
2139*4882a593Smuzhiyun 		pr_err("NFS: migration recovery failed (server %s)\n",
2140*4882a593Smuzhiyun 				clp->cl_hostname);
2141*4882a593Smuzhiyun 		set_bit(NFS_MIG_FAILED, &server->mig_status);
2142*4882a593Smuzhiyun 	}
2143*4882a593Smuzhiyun 	return result;
2144*4882a593Smuzhiyun }
2145*4882a593Smuzhiyun 
2146*4882a593Smuzhiyun /*
2147*4882a593Smuzhiyun  * Returns zero or a negative NFS4ERR status code.
2148*4882a593Smuzhiyun  */
nfs4_handle_migration(struct nfs_client * clp)2149*4882a593Smuzhiyun static int nfs4_handle_migration(struct nfs_client *clp)
2150*4882a593Smuzhiyun {
2151*4882a593Smuzhiyun 	const struct nfs4_state_maintenance_ops *ops =
2152*4882a593Smuzhiyun 				clp->cl_mvops->state_renewal_ops;
2153*4882a593Smuzhiyun 	struct nfs_server *server;
2154*4882a593Smuzhiyun 	const struct cred *cred;
2155*4882a593Smuzhiyun 
2156*4882a593Smuzhiyun 	dprintk("%s: migration reported on \"%s\"\n", __func__,
2157*4882a593Smuzhiyun 			clp->cl_hostname);
2158*4882a593Smuzhiyun 
2159*4882a593Smuzhiyun 	cred = ops->get_state_renewal_cred(clp);
2160*4882a593Smuzhiyun 	if (cred == NULL)
2161*4882a593Smuzhiyun 		return -NFS4ERR_NOENT;
2162*4882a593Smuzhiyun 
2163*4882a593Smuzhiyun 	clp->cl_mig_gen++;
2164*4882a593Smuzhiyun restart:
2165*4882a593Smuzhiyun 	rcu_read_lock();
2166*4882a593Smuzhiyun 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
2167*4882a593Smuzhiyun 		int status;
2168*4882a593Smuzhiyun 
2169*4882a593Smuzhiyun 		if (server->mig_gen == clp->cl_mig_gen)
2170*4882a593Smuzhiyun 			continue;
2171*4882a593Smuzhiyun 		server->mig_gen = clp->cl_mig_gen;
2172*4882a593Smuzhiyun 
2173*4882a593Smuzhiyun 		if (!test_and_clear_bit(NFS_MIG_IN_TRANSITION,
2174*4882a593Smuzhiyun 						&server->mig_status))
2175*4882a593Smuzhiyun 			continue;
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun 		rcu_read_unlock();
2178*4882a593Smuzhiyun 		status = nfs4_try_migration(server, cred);
2179*4882a593Smuzhiyun 		if (status < 0) {
2180*4882a593Smuzhiyun 			put_cred(cred);
2181*4882a593Smuzhiyun 			return status;
2182*4882a593Smuzhiyun 		}
2183*4882a593Smuzhiyun 		goto restart;
2184*4882a593Smuzhiyun 	}
2185*4882a593Smuzhiyun 	rcu_read_unlock();
2186*4882a593Smuzhiyun 	put_cred(cred);
2187*4882a593Smuzhiyun 	return 0;
2188*4882a593Smuzhiyun }
2189*4882a593Smuzhiyun 
2190*4882a593Smuzhiyun /*
2191*4882a593Smuzhiyun  * Test each nfs_server on the clp's cl_superblocks list to see
2192*4882a593Smuzhiyun  * if it's moved to another server.  Stop when the server no longer
2193*4882a593Smuzhiyun  * returns NFS4ERR_LEASE_MOVED.
2194*4882a593Smuzhiyun  */
nfs4_handle_lease_moved(struct nfs_client * clp)2195*4882a593Smuzhiyun static int nfs4_handle_lease_moved(struct nfs_client *clp)
2196*4882a593Smuzhiyun {
2197*4882a593Smuzhiyun 	const struct nfs4_state_maintenance_ops *ops =
2198*4882a593Smuzhiyun 				clp->cl_mvops->state_renewal_ops;
2199*4882a593Smuzhiyun 	struct nfs_server *server;
2200*4882a593Smuzhiyun 	const struct cred *cred;
2201*4882a593Smuzhiyun 
2202*4882a593Smuzhiyun 	dprintk("%s: lease moved reported on \"%s\"\n", __func__,
2203*4882a593Smuzhiyun 			clp->cl_hostname);
2204*4882a593Smuzhiyun 
2205*4882a593Smuzhiyun 	cred = ops->get_state_renewal_cred(clp);
2206*4882a593Smuzhiyun 	if (cred == NULL)
2207*4882a593Smuzhiyun 		return -NFS4ERR_NOENT;
2208*4882a593Smuzhiyun 
2209*4882a593Smuzhiyun 	clp->cl_mig_gen++;
2210*4882a593Smuzhiyun restart:
2211*4882a593Smuzhiyun 	rcu_read_lock();
2212*4882a593Smuzhiyun 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
2213*4882a593Smuzhiyun 		struct inode *inode;
2214*4882a593Smuzhiyun 		int status;
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun 		if (server->mig_gen == clp->cl_mig_gen)
2217*4882a593Smuzhiyun 			continue;
2218*4882a593Smuzhiyun 		server->mig_gen = clp->cl_mig_gen;
2219*4882a593Smuzhiyun 
2220*4882a593Smuzhiyun 		rcu_read_unlock();
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 		inode = d_inode(server->super->s_root);
2223*4882a593Smuzhiyun 		status = nfs4_proc_fsid_present(inode, cred);
2224*4882a593Smuzhiyun 		if (status != -NFS4ERR_MOVED)
2225*4882a593Smuzhiyun 			goto restart;	/* wasn't this one */
2226*4882a593Smuzhiyun 		if (nfs4_try_migration(server, cred) == -NFS4ERR_LEASE_MOVED)
2227*4882a593Smuzhiyun 			goto restart;	/* there are more */
2228*4882a593Smuzhiyun 		goto out;
2229*4882a593Smuzhiyun 	}
2230*4882a593Smuzhiyun 	rcu_read_unlock();
2231*4882a593Smuzhiyun 
2232*4882a593Smuzhiyun out:
2233*4882a593Smuzhiyun 	put_cred(cred);
2234*4882a593Smuzhiyun 	return 0;
2235*4882a593Smuzhiyun }
2236*4882a593Smuzhiyun 
2237*4882a593Smuzhiyun /**
2238*4882a593Smuzhiyun  * nfs4_discover_server_trunking - Detect server IP address trunking
2239*4882a593Smuzhiyun  *
2240*4882a593Smuzhiyun  * @clp: nfs_client under test
2241*4882a593Smuzhiyun  * @result: OUT: found nfs_client, or clp
2242*4882a593Smuzhiyun  *
2243*4882a593Smuzhiyun  * Returns zero or a negative errno.  If zero is returned,
2244*4882a593Smuzhiyun  * an nfs_client pointer is planted in "result".
2245*4882a593Smuzhiyun  *
2246*4882a593Smuzhiyun  * Note: since we are invoked in process context, and
2247*4882a593Smuzhiyun  * not from inside the state manager, we cannot use
2248*4882a593Smuzhiyun  * nfs4_handle_reclaim_lease_error().
2249*4882a593Smuzhiyun  */
nfs4_discover_server_trunking(struct nfs_client * clp,struct nfs_client ** result)2250*4882a593Smuzhiyun int nfs4_discover_server_trunking(struct nfs_client *clp,
2251*4882a593Smuzhiyun 				  struct nfs_client **result)
2252*4882a593Smuzhiyun {
2253*4882a593Smuzhiyun 	const struct nfs4_state_recovery_ops *ops =
2254*4882a593Smuzhiyun 				clp->cl_mvops->reboot_recovery_ops;
2255*4882a593Smuzhiyun 	struct rpc_clnt *clnt;
2256*4882a593Smuzhiyun 	const struct cred *cred;
2257*4882a593Smuzhiyun 	int i, status;
2258*4882a593Smuzhiyun 
2259*4882a593Smuzhiyun 	dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);
2260*4882a593Smuzhiyun 
2261*4882a593Smuzhiyun 	clnt = clp->cl_rpcclient;
2262*4882a593Smuzhiyun 	i = 0;
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 	mutex_lock(&nfs_clid_init_mutex);
2265*4882a593Smuzhiyun again:
2266*4882a593Smuzhiyun 	status  = -ENOENT;
2267*4882a593Smuzhiyun 	cred = nfs4_get_clid_cred(clp);
2268*4882a593Smuzhiyun 	if (cred == NULL)
2269*4882a593Smuzhiyun 		goto out_unlock;
2270*4882a593Smuzhiyun 
2271*4882a593Smuzhiyun 	status = ops->detect_trunking(clp, result, cred);
2272*4882a593Smuzhiyun 	put_cred(cred);
2273*4882a593Smuzhiyun 	switch (status) {
2274*4882a593Smuzhiyun 	case 0:
2275*4882a593Smuzhiyun 	case -EINTR:
2276*4882a593Smuzhiyun 	case -ERESTARTSYS:
2277*4882a593Smuzhiyun 		break;
2278*4882a593Smuzhiyun 	case -ETIMEDOUT:
2279*4882a593Smuzhiyun 		if (clnt->cl_softrtry)
2280*4882a593Smuzhiyun 			break;
2281*4882a593Smuzhiyun 		fallthrough;
2282*4882a593Smuzhiyun 	case -NFS4ERR_DELAY:
2283*4882a593Smuzhiyun 	case -EAGAIN:
2284*4882a593Smuzhiyun 		ssleep(1);
2285*4882a593Smuzhiyun 		fallthrough;
2286*4882a593Smuzhiyun 	case -NFS4ERR_STALE_CLIENTID:
2287*4882a593Smuzhiyun 		dprintk("NFS: %s after status %d, retrying\n",
2288*4882a593Smuzhiyun 			__func__, status);
2289*4882a593Smuzhiyun 		goto again;
2290*4882a593Smuzhiyun 	case -EACCES:
2291*4882a593Smuzhiyun 		if (i++ == 0) {
2292*4882a593Smuzhiyun 			nfs4_root_machine_cred(clp);
2293*4882a593Smuzhiyun 			goto again;
2294*4882a593Smuzhiyun 		}
2295*4882a593Smuzhiyun 		if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX)
2296*4882a593Smuzhiyun 			break;
2297*4882a593Smuzhiyun 		fallthrough;
2298*4882a593Smuzhiyun 	case -NFS4ERR_CLID_INUSE:
2299*4882a593Smuzhiyun 	case -NFS4ERR_WRONGSEC:
2300*4882a593Smuzhiyun 		/* No point in retrying if we already used RPC_AUTH_UNIX */
2301*4882a593Smuzhiyun 		if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX) {
2302*4882a593Smuzhiyun 			status = -EPERM;
2303*4882a593Smuzhiyun 			break;
2304*4882a593Smuzhiyun 		}
2305*4882a593Smuzhiyun 		clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
2306*4882a593Smuzhiyun 		if (IS_ERR(clnt)) {
2307*4882a593Smuzhiyun 			status = PTR_ERR(clnt);
2308*4882a593Smuzhiyun 			break;
2309*4882a593Smuzhiyun 		}
2310*4882a593Smuzhiyun 		/* Note: this is safe because we haven't yet marked the
2311*4882a593Smuzhiyun 		 * client as ready, so we are the only user of
2312*4882a593Smuzhiyun 		 * clp->cl_rpcclient
2313*4882a593Smuzhiyun 		 */
2314*4882a593Smuzhiyun 		clnt = xchg(&clp->cl_rpcclient, clnt);
2315*4882a593Smuzhiyun 		rpc_shutdown_client(clnt);
2316*4882a593Smuzhiyun 		clnt = clp->cl_rpcclient;
2317*4882a593Smuzhiyun 		goto again;
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun 	case -NFS4ERR_MINOR_VERS_MISMATCH:
2320*4882a593Smuzhiyun 		status = -EPROTONOSUPPORT;
2321*4882a593Smuzhiyun 		break;
2322*4882a593Smuzhiyun 
2323*4882a593Smuzhiyun 	case -EKEYEXPIRED:
2324*4882a593Smuzhiyun 	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
2325*4882a593Smuzhiyun 				 * in nfs4_exchange_id */
2326*4882a593Smuzhiyun 		status = -EKEYEXPIRED;
2327*4882a593Smuzhiyun 		break;
2328*4882a593Smuzhiyun 	default:
2329*4882a593Smuzhiyun 		pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
2330*4882a593Smuzhiyun 				__func__, status);
2331*4882a593Smuzhiyun 		status = -EIO;
2332*4882a593Smuzhiyun 	}
2333*4882a593Smuzhiyun 
2334*4882a593Smuzhiyun out_unlock:
2335*4882a593Smuzhiyun 	mutex_unlock(&nfs_clid_init_mutex);
2336*4882a593Smuzhiyun 	dprintk("NFS: %s: status = %d\n", __func__, status);
2337*4882a593Smuzhiyun 	return status;
2338*4882a593Smuzhiyun }
2339*4882a593Smuzhiyun 
2340*4882a593Smuzhiyun #ifdef CONFIG_NFS_V4_1
nfs4_schedule_session_recovery(struct nfs4_session * session,int err)2341*4882a593Smuzhiyun void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
2342*4882a593Smuzhiyun {
2343*4882a593Smuzhiyun 	struct nfs_client *clp = session->clp;
2344*4882a593Smuzhiyun 
2345*4882a593Smuzhiyun 	switch (err) {
2346*4882a593Smuzhiyun 	default:
2347*4882a593Smuzhiyun 		set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
2348*4882a593Smuzhiyun 		break;
2349*4882a593Smuzhiyun 	case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
2350*4882a593Smuzhiyun 		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
2351*4882a593Smuzhiyun 	}
2352*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
2353*4882a593Smuzhiyun }
2354*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
2355*4882a593Smuzhiyun 
nfs41_notify_server(struct nfs_client * clp)2356*4882a593Smuzhiyun void nfs41_notify_server(struct nfs_client *clp)
2357*4882a593Smuzhiyun {
2358*4882a593Smuzhiyun 	/* Use CHECK_LEASE to ping the server with a SEQUENCE */
2359*4882a593Smuzhiyun 	set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
2360*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
2361*4882a593Smuzhiyun }
2362*4882a593Smuzhiyun 
nfs4_reset_all_state(struct nfs_client * clp)2363*4882a593Smuzhiyun static void nfs4_reset_all_state(struct nfs_client *clp)
2364*4882a593Smuzhiyun {
2365*4882a593Smuzhiyun 	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
2366*4882a593Smuzhiyun 		set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
2367*4882a593Smuzhiyun 		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
2368*4882a593Smuzhiyun 		nfs4_state_start_reclaim_nograce(clp);
2369*4882a593Smuzhiyun 		dprintk("%s: scheduling reset of all state for server %s!\n",
2370*4882a593Smuzhiyun 				__func__, clp->cl_hostname);
2371*4882a593Smuzhiyun 		nfs4_schedule_state_manager(clp);
2372*4882a593Smuzhiyun 	}
2373*4882a593Smuzhiyun }
2374*4882a593Smuzhiyun 
nfs41_handle_server_reboot(struct nfs_client * clp)2375*4882a593Smuzhiyun static void nfs41_handle_server_reboot(struct nfs_client *clp)
2376*4882a593Smuzhiyun {
2377*4882a593Smuzhiyun 	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
2378*4882a593Smuzhiyun 		nfs4_state_start_reclaim_reboot(clp);
2379*4882a593Smuzhiyun 		dprintk("%s: server %s rebooted!\n", __func__,
2380*4882a593Smuzhiyun 				clp->cl_hostname);
2381*4882a593Smuzhiyun 		nfs4_schedule_state_manager(clp);
2382*4882a593Smuzhiyun 	}
2383*4882a593Smuzhiyun }
2384*4882a593Smuzhiyun 
nfs41_handle_all_state_revoked(struct nfs_client * clp)2385*4882a593Smuzhiyun static void nfs41_handle_all_state_revoked(struct nfs_client *clp)
2386*4882a593Smuzhiyun {
2387*4882a593Smuzhiyun 	nfs4_reset_all_state(clp);
2388*4882a593Smuzhiyun 	dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
2389*4882a593Smuzhiyun }
2390*4882a593Smuzhiyun 
nfs41_handle_some_state_revoked(struct nfs_client * clp)2391*4882a593Smuzhiyun static void nfs41_handle_some_state_revoked(struct nfs_client *clp)
2392*4882a593Smuzhiyun {
2393*4882a593Smuzhiyun 	nfs4_state_start_reclaim_nograce(clp);
2394*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
2395*4882a593Smuzhiyun 
2396*4882a593Smuzhiyun 	dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
2397*4882a593Smuzhiyun }
2398*4882a593Smuzhiyun 
nfs41_handle_recallable_state_revoked(struct nfs_client * clp)2399*4882a593Smuzhiyun static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
2400*4882a593Smuzhiyun {
2401*4882a593Smuzhiyun 	/* FIXME: For now, we destroy all layouts. */
2402*4882a593Smuzhiyun 	pnfs_destroy_all_layouts(clp);
2403*4882a593Smuzhiyun 	nfs_test_expired_all_delegations(clp);
2404*4882a593Smuzhiyun 	dprintk("%s: Recallable state revoked on server %s!\n", __func__,
2405*4882a593Smuzhiyun 			clp->cl_hostname);
2406*4882a593Smuzhiyun }
2407*4882a593Smuzhiyun 
nfs41_handle_backchannel_fault(struct nfs_client * clp)2408*4882a593Smuzhiyun static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
2409*4882a593Smuzhiyun {
2410*4882a593Smuzhiyun 	set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
2411*4882a593Smuzhiyun 	nfs4_schedule_state_manager(clp);
2412*4882a593Smuzhiyun 
2413*4882a593Smuzhiyun 	dprintk("%s: server %s declared a backchannel fault\n", __func__,
2414*4882a593Smuzhiyun 			clp->cl_hostname);
2415*4882a593Smuzhiyun }
2416*4882a593Smuzhiyun 
nfs41_handle_cb_path_down(struct nfs_client * clp)2417*4882a593Smuzhiyun static void nfs41_handle_cb_path_down(struct nfs_client *clp)
2418*4882a593Smuzhiyun {
2419*4882a593Smuzhiyun 	if (test_and_set_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
2420*4882a593Smuzhiyun 		&clp->cl_state) == 0)
2421*4882a593Smuzhiyun 		nfs4_schedule_state_manager(clp);
2422*4882a593Smuzhiyun }
2423*4882a593Smuzhiyun 
nfs41_handle_sequence_flag_errors(struct nfs_client * clp,u32 flags,bool recovery)2424*4882a593Smuzhiyun void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags,
2425*4882a593Smuzhiyun 		bool recovery)
2426*4882a593Smuzhiyun {
2427*4882a593Smuzhiyun 	if (!flags)
2428*4882a593Smuzhiyun 		return;
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun 	dprintk("%s: \"%s\" (client ID %llx) flags=0x%08x\n",
2431*4882a593Smuzhiyun 		__func__, clp->cl_hostname, clp->cl_clientid, flags);
2432*4882a593Smuzhiyun 	/*
2433*4882a593Smuzhiyun 	 * If we're called from the state manager thread, then assume we're
2434*4882a593Smuzhiyun 	 * already handling the RECLAIM_NEEDED and/or STATE_REVOKED.
2435*4882a593Smuzhiyun 	 * Those flags are expected to remain set until we're done
2436*4882a593Smuzhiyun 	 * recovering (see RFC5661, section 18.46.3).
2437*4882a593Smuzhiyun 	 */
2438*4882a593Smuzhiyun 	if (recovery)
2439*4882a593Smuzhiyun 		goto out_recovery;
2440*4882a593Smuzhiyun 
2441*4882a593Smuzhiyun 	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
2442*4882a593Smuzhiyun 		nfs41_handle_server_reboot(clp);
2443*4882a593Smuzhiyun 	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED))
2444*4882a593Smuzhiyun 		nfs41_handle_all_state_revoked(clp);
2445*4882a593Smuzhiyun 	if (flags & (SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
2446*4882a593Smuzhiyun 			    SEQ4_STATUS_ADMIN_STATE_REVOKED))
2447*4882a593Smuzhiyun 		nfs41_handle_some_state_revoked(clp);
2448*4882a593Smuzhiyun 	if (flags & SEQ4_STATUS_LEASE_MOVED)
2449*4882a593Smuzhiyun 		nfs4_schedule_lease_moved_recovery(clp);
2450*4882a593Smuzhiyun 	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
2451*4882a593Smuzhiyun 		nfs41_handle_recallable_state_revoked(clp);
2452*4882a593Smuzhiyun out_recovery:
2453*4882a593Smuzhiyun 	if (flags & SEQ4_STATUS_BACKCHANNEL_FAULT)
2454*4882a593Smuzhiyun 		nfs41_handle_backchannel_fault(clp);
2455*4882a593Smuzhiyun 	else if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
2456*4882a593Smuzhiyun 				SEQ4_STATUS_CB_PATH_DOWN_SESSION))
2457*4882a593Smuzhiyun 		nfs41_handle_cb_path_down(clp);
2458*4882a593Smuzhiyun }
2459*4882a593Smuzhiyun 
nfs4_reset_session(struct nfs_client * clp)2460*4882a593Smuzhiyun static int nfs4_reset_session(struct nfs_client *clp)
2461*4882a593Smuzhiyun {
2462*4882a593Smuzhiyun 	const struct cred *cred;
2463*4882a593Smuzhiyun 	int status;
2464*4882a593Smuzhiyun 
2465*4882a593Smuzhiyun 	if (!nfs4_has_session(clp))
2466*4882a593Smuzhiyun 		return 0;
2467*4882a593Smuzhiyun 	status = nfs4_begin_drain_session(clp);
2468*4882a593Smuzhiyun 	if (status != 0)
2469*4882a593Smuzhiyun 		return status;
2470*4882a593Smuzhiyun 	cred = nfs4_get_clid_cred(clp);
2471*4882a593Smuzhiyun 	status = nfs4_proc_destroy_session(clp->cl_session, cred);
2472*4882a593Smuzhiyun 	switch (status) {
2473*4882a593Smuzhiyun 	case 0:
2474*4882a593Smuzhiyun 	case -NFS4ERR_BADSESSION:
2475*4882a593Smuzhiyun 	case -NFS4ERR_DEADSESSION:
2476*4882a593Smuzhiyun 		break;
2477*4882a593Smuzhiyun 	case -NFS4ERR_BACK_CHAN_BUSY:
2478*4882a593Smuzhiyun 	case -NFS4ERR_DELAY:
2479*4882a593Smuzhiyun 		set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
2480*4882a593Smuzhiyun 		status = 0;
2481*4882a593Smuzhiyun 		ssleep(1);
2482*4882a593Smuzhiyun 		goto out;
2483*4882a593Smuzhiyun 	default:
2484*4882a593Smuzhiyun 		status = nfs4_recovery_handle_error(clp, status);
2485*4882a593Smuzhiyun 		goto out;
2486*4882a593Smuzhiyun 	}
2487*4882a593Smuzhiyun 
2488*4882a593Smuzhiyun 	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
2489*4882a593Smuzhiyun 	status = nfs4_proc_create_session(clp, cred);
2490*4882a593Smuzhiyun 	if (status) {
2491*4882a593Smuzhiyun 		dprintk("%s: session reset failed with status %d for server %s!\n",
2492*4882a593Smuzhiyun 			__func__, status, clp->cl_hostname);
2493*4882a593Smuzhiyun 		status = nfs4_handle_reclaim_lease_error(clp, status);
2494*4882a593Smuzhiyun 		goto out;
2495*4882a593Smuzhiyun 	}
2496*4882a593Smuzhiyun 	nfs41_finish_session_reset(clp);
2497*4882a593Smuzhiyun 	dprintk("%s: session reset was successful for server %s!\n",
2498*4882a593Smuzhiyun 			__func__, clp->cl_hostname);
2499*4882a593Smuzhiyun out:
2500*4882a593Smuzhiyun 	put_cred(cred);
2501*4882a593Smuzhiyun 	return status;
2502*4882a593Smuzhiyun }
2503*4882a593Smuzhiyun 
nfs4_bind_conn_to_session(struct nfs_client * clp)2504*4882a593Smuzhiyun static int nfs4_bind_conn_to_session(struct nfs_client *clp)
2505*4882a593Smuzhiyun {
2506*4882a593Smuzhiyun 	const struct cred *cred;
2507*4882a593Smuzhiyun 	int ret;
2508*4882a593Smuzhiyun 
2509*4882a593Smuzhiyun 	if (!nfs4_has_session(clp))
2510*4882a593Smuzhiyun 		return 0;
2511*4882a593Smuzhiyun 	ret = nfs4_begin_drain_session(clp);
2512*4882a593Smuzhiyun 	if (ret != 0)
2513*4882a593Smuzhiyun 		return ret;
2514*4882a593Smuzhiyun 	cred = nfs4_get_clid_cred(clp);
2515*4882a593Smuzhiyun 	ret = nfs4_proc_bind_conn_to_session(clp, cred);
2516*4882a593Smuzhiyun 	put_cred(cred);
2517*4882a593Smuzhiyun 	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
2518*4882a593Smuzhiyun 	switch (ret) {
2519*4882a593Smuzhiyun 	case 0:
2520*4882a593Smuzhiyun 		dprintk("%s: bind_conn_to_session was successful for server %s!\n",
2521*4882a593Smuzhiyun 			__func__, clp->cl_hostname);
2522*4882a593Smuzhiyun 		break;
2523*4882a593Smuzhiyun 	case -NFS4ERR_DELAY:
2524*4882a593Smuzhiyun 		ssleep(1);
2525*4882a593Smuzhiyun 		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
2526*4882a593Smuzhiyun 		break;
2527*4882a593Smuzhiyun 	default:
2528*4882a593Smuzhiyun 		return nfs4_recovery_handle_error(clp, ret);
2529*4882a593Smuzhiyun 	}
2530*4882a593Smuzhiyun 	return 0;
2531*4882a593Smuzhiyun }
2532*4882a593Smuzhiyun 
nfs4_layoutreturn_any_run(struct nfs_client * clp)2533*4882a593Smuzhiyun static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
2534*4882a593Smuzhiyun {
2535*4882a593Smuzhiyun 	int iomode = 0;
2536*4882a593Smuzhiyun 
2537*4882a593Smuzhiyun 	if (test_and_clear_bit(NFS4CLNT_RECALL_ANY_LAYOUT_READ, &clp->cl_state))
2538*4882a593Smuzhiyun 		iomode += IOMODE_READ;
2539*4882a593Smuzhiyun 	if (test_and_clear_bit(NFS4CLNT_RECALL_ANY_LAYOUT_RW, &clp->cl_state))
2540*4882a593Smuzhiyun 		iomode += IOMODE_RW;
2541*4882a593Smuzhiyun 	/* Note: IOMODE_READ + IOMODE_RW == IOMODE_ANY */
2542*4882a593Smuzhiyun 	if (iomode) {
2543*4882a593Smuzhiyun 		pnfs_layout_return_unused_byclid(clp, iomode);
2544*4882a593Smuzhiyun 		set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
2545*4882a593Smuzhiyun 	}
2546*4882a593Smuzhiyun }
2547*4882a593Smuzhiyun #else /* CONFIG_NFS_V4_1 */
nfs4_reset_session(struct nfs_client * clp)2548*4882a593Smuzhiyun static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
2549*4882a593Smuzhiyun 
nfs4_bind_conn_to_session(struct nfs_client * clp)2550*4882a593Smuzhiyun static int nfs4_bind_conn_to_session(struct nfs_client *clp)
2551*4882a593Smuzhiyun {
2552*4882a593Smuzhiyun 	return 0;
2553*4882a593Smuzhiyun }
2554*4882a593Smuzhiyun 
nfs4_layoutreturn_any_run(struct nfs_client * clp)2555*4882a593Smuzhiyun static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
2556*4882a593Smuzhiyun {
2557*4882a593Smuzhiyun }
2558*4882a593Smuzhiyun #endif /* CONFIG_NFS_V4_1 */
2559*4882a593Smuzhiyun 
nfs4_state_manager(struct nfs_client * clp)2560*4882a593Smuzhiyun static void nfs4_state_manager(struct nfs_client *clp)
2561*4882a593Smuzhiyun {
2562*4882a593Smuzhiyun 	unsigned int memflags;
2563*4882a593Smuzhiyun 	int status = 0;
2564*4882a593Smuzhiyun 	const char *section = "", *section_sep = "";
2565*4882a593Smuzhiyun 
2566*4882a593Smuzhiyun 	/*
2567*4882a593Smuzhiyun 	 * State recovery can deadlock if the direct reclaim code tries
2568*4882a593Smuzhiyun 	 * start NFS writeback. So ensure memory allocations are all
2569*4882a593Smuzhiyun 	 * GFP_NOFS.
2570*4882a593Smuzhiyun 	 */
2571*4882a593Smuzhiyun 	memflags = memalloc_nofs_save();
2572*4882a593Smuzhiyun 
2573*4882a593Smuzhiyun 	/* Ensure exclusive access to NFSv4 state */
2574*4882a593Smuzhiyun 	do {
2575*4882a593Smuzhiyun 		trace_nfs4_state_mgr(clp);
2576*4882a593Smuzhiyun 		clear_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
2577*4882a593Smuzhiyun 		if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
2578*4882a593Smuzhiyun 			section = "purge state";
2579*4882a593Smuzhiyun 			status = nfs4_purge_lease(clp);
2580*4882a593Smuzhiyun 			if (status < 0)
2581*4882a593Smuzhiyun 				goto out_error;
2582*4882a593Smuzhiyun 			continue;
2583*4882a593Smuzhiyun 		}
2584*4882a593Smuzhiyun 
2585*4882a593Smuzhiyun 		if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
2586*4882a593Smuzhiyun 			section = "lease expired";
2587*4882a593Smuzhiyun 			/* We're going to have to re-establish a clientid */
2588*4882a593Smuzhiyun 			status = nfs4_reclaim_lease(clp);
2589*4882a593Smuzhiyun 			if (status < 0)
2590*4882a593Smuzhiyun 				goto out_error;
2591*4882a593Smuzhiyun 			continue;
2592*4882a593Smuzhiyun 		}
2593*4882a593Smuzhiyun 
2594*4882a593Smuzhiyun 		/* Initialize or reset the session */
2595*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
2596*4882a593Smuzhiyun 			section = "reset session";
2597*4882a593Smuzhiyun 			status = nfs4_reset_session(clp);
2598*4882a593Smuzhiyun 			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
2599*4882a593Smuzhiyun 				continue;
2600*4882a593Smuzhiyun 			if (status < 0)
2601*4882a593Smuzhiyun 				goto out_error;
2602*4882a593Smuzhiyun 		}
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 		/* Send BIND_CONN_TO_SESSION */
2605*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
2606*4882a593Smuzhiyun 				&clp->cl_state)) {
2607*4882a593Smuzhiyun 			section = "bind conn to session";
2608*4882a593Smuzhiyun 			status = nfs4_bind_conn_to_session(clp);
2609*4882a593Smuzhiyun 			if (status < 0)
2610*4882a593Smuzhiyun 				goto out_error;
2611*4882a593Smuzhiyun 			continue;
2612*4882a593Smuzhiyun 		}
2613*4882a593Smuzhiyun 
2614*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
2615*4882a593Smuzhiyun 			section = "check lease";
2616*4882a593Smuzhiyun 			status = nfs4_check_lease(clp);
2617*4882a593Smuzhiyun 			if (status < 0)
2618*4882a593Smuzhiyun 				goto out_error;
2619*4882a593Smuzhiyun 			continue;
2620*4882a593Smuzhiyun 		}
2621*4882a593Smuzhiyun 
2622*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS4CLNT_MOVED, &clp->cl_state)) {
2623*4882a593Smuzhiyun 			section = "migration";
2624*4882a593Smuzhiyun 			status = nfs4_handle_migration(clp);
2625*4882a593Smuzhiyun 			if (status < 0)
2626*4882a593Smuzhiyun 				goto out_error;
2627*4882a593Smuzhiyun 		}
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS4CLNT_LEASE_MOVED, &clp->cl_state)) {
2630*4882a593Smuzhiyun 			section = "lease moved";
2631*4882a593Smuzhiyun 			status = nfs4_handle_lease_moved(clp);
2632*4882a593Smuzhiyun 			if (status < 0)
2633*4882a593Smuzhiyun 				goto out_error;
2634*4882a593Smuzhiyun 		}
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun 		/* First recover reboot state... */
2637*4882a593Smuzhiyun 		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
2638*4882a593Smuzhiyun 			section = "reclaim reboot";
2639*4882a593Smuzhiyun 			status = nfs4_do_reclaim(clp,
2640*4882a593Smuzhiyun 				clp->cl_mvops->reboot_recovery_ops);
2641*4882a593Smuzhiyun 			if (status == -EAGAIN)
2642*4882a593Smuzhiyun 				continue;
2643*4882a593Smuzhiyun 			if (status < 0)
2644*4882a593Smuzhiyun 				goto out_error;
2645*4882a593Smuzhiyun 			nfs4_state_end_reclaim_reboot(clp);
2646*4882a593Smuzhiyun 			continue;
2647*4882a593Smuzhiyun 		}
2648*4882a593Smuzhiyun 
2649*4882a593Smuzhiyun 		/* Detect expired delegations... */
2650*4882a593Smuzhiyun 		if (test_and_clear_bit(NFS4CLNT_DELEGATION_EXPIRED, &clp->cl_state)) {
2651*4882a593Smuzhiyun 			section = "detect expired delegations";
2652*4882a593Smuzhiyun 			nfs_reap_expired_delegations(clp);
2653*4882a593Smuzhiyun 			continue;
2654*4882a593Smuzhiyun 		}
2655*4882a593Smuzhiyun 
2656*4882a593Smuzhiyun 		/* Now recover expired state... */
2657*4882a593Smuzhiyun 		if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
2658*4882a593Smuzhiyun 			section = "reclaim nograce";
2659*4882a593Smuzhiyun 			status = nfs4_do_reclaim(clp,
2660*4882a593Smuzhiyun 				clp->cl_mvops->nograce_recovery_ops);
2661*4882a593Smuzhiyun 			if (status == -EAGAIN)
2662*4882a593Smuzhiyun 				continue;
2663*4882a593Smuzhiyun 			if (status < 0)
2664*4882a593Smuzhiyun 				goto out_error;
2665*4882a593Smuzhiyun 			clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
2666*4882a593Smuzhiyun 		}
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun 		memalloc_nofs_restore(memflags);
2669*4882a593Smuzhiyun 		nfs4_end_drain_session(clp);
2670*4882a593Smuzhiyun 		nfs4_clear_state_manager_bit(clp);
2671*4882a593Smuzhiyun 
2672*4882a593Smuzhiyun 		if (!test_and_set_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state)) {
2673*4882a593Smuzhiyun 			if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
2674*4882a593Smuzhiyun 				nfs_client_return_marked_delegations(clp);
2675*4882a593Smuzhiyun 				set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
2676*4882a593Smuzhiyun 			}
2677*4882a593Smuzhiyun 			nfs4_layoutreturn_any_run(clp);
2678*4882a593Smuzhiyun 			clear_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state);
2679*4882a593Smuzhiyun 		}
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 		/* Did we race with an attempt to give us more work? */
2682*4882a593Smuzhiyun 		if (!test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
2683*4882a593Smuzhiyun 			return;
2684*4882a593Smuzhiyun 		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
2685*4882a593Smuzhiyun 			return;
2686*4882a593Smuzhiyun 		memflags = memalloc_nofs_save();
2687*4882a593Smuzhiyun 	} while (refcount_read(&clp->cl_count) > 1 && !signalled());
2688*4882a593Smuzhiyun 	goto out_drain;
2689*4882a593Smuzhiyun 
2690*4882a593Smuzhiyun out_error:
2691*4882a593Smuzhiyun 	if (strlen(section))
2692*4882a593Smuzhiyun 		section_sep = ": ";
2693*4882a593Smuzhiyun 	trace_nfs4_state_mgr_failed(clp, section, status);
2694*4882a593Smuzhiyun 	pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
2695*4882a593Smuzhiyun 			" with error %d\n", section_sep, section,
2696*4882a593Smuzhiyun 			clp->cl_hostname, -status);
2697*4882a593Smuzhiyun 	ssleep(1);
2698*4882a593Smuzhiyun out_drain:
2699*4882a593Smuzhiyun 	memalloc_nofs_restore(memflags);
2700*4882a593Smuzhiyun 	nfs4_end_drain_session(clp);
2701*4882a593Smuzhiyun 	nfs4_clear_state_manager_bit(clp);
2702*4882a593Smuzhiyun }
2703*4882a593Smuzhiyun 
nfs4_run_state_manager(void * ptr)2704*4882a593Smuzhiyun static int nfs4_run_state_manager(void *ptr)
2705*4882a593Smuzhiyun {
2706*4882a593Smuzhiyun 	struct nfs_client *clp = ptr;
2707*4882a593Smuzhiyun 
2708*4882a593Smuzhiyun 	allow_signal(SIGKILL);
2709*4882a593Smuzhiyun 	nfs4_state_manager(clp);
2710*4882a593Smuzhiyun 	nfs_put_client(clp);
2711*4882a593Smuzhiyun 	module_put_and_exit(0);
2712*4882a593Smuzhiyun 	return 0;
2713*4882a593Smuzhiyun }
2714*4882a593Smuzhiyun 
2715*4882a593Smuzhiyun /*
2716*4882a593Smuzhiyun  * Local variables:
2717*4882a593Smuzhiyun  *  c-basic-offset: 8
2718*4882a593Smuzhiyun  * End:
2719*4882a593Smuzhiyun  */
2720