xref: /openbmc/linux/fs/nfsd/nfs4state.c (revision 920dd9bb)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds *  Copyright (c) 2001 The Regents of the University of Michigan.
31da177e4SLinus Torvalds *  All rights reserved.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *  Kendrick Smith <kmsmith@umich.edu>
61da177e4SLinus Torvalds *  Andy Adamson <kandros@umich.edu>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds *  Redistribution and use in source and binary forms, with or without
91da177e4SLinus Torvalds *  modification, are permitted provided that the following conditions
101da177e4SLinus Torvalds *  are met:
111da177e4SLinus Torvalds *
121da177e4SLinus Torvalds *  1. Redistributions of source code must retain the above copyright
131da177e4SLinus Torvalds *     notice, this list of conditions and the following disclaimer.
141da177e4SLinus Torvalds *  2. Redistributions in binary form must reproduce the above copyright
151da177e4SLinus Torvalds *     notice, this list of conditions and the following disclaimer in the
161da177e4SLinus Torvalds *     documentation and/or other materials provided with the distribution.
171da177e4SLinus Torvalds *  3. Neither the name of the University nor the names of its
181da177e4SLinus Torvalds *     contributors may be used to endorse or promote products derived
191da177e4SLinus Torvalds *     from this software without specific prior written permission.
201da177e4SLinus Torvalds *
211da177e4SLinus Torvalds *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
221da177e4SLinus Torvalds *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
231da177e4SLinus Torvalds *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
241da177e4SLinus Torvalds *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251da177e4SLinus Torvalds *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
261da177e4SLinus Torvalds *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
271da177e4SLinus Torvalds *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
281da177e4SLinus Torvalds *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
291da177e4SLinus Torvalds *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
301da177e4SLinus Torvalds *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
311da177e4SLinus Torvalds *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
321da177e4SLinus Torvalds *
331da177e4SLinus Torvalds */
341da177e4SLinus Torvalds 
35aceaf78dSDave Hansen #include <linux/file.h>
36b89f4321SArnd Bergmann #include <linux/fs.h>
375a0e3ad6STejun Heo #include <linux/slab.h>
380964a3d3SNeilBrown #include <linux/namei.h>
39c2f1a551SMeelap Shah #include <linux/swap.h>
4017456804SBryan Schumaker #include <linux/pagemap.h>
417df302f7SChuck Lever #include <linux/ratelimit.h>
4268e76ad0SOlga Kornievskaia #include <linux/sunrpc/svcauth_gss.h>
435976687aSJeff Layton #include <linux/sunrpc/addr.h>
4487545899SDaniel Borkmann #include <linux/jhash.h>
459a74af21SBoaz Harrosh #include "xdr4.h"
4606b332a5SJ. Bruce Fields #include "xdr4cb.h"
470a3adadeSJ. Bruce Fields #include "vfs.h"
48bfa4b365SJ. Bruce Fields #include "current_stateid.h"
491da177e4SLinus Torvalds 
505e1533c7SStanislav Kinsbursky #include "netns.h"
519cf514ccSChristoph Hellwig #include "pnfs.h"
525e1533c7SStanislav Kinsbursky 
531da177e4SLinus Torvalds #define NFSDDBG_FACILITY                NFSDDBG_PROC
541da177e4SLinus Torvalds 
55f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0}
56f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = {
57f32f3c2dSJ. Bruce Fields 	.si_generation = ~0,
58f32f3c2dSJ. Bruce Fields 	.si_opaque = all_ones,
59f32f3c2dSJ. Bruce Fields };
60f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = {
61f32f3c2dSJ. Bruce Fields 	/* all fields zero */
62f32f3c2dSJ. Bruce Fields };
6319ff0f28STigran Mkrtchyan static const stateid_t currentstateid = {
6419ff0f28STigran Mkrtchyan 	.si_generation = 1,
6519ff0f28STigran Mkrtchyan };
66f32f3c2dSJ. Bruce Fields 
67ec6b5d7bSAndy Adamson static u64 current_sessionid = 1;
68fd39ca9aSNeilBrown 
69f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
70f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
7119ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds /* forward declarations */
74f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
756011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
761da177e4SLinus Torvalds 
778b671b80SJ. Bruce Fields /* Locking: */
788b671b80SJ. Bruce Fields 
798b671b80SJ. Bruce Fields /*
808b671b80SJ. Bruce Fields  * Currently used for the del_recall_lru and file hash table.  In an
818b671b80SJ. Bruce Fields  * effort to decrease the scope of the client_mutex, this spinlock may
828b671b80SJ. Bruce Fields  * eventually cover more:
838b671b80SJ. Bruce Fields  */
84cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock);
858b671b80SJ. Bruce Fields 
86b401be22SJeff Layton /*
87b401be22SJeff Layton  * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for
88b401be22SJeff Layton  * the refcount on the open stateid to drop.
89b401be22SJeff Layton  */
90b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq);
91b401be22SJeff Layton 
92abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab;
93abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab;
94abf1135bSChristoph Hellwig static struct kmem_cache *file_slab;
95abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab;
96abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab;
978287f009SSachin Bhamare static struct kmem_cache *odstate_slab;
98e60d4398SNeilBrown 
9966b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *);
100508dc6e1SBenny Halevy 
101c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
1020162ac2bSChristoph Hellwig 
10366b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses)
104508dc6e1SBenny Halevy {
10566b2b9b2SJ. Bruce Fields 	return ses->se_flags & NFS4_SESSION_DEAD;
10666b2b9b2SJ. Bruce Fields }
10766b2b9b2SJ. Bruce Fields 
108f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
109f0f51f5cSJ. Bruce Fields {
110f0f51f5cSJ. Bruce Fields 	if (atomic_read(&ses->se_ref) > ref_held_by_me)
11166b2b9b2SJ. Bruce Fields 		return nfserr_jukebox;
11266b2b9b2SJ. Bruce Fields 	ses->se_flags |= NFS4_SESSION_DEAD;
11366b2b9b2SJ. Bruce Fields 	return nfs_ok;
11466b2b9b2SJ. Bruce Fields }
11566b2b9b2SJ. Bruce Fields 
116221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp)
117221a6876SJ. Bruce Fields {
118221a6876SJ. Bruce Fields 	return clp->cl_time == 0;
119221a6876SJ. Bruce Fields }
120221a6876SJ. Bruce Fields 
121221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp)
122221a6876SJ. Bruce Fields {
1230a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1240a880a28STrond Myklebust 
1250a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1260a880a28STrond Myklebust 
127221a6876SJ. Bruce Fields 	if (is_client_expired(clp))
128221a6876SJ. Bruce Fields 		return nfserr_expired;
129221a6876SJ. Bruce Fields 	atomic_inc(&clp->cl_refcount);
130221a6876SJ. Bruce Fields 	return nfs_ok;
131221a6876SJ. Bruce Fields }
132221a6876SJ. Bruce Fields 
133221a6876SJ. Bruce Fields /* must be called under the client_lock */
134221a6876SJ. Bruce Fields static inline void
135221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp)
136221a6876SJ. Bruce Fields {
137221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
138221a6876SJ. Bruce Fields 
139221a6876SJ. Bruce Fields 	if (is_client_expired(clp)) {
140221a6876SJ. Bruce Fields 		WARN_ON(1);
141221a6876SJ. Bruce Fields 		printk("%s: client (clientid %08x/%08x) already expired\n",
142221a6876SJ. Bruce Fields 			__func__,
143221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
144221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
145221a6876SJ. Bruce Fields 		return;
146221a6876SJ. Bruce Fields 	}
147221a6876SJ. Bruce Fields 
148221a6876SJ. Bruce Fields 	dprintk("renewing client (clientid %08x/%08x)\n",
149221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
150221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
151221a6876SJ. Bruce Fields 	list_move_tail(&clp->cl_lru, &nn->client_lru);
152221a6876SJ. Bruce Fields 	clp->cl_time = get_seconds();
153221a6876SJ. Bruce Fields }
154221a6876SJ. Bruce Fields 
155ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp)
156221a6876SJ. Bruce Fields {
1570a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1580a880a28STrond Myklebust 
1590a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1600a880a28STrond Myklebust 
161221a6876SJ. Bruce Fields 	if (!atomic_dec_and_test(&clp->cl_refcount))
162221a6876SJ. Bruce Fields 		return;
163221a6876SJ. Bruce Fields 	if (!is_client_expired(clp))
164221a6876SJ. Bruce Fields 		renew_client_locked(clp);
165221a6876SJ. Bruce Fields }
166221a6876SJ. Bruce Fields 
1674b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp)
1684b24ca7dSJeff Layton {
1694b24ca7dSJeff Layton 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1704b24ca7dSJeff Layton 
171d6c249b4SJeff Layton 	if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
172d6c249b4SJeff Layton 		return;
173d6c249b4SJeff Layton 	if (!is_client_expired(clp))
174d6c249b4SJeff Layton 		renew_client_locked(clp);
1754b24ca7dSJeff Layton 	spin_unlock(&nn->client_lock);
1764b24ca7dSJeff Layton }
1774b24ca7dSJeff Layton 
178d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
179d4e19e70STrond Myklebust {
180d4e19e70STrond Myklebust 	__be32 status;
181d4e19e70STrond Myklebust 
182d4e19e70STrond Myklebust 	if (is_session_dead(ses))
183d4e19e70STrond Myklebust 		return nfserr_badsession;
184d4e19e70STrond Myklebust 	status = get_client_locked(ses->se_client);
185d4e19e70STrond Myklebust 	if (status)
186d4e19e70STrond Myklebust 		return status;
187d4e19e70STrond Myklebust 	atomic_inc(&ses->se_ref);
188d4e19e70STrond Myklebust 	return nfs_ok;
189d4e19e70STrond Myklebust }
190d4e19e70STrond Myklebust 
191d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses)
192d4e19e70STrond Myklebust {
193d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
1940a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1950a880a28STrond Myklebust 
1960a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
197d4e19e70STrond Myklebust 
198d4e19e70STrond Myklebust 	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
199d4e19e70STrond Myklebust 		free_session(ses);
200d4e19e70STrond Myklebust 	put_client_renew_locked(clp);
201d4e19e70STrond Myklebust }
202d4e19e70STrond Myklebust 
203d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses)
204d4e19e70STrond Myklebust {
205d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
206d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
207d4e19e70STrond Myklebust 
208d4e19e70STrond Myklebust 	spin_lock(&nn->client_lock);
209d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
210d4e19e70STrond Myklebust 	spin_unlock(&nn->client_lock);
211d4e19e70STrond Myklebust }
212d4e19e70STrond Myklebust 
213b5971afaSKinglong Mee static inline struct nfs4_stateowner *
214b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop)
215b5971afaSKinglong Mee {
216b5971afaSKinglong Mee 	atomic_inc(&sop->so_count);
217b5971afaSKinglong Mee 	return sop;
218b5971afaSKinglong Mee }
219b5971afaSKinglong Mee 
2207ffb5880STrond Myklebust static int
221d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
2227ffb5880STrond Myklebust {
2237ffb5880STrond Myklebust 	return (sop->so_owner.len == owner->len) &&
224d4f0489fSTrond Myklebust 		0 == memcmp(sop->so_owner.data, owner->data, owner->len);
2257ffb5880STrond Myklebust }
2267ffb5880STrond Myklebust 
2277ffb5880STrond Myklebust static struct nfs4_openowner *
2287ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
229d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
2307ffb5880STrond Myklebust {
2317ffb5880STrond Myklebust 	struct nfs4_stateowner *so;
2327ffb5880STrond Myklebust 
233d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
2347ffb5880STrond Myklebust 
235d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval],
236d4f0489fSTrond Myklebust 			    so_strhash) {
2377ffb5880STrond Myklebust 		if (!so->so_is_open_owner)
2387ffb5880STrond Myklebust 			continue;
239b5971afaSKinglong Mee 		if (same_owner_str(so, &open->op_owner))
240b5971afaSKinglong Mee 			return openowner(nfs4_get_stateowner(so));
2417ffb5880STrond Myklebust 	}
2427ffb5880STrond Myklebust 	return NULL;
2437ffb5880STrond Myklebust }
2447ffb5880STrond Myklebust 
2457ffb5880STrond Myklebust static struct nfs4_openowner *
2467ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
247d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
2487ffb5880STrond Myklebust {
2497ffb5880STrond Myklebust 	struct nfs4_openowner *oo;
2507ffb5880STrond Myklebust 
251d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
252d4f0489fSTrond Myklebust 	oo = find_openstateowner_str_locked(hashval, open, clp);
253d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
2547ffb5880STrond Myklebust 	return oo;
2557ffb5880STrond Myklebust }
2567ffb5880STrond Myklebust 
2571da177e4SLinus Torvalds static inline u32
2581da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes)
2591da177e4SLinus Torvalds {
2601da177e4SLinus Torvalds 	unsigned char *cptr = (unsigned char *) ptr;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	u32 x = 0;
2631da177e4SLinus Torvalds 	while (nbytes--) {
2641da177e4SLinus Torvalds 		x *= 37;
2651da177e4SLinus Torvalds 		x += *cptr++;
2661da177e4SLinus Torvalds 	}
2671da177e4SLinus Torvalds 	return x;
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds 
2705b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu)
27132513b40SJ. Bruce Fields {
2725b095e99SJeff Layton 	struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu);
2735b095e99SJeff Layton 
2745b095e99SJeff Layton 	kmem_cache_free(file_slab, fp);
27532513b40SJ. Bruce Fields }
27632513b40SJ. Bruce Fields 
277e6ba76e1SChristoph Hellwig void
27813cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi)
27913cd2184SNeilBrown {
28002e1215fSJeff Layton 	might_lock(&state_lock);
28102e1215fSJeff Layton 
282cdc97505SBenny Halevy 	if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
2835b095e99SJeff Layton 		hlist_del_rcu(&fi->fi_hash);
284cdc97505SBenny Halevy 		spin_unlock(&state_lock);
2858287f009SSachin Bhamare 		WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
2865b095e99SJeff Layton 		WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
2875b095e99SJeff Layton 		call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
2888b671b80SJ. Bruce Fields 	}
28913cd2184SNeilBrown }
29013cd2184SNeilBrown 
291de18643dSTrond Myklebust static struct file *
292de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag)
293de18643dSTrond Myklebust {
294de18643dSTrond Myklebust 	if (f->fi_fds[oflag])
295de18643dSTrond Myklebust 		return get_file(f->fi_fds[oflag]);
296de18643dSTrond Myklebust 	return NULL;
297de18643dSTrond Myklebust }
298de18643dSTrond Myklebust 
299de18643dSTrond Myklebust static struct file *
300de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f)
301de18643dSTrond Myklebust {
302de18643dSTrond Myklebust 	struct file *ret;
303de18643dSTrond Myklebust 
304de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
305de18643dSTrond Myklebust 
306de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_WRONLY);
307de18643dSTrond Myklebust 	if (!ret)
308de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
309de18643dSTrond Myklebust 	return ret;
310de18643dSTrond Myklebust }
311de18643dSTrond Myklebust 
312de18643dSTrond Myklebust static struct file *
313de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f)
314de18643dSTrond Myklebust {
315de18643dSTrond Myklebust 	struct file *ret;
316de18643dSTrond Myklebust 
317de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
318de18643dSTrond Myklebust 	ret = find_writeable_file_locked(f);
319de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
320de18643dSTrond Myklebust 
321de18643dSTrond Myklebust 	return ret;
322de18643dSTrond Myklebust }
323de18643dSTrond Myklebust 
324de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f)
325de18643dSTrond Myklebust {
326de18643dSTrond Myklebust 	struct file *ret;
327de18643dSTrond Myklebust 
328de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
329de18643dSTrond Myklebust 
330de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDONLY);
331de18643dSTrond Myklebust 	if (!ret)
332de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
333de18643dSTrond Myklebust 	return ret;
334de18643dSTrond Myklebust }
335de18643dSTrond Myklebust 
336de18643dSTrond Myklebust static struct file *
337de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f)
338de18643dSTrond Myklebust {
339de18643dSTrond Myklebust 	struct file *ret;
340de18643dSTrond Myklebust 
341de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
342de18643dSTrond Myklebust 	ret = find_readable_file_locked(f);
343de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
344de18643dSTrond Myklebust 
345de18643dSTrond Myklebust 	return ret;
346de18643dSTrond Myklebust }
347de18643dSTrond Myklebust 
3484d227fcaSChristoph Hellwig struct file *
349de18643dSTrond Myklebust find_any_file(struct nfs4_file *f)
350de18643dSTrond Myklebust {
351de18643dSTrond Myklebust 	struct file *ret;
352de18643dSTrond Myklebust 
353de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
354de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDWR);
355de18643dSTrond Myklebust 	if (!ret) {
356de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_WRONLY);
357de18643dSTrond Myklebust 		if (!ret)
358de18643dSTrond Myklebust 			ret = __nfs4_get_fd(f, O_RDONLY);
359de18643dSTrond Myklebust 	}
360de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
361de18643dSTrond Myklebust 	return ret;
362de18643dSTrond Myklebust }
363de18643dSTrond Myklebust 
36402a3508dSTrond Myklebust static atomic_long_t num_delegations;
365697ce9beSZhang Yanfei unsigned long max_delegations;
366ef0f3390SNeilBrown 
367ef0f3390SNeilBrown /*
368ef0f3390SNeilBrown  * Open owner state (share locks)
369ef0f3390SNeilBrown  */
370ef0f3390SNeilBrown 
37116bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */
37216bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS              8
37316bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
37416bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
375ef0f3390SNeilBrown 
376d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername)
377ddc04c41SJ. Bruce Fields {
378ddc04c41SJ. Bruce Fields 	unsigned int ret;
379ddc04c41SJ. Bruce Fields 
380ddc04c41SJ. Bruce Fields 	ret = opaque_hashval(ownername->data, ownername->len);
38116bfdaafSJ. Bruce Fields 	return ret & OWNER_HASH_MASK;
382ddc04c41SJ. Bruce Fields }
383ef0f3390SNeilBrown 
384ef0f3390SNeilBrown /* hash table for nfs4_file */
385ef0f3390SNeilBrown #define FILE_HASH_BITS                   8
386ef0f3390SNeilBrown #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
38735079582SShan Wei 
388ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh)
389ddc04c41SJ. Bruce Fields {
390ca943217STrond Myklebust 	return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0);
391ca943217STrond Myklebust }
392ca943217STrond Myklebust 
393ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh)
394ca943217STrond Myklebust {
395ca943217STrond Myklebust 	return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1);
396ca943217STrond Myklebust }
397ca943217STrond Myklebust 
39889876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
399ef0f3390SNeilBrown 
40012659651SJeff Layton static void
40112659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
4023477565eSJ. Bruce Fields {
4037214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4047214e860SJeff Layton 
40512659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
40612659651SJeff Layton 		atomic_inc(&fp->fi_access[O_WRONLY]);
40712659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
40812659651SJeff Layton 		atomic_inc(&fp->fi_access[O_RDONLY]);
4093477565eSJ. Bruce Fields }
4103477565eSJ. Bruce Fields 
41112659651SJeff Layton static __be32
41212659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access)
413998db52cSJ. Bruce Fields {
4147214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4157214e860SJeff Layton 
41612659651SJeff Layton 	/* Does this access mode make sense? */
41712659651SJeff Layton 	if (access & ~NFS4_SHARE_ACCESS_BOTH)
41812659651SJeff Layton 		return nfserr_inval;
41912659651SJeff Layton 
420baeb4ff0SJeff Layton 	/* Does it conflict with a deny mode already set? */
421baeb4ff0SJeff Layton 	if ((access & fp->fi_share_deny) != 0)
422baeb4ff0SJeff Layton 		return nfserr_share_denied;
423baeb4ff0SJeff Layton 
42412659651SJeff Layton 	__nfs4_file_get_access(fp, access);
42512659651SJeff Layton 	return nfs_ok;
426998db52cSJ. Bruce Fields }
427998db52cSJ. Bruce Fields 
428baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny)
429baeb4ff0SJeff Layton {
430baeb4ff0SJeff Layton 	/* Common case is that there is no deny mode. */
431baeb4ff0SJeff Layton 	if (deny) {
432baeb4ff0SJeff Layton 		/* Does this deny mode make sense? */
433baeb4ff0SJeff Layton 		if (deny & ~NFS4_SHARE_DENY_BOTH)
434baeb4ff0SJeff Layton 			return nfserr_inval;
435baeb4ff0SJeff Layton 
436baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_READ) &&
437baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_RDONLY]))
438baeb4ff0SJeff Layton 			return nfserr_share_denied;
439baeb4ff0SJeff Layton 
440baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_WRITE) &&
441baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_WRONLY]))
442baeb4ff0SJeff Layton 			return nfserr_share_denied;
443baeb4ff0SJeff Layton 	}
444baeb4ff0SJeff Layton 	return nfs_ok;
445baeb4ff0SJeff Layton }
446baeb4ff0SJeff Layton 
447998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
448f9d7562fSJ. Bruce Fields {
449de18643dSTrond Myklebust 	might_lock(&fp->fi_lock);
450de18643dSTrond Myklebust 
451de18643dSTrond Myklebust 	if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) {
452de18643dSTrond Myklebust 		struct file *f1 = NULL;
453de18643dSTrond Myklebust 		struct file *f2 = NULL;
454de18643dSTrond Myklebust 
4556d338b51SJeff Layton 		swap(f1, fp->fi_fds[oflag]);
4560c7c3e67SJ. Bruce Fields 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
4576d338b51SJeff Layton 			swap(f2, fp->fi_fds[O_RDWR]);
458de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
459de18643dSTrond Myklebust 		if (f1)
460de18643dSTrond Myklebust 			fput(f1);
461de18643dSTrond Myklebust 		if (f2)
462de18643dSTrond Myklebust 			fput(f2);
463f9d7562fSJ. Bruce Fields 	}
464f9d7562fSJ. Bruce Fields }
465f9d7562fSJ. Bruce Fields 
46612659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
467998db52cSJ. Bruce Fields {
46812659651SJeff Layton 	WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH);
46912659651SJeff Layton 
47012659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
471998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, O_WRONLY);
47212659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
47312659651SJeff Layton 		__nfs4_file_put_access(fp, O_RDONLY);
474998db52cSJ. Bruce Fields }
475998db52cSJ. Bruce Fields 
4768287f009SSachin Bhamare /*
4778287f009SSachin Bhamare  * Allocate a new open/delegation state counter. This is needed for
4788287f009SSachin Bhamare  * pNFS for proper return on close semantics.
4798287f009SSachin Bhamare  *
4808287f009SSachin Bhamare  * Note that we only allocate it for pNFS-enabled exports, otherwise
4818287f009SSachin Bhamare  * all pointers to struct nfs4_clnt_odstate are always NULL.
4828287f009SSachin Bhamare  */
4838287f009SSachin Bhamare static struct nfs4_clnt_odstate *
4848287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp)
4858287f009SSachin Bhamare {
4868287f009SSachin Bhamare 	struct nfs4_clnt_odstate *co;
4878287f009SSachin Bhamare 
4888287f009SSachin Bhamare 	co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL);
4898287f009SSachin Bhamare 	if (co) {
4908287f009SSachin Bhamare 		co->co_client = clp;
4918287f009SSachin Bhamare 		atomic_set(&co->co_odcount, 1);
4928287f009SSachin Bhamare 	}
4938287f009SSachin Bhamare 	return co;
4948287f009SSachin Bhamare }
4958287f009SSachin Bhamare 
4968287f009SSachin Bhamare static void
4978287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co)
4988287f009SSachin Bhamare {
4998287f009SSachin Bhamare 	struct nfs4_file *fp = co->co_file;
5008287f009SSachin Bhamare 
5018287f009SSachin Bhamare 	lockdep_assert_held(&fp->fi_lock);
5028287f009SSachin Bhamare 	list_add(&co->co_perfile, &fp->fi_clnt_odstate);
5038287f009SSachin Bhamare }
5048287f009SSachin Bhamare 
5058287f009SSachin Bhamare static inline void
5068287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co)
5078287f009SSachin Bhamare {
5088287f009SSachin Bhamare 	if (co)
5098287f009SSachin Bhamare 		atomic_inc(&co->co_odcount);
5108287f009SSachin Bhamare }
5118287f009SSachin Bhamare 
5128287f009SSachin Bhamare static void
5138287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co)
5148287f009SSachin Bhamare {
5158287f009SSachin Bhamare 	struct nfs4_file *fp;
5168287f009SSachin Bhamare 
5178287f009SSachin Bhamare 	if (!co)
5188287f009SSachin Bhamare 		return;
5198287f009SSachin Bhamare 
5208287f009SSachin Bhamare 	fp = co->co_file;
5218287f009SSachin Bhamare 	if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
5228287f009SSachin Bhamare 		list_del(&co->co_perfile);
5238287f009SSachin Bhamare 		spin_unlock(&fp->fi_lock);
5248287f009SSachin Bhamare 
5258287f009SSachin Bhamare 		nfsd4_return_all_file_layouts(co->co_client, fp);
5268287f009SSachin Bhamare 		kmem_cache_free(odstate_slab, co);
5278287f009SSachin Bhamare 	}
5288287f009SSachin Bhamare }
5298287f009SSachin Bhamare 
5308287f009SSachin Bhamare static struct nfs4_clnt_odstate *
5318287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new)
5328287f009SSachin Bhamare {
5338287f009SSachin Bhamare 	struct nfs4_clnt_odstate *co;
5348287f009SSachin Bhamare 	struct nfs4_client *cl;
5358287f009SSachin Bhamare 
5368287f009SSachin Bhamare 	if (!new)
5378287f009SSachin Bhamare 		return NULL;
5388287f009SSachin Bhamare 
5398287f009SSachin Bhamare 	cl = new->co_client;
5408287f009SSachin Bhamare 
5418287f009SSachin Bhamare 	spin_lock(&fp->fi_lock);
5428287f009SSachin Bhamare 	list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) {
5438287f009SSachin Bhamare 		if (co->co_client == cl) {
5448287f009SSachin Bhamare 			get_clnt_odstate(co);
5458287f009SSachin Bhamare 			goto out;
5468287f009SSachin Bhamare 		}
5478287f009SSachin Bhamare 	}
5488287f009SSachin Bhamare 	co = new;
5498287f009SSachin Bhamare 	co->co_file = fp;
5508287f009SSachin Bhamare 	hash_clnt_odstate_locked(new);
5518287f009SSachin Bhamare out:
5528287f009SSachin Bhamare 	spin_unlock(&fp->fi_lock);
5538287f009SSachin Bhamare 	return co;
5548287f009SSachin Bhamare }
5558287f009SSachin Bhamare 
556cd61c522SChristoph Hellwig struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
5576011695dSTrond Myklebust 					 struct kmem_cache *slab)
558996e0938SJ. Bruce Fields {
5593abdb607SJ. Bruce Fields 	struct nfs4_stid *stid;
5603abdb607SJ. Bruce Fields 	int new_id;
5613abdb607SJ. Bruce Fields 
562f8338834STrond Myklebust 	stid = kmem_cache_zalloc(slab, GFP_KERNEL);
5633abdb607SJ. Bruce Fields 	if (!stid)
5643abdb607SJ. Bruce Fields 		return NULL;
565996e0938SJ. Bruce Fields 
5664770d722SJeff Layton 	idr_preload(GFP_KERNEL);
5674770d722SJeff Layton 	spin_lock(&cl->cl_lock);
5684770d722SJeff Layton 	new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT);
5694770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
5704770d722SJeff Layton 	idr_preload_end();
571ebd6c707STejun Heo 	if (new_id < 0)
5723abdb607SJ. Bruce Fields 		goto out_free;
5733abdb607SJ. Bruce Fields 	stid->sc_client = cl;
5743abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_id = new_id;
5753abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
5763abdb607SJ. Bruce Fields 	/* Will be incremented before return to client: */
57772c0b0fbSTrond Myklebust 	atomic_set(&stid->sc_count, 1);
5789767feb2SJeff Layton 	spin_lock_init(&stid->sc_lock);
5793abdb607SJ. Bruce Fields 
580996e0938SJ. Bruce Fields 	/*
5813abdb607SJ. Bruce Fields 	 * It shouldn't be a problem to reuse an opaque stateid value.
5823abdb607SJ. Bruce Fields 	 * I don't think it is for 4.1.  But with 4.0 I worry that, for
5833abdb607SJ. Bruce Fields 	 * example, a stray write retransmission could be accepted by
5843abdb607SJ. Bruce Fields 	 * the server when it should have been rejected.  Therefore,
5853abdb607SJ. Bruce Fields 	 * adopt a trick from the sctp code to attempt to maximize the
5863abdb607SJ. Bruce Fields 	 * amount of time until an id is reused, by ensuring they always
5873abdb607SJ. Bruce Fields 	 * "increase" (mod INT_MAX):
588996e0938SJ. Bruce Fields 	 */
5893abdb607SJ. Bruce Fields 	return stid;
5903abdb607SJ. Bruce Fields out_free:
5912c44a234SWei Yongjun 	kmem_cache_free(slab, stid);
5923abdb607SJ. Bruce Fields 	return NULL;
5932a74aba7SJ. Bruce Fields }
5942a74aba7SJ. Bruce Fields 
595b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
5964cdc951bSJ. Bruce Fields {
5976011695dSTrond Myklebust 	struct nfs4_stid *stid;
5986011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp;
5996011695dSTrond Myklebust 
6006011695dSTrond Myklebust 	stid = nfs4_alloc_stid(clp, stateid_slab);
6016011695dSTrond Myklebust 	if (!stid)
6026011695dSTrond Myklebust 		return NULL;
6036011695dSTrond Myklebust 
6046011695dSTrond Myklebust 	stp = openlockstateid(stid);
6056011695dSTrond Myklebust 	stp->st_stid.sc_free = nfs4_free_ol_stateid;
6066011695dSTrond Myklebust 	return stp;
6076011695dSTrond Myklebust }
6086011695dSTrond Myklebust 
6096011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid)
6106011695dSTrond Myklebust {
6116011695dSTrond Myklebust 	kmem_cache_free(deleg_slab, stid);
6126011695dSTrond Myklebust 	atomic_long_dec(&num_delegations);
6134cdc951bSJ. Bruce Fields }
6144cdc951bSJ. Bruce Fields 
6156282cd56SNeilBrown /*
6166282cd56SNeilBrown  * When we recall a delegation, we should be careful not to hand it
6176282cd56SNeilBrown  * out again straight away.
6186282cd56SNeilBrown  * To ensure this we keep a pair of bloom filters ('new' and 'old')
6196282cd56SNeilBrown  * in which the filehandles of recalled delegations are "stored".
6206282cd56SNeilBrown  * If a filehandle appear in either filter, a delegation is blocked.
6216282cd56SNeilBrown  * When a delegation is recalled, the filehandle is stored in the "new"
6226282cd56SNeilBrown  * filter.
6236282cd56SNeilBrown  * Every 30 seconds we swap the filters and clear the "new" one,
6246282cd56SNeilBrown  * unless both are empty of course.
6256282cd56SNeilBrown  *
6266282cd56SNeilBrown  * Each filter is 256 bits.  We hash the filehandle to 32bit and use the
6276282cd56SNeilBrown  * low 3 bytes as hash-table indices.
6286282cd56SNeilBrown  *
629f54fe962SJeff Layton  * 'blocked_delegations_lock', which is always taken in block_delegations(),
6306282cd56SNeilBrown  * is used to manage concurrent access.  Testing does not need the lock
6316282cd56SNeilBrown  * except when swapping the two filters.
6326282cd56SNeilBrown  */
633f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock);
6346282cd56SNeilBrown static struct bloom_pair {
6356282cd56SNeilBrown 	int	entries, old_entries;
6366282cd56SNeilBrown 	time_t	swap_time;
6376282cd56SNeilBrown 	int	new; /* index into 'set' */
6386282cd56SNeilBrown 	DECLARE_BITMAP(set[2], 256);
6396282cd56SNeilBrown } blocked_delegations;
6406282cd56SNeilBrown 
6416282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh)
6426282cd56SNeilBrown {
6436282cd56SNeilBrown 	u32 hash;
6446282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
6456282cd56SNeilBrown 
6466282cd56SNeilBrown 	if (bd->entries == 0)
6476282cd56SNeilBrown 		return 0;
6486282cd56SNeilBrown 	if (seconds_since_boot() - bd->swap_time > 30) {
649f54fe962SJeff Layton 		spin_lock(&blocked_delegations_lock);
6506282cd56SNeilBrown 		if (seconds_since_boot() - bd->swap_time > 30) {
6516282cd56SNeilBrown 			bd->entries -= bd->old_entries;
6526282cd56SNeilBrown 			bd->old_entries = bd->entries;
6536282cd56SNeilBrown 			memset(bd->set[bd->new], 0,
6546282cd56SNeilBrown 			       sizeof(bd->set[0]));
6556282cd56SNeilBrown 			bd->new = 1-bd->new;
6566282cd56SNeilBrown 			bd->swap_time = seconds_since_boot();
6576282cd56SNeilBrown 		}
658f54fe962SJeff Layton 		spin_unlock(&blocked_delegations_lock);
6596282cd56SNeilBrown 	}
66087545899SDaniel Borkmann 	hash = jhash(&fh->fh_base, fh->fh_size, 0);
6616282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[0]) &&
6626282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[0]) &&
6636282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[0]))
6646282cd56SNeilBrown 		return 1;
6656282cd56SNeilBrown 
6666282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[1]) &&
6676282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[1]) &&
6686282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[1]))
6696282cd56SNeilBrown 		return 1;
6706282cd56SNeilBrown 
6716282cd56SNeilBrown 	return 0;
6726282cd56SNeilBrown }
6736282cd56SNeilBrown 
6746282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh)
6756282cd56SNeilBrown {
6766282cd56SNeilBrown 	u32 hash;
6776282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
6786282cd56SNeilBrown 
67987545899SDaniel Borkmann 	hash = jhash(&fh->fh_base, fh->fh_size, 0);
6806282cd56SNeilBrown 
681f54fe962SJeff Layton 	spin_lock(&blocked_delegations_lock);
6826282cd56SNeilBrown 	__set_bit(hash&255, bd->set[bd->new]);
6836282cd56SNeilBrown 	__set_bit((hash>>8)&255, bd->set[bd->new]);
6846282cd56SNeilBrown 	__set_bit((hash>>16)&255, bd->set[bd->new]);
6856282cd56SNeilBrown 	if (bd->entries == 0)
6866282cd56SNeilBrown 		bd->swap_time = seconds_since_boot();
6876282cd56SNeilBrown 	bd->entries += 1;
688f54fe962SJeff Layton 	spin_unlock(&blocked_delegations_lock);
6896282cd56SNeilBrown }
6906282cd56SNeilBrown 
6911da177e4SLinus Torvalds static struct nfs4_delegation *
6928287f009SSachin Bhamare alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
6938287f009SSachin Bhamare 		 struct nfs4_clnt_odstate *odstate)
6941da177e4SLinus Torvalds {
6951da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
69602a3508dSTrond Myklebust 	long n;
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	dprintk("NFSD alloc_init_deleg\n");
69902a3508dSTrond Myklebust 	n = atomic_long_inc_return(&num_delegations);
70002a3508dSTrond Myklebust 	if (n < 0 || n > max_delegations)
70102a3508dSTrond Myklebust 		goto out_dec;
7026282cd56SNeilBrown 	if (delegation_blocked(&current_fh->fh_handle))
70302a3508dSTrond Myklebust 		goto out_dec;
704996e0938SJ. Bruce Fields 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
7055b2d21c1SNeilBrown 	if (dp == NULL)
70602a3508dSTrond Myklebust 		goto out_dec;
7076011695dSTrond Myklebust 
7086011695dSTrond Myklebust 	dp->dl_stid.sc_free = nfs4_free_deleg;
7092a74aba7SJ. Bruce Fields 	/*
7102a74aba7SJ. Bruce Fields 	 * delegation seqid's are never incremented.  The 4.1 special
7116136d2b4SJ. Bruce Fields 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
7126136d2b4SJ. Bruce Fields 	 * 0 anyway just for consistency and use 1:
7132a74aba7SJ. Bruce Fields 	 */
7142a74aba7SJ. Bruce Fields 	dp->dl_stid.sc_stateid.si_generation = 1;
715ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perfile);
716ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perclnt);
7171da177e4SLinus Torvalds 	INIT_LIST_HEAD(&dp->dl_recall_lru);
7188287f009SSachin Bhamare 	dp->dl_clnt_odstate = odstate;
7198287f009SSachin Bhamare 	get_clnt_odstate(odstate);
72099c41515SJ. Bruce Fields 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
721f0b5de1bSChristoph Hellwig 	dp->dl_retries = 1;
722f0b5de1bSChristoph Hellwig 	nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client,
7230162ac2bSChristoph Hellwig 		      &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL);
7241da177e4SLinus Torvalds 	return dp;
72502a3508dSTrond Myklebust out_dec:
72602a3508dSTrond Myklebust 	atomic_long_dec(&num_delegations);
72702a3508dSTrond Myklebust 	return NULL;
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds void
7316011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s)
7321da177e4SLinus Torvalds {
73311b9164aSTrond Myklebust 	struct nfs4_file *fp = s->sc_file;
7346011695dSTrond Myklebust 	struct nfs4_client *clp = s->sc_client;
7356011695dSTrond Myklebust 
7364770d722SJeff Layton 	might_lock(&clp->cl_lock);
7374770d722SJeff Layton 
738b401be22SJeff Layton 	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
739b401be22SJeff Layton 		wake_up_all(&close_wq);
7406011695dSTrond Myklebust 		return;
741b401be22SJeff Layton 	}
7426011695dSTrond Myklebust 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
7434770d722SJeff Layton 	spin_unlock(&clp->cl_lock);
7446011695dSTrond Myklebust 	s->sc_free(s);
74511b9164aSTrond Myklebust 	if (fp)
74611b9164aSTrond Myklebust 		put_nfs4_file(fp);
7471da177e4SLinus Torvalds }
7481da177e4SLinus Torvalds 
7499767feb2SJeff Layton void
7509767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid)
7519767feb2SJeff Layton {
7529767feb2SJeff Layton 	stateid_t *src = &stid->sc_stateid;
7539767feb2SJeff Layton 
7549767feb2SJeff Layton 	spin_lock(&stid->sc_lock);
7559767feb2SJeff Layton 	if (unlikely(++src->si_generation == 0))
7569767feb2SJeff Layton 		src->si_generation = 1;
7579767feb2SJeff Layton 	memcpy(dst, src, sizeof(*dst));
7589767feb2SJeff Layton 	spin_unlock(&stid->sc_lock);
7599767feb2SJeff Layton }
7609767feb2SJeff Layton 
761acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp)
7621da177e4SLinus Torvalds {
7636bcc034eSJeff Layton 	struct file *filp = NULL;
764417c6629SJeff Layton 
7656bcc034eSJeff Layton 	spin_lock(&fp->fi_lock);
76667db1034SJeff Layton 	if (fp->fi_deleg_file && --fp->fi_delegees == 0)
7676bcc034eSJeff Layton 		swap(filp, fp->fi_deleg_file);
7686bcc034eSJeff Layton 	spin_unlock(&fp->fi_lock);
7696bcc034eSJeff Layton 
7706bcc034eSJeff Layton 	if (filp) {
7712ab99ee1SChristoph Hellwig 		vfs_setlease(filp, F_UNLCK, NULL, (void **)&fp);
7726bcc034eSJeff Layton 		fput(filp);
773acfdf5c3SJ. Bruce Fields 	}
7741da177e4SLinus Torvalds }
7751da177e4SLinus Torvalds 
776cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s)
7776136d2b4SJ. Bruce Fields {
7783abdb607SJ. Bruce Fields 	s->sc_type = 0;
7796136d2b4SJ. Bruce Fields }
7806136d2b4SJ. Bruce Fields 
78134ed9872SAndrew Elble /**
78234ed9872SAndrew Elble  * nfs4_get_existing_delegation - Discover if this delegation already exists
78334ed9872SAndrew Elble  * @clp:     a pointer to the nfs4_client we're granting a delegation to
78434ed9872SAndrew Elble  * @fp:      a pointer to the nfs4_file we're granting a delegation on
78534ed9872SAndrew Elble  *
78634ed9872SAndrew Elble  * Return:
78734ed9872SAndrew Elble  *      On success: NULL if an existing delegation was not found.
78834ed9872SAndrew Elble  *
78934ed9872SAndrew Elble  *      On error: -EAGAIN if one was previously granted to this nfs4_client
79034ed9872SAndrew Elble  *                 for this nfs4_file.
79134ed9872SAndrew Elble  *
79234ed9872SAndrew Elble  */
79334ed9872SAndrew Elble 
79434ed9872SAndrew Elble static int
79534ed9872SAndrew Elble nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
796931ee56cSBenny Halevy {
79734ed9872SAndrew Elble 	struct nfs4_delegation *searchdp = NULL;
79834ed9872SAndrew Elble 	struct nfs4_client *searchclp = NULL;
79934ed9872SAndrew Elble 
800cdc97505SBenny Halevy 	lockdep_assert_held(&state_lock);
801417c6629SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
802931ee56cSBenny Halevy 
80334ed9872SAndrew Elble 	list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) {
80434ed9872SAndrew Elble 		searchclp = searchdp->dl_stid.sc_client;
80534ed9872SAndrew Elble 		if (clp == searchclp) {
80634ed9872SAndrew Elble 			return -EAGAIN;
80734ed9872SAndrew Elble 		}
80834ed9872SAndrew Elble 	}
80934ed9872SAndrew Elble 	return 0;
81034ed9872SAndrew Elble }
81134ed9872SAndrew Elble 
81234ed9872SAndrew Elble /**
81334ed9872SAndrew Elble  * hash_delegation_locked - Add a delegation to the appropriate lists
81434ed9872SAndrew Elble  * @dp:     a pointer to the nfs4_delegation we are adding.
81534ed9872SAndrew Elble  * @fp:     a pointer to the nfs4_file we're granting a delegation on
81634ed9872SAndrew Elble  *
81734ed9872SAndrew Elble  * Return:
81834ed9872SAndrew Elble  *      On success: NULL if the delegation was successfully hashed.
81934ed9872SAndrew Elble  *
82034ed9872SAndrew Elble  *      On error: -EAGAIN if one was previously granted to this
82134ed9872SAndrew Elble  *                 nfs4_client for this nfs4_file. Delegation is not hashed.
82234ed9872SAndrew Elble  *
82334ed9872SAndrew Elble  */
82434ed9872SAndrew Elble 
82534ed9872SAndrew Elble static int
82634ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
82734ed9872SAndrew Elble {
82834ed9872SAndrew Elble 	int status;
82934ed9872SAndrew Elble 	struct nfs4_client *clp = dp->dl_stid.sc_client;
83034ed9872SAndrew Elble 
83134ed9872SAndrew Elble 	lockdep_assert_held(&state_lock);
83234ed9872SAndrew Elble 	lockdep_assert_held(&fp->fi_lock);
83334ed9872SAndrew Elble 
83434ed9872SAndrew Elble 	status = nfs4_get_existing_delegation(clp, fp);
83534ed9872SAndrew Elble 	if (status)
83634ed9872SAndrew Elble 		return status;
83734ed9872SAndrew Elble 	++fp->fi_delegees;
83867cb1279STrond Myklebust 	atomic_inc(&dp->dl_stid.sc_count);
8393fb87d13SBenny Halevy 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
840931ee56cSBenny Halevy 	list_add(&dp->dl_perfile, &fp->fi_delegations);
84134ed9872SAndrew Elble 	list_add(&dp->dl_perclnt, &clp->cl_delegations);
84234ed9872SAndrew Elble 	return 0;
843931ee56cSBenny Halevy }
844931ee56cSBenny Halevy 
8453fcbbd24SJeff Layton static bool
84642690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp)
8471da177e4SLinus Torvalds {
84811b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
84902e1215fSJeff Layton 
85042690676SJeff Layton 	lockdep_assert_held(&state_lock);
85142690676SJeff Layton 
8523fcbbd24SJeff Layton 	if (list_empty(&dp->dl_perfile))
8533fcbbd24SJeff Layton 		return false;
8543fcbbd24SJeff Layton 
855b0fc29d6STrond Myklebust 	dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
856d55a166cSJeff Layton 	/* Ensure that deleg break won't try to requeue it */
857d55a166cSJeff Layton 	++dp->dl_time;
858417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
859931ee56cSBenny Halevy 	list_del_init(&dp->dl_perclnt);
8601da177e4SLinus Torvalds 	list_del_init(&dp->dl_recall_lru);
86102e1215fSJeff Layton 	list_del_init(&dp->dl_perfile);
86202e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
8633fcbbd24SJeff Layton 	return true;
864cbf7a75bSJ. Bruce Fields }
8653bd64a5bSJ. Bruce Fields 
8663bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp)
8673bd64a5bSJ. Bruce Fields {
8683fcbbd24SJeff Layton 	bool unhashed;
8693fcbbd24SJeff Layton 
87042690676SJeff Layton 	spin_lock(&state_lock);
8713fcbbd24SJeff Layton 	unhashed = unhash_delegation_locked(dp);
87242690676SJeff Layton 	spin_unlock(&state_lock);
8733fcbbd24SJeff Layton 	if (unhashed) {
8748287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
875afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
8766011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
8773bd64a5bSJ. Bruce Fields 	}
8783fcbbd24SJeff Layton }
8793bd64a5bSJ. Bruce Fields 
8803bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp)
8813bd64a5bSJ. Bruce Fields {
8823bd64a5bSJ. Bruce Fields 	struct nfs4_client *clp = dp->dl_stid.sc_client;
8833bd64a5bSJ. Bruce Fields 
8842d4a532dSJeff Layton 	WARN_ON(!list_empty(&dp->dl_recall_lru));
8852d4a532dSJeff Layton 
8868287f009SSachin Bhamare 	put_clnt_odstate(dp->dl_clnt_odstate);
887afbda402SJeff Layton 	nfs4_put_deleg_lease(dp->dl_stid.sc_file);
888afbda402SJeff Layton 
8893bd64a5bSJ. Bruce Fields 	if (clp->cl_minorversion == 0)
8906011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
8913bd64a5bSJ. Bruce Fields 	else {
8923bd64a5bSJ. Bruce Fields 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
8932d4a532dSJeff Layton 		spin_lock(&clp->cl_lock);
8942d4a532dSJeff Layton 		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
8952d4a532dSJeff Layton 		spin_unlock(&clp->cl_lock);
8963bd64a5bSJ. Bruce Fields 	}
8973bd64a5bSJ. Bruce Fields }
8983bd64a5bSJ. Bruce Fields 
8991da177e4SLinus Torvalds /*
9001da177e4SLinus Torvalds  * SETCLIENTID state
9011da177e4SLinus Torvalds  */
9021da177e4SLinus Torvalds 
903ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id)
904ddc04c41SJ. Bruce Fields {
905ddc04c41SJ. Bruce Fields 	return id & CLIENT_HASH_MASK;
906ddc04c41SJ. Bruce Fields }
907ddc04c41SJ. Bruce Fields 
908ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name)
909ddc04c41SJ. Bruce Fields {
910ddc04c41SJ. Bruce Fields 	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
911ddc04c41SJ. Bruce Fields }
912ddc04c41SJ. Bruce Fields 
9131da177e4SLinus Torvalds /*
914f9d7562fSJ. Bruce Fields  * We store the NONE, READ, WRITE, and BOTH bits separately in the
915f9d7562fSJ. Bruce Fields  * st_{access,deny}_bmap field of the stateid, in order to track not
916f9d7562fSJ. Bruce Fields  * only what share bits are currently in force, but also what
917f9d7562fSJ. Bruce Fields  * combinations of share bits previous opens have used.  This allows us
918f9d7562fSJ. Bruce Fields  * to enforce the recommendation of rfc 3530 14.2.19 that the server
919f9d7562fSJ. Bruce Fields  * return an error if the client attempt to downgrade to a combination
920f9d7562fSJ. Bruce Fields  * of share bits not explicable by closing some of its previous opens.
921f9d7562fSJ. Bruce Fields  *
922f9d7562fSJ. Bruce Fields  * XXX: This enforcement is actually incomplete, since we don't keep
923f9d7562fSJ. Bruce Fields  * track of access/deny bit combinations; so, e.g., we allow:
924f9d7562fSJ. Bruce Fields  *
925f9d7562fSJ. Bruce Fields  *	OPEN allow read, deny write
926f9d7562fSJ. Bruce Fields  *	OPEN allow both, deny none
927f9d7562fSJ. Bruce Fields  *	DOWNGRADE allow read, deny none
928f9d7562fSJ. Bruce Fields  *
929f9d7562fSJ. Bruce Fields  * which we should reject.
930f9d7562fSJ. Bruce Fields  */
9315ae037e5SJeff Layton static unsigned int
9325ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) {
933f9d7562fSJ. Bruce Fields 	int i;
9345ae037e5SJeff Layton 	unsigned int access = 0;
935f9d7562fSJ. Bruce Fields 
936f9d7562fSJ. Bruce Fields 	for (i = 1; i < 4; i++) {
937f9d7562fSJ. Bruce Fields 		if (test_bit(i, &bmap))
9385ae037e5SJeff Layton 			access |= i;
939f9d7562fSJ. Bruce Fields 	}
9405ae037e5SJeff Layton 	return access;
941f9d7562fSJ. Bruce Fields }
942f9d7562fSJ. Bruce Fields 
94382c5ff1bSJeff Layton /* set share access for a given stateid */
94482c5ff1bSJeff Layton static inline void
94582c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp)
94682c5ff1bSJeff Layton {
947c11c591fSJeff Layton 	unsigned char mask = 1 << access;
948c11c591fSJeff Layton 
949c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
950c11c591fSJeff Layton 	stp->st_access_bmap |= mask;
95182c5ff1bSJeff Layton }
95282c5ff1bSJeff Layton 
95382c5ff1bSJeff Layton /* clear share access for a given stateid */
95482c5ff1bSJeff Layton static inline void
95582c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp)
95682c5ff1bSJeff Layton {
957c11c591fSJeff Layton 	unsigned char mask = 1 << access;
958c11c591fSJeff Layton 
959c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
960c11c591fSJeff Layton 	stp->st_access_bmap &= ~mask;
96182c5ff1bSJeff Layton }
96282c5ff1bSJeff Layton 
96382c5ff1bSJeff Layton /* test whether a given stateid has access */
96482c5ff1bSJeff Layton static inline bool
96582c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp)
96682c5ff1bSJeff Layton {
967c11c591fSJeff Layton 	unsigned char mask = 1 << access;
968c11c591fSJeff Layton 
969c11c591fSJeff Layton 	return (bool)(stp->st_access_bmap & mask);
97082c5ff1bSJeff Layton }
97182c5ff1bSJeff Layton 
972ce0fc43cSJeff Layton /* set share deny for a given stateid */
973ce0fc43cSJeff Layton static inline void
974c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp)
975ce0fc43cSJeff Layton {
976c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
977c11c591fSJeff Layton 
978c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
979c11c591fSJeff Layton 	stp->st_deny_bmap |= mask;
980ce0fc43cSJeff Layton }
981ce0fc43cSJeff Layton 
982ce0fc43cSJeff Layton /* clear share deny for a given stateid */
983ce0fc43cSJeff Layton static inline void
984c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp)
985ce0fc43cSJeff Layton {
986c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
987c11c591fSJeff Layton 
988c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
989c11c591fSJeff Layton 	stp->st_deny_bmap &= ~mask;
990ce0fc43cSJeff Layton }
991ce0fc43cSJeff Layton 
992ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */
993ce0fc43cSJeff Layton static inline bool
994c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp)
995ce0fc43cSJeff Layton {
996c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
997c11c591fSJeff Layton 
998c11c591fSJeff Layton 	return (bool)(stp->st_deny_bmap & mask);
999f9d7562fSJ. Bruce Fields }
1000f9d7562fSJ. Bruce Fields 
1001f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access)
1002f9d7562fSJ. Bruce Fields {
10038f34a430SJ. Bruce Fields 	switch (access & NFS4_SHARE_ACCESS_BOTH) {
1004f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
1005f9d7562fSJ. Bruce Fields 		return O_RDONLY;
1006f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
1007f9d7562fSJ. Bruce Fields 		return O_WRONLY;
1008f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
1009f9d7562fSJ. Bruce Fields 		return O_RDWR;
1010f9d7562fSJ. Bruce Fields 	}
1011063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(1);
1012063b0fb9SJ. Bruce Fields 	return O_RDONLY;
1013f9d7562fSJ. Bruce Fields }
1014f9d7562fSJ. Bruce Fields 
1015baeb4ff0SJeff Layton /*
1016baeb4ff0SJeff Layton  * A stateid that had a deny mode associated with it is being released
1017baeb4ff0SJeff Layton  * or downgraded. Recalculate the deny mode on the file.
1018baeb4ff0SJeff Layton  */
1019baeb4ff0SJeff Layton static void
1020baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp)
1021baeb4ff0SJeff Layton {
1022baeb4ff0SJeff Layton 	struct nfs4_ol_stateid *stp;
1023baeb4ff0SJeff Layton 
1024baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
1025baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
1026baeb4ff0SJeff Layton 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile)
1027baeb4ff0SJeff Layton 		fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap);
1028baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
1029baeb4ff0SJeff Layton }
1030baeb4ff0SJeff Layton 
1031baeb4ff0SJeff Layton static void
1032baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp)
1033baeb4ff0SJeff Layton {
1034baeb4ff0SJeff Layton 	int i;
1035baeb4ff0SJeff Layton 	bool change = false;
1036baeb4ff0SJeff Layton 
1037baeb4ff0SJeff Layton 	for (i = 1; i < 4; i++) {
1038baeb4ff0SJeff Layton 		if ((i & deny) != i) {
1039baeb4ff0SJeff Layton 			change = true;
1040baeb4ff0SJeff Layton 			clear_deny(i, stp);
1041baeb4ff0SJeff Layton 		}
1042baeb4ff0SJeff Layton 	}
1043baeb4ff0SJeff Layton 
1044baeb4ff0SJeff Layton 	/* Recalculate per-file deny mode if there was a change */
1045baeb4ff0SJeff Layton 	if (change)
104611b9164aSTrond Myklebust 		recalculate_deny_mode(stp->st_stid.sc_file);
1047baeb4ff0SJeff Layton }
1048baeb4ff0SJeff Layton 
104982c5ff1bSJeff Layton /* release all access and file references for a given stateid */
105082c5ff1bSJeff Layton static void
105182c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp)
105282c5ff1bSJeff Layton {
105382c5ff1bSJeff Layton 	int i;
105411b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
1055baeb4ff0SJeff Layton 
1056baeb4ff0SJeff Layton 	if (fp && stp->st_deny_bmap != 0)
1057baeb4ff0SJeff Layton 		recalculate_deny_mode(fp);
105882c5ff1bSJeff Layton 
105982c5ff1bSJeff Layton 	for (i = 1; i < 4; i++) {
106082c5ff1bSJeff Layton 		if (test_access(i, stp))
106111b9164aSTrond Myklebust 			nfs4_file_put_access(stp->st_stid.sc_file, i);
106282c5ff1bSJeff Layton 		clear_access(i, stp);
106382c5ff1bSJeff Layton 	}
106482c5ff1bSJeff Layton }
106582c5ff1bSJeff Layton 
1066d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop)
1067d50ffdedSKinglong Mee {
1068d50ffdedSKinglong Mee 	kfree(sop->so_owner.data);
1069d50ffdedSKinglong Mee 	sop->so_ops->so_free(sop);
1070d50ffdedSKinglong Mee }
1071d50ffdedSKinglong Mee 
10726b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
10736b180f0bSJeff Layton {
1074a819ecc1SJeff Layton 	struct nfs4_client *clp = sop->so_client;
1075a819ecc1SJeff Layton 
1076a819ecc1SJeff Layton 	might_lock(&clp->cl_lock);
1077a819ecc1SJeff Layton 
1078a819ecc1SJeff Layton 	if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock))
10796b180f0bSJeff Layton 		return;
10808f4b54c5SJeff Layton 	sop->so_ops->so_unhash(sop);
1081a819ecc1SJeff Layton 	spin_unlock(&clp->cl_lock);
1082d50ffdedSKinglong Mee 	nfs4_free_stateowner(sop);
10836b180f0bSJeff Layton }
10846b180f0bSJeff Layton 
1085e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp)
1086529d7b2aSJ. Bruce Fields {
108711b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
10881d31a253STrond Myklebust 
10891c755dc1SJeff Layton 	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
10901c755dc1SJeff Layton 
1091e8568739SJeff Layton 	if (list_empty(&stp->st_perfile))
1092e8568739SJeff Layton 		return false;
1093e8568739SJeff Layton 
10941d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
1095e8568739SJeff Layton 	list_del_init(&stp->st_perfile);
10961d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
1097529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perstateowner);
1098e8568739SJeff Layton 	return true;
1099529d7b2aSJ. Bruce Fields }
1100529d7b2aSJ. Bruce Fields 
11016011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
1102529d7b2aSJ. Bruce Fields {
11036011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
11044665e2baSJ. Bruce Fields 
11058287f009SSachin Bhamare 	put_clnt_odstate(stp->st_clnt_odstate);
11066011695dSTrond Myklebust 	release_all_access(stp);
1107d3134b10SJeff Layton 	if (stp->st_stateowner)
1108d3134b10SJeff Layton 		nfs4_put_stateowner(stp->st_stateowner);
11096011695dSTrond Myklebust 	kmem_cache_free(stateid_slab, stid);
1110529d7b2aSJ. Bruce Fields }
1111529d7b2aSJ. Bruce Fields 
1112b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid)
1113529d7b2aSJ. Bruce Fields {
1114b49e084dSJeff Layton 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
1115b49e084dSJeff Layton 	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
1116529d7b2aSJ. Bruce Fields 	struct file *file;
1117529d7b2aSJ. Bruce Fields 
1118b49e084dSJeff Layton 	file = find_any_file(stp->st_stid.sc_file);
1119b49e084dSJeff Layton 	if (file)
1120b49e084dSJeff Layton 		filp_close(file, (fl_owner_t)lo);
1121b49e084dSJeff Layton 	nfs4_free_ol_stateid(stid);
1122b49e084dSJeff Layton }
1123b49e084dSJeff Layton 
11242c41beb0SJeff Layton /*
11252c41beb0SJeff Layton  * Put the persistent reference to an already unhashed generic stateid, while
11262c41beb0SJeff Layton  * holding the cl_lock. If it's the last reference, then put it onto the
11272c41beb0SJeff Layton  * reaplist for later destruction.
11282c41beb0SJeff Layton  */
11292c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
11302c41beb0SJeff Layton 				       struct list_head *reaplist)
11312c41beb0SJeff Layton {
11322c41beb0SJeff Layton 	struct nfs4_stid *s = &stp->st_stid;
11332c41beb0SJeff Layton 	struct nfs4_client *clp = s->sc_client;
11342c41beb0SJeff Layton 
11352c41beb0SJeff Layton 	lockdep_assert_held(&clp->cl_lock);
11362c41beb0SJeff Layton 
11372c41beb0SJeff Layton 	WARN_ON_ONCE(!list_empty(&stp->st_locks));
11382c41beb0SJeff Layton 
11392c41beb0SJeff Layton 	if (!atomic_dec_and_test(&s->sc_count)) {
11402c41beb0SJeff Layton 		wake_up_all(&close_wq);
11412c41beb0SJeff Layton 		return;
11422c41beb0SJeff Layton 	}
11432c41beb0SJeff Layton 
11442c41beb0SJeff Layton 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
11452c41beb0SJeff Layton 	list_add(&stp->st_locks, reaplist);
11462c41beb0SJeff Layton }
11472c41beb0SJeff Layton 
1148e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
11493c1c995cSJeff Layton {
11503c1c995cSJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
11513c1c995cSJeff Layton 
11523c1c995cSJeff Layton 	lockdep_assert_held(&oo->oo_owner.so_client->cl_lock);
11533c1c995cSJeff Layton 
11543c1c995cSJeff Layton 	list_del_init(&stp->st_locks);
1155cd61c522SChristoph Hellwig 	nfs4_unhash_stid(&stp->st_stid);
1156e8568739SJeff Layton 	return unhash_ol_stateid(stp);
11573c1c995cSJeff Layton }
11583c1c995cSJeff Layton 
11595adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp)
1160b49e084dSJeff Layton {
11611c755dc1SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
1162e8568739SJeff Layton 	bool unhashed;
11631c755dc1SJeff Layton 
11641c755dc1SJeff Layton 	spin_lock(&oo->oo_owner.so_client->cl_lock);
1165e8568739SJeff Layton 	unhashed = unhash_lock_stateid(stp);
11661c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
1167e8568739SJeff Layton 	if (unhashed)
11686011695dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
1169529d7b2aSJ. Bruce Fields }
1170529d7b2aSJ. Bruce Fields 
1171c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
1172529d7b2aSJ. Bruce Fields {
1173d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
1174c58c6610STrond Myklebust 
1175d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
1176c58c6610STrond Myklebust 
11778f4b54c5SJeff Layton 	list_del_init(&lo->lo_owner.so_strhash);
11788f4b54c5SJeff Layton }
11798f4b54c5SJeff Layton 
11802c41beb0SJeff Layton /*
11812c41beb0SJeff Layton  * Free a list of generic stateids that were collected earlier after being
11822c41beb0SJeff Layton  * fully unhashed.
11832c41beb0SJeff Layton  */
11842c41beb0SJeff Layton static void
11852c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist)
11862c41beb0SJeff Layton {
11872c41beb0SJeff Layton 	struct nfs4_ol_stateid *stp;
1188fb94d766SKinglong Mee 	struct nfs4_file *fp;
11892c41beb0SJeff Layton 
11902c41beb0SJeff Layton 	might_sleep();
11912c41beb0SJeff Layton 
11922c41beb0SJeff Layton 	while (!list_empty(reaplist)) {
11932c41beb0SJeff Layton 		stp = list_first_entry(reaplist, struct nfs4_ol_stateid,
11942c41beb0SJeff Layton 				       st_locks);
11952c41beb0SJeff Layton 		list_del(&stp->st_locks);
1196fb94d766SKinglong Mee 		fp = stp->st_stid.sc_file;
11972c41beb0SJeff Layton 		stp->st_stid.sc_free(&stp->st_stid);
1198fb94d766SKinglong Mee 		if (fp)
1199fb94d766SKinglong Mee 			put_nfs4_file(fp);
12002c41beb0SJeff Layton 	}
12012c41beb0SJeff Layton }
12022c41beb0SJeff Layton 
1203fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo)
1204529d7b2aSJ. Bruce Fields {
1205d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
12063c1c995cSJeff Layton 	struct nfs4_ol_stateid *stp;
12073c1c995cSJeff Layton 	struct list_head reaplist;
12083c1c995cSJeff Layton 
12093c1c995cSJeff Layton 	INIT_LIST_HEAD(&reaplist);
1210c58c6610STrond Myklebust 
1211d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
1212c58c6610STrond Myklebust 	unhash_lockowner_locked(lo);
12133c1c995cSJeff Layton 	while (!list_empty(&lo->lo_owner.so_stateids)) {
12143c1c995cSJeff Layton 		stp = list_first_entry(&lo->lo_owner.so_stateids,
12153c1c995cSJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
1216e8568739SJeff Layton 		WARN_ON(!unhash_lock_stateid(stp));
12172c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
12183c1c995cSJeff Layton 	}
1219d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
12202c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
12216b180f0bSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
1222529d7b2aSJ. Bruce Fields }
1223529d7b2aSJ. Bruce Fields 
1224d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
1225d83017f9SJeff Layton 				       struct list_head *reaplist)
12263c87b9b7STrond Myklebust {
12273c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *stp;
12283c87b9b7STrond Myklebust 
1229e8568739SJeff Layton 	lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock);
1230e8568739SJeff Layton 
12313c87b9b7STrond Myklebust 	while (!list_empty(&open_stp->st_locks)) {
12323c87b9b7STrond Myklebust 		stp = list_entry(open_stp->st_locks.next,
12333c87b9b7STrond Myklebust 				struct nfs4_ol_stateid, st_locks);
1234e8568739SJeff Layton 		WARN_ON(!unhash_lock_stateid(stp));
1235d83017f9SJeff Layton 		put_ol_stateid_locked(stp, reaplist);
1236529d7b2aSJ. Bruce Fields 	}
1237529d7b2aSJ. Bruce Fields }
1238529d7b2aSJ. Bruce Fields 
1239e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp,
1240d83017f9SJeff Layton 				struct list_head *reaplist)
12412283963fSJ. Bruce Fields {
1242e8568739SJeff Layton 	bool unhashed;
1243e8568739SJeff Layton 
12442c41beb0SJeff Layton 	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
12452c41beb0SJeff Layton 
1246e8568739SJeff Layton 	unhashed = unhash_ol_stateid(stp);
1247d83017f9SJeff Layton 	release_open_stateid_locks(stp, reaplist);
1248e8568739SJeff Layton 	return unhashed;
124938c387b5SJ. Bruce Fields }
125038c387b5SJ. Bruce Fields 
125138c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp)
125238c387b5SJ. Bruce Fields {
12532c41beb0SJeff Layton 	LIST_HEAD(reaplist);
12542c41beb0SJeff Layton 
12552c41beb0SJeff Layton 	spin_lock(&stp->st_stid.sc_client->cl_lock);
1256e8568739SJeff Layton 	if (unhash_open_stateid(stp, &reaplist))
12572c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
12582c41beb0SJeff Layton 	spin_unlock(&stp->st_stid.sc_client->cl_lock);
12592c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
12602283963fSJ. Bruce Fields }
12612283963fSJ. Bruce Fields 
12627ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo)
1263f1d110caSJ. Bruce Fields {
1264d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
12657ffb5880STrond Myklebust 
1266d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
12677ffb5880STrond Myklebust 
12688f4b54c5SJeff Layton 	list_del_init(&oo->oo_owner.so_strhash);
12698f4b54c5SJeff Layton 	list_del_init(&oo->oo_perclient);
1270f1d110caSJ. Bruce Fields }
1271f1d110caSJ. Bruce Fields 
1272f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo)
1273f7a4d872SJ. Bruce Fields {
1274217526e7SJeff Layton 	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1275217526e7SJeff Layton 					  nfsd_net_id);
1276217526e7SJeff Layton 	struct nfs4_ol_stateid *s;
1277f7a4d872SJ. Bruce Fields 
1278217526e7SJeff Layton 	spin_lock(&nn->client_lock);
1279217526e7SJeff Layton 	s = oo->oo_last_closed_stid;
1280f7a4d872SJ. Bruce Fields 	if (s) {
1281d3134b10SJeff Layton 		list_del_init(&oo->oo_close_lru);
1282f7a4d872SJ. Bruce Fields 		oo->oo_last_closed_stid = NULL;
1283f7a4d872SJ. Bruce Fields 	}
1284217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
1285217526e7SJeff Layton 	if (s)
1286217526e7SJeff Layton 		nfs4_put_stid(&s->st_stid);
1287f7a4d872SJ. Bruce Fields }
1288f7a4d872SJ. Bruce Fields 
12892c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo)
12908f4b54c5SJeff Layton {
12918f4b54c5SJeff Layton 	struct nfs4_ol_stateid *stp;
1292d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
12932c41beb0SJeff Layton 	struct list_head reaplist;
12947ffb5880STrond Myklebust 
12952c41beb0SJeff Layton 	INIT_LIST_HEAD(&reaplist);
12967ffb5880STrond Myklebust 
1297d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
12987ffb5880STrond Myklebust 	unhash_openowner_locked(oo);
12992c41beb0SJeff Layton 	while (!list_empty(&oo->oo_owner.so_stateids)) {
13002c41beb0SJeff Layton 		stp = list_first_entry(&oo->oo_owner.so_stateids,
13012c41beb0SJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
1302e8568739SJeff Layton 		if (unhash_open_stateid(stp, &reaplist))
13032c41beb0SJeff Layton 			put_ol_stateid_locked(stp, &reaplist);
13042c41beb0SJeff Layton 	}
1305d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
13062c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
1307f7a4d872SJ. Bruce Fields 	release_last_closed_stateid(oo);
13086b180f0bSJeff Layton 	nfs4_put_stateowner(&oo->oo_owner);
1309f1d110caSJ. Bruce Fields }
1310f1d110caSJ. Bruce Fields 
13115282fd72SMarc Eshel static inline int
13125282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid)
13135282fd72SMarc Eshel {
13145282fd72SMarc Eshel 	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
13155282fd72SMarc Eshel 
13165282fd72SMarc Eshel 	return sid->sequence % SESSION_HASH_SIZE;
13175282fd72SMarc Eshel }
13185282fd72SMarc Eshel 
1319135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG
13205282fd72SMarc Eshel static inline void
13215282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
13225282fd72SMarc Eshel {
13235282fd72SMarc Eshel 	u32 *ptr = (u32 *)(&sessionid->data[0]);
13245282fd72SMarc Eshel 	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
13255282fd72SMarc Eshel }
13268f199b82STrond Myklebust #else
13278f199b82STrond Myklebust static inline void
13288f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
13298f199b82STrond Myklebust {
13308f199b82STrond Myklebust }
13318f199b82STrond Myklebust #endif
13328f199b82STrond Myklebust 
13339411b1d4SJ. Bruce Fields /*
13349411b1d4SJ. Bruce Fields  * Bump the seqid on cstate->replay_owner, and clear replay_owner if it
13359411b1d4SJ. Bruce Fields  * won't be used for replay.
13369411b1d4SJ. Bruce Fields  */
13379411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
13389411b1d4SJ. Bruce Fields {
13399411b1d4SJ. Bruce Fields 	struct nfs4_stateowner *so = cstate->replay_owner;
13409411b1d4SJ. Bruce Fields 
13419411b1d4SJ. Bruce Fields 	if (nfserr == nfserr_replay_me)
13429411b1d4SJ. Bruce Fields 		return;
13439411b1d4SJ. Bruce Fields 
13449411b1d4SJ. Bruce Fields 	if (!seqid_mutating_err(ntohl(nfserr))) {
134558fb12e6SJeff Layton 		nfsd4_cstate_clear_replay(cstate);
13469411b1d4SJ. Bruce Fields 		return;
13479411b1d4SJ. Bruce Fields 	}
13489411b1d4SJ. Bruce Fields 	if (!so)
13499411b1d4SJ. Bruce Fields 		return;
13509411b1d4SJ. Bruce Fields 	if (so->so_is_open_owner)
13519411b1d4SJ. Bruce Fields 		release_last_closed_stateid(openowner(so));
13529411b1d4SJ. Bruce Fields 	so->so_seqid++;
13539411b1d4SJ. Bruce Fields 	return;
13549411b1d4SJ. Bruce Fields }
13555282fd72SMarc Eshel 
1356ec6b5d7bSAndy Adamson static void
1357ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses)
1358ec6b5d7bSAndy Adamson {
1359ec6b5d7bSAndy Adamson 	struct nfs4_client *clp = ses->se_client;
1360ec6b5d7bSAndy Adamson 	struct nfsd4_sessionid *sid;
1361ec6b5d7bSAndy Adamson 
1362ec6b5d7bSAndy Adamson 	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
1363ec6b5d7bSAndy Adamson 	sid->clientid = clp->cl_clientid;
1364ec6b5d7bSAndy Adamson 	sid->sequence = current_sessionid++;
1365ec6b5d7bSAndy Adamson 	sid->reserved = 0;
1366ec6b5d7bSAndy Adamson }
1367ec6b5d7bSAndy Adamson 
1368ec6b5d7bSAndy Adamson /*
1369a649637cSAndy Adamson  * The protocol defines ca_maxresponssize_cached to include the size of
1370a649637cSAndy Adamson  * the rpc header, but all we need to cache is the data starting after
1371a649637cSAndy Adamson  * the end of the initial SEQUENCE operation--the rest we regenerate
1372a649637cSAndy Adamson  * each time.  Therefore we can advertise a ca_maxresponssize_cached
1373a649637cSAndy Adamson  * value that is the number of bytes in our cache plus a few additional
1374a649637cSAndy Adamson  * bytes.  In order to stay on the safe side, and not promise more than
1375a649637cSAndy Adamson  * we can cache, those additional bytes must be the minimum possible: 24
1376a649637cSAndy Adamson  * bytes of rpc header (xid through accept state, with AUTH_NULL
1377a649637cSAndy Adamson  * verifier), 12 for the compound header (with zero-length tag), and 44
1378a649637cSAndy Adamson  * for the SEQUENCE op response:
1379ec6b5d7bSAndy Adamson  */
1380a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
1381a649637cSAndy Adamson 
1382557ce264SAndy Adamson static void
1383557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses)
1384557ce264SAndy Adamson {
1385557ce264SAndy Adamson 	int i;
1386557ce264SAndy Adamson 
1387557ce264SAndy Adamson 	for (i = 0; i < ses->se_fchannel.maxreqs; i++)
1388557ce264SAndy Adamson 		kfree(ses->se_slots[i]);
1389557ce264SAndy Adamson }
1390557ce264SAndy Adamson 
1391efe0cb6dSJ. Bruce Fields /*
1392efe0cb6dSJ. Bruce Fields  * We don't actually need to cache the rpc and session headers, so we
1393efe0cb6dSJ. Bruce Fields  * can allocate a little less for each slot:
1394efe0cb6dSJ. Bruce Fields  */
139555c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca)
1396efe0cb6dSJ. Bruce Fields {
139755c760cfSJ. Bruce Fields 	u32 size;
1398efe0cb6dSJ. Bruce Fields 
139955c760cfSJ. Bruce Fields 	if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ)
140055c760cfSJ. Bruce Fields 		size = 0;
140155c760cfSJ. Bruce Fields 	else
140255c760cfSJ. Bruce Fields 		size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
140355c760cfSJ. Bruce Fields 	return size + sizeof(struct nfsd4_slot);
1404557ce264SAndy Adamson }
1405557ce264SAndy Adamson 
14065b6feee9SJ. Bruce Fields /*
14075b6feee9SJ. Bruce Fields  * XXX: If we run out of reserved DRC memory we could (up to a point)
14085b6feee9SJ. Bruce Fields  * re-negotiate active sessions and reduce their slot usage to make
140942b2aa86SJustin P. Mattock  * room for new connections. For now we just fail the create session.
14105b6feee9SJ. Bruce Fields  */
141155c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
14125b6feee9SJ. Bruce Fields {
141355c760cfSJ. Bruce Fields 	u32 slotsize = slot_bytes(ca);
141455c760cfSJ. Bruce Fields 	u32 num = ca->maxreqs;
14155b6feee9SJ. Bruce Fields 	int avail;
14165b6feee9SJ. Bruce Fields 
14175b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
1418697ce9beSZhang Yanfei 	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
14195b6feee9SJ. Bruce Fields 		    nfsd_drc_max_mem - nfsd_drc_mem_used);
14205b6feee9SJ. Bruce Fields 	num = min_t(int, num, avail / slotsize);
14215b6feee9SJ. Bruce Fields 	nfsd_drc_mem_used += num * slotsize;
14225b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
14235b6feee9SJ. Bruce Fields 
14245b6feee9SJ. Bruce Fields 	return num;
14255b6feee9SJ. Bruce Fields }
14265b6feee9SJ. Bruce Fields 
142755c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
14285b6feee9SJ. Bruce Fields {
142955c760cfSJ. Bruce Fields 	int slotsize = slot_bytes(ca);
143055c760cfSJ. Bruce Fields 
14315b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
143255c760cfSJ. Bruce Fields 	nfsd_drc_mem_used -= slotsize * ca->maxreqs;
14335b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
14345b6feee9SJ. Bruce Fields }
14355b6feee9SJ. Bruce Fields 
143660810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
143760810e54SKinglong Mee 					   struct nfsd4_channel_attrs *battrs)
14385b6feee9SJ. Bruce Fields {
143960810e54SKinglong Mee 	int numslots = fattrs->maxreqs;
144060810e54SKinglong Mee 	int slotsize = slot_bytes(fattrs);
14415b6feee9SJ. Bruce Fields 	struct nfsd4_session *new;
14425b6feee9SJ. Bruce Fields 	int mem, i;
1443ec6b5d7bSAndy Adamson 
1444c23753daSJ. Bruce Fields 	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
1445ec6b5d7bSAndy Adamson 			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
14465b6feee9SJ. Bruce Fields 	mem = numslots * sizeof(struct nfsd4_slot *);
1447ec6b5d7bSAndy Adamson 
14485b6feee9SJ. Bruce Fields 	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
14496c18ba9fSAlexandros Batsakis 	if (!new)
14505b6feee9SJ. Bruce Fields 		return NULL;
1451ec6b5d7bSAndy Adamson 	/* allocate each struct nfsd4_slot and data cache in one piece */
14525b6feee9SJ. Bruce Fields 	for (i = 0; i < numslots; i++) {
145355c760cfSJ. Bruce Fields 		new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL);
14545b6feee9SJ. Bruce Fields 		if (!new->se_slots[i])
1455ec6b5d7bSAndy Adamson 			goto out_free;
1456ec6b5d7bSAndy Adamson 	}
145760810e54SKinglong Mee 
145860810e54SKinglong Mee 	memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
145960810e54SKinglong Mee 	memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
146060810e54SKinglong Mee 
14615b6feee9SJ. Bruce Fields 	return new;
14625b6feee9SJ. Bruce Fields out_free:
14635b6feee9SJ. Bruce Fields 	while (i--)
14645b6feee9SJ. Bruce Fields 		kfree(new->se_slots[i]);
14655b6feee9SJ. Bruce Fields 	kfree(new);
14665b6feee9SJ. Bruce Fields 	return NULL;
14675b6feee9SJ. Bruce Fields }
14685b6feee9SJ. Bruce Fields 
146919cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c)
147019cf5c02SJ. Bruce Fields {
147119cf5c02SJ. Bruce Fields 	svc_xprt_put(c->cn_xprt);
147219cf5c02SJ. Bruce Fields 	kfree(c);
147319cf5c02SJ. Bruce Fields }
147419cf5c02SJ. Bruce Fields 
147519cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u)
147619cf5c02SJ. Bruce Fields {
147719cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
147819cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = c->cn_session->se_client;
147919cf5c02SJ. Bruce Fields 
148019cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
148119cf5c02SJ. Bruce Fields 	if (!list_empty(&c->cn_persession)) {
148219cf5c02SJ. Bruce Fields 		list_del(&c->cn_persession);
148319cf5c02SJ. Bruce Fields 		free_conn(c);
148419cf5c02SJ. Bruce Fields 	}
1485eea49806SJ. Bruce Fields 	nfsd4_probe_callback(clp);
14862e4b7239SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
148719cf5c02SJ. Bruce Fields }
148819cf5c02SJ. Bruce Fields 
1489d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
1490c7662518SJ. Bruce Fields {
1491c7662518SJ. Bruce Fields 	struct nfsd4_conn *conn;
1492c7662518SJ. Bruce Fields 
1493c7662518SJ. Bruce Fields 	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
1494c7662518SJ. Bruce Fields 	if (!conn)
1495db90681dSJ. Bruce Fields 		return NULL;
1496c7662518SJ. Bruce Fields 	svc_xprt_get(rqstp->rq_xprt);
1497c7662518SJ. Bruce Fields 	conn->cn_xprt = rqstp->rq_xprt;
1498d29c374cSJ. Bruce Fields 	conn->cn_flags = flags;
1499db90681dSJ. Bruce Fields 	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
1500db90681dSJ. Bruce Fields 	return conn;
1501db90681dSJ. Bruce Fields }
1502db90681dSJ. Bruce Fields 
1503328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1504328ead28SJ. Bruce Fields {
1505328ead28SJ. Bruce Fields 	conn->cn_session = ses;
1506328ead28SJ. Bruce Fields 	list_add(&conn->cn_persession, &ses->se_conns);
1507328ead28SJ. Bruce Fields }
1508328ead28SJ. Bruce Fields 
1509db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1510db90681dSJ. Bruce Fields {
1511db90681dSJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
1512c7662518SJ. Bruce Fields 
1513c7662518SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1514328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(conn, ses);
1515c7662518SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1516db90681dSJ. Bruce Fields }
1517c7662518SJ. Bruce Fields 
151821b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn)
1519db90681dSJ. Bruce Fields {
152019cf5c02SJ. Bruce Fields 	conn->cn_xpt_user.callback = nfsd4_conn_lost;
152121b75b01SJ. Bruce Fields 	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
1522db90681dSJ. Bruce Fields }
1523db90681dSJ. Bruce Fields 
1524e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
1525db90681dSJ. Bruce Fields {
152621b75b01SJ. Bruce Fields 	int ret;
1527db90681dSJ. Bruce Fields 
1528db90681dSJ. Bruce Fields 	nfsd4_hash_conn(conn, ses);
152921b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(conn);
153021b75b01SJ. Bruce Fields 	if (ret)
153121b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
153221b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&conn->cn_xpt_user);
153357a37144SJ. Bruce Fields 	/* We may have gained or lost a callback channel: */
153457a37144SJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
1535c7662518SJ. Bruce Fields }
1536c7662518SJ. Bruce Fields 
1537e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
15381d1bc8f2SJ. Bruce Fields {
15391d1bc8f2SJ. Bruce Fields 	u32 dir = NFS4_CDFC4_FORE;
15401d1bc8f2SJ. Bruce Fields 
1541e1ff371fSJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN)
15421d1bc8f2SJ. Bruce Fields 		dir |= NFS4_CDFC4_BACK;
1543e1ff371fSJ. Bruce Fields 	return alloc_conn(rqstp, dir);
15441d1bc8f2SJ. Bruce Fields }
15451d1bc8f2SJ. Bruce Fields 
15461d1bc8f2SJ. Bruce Fields /* must be called under client_lock */
154719cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s)
1548c7662518SJ. Bruce Fields {
154919cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = s->se_client;
155019cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c;
155119cf5c02SJ. Bruce Fields 
155219cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
155319cf5c02SJ. Bruce Fields 	while (!list_empty(&s->se_conns)) {
155419cf5c02SJ. Bruce Fields 		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
155519cf5c02SJ. Bruce Fields 		list_del_init(&c->cn_persession);
155619cf5c02SJ. Bruce Fields 		spin_unlock(&clp->cl_lock);
155719cf5c02SJ. Bruce Fields 
155819cf5c02SJ. Bruce Fields 		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
155919cf5c02SJ. Bruce Fields 		free_conn(c);
156019cf5c02SJ. Bruce Fields 
156119cf5c02SJ. Bruce Fields 		spin_lock(&clp->cl_lock);
156219cf5c02SJ. Bruce Fields 	}
156319cf5c02SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1564c7662518SJ. Bruce Fields }
1565c7662518SJ. Bruce Fields 
15661377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses)
15671377b69eSJ. Bruce Fields {
15681377b69eSJ. Bruce Fields 	free_session_slots(ses);
15691377b69eSJ. Bruce Fields 	kfree(ses);
15701377b69eSJ. Bruce Fields }
15711377b69eSJ. Bruce Fields 
157266b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses)
1573508dc6e1SBenny Halevy {
1574c7662518SJ. Bruce Fields 	nfsd4_del_conns(ses);
157555c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&ses->se_fchannel);
1576c7662518SJ. Bruce Fields 	__free_session(ses);
1577a827bcb2SJ. Bruce Fields }
1578ec6b5d7bSAndy Adamson 
1579135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
1580a827bcb2SJ. Bruce Fields {
1581a827bcb2SJ. Bruce Fields 	int idx;
15821872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1583a827bcb2SJ. Bruce Fields 
1584ec6b5d7bSAndy Adamson 	new->se_client = clp;
1585ec6b5d7bSAndy Adamson 	gen_sessionid(new);
1586ec6b5d7bSAndy Adamson 
1587c7662518SJ. Bruce Fields 	INIT_LIST_HEAD(&new->se_conns);
1588c7662518SJ. Bruce Fields 
1589ac7c46f2SJ. Bruce Fields 	new->se_cb_seq_nr = 1;
1590ec6b5d7bSAndy Adamson 	new->se_flags = cses->flags;
15918b5ce5cdSJ. Bruce Fields 	new->se_cb_prog = cses->callback_prog;
1592c6bb3ca2SJ. Bruce Fields 	new->se_cb_sec = cses->cb_sec;
159366b2b9b2SJ. Bruce Fields 	atomic_set(&new->se_ref, 0);
15945b6feee9SJ. Bruce Fields 	idx = hash_sessionid(&new->se_sessionid);
15951872de0eSStanislav Kinsbursky 	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
15964c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1597ec6b5d7bSAndy Adamson 	list_add(&new->se_perclnt, &clp->cl_sessions);
15984c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
159960810e54SKinglong Mee 
1600b0d2e42cSChuck Lever 	{
1601edd76786SJ. Bruce Fields 		struct sockaddr *sa = svc_addr(rqstp);
1602dcbeaa68SJ. Bruce Fields 		/*
1603dcbeaa68SJ. Bruce Fields 		 * This is a little silly; with sessions there's no real
1604dcbeaa68SJ. Bruce Fields 		 * use for the callback address.  Use the peer address
1605dcbeaa68SJ. Bruce Fields 		 * as a reasonable default for now, but consider fixing
1606dcbeaa68SJ. Bruce Fields 		 * the rpc client not to require an address in the
1607dcbeaa68SJ. Bruce Fields 		 * future:
1608dcbeaa68SJ. Bruce Fields 		 */
1609edd76786SJ. Bruce Fields 		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
1610edd76786SJ. Bruce Fields 		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
1611edd76786SJ. Bruce Fields 	}
1612ec6b5d7bSAndy Adamson }
1613ec6b5d7bSAndy Adamson 
16149089f1b4SBenny Halevy /* caller must hold client_lock */
16155282fd72SMarc Eshel static struct nfsd4_session *
1616d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
16175282fd72SMarc Eshel {
16185282fd72SMarc Eshel 	struct nfsd4_session *elem;
16195282fd72SMarc Eshel 	int idx;
16201872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
16215282fd72SMarc Eshel 
16220a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
16230a880a28STrond Myklebust 
16245282fd72SMarc Eshel 	dump_sessionid(__func__, sessionid);
16255282fd72SMarc Eshel 	idx = hash_sessionid(sessionid);
16265282fd72SMarc Eshel 	/* Search in the appropriate list */
16271872de0eSStanislav Kinsbursky 	list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) {
16285282fd72SMarc Eshel 		if (!memcmp(elem->se_sessionid.data, sessionid->data,
16295282fd72SMarc Eshel 			    NFS4_MAX_SESSIONID_LEN)) {
16305282fd72SMarc Eshel 			return elem;
16315282fd72SMarc Eshel 		}
16325282fd72SMarc Eshel 	}
16335282fd72SMarc Eshel 
16345282fd72SMarc Eshel 	dprintk("%s: session not found\n", __func__);
16355282fd72SMarc Eshel 	return NULL;
16365282fd72SMarc Eshel }
16375282fd72SMarc Eshel 
1638d4e19e70STrond Myklebust static struct nfsd4_session *
1639d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net,
1640d4e19e70STrond Myklebust 		__be32 *ret)
1641d4e19e70STrond Myklebust {
1642d4e19e70STrond Myklebust 	struct nfsd4_session *session;
1643d4e19e70STrond Myklebust 	__be32 status = nfserr_badsession;
1644d4e19e70STrond Myklebust 
1645d4e19e70STrond Myklebust 	session = __find_in_sessionid_hashtbl(sessionid, net);
1646d4e19e70STrond Myklebust 	if (!session)
1647d4e19e70STrond Myklebust 		goto out;
1648d4e19e70STrond Myklebust 	status = nfsd4_get_session_locked(session);
1649d4e19e70STrond Myklebust 	if (status)
1650d4e19e70STrond Myklebust 		session = NULL;
1651d4e19e70STrond Myklebust out:
1652d4e19e70STrond Myklebust 	*ret = status;
1653d4e19e70STrond Myklebust 	return session;
1654d4e19e70STrond Myklebust }
1655d4e19e70STrond Myklebust 
16569089f1b4SBenny Halevy /* caller must hold client_lock */
16577116ed6bSAndy Adamson static void
16585282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses)
16597116ed6bSAndy Adamson {
16600a880a28STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
16610a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
16620a880a28STrond Myklebust 
16630a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
16640a880a28STrond Myklebust 
16657116ed6bSAndy Adamson 	list_del(&ses->se_hash);
16664c649378SJ. Bruce Fields 	spin_lock(&ses->se_client->cl_lock);
16677116ed6bSAndy Adamson 	list_del(&ses->se_perclnt);
16684c649378SJ. Bruce Fields 	spin_unlock(&ses->se_client->cl_lock);
16695282fd72SMarc Eshel }
16705282fd72SMarc Eshel 
16711da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
16721da177e4SLinus Torvalds static int
16732c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
16741da177e4SLinus Torvalds {
1675bbc7f33aSJ. Bruce Fields 	/*
1676bbc7f33aSJ. Bruce Fields 	 * We're assuming the clid was not given out from a boot
1677bbc7f33aSJ. Bruce Fields 	 * precisely 2^32 (about 136 years) before this one.  That seems
1678bbc7f33aSJ. Bruce Fields 	 * a safe assumption:
1679bbc7f33aSJ. Bruce Fields 	 */
1680bbc7f33aSJ. Bruce Fields 	if (clid->cl_boot == (u32)nn->boot_time)
16811da177e4SLinus Torvalds 		return 0;
168260adfc50SAndy Adamson 	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
16832c142baaSStanislav Kinsbursky 		clid->cl_boot, clid->cl_id, nn->boot_time);
16841da177e4SLinus Torvalds 	return 1;
16851da177e4SLinus Torvalds }
16861da177e4SLinus Torvalds 
16871da177e4SLinus Torvalds /*
16881da177e4SLinus Torvalds  * XXX Should we use a slab cache ?
16891da177e4SLinus Torvalds  * This type of memory management is somewhat inefficient, but we use it
16901da177e4SLinus Torvalds  * anyway since SETCLIENTID is not a common operation.
16911da177e4SLinus Torvalds  */
169235bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name)
16931da177e4SLinus Torvalds {
16941da177e4SLinus Torvalds 	struct nfs4_client *clp;
1695d4f0489fSTrond Myklebust 	int i;
16961da177e4SLinus Torvalds 
169735bba9a3SJ. Bruce Fields 	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
169835bba9a3SJ. Bruce Fields 	if (clp == NULL)
169935bba9a3SJ. Bruce Fields 		return NULL;
170067114fe6SThomas Meyer 	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
1701d4f0489fSTrond Myklebust 	if (clp->cl_name.data == NULL)
1702d4f0489fSTrond Myklebust 		goto err_no_name;
1703d4f0489fSTrond Myklebust 	clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
1704d4f0489fSTrond Myklebust 			OWNER_HASH_SIZE, GFP_KERNEL);
1705d4f0489fSTrond Myklebust 	if (!clp->cl_ownerstr_hashtbl)
1706d4f0489fSTrond Myklebust 		goto err_no_hashtbl;
1707d4f0489fSTrond Myklebust 	for (i = 0; i < OWNER_HASH_SIZE; i++)
1708d4f0489fSTrond Myklebust 		INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]);
17091da177e4SLinus Torvalds 	clp->cl_name.len = name.len;
17105694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_sessions);
17115694c93eSTrond Myklebust 	idr_init(&clp->cl_stateids);
17125694c93eSTrond Myklebust 	atomic_set(&clp->cl_refcount, 0);
17135694c93eSTrond Myklebust 	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
17145694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_idhash);
17155694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_openowners);
17165694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_delegations);
17175694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_lru);
17185694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_revoked);
17199cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
17209cf514ccSChristoph Hellwig 	INIT_LIST_HEAD(&clp->cl_lo_states);
17219cf514ccSChristoph Hellwig #endif
17225694c93eSTrond Myklebust 	spin_lock_init(&clp->cl_lock);
17235694c93eSTrond Myklebust 	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
17241da177e4SLinus Torvalds 	return clp;
1725d4f0489fSTrond Myklebust err_no_hashtbl:
1726d4f0489fSTrond Myklebust 	kfree(clp->cl_name.data);
1727d4f0489fSTrond Myklebust err_no_name:
1728d4f0489fSTrond Myklebust 	kfree(clp);
1729d4f0489fSTrond Myklebust 	return NULL;
17301da177e4SLinus Torvalds }
17311da177e4SLinus Torvalds 
17324dd86e15STrond Myklebust static void
17331da177e4SLinus Torvalds free_client(struct nfs4_client *clp)
17341da177e4SLinus Torvalds {
1735792c95ddSJ. Bruce Fields 	while (!list_empty(&clp->cl_sessions)) {
1736792c95ddSJ. Bruce Fields 		struct nfsd4_session *ses;
1737792c95ddSJ. Bruce Fields 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
1738792c95ddSJ. Bruce Fields 				se_perclnt);
1739792c95ddSJ. Bruce Fields 		list_del(&ses->se_perclnt);
174066b2b9b2SJ. Bruce Fields 		WARN_ON_ONCE(atomic_read(&ses->se_ref));
174166b2b9b2SJ. Bruce Fields 		free_session(ses);
1742792c95ddSJ. Bruce Fields 	}
17434cb57e30STrond Myklebust 	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
174403a4e1f6SJ. Bruce Fields 	free_svc_cred(&clp->cl_cred);
1745d4f0489fSTrond Myklebust 	kfree(clp->cl_ownerstr_hashtbl);
17461da177e4SLinus Torvalds 	kfree(clp->cl_name.data);
17472d32b29aSmajianpeng 	idr_destroy(&clp->cl_stateids);
17481da177e4SLinus Torvalds 	kfree(clp);
17491da177e4SLinus Torvalds }
17501da177e4SLinus Torvalds 
175184d38ac9SBenny Halevy /* must be called under the client_lock */
17524beb345bSTrond Myklebust static void
175384d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp)
175484d38ac9SBenny Halevy {
17554beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1756792c95ddSJ. Bruce Fields 	struct nfsd4_session *ses;
1757792c95ddSJ. Bruce Fields 
17580a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
17590a880a28STrond Myklebust 
17604beb345bSTrond Myklebust 	/* Mark the client as expired! */
17614beb345bSTrond Myklebust 	clp->cl_time = 0;
17624beb345bSTrond Myklebust 	/* Make it invisible */
17634beb345bSTrond Myklebust 	if (!list_empty(&clp->cl_idhash)) {
17644beb345bSTrond Myklebust 		list_del_init(&clp->cl_idhash);
17654beb345bSTrond Myklebust 		if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
17664beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
17674beb345bSTrond Myklebust 		else
17684beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
17694beb345bSTrond Myklebust 	}
17704beb345bSTrond Myklebust 	list_del_init(&clp->cl_lru);
17714c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1772792c95ddSJ. Bruce Fields 	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
1773792c95ddSJ. Bruce Fields 		list_del_init(&ses->se_hash);
17744c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
177584d38ac9SBenny Halevy }
177684d38ac9SBenny Halevy 
17771da177e4SLinus Torvalds static void
17784beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp)
17794beb345bSTrond Myklebust {
17804beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
17814beb345bSTrond Myklebust 
17824beb345bSTrond Myklebust 	spin_lock(&nn->client_lock);
17834beb345bSTrond Myklebust 	unhash_client_locked(clp);
17844beb345bSTrond Myklebust 	spin_unlock(&nn->client_lock);
17854beb345bSTrond Myklebust }
17864beb345bSTrond Myklebust 
178797403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp)
178897403d95SJeff Layton {
178997403d95SJeff Layton 	if (atomic_read(&clp->cl_refcount))
179097403d95SJeff Layton 		return nfserr_jukebox;
179197403d95SJeff Layton 	unhash_client_locked(clp);
179297403d95SJeff Layton 	return nfs_ok;
179397403d95SJeff Layton }
179497403d95SJeff Layton 
17954beb345bSTrond Myklebust static void
17964beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp)
17971da177e4SLinus Torvalds {
1798fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
17991da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
18001da177e4SLinus Torvalds 	struct list_head reaplist;
18011da177e4SLinus Torvalds 
18021da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
1803cdc97505SBenny Halevy 	spin_lock(&state_lock);
1804ea1da636SNeilBrown 	while (!list_empty(&clp->cl_delegations)) {
1805ea1da636SNeilBrown 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
18063fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
180742690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
18081da177e4SLinus Torvalds 	}
1809cdc97505SBenny Halevy 	spin_unlock(&state_lock);
18101da177e4SLinus Torvalds 	while (!list_empty(&reaplist)) {
18111da177e4SLinus Torvalds 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
181242690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
18138287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
1814afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
18156011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
18161da177e4SLinus Torvalds 	}
18172d4a532dSJeff Layton 	while (!list_empty(&clp->cl_revoked)) {
1818c876486bSAndrew Elble 		dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru);
18192d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
18206011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
1821956c4feeSBenny Halevy 	}
1822ea1da636SNeilBrown 	while (!list_empty(&clp->cl_openowners)) {
1823fe0750e5SJ. Bruce Fields 		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
1824b5971afaSKinglong Mee 		nfs4_get_stateowner(&oo->oo_owner);
1825fe0750e5SJ. Bruce Fields 		release_openowner(oo);
18261da177e4SLinus Torvalds 	}
18279cf514ccSChristoph Hellwig 	nfsd4_return_all_client_layouts(clp);
18286ff8da08SJ. Bruce Fields 	nfsd4_shutdown_callback(clp);
18292bf23875SJ. Bruce Fields 	if (clp->cl_cb_conn.cb_xprt)
18302bf23875SJ. Bruce Fields 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1831b12a05cbSJ. Bruce Fields 	free_client(clp);
18321da177e4SLinus Torvalds }
18331da177e4SLinus Torvalds 
18344beb345bSTrond Myklebust static void
18354beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp)
18364beb345bSTrond Myklebust {
18374beb345bSTrond Myklebust 	unhash_client(clp);
18384beb345bSTrond Myklebust 	__destroy_client(clp);
18394beb345bSTrond Myklebust }
18404beb345bSTrond Myklebust 
18410d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp)
18420d22f68fSJ. Bruce Fields {
18434beb345bSTrond Myklebust 	unhash_client(clp);
18440d22f68fSJ. Bruce Fields 	nfsd4_client_record_remove(clp);
18454beb345bSTrond Myklebust 	__destroy_client(clp);
18460d22f68fSJ. Bruce Fields }
18470d22f68fSJ. Bruce Fields 
184835bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
184935bba9a3SJ. Bruce Fields {
185035bba9a3SJ. Bruce Fields 	memcpy(target->cl_verifier.data, source->data,
185135bba9a3SJ. Bruce Fields 			sizeof(target->cl_verifier.data));
18521da177e4SLinus Torvalds }
18531da177e4SLinus Torvalds 
185435bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
185535bba9a3SJ. Bruce Fields {
18561da177e4SLinus Torvalds 	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
18571da177e4SLinus Torvalds 	target->cl_clientid.cl_id = source->cl_clientid.cl_id;
18581da177e4SLinus Torvalds }
18591da177e4SLinus Torvalds 
186050043859SJ. Bruce Fields int strdup_if_nonnull(char **target, char *source)
186135bba9a3SJ. Bruce Fields {
186250043859SJ. Bruce Fields 	if (source) {
186350043859SJ. Bruce Fields 		*target = kstrdup(source, GFP_KERNEL);
186450043859SJ. Bruce Fields 		if (!*target)
186503a4e1f6SJ. Bruce Fields 			return -ENOMEM;
186603a4e1f6SJ. Bruce Fields 	} else
186750043859SJ. Bruce Fields 		*target = NULL;
186850043859SJ. Bruce Fields 	return 0;
186950043859SJ. Bruce Fields }
187050043859SJ. Bruce Fields 
187150043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source)
187250043859SJ. Bruce Fields {
187350043859SJ. Bruce Fields 	int ret;
187450043859SJ. Bruce Fields 
187550043859SJ. Bruce Fields 	ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal);
187650043859SJ. Bruce Fields 	if (ret)
187750043859SJ. Bruce Fields 		return ret;
1878d5497fc6SJ. Bruce Fields 	target->cr_flavor = source->cr_flavor;
18791da177e4SLinus Torvalds 	target->cr_uid = source->cr_uid;
18801da177e4SLinus Torvalds 	target->cr_gid = source->cr_gid;
18811da177e4SLinus Torvalds 	target->cr_group_info = source->cr_group_info;
18821da177e4SLinus Torvalds 	get_group_info(target->cr_group_info);
18830dc1531aSJ. Bruce Fields 	target->cr_gss_mech = source->cr_gss_mech;
18840dc1531aSJ. Bruce Fields 	if (source->cr_gss_mech)
18850dc1531aSJ. Bruce Fields 		gss_mech_get(source->cr_gss_mech);
188603a4e1f6SJ. Bruce Fields 	return 0;
18871da177e4SLinus Torvalds }
18881da177e4SLinus Torvalds 
1889ef17af2aSRasmus Villemoes static int
1890ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
1891ac55fdc4SJeff Layton {
1892ef17af2aSRasmus Villemoes 	if (o1->len < o2->len)
1893ef17af2aSRasmus Villemoes 		return -1;
1894ef17af2aSRasmus Villemoes 	if (o1->len > o2->len)
1895ef17af2aSRasmus Villemoes 		return 1;
1896ef17af2aSRasmus Villemoes 	return memcmp(o1->data, o2->data, o1->len);
1897ac55fdc4SJeff Layton }
1898ac55fdc4SJeff Layton 
189935bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2)
1900599e0a22SJ. Bruce Fields {
1901a55370a3SNeilBrown 	return 0 == memcmp(n1, n2, HEXDIR_LEN);
19021da177e4SLinus Torvalds }
19031da177e4SLinus Torvalds 
19041da177e4SLinus Torvalds static int
1905599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
1906599e0a22SJ. Bruce Fields {
1907599e0a22SJ. Bruce Fields 	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
19081da177e4SLinus Torvalds }
19091da177e4SLinus Torvalds 
19101da177e4SLinus Torvalds static int
1911599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2)
1912599e0a22SJ. Bruce Fields {
1913599e0a22SJ. Bruce Fields 	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
19141da177e4SLinus Torvalds }
19151da177e4SLinus Torvalds 
19168fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2)
19178fbba96eSJ. Bruce Fields {
19188fbba96eSJ. Bruce Fields 	int i;
19198fbba96eSJ. Bruce Fields 
19208fbba96eSJ. Bruce Fields 	if (g1->ngroups != g2->ngroups)
19218fbba96eSJ. Bruce Fields 		return false;
19228fbba96eSJ. Bruce Fields 	for (i=0; i<g1->ngroups; i++)
19236fab8779SEric W. Biederman 		if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i)))
19248fbba96eSJ. Bruce Fields 			return false;
19258fbba96eSJ. Bruce Fields 	return true;
19268fbba96eSJ. Bruce Fields }
19278fbba96eSJ. Bruce Fields 
192868eb3508SJ. Bruce Fields /*
192968eb3508SJ. Bruce Fields  * RFC 3530 language requires clid_inuse be returned when the
193068eb3508SJ. Bruce Fields  * "principal" associated with a requests differs from that previously
193168eb3508SJ. Bruce Fields  * used.  We use uid, gid's, and gss principal string as our best
193268eb3508SJ. Bruce Fields  * approximation.  We also don't want to allow non-gss use of a client
193368eb3508SJ. Bruce Fields  * established using gss: in theory cr_principal should catch that
193468eb3508SJ. Bruce Fields  * change, but in practice cr_principal can be null even in the gss case
193568eb3508SJ. Bruce Fields  * since gssd doesn't always pass down a principal string.
193668eb3508SJ. Bruce Fields  */
193768eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr)
193868eb3508SJ. Bruce Fields {
193968eb3508SJ. Bruce Fields 	/* Is cr_flavor one of the gss "pseudoflavors"?: */
194068eb3508SJ. Bruce Fields 	return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
194168eb3508SJ. Bruce Fields }
194268eb3508SJ. Bruce Fields 
194368eb3508SJ. Bruce Fields 
19445559b50aSVivek Trivedi static bool
1945599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
1946599e0a22SJ. Bruce Fields {
194768eb3508SJ. Bruce Fields 	if ((is_gss_cred(cr1) != is_gss_cred(cr2))
19486fab8779SEric W. Biederman 		|| (!uid_eq(cr1->cr_uid, cr2->cr_uid))
19496fab8779SEric W. Biederman 		|| (!gid_eq(cr1->cr_gid, cr2->cr_gid))
19508fbba96eSJ. Bruce Fields 		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
19518fbba96eSJ. Bruce Fields 		return false;
19528fbba96eSJ. Bruce Fields 	if (cr1->cr_principal == cr2->cr_principal)
19538fbba96eSJ. Bruce Fields 		return true;
19548fbba96eSJ. Bruce Fields 	if (!cr1->cr_principal || !cr2->cr_principal)
19558fbba96eSJ. Bruce Fields 		return false;
19565559b50aSVivek Trivedi 	return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
19571da177e4SLinus Torvalds }
19581da177e4SLinus Torvalds 
195957266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
196057266a6eSJ. Bruce Fields {
196157266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
196257266a6eSJ. Bruce Fields 	u32 service;
196357266a6eSJ. Bruce Fields 
1964c4720591SJ. Bruce Fields 	if (!cr->cr_gss_mech)
1965c4720591SJ. Bruce Fields 		return false;
196657266a6eSJ. Bruce Fields 	service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
196757266a6eSJ. Bruce Fields 	return service == RPC_GSS_SVC_INTEGRITY ||
196857266a6eSJ. Bruce Fields 	       service == RPC_GSS_SVC_PRIVACY;
196957266a6eSJ. Bruce Fields }
197057266a6eSJ. Bruce Fields 
197157266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
197257266a6eSJ. Bruce Fields {
197357266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
197457266a6eSJ. Bruce Fields 
197557266a6eSJ. Bruce Fields 	if (!cl->cl_mach_cred)
197657266a6eSJ. Bruce Fields 		return true;
197757266a6eSJ. Bruce Fields 	if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
197857266a6eSJ. Bruce Fields 		return false;
197957266a6eSJ. Bruce Fields 	if (!svc_rqst_integrity_protected(rqstp))
198057266a6eSJ. Bruce Fields 		return false;
198157266a6eSJ. Bruce Fields 	if (!cr->cr_principal)
198257266a6eSJ. Bruce Fields 		return false;
198357266a6eSJ. Bruce Fields 	return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
198457266a6eSJ. Bruce Fields }
198557266a6eSJ. Bruce Fields 
1986294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
1987deda2faaSJ. Bruce Fields {
1988ab4684d1SChuck Lever 	__be32 verf[2];
19891da177e4SLinus Torvalds 
1990f419992cSJeff Layton 	/*
1991f419992cSJeff Layton 	 * This is opaque to client, so no need to byte-swap. Use
1992f419992cSJeff Layton 	 * __force to keep sparse happy
1993f419992cSJeff Layton 	 */
1994f419992cSJeff Layton 	verf[0] = (__force __be32)get_seconds();
199519311aa8SKinglong Mee 	verf[1] = (__force __be32)nn->clverifier_counter++;
1996ab4684d1SChuck Lever 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
19971da177e4SLinus Torvalds }
19981da177e4SLinus Torvalds 
1999294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
2000294ac32eSJeff Layton {
2001294ac32eSJeff Layton 	clp->cl_clientid.cl_boot = nn->boot_time;
2002294ac32eSJeff Layton 	clp->cl_clientid.cl_id = nn->clientid_counter++;
2003294ac32eSJeff Layton 	gen_confirm(clp, nn);
2004294ac32eSJeff Layton }
2005294ac32eSJeff Layton 
20064770d722SJeff Layton static struct nfs4_stid *
20074770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
20084581d140SJ. Bruce Fields {
20093abdb607SJ. Bruce Fields 	struct nfs4_stid *ret;
20103abdb607SJ. Bruce Fields 
20113abdb607SJ. Bruce Fields 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
20123abdb607SJ. Bruce Fields 	if (!ret || !ret->sc_type)
20133abdb607SJ. Bruce Fields 		return NULL;
20143abdb607SJ. Bruce Fields 	return ret;
20154581d140SJ. Bruce Fields }
20164d71ab87SJ. Bruce Fields 
20174770d722SJeff Layton static struct nfs4_stid *
20184770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
2019f459e453SJ. Bruce Fields {
2020f459e453SJ. Bruce Fields 	struct nfs4_stid *s;
2021f459e453SJ. Bruce Fields 
20224770d722SJeff Layton 	spin_lock(&cl->cl_lock);
20234770d722SJeff Layton 	s = find_stateid_locked(cl, t);
20242d3f9668STrond Myklebust 	if (s != NULL) {
20252d3f9668STrond Myklebust 		if (typemask & s->sc_type)
20262d3f9668STrond Myklebust 			atomic_inc(&s->sc_count);
20272d3f9668STrond Myklebust 		else
20284770d722SJeff Layton 			s = NULL;
20292d3f9668STrond Myklebust 	}
20304770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
20314d71ab87SJ. Bruce Fields 	return s;
20324581d140SJ. Bruce Fields }
20334581d140SJ. Bruce Fields 
20342216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name,
2035b09333c4SRicardo Labiaga 		struct svc_rqst *rqstp, nfs4_verifier *verf)
2036b09333c4SRicardo Labiaga {
2037b09333c4SRicardo Labiaga 	struct nfs4_client *clp;
2038b09333c4SRicardo Labiaga 	struct sockaddr *sa = svc_addr(rqstp);
203903a4e1f6SJ. Bruce Fields 	int ret;
2040c212cecfSStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
2041b09333c4SRicardo Labiaga 
2042b09333c4SRicardo Labiaga 	clp = alloc_client(name);
2043b09333c4SRicardo Labiaga 	if (clp == NULL)
2044b09333c4SRicardo Labiaga 		return NULL;
2045b09333c4SRicardo Labiaga 
204603a4e1f6SJ. Bruce Fields 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
204703a4e1f6SJ. Bruce Fields 	if (ret) {
2048b09333c4SRicardo Labiaga 		free_client(clp);
2049b09333c4SRicardo Labiaga 		return NULL;
2050b09333c4SRicardo Labiaga 	}
20510162ac2bSChristoph Hellwig 	nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL);
205207cd4909SBenny Halevy 	clp->cl_time = get_seconds();
2053b09333c4SRicardo Labiaga 	clear_bit(0, &clp->cl_cb_slot_busy);
2054b09333c4SRicardo Labiaga 	copy_verf(clp, verf);
2055b09333c4SRicardo Labiaga 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
2056edd76786SJ. Bruce Fields 	clp->cl_cb_session = NULL;
2057c212cecfSStanislav Kinsbursky 	clp->net = net;
2058b09333c4SRicardo Labiaga 	return clp;
2059b09333c4SRicardo Labiaga }
2060b09333c4SRicardo Labiaga 
2061fd39ca9aSNeilBrown static void
2062ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
2063ac55fdc4SJeff Layton {
2064ac55fdc4SJeff Layton 	struct rb_node **new = &(root->rb_node), *parent = NULL;
2065ac55fdc4SJeff Layton 	struct nfs4_client *clp;
2066ac55fdc4SJeff Layton 
2067ac55fdc4SJeff Layton 	while (*new) {
2068ac55fdc4SJeff Layton 		clp = rb_entry(*new, struct nfs4_client, cl_namenode);
2069ac55fdc4SJeff Layton 		parent = *new;
2070ac55fdc4SJeff Layton 
2071ac55fdc4SJeff Layton 		if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
2072ac55fdc4SJeff Layton 			new = &((*new)->rb_left);
2073ac55fdc4SJeff Layton 		else
2074ac55fdc4SJeff Layton 			new = &((*new)->rb_right);
2075ac55fdc4SJeff Layton 	}
2076ac55fdc4SJeff Layton 
2077ac55fdc4SJeff Layton 	rb_link_node(&new_clp->cl_namenode, parent, new);
2078ac55fdc4SJeff Layton 	rb_insert_color(&new_clp->cl_namenode, root);
2079ac55fdc4SJeff Layton }
2080ac55fdc4SJeff Layton 
2081ac55fdc4SJeff Layton static struct nfs4_client *
2082ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
2083ac55fdc4SJeff Layton {
2084ef17af2aSRasmus Villemoes 	int cmp;
2085ac55fdc4SJeff Layton 	struct rb_node *node = root->rb_node;
2086ac55fdc4SJeff Layton 	struct nfs4_client *clp;
2087ac55fdc4SJeff Layton 
2088ac55fdc4SJeff Layton 	while (node) {
2089ac55fdc4SJeff Layton 		clp = rb_entry(node, struct nfs4_client, cl_namenode);
2090ac55fdc4SJeff Layton 		cmp = compare_blob(&clp->cl_name, name);
2091ac55fdc4SJeff Layton 		if (cmp > 0)
2092ac55fdc4SJeff Layton 			node = node->rb_left;
2093ac55fdc4SJeff Layton 		else if (cmp < 0)
2094ac55fdc4SJeff Layton 			node = node->rb_right;
2095ac55fdc4SJeff Layton 		else
2096ac55fdc4SJeff Layton 			return clp;
2097ac55fdc4SJeff Layton 	}
2098ac55fdc4SJeff Layton 	return NULL;
2099ac55fdc4SJeff Layton }
2100ac55fdc4SJeff Layton 
2101ac55fdc4SJeff Layton static void
2102ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp)
21031da177e4SLinus Torvalds {
21041da177e4SLinus Torvalds 	unsigned int idhashval;
21050a7ec377SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
21061da177e4SLinus Torvalds 
21070a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
21080a880a28STrond Myklebust 
2109ac55fdc4SJeff Layton 	clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
2110a99454aaSStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
21111da177e4SLinus Torvalds 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
21120a7ec377SStanislav Kinsbursky 	list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
21133dbacee6STrond Myklebust 	renew_client_locked(clp);
21141da177e4SLinus Torvalds }
21151da177e4SLinus Torvalds 
2116fd39ca9aSNeilBrown static void
21171da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp)
21181da177e4SLinus Torvalds {
21191da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
21208daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
21211da177e4SLinus Torvalds 
21220a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
21230a880a28STrond Myklebust 
21241da177e4SLinus Torvalds 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
21258daae4dcSStanislav Kinsbursky 	list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
2126a99454aaSStanislav Kinsbursky 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
2127382a62e7SStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->conf_name_tree);
2128ac55fdc4SJeff Layton 	set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
21293dbacee6STrond Myklebust 	renew_client_locked(clp);
21301da177e4SLinus Torvalds }
21311da177e4SLinus Torvalds 
21321da177e4SLinus Torvalds static struct nfs4_client *
2133bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
21341da177e4SLinus Torvalds {
21351da177e4SLinus Torvalds 	struct nfs4_client *clp;
21361da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clid->cl_id);
21371da177e4SLinus Torvalds 
2138bfa85e83SJ. Bruce Fields 	list_for_each_entry(clp, &tbl[idhashval], cl_idhash) {
2139a50d2ad1SJ. Bruce Fields 		if (same_clid(&clp->cl_clientid, clid)) {
2140d15c077eSJ. Bruce Fields 			if ((bool)clp->cl_minorversion != sessions)
2141d15c077eSJ. Bruce Fields 				return NULL;
21423dbacee6STrond Myklebust 			renew_client_locked(clp);
21431da177e4SLinus Torvalds 			return clp;
21441da177e4SLinus Torvalds 		}
2145a50d2ad1SJ. Bruce Fields 	}
21461da177e4SLinus Torvalds 	return NULL;
21471da177e4SLinus Torvalds }
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds static struct nfs4_client *
2150bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
2151bfa85e83SJ. Bruce Fields {
2152bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->conf_id_hashtbl;
2153bfa85e83SJ. Bruce Fields 
21540a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2155bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
2156bfa85e83SJ. Bruce Fields }
2157bfa85e83SJ. Bruce Fields 
2158bfa85e83SJ. Bruce Fields static struct nfs4_client *
21590a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
21601da177e4SLinus Torvalds {
2161bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->unconf_id_hashtbl;
21621da177e4SLinus Torvalds 
21630a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2164bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
21651da177e4SLinus Torvalds }
21661da177e4SLinus Torvalds 
21676e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp)
2168a1bcecd2SAndy Adamson {
21696e5f15c9SJ. Bruce Fields 	return clp->cl_exchange_flags != 0;
2170a1bcecd2SAndy Adamson }
2171a1bcecd2SAndy Adamson 
217228ce6054SNeilBrown static struct nfs4_client *
2173382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
217428ce6054SNeilBrown {
21750a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2176382a62e7SStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->conf_name_tree);
217728ce6054SNeilBrown }
217828ce6054SNeilBrown 
217928ce6054SNeilBrown static struct nfs4_client *
2180a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
218128ce6054SNeilBrown {
21820a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2183a99454aaSStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->unconf_name_tree);
218428ce6054SNeilBrown }
218528ce6054SNeilBrown 
2186fd39ca9aSNeilBrown static void
21876f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
21881da177e4SLinus Torvalds {
218907263f1eSJ. Bruce Fields 	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
21906f3d772fSTakuma Umeya 	struct sockaddr	*sa = svc_addr(rqstp);
21916f3d772fSTakuma Umeya 	u32 scopeid = rpc_get_scope_id(sa);
21927077ecbaSJeff Layton 	unsigned short expected_family;
21931da177e4SLinus Torvalds 
21947077ecbaSJeff Layton 	/* Currently, we only support tcp and tcp6 for the callback channel */
21957077ecbaSJeff Layton 	if (se->se_callback_netid_len == 3 &&
21967077ecbaSJeff Layton 	    !memcmp(se->se_callback_netid_val, "tcp", 3))
21977077ecbaSJeff Layton 		expected_family = AF_INET;
21987077ecbaSJeff Layton 	else if (se->se_callback_netid_len == 4 &&
21997077ecbaSJeff Layton 		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
22007077ecbaSJeff Layton 		expected_family = AF_INET6;
22017077ecbaSJeff Layton 	else
22021da177e4SLinus Torvalds 		goto out_err;
22031da177e4SLinus Torvalds 
2204c212cecfSStanislav Kinsbursky 	conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val,
2205aa9a4ec7SJeff Layton 					    se->se_callback_addr_len,
220607263f1eSJ. Bruce Fields 					    (struct sockaddr *)&conn->cb_addr,
220707263f1eSJ. Bruce Fields 					    sizeof(conn->cb_addr));
2208aa9a4ec7SJeff Layton 
220907263f1eSJ. Bruce Fields 	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
22101da177e4SLinus Torvalds 		goto out_err;
2211aa9a4ec7SJeff Layton 
221207263f1eSJ. Bruce Fields 	if (conn->cb_addr.ss_family == AF_INET6)
221307263f1eSJ. Bruce Fields 		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
2214fbf4665fSJeff Layton 
221507263f1eSJ. Bruce Fields 	conn->cb_prog = se->se_callback_prog;
221607263f1eSJ. Bruce Fields 	conn->cb_ident = se->se_callback_ident;
2217849a1cf1SMi Jinlong 	memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
22181da177e4SLinus Torvalds 	return;
22191da177e4SLinus Torvalds out_err:
222007263f1eSJ. Bruce Fields 	conn->cb_addr.ss_family = AF_UNSPEC;
222107263f1eSJ. Bruce Fields 	conn->cb_addrlen = 0;
2222849823c5SNeil Brown 	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
22231da177e4SLinus Torvalds 		"will not receive delegations\n",
22241da177e4SLinus Torvalds 		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 	return;
22271da177e4SLinus Torvalds }
22281da177e4SLinus Torvalds 
2229074fe897SAndy Adamson /*
2230067e1aceSJ. Bruce Fields  * Cache a reply. nfsd4_check_resp_size() has bounded the cache size.
2231074fe897SAndy Adamson  */
2232b607664eSTrond Myklebust static void
2233074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
2234074fe897SAndy Adamson {
2235f5236013SJ. Bruce Fields 	struct xdr_buf *buf = resp->xdr.buf;
2236557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2237557ce264SAndy Adamson 	unsigned int base;
2238074fe897SAndy Adamson 
2239557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2240074fe897SAndy Adamson 
2241557ce264SAndy Adamson 	slot->sl_opcnt = resp->opcnt;
2242557ce264SAndy Adamson 	slot->sl_status = resp->cstate.status;
2243bf864a31SAndy Adamson 
2244bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
2245bf864a31SAndy Adamson 	if (nfsd4_not_cached(resp)) {
2246557ce264SAndy Adamson 		slot->sl_datalen = 0;
2247bf864a31SAndy Adamson 		return;
2248bf864a31SAndy Adamson 	}
2249f5236013SJ. Bruce Fields 	base = resp->cstate.data_offset;
2250f5236013SJ. Bruce Fields 	slot->sl_datalen = buf->len - base;
2251f5236013SJ. Bruce Fields 	if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
2252d3f03403SDan Carpenter 		WARN(1, "%s: sessions DRC could not cache compound\n",
2253d3f03403SDan Carpenter 		     __func__);
2254557ce264SAndy Adamson 	return;
2255074fe897SAndy Adamson }
2256074fe897SAndy Adamson 
2257074fe897SAndy Adamson /*
2258abfabf8cSAndy Adamson  * Encode the replay sequence operation from the slot values.
2259abfabf8cSAndy Adamson  * If cachethis is FALSE encode the uncached rep error on the next
2260abfabf8cSAndy Adamson  * operation which sets resp->p and increments resp->opcnt for
2261abfabf8cSAndy Adamson  * nfs4svc_encode_compoundres.
2262abfabf8cSAndy Adamson  *
2263074fe897SAndy Adamson  */
2264abfabf8cSAndy Adamson static __be32
2265abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
2266abfabf8cSAndy Adamson 			  struct nfsd4_compoundres *resp)
2267074fe897SAndy Adamson {
2268abfabf8cSAndy Adamson 	struct nfsd4_op *op;
2269abfabf8cSAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2270074fe897SAndy Adamson 
2271abfabf8cSAndy Adamson 	/* Encode the replayed sequence operation */
2272abfabf8cSAndy Adamson 	op = &args->ops[resp->opcnt - 1];
2273abfabf8cSAndy Adamson 	nfsd4_encode_operation(resp, op);
2274abfabf8cSAndy Adamson 
2275abfabf8cSAndy Adamson 	/* Return nfserr_retry_uncached_rep in next operation. */
227673e79482SJ. Bruce Fields 	if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
2277abfabf8cSAndy Adamson 		op = &args->ops[resp->opcnt++];
2278abfabf8cSAndy Adamson 		op->status = nfserr_retry_uncached_rep;
2279abfabf8cSAndy Adamson 		nfsd4_encode_operation(resp, op);
2280074fe897SAndy Adamson 	}
2281abfabf8cSAndy Adamson 	return op->status;
2282074fe897SAndy Adamson }
2283074fe897SAndy Adamson 
2284074fe897SAndy Adamson /*
2285557ce264SAndy Adamson  * The sequence operation is not cached because we can use the slot and
2286557ce264SAndy Adamson  * session values.
2287074fe897SAndy Adamson  */
22883ca2eb98SJ. Bruce Fields static __be32
2289bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
2290bf864a31SAndy Adamson 			 struct nfsd4_sequence *seq)
2291074fe897SAndy Adamson {
2292557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2293f5236013SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2294f5236013SJ. Bruce Fields 	__be32 *p;
2295074fe897SAndy Adamson 	__be32 status;
2296074fe897SAndy Adamson 
2297557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2298074fe897SAndy Adamson 
2299abfabf8cSAndy Adamson 	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
23000da7b19cSJ. Bruce Fields 	if (status)
2301abfabf8cSAndy Adamson 		return status;
2302074fe897SAndy Adamson 
2303f5236013SJ. Bruce Fields 	p = xdr_reserve_space(xdr, slot->sl_datalen);
2304f5236013SJ. Bruce Fields 	if (!p) {
2305f5236013SJ. Bruce Fields 		WARN_ON_ONCE(1);
2306f5236013SJ. Bruce Fields 		return nfserr_serverfault;
2307f5236013SJ. Bruce Fields 	}
2308f5236013SJ. Bruce Fields 	xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen);
2309f5236013SJ. Bruce Fields 	xdr_commit_encode(xdr);
2310074fe897SAndy Adamson 
2311557ce264SAndy Adamson 	resp->opcnt = slot->sl_opcnt;
2312f5236013SJ. Bruce Fields 	return slot->sl_status;
2313074fe897SAndy Adamson }
2314074fe897SAndy Adamson 
23150733d213SAndy Adamson /*
23160733d213SAndy Adamson  * Set the exchange_id flags returned by the server.
23170733d213SAndy Adamson  */
23180733d213SAndy Adamson static void
23190733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
23200733d213SAndy Adamson {
23219cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
23229cf514ccSChristoph Hellwig 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS;
23239cf514ccSChristoph Hellwig #else
23240733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
23259cf514ccSChristoph Hellwig #endif
23260733d213SAndy Adamson 
23270733d213SAndy Adamson 	/* Referrals are supported, Migration is not. */
23280733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
23290733d213SAndy Adamson 
23300733d213SAndy Adamson 	/* set the wire flags to return to client. */
23310733d213SAndy Adamson 	clid->flags = new->cl_exchange_flags;
23320733d213SAndy Adamson }
23330733d213SAndy Adamson 
23344eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp)
23354eaea134SJ. Bruce Fields {
23364eaea134SJ. Bruce Fields 	struct nfs4_openowner *oo;
23374eaea134SJ. Bruce Fields 
23384eaea134SJ. Bruce Fields 	list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) {
23394eaea134SJ. Bruce Fields 		if (!list_empty(&oo->oo_owner.so_stateids))
23404eaea134SJ. Bruce Fields 			return true;
23414eaea134SJ. Bruce Fields 	}
23424eaea134SJ. Bruce Fields 	return false;
23434eaea134SJ. Bruce Fields }
23444eaea134SJ. Bruce Fields 
2345631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp)
2346631fc9eaSJ. Bruce Fields {
23474eaea134SJ. Bruce Fields 	return client_has_openowners(clp)
234847e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS
234947e970beSKinglong Mee 		|| !list_empty(&clp->cl_lo_states)
235047e970beSKinglong Mee #endif
23516eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_delegations)
23526eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_sessions);
2353631fc9eaSJ. Bruce Fields }
2354631fc9eaSJ. Bruce Fields 
2355b37ad28bSAl Viro __be32
2356069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp,
2357069b6ad4SAndy Adamson 		  struct nfsd4_compound_state *cstate,
2358069b6ad4SAndy Adamson 		  struct nfsd4_exchange_id *exid)
2359069b6ad4SAndy Adamson {
23603dbacee6STrond Myklebust 	struct nfs4_client *conf, *new;
23613dbacee6STrond Myklebust 	struct nfs4_client *unconf = NULL;
236257b7b43bSJ. Bruce Fields 	__be32 status;
2363363168b4SJeff Layton 	char			addr_str[INET6_ADDRSTRLEN];
23640733d213SAndy Adamson 	nfs4_verifier		verf = exid->verifier;
2365363168b4SJeff Layton 	struct sockaddr		*sa = svc_addr(rqstp);
236683e08fd4SJ. Bruce Fields 	bool	update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A;
2367c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
23680733d213SAndy Adamson 
2369363168b4SJeff Layton 	rpc_ntop(sa, addr_str, sizeof(addr_str));
23700733d213SAndy Adamson 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
2371363168b4SJeff Layton 		"ip_addr=%s flags %x, spa_how %d\n",
23720733d213SAndy Adamson 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
2373363168b4SJeff Layton 		addr_str, exid->flags, exid->spa_how);
23740733d213SAndy Adamson 
2375a084daf5SJ. Bruce Fields 	if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
23760733d213SAndy Adamson 		return nfserr_inval;
23770733d213SAndy Adamson 
237850c7b948SJ. Bruce Fields 	new = create_client(exid->clname, rqstp, &verf);
237950c7b948SJ. Bruce Fields 	if (new == NULL)
238050c7b948SJ. Bruce Fields 		return nfserr_jukebox;
238150c7b948SJ. Bruce Fields 
23820733d213SAndy Adamson 	switch (exid->spa_how) {
238357266a6eSJ. Bruce Fields 	case SP4_MACH_CRED:
238450c7b948SJ. Bruce Fields 		if (!svc_rqst_integrity_protected(rqstp)) {
238550c7b948SJ. Bruce Fields 			status = nfserr_inval;
238650c7b948SJ. Bruce Fields 			goto out_nolock;
238750c7b948SJ. Bruce Fields 		}
2388920dd9bbSJ. Bruce Fields 		/*
2389920dd9bbSJ. Bruce Fields 		 * Sometimes userspace doesn't give us a principal.
2390920dd9bbSJ. Bruce Fields 		 * Which is a bug, really.  Anyway, we can't enforce
2391920dd9bbSJ. Bruce Fields 		 * MACH_CRED in that case, better to give up now:
2392920dd9bbSJ. Bruce Fields 		 */
2393920dd9bbSJ. Bruce Fields 		if (!new->cl_cred.cr_principal) {
2394920dd9bbSJ. Bruce Fields 			status = nfserr_serverfault;
2395920dd9bbSJ. Bruce Fields 			goto out_nolock;
2396920dd9bbSJ. Bruce Fields 		}
239750c7b948SJ. Bruce Fields 		new->cl_mach_cred = true;
23980733d213SAndy Adamson 	case SP4_NONE:
23990733d213SAndy Adamson 		break;
2400063b0fb9SJ. Bruce Fields 	default:				/* checked by xdr code */
2401063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
24020733d213SAndy Adamson 	case SP4_SSV:
2403dd30333cSJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
24040733d213SAndy Adamson 	}
24050733d213SAndy Adamson 
24062dbb269dSJ. Bruce Fields 	/* Cases below refer to rfc 5661 section 18.35.4: */
24073dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
2408382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&exid->clname, nn);
24090733d213SAndy Adamson 	if (conf) {
241083e08fd4SJ. Bruce Fields 		bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
241183e08fd4SJ. Bruce Fields 		bool verfs_match = same_verf(&verf, &conf->cl_verifier);
241283e08fd4SJ. Bruce Fields 
2413136e658dSJ. Bruce Fields 		if (update) {
2414136e658dSJ. Bruce Fields 			if (!clp_used_exchangeid(conf)) { /* buggy client */
24152dbb269dSJ. Bruce Fields 				status = nfserr_inval;
2416e203d506SJ. Bruce Fields 				goto out;
2417e203d506SJ. Bruce Fields 			}
241857266a6eSJ. Bruce Fields 			if (!mach_creds_match(conf, rqstp)) {
241957266a6eSJ. Bruce Fields 				status = nfserr_wrong_cred;
242057266a6eSJ. Bruce Fields 				goto out;
242157266a6eSJ. Bruce Fields 			}
24222dbb269dSJ. Bruce Fields 			if (!creds_match) { /* case 9 */
24230733d213SAndy Adamson 				status = nfserr_perm;
24240733d213SAndy Adamson 				goto out;
24250733d213SAndy Adamson 			}
24262dbb269dSJ. Bruce Fields 			if (!verfs_match) { /* case 8 */
24270733d213SAndy Adamson 				status = nfserr_not_same;
24280733d213SAndy Adamson 				goto out;
24290733d213SAndy Adamson 			}
2430136e658dSJ. Bruce Fields 			/* case 6 */
24310733d213SAndy Adamson 			exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
24320733d213SAndy Adamson 			goto out_copy;
24336ddbbbfeSMike Sager 		}
2434136e658dSJ. Bruce Fields 		if (!creds_match) { /* case 3 */
2435631fc9eaSJ. Bruce Fields 			if (client_has_state(conf)) {
2436136e658dSJ. Bruce Fields 				status = nfserr_clid_inuse;
2437136e658dSJ. Bruce Fields 				goto out;
2438136e658dSJ. Bruce Fields 			}
2439b9831b59SJ. Bruce Fields 			goto out_new;
2440631fc9eaSJ. Bruce Fields 		}
2441136e658dSJ. Bruce Fields 		if (verfs_match) { /* case 2 */
24420f1ba0efSJ. Bruce Fields 			conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
2443136e658dSJ. Bruce Fields 			goto out_copy;
2444136e658dSJ. Bruce Fields 		}
24452dbb269dSJ. Bruce Fields 		/* case 5, client reboot */
24463dbacee6STrond Myklebust 		conf = NULL;
24470733d213SAndy Adamson 		goto out_new;
24480733d213SAndy Adamson 	}
24496ddbbbfeSMike Sager 
24502dbb269dSJ. Bruce Fields 	if (update) { /* case 7 */
24510733d213SAndy Adamson 		status = nfserr_noent;
24520733d213SAndy Adamson 		goto out;
24530733d213SAndy Adamson 	}
24540733d213SAndy Adamson 
2455a99454aaSStanislav Kinsbursky 	unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
24562dbb269dSJ. Bruce Fields 	if (unconf) /* case 4, possible retry or client restart */
24573dbacee6STrond Myklebust 		unhash_client_locked(unconf);
24580733d213SAndy Adamson 
24592dbb269dSJ. Bruce Fields 	/* case 1 (normal case) */
24600733d213SAndy Adamson out_new:
2461fd699b8aSJeff Layton 	if (conf) {
2462fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
2463fd699b8aSJeff Layton 		if (status)
2464fd699b8aSJeff Layton 			goto out;
2465fd699b8aSJeff Layton 	}
24664f540e29SJ. Bruce Fields 	new->cl_minorversion = cstate->minorversion;
24670733d213SAndy Adamson 
2468c212cecfSStanislav Kinsbursky 	gen_clid(new, nn);
2469ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
24703dbacee6STrond Myklebust 	swap(new, conf);
24710733d213SAndy Adamson out_copy:
24725cc40fd7STrond Myklebust 	exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
24735cc40fd7STrond Myklebust 	exid->clientid.cl_id = conf->cl_clientid.cl_id;
24740733d213SAndy Adamson 
24755cc40fd7STrond Myklebust 	exid->seqid = conf->cl_cs_slot.sl_seqid + 1;
24765cc40fd7STrond Myklebust 	nfsd4_set_ex_flags(conf, exid);
24770733d213SAndy Adamson 
24780733d213SAndy Adamson 	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
24795cc40fd7STrond Myklebust 		conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags);
24800733d213SAndy Adamson 	status = nfs_ok;
24810733d213SAndy Adamson 
24820733d213SAndy Adamson out:
24833dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
248450c7b948SJ. Bruce Fields out_nolock:
24855cc40fd7STrond Myklebust 	if (new)
24863dbacee6STrond Myklebust 		expire_client(new);
24873dbacee6STrond Myklebust 	if (unconf)
24883dbacee6STrond Myklebust 		expire_client(unconf);
24890733d213SAndy Adamson 	return status;
2490069b6ad4SAndy Adamson }
2491069b6ad4SAndy Adamson 
249257b7b43bSJ. Bruce Fields static __be32
249388e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
2494b85d4c01SBenny Halevy {
249588e588d5SAndy Adamson 	dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
249688e588d5SAndy Adamson 		slot_seqid);
2497b85d4c01SBenny Halevy 
2498b85d4c01SBenny Halevy 	/* The slot is in use, and no response has been sent. */
249988e588d5SAndy Adamson 	if (slot_inuse) {
250088e588d5SAndy Adamson 		if (seqid == slot_seqid)
2501b85d4c01SBenny Halevy 			return nfserr_jukebox;
2502b85d4c01SBenny Halevy 		else
2503b85d4c01SBenny Halevy 			return nfserr_seq_misordered;
2504b85d4c01SBenny Halevy 	}
2505f6d82485SJ. Bruce Fields 	/* Note unsigned 32-bit arithmetic handles wraparound: */
250688e588d5SAndy Adamson 	if (likely(seqid == slot_seqid + 1))
2507b85d4c01SBenny Halevy 		return nfs_ok;
250888e588d5SAndy Adamson 	if (seqid == slot_seqid)
2509b85d4c01SBenny Halevy 		return nfserr_replay_cache;
2510b85d4c01SBenny Halevy 	return nfserr_seq_misordered;
2511b85d4c01SBenny Halevy }
2512b85d4c01SBenny Halevy 
251349557cc7SAndy Adamson /*
251449557cc7SAndy Adamson  * Cache the create session result into the create session single DRC
251549557cc7SAndy Adamson  * slot cache by saving the xdr structure. sl_seqid has been set.
251649557cc7SAndy Adamson  * Do this for solo or embedded create session operations.
251749557cc7SAndy Adamson  */
251849557cc7SAndy Adamson static void
251949557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
252057b7b43bSJ. Bruce Fields 			   struct nfsd4_clid_slot *slot, __be32 nfserr)
252149557cc7SAndy Adamson {
252249557cc7SAndy Adamson 	slot->sl_status = nfserr;
252349557cc7SAndy Adamson 	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
252449557cc7SAndy Adamson }
252549557cc7SAndy Adamson 
252649557cc7SAndy Adamson static __be32
252749557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
252849557cc7SAndy Adamson 			    struct nfsd4_clid_slot *slot)
252949557cc7SAndy Adamson {
253049557cc7SAndy Adamson 	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
253149557cc7SAndy Adamson 	return slot->sl_status;
253249557cc7SAndy Adamson }
253349557cc7SAndy Adamson 
25341b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
25351b74c25bSMi Jinlong 			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
25361b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
25371b74c25bSMi Jinlong 			3 +	/* version, opcount, opcode */ \
25381b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
25391b74c25bSMi Jinlong 				/* seqid, slotID, slotID, cache */ \
25401b74c25bSMi Jinlong 			4 ) * sizeof(__be32))
25411b74c25bSMi Jinlong 
25421b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
25431b74c25bSMi Jinlong 			2 +	/* verifier: AUTH_NULL, length 0 */\
25441b74c25bSMi Jinlong 			1 +	/* status */ \
25451b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
25461b74c25bSMi Jinlong 			3 +	/* opcount, opcode, opstatus*/ \
25471b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
25481b74c25bSMi Jinlong 				/* seqid, slotID, slotID, slotID, status */ \
25491b74c25bSMi Jinlong 			5 ) * sizeof(__be32))
25501b74c25bSMi Jinlong 
255155c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn)
25521b74c25bSMi Jinlong {
255355c760cfSJ. Bruce Fields 	u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
255455c760cfSJ. Bruce Fields 
2555373cd409SJ. Bruce Fields 	if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
2556373cd409SJ. Bruce Fields 		return nfserr_toosmall;
2557373cd409SJ. Bruce Fields 	if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
2558373cd409SJ. Bruce Fields 		return nfserr_toosmall;
255955c760cfSJ. Bruce Fields 	ca->headerpadsz = 0;
256055c760cfSJ. Bruce Fields 	ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
256155c760cfSJ. Bruce Fields 	ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
256255c760cfSJ. Bruce Fields 	ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
256355c760cfSJ. Bruce Fields 	ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
256455c760cfSJ. Bruce Fields 			NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
256555c760cfSJ. Bruce Fields 	ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
256655c760cfSJ. Bruce Fields 	/*
256755c760cfSJ. Bruce Fields 	 * Note decreasing slot size below client's request may make it
256855c760cfSJ. Bruce Fields 	 * difficult for client to function correctly, whereas
256955c760cfSJ. Bruce Fields 	 * decreasing the number of slots will (just?) affect
257055c760cfSJ. Bruce Fields 	 * performance.  When short on memory we therefore prefer to
257155c760cfSJ. Bruce Fields 	 * decrease number of slots instead of their size.  Clients that
257255c760cfSJ. Bruce Fields 	 * request larger slots than they need will get poor results:
257355c760cfSJ. Bruce Fields 	 */
257455c760cfSJ. Bruce Fields 	ca->maxreqs = nfsd4_get_drc_mem(ca);
257555c760cfSJ. Bruce Fields 	if (!ca->maxreqs)
257655c760cfSJ. Bruce Fields 		return nfserr_jukebox;
257755c760cfSJ. Bruce Fields 
2578373cd409SJ. Bruce Fields 	return nfs_ok;
25791b74c25bSMi Jinlong }
25801b74c25bSMi Jinlong 
25818a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ	((NFS4_enc_cb_recall_sz + \
25828a891633SKinglong Mee 				 RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32))
25838a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ	((NFS4_dec_cb_recall_sz + \
25848a891633SKinglong Mee 				 RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32))
25858a891633SKinglong Mee 
258606b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
258706b332a5SJ. Bruce Fields {
258806b332a5SJ. Bruce Fields 	ca->headerpadsz = 0;
258906b332a5SJ. Bruce Fields 
259006b332a5SJ. Bruce Fields 	/*
259106b332a5SJ. Bruce Fields 	 * These RPC_MAX_HEADER macros are overkill, especially since we
259206b332a5SJ. Bruce Fields 	 * don't even do gss on the backchannel yet.  But this is still
259306b332a5SJ. Bruce Fields 	 * less than 1k.  Tighten up this estimate in the unlikely event
259406b332a5SJ. Bruce Fields 	 * it turns out to be a problem for some client:
259506b332a5SJ. Bruce Fields 	 */
25968a891633SKinglong Mee 	if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ)
259706b332a5SJ. Bruce Fields 		return nfserr_toosmall;
25988a891633SKinglong Mee 	if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ)
259906b332a5SJ. Bruce Fields 		return nfserr_toosmall;
260006b332a5SJ. Bruce Fields 	ca->maxresp_cached = 0;
260106b332a5SJ. Bruce Fields 	if (ca->maxops < 2)
260206b332a5SJ. Bruce Fields 		return nfserr_toosmall;
260306b332a5SJ. Bruce Fields 
260406b332a5SJ. Bruce Fields 	return nfs_ok;
2605069b6ad4SAndy Adamson }
2606069b6ad4SAndy Adamson 
2607b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
2608b78724b7SJ. Bruce Fields {
2609b78724b7SJ. Bruce Fields 	switch (cbs->flavor) {
2610b78724b7SJ. Bruce Fields 	case RPC_AUTH_NULL:
2611b78724b7SJ. Bruce Fields 	case RPC_AUTH_UNIX:
2612b78724b7SJ. Bruce Fields 		return nfs_ok;
2613b78724b7SJ. Bruce Fields 	default:
2614b78724b7SJ. Bruce Fields 		/*
2615b78724b7SJ. Bruce Fields 		 * GSS case: the spec doesn't allow us to return this
2616b78724b7SJ. Bruce Fields 		 * error.  But it also doesn't allow us not to support
2617b78724b7SJ. Bruce Fields 		 * GSS.
2618b78724b7SJ. Bruce Fields 		 * I'd rather this fail hard than return some error the
2619b78724b7SJ. Bruce Fields 		 * client might think it can already handle:
2620b78724b7SJ. Bruce Fields 		 */
2621b78724b7SJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
2622b78724b7SJ. Bruce Fields 	}
2623b78724b7SJ. Bruce Fields }
2624b78724b7SJ. Bruce Fields 
2625069b6ad4SAndy Adamson __be32
2626069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp,
2627069b6ad4SAndy Adamson 		     struct nfsd4_compound_state *cstate,
2628069b6ad4SAndy Adamson 		     struct nfsd4_create_session *cr_ses)
2629069b6ad4SAndy Adamson {
2630363168b4SJeff Layton 	struct sockaddr *sa = svc_addr(rqstp);
2631ec6b5d7bSAndy Adamson 	struct nfs4_client *conf, *unconf;
2632d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
2633ac7c46f2SJ. Bruce Fields 	struct nfsd4_session *new;
263481f0b2a4SJ. Bruce Fields 	struct nfsd4_conn *conn;
263549557cc7SAndy Adamson 	struct nfsd4_clid_slot *cs_slot = NULL;
263657b7b43bSJ. Bruce Fields 	__be32 status = 0;
26378daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2638ec6b5d7bSAndy Adamson 
2639a62573dcSMi Jinlong 	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
2640a62573dcSMi Jinlong 		return nfserr_inval;
2641b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
2642b78724b7SJ. Bruce Fields 	if (status)
2643b78724b7SJ. Bruce Fields 		return status;
264455c760cfSJ. Bruce Fields 	status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
2645373cd409SJ. Bruce Fields 	if (status)
2646373cd409SJ. Bruce Fields 		return status;
264706b332a5SJ. Bruce Fields 	status = check_backchannel_attrs(&cr_ses->back_channel);
264806b332a5SJ. Bruce Fields 	if (status)
2649f403e450SKinglong Mee 		goto out_release_drc_mem;
265081f0b2a4SJ. Bruce Fields 	status = nfserr_jukebox;
265160810e54SKinglong Mee 	new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
265255c760cfSJ. Bruce Fields 	if (!new)
265355c760cfSJ. Bruce Fields 		goto out_release_drc_mem;
265481f0b2a4SJ. Bruce Fields 	conn = alloc_conn_from_crses(rqstp, cr_ses);
265581f0b2a4SJ. Bruce Fields 	if (!conn)
265681f0b2a4SJ. Bruce Fields 		goto out_free_session;
2657a62573dcSMi Jinlong 
2658d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
26590a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
26608daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
266178389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2662ec6b5d7bSAndy Adamson 
2663ec6b5d7bSAndy Adamson 	if (conf) {
266457266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
266557266a6eSJ. Bruce Fields 		if (!mach_creds_match(conf, rqstp))
266657266a6eSJ. Bruce Fields 			goto out_free_conn;
266749557cc7SAndy Adamson 		cs_slot = &conf->cl_cs_slot;
266849557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
2669f5e22bb6SKinglong Mee 		if (status) {
2670f5e22bb6SKinglong Mee 			if (status == nfserr_replay_cache)
267149557cc7SAndy Adamson 				status = nfsd4_replay_create_session(cr_ses, cs_slot);
267281f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2673ec6b5d7bSAndy Adamson 		}
2674ec6b5d7bSAndy Adamson 	} else if (unconf) {
2675ec6b5d7bSAndy Adamson 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
2676363168b4SJeff Layton 		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
2677ec6b5d7bSAndy Adamson 			status = nfserr_clid_inuse;
267881f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2679ec6b5d7bSAndy Adamson 		}
268057266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
268157266a6eSJ. Bruce Fields 		if (!mach_creds_match(unconf, rqstp))
268257266a6eSJ. Bruce Fields 			goto out_free_conn;
268349557cc7SAndy Adamson 		cs_slot = &unconf->cl_cs_slot;
268449557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
268538eb76a5SAndy Adamson 		if (status) {
268638eb76a5SAndy Adamson 			/* an unconfirmed replay returns misordered */
2687ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
268881f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2689ec6b5d7bSAndy Adamson 		}
2690382a62e7SStanislav Kinsbursky 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
2691221a6876SJ. Bruce Fields 		if (old) {
2692d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
26937abea1e8SJeff Layton 			if (status) {
26947abea1e8SJeff Layton 				old = NULL;
2695221a6876SJ. Bruce Fields 				goto out_free_conn;
2696221a6876SJ. Bruce Fields 			}
26977abea1e8SJeff Layton 		}
26988f9d3d3bSJ. Bruce Fields 		move_to_confirmed(unconf);
2699ec6b5d7bSAndy Adamson 		conf = unconf;
2700ec6b5d7bSAndy Adamson 	} else {
2701ec6b5d7bSAndy Adamson 		status = nfserr_stale_clientid;
270281f0b2a4SJ. Bruce Fields 		goto out_free_conn;
2703ec6b5d7bSAndy Adamson 	}
270481f0b2a4SJ. Bruce Fields 	status = nfs_ok;
27058323c3b2SJ. Bruce Fields 	/*
2706408b79bcSJ. Bruce Fields 	 * We do not support RDMA or persistent sessions
2707408b79bcSJ. Bruce Fields 	 */
2708408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_PERSIST;
2709408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_RDMA;
2710408b79bcSJ. Bruce Fields 
271181f0b2a4SJ. Bruce Fields 	init_session(rqstp, new, conf, cr_ses);
2712d20c11d8SJeff Layton 	nfsd4_get_session_locked(new);
271381f0b2a4SJ. Bruce Fields 
2714ac7c46f2SJ. Bruce Fields 	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
2715ec6b5d7bSAndy Adamson 	       NFS4_MAX_SESSIONID_LEN);
271686c3e16cSJ. Bruce Fields 	cs_slot->sl_seqid++;
271749557cc7SAndy Adamson 	cr_ses->seqid = cs_slot->sl_seqid;
2718ec6b5d7bSAndy Adamson 
2719d20c11d8SJeff Layton 	/* cache solo and embedded create sessions under the client_lock */
272049557cc7SAndy Adamson 	nfsd4_cache_create_session(cr_ses, cs_slot, status);
2721d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
2722d20c11d8SJeff Layton 	/* init connection and backchannel */
2723d20c11d8SJeff Layton 	nfsd4_init_conn(rqstp, conn, new);
2724d20c11d8SJeff Layton 	nfsd4_put_session(new);
2725d20c11d8SJeff Layton 	if (old)
2726d20c11d8SJeff Layton 		expire_client(old);
2727ec6b5d7bSAndy Adamson 	return status;
272881f0b2a4SJ. Bruce Fields out_free_conn:
2729d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
273081f0b2a4SJ. Bruce Fields 	free_conn(conn);
2731d20c11d8SJeff Layton 	if (old)
2732d20c11d8SJeff Layton 		expire_client(old);
273381f0b2a4SJ. Bruce Fields out_free_session:
273481f0b2a4SJ. Bruce Fields 	__free_session(new);
273555c760cfSJ. Bruce Fields out_release_drc_mem:
273655c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&cr_ses->fore_channel);
27371ca50792SJ. Bruce Fields 	return status;
2738069b6ad4SAndy Adamson }
2739069b6ad4SAndy Adamson 
27401d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir)
27411d1bc8f2SJ. Bruce Fields {
27421d1bc8f2SJ. Bruce Fields 	switch (*dir) {
27431d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE:
27441d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK:
27451d1bc8f2SJ. Bruce Fields 		return nfs_ok;
27461d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE_OR_BOTH:
27471d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK_OR_BOTH:
27481d1bc8f2SJ. Bruce Fields 		*dir = NFS4_CDFC4_BOTH;
27491d1bc8f2SJ. Bruce Fields 		return nfs_ok;
27501d1bc8f2SJ. Bruce Fields 	};
27511d1bc8f2SJ. Bruce Fields 	return nfserr_inval;
27521d1bc8f2SJ. Bruce Fields }
27531d1bc8f2SJ. Bruce Fields 
2754cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc)
2755cb73a9f4SJ. Bruce Fields {
2756cb73a9f4SJ. Bruce Fields 	struct nfsd4_session *session = cstate->session;
2757c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2758b78724b7SJ. Bruce Fields 	__be32 status;
2759cb73a9f4SJ. Bruce Fields 
2760b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
2761b78724b7SJ. Bruce Fields 	if (status)
2762b78724b7SJ. Bruce Fields 		return status;
2763c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2764cb73a9f4SJ. Bruce Fields 	session->se_cb_prog = bc->bc_cb_program;
2765cb73a9f4SJ. Bruce Fields 	session->se_cb_sec = bc->bc_cb_sec;
2766c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2767cb73a9f4SJ. Bruce Fields 
2768cb73a9f4SJ. Bruce Fields 	nfsd4_probe_callback(session->se_client);
2769cb73a9f4SJ. Bruce Fields 
2770cb73a9f4SJ. Bruce Fields 	return nfs_ok;
2771cb73a9f4SJ. Bruce Fields }
2772cb73a9f4SJ. Bruce Fields 
27731d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
27741d1bc8f2SJ. Bruce Fields 		     struct nfsd4_compound_state *cstate,
27751d1bc8f2SJ. Bruce Fields 		     struct nfsd4_bind_conn_to_session *bcts)
27761d1bc8f2SJ. Bruce Fields {
27771d1bc8f2SJ. Bruce Fields 	__be32 status;
27783ba63671SJ. Bruce Fields 	struct nfsd4_conn *conn;
27794f6e6c17SJ. Bruce Fields 	struct nfsd4_session *session;
2780d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2781d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
27821d1bc8f2SJ. Bruce Fields 
27831d1bc8f2SJ. Bruce Fields 	if (!nfsd4_last_compound_op(rqstp))
27841d1bc8f2SJ. Bruce Fields 		return nfserr_not_only_op;
2785c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2786d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status);
2787c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
27884f6e6c17SJ. Bruce Fields 	if (!session)
2789d4e19e70STrond Myklebust 		goto out_no_session;
279057266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
279157266a6eSJ. Bruce Fields 	if (!mach_creds_match(session->se_client, rqstp))
279257266a6eSJ. Bruce Fields 		goto out;
27931d1bc8f2SJ. Bruce Fields 	status = nfsd4_map_bcts_dir(&bcts->dir);
27943ba63671SJ. Bruce Fields 	if (status)
27954f6e6c17SJ. Bruce Fields 		goto out;
27963ba63671SJ. Bruce Fields 	conn = alloc_conn(rqstp, bcts->dir);
27974f6e6c17SJ. Bruce Fields 	status = nfserr_jukebox;
27983ba63671SJ. Bruce Fields 	if (!conn)
27994f6e6c17SJ. Bruce Fields 		goto out;
28004f6e6c17SJ. Bruce Fields 	nfsd4_init_conn(rqstp, conn, session);
28014f6e6c17SJ. Bruce Fields 	status = nfs_ok;
28024f6e6c17SJ. Bruce Fields out:
2803d4e19e70STrond Myklebust 	nfsd4_put_session(session);
2804d4e19e70STrond Myklebust out_no_session:
28054f6e6c17SJ. Bruce Fields 	return status;
28061d1bc8f2SJ. Bruce Fields }
28071d1bc8f2SJ. Bruce Fields 
28085d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
28095d4cec2fSJ. Bruce Fields {
28105d4cec2fSJ. Bruce Fields 	if (!session)
28115d4cec2fSJ. Bruce Fields 		return 0;
28125d4cec2fSJ. Bruce Fields 	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
28135d4cec2fSJ. Bruce Fields }
28145d4cec2fSJ. Bruce Fields 
2815069b6ad4SAndy Adamson __be32
2816069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r,
2817069b6ad4SAndy Adamson 		      struct nfsd4_compound_state *cstate,
2818069b6ad4SAndy Adamson 		      struct nfsd4_destroy_session *sessionid)
2819069b6ad4SAndy Adamson {
2820e10e0cfcSBenny Halevy 	struct nfsd4_session *ses;
2821abcdff09SJ. Bruce Fields 	__be32 status;
2822f0f51f5cSJ. Bruce Fields 	int ref_held_by_me = 0;
2823d4e19e70STrond Myklebust 	struct net *net = SVC_NET(r);
2824d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2825e10e0cfcSBenny Halevy 
2826abcdff09SJ. Bruce Fields 	status = nfserr_not_only_op;
28275d4cec2fSJ. Bruce Fields 	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
282857716355SJ. Bruce Fields 		if (!nfsd4_last_compound_op(r))
2829abcdff09SJ. Bruce Fields 			goto out;
2830f0f51f5cSJ. Bruce Fields 		ref_held_by_me++;
283157716355SJ. Bruce Fields 	}
2832e10e0cfcSBenny Halevy 	dump_sessionid(__func__, &sessionid->sessionid);
2833c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2834d4e19e70STrond Myklebust 	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status);
2835abcdff09SJ. Bruce Fields 	if (!ses)
2836abcdff09SJ. Bruce Fields 		goto out_client_lock;
283757266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
283857266a6eSJ. Bruce Fields 	if (!mach_creds_match(ses->se_client, r))
2839d4e19e70STrond Myklebust 		goto out_put_session;
2840f0f51f5cSJ. Bruce Fields 	status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
284166b2b9b2SJ. Bruce Fields 	if (status)
2842f0f51f5cSJ. Bruce Fields 		goto out_put_session;
2843e10e0cfcSBenny Halevy 	unhash_session(ses);
2844c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2845e10e0cfcSBenny Halevy 
284684f5f7ccSJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
284719cf5c02SJ. Bruce Fields 
2848c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2849e10e0cfcSBenny Halevy 	status = nfs_ok;
2850f0f51f5cSJ. Bruce Fields out_put_session:
2851d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
2852abcdff09SJ. Bruce Fields out_client_lock:
2853abcdff09SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
2854e10e0cfcSBenny Halevy out:
2855e10e0cfcSBenny Halevy 	return status;
2856069b6ad4SAndy Adamson }
2857069b6ad4SAndy Adamson 
2858a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
2859328ead28SJ. Bruce Fields {
2860328ead28SJ. Bruce Fields 	struct nfsd4_conn *c;
2861328ead28SJ. Bruce Fields 
2862328ead28SJ. Bruce Fields 	list_for_each_entry(c, &s->se_conns, cn_persession) {
2863a663bdd8SJ. Bruce Fields 		if (c->cn_xprt == xpt) {
2864328ead28SJ. Bruce Fields 			return c;
2865328ead28SJ. Bruce Fields 		}
2866328ead28SJ. Bruce Fields 	}
2867328ead28SJ. Bruce Fields 	return NULL;
2868328ead28SJ. Bruce Fields }
2869328ead28SJ. Bruce Fields 
287057266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
2871328ead28SJ. Bruce Fields {
2872328ead28SJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
2873a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *c;
287457266a6eSJ. Bruce Fields 	__be32 status = nfs_ok;
287521b75b01SJ. Bruce Fields 	int ret;
2876328ead28SJ. Bruce Fields 
2877328ead28SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
2878a663bdd8SJ. Bruce Fields 	c = __nfsd4_find_conn(new->cn_xprt, ses);
287957266a6eSJ. Bruce Fields 	if (c)
288057266a6eSJ. Bruce Fields 		goto out_free;
288157266a6eSJ. Bruce Fields 	status = nfserr_conn_not_bound_to_session;
288257266a6eSJ. Bruce Fields 	if (clp->cl_mach_cred)
288357266a6eSJ. Bruce Fields 		goto out_free;
2884328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(new, ses);
2885328ead28SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
288621b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(new);
288721b75b01SJ. Bruce Fields 	if (ret)
288821b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
288921b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&new->cn_xpt_user);
289057266a6eSJ. Bruce Fields 	return nfs_ok;
289157266a6eSJ. Bruce Fields out_free:
289257266a6eSJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
289357266a6eSJ. Bruce Fields 	free_conn(new);
289457266a6eSJ. Bruce Fields 	return status;
2895328ead28SJ. Bruce Fields }
2896328ead28SJ. Bruce Fields 
2897868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
2898868b89c3SMi Jinlong {
2899868b89c3SMi Jinlong 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
2900868b89c3SMi Jinlong 
2901868b89c3SMi Jinlong 	return args->opcnt > session->se_fchannel.maxops;
2902868b89c3SMi Jinlong }
2903868b89c3SMi Jinlong 
2904ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
2905ae82a8d0SMi Jinlong 				  struct nfsd4_session *session)
2906ae82a8d0SMi Jinlong {
2907ae82a8d0SMi Jinlong 	struct xdr_buf *xb = &rqstp->rq_arg;
2908ae82a8d0SMi Jinlong 
2909ae82a8d0SMi Jinlong 	return xb->len > session->se_fchannel.maxreq_sz;
2910ae82a8d0SMi Jinlong }
2911ae82a8d0SMi Jinlong 
2912069b6ad4SAndy Adamson __be32
2913b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp,
2914069b6ad4SAndy Adamson 	       struct nfsd4_compound_state *cstate,
2915069b6ad4SAndy Adamson 	       struct nfsd4_sequence *seq)
2916069b6ad4SAndy Adamson {
2917f9bb94c4SAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
291847ee5298SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2919b85d4c01SBenny Halevy 	struct nfsd4_session *session;
2920221a6876SJ. Bruce Fields 	struct nfs4_client *clp;
2921b85d4c01SBenny Halevy 	struct nfsd4_slot *slot;
2922a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *conn;
292357b7b43bSJ. Bruce Fields 	__be32 status;
292447ee5298SJ. Bruce Fields 	int buflen;
2925d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2926d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2927b85d4c01SBenny Halevy 
2928f9bb94c4SAndy Adamson 	if (resp->opcnt != 1)
2929f9bb94c4SAndy Adamson 		return nfserr_sequence_pos;
2930f9bb94c4SAndy Adamson 
2931a663bdd8SJ. Bruce Fields 	/*
2932a663bdd8SJ. Bruce Fields 	 * Will be either used or freed by nfsd4_sequence_check_conn
2933a663bdd8SJ. Bruce Fields 	 * below.
2934a663bdd8SJ. Bruce Fields 	 */
2935a663bdd8SJ. Bruce Fields 	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
2936a663bdd8SJ. Bruce Fields 	if (!conn)
2937a663bdd8SJ. Bruce Fields 		return nfserr_jukebox;
2938a663bdd8SJ. Bruce Fields 
2939c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2940d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status);
2941b85d4c01SBenny Halevy 	if (!session)
2942221a6876SJ. Bruce Fields 		goto out_no_session;
2943221a6876SJ. Bruce Fields 	clp = session->se_client;
2944b85d4c01SBenny Halevy 
2945868b89c3SMi Jinlong 	status = nfserr_too_many_ops;
2946868b89c3SMi Jinlong 	if (nfsd4_session_too_many_ops(rqstp, session))
294766b2b9b2SJ. Bruce Fields 		goto out_put_session;
2948868b89c3SMi Jinlong 
2949ae82a8d0SMi Jinlong 	status = nfserr_req_too_big;
2950ae82a8d0SMi Jinlong 	if (nfsd4_request_too_big(rqstp, session))
295166b2b9b2SJ. Bruce Fields 		goto out_put_session;
2952ae82a8d0SMi Jinlong 
2953b85d4c01SBenny Halevy 	status = nfserr_badslot;
29546c18ba9fSAlexandros Batsakis 	if (seq->slotid >= session->se_fchannel.maxreqs)
295566b2b9b2SJ. Bruce Fields 		goto out_put_session;
2956b85d4c01SBenny Halevy 
2957557ce264SAndy Adamson 	slot = session->se_slots[seq->slotid];
2958b85d4c01SBenny Halevy 	dprintk("%s: slotid %d\n", __func__, seq->slotid);
2959b85d4c01SBenny Halevy 
2960a8dfdaebSAndy Adamson 	/* We do not negotiate the number of slots yet, so set the
2961a8dfdaebSAndy Adamson 	 * maxslots to the session maxreqs which is used to encode
2962a8dfdaebSAndy Adamson 	 * sr_highest_slotid and the sr_target_slot id to maxslots */
2963a8dfdaebSAndy Adamson 	seq->maxslots = session->se_fchannel.maxreqs;
2964a8dfdaebSAndy Adamson 
296573e79482SJ. Bruce Fields 	status = check_slot_seqid(seq->seqid, slot->sl_seqid,
296673e79482SJ. Bruce Fields 					slot->sl_flags & NFSD4_SLOT_INUSE);
2967b85d4c01SBenny Halevy 	if (status == nfserr_replay_cache) {
2968bf5c43c8SJ. Bruce Fields 		status = nfserr_seq_misordered;
2969bf5c43c8SJ. Bruce Fields 		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
297066b2b9b2SJ. Bruce Fields 			goto out_put_session;
2971b85d4c01SBenny Halevy 		cstate->slot = slot;
2972b85d4c01SBenny Halevy 		cstate->session = session;
29734b24ca7dSJeff Layton 		cstate->clp = clp;
2974da3846a2SAndy Adamson 		/* Return the cached reply status and set cstate->status
2975557ce264SAndy Adamson 		 * for nfsd4_proc_compound processing */
2976bf864a31SAndy Adamson 		status = nfsd4_replay_cache_entry(resp, seq);
2977da3846a2SAndy Adamson 		cstate->status = nfserr_replay_cache;
2978aaf84eb9SBenny Halevy 		goto out;
2979b85d4c01SBenny Halevy 	}
2980b85d4c01SBenny Halevy 	if (status)
298166b2b9b2SJ. Bruce Fields 		goto out_put_session;
2982b85d4c01SBenny Halevy 
298357266a6eSJ. Bruce Fields 	status = nfsd4_sequence_check_conn(conn, session);
2984a663bdd8SJ. Bruce Fields 	conn = NULL;
298557266a6eSJ. Bruce Fields 	if (status)
298657266a6eSJ. Bruce Fields 		goto out_put_session;
2987328ead28SJ. Bruce Fields 
298847ee5298SJ. Bruce Fields 	buflen = (seq->cachethis) ?
298947ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_cached :
299047ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_sz;
299147ee5298SJ. Bruce Fields 	status = (seq->cachethis) ? nfserr_rep_too_big_to_cache :
299247ee5298SJ. Bruce Fields 				    nfserr_rep_too_big;
2993a5cddc88SJ. Bruce Fields 	if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack))
299447ee5298SJ. Bruce Fields 		goto out_put_session;
299532aaa62eSJ. Bruce Fields 	svc_reserve(rqstp, buflen);
299647ee5298SJ. Bruce Fields 
299747ee5298SJ. Bruce Fields 	status = nfs_ok;
2998b85d4c01SBenny Halevy 	/* Success! bump slot seqid */
2999b85d4c01SBenny Halevy 	slot->sl_seqid = seq->seqid;
3000bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INUSE;
300173e79482SJ. Bruce Fields 	if (seq->cachethis)
300273e79482SJ. Bruce Fields 		slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
3003bf5c43c8SJ. Bruce Fields 	else
3004bf5c43c8SJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
3005b85d4c01SBenny Halevy 
3006b85d4c01SBenny Halevy 	cstate->slot = slot;
3007b85d4c01SBenny Halevy 	cstate->session = session;
30084b24ca7dSJeff Layton 	cstate->clp = clp;
3009b85d4c01SBenny Halevy 
3010b85d4c01SBenny Halevy out:
30115423732aSBenny Halevy 	switch (clp->cl_cb_state) {
30125423732aSBenny Halevy 	case NFSD4_CB_DOWN:
3013fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
30145423732aSBenny Halevy 		break;
30155423732aSBenny Halevy 	case NFSD4_CB_FAULT:
3016fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
30175423732aSBenny Halevy 		break;
3018fc0c3dd1SBenny Halevy 	default:
3019fc0c3dd1SBenny Halevy 		seq->status_flags = 0;
30205423732aSBenny Halevy 	}
30213bd64a5bSJ. Bruce Fields 	if (!list_empty(&clp->cl_revoked))
30223bd64a5bSJ. Bruce Fields 		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
3023221a6876SJ. Bruce Fields out_no_session:
30243f42d2c4SKinglong Mee 	if (conn)
30253f42d2c4SKinglong Mee 		free_conn(conn);
3026c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
3027b85d4c01SBenny Halevy 	return status;
302866b2b9b2SJ. Bruce Fields out_put_session:
3029d4e19e70STrond Myklebust 	nfsd4_put_session_locked(session);
3030221a6876SJ. Bruce Fields 	goto out_no_session;
3031069b6ad4SAndy Adamson }
3032069b6ad4SAndy Adamson 
3033b607664eSTrond Myklebust void
3034b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp)
3035b607664eSTrond Myklebust {
3036b607664eSTrond Myklebust 	struct nfsd4_compound_state *cs = &resp->cstate;
3037b607664eSTrond Myklebust 
3038b607664eSTrond Myklebust 	if (nfsd4_has_session(cs)) {
3039b607664eSTrond Myklebust 		if (cs->status != nfserr_replay_cache) {
3040b607664eSTrond Myklebust 			nfsd4_store_cache_entry(resp);
3041b607664eSTrond Myklebust 			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
3042b607664eSTrond Myklebust 		}
3043d4e19e70STrond Myklebust 		/* Drop session reference that was taken in nfsd4_sequence() */
3044b607664eSTrond Myklebust 		nfsd4_put_session(cs->session);
30454b24ca7dSJeff Layton 	} else if (cs->clp)
30464b24ca7dSJeff Layton 		put_client_renew(cs->clp);
3047b607664eSTrond Myklebust }
3048b607664eSTrond Myklebust 
3049345c2842SMi Jinlong __be32
3050345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
3051345c2842SMi Jinlong {
30526b10ad19STrond Myklebust 	struct nfs4_client *conf, *unconf;
30536b10ad19STrond Myklebust 	struct nfs4_client *clp = NULL;
305457b7b43bSJ. Bruce Fields 	__be32 status = 0;
30558daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
3056345c2842SMi Jinlong 
30576b10ad19STrond Myklebust 	spin_lock(&nn->client_lock);
30580a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
30598daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&dc->clientid, true, nn);
306078389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
3061345c2842SMi Jinlong 
3062345c2842SMi Jinlong 	if (conf) {
3063c0293b01SJ. Bruce Fields 		if (client_has_state(conf)) {
3064345c2842SMi Jinlong 			status = nfserr_clientid_busy;
3065345c2842SMi Jinlong 			goto out;
3066345c2842SMi Jinlong 		}
3067fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
3068fd699b8aSJeff Layton 		if (status)
3069fd699b8aSJeff Layton 			goto out;
30706b10ad19STrond Myklebust 		clp = conf;
3071345c2842SMi Jinlong 	} else if (unconf)
3072345c2842SMi Jinlong 		clp = unconf;
3073345c2842SMi Jinlong 	else {
3074345c2842SMi Jinlong 		status = nfserr_stale_clientid;
3075345c2842SMi Jinlong 		goto out;
3076345c2842SMi Jinlong 	}
307757266a6eSJ. Bruce Fields 	if (!mach_creds_match(clp, rqstp)) {
30786b10ad19STrond Myklebust 		clp = NULL;
307957266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
308057266a6eSJ. Bruce Fields 		goto out;
308157266a6eSJ. Bruce Fields 	}
30826b10ad19STrond Myklebust 	unhash_client_locked(clp);
3083345c2842SMi Jinlong out:
30846b10ad19STrond Myklebust 	spin_unlock(&nn->client_lock);
30856b10ad19STrond Myklebust 	if (clp)
30866b10ad19STrond Myklebust 		expire_client(clp);
3087345c2842SMi Jinlong 	return status;
3088345c2842SMi Jinlong }
3089345c2842SMi Jinlong 
3090069b6ad4SAndy Adamson __be32
30914dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
30924dc6ec00SJ. Bruce Fields {
309357b7b43bSJ. Bruce Fields 	__be32 status = 0;
3094bcecf1ccSMi Jinlong 
30954dc6ec00SJ. Bruce Fields 	if (rc->rca_one_fs) {
30964dc6ec00SJ. Bruce Fields 		if (!cstate->current_fh.fh_dentry)
30974dc6ec00SJ. Bruce Fields 			return nfserr_nofilehandle;
30984dc6ec00SJ. Bruce Fields 		/*
30994dc6ec00SJ. Bruce Fields 		 * We don't take advantage of the rca_one_fs case.
31004dc6ec00SJ. Bruce Fields 		 * That's OK, it's optional, we can safely ignore it.
31014dc6ec00SJ. Bruce Fields 		 */
31024dc6ec00SJ. Bruce Fields 		 return nfs_ok;
31034dc6ec00SJ. Bruce Fields 	}
3104bcecf1ccSMi Jinlong 
3105bcecf1ccSMi Jinlong 	status = nfserr_complete_already;
3106a52d726bSJeff Layton 	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
3107a52d726bSJeff Layton 			     &cstate->session->se_client->cl_flags))
3108bcecf1ccSMi Jinlong 		goto out;
3109bcecf1ccSMi Jinlong 
3110bcecf1ccSMi Jinlong 	status = nfserr_stale_clientid;
3111bcecf1ccSMi Jinlong 	if (is_client_expired(cstate->session->se_client))
31124dc6ec00SJ. Bruce Fields 		/*
31134dc6ec00SJ. Bruce Fields 		 * The following error isn't really legal.
31144dc6ec00SJ. Bruce Fields 		 * But we only get here if the client just explicitly
31154dc6ec00SJ. Bruce Fields 		 * destroyed the client.  Surely it no longer cares what
31164dc6ec00SJ. Bruce Fields 		 * error it gets back on an operation for the dead
31174dc6ec00SJ. Bruce Fields 		 * client.
31184dc6ec00SJ. Bruce Fields 		 */
3119bcecf1ccSMi Jinlong 		goto out;
3120bcecf1ccSMi Jinlong 
3121bcecf1ccSMi Jinlong 	status = nfs_ok;
31222a4317c5SJeff Layton 	nfsd4_client_record_create(cstate->session->se_client);
3123bcecf1ccSMi Jinlong out:
3124bcecf1ccSMi Jinlong 	return status;
31254dc6ec00SJ. Bruce Fields }
31264dc6ec00SJ. Bruce Fields 
31274dc6ec00SJ. Bruce Fields __be32
3128b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3129b591480bSJ.Bruce Fields 		  struct nfsd4_setclientid *setclid)
31301da177e4SLinus Torvalds {
3131a084daf5SJ. Bruce Fields 	struct xdr_netobj 	clname = setclid->se_name;
31321da177e4SLinus Torvalds 	nfs4_verifier		clverifier = setclid->se_verf;
31333dbacee6STrond Myklebust 	struct nfs4_client	*conf, *new;
31343dbacee6STrond Myklebust 	struct nfs4_client	*unconf = NULL;
3135b37ad28bSAl Viro 	__be32 			status;
3136c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
3137a55370a3SNeilBrown 
31385cc40fd7STrond Myklebust 	new = create_client(clname, rqstp, &clverifier);
31395cc40fd7STrond Myklebust 	if (new == NULL)
31405cc40fd7STrond Myklebust 		return nfserr_jukebox;
314163db4632SJ. Bruce Fields 	/* Cases below refer to rfc 3530 section 14.2.33: */
31423dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
3143382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&clname, nn);
31442b634821SJ. Bruce Fields 	if (conf && client_has_state(conf)) {
314563db4632SJ. Bruce Fields 		/* case 0: */
31461da177e4SLinus Torvalds 		status = nfserr_clid_inuse;
3147e203d506SJ. Bruce Fields 		if (clp_used_exchangeid(conf))
3148e203d506SJ. Bruce Fields 			goto out;
3149026722c2SJ. Bruce Fields 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
3150363168b4SJeff Layton 			char addr_str[INET6_ADDRSTRLEN];
3151363168b4SJeff Layton 			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
3152363168b4SJeff Layton 				 sizeof(addr_str));
3153026722c2SJ. Bruce Fields 			dprintk("NFSD: setclientid: string in use by client "
3154363168b4SJeff Layton 				"at %s\n", addr_str);
31551da177e4SLinus Torvalds 			goto out;
31561da177e4SLinus Torvalds 		}
31571da177e4SLinus Torvalds 	}
3158a99454aaSStanislav Kinsbursky 	unconf = find_unconfirmed_client_by_name(&clname, nn);
31591da177e4SLinus Torvalds 	if (unconf)
31603dbacee6STrond Myklebust 		unhash_client_locked(unconf);
316141eb1670SKinglong Mee 	if (conf && same_verf(&conf->cl_verifier, &clverifier)) {
316263db4632SJ. Bruce Fields 		/* case 1: probable callback update */
31631da177e4SLinus Torvalds 		copy_clid(new, conf);
316441eb1670SKinglong Mee 		gen_confirm(new, nn);
316541eb1670SKinglong Mee 	} else /* case 4 (new client) or cases 2, 3 (client reboot): */
3166c212cecfSStanislav Kinsbursky 		gen_clid(new, nn);
31678323c3b2SJ. Bruce Fields 	new->cl_minorversion = 0;
31686f3d772fSTakuma Umeya 	gen_callback(new, setclid, rqstp);
3169ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
31701da177e4SLinus Torvalds 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
31711da177e4SLinus Torvalds 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
31721da177e4SLinus Torvalds 	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
31735cc40fd7STrond Myklebust 	new = NULL;
31741da177e4SLinus Torvalds 	status = nfs_ok;
31751da177e4SLinus Torvalds out:
31763dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
31775cc40fd7STrond Myklebust 	if (new)
31785cc40fd7STrond Myklebust 		free_client(new);
31793dbacee6STrond Myklebust 	if (unconf)
31803dbacee6STrond Myklebust 		expire_client(unconf);
31811da177e4SLinus Torvalds 	return status;
31821da177e4SLinus Torvalds }
31831da177e4SLinus Torvalds 
31841da177e4SLinus Torvalds 
3185b37ad28bSAl Viro __be32
3186b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
3187b591480bSJ.Bruce Fields 			 struct nfsd4_compound_state *cstate,
3188b591480bSJ.Bruce Fields 			 struct nfsd4_setclientid_confirm *setclientid_confirm)
31891da177e4SLinus Torvalds {
319021ab45a4SNeilBrown 	struct nfs4_client *conf, *unconf;
3191d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
31921da177e4SLinus Torvalds 	nfs4_verifier confirm = setclientid_confirm->sc_confirm;
31931da177e4SLinus Torvalds 	clientid_t * clid = &setclientid_confirm->sc_clientid;
3194b37ad28bSAl Viro 	__be32 status;
31957f2210faSStanislav Kinsbursky 	struct nfsd_net	*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
31961da177e4SLinus Torvalds 
31972c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(clid, nn))
31981da177e4SLinus Torvalds 		return nfserr_stale_clientid;
319921ab45a4SNeilBrown 
3200d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
32018daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(clid, false, nn);
32020a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(clid, false, nn);
3203a186e767SJ. Bruce Fields 	/*
32048695b90aSJ. Bruce Fields 	 * We try hard to give out unique clientid's, so if we get an
32058695b90aSJ. Bruce Fields 	 * attempt to confirm the same clientid with a different cred,
3206f984a7ceSJ. Bruce Fields 	 * the client may be buggy; this should never happen.
3207f984a7ceSJ. Bruce Fields 	 *
3208f984a7ceSJ. Bruce Fields 	 * Nevertheless, RFC 7530 recommends INUSE for this case:
3209a186e767SJ. Bruce Fields 	 */
3210f984a7ceSJ. Bruce Fields 	status = nfserr_clid_inuse;
32118695b90aSJ. Bruce Fields 	if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred))
32128695b90aSJ. Bruce Fields 		goto out;
32138695b90aSJ. Bruce Fields 	if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred))
32148695b90aSJ. Bruce Fields 		goto out;
321563db4632SJ. Bruce Fields 	/* cases below refer to rfc 3530 section 14.2.34: */
321690d700b7SJ. Bruce Fields 	if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) {
321790d700b7SJ. Bruce Fields 		if (conf && !unconf) /* case 2: probable retransmit */
321890d700b7SJ. Bruce Fields 			status = nfs_ok;
321990d700b7SJ. Bruce Fields 		else /* case 4: client hasn't noticed we rebooted yet? */
322090d700b7SJ. Bruce Fields 			status = nfserr_stale_clientid;
322190d700b7SJ. Bruce Fields 		goto out;
322290d700b7SJ. Bruce Fields 	}
322390d700b7SJ. Bruce Fields 	status = nfs_ok;
322490d700b7SJ. Bruce Fields 	if (conf) { /* case 1: callback update */
3225d20c11d8SJeff Layton 		old = unconf;
3226d20c11d8SJeff Layton 		unhash_client_locked(old);
32275a3c9d71SJ. Bruce Fields 		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
322890d700b7SJ. Bruce Fields 	} else { /* case 3: normal case; new or rebooted client */
3229d20c11d8SJeff Layton 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
3230d20c11d8SJeff Layton 		if (old) {
32312b634821SJ. Bruce Fields 			status = nfserr_clid_inuse;
32322b634821SJ. Bruce Fields 			if (client_has_state(old)
32332b634821SJ. Bruce Fields 					&& !same_creds(&unconf->cl_cred,
32342b634821SJ. Bruce Fields 							&old->cl_cred))
32352b634821SJ. Bruce Fields 				goto out;
3236d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
32377abea1e8SJeff Layton 			if (status) {
32387abea1e8SJeff Layton 				old = NULL;
3239221a6876SJ. Bruce Fields 				goto out;
3240221a6876SJ. Bruce Fields 			}
32417abea1e8SJeff Layton 		}
32421da177e4SLinus Torvalds 		move_to_confirmed(unconf);
3243d20c11d8SJeff Layton 		conf = unconf;
324408e8987cSNeilBrown 	}
3245d20c11d8SJeff Layton 	get_client_locked(conf);
3246d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3247d20c11d8SJeff Layton 	nfsd4_probe_callback(conf);
3248d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
3249d20c11d8SJeff Layton 	put_client_renew_locked(conf);
32501da177e4SLinus Torvalds out:
3251d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3252d20c11d8SJeff Layton 	if (old)
3253d20c11d8SJeff Layton 		expire_client(old);
32541da177e4SLinus Torvalds 	return status;
32551da177e4SLinus Torvalds }
32561da177e4SLinus Torvalds 
325732513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void)
32581da177e4SLinus Torvalds {
325932513b40SJ. Bruce Fields 	return kmem_cache_alloc(file_slab, GFP_KERNEL);
326032513b40SJ. Bruce Fields }
326132513b40SJ. Bruce Fields 
326232513b40SJ. Bruce Fields /* OPEN Share state helper functions */
32635b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
32645b095e99SJeff Layton 				struct nfs4_file *fp)
326532513b40SJ. Bruce Fields {
3266950e0118STrond Myklebust 	lockdep_assert_held(&state_lock);
3267950e0118STrond Myklebust 
32688b671b80SJ. Bruce Fields 	atomic_set(&fp->fi_ref, 1);
32691d31a253STrond Myklebust 	spin_lock_init(&fp->fi_lock);
32708beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_stateids);
32718beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_delegations);
32728287f009SSachin Bhamare 	INIT_LIST_HEAD(&fp->fi_clnt_odstate);
3273e2cf80d7STrond Myklebust 	fh_copy_shallow(&fp->fi_fhandle, fh);
32740c637be8SJeff Layton 	fp->fi_deleg_file = NULL;
327547f9940cSMeelap Shah 	fp->fi_had_conflict = false;
3276baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
3277f9d7562fSJ. Bruce Fields 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
3278f9d7562fSJ. Bruce Fields 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
32799cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
32809cf514ccSChristoph Hellwig 	INIT_LIST_HEAD(&fp->fi_lo_states);
3281c5c707f9SChristoph Hellwig 	atomic_set(&fp->fi_lo_recalls, 0);
32829cf514ccSChristoph Hellwig #endif
32835b095e99SJeff Layton 	hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]);
32841da177e4SLinus Torvalds }
32851da177e4SLinus Torvalds 
3286e8ff2a84SJ. Bruce Fields void
3287e60d4398SNeilBrown nfsd4_free_slabs(void)
3288e60d4398SNeilBrown {
32898287f009SSachin Bhamare 	kmem_cache_destroy(odstate_slab);
3290abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3291abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3292abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3293abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3294abf1135bSChristoph Hellwig 	kmem_cache_destroy(deleg_slab);
3295e60d4398SNeilBrown }
32961da177e4SLinus Torvalds 
329772083396SBryan Schumaker int
32981da177e4SLinus Torvalds nfsd4_init_slabs(void)
32991da177e4SLinus Torvalds {
3300fe0750e5SJ. Bruce Fields 	openowner_slab = kmem_cache_create("nfsd4_openowners",
3301fe0750e5SJ. Bruce Fields 			sizeof(struct nfs4_openowner), 0, 0, NULL);
3302fe0750e5SJ. Bruce Fields 	if (openowner_slab == NULL)
3303abf1135bSChristoph Hellwig 		goto out;
3304fe0750e5SJ. Bruce Fields 	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
33053c40794bSYanchuan Nian 			sizeof(struct nfs4_lockowner), 0, 0, NULL);
3306fe0750e5SJ. Bruce Fields 	if (lockowner_slab == NULL)
3307abf1135bSChristoph Hellwig 		goto out_free_openowner_slab;
3308e60d4398SNeilBrown 	file_slab = kmem_cache_create("nfsd4_files",
330920c2df83SPaul Mundt 			sizeof(struct nfs4_file), 0, 0, NULL);
3310e60d4398SNeilBrown 	if (file_slab == NULL)
3311abf1135bSChristoph Hellwig 		goto out_free_lockowner_slab;
33125ac049acSNeilBrown 	stateid_slab = kmem_cache_create("nfsd4_stateids",
3313dcef0413SJ. Bruce Fields 			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
33145ac049acSNeilBrown 	if (stateid_slab == NULL)
3315abf1135bSChristoph Hellwig 		goto out_free_file_slab;
33165b2d21c1SNeilBrown 	deleg_slab = kmem_cache_create("nfsd4_delegations",
331720c2df83SPaul Mundt 			sizeof(struct nfs4_delegation), 0, 0, NULL);
33185b2d21c1SNeilBrown 	if (deleg_slab == NULL)
3319abf1135bSChristoph Hellwig 		goto out_free_stateid_slab;
33208287f009SSachin Bhamare 	odstate_slab = kmem_cache_create("nfsd4_odstate",
33218287f009SSachin Bhamare 			sizeof(struct nfs4_clnt_odstate), 0, 0, NULL);
33228287f009SSachin Bhamare 	if (odstate_slab == NULL)
33238287f009SSachin Bhamare 		goto out_free_deleg_slab;
3324e60d4398SNeilBrown 	return 0;
3325abf1135bSChristoph Hellwig 
33268287f009SSachin Bhamare out_free_deleg_slab:
33278287f009SSachin Bhamare 	kmem_cache_destroy(deleg_slab);
3328abf1135bSChristoph Hellwig out_free_stateid_slab:
3329abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3330abf1135bSChristoph Hellwig out_free_file_slab:
3331abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3332abf1135bSChristoph Hellwig out_free_lockowner_slab:
3333abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3334abf1135bSChristoph Hellwig out_free_openowner_slab:
3335abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3336abf1135bSChristoph Hellwig out:
33371da177e4SLinus Torvalds 	dprintk("nfsd4: out of memory while initializing nfsv4\n");
33381da177e4SLinus Torvalds 	return -ENOMEM;
33391da177e4SLinus Torvalds }
33401da177e4SLinus Torvalds 
3341ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp)
3342ff194bd9SJ. Bruce Fields {
3343ff194bd9SJ. Bruce Fields 	rp->rp_status = nfserr_serverfault;
3344ff194bd9SJ. Bruce Fields 	rp->rp_buflen = 0;
3345ff194bd9SJ. Bruce Fields 	rp->rp_buf = rp->rp_ibuf;
334658fb12e6SJeff Layton 	mutex_init(&rp->rp_mutex);
334758fb12e6SJeff Layton }
334858fb12e6SJeff Layton 
334958fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
335058fb12e6SJeff Layton 		struct nfs4_stateowner *so)
335158fb12e6SJeff Layton {
335258fb12e6SJeff Layton 	if (!nfsd4_has_session(cstate)) {
335358fb12e6SJeff Layton 		mutex_lock(&so->so_replay.rp_mutex);
3354b5971afaSKinglong Mee 		cstate->replay_owner = nfs4_get_stateowner(so);
335558fb12e6SJeff Layton 	}
335658fb12e6SJeff Layton }
335758fb12e6SJeff Layton 
335858fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate)
335958fb12e6SJeff Layton {
336058fb12e6SJeff Layton 	struct nfs4_stateowner *so = cstate->replay_owner;
336158fb12e6SJeff Layton 
336258fb12e6SJeff Layton 	if (so != NULL) {
336358fb12e6SJeff Layton 		cstate->replay_owner = NULL;
336458fb12e6SJeff Layton 		mutex_unlock(&so->so_replay.rp_mutex);
336558fb12e6SJeff Layton 		nfs4_put_stateowner(so);
336658fb12e6SJeff Layton 	}
3367ff194bd9SJ. Bruce Fields }
3368ff194bd9SJ. Bruce Fields 
3369fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
33701da177e4SLinus Torvalds {
33711da177e4SLinus Torvalds 	struct nfs4_stateowner *sop;
33721da177e4SLinus Torvalds 
3373fe0750e5SJ. Bruce Fields 	sop = kmem_cache_alloc(slab, GFP_KERNEL);
3374ff194bd9SJ. Bruce Fields 	if (!sop)
3375ff194bd9SJ. Bruce Fields 		return NULL;
3376ff194bd9SJ. Bruce Fields 
3377ff194bd9SJ. Bruce Fields 	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
3378ff194bd9SJ. Bruce Fields 	if (!sop->so_owner.data) {
3379fe0750e5SJ. Bruce Fields 		kmem_cache_free(slab, sop);
3380ff194bd9SJ. Bruce Fields 		return NULL;
3381ff194bd9SJ. Bruce Fields 	}
33821da177e4SLinus Torvalds 	sop->so_owner.len = owner->len;
3383ff194bd9SJ. Bruce Fields 
3384ff194bd9SJ. Bruce Fields 	INIT_LIST_HEAD(&sop->so_stateids);
3385ff194bd9SJ. Bruce Fields 	sop->so_client = clp;
3386ff194bd9SJ. Bruce Fields 	init_nfs4_replay(&sop->so_replay);
33876b180f0bSJeff Layton 	atomic_set(&sop->so_count, 1);
33881da177e4SLinus Torvalds 	return sop;
33891da177e4SLinus Torvalds }
3390ff194bd9SJ. Bruce Fields 
3391fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
3392ff194bd9SJ. Bruce Fields {
3393d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
33949b531137SStanislav Kinsbursky 
3395d4f0489fSTrond Myklebust 	list_add(&oo->oo_owner.so_strhash,
3396d4f0489fSTrond Myklebust 		 &clp->cl_ownerstr_hashtbl[strhashval]);
3397fe0750e5SJ. Bruce Fields 	list_add(&oo->oo_perclient, &clp->cl_openowners);
33981da177e4SLinus Torvalds }
33991da177e4SLinus Torvalds 
34008f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
34018f4b54c5SJeff Layton {
3402d4f0489fSTrond Myklebust 	unhash_openowner_locked(openowner(so));
34038f4b54c5SJeff Layton }
34048f4b54c5SJeff Layton 
34056b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so)
34066b180f0bSJeff Layton {
34076b180f0bSJeff Layton 	struct nfs4_openowner *oo = openowner(so);
34086b180f0bSJeff Layton 
34096b180f0bSJeff Layton 	kmem_cache_free(openowner_slab, oo);
34106b180f0bSJeff Layton }
34116b180f0bSJeff Layton 
34126b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = {
34138f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_openowner,
34146b180f0bSJeff Layton 	.so_free =	nfs4_free_openowner,
34156b180f0bSJeff Layton };
34166b180f0bSJeff Layton 
34177fc0564eSAndrew Elble static struct nfs4_ol_stateid *
34187fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
34197fc0564eSAndrew Elble {
34207fc0564eSAndrew Elble 	struct nfs4_ol_stateid *local, *ret = NULL;
34217fc0564eSAndrew Elble 	struct nfs4_openowner *oo = open->op_openowner;
34227fc0564eSAndrew Elble 
34237fc0564eSAndrew Elble 	lockdep_assert_held(&fp->fi_lock);
34247fc0564eSAndrew Elble 
34257fc0564eSAndrew Elble 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
34267fc0564eSAndrew Elble 		/* ignore lock owners */
34277fc0564eSAndrew Elble 		if (local->st_stateowner->so_is_open_owner == 0)
34287fc0564eSAndrew Elble 			continue;
34297fc0564eSAndrew Elble 		if (local->st_stateowner == &oo->oo_owner) {
34307fc0564eSAndrew Elble 			ret = local;
34317fc0564eSAndrew Elble 			atomic_inc(&ret->st_stid.sc_count);
34327fc0564eSAndrew Elble 			break;
34337fc0564eSAndrew Elble 		}
34347fc0564eSAndrew Elble 	}
34357fc0564eSAndrew Elble 	return ret;
34367fc0564eSAndrew Elble }
34377fc0564eSAndrew Elble 
3438fe0750e5SJ. Bruce Fields static struct nfs4_openowner *
343913d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3440db24b3b4SJeff Layton 			   struct nfsd4_compound_state *cstate)
3441db24b3b4SJeff Layton {
344213d6f66bSTrond Myklebust 	struct nfs4_client *clp = cstate->clp;
34437ffb5880STrond Myklebust 	struct nfs4_openowner *oo, *ret;
34441da177e4SLinus Torvalds 
3445fe0750e5SJ. Bruce Fields 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
3446fe0750e5SJ. Bruce Fields 	if (!oo)
34471da177e4SLinus Torvalds 		return NULL;
34486b180f0bSJeff Layton 	oo->oo_owner.so_ops = &openowner_ops;
3449fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_is_open_owner = 1;
3450fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_seqid = open->op_seqid;
3451d3134b10SJeff Layton 	oo->oo_flags = 0;
3452db24b3b4SJeff Layton 	if (nfsd4_has_session(cstate))
3453db24b3b4SJeff Layton 		oo->oo_flags |= NFS4_OO_CONFIRMED;
3454fe0750e5SJ. Bruce Fields 	oo->oo_time = 0;
345538c387b5SJ. Bruce Fields 	oo->oo_last_closed_stid = NULL;
3456fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&oo->oo_close_lru);
3457d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
3458d4f0489fSTrond Myklebust 	ret = find_openstateowner_str_locked(strhashval, open, clp);
34597ffb5880STrond Myklebust 	if (ret == NULL) {
3460fe0750e5SJ. Bruce Fields 		hash_openowner(oo, clp, strhashval);
34617ffb5880STrond Myklebust 		ret = oo;
34627ffb5880STrond Myklebust 	} else
3463d50ffdedSKinglong Mee 		nfs4_free_stateowner(&oo->oo_owner);
3464d50ffdedSKinglong Mee 
3465d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
3466c5952338SJeff Layton 	return ret;
34671da177e4SLinus Torvalds }
34681da177e4SLinus Torvalds 
34697fc0564eSAndrew Elble static struct nfs4_ol_stateid *
34707fc0564eSAndrew Elble init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
34717fc0564eSAndrew Elble 		struct nfsd4_open *open)
34727fc0564eSAndrew Elble {
34731da177e4SLinus Torvalds 
34747fc0564eSAndrew Elble 	struct nfs4_openowner *oo = open->op_openowner;
34757fc0564eSAndrew Elble 	struct nfs4_ol_stateid *retstp = NULL;
34767fc0564eSAndrew Elble 
34777fc0564eSAndrew Elble 	spin_lock(&oo->oo_owner.so_client->cl_lock);
34787fc0564eSAndrew Elble 	spin_lock(&fp->fi_lock);
34797fc0564eSAndrew Elble 
34807fc0564eSAndrew Elble 	retstp = nfsd4_find_existing_open(fp, open);
34817fc0564eSAndrew Elble 	if (retstp)
34827fc0564eSAndrew Elble 		goto out_unlock;
3483d6f2bc5dSTrond Myklebust 	atomic_inc(&stp->st_stid.sc_count);
34843abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_OPEN_STID;
34853c87b9b7STrond Myklebust 	INIT_LIST_HEAD(&stp->st_locks);
3486b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
348713cd2184SNeilBrown 	get_nfs4_file(fp);
348811b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
34891da177e4SLinus Torvalds 	stp->st_access_bmap = 0;
34901da177e4SLinus Torvalds 	stp->st_deny_bmap = 0;
34914c4cd222SNeilBrown 	stp->st_openstp = NULL;
349235a92fe8SJeff Layton 	init_rwsem(&stp->st_rwsem);
34931c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
34941d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
34957fc0564eSAndrew Elble 
34967fc0564eSAndrew Elble out_unlock:
34971d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
34981c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
34997fc0564eSAndrew Elble 	return retstp;
35001da177e4SLinus Torvalds }
35011da177e4SLinus Torvalds 
3502d3134b10SJeff Layton /*
3503d3134b10SJeff Layton  * In the 4.0 case we need to keep the owners around a little while to handle
3504d3134b10SJeff Layton  * CLOSE replay. We still do need to release any file access that is held by
3505d3134b10SJeff Layton  * them before returning however.
3506d3134b10SJeff Layton  */
35071da177e4SLinus Torvalds static void
3508d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
35091da177e4SLinus Torvalds {
3510217526e7SJeff Layton 	struct nfs4_ol_stateid *last;
3511d3134b10SJeff Layton 	struct nfs4_openowner *oo = openowner(s->st_stateowner);
3512d3134b10SJeff Layton 	struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net,
3513d3134b10SJeff Layton 						nfsd_net_id);
351473758fedSStanislav Kinsbursky 
3515fe0750e5SJ. Bruce Fields 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
35161da177e4SLinus Torvalds 
3517b401be22SJeff Layton 	/*
3518b401be22SJeff Layton 	 * We know that we hold one reference via nfsd4_close, and another
3519b401be22SJeff Layton 	 * "persistent" reference for the client. If the refcount is higher
3520b401be22SJeff Layton 	 * than 2, then there are still calls in progress that are using this
3521b401be22SJeff Layton 	 * stateid. We can't put the sc_file reference until they are finished.
3522b401be22SJeff Layton 	 * Wait for the refcount to drop to 2. Since it has been unhashed,
3523b401be22SJeff Layton 	 * there should be no danger of the refcount going back up again at
3524b401be22SJeff Layton 	 * this point.
3525b401be22SJeff Layton 	 */
3526b401be22SJeff Layton 	wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2);
3527b401be22SJeff Layton 
3528d3134b10SJeff Layton 	release_all_access(s);
3529d3134b10SJeff Layton 	if (s->st_stid.sc_file) {
3530d3134b10SJeff Layton 		put_nfs4_file(s->st_stid.sc_file);
3531d3134b10SJeff Layton 		s->st_stid.sc_file = NULL;
3532d3134b10SJeff Layton 	}
3533217526e7SJeff Layton 
3534217526e7SJeff Layton 	spin_lock(&nn->client_lock);
3535217526e7SJeff Layton 	last = oo->oo_last_closed_stid;
3536d3134b10SJeff Layton 	oo->oo_last_closed_stid = s;
353773758fedSStanislav Kinsbursky 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
3538fe0750e5SJ. Bruce Fields 	oo->oo_time = get_seconds();
3539217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
3540217526e7SJeff Layton 	if (last)
3541217526e7SJeff Layton 		nfs4_put_stid(&last->st_stid);
35421da177e4SLinus Torvalds }
35431da177e4SLinus Torvalds 
35441da177e4SLinus Torvalds /* search file_hashtbl[] for file */
35451da177e4SLinus Torvalds static struct nfs4_file *
35465b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval)
35471da177e4SLinus Torvalds {
35481da177e4SLinus Torvalds 	struct nfs4_file *fp;
35491da177e4SLinus Torvalds 
35505b095e99SJeff Layton 	hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) {
35514d94c2efSChristoph Hellwig 		if (fh_match(&fp->fi_fhandle, fh)) {
35525b095e99SJeff Layton 			if (atomic_inc_not_zero(&fp->fi_ref))
35531da177e4SLinus Torvalds 				return fp;
35541da177e4SLinus Torvalds 		}
355513cd2184SNeilBrown 	}
35561da177e4SLinus Torvalds 	return NULL;
35571da177e4SLinus Torvalds }
35581da177e4SLinus Torvalds 
3559e6ba76e1SChristoph Hellwig struct nfs4_file *
3560ca943217STrond Myklebust find_file(struct knfsd_fh *fh)
3561950e0118STrond Myklebust {
3562950e0118STrond Myklebust 	struct nfs4_file *fp;
35635b095e99SJeff Layton 	unsigned int hashval = file_hashval(fh);
3564950e0118STrond Myklebust 
35655b095e99SJeff Layton 	rcu_read_lock();
35665b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
35675b095e99SJeff Layton 	rcu_read_unlock();
3568950e0118STrond Myklebust 	return fp;
3569950e0118STrond Myklebust }
3570950e0118STrond Myklebust 
3571950e0118STrond Myklebust static struct nfs4_file *
3572f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh)
3573950e0118STrond Myklebust {
3574950e0118STrond Myklebust 	struct nfs4_file *fp;
35755b095e99SJeff Layton 	unsigned int hashval = file_hashval(fh);
35765b095e99SJeff Layton 
35775b095e99SJeff Layton 	rcu_read_lock();
35785b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
35795b095e99SJeff Layton 	rcu_read_unlock();
35805b095e99SJeff Layton 	if (fp)
35815b095e99SJeff Layton 		return fp;
3582950e0118STrond Myklebust 
3583950e0118STrond Myklebust 	spin_lock(&state_lock);
35845b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
35855b095e99SJeff Layton 	if (likely(fp == NULL)) {
35865b095e99SJeff Layton 		nfsd4_init_file(fh, hashval, new);
3587950e0118STrond Myklebust 		fp = new;
3588950e0118STrond Myklebust 	}
3589950e0118STrond Myklebust 	spin_unlock(&state_lock);
3590950e0118STrond Myklebust 
3591950e0118STrond Myklebust 	return fp;
3592950e0118STrond Myklebust }
3593950e0118STrond Myklebust 
35944f83aa30SJ. Bruce Fields /*
35951da177e4SLinus Torvalds  * Called to check deny when READ with all zero stateid or
35961da177e4SLinus Torvalds  * WRITE with all zero or all one stateid
35971da177e4SLinus Torvalds  */
3598b37ad28bSAl Viro static __be32
35991da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
36001da177e4SLinus Torvalds {
36011da177e4SLinus Torvalds 	struct nfs4_file *fp;
3602baeb4ff0SJeff Layton 	__be32 ret = nfs_ok;
36031da177e4SLinus Torvalds 
3604ca943217STrond Myklebust 	fp = find_file(&current_fh->fh_handle);
360513cd2184SNeilBrown 	if (!fp)
3606baeb4ff0SJeff Layton 		return ret;
3607baeb4ff0SJeff Layton 	/* Check for conflicting share reservations */
36081d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
3609baeb4ff0SJeff Layton 	if (fp->fi_share_deny & deny_type)
3610baeb4ff0SJeff Layton 		ret = nfserr_locked;
36111d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
361213cd2184SNeilBrown 	put_nfs4_file(fp);
361313cd2184SNeilBrown 	return ret;
36141da177e4SLinus Torvalds }
36151da177e4SLinus Torvalds 
36160162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb)
36171da177e4SLinus Torvalds {
36180162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
361911b9164aSTrond Myklebust 	struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net,
362011b9164aSTrond Myklebust 					  nfsd_net_id);
3621e8c69d17SJ. Bruce Fields 
362211b9164aSTrond Myklebust 	block_delegations(&dp->dl_stid.sc_file->fi_fhandle);
3623f54fe962SJeff Layton 
362402e1215fSJeff Layton 	/*
362502e1215fSJeff Layton 	 * We can't do this in nfsd_break_deleg_cb because it is
3626f54fe962SJeff Layton 	 * already holding inode->i_lock.
3627f54fe962SJeff Layton 	 *
3628dff1399fSJeff Layton 	 * If the dl_time != 0, then we know that it has already been
3629dff1399fSJeff Layton 	 * queued for a lease break. Don't queue it again.
3630dff1399fSJeff Layton 	 */
3631f54fe962SJeff Layton 	spin_lock(&state_lock);
3632dff1399fSJeff Layton 	if (dp->dl_time == 0) {
36331da177e4SLinus Torvalds 		dp->dl_time = get_seconds();
363402e1215fSJeff Layton 		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
363502e1215fSJeff Layton 	}
363602e1215fSJeff Layton 	spin_unlock(&state_lock);
3637dff1399fSJeff Layton }
36381da177e4SLinus Torvalds 
36390162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
36400162ac2bSChristoph Hellwig 		struct rpc_task *task)
36410162ac2bSChristoph Hellwig {
36420162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
36430162ac2bSChristoph Hellwig 
3644a457974fSAndrew Elble 	if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID)
3645a457974fSAndrew Elble 	        return 1;
3646a457974fSAndrew Elble 
36470162ac2bSChristoph Hellwig 	switch (task->tk_status) {
36480162ac2bSChristoph Hellwig 	case 0:
36490162ac2bSChristoph Hellwig 		return 1;
36500162ac2bSChristoph Hellwig 	case -EBADHANDLE:
36510162ac2bSChristoph Hellwig 	case -NFS4ERR_BAD_STATEID:
36520162ac2bSChristoph Hellwig 		/*
36530162ac2bSChristoph Hellwig 		 * Race: client probably got cb_recall before open reply
36540162ac2bSChristoph Hellwig 		 * granting delegation.
36550162ac2bSChristoph Hellwig 		 */
36560162ac2bSChristoph Hellwig 		if (dp->dl_retries--) {
36570162ac2bSChristoph Hellwig 			rpc_delay(task, 2 * HZ);
36580162ac2bSChristoph Hellwig 			return 0;
36590162ac2bSChristoph Hellwig 		}
36600162ac2bSChristoph Hellwig 		/*FALLTHRU*/
36610162ac2bSChristoph Hellwig 	default:
36620162ac2bSChristoph Hellwig 		return -1;
36630162ac2bSChristoph Hellwig 	}
36640162ac2bSChristoph Hellwig }
36650162ac2bSChristoph Hellwig 
36660162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb)
36670162ac2bSChristoph Hellwig {
36680162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
36690162ac2bSChristoph Hellwig 
36700162ac2bSChristoph Hellwig 	nfs4_put_stid(&dp->dl_stid);
36710162ac2bSChristoph Hellwig }
36720162ac2bSChristoph Hellwig 
3673c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
36740162ac2bSChristoph Hellwig 	.prepare	= nfsd4_cb_recall_prepare,
36750162ac2bSChristoph Hellwig 	.done		= nfsd4_cb_recall_done,
36760162ac2bSChristoph Hellwig 	.release	= nfsd4_cb_recall_release,
36770162ac2bSChristoph Hellwig };
36780162ac2bSChristoph Hellwig 
367902e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
368002e1215fSJeff Layton {
368102e1215fSJeff Layton 	/*
368202e1215fSJeff Layton 	 * We're assuming the state code never drops its reference
368302e1215fSJeff Layton 	 * without first removing the lease.  Since we're in this lease
368402e1215fSJeff Layton 	 * callback (and since the lease code is serialized by the kernel
368502e1215fSJeff Layton 	 * lock) we know the server hasn't removed the lease yet, we know
368602e1215fSJeff Layton 	 * it's safe to take a reference.
368702e1215fSJeff Layton 	 */
368872c0b0fbSTrond Myklebust 	atomic_inc(&dp->dl_stid.sc_count);
3689f0b5de1bSChristoph Hellwig 	nfsd4_run_cb(&dp->dl_recall);
36906b57d9c8SJ. Bruce Fields }
36916b57d9c8SJ. Bruce Fields 
36921c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */
36934d01b7f5SJeff Layton static bool
36944d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl)
36956b57d9c8SJ. Bruce Fields {
36964d01b7f5SJeff Layton 	bool ret = false;
3697acfdf5c3SJ. Bruce Fields 	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
3698acfdf5c3SJ. Bruce Fields 	struct nfs4_delegation *dp;
36996b57d9c8SJ. Bruce Fields 
37007fa10cd1SJ. Bruce Fields 	if (!fp) {
37017fa10cd1SJ. Bruce Fields 		WARN(1, "(%p)->fl_owner NULL\n", fl);
37024d01b7f5SJeff Layton 		return ret;
37037fa10cd1SJ. Bruce Fields 	}
37047fa10cd1SJ. Bruce Fields 	if (fp->fi_had_conflict) {
37057fa10cd1SJ. Bruce Fields 		WARN(1, "duplicate break on %p\n", fp);
37064d01b7f5SJeff Layton 		return ret;
37077fa10cd1SJ. Bruce Fields 	}
37080272e1fdSJ. Bruce Fields 	/*
37090272e1fdSJ. Bruce Fields 	 * We don't want the locks code to timeout the lease for us;
3710acfdf5c3SJ. Bruce Fields 	 * we'll remove it ourself if a delegation isn't returned
37116b57d9c8SJ. Bruce Fields 	 * in time:
37120272e1fdSJ. Bruce Fields 	 */
37130272e1fdSJ. Bruce Fields 	fl->fl_break_time = 0;
37141da177e4SLinus Torvalds 
371502e1215fSJeff Layton 	spin_lock(&fp->fi_lock);
3716417c6629SJeff Layton 	fp->fi_had_conflict = true;
3717417c6629SJeff Layton 	/*
37184d01b7f5SJeff Layton 	 * If there are no delegations on the list, then return true
37194d01b7f5SJeff Layton 	 * so that the lease code will go ahead and delete it.
3720417c6629SJeff Layton 	 */
3721417c6629SJeff Layton 	if (list_empty(&fp->fi_delegations))
37224d01b7f5SJeff Layton 		ret = true;
3723417c6629SJeff Layton 	else
3724acfdf5c3SJ. Bruce Fields 		list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
37255d926e8cSJ. Bruce Fields 			nfsd_break_one_deleg(dp);
372602e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
37274d01b7f5SJeff Layton 	return ret;
37281da177e4SLinus Torvalds }
37291da177e4SLinus Torvalds 
3730c45198edSJeff Layton static int
37317448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
37327448cc37SJeff Layton 		     struct list_head *dispose)
37331da177e4SLinus Torvalds {
37341da177e4SLinus Torvalds 	if (arg & F_UNLCK)
3735c45198edSJeff Layton 		return lease_modify(onlist, arg, dispose);
37361da177e4SLinus Torvalds 	else
37371da177e4SLinus Torvalds 		return -EAGAIN;
37381da177e4SLinus Torvalds }
37391da177e4SLinus Torvalds 
37407b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = {
37418fb47a4fSJ. Bruce Fields 	.lm_break = nfsd_break_deleg_cb,
37428fb47a4fSJ. Bruce Fields 	.lm_change = nfsd_change_deleg_cb,
37431da177e4SLinus Torvalds };
37441da177e4SLinus Torvalds 
37457a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
37467a8711c9SJ. Bruce Fields {
37477a8711c9SJ. Bruce Fields 	if (nfsd4_has_session(cstate))
37487a8711c9SJ. Bruce Fields 		return nfs_ok;
37497a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid - 1)
37507a8711c9SJ. Bruce Fields 		return nfserr_replay_me;
37517a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid)
37527a8711c9SJ. Bruce Fields 		return nfs_ok;
37537a8711c9SJ. Bruce Fields 	return nfserr_bad_seqid;
37547a8711c9SJ. Bruce Fields }
37551da177e4SLinus Torvalds 
37564b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid,
37574b24ca7dSJeff Layton 		struct nfsd4_compound_state *cstate,
37584b24ca7dSJeff Layton 		struct nfsd_net *nn)
37594b24ca7dSJeff Layton {
37604b24ca7dSJeff Layton 	struct nfs4_client *found;
37614b24ca7dSJeff Layton 
37624b24ca7dSJeff Layton 	if (cstate->clp) {
37634b24ca7dSJeff Layton 		found = cstate->clp;
37644b24ca7dSJeff Layton 		if (!same_clid(&found->cl_clientid, clid))
37654b24ca7dSJeff Layton 			return nfserr_stale_clientid;
37664b24ca7dSJeff Layton 		return nfs_ok;
37674b24ca7dSJeff Layton 	}
37684b24ca7dSJeff Layton 
37694b24ca7dSJeff Layton 	if (STALE_CLIENTID(clid, nn))
37704b24ca7dSJeff Layton 		return nfserr_stale_clientid;
37714b24ca7dSJeff Layton 
37724b24ca7dSJeff Layton 	/*
37734b24ca7dSJeff Layton 	 * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
37744b24ca7dSJeff Layton 	 * cached already then we know this is for is for v4.0 and "sessions"
37754b24ca7dSJeff Layton 	 * will be false.
37764b24ca7dSJeff Layton 	 */
37774b24ca7dSJeff Layton 	WARN_ON_ONCE(cstate->session);
37783e339f96STrond Myklebust 	spin_lock(&nn->client_lock);
37794b24ca7dSJeff Layton 	found = find_confirmed_client(clid, false, nn);
37803e339f96STrond Myklebust 	if (!found) {
37813e339f96STrond Myklebust 		spin_unlock(&nn->client_lock);
37824b24ca7dSJeff Layton 		return nfserr_expired;
37833e339f96STrond Myklebust 	}
37843e339f96STrond Myklebust 	atomic_inc(&found->cl_refcount);
37853e339f96STrond Myklebust 	spin_unlock(&nn->client_lock);
37864b24ca7dSJeff Layton 
37874b24ca7dSJeff Layton 	/* Cache the nfs4_client in cstate! */
37884b24ca7dSJeff Layton 	cstate->clp = found;
37894b24ca7dSJeff Layton 	return nfs_ok;
37904b24ca7dSJeff Layton }
37914b24ca7dSJeff Layton 
3792b37ad28bSAl Viro __be32
37936668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate,
37943320fef1SStanislav Kinsbursky 		    struct nfsd4_open *open, struct nfsd_net *nn)
37951da177e4SLinus Torvalds {
37961da177e4SLinus Torvalds 	clientid_t *clientid = &open->op_clientid;
37971da177e4SLinus Torvalds 	struct nfs4_client *clp = NULL;
37981da177e4SLinus Torvalds 	unsigned int strhashval;
3799fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = NULL;
38004cdc951bSJ. Bruce Fields 	__be32 status;
38011da177e4SLinus Torvalds 
38022c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(&open->op_clientid, nn))
38031da177e4SLinus Torvalds 		return nfserr_stale_clientid;
380432513b40SJ. Bruce Fields 	/*
380532513b40SJ. Bruce Fields 	 * In case we need it later, after we've already created the
380632513b40SJ. Bruce Fields 	 * file and don't want to risk a further failure:
380732513b40SJ. Bruce Fields 	 */
380832513b40SJ. Bruce Fields 	open->op_file = nfsd4_alloc_file();
380932513b40SJ. Bruce Fields 	if (open->op_file == NULL)
381032513b40SJ. Bruce Fields 		return nfserr_jukebox;
38111da177e4SLinus Torvalds 
381213d6f66bSTrond Myklebust 	status = lookup_clientid(clientid, cstate, nn);
381313d6f66bSTrond Myklebust 	if (status)
381413d6f66bSTrond Myklebust 		return status;
381513d6f66bSTrond Myklebust 	clp = cstate->clp;
38162d91e895STrond Myklebust 
3817d4f0489fSTrond Myklebust 	strhashval = ownerstr_hashval(&open->op_owner);
3818d4f0489fSTrond Myklebust 	oo = find_openstateowner_str(strhashval, open, clp);
38192d91e895STrond Myklebust 	open->op_openowner = oo;
38202d91e895STrond Myklebust 	if (!oo) {
3821bcf130f9SJ. Bruce Fields 		goto new_owner;
38220f442aa2SJ. Bruce Fields 	}
3823dad1c067SJ. Bruce Fields 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
38240f442aa2SJ. Bruce Fields 		/* Replace unconfirmed owners without checking for replay. */
3825fe0750e5SJ. Bruce Fields 		release_openowner(oo);
3826fe0750e5SJ. Bruce Fields 		open->op_openowner = NULL;
3827bcf130f9SJ. Bruce Fields 		goto new_owner;
38280f442aa2SJ. Bruce Fields 	}
38294cdc951bSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
38304cdc951bSJ. Bruce Fields 	if (status)
38314cdc951bSJ. Bruce Fields 		return status;
38324cdc951bSJ. Bruce Fields 	goto alloc_stateid;
3833bcf130f9SJ. Bruce Fields new_owner:
383413d6f66bSTrond Myklebust 	oo = alloc_init_open_stateowner(strhashval, open, cstate);
3835fe0750e5SJ. Bruce Fields 	if (oo == NULL)
38363e772463SJ. Bruce Fields 		return nfserr_jukebox;
3837fe0750e5SJ. Bruce Fields 	open->op_openowner = oo;
38384cdc951bSJ. Bruce Fields alloc_stateid:
3839b49e084dSJeff Layton 	open->op_stp = nfs4_alloc_open_stateid(clp);
38404cdc951bSJ. Bruce Fields 	if (!open->op_stp)
38414cdc951bSJ. Bruce Fields 		return nfserr_jukebox;
38428287f009SSachin Bhamare 
38438287f009SSachin Bhamare 	if (nfsd4_has_session(cstate) &&
38448287f009SSachin Bhamare 	    (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) {
38458287f009SSachin Bhamare 		open->op_odstate = alloc_clnt_odstate(clp);
38468287f009SSachin Bhamare 		if (!open->op_odstate)
38478287f009SSachin Bhamare 			return nfserr_jukebox;
38488287f009SSachin Bhamare 	}
38498287f009SSachin Bhamare 
38500f442aa2SJ. Bruce Fields 	return nfs_ok;
38511da177e4SLinus Torvalds }
38521da177e4SLinus Torvalds 
3853b37ad28bSAl Viro static inline __be32
38544a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
38554a6e43e6SNeilBrown {
38564a6e43e6SNeilBrown 	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
38574a6e43e6SNeilBrown 		return nfserr_openmode;
38584a6e43e6SNeilBrown 	else
38594a6e43e6SNeilBrown 		return nfs_ok;
38604a6e43e6SNeilBrown }
38614a6e43e6SNeilBrown 
3862c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access)
386324a0111eSJ. Bruce Fields {
386424a0111eSJ. Bruce Fields 	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
386524a0111eSJ. Bruce Fields }
386624a0111eSJ. Bruce Fields 
386738c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
3868f459e453SJ. Bruce Fields {
3869f459e453SJ. Bruce Fields 	struct nfs4_stid *ret;
3870f459e453SJ. Bruce Fields 
387138c2f4b1SJ. Bruce Fields 	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
3872f459e453SJ. Bruce Fields 	if (!ret)
3873f459e453SJ. Bruce Fields 		return NULL;
3874f459e453SJ. Bruce Fields 	return delegstateid(ret);
3875f459e453SJ. Bruce Fields }
3876f459e453SJ. Bruce Fields 
38778b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
38788b289b2cSJ. Bruce Fields {
38798b289b2cSJ. Bruce Fields 	return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
38808b289b2cSJ. Bruce Fields 	       open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
38818b289b2cSJ. Bruce Fields }
38828b289b2cSJ. Bruce Fields 
3883b37ad28bSAl Viro static __be32
388441d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
3885567d9829SNeilBrown 		struct nfs4_delegation **dp)
3886567d9829SNeilBrown {
3887567d9829SNeilBrown 	int flags;
3888b37ad28bSAl Viro 	__be32 status = nfserr_bad_stateid;
3889dcd94cc2STrond Myklebust 	struct nfs4_delegation *deleg;
3890567d9829SNeilBrown 
3891dcd94cc2STrond Myklebust 	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
3892dcd94cc2STrond Myklebust 	if (deleg == NULL)
3893c44c5eebSNeilBrown 		goto out;
389424a0111eSJ. Bruce Fields 	flags = share_access_to_flags(open->op_share_access);
3895dcd94cc2STrond Myklebust 	status = nfs4_check_delegmode(deleg, flags);
3896dcd94cc2STrond Myklebust 	if (status) {
3897dcd94cc2STrond Myklebust 		nfs4_put_stid(&deleg->dl_stid);
3898dcd94cc2STrond Myklebust 		goto out;
3899dcd94cc2STrond Myklebust 	}
3900dcd94cc2STrond Myklebust 	*dp = deleg;
3901c44c5eebSNeilBrown out:
39028b289b2cSJ. Bruce Fields 	if (!nfsd4_is_deleg_cur(open))
3903c44c5eebSNeilBrown 		return nfs_ok;
3904c44c5eebSNeilBrown 	if (status)
3905c44c5eebSNeilBrown 		return status;
3906dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
3907c44c5eebSNeilBrown 	return nfs_ok;
3908567d9829SNeilBrown }
3909567d9829SNeilBrown 
391021fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access)
391121fb4016SJ. Bruce Fields {
391221fb4016SJ. Bruce Fields 	int flags = 0;
391321fb4016SJ. Bruce Fields 
391421fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
391521fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_READ;
391621fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
391721fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_WRITE;
391821fb4016SJ. Bruce Fields 	return flags;
391921fb4016SJ. Bruce Fields }
392021fb4016SJ. Bruce Fields 
3921b37ad28bSAl Viro static inline __be32
39221da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
39231da177e4SLinus Torvalds 		struct nfsd4_open *open)
39241da177e4SLinus Torvalds {
39251da177e4SLinus Torvalds 	struct iattr iattr = {
39261da177e4SLinus Torvalds 		.ia_valid = ATTR_SIZE,
39271da177e4SLinus Torvalds 		.ia_size = 0,
39281da177e4SLinus Torvalds 	};
39291da177e4SLinus Torvalds 	if (!open->op_truncate)
39301da177e4SLinus Torvalds 		return 0;
39311da177e4SLinus Torvalds 	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
39329246585aSAl Viro 		return nfserr_inval;
39331da177e4SLinus Torvalds 	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
39341da177e4SLinus Torvalds }
39351da177e4SLinus Torvalds 
39367e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
39376eb3a1d0SJeff Layton 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
39386eb3a1d0SJeff Layton 		struct nfsd4_open *open)
39397e6a72e5SChristoph Hellwig {
3940de18643dSTrond Myklebust 	struct file *filp = NULL;
39417e6a72e5SChristoph Hellwig 	__be32 status;
39427e6a72e5SChristoph Hellwig 	int oflag = nfs4_access_to_omode(open->op_share_access);
39437e6a72e5SChristoph Hellwig 	int access = nfs4_access_to_access(open->op_share_access);
3944baeb4ff0SJeff Layton 	unsigned char old_access_bmap, old_deny_bmap;
39457e6a72e5SChristoph Hellwig 
3946de18643dSTrond Myklebust 	spin_lock(&fp->fi_lock);
3947baeb4ff0SJeff Layton 
3948baeb4ff0SJeff Layton 	/*
3949baeb4ff0SJeff Layton 	 * Are we trying to set a deny mode that would conflict with
3950baeb4ff0SJeff Layton 	 * current access?
3951baeb4ff0SJeff Layton 	 */
3952baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
3953baeb4ff0SJeff Layton 	if (status != nfs_ok) {
3954baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
3955baeb4ff0SJeff Layton 		goto out;
3956baeb4ff0SJeff Layton 	}
3957baeb4ff0SJeff Layton 
3958baeb4ff0SJeff Layton 	/* set access to the file */
3959baeb4ff0SJeff Layton 	status = nfs4_file_get_access(fp, open->op_share_access);
3960baeb4ff0SJeff Layton 	if (status != nfs_ok) {
3961baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
3962baeb4ff0SJeff Layton 		goto out;
3963baeb4ff0SJeff Layton 	}
3964baeb4ff0SJeff Layton 
3965baeb4ff0SJeff Layton 	/* Set access bits in stateid */
3966baeb4ff0SJeff Layton 	old_access_bmap = stp->st_access_bmap;
3967baeb4ff0SJeff Layton 	set_access(open->op_share_access, stp);
3968baeb4ff0SJeff Layton 
3969baeb4ff0SJeff Layton 	/* Set new deny mask */
3970baeb4ff0SJeff Layton 	old_deny_bmap = stp->st_deny_bmap;
3971baeb4ff0SJeff Layton 	set_deny(open->op_share_deny, stp);
3972baeb4ff0SJeff Layton 	fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH);
3973baeb4ff0SJeff Layton 
39747e6a72e5SChristoph Hellwig 	if (!fp->fi_fds[oflag]) {
3975de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
3976de18643dSTrond Myklebust 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
39777e6a72e5SChristoph Hellwig 		if (status)
3978baeb4ff0SJeff Layton 			goto out_put_access;
3979de18643dSTrond Myklebust 		spin_lock(&fp->fi_lock);
3980de18643dSTrond Myklebust 		if (!fp->fi_fds[oflag]) {
3981de18643dSTrond Myklebust 			fp->fi_fds[oflag] = filp;
3982de18643dSTrond Myklebust 			filp = NULL;
3983de18643dSTrond Myklebust 		}
39847e6a72e5SChristoph Hellwig 	}
3985de18643dSTrond Myklebust 	spin_unlock(&fp->fi_lock);
3986de18643dSTrond Myklebust 	if (filp)
3987de18643dSTrond Myklebust 		fput(filp);
39887e6a72e5SChristoph Hellwig 
39897e6a72e5SChristoph Hellwig 	status = nfsd4_truncate(rqstp, cur_fh, open);
39907e6a72e5SChristoph Hellwig 	if (status)
39917e6a72e5SChristoph Hellwig 		goto out_put_access;
39927e6a72e5SChristoph Hellwig out:
39937e6a72e5SChristoph Hellwig 	return status;
3994baeb4ff0SJeff Layton out_put_access:
3995baeb4ff0SJeff Layton 	stp->st_access_bmap = old_access_bmap;
3996baeb4ff0SJeff Layton 	nfs4_file_put_access(fp, open->op_share_access);
3997baeb4ff0SJeff Layton 	reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp);
3998baeb4ff0SJeff Layton 	goto out;
39997e6a72e5SChristoph Hellwig }
40007e6a72e5SChristoph Hellwig 
4001b37ad28bSAl Viro static __be32
4002dcef0413SJ. Bruce Fields nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
40031da177e4SLinus Torvalds {
4004b37ad28bSAl Viro 	__be32 status;
40056ac75368SArnd Bergmann 	unsigned char old_deny_bmap = stp->st_deny_bmap;
40061da177e4SLinus Torvalds 
40076eb3a1d0SJeff Layton 	if (!test_access(open->op_share_access, stp))
4008baeb4ff0SJeff Layton 		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
40097e6a72e5SChristoph Hellwig 
4010baeb4ff0SJeff Layton 	/* test and set deny mode */
4011baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
4012baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
4013baeb4ff0SJeff Layton 	if (status == nfs_ok) {
4014baeb4ff0SJeff Layton 		set_deny(open->op_share_deny, stp);
4015baeb4ff0SJeff Layton 		fp->fi_share_deny |=
4016baeb4ff0SJeff Layton 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
40171da177e4SLinus Torvalds 	}
4018baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
40191da177e4SLinus Torvalds 
4020baeb4ff0SJeff Layton 	if (status != nfs_ok)
4021baeb4ff0SJeff Layton 		return status;
4022baeb4ff0SJeff Layton 
4023baeb4ff0SJeff Layton 	status = nfsd4_truncate(rqstp, cur_fh, open);
4024baeb4ff0SJeff Layton 	if (status != nfs_ok)
4025baeb4ff0SJeff Layton 		reset_union_bmap_deny(old_deny_bmap, stp);
4026baeb4ff0SJeff Layton 	return status;
4027baeb4ff0SJeff Layton }
40281da177e4SLinus Torvalds 
402914a24e99SJ. Bruce Fields /* Should we give out recallable state?: */
403014a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
403114a24e99SJ. Bruce Fields {
403214a24e99SJ. Bruce Fields 	if (clp->cl_cb_state == NFSD4_CB_UP)
403314a24e99SJ. Bruce Fields 		return true;
403414a24e99SJ. Bruce Fields 	/*
403514a24e99SJ. Bruce Fields 	 * In the sessions case, since we don't have to establish a
403614a24e99SJ. Bruce Fields 	 * separate connection for callbacks, we assume it's OK
403714a24e99SJ. Bruce Fields 	 * until we hear otherwise:
403814a24e99SJ. Bruce Fields 	 */
403914a24e99SJ. Bruce Fields 	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
404014a24e99SJ. Bruce Fields }
404114a24e99SJ. Bruce Fields 
4042d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
404322d38c4cSJ. Bruce Fields {
404422d38c4cSJ. Bruce Fields 	struct file_lock *fl;
404522d38c4cSJ. Bruce Fields 
404622d38c4cSJ. Bruce Fields 	fl = locks_alloc_lock();
404722d38c4cSJ. Bruce Fields 	if (!fl)
404822d38c4cSJ. Bruce Fields 		return NULL;
404922d38c4cSJ. Bruce Fields 	fl->fl_lmops = &nfsd_lease_mng_ops;
4050617588d5SJ. Bruce Fields 	fl->fl_flags = FL_DELEG;
405122d38c4cSJ. Bruce Fields 	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
405222d38c4cSJ. Bruce Fields 	fl->fl_end = OFFSET_MAX;
4053d564fbecSJeff Layton 	fl->fl_owner = (fl_owner_t)fp;
405422d38c4cSJ. Bruce Fields 	fl->fl_pid = current->tgid;
405522d38c4cSJ. Bruce Fields 	return fl;
405622d38c4cSJ. Bruce Fields }
405722d38c4cSJ. Bruce Fields 
405834ed9872SAndrew Elble /**
405934ed9872SAndrew Elble  * nfs4_setlease - Obtain a delegation by requesting lease from vfs layer
406034ed9872SAndrew Elble  * @dp:   a pointer to the nfs4_delegation we're adding.
406134ed9872SAndrew Elble  *
406234ed9872SAndrew Elble  * Return:
406334ed9872SAndrew Elble  *      On success: Return code will be 0 on success.
406434ed9872SAndrew Elble  *
406534ed9872SAndrew Elble  *      On error: -EAGAIN if there was an existing delegation.
406634ed9872SAndrew Elble  *                 nonzero if there is an error in other cases.
406734ed9872SAndrew Elble  *
406834ed9872SAndrew Elble  */
406934ed9872SAndrew Elble 
407099c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp)
4071edab9782SJ. Bruce Fields {
407211b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
4073efde6b4dSKinglong Mee 	struct file_lock *fl;
4074417c6629SJeff Layton 	struct file *filp;
4075417c6629SJeff Layton 	int status = 0;
4076edab9782SJ. Bruce Fields 
4077d564fbecSJeff Layton 	fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ);
4078edab9782SJ. Bruce Fields 	if (!fl)
4079edab9782SJ. Bruce Fields 		return -ENOMEM;
4080417c6629SJeff Layton 	filp = find_readable_file(fp);
4081417c6629SJeff Layton 	if (!filp) {
4082417c6629SJeff Layton 		/* We should always have a readable file here */
4083417c6629SJeff Layton 		WARN_ON_ONCE(1);
4084af9dbaf4SKinglong Mee 		locks_free_lock(fl);
4085417c6629SJeff Layton 		return -EBADF;
4086417c6629SJeff Layton 	}
4087417c6629SJeff Layton 	fl->fl_file = filp;
4088e6f5c789SJeff Layton 	status = vfs_setlease(filp, fl->fl_type, &fl, NULL);
40891c7dd2ffSJeff Layton 	if (fl)
4090417c6629SJeff Layton 		locks_free_lock(fl);
40911c7dd2ffSJeff Layton 	if (status)
4092417c6629SJeff Layton 		goto out_fput;
4093cdc97505SBenny Halevy 	spin_lock(&state_lock);
4094417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
4095417c6629SJeff Layton 	/* Did the lease get broken before we took the lock? */
4096417c6629SJeff Layton 	status = -EAGAIN;
4097417c6629SJeff Layton 	if (fp->fi_had_conflict)
4098417c6629SJeff Layton 		goto out_unlock;
4099417c6629SJeff Layton 	/* Race breaker */
41000c637be8SJeff Layton 	if (fp->fi_deleg_file) {
410134ed9872SAndrew Elble 		status = hash_delegation_locked(dp, fp);
4102417c6629SJeff Layton 		goto out_unlock;
4103417c6629SJeff Layton 	}
4104417c6629SJeff Layton 	fp->fi_deleg_file = filp;
410534ed9872SAndrew Elble 	fp->fi_delegees = 0;
410634ed9872SAndrew Elble 	status = hash_delegation_locked(dp, fp);
4107417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4108cdc97505SBenny Halevy 	spin_unlock(&state_lock);
410934ed9872SAndrew Elble 	if (status) {
411034ed9872SAndrew Elble 		/* Should never happen, this is a new fi_deleg_file  */
411134ed9872SAndrew Elble 		WARN_ON_ONCE(1);
411234ed9872SAndrew Elble 		goto out_fput;
411334ed9872SAndrew Elble 	}
4114acfdf5c3SJ. Bruce Fields 	return 0;
4115417c6629SJeff Layton out_unlock:
4116417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4117417c6629SJeff Layton 	spin_unlock(&state_lock);
4118417c6629SJeff Layton out_fput:
4119417c6629SJeff Layton 	fput(filp);
4120e873088fSJ. Bruce Fields 	return status;
4121acfdf5c3SJ. Bruce Fields }
4122acfdf5c3SJ. Bruce Fields 
41230b26693cSJeff Layton static struct nfs4_delegation *
41240b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
41258287f009SSachin Bhamare 		    struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
4126acfdf5c3SJ. Bruce Fields {
41270b26693cSJeff Layton 	int status;
41280b26693cSJeff Layton 	struct nfs4_delegation *dp;
4129417c6629SJeff Layton 
4130bf7bd3e9SJ. Bruce Fields 	if (fp->fi_had_conflict)
41310b26693cSJeff Layton 		return ERR_PTR(-EAGAIN);
41320b26693cSJeff Layton 
413334ed9872SAndrew Elble 	spin_lock(&state_lock);
413434ed9872SAndrew Elble 	spin_lock(&fp->fi_lock);
413534ed9872SAndrew Elble 	status = nfs4_get_existing_delegation(clp, fp);
413634ed9872SAndrew Elble 	spin_unlock(&fp->fi_lock);
413734ed9872SAndrew Elble 	spin_unlock(&state_lock);
413834ed9872SAndrew Elble 
413934ed9872SAndrew Elble 	if (status)
414034ed9872SAndrew Elble 		return ERR_PTR(status);
414134ed9872SAndrew Elble 
41428287f009SSachin Bhamare 	dp = alloc_init_deleg(clp, fh, odstate);
41430b26693cSJeff Layton 	if (!dp)
41440b26693cSJeff Layton 		return ERR_PTR(-ENOMEM);
41450b26693cSJeff Layton 
4146bf7bd3e9SJ. Bruce Fields 	get_nfs4_file(fp);
4147cdc97505SBenny Halevy 	spin_lock(&state_lock);
4148417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
414911b9164aSTrond Myklebust 	dp->dl_stid.sc_file = fp;
41500c637be8SJeff Layton 	if (!fp->fi_deleg_file) {
4151417c6629SJeff Layton 		spin_unlock(&fp->fi_lock);
4152417c6629SJeff Layton 		spin_unlock(&state_lock);
41530b26693cSJeff Layton 		status = nfs4_setlease(dp);
41540b26693cSJeff Layton 		goto out;
4155417c6629SJeff Layton 	}
4156acfdf5c3SJ. Bruce Fields 	if (fp->fi_had_conflict) {
4157417c6629SJeff Layton 		status = -EAGAIN;
4158417c6629SJeff Layton 		goto out_unlock;
4159acfdf5c3SJ. Bruce Fields 	}
416034ed9872SAndrew Elble 	status = hash_delegation_locked(dp, fp);
4161417c6629SJeff Layton out_unlock:
4162417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4163cdc97505SBenny Halevy 	spin_unlock(&state_lock);
41640b26693cSJeff Layton out:
41650b26693cSJeff Layton 	if (status) {
41668287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
41676011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
41680b26693cSJeff Layton 		return ERR_PTR(status);
41690b26693cSJeff Layton 	}
41700b26693cSJeff Layton 	return dp;
4171edab9782SJ. Bruce Fields }
4172edab9782SJ. Bruce Fields 
41734aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
41744aa8913cSBenny Halevy {
41754aa8913cSBenny Halevy 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
41764aa8913cSBenny Halevy 	if (status == -EAGAIN)
41774aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_CONTENTION;
41784aa8913cSBenny Halevy 	else {
41794aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_RESOURCE;
41804aa8913cSBenny Halevy 		switch (open->op_deleg_want) {
41814aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_READ_DELEG:
41824aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_WRITE_DELEG:
41834aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_ANY_DELEG:
41844aa8913cSBenny Halevy 			break;
41854aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_CANCEL:
41864aa8913cSBenny Halevy 			open->op_why_no_deleg = WND4_CANCELLED;
41874aa8913cSBenny Halevy 			break;
41884aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_NO_DELEG:
4189063b0fb9SJ. Bruce Fields 			WARN_ON_ONCE(1);
41904aa8913cSBenny Halevy 		}
41914aa8913cSBenny Halevy 	}
41924aa8913cSBenny Halevy }
41934aa8913cSBenny Halevy 
41941da177e4SLinus Torvalds /*
41951da177e4SLinus Torvalds  * Attempt to hand out a delegation.
419699c41515SJ. Bruce Fields  *
419799c41515SJ. Bruce Fields  * Note we don't support write delegations, and won't until the vfs has
419899c41515SJ. Bruce Fields  * proper support for them.
41991da177e4SLinus Torvalds  */
42001da177e4SLinus Torvalds static void
42014cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
42024cf59221SJeff Layton 			struct nfs4_ol_stateid *stp)
42031da177e4SLinus Torvalds {
42041da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
42054cf59221SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_stateowner);
42064cf59221SJeff Layton 	struct nfs4_client *clp = stp->st_stid.sc_client;
420714a24e99SJ. Bruce Fields 	int cb_up;
420899c41515SJ. Bruce Fields 	int status = 0;
42091da177e4SLinus Torvalds 
4210fe0750e5SJ. Bruce Fields 	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
42117b190fecSNeilBrown 	open->op_recall = 0;
42127b190fecSNeilBrown 	switch (open->op_claim_type) {
42137b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_PREVIOUS:
42142bf23875SJ. Bruce Fields 			if (!cb_up)
42157b190fecSNeilBrown 				open->op_recall = 1;
421699c41515SJ. Bruce Fields 			if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
421799c41515SJ. Bruce Fields 				goto out_no_deleg;
42187b190fecSNeilBrown 			break;
42197b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_NULL:
4220ed47b062SMing Chen 		case NFS4_OPEN_CLAIM_FH:
422199c41515SJ. Bruce Fields 			/*
422299c41515SJ. Bruce Fields 			 * Let's not give out any delegations till everyone's
4223c87fb4a3SJ. Bruce Fields 			 * had the chance to reclaim theirs, *and* until
4224c87fb4a3SJ. Bruce Fields 			 * NLM locks have all been reclaimed:
422599c41515SJ. Bruce Fields 			 */
42264cf59221SJeff Layton 			if (locks_in_grace(clp->net))
422799c41515SJ. Bruce Fields 				goto out_no_deleg;
4228dad1c067SJ. Bruce Fields 			if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
422999c41515SJ. Bruce Fields 				goto out_no_deleg;
42309a0590aeSSteve Dickson 			/*
42319a0590aeSSteve Dickson 			 * Also, if the file was opened for write or
42329a0590aeSSteve Dickson 			 * create, there's a good chance the client's
42339a0590aeSSteve Dickson 			 * about to write to it, resulting in an
42349a0590aeSSteve Dickson 			 * immediate recall (since we don't support
42359a0590aeSSteve Dickson 			 * write delegations):
42369a0590aeSSteve Dickson 			 */
42371da177e4SLinus Torvalds 			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
423899c41515SJ. Bruce Fields 				goto out_no_deleg;
423999c41515SJ. Bruce Fields 			if (open->op_create == NFS4_OPEN_CREATE)
424099c41515SJ. Bruce Fields 				goto out_no_deleg;
42417b190fecSNeilBrown 			break;
42427b190fecSNeilBrown 		default:
424399c41515SJ. Bruce Fields 			goto out_no_deleg;
42447b190fecSNeilBrown 	}
42458287f009SSachin Bhamare 	dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
42460b26693cSJeff Layton 	if (IS_ERR(dp))
4247dd239cc0SJ. Bruce Fields 		goto out_no_deleg;
42481da177e4SLinus Torvalds 
4249d5477a8dSJ. Bruce Fields 	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
42501da177e4SLinus Torvalds 
42518c10cbdbSBenny Halevy 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
4252d5477a8dSJ. Bruce Fields 		STATEID_VAL(&dp->dl_stid.sc_stateid));
425399c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
425467cb1279STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
4255dd239cc0SJ. Bruce Fields 	return;
4256dd239cc0SJ. Bruce Fields out_no_deleg:
425799c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
42587b190fecSNeilBrown 	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
4259d08d32e6SJ. Bruce Fields 	    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
42601da177e4SLinus Torvalds 		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
4261d08d32e6SJ. Bruce Fields 		open->op_recall = 1;
4262d08d32e6SJ. Bruce Fields 	}
4263dd239cc0SJ. Bruce Fields 
4264dd239cc0SJ. Bruce Fields 	/* 4.1 client asking for a delegation? */
4265dd239cc0SJ. Bruce Fields 	if (open->op_deleg_want)
4266dd239cc0SJ. Bruce Fields 		nfsd4_open_deleg_none_ext(open, status);
4267dd239cc0SJ. Bruce Fields 	return;
42681da177e4SLinus Torvalds }
42691da177e4SLinus Torvalds 
4270e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
4271e27f49c3SBenny Halevy 					struct nfs4_delegation *dp)
4272e27f49c3SBenny Halevy {
4273e27f49c3SBenny Halevy 	if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
4274e27f49c3SBenny Halevy 	    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
4275e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4276e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
4277e27f49c3SBenny Halevy 	} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
4278e27f49c3SBenny Halevy 		   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
4279e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4280e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
4281e27f49c3SBenny Halevy 	}
4282e27f49c3SBenny Halevy 	/* Otherwise the client must be confused wanting a delegation
4283e27f49c3SBenny Halevy 	 * it already has, therefore we don't return
4284e27f49c3SBenny Halevy 	 * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
4285e27f49c3SBenny Halevy 	 */
4286e27f49c3SBenny Halevy }
4287e27f49c3SBenny Halevy 
4288b37ad28bSAl Viro __be32
42891da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
42901da177e4SLinus Torvalds {
42916668958fSAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
429238c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
42931da177e4SLinus Torvalds 	struct nfs4_file *fp = NULL;
4294dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
42957fc0564eSAndrew Elble 	struct nfs4_ol_stateid *swapstp = NULL;
4296567d9829SNeilBrown 	struct nfs4_delegation *dp = NULL;
4297b37ad28bSAl Viro 	__be32 status;
42981da177e4SLinus Torvalds 
42991da177e4SLinus Torvalds 	/*
43001da177e4SLinus Torvalds 	 * Lookup file; if found, lookup stateid and check open request,
43011da177e4SLinus Torvalds 	 * and check for delegations in the process of being recalled.
43021da177e4SLinus Torvalds 	 * If not found, create the nfs4_file struct
43031da177e4SLinus Torvalds 	 */
4304f9c00c3aSJeff Layton 	fp = find_or_add_file(open->op_file, &current_fh->fh_handle);
4305950e0118STrond Myklebust 	if (fp != open->op_file) {
430641d22663SJ. Bruce Fields 		status = nfs4_check_deleg(cl, open, &dp);
4307c44c5eebSNeilBrown 		if (status)
4308c44c5eebSNeilBrown 			goto out;
43097fc0564eSAndrew Elble 		spin_lock(&fp->fi_lock);
4310a46cb7f2SJeff Layton 		stp = nfsd4_find_existing_open(fp, open);
43117fc0564eSAndrew Elble 		spin_unlock(&fp->fi_lock);
43121da177e4SLinus Torvalds 	} else {
4313950e0118STrond Myklebust 		open->op_file = NULL;
4314c44c5eebSNeilBrown 		status = nfserr_bad_stateid;
43158b289b2cSJ. Bruce Fields 		if (nfsd4_is_deleg_cur(open))
4316c44c5eebSNeilBrown 			goto out;
43171da177e4SLinus Torvalds 	}
43181da177e4SLinus Torvalds 
43191da177e4SLinus Torvalds 	/*
43201da177e4SLinus Torvalds 	 * OPEN the file, or upgrade an existing OPEN.
43211da177e4SLinus Torvalds 	 * If truncate fails, the OPEN fails.
43221da177e4SLinus Torvalds 	 */
43231da177e4SLinus Torvalds 	if (stp) {
43241da177e4SLinus Torvalds 		/* Stateid was found, this is an OPEN upgrade */
432535a92fe8SJeff Layton 		down_read(&stp->st_rwsem);
4326f9d7562fSJ. Bruce Fields 		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
432735a92fe8SJeff Layton 		if (status) {
432835a92fe8SJeff Layton 			up_read(&stp->st_rwsem);
43291da177e4SLinus Torvalds 			goto out;
433035a92fe8SJeff Layton 		}
43311da177e4SLinus Torvalds 	} else {
43324cdc951bSJ. Bruce Fields 		stp = open->op_stp;
43334cdc951bSJ. Bruce Fields 		open->op_stp = NULL;
43347fc0564eSAndrew Elble 		swapstp = init_open_stateid(stp, fp, open);
43357fc0564eSAndrew Elble 		if (swapstp) {
43367fc0564eSAndrew Elble 			nfs4_put_stid(&stp->st_stid);
43377fc0564eSAndrew Elble 			stp = swapstp;
43387fc0564eSAndrew Elble 			down_read(&stp->st_rwsem);
43397fc0564eSAndrew Elble 			status = nfs4_upgrade_open(rqstp, fp, current_fh,
43407fc0564eSAndrew Elble 						stp, open);
43417fc0564eSAndrew Elble 			if (status) {
43427fc0564eSAndrew Elble 				up_read(&stp->st_rwsem);
43437fc0564eSAndrew Elble 				goto out;
43447fc0564eSAndrew Elble 			}
43457fc0564eSAndrew Elble 			goto upgrade_out;
43467fc0564eSAndrew Elble 		}
434735a92fe8SJeff Layton 		down_read(&stp->st_rwsem);
43486eb3a1d0SJeff Layton 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
43496eb3a1d0SJeff Layton 		if (status) {
435035a92fe8SJeff Layton 			up_read(&stp->st_rwsem);
43516eb3a1d0SJeff Layton 			release_open_stateid(stp);
43526eb3a1d0SJeff Layton 			goto out;
43536eb3a1d0SJeff Layton 		}
43548287f009SSachin Bhamare 
43558287f009SSachin Bhamare 		stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp,
43568287f009SSachin Bhamare 							open->op_odstate);
43578287f009SSachin Bhamare 		if (stp->st_clnt_odstate == open->op_odstate)
43588287f009SSachin Bhamare 			open->op_odstate = NULL;
43591da177e4SLinus Torvalds 	}
43607fc0564eSAndrew Elble upgrade_out:
43619767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
436235a92fe8SJeff Layton 	up_read(&stp->st_rwsem);
43631da177e4SLinus Torvalds 
4364d24433cdSBenny Halevy 	if (nfsd4_has_session(&resp->cstate)) {
4365d24433cdSBenny Halevy 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
4366d24433cdSBenny Halevy 			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4367d24433cdSBenny Halevy 			open->op_why_no_deleg = WND4_NOT_WANTED;
4368d24433cdSBenny Halevy 			goto nodeleg;
4369d24433cdSBenny Halevy 		}
4370d24433cdSBenny Halevy 	}
4371d24433cdSBenny Halevy 
43721da177e4SLinus Torvalds 	/*
43731da177e4SLinus Torvalds 	* Attempt to hand out a delegation. No error return, because the
43741da177e4SLinus Torvalds 	* OPEN succeeds even if we fail.
43751da177e4SLinus Torvalds 	*/
43764cf59221SJeff Layton 	nfs4_open_delegation(current_fh, open, stp);
4377d24433cdSBenny Halevy nodeleg:
43781da177e4SLinus Torvalds 	status = nfs_ok;
43791da177e4SLinus Torvalds 
43808c10cbdbSBenny Halevy 	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
4381dcef0413SJ. Bruce Fields 		STATEID_VAL(&stp->st_stid.sc_stateid));
43821da177e4SLinus Torvalds out:
4383d24433cdSBenny Halevy 	/* 4.1 client trying to upgrade/downgrade delegation? */
4384d24433cdSBenny Halevy 	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
4385e27f49c3SBenny Halevy 	    open->op_deleg_want)
4386e27f49c3SBenny Halevy 		nfsd4_deleg_xgrade_none_ext(open, dp);
4387d24433cdSBenny Halevy 
438813cd2184SNeilBrown 	if (fp)
438913cd2184SNeilBrown 		put_nfs4_file(fp);
439037515177SNeilBrown 	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
439187186022SKinglong Mee 		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
43921da177e4SLinus Torvalds 	/*
43931da177e4SLinus Torvalds 	* To finish the open response, we just need to set the rflags.
43941da177e4SLinus Torvalds 	*/
43951da177e4SLinus Torvalds 	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
4396dad1c067SJ. Bruce Fields 	if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
43976668958fSAndy Adamson 	    !nfsd4_has_session(&resp->cstate))
43981da177e4SLinus Torvalds 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
4399dcd94cc2STrond Myklebust 	if (dp)
4400dcd94cc2STrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
4401d6f2bc5dSTrond Myklebust 	if (stp)
4402d6f2bc5dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
44031da177e4SLinus Torvalds 
44041da177e4SLinus Torvalds 	return status;
44051da177e4SLinus Torvalds }
44061da177e4SLinus Torvalds 
440758fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
440842297899SJeff Layton 			      struct nfsd4_open *open)
4409d29b20cdSJ. Bruce Fields {
4410d29b20cdSJ. Bruce Fields 	if (open->op_openowner) {
4411d3134b10SJeff Layton 		struct nfs4_stateowner *so = &open->op_openowner->oo_owner;
4412d29b20cdSJ. Bruce Fields 
4413d3134b10SJeff Layton 		nfsd4_cstate_assign_replay(cstate, so);
4414d3134b10SJeff Layton 		nfs4_put_stateowner(so);
4415d29b20cdSJ. Bruce Fields 	}
441632513b40SJ. Bruce Fields 	if (open->op_file)
44175b095e99SJeff Layton 		kmem_cache_free(file_slab, open->op_file);
44184cdc951bSJ. Bruce Fields 	if (open->op_stp)
44196011695dSTrond Myklebust 		nfs4_put_stid(&open->op_stp->st_stid);
44208287f009SSachin Bhamare 	if (open->op_odstate)
44218287f009SSachin Bhamare 		kmem_cache_free(odstate_slab, open->op_odstate);
4422d29b20cdSJ. Bruce Fields }
4423d29b20cdSJ. Bruce Fields 
4424b37ad28bSAl Viro __be32
4425b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4426b591480bSJ.Bruce Fields 	    clientid_t *clid)
44271da177e4SLinus Torvalds {
44281da177e4SLinus Torvalds 	struct nfs4_client *clp;
4429b37ad28bSAl Viro 	__be32 status;
44307f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
44311da177e4SLinus Torvalds 
44321da177e4SLinus Torvalds 	dprintk("process_renew(%08x/%08x): starting\n",
44331da177e4SLinus Torvalds 			clid->cl_boot, clid->cl_id);
44344b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
44359b2ef62bSJ. Bruce Fields 	if (status)
44361da177e4SLinus Torvalds 		goto out;
44374b24ca7dSJeff Layton 	clp = cstate->clp;
44381da177e4SLinus Torvalds 	status = nfserr_cb_path_down;
4439ea1da636SNeilBrown 	if (!list_empty(&clp->cl_delegations)
444077a3569dSJ. Bruce Fields 			&& clp->cl_cb_state != NFSD4_CB_UP)
44411da177e4SLinus Torvalds 		goto out;
44421da177e4SLinus Torvalds 	status = nfs_ok;
44431da177e4SLinus Torvalds out:
44441da177e4SLinus Torvalds 	return status;
44451da177e4SLinus Torvalds }
44461da177e4SLinus Torvalds 
44477f5ef2e9SJeff Layton void
444812760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn)
4449a76b4319SNeilBrown {
445033dcc481SJeff Layton 	/* do nothing if grace period already ended */
4451a51c84edSStanislav Kinsbursky 	if (nn->grace_ended)
445233dcc481SJeff Layton 		return;
445333dcc481SJeff Layton 
4454a76b4319SNeilBrown 	dprintk("NFSD: end of grace period\n");
4455a51c84edSStanislav Kinsbursky 	nn->grace_ended = true;
445670b28235SJ. Bruce Fields 	/*
445770b28235SJ. Bruce Fields 	 * If the server goes down again right now, an NFSv4
445870b28235SJ. Bruce Fields 	 * client will still be allowed to reclaim after it comes back up,
445970b28235SJ. Bruce Fields 	 * even if it hasn't yet had a chance to reclaim state this time.
446070b28235SJ. Bruce Fields 	 *
446170b28235SJ. Bruce Fields 	 */
4462919b8049SJeff Layton 	nfsd4_record_grace_done(nn);
446370b28235SJ. Bruce Fields 	/*
446470b28235SJ. Bruce Fields 	 * At this point, NFSv4 clients can still reclaim.  But if the
446570b28235SJ. Bruce Fields 	 * server crashes, any that have not yet reclaimed will be out
446670b28235SJ. Bruce Fields 	 * of luck on the next boot.
446770b28235SJ. Bruce Fields 	 *
446870b28235SJ. Bruce Fields 	 * (NFSv4.1+ clients are considered to have reclaimed once they
446970b28235SJ. Bruce Fields 	 * call RECLAIM_COMPLETE.  NFSv4.0 clients are considered to
447070b28235SJ. Bruce Fields 	 * have reclaimed after their first OPEN.)
447170b28235SJ. Bruce Fields 	 */
44725e1533c7SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
447370b28235SJ. Bruce Fields 	/*
447470b28235SJ. Bruce Fields 	 * At this point, and once lockd and/or any other containers
447570b28235SJ. Bruce Fields 	 * exit their grace period, further reclaims will fail and
447670b28235SJ. Bruce Fields 	 * regular locking can resume.
447770b28235SJ. Bruce Fields 	 */
4478a76b4319SNeilBrown }
4479a76b4319SNeilBrown 
4480fd39ca9aSNeilBrown static time_t
448109121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn)
44821da177e4SLinus Torvalds {
44831da177e4SLinus Torvalds 	struct nfs4_client *clp;
4484fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
44851da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
4486217526e7SJeff Layton 	struct nfs4_ol_stateid *stp;
44871da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
44883d733711SStanislav Kinsbursky 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
4489a832e7aeSJeff Layton 	time_t t, new_timeo = nn->nfsd4_lease;
44901da177e4SLinus Torvalds 
44911da177e4SLinus Torvalds 	dprintk("NFSD: laundromat service - starting\n");
449212760c66SStanislav Kinsbursky 	nfsd4_end_grace(nn);
449336acb66bSBenny Halevy 	INIT_LIST_HEAD(&reaplist);
4494c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
44955ed58bb2SStanislav Kinsbursky 	list_for_each_safe(pos, next, &nn->client_lru) {
44961da177e4SLinus Torvalds 		clp = list_entry(pos, struct nfs4_client, cl_lru);
44971da177e4SLinus Torvalds 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
44981da177e4SLinus Torvalds 			t = clp->cl_time - cutoff;
4499a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
45001da177e4SLinus Torvalds 			break;
45011da177e4SLinus Torvalds 		}
4502221a6876SJ. Bruce Fields 		if (mark_client_expired_locked(clp)) {
4503d7682988SBenny Halevy 			dprintk("NFSD: client in use (clientid %08x)\n",
4504d7682988SBenny Halevy 				clp->cl_clientid.cl_id);
4505d7682988SBenny Halevy 			continue;
4506d7682988SBenny Halevy 		}
45074864af97STrond Myklebust 		list_add(&clp->cl_lru, &reaplist);
450836acb66bSBenny Halevy 	}
4509c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
451036acb66bSBenny Halevy 	list_for_each_safe(pos, next, &reaplist) {
451136acb66bSBenny Halevy 		clp = list_entry(pos, struct nfs4_client, cl_lru);
45121da177e4SLinus Torvalds 		dprintk("NFSD: purging unused client (clientid %08x)\n",
45131da177e4SLinus Torvalds 			clp->cl_clientid.cl_id);
45144864af97STrond Myklebust 		list_del_init(&clp->cl_lru);
45151da177e4SLinus Torvalds 		expire_client(clp);
45161da177e4SLinus Torvalds 	}
4517cdc97505SBenny Halevy 	spin_lock(&state_lock);
4518e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
45191da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
45201da177e4SLinus Torvalds 		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
4521a832e7aeSJeff Layton 			t = dp->dl_time - cutoff;
4522a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
45231da177e4SLinus Torvalds 			break;
45241da177e4SLinus Torvalds 		}
45253fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
452642690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
45271da177e4SLinus Torvalds 	}
4528cdc97505SBenny Halevy 	spin_unlock(&state_lock);
45292d4a532dSJeff Layton 	while (!list_empty(&reaplist)) {
45302d4a532dSJeff Layton 		dp = list_first_entry(&reaplist, struct nfs4_delegation,
45312d4a532dSJeff Layton 					dl_recall_lru);
45322d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
45333bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
45341da177e4SLinus Torvalds 	}
4535217526e7SJeff Layton 
4536217526e7SJeff Layton 	spin_lock(&nn->client_lock);
4537217526e7SJeff Layton 	while (!list_empty(&nn->close_lru)) {
4538217526e7SJeff Layton 		oo = list_first_entry(&nn->close_lru, struct nfs4_openowner,
4539217526e7SJeff Layton 					oo_close_lru);
4540217526e7SJeff Layton 		if (time_after((unsigned long)oo->oo_time,
4541217526e7SJeff Layton 			       (unsigned long)cutoff)) {
4542a832e7aeSJeff Layton 			t = oo->oo_time - cutoff;
4543a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
45441da177e4SLinus Torvalds 			break;
45451da177e4SLinus Torvalds 		}
4546217526e7SJeff Layton 		list_del_init(&oo->oo_close_lru);
4547217526e7SJeff Layton 		stp = oo->oo_last_closed_stid;
4548217526e7SJeff Layton 		oo->oo_last_closed_stid = NULL;
4549217526e7SJeff Layton 		spin_unlock(&nn->client_lock);
4550217526e7SJeff Layton 		nfs4_put_stid(&stp->st_stid);
4551217526e7SJeff Layton 		spin_lock(&nn->client_lock);
45521da177e4SLinus Torvalds 	}
4553217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
4554217526e7SJeff Layton 
4555a832e7aeSJeff Layton 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
4556a832e7aeSJeff Layton 	return new_timeo;
45571da177e4SLinus Torvalds }
45581da177e4SLinus Torvalds 
4559a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq;
4560a254b246SHarvey Harrison static void laundromat_main(struct work_struct *);
4561a254b246SHarvey Harrison 
4562a254b246SHarvey Harrison static void
456309121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry)
45641da177e4SLinus Torvalds {
45651da177e4SLinus Torvalds 	time_t t;
456609121281SStanislav Kinsbursky 	struct delayed_work *dwork = container_of(laundry, struct delayed_work,
456709121281SStanislav Kinsbursky 						  work);
456809121281SStanislav Kinsbursky 	struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
456909121281SStanislav Kinsbursky 					   laundromat_work);
45701da177e4SLinus Torvalds 
457109121281SStanislav Kinsbursky 	t = nfs4_laundromat(nn);
45721da177e4SLinus Torvalds 	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
457309121281SStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
45741da177e4SLinus Torvalds }
45751da177e4SLinus Torvalds 
45768fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
4577f8816512SNeilBrown {
45788fcd461dSJeff Layton 	if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
4579f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
4580f7a4d872SJ. Bruce Fields 	return nfs_ok;
45811da177e4SLinus Torvalds }
45821da177e4SLinus Torvalds 
45831da177e4SLinus Torvalds static inline int
458482c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp)
45851da177e4SLinus Torvalds {
458682c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_READ, stp) ||
458782c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp) ||
458882c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_WRITE, stp);
45891da177e4SLinus Torvalds }
45901da177e4SLinus Torvalds 
45911da177e4SLinus Torvalds static inline int
459282c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp)
45931da177e4SLinus Torvalds {
459482c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_WRITE, stp) ||
459582c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp);
45961da177e4SLinus Torvalds }
45971da177e4SLinus Torvalds 
45981da177e4SLinus Torvalds static
4599dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
46001da177e4SLinus Torvalds {
4601b37ad28bSAl Viro         __be32 status = nfserr_openmode;
46021da177e4SLinus Torvalds 
460302921914SJ. Bruce Fields 	/* For lock stateid's, we test the parent open, not the lock: */
460402921914SJ. Bruce Fields 	if (stp->st_openstp)
460502921914SJ. Bruce Fields 		stp = stp->st_openstp;
460682c5ff1bSJeff Layton 	if ((flags & WR_STATE) && !access_permit_write(stp))
46071da177e4SLinus Torvalds                 goto out;
460882c5ff1bSJeff Layton 	if ((flags & RD_STATE) && !access_permit_read(stp))
46091da177e4SLinus Torvalds                 goto out;
46101da177e4SLinus Torvalds 	status = nfs_ok;
46111da177e4SLinus Torvalds out:
46121da177e4SLinus Torvalds 	return status;
46131da177e4SLinus Torvalds }
46141da177e4SLinus Torvalds 
4615b37ad28bSAl Viro static inline __be32
46165ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags)
46171da177e4SLinus Torvalds {
4618203a8c8eSJ. Bruce Fields 	if (ONE_STATEID(stateid) && (flags & RD_STATE))
46191da177e4SLinus Torvalds 		return nfs_ok;
4620c87fb4a3SJ. Bruce Fields 	else if (opens_in_grace(net)) {
462125985edcSLucas De Marchi 		/* Answer in remaining cases depends on existence of
46221da177e4SLinus Torvalds 		 * conflicting state; so we must wait out the grace period. */
46231da177e4SLinus Torvalds 		return nfserr_grace;
46241da177e4SLinus Torvalds 	} else if (flags & WR_STATE)
46251da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
46261da177e4SLinus Torvalds 				NFS4_SHARE_DENY_WRITE);
46271da177e4SLinus Torvalds 	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
46281da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
46291da177e4SLinus Torvalds 				NFS4_SHARE_DENY_READ);
46301da177e4SLinus Torvalds }
46311da177e4SLinus Torvalds 
46321da177e4SLinus Torvalds /*
46331da177e4SLinus Torvalds  * Allow READ/WRITE during grace period on recovered state only for files
46341da177e4SLinus Torvalds  * that are not able to provide mandatory locking.
46351da177e4SLinus Torvalds  */
46361da177e4SLinus Torvalds static inline int
46375ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode)
46381da177e4SLinus Torvalds {
4639c87fb4a3SJ. Bruce Fields 	return opens_in_grace(net) && mandatory_lock(inode);
46401da177e4SLinus Torvalds }
46411da177e4SLinus Torvalds 
464281b82965SJ. Bruce Fields /* Returns true iff a is later than b: */
464381b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b)
464481b82965SJ. Bruce Fields {
46451a9357f4SJim Rees 	return (s32)(a->si_generation - b->si_generation) > 0;
464681b82965SJ. Bruce Fields }
464781b82965SJ. Bruce Fields 
464857b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
46490836f587SJ. Bruce Fields {
46506668958fSAndy Adamson 	/*
46516668958fSAndy Adamson 	 * When sessions are used the stateid generation number is ignored
46526668958fSAndy Adamson 	 * when it is zero.
46536668958fSAndy Adamson 	 */
465428dde241SJ. Bruce Fields 	if (has_session && in->si_generation == 0)
465581b82965SJ. Bruce Fields 		return nfs_ok;
465681b82965SJ. Bruce Fields 
465781b82965SJ. Bruce Fields 	if (in->si_generation == ref->si_generation)
465881b82965SJ. Bruce Fields 		return nfs_ok;
46596668958fSAndy Adamson 
46600836f587SJ. Bruce Fields 	/* If the client sends us a stateid from the future, it's buggy: */
466181b82965SJ. Bruce Fields 	if (stateid_generation_after(in, ref))
46620836f587SJ. Bruce Fields 		return nfserr_bad_stateid;
46630836f587SJ. Bruce Fields 	/*
466481b82965SJ. Bruce Fields 	 * However, we could see a stateid from the past, even from a
466581b82965SJ. Bruce Fields 	 * non-buggy client.  For example, if the client sends a lock
466681b82965SJ. Bruce Fields 	 * while some IO is outstanding, the lock may bump si_generation
466781b82965SJ. Bruce Fields 	 * while the IO is still in flight.  The client could avoid that
466881b82965SJ. Bruce Fields 	 * situation by waiting for responses on all the IO requests,
466981b82965SJ. Bruce Fields 	 * but better performance may result in retrying IO that
467081b82965SJ. Bruce Fields 	 * receives an old_stateid error if requests are rarely
467181b82965SJ. Bruce Fields 	 * reordered in flight:
46720836f587SJ. Bruce Fields 	 */
46730836f587SJ. Bruce Fields 	return nfserr_old_stateid;
46740836f587SJ. Bruce Fields }
46750836f587SJ. Bruce Fields 
4676ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols)
4677ebe9cb3bSChristoph Hellwig {
4678ebe9cb3bSChristoph Hellwig 	if (ols->st_stateowner->so_is_open_owner &&
4679ebe9cb3bSChristoph Hellwig 	    !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
4680ebe9cb3bSChristoph Hellwig 		return nfserr_bad_stateid;
4681ebe9cb3bSChristoph Hellwig 	return nfs_ok;
4682ebe9cb3bSChristoph Hellwig }
4683ebe9cb3bSChristoph Hellwig 
46847df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
468517456804SBryan Schumaker {
468697b7e3b6SJ. Bruce Fields 	struct nfs4_stid *s;
46871af71cc8SJeff Layton 	__be32 status = nfserr_bad_stateid;
468817456804SBryan Schumaker 
46897df302f7SChuck Lever 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
46901af71cc8SJeff Layton 		return status;
46917df302f7SChuck Lever 	/* Client debugging aid. */
46927df302f7SChuck Lever 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
46937df302f7SChuck Lever 		char addr_str[INET6_ADDRSTRLEN];
46947df302f7SChuck Lever 		rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
46957df302f7SChuck Lever 				 sizeof(addr_str));
46967df302f7SChuck Lever 		pr_warn_ratelimited("NFSD: client %s testing state ID "
46977df302f7SChuck Lever 					"with incorrect client ID\n", addr_str);
46981af71cc8SJeff Layton 		return status;
46997df302f7SChuck Lever 	}
47001af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
47011af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
470297b7e3b6SJ. Bruce Fields 	if (!s)
47031af71cc8SJeff Layton 		goto out_unlock;
470436279ac1SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
470517456804SBryan Schumaker 	if (status)
47061af71cc8SJeff Layton 		goto out_unlock;
470723340032SJ. Bruce Fields 	switch (s->sc_type) {
470823340032SJ. Bruce Fields 	case NFS4_DELEG_STID:
47091af71cc8SJeff Layton 		status = nfs_ok;
47101af71cc8SJeff Layton 		break;
47113bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
47121af71cc8SJeff Layton 		status = nfserr_deleg_revoked;
47131af71cc8SJeff Layton 		break;
471423340032SJ. Bruce Fields 	case NFS4_OPEN_STID:
471523340032SJ. Bruce Fields 	case NFS4_LOCK_STID:
4716ebe9cb3bSChristoph Hellwig 		status = nfsd4_check_openowner_confirmed(openlockstateid(s));
47171af71cc8SJeff Layton 		break;
471823340032SJ. Bruce Fields 	default:
471923340032SJ. Bruce Fields 		printk("unknown stateid type %x\n", s->sc_type);
4720b0fc29d6STrond Myklebust 		/* Fallthrough */
472123340032SJ. Bruce Fields 	case NFS4_CLOSED_STID:
4722b0fc29d6STrond Myklebust 	case NFS4_CLOSED_DELEG_STID:
47231af71cc8SJeff Layton 		status = nfserr_bad_stateid;
472423340032SJ. Bruce Fields 	}
47251af71cc8SJeff Layton out_unlock:
47261af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
47271af71cc8SJeff Layton 	return status;
472817456804SBryan Schumaker }
472917456804SBryan Schumaker 
4730cd61c522SChristoph Hellwig __be32
47312dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
47322dd6e458STrond Myklebust 		     stateid_t *stateid, unsigned char typemask,
47332dd6e458STrond Myklebust 		     struct nfs4_stid **s, struct nfsd_net *nn)
473438c2f4b1SJ. Bruce Fields {
47350eb6f20aSJ. Bruce Fields 	__be32 status;
473638c2f4b1SJ. Bruce Fields 
473738c2f4b1SJ. Bruce Fields 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
473838c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
47394b24ca7dSJeff Layton 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
4740a8a7c677STrond Myklebust 	if (status == nfserr_stale_clientid) {
47414b24ca7dSJeff Layton 		if (cstate->session)
4742a8a7c677STrond Myklebust 			return nfserr_bad_stateid;
474338c2f4b1SJ. Bruce Fields 		return nfserr_stale_stateid;
4744a8a7c677STrond Myklebust 	}
47450eb6f20aSJ. Bruce Fields 	if (status)
47460eb6f20aSJ. Bruce Fields 		return status;
47474b24ca7dSJeff Layton 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
474838c2f4b1SJ. Bruce Fields 	if (!*s)
474938c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
475038c2f4b1SJ. Bruce Fields 	return nfs_ok;
475138c2f4b1SJ. Bruce Fields }
475238c2f4b1SJ. Bruce Fields 
4753a0649b2dSChristoph Hellwig static struct file *
4754a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags)
4755a0649b2dSChristoph Hellwig {
4756af90f707SChristoph Hellwig 	if (!s)
4757af90f707SChristoph Hellwig 		return NULL;
4758af90f707SChristoph Hellwig 
4759a0649b2dSChristoph Hellwig 	switch (s->sc_type) {
4760a0649b2dSChristoph Hellwig 	case NFS4_DELEG_STID:
4761a0649b2dSChristoph Hellwig 		if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file))
4762a0649b2dSChristoph Hellwig 			return NULL;
4763a0649b2dSChristoph Hellwig 		return get_file(s->sc_file->fi_deleg_file);
4764a0649b2dSChristoph Hellwig 	case NFS4_OPEN_STID:
4765a0649b2dSChristoph Hellwig 	case NFS4_LOCK_STID:
4766a0649b2dSChristoph Hellwig 		if (flags & RD_STATE)
4767a0649b2dSChristoph Hellwig 			return find_readable_file(s->sc_file);
4768a0649b2dSChristoph Hellwig 		else
4769a0649b2dSChristoph Hellwig 			return find_writeable_file(s->sc_file);
4770a0649b2dSChristoph Hellwig 		break;
4771a0649b2dSChristoph Hellwig 	}
4772a0649b2dSChristoph Hellwig 
4773a0649b2dSChristoph Hellwig 	return NULL;
4774a0649b2dSChristoph Hellwig }
4775a0649b2dSChristoph Hellwig 
4776a0649b2dSChristoph Hellwig static __be32
4777a0649b2dSChristoph Hellwig nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags)
4778a0649b2dSChristoph Hellwig {
4779a0649b2dSChristoph Hellwig 	__be32 status;
4780a0649b2dSChristoph Hellwig 
4781a0649b2dSChristoph Hellwig 	status = nfsd4_check_openowner_confirmed(ols);
4782a0649b2dSChristoph Hellwig 	if (status)
4783a0649b2dSChristoph Hellwig 		return status;
4784a0649b2dSChristoph Hellwig 	return nfs4_check_openmode(ols, flags);
4785a0649b2dSChristoph Hellwig }
4786a0649b2dSChristoph Hellwig 
4787af90f707SChristoph Hellwig static __be32
4788af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s,
4789af90f707SChristoph Hellwig 		struct file **filpp, bool *tmp_file, int flags)
4790af90f707SChristoph Hellwig {
4791af90f707SChristoph Hellwig 	int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE;
4792af90f707SChristoph Hellwig 	struct file *file;
4793af90f707SChristoph Hellwig 	__be32 status;
4794af90f707SChristoph Hellwig 
4795af90f707SChristoph Hellwig 	file = nfs4_find_file(s, flags);
4796af90f707SChristoph Hellwig 	if (file) {
4797af90f707SChristoph Hellwig 		status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
4798af90f707SChristoph Hellwig 				acc | NFSD_MAY_OWNER_OVERRIDE);
4799af90f707SChristoph Hellwig 		if (status) {
4800af90f707SChristoph Hellwig 			fput(file);
4801af90f707SChristoph Hellwig 			return status;
4802af90f707SChristoph Hellwig 		}
4803af90f707SChristoph Hellwig 
4804af90f707SChristoph Hellwig 		*filpp = file;
4805af90f707SChristoph Hellwig 	} else {
4806af90f707SChristoph Hellwig 		status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp);
4807af90f707SChristoph Hellwig 		if (status)
4808af90f707SChristoph Hellwig 			return status;
4809af90f707SChristoph Hellwig 
4810af90f707SChristoph Hellwig 		if (tmp_file)
4811af90f707SChristoph Hellwig 			*tmp_file = true;
4812af90f707SChristoph Hellwig 	}
4813af90f707SChristoph Hellwig 
4814af90f707SChristoph Hellwig 	return 0;
4815af90f707SChristoph Hellwig }
4816af90f707SChristoph Hellwig 
48171da177e4SLinus Torvalds /*
48181da177e4SLinus Torvalds  * Checks for stateid operations
48191da177e4SLinus Torvalds  */
4820b37ad28bSAl Viro __be32
4821af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
4822af90f707SChristoph Hellwig 		struct nfsd4_compound_state *cstate, stateid_t *stateid,
4823af90f707SChristoph Hellwig 		int flags, struct file **filpp, bool *tmp_file)
48241da177e4SLinus Torvalds {
4825a0649b2dSChristoph Hellwig 	struct svc_fh *fhp = &cstate->current_fh;
4826a0649b2dSChristoph Hellwig 	struct inode *ino = d_inode(fhp->fh_dentry);
4827af90f707SChristoph Hellwig 	struct net *net = SVC_NET(rqstp);
48283320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
4829af90f707SChristoph Hellwig 	struct nfs4_stid *s = NULL;
4830b37ad28bSAl Viro 	__be32 status;
48311da177e4SLinus Torvalds 
48321da177e4SLinus Torvalds 	if (filpp)
48331da177e4SLinus Torvalds 		*filpp = NULL;
4834af90f707SChristoph Hellwig 	if (tmp_file)
4835af90f707SChristoph Hellwig 		*tmp_file = false;
48361da177e4SLinus Torvalds 
48375ccb0066SStanislav Kinsbursky 	if (grace_disallows_io(net, ino))
48381da177e4SLinus Torvalds 		return nfserr_grace;
48391da177e4SLinus Torvalds 
4840af90f707SChristoph Hellwig 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
4841af90f707SChristoph Hellwig 		status = check_special_stateids(net, fhp, stateid, flags);
4842af90f707SChristoph Hellwig 		goto done;
4843af90f707SChristoph Hellwig 	}
48441da177e4SLinus Torvalds 
48452dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid,
4846db24b3b4SJeff Layton 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
48472dd6e458STrond Myklebust 				&s, nn);
484838c2f4b1SJ. Bruce Fields 	if (status)
4849c2d1d6a8STrond Myklebust 		return status;
4850a0649b2dSChristoph Hellwig 	status = check_stateid_generation(stateid, &s->sc_stateid,
4851a0649b2dSChristoph Hellwig 			nfsd4_has_session(cstate));
48520c2a498fSJ. Bruce Fields 	if (status)
48530c2a498fSJ. Bruce Fields 		goto out;
4854a0649b2dSChristoph Hellwig 
4855f7a4d872SJ. Bruce Fields 	switch (s->sc_type) {
4856f7a4d872SJ. Bruce Fields 	case NFS4_DELEG_STID:
4857a0649b2dSChristoph Hellwig 		status = nfs4_check_delegmode(delegstateid(s), flags);
4858f7a4d872SJ. Bruce Fields 		break;
4859f7a4d872SJ. Bruce Fields 	case NFS4_OPEN_STID:
4860f7a4d872SJ. Bruce Fields 	case NFS4_LOCK_STID:
4861a0649b2dSChristoph Hellwig 		status = nfs4_check_olstateid(fhp, openlockstateid(s), flags);
4862f7a4d872SJ. Bruce Fields 		break;
4863f7a4d872SJ. Bruce Fields 	default:
486414bcab1aSTrond Myklebust 		status = nfserr_bad_stateid;
4865a0649b2dSChristoph Hellwig 		break;
48661da177e4SLinus Torvalds 	}
48678fcd461dSJeff Layton 	if (status)
48688fcd461dSJeff Layton 		goto out;
48698fcd461dSJeff Layton 	status = nfs4_check_fh(fhp, s);
4870a0649b2dSChristoph Hellwig 
4871af90f707SChristoph Hellwig done:
4872af90f707SChristoph Hellwig 	if (!status && filpp)
4873af90f707SChristoph Hellwig 		status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags);
48741da177e4SLinus Torvalds out:
4875af90f707SChristoph Hellwig 	if (s)
4876fd911011STrond Myklebust 		nfs4_put_stid(s);
48771da177e4SLinus Torvalds 	return status;
48781da177e4SLinus Torvalds }
48791da177e4SLinus Torvalds 
4880e1ca12dfSBryan Schumaker /*
488117456804SBryan Schumaker  * Test if the stateid is valid
488217456804SBryan Schumaker  */
488317456804SBryan Schumaker __be32
488417456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
488517456804SBryan Schumaker 		   struct nfsd4_test_stateid *test_stateid)
488617456804SBryan Schumaker {
488703cfb420SBryan Schumaker 	struct nfsd4_test_stateid_id *stateid;
488803cfb420SBryan Schumaker 	struct nfs4_client *cl = cstate->session->se_client;
488903cfb420SBryan Schumaker 
489003cfb420SBryan Schumaker 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
48917df302f7SChuck Lever 		stateid->ts_id_status =
48927df302f7SChuck Lever 			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
489303cfb420SBryan Schumaker 
489417456804SBryan Schumaker 	return nfs_ok;
489517456804SBryan Schumaker }
489617456804SBryan Schumaker 
4897e1ca12dfSBryan Schumaker __be32
4898e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4899e1ca12dfSBryan Schumaker 		   struct nfsd4_free_stateid *free_stateid)
4900e1ca12dfSBryan Schumaker {
4901e1ca12dfSBryan Schumaker 	stateid_t *stateid = &free_stateid->fr_stateid;
49022da1cec7SJ. Bruce Fields 	struct nfs4_stid *s;
49033bd64a5bSJ. Bruce Fields 	struct nfs4_delegation *dp;
4904fc5a96c3SJeff Layton 	struct nfs4_ol_stateid *stp;
490538c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = cstate->session->se_client;
49062da1cec7SJ. Bruce Fields 	__be32 ret = nfserr_bad_stateid;
4907e1ca12dfSBryan Schumaker 
49081af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
49091af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
49102da1cec7SJ. Bruce Fields 	if (!s)
49111af71cc8SJeff Layton 		goto out_unlock;
49122da1cec7SJ. Bruce Fields 	switch (s->sc_type) {
49132da1cec7SJ. Bruce Fields 	case NFS4_DELEG_STID:
4914e1ca12dfSBryan Schumaker 		ret = nfserr_locks_held;
49151af71cc8SJeff Layton 		break;
49162da1cec7SJ. Bruce Fields 	case NFS4_OPEN_STID:
49171af71cc8SJeff Layton 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
49181af71cc8SJeff Layton 		if (ret)
49191af71cc8SJeff Layton 			break;
49201af71cc8SJeff Layton 		ret = nfserr_locks_held;
49211af71cc8SJeff Layton 		break;
49222da1cec7SJ. Bruce Fields 	case NFS4_LOCK_STID:
49232da1cec7SJ. Bruce Fields 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
49242da1cec7SJ. Bruce Fields 		if (ret)
4925f7a4d872SJ. Bruce Fields 			break;
4926fc5a96c3SJeff Layton 		stp = openlockstateid(s);
4927fc5a96c3SJeff Layton 		ret = nfserr_locks_held;
4928fc5a96c3SJeff Layton 		if (check_for_locks(stp->st_stid.sc_file,
4929fc5a96c3SJeff Layton 				    lockowner(stp->st_stateowner)))
4930fc5a96c3SJeff Layton 			break;
4931e8568739SJeff Layton 		WARN_ON(!unhash_lock_stateid(stp));
49321af71cc8SJeff Layton 		spin_unlock(&cl->cl_lock);
4933fc5a96c3SJeff Layton 		nfs4_put_stid(s);
4934fc5a96c3SJeff Layton 		ret = nfs_ok;
49351af71cc8SJeff Layton 		goto out;
49363bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
49373bd64a5bSJ. Bruce Fields 		dp = delegstateid(s);
49382d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
49392d4a532dSJeff Layton 		spin_unlock(&cl->cl_lock);
49406011695dSTrond Myklebust 		nfs4_put_stid(s);
49413bd64a5bSJ. Bruce Fields 		ret = nfs_ok;
49421af71cc8SJeff Layton 		goto out;
49431af71cc8SJeff Layton 	/* Default falls through and returns nfserr_bad_stateid */
4944e1ca12dfSBryan Schumaker 	}
49451af71cc8SJeff Layton out_unlock:
49461af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
4947e1ca12dfSBryan Schumaker out:
4948e1ca12dfSBryan Schumaker 	return ret;
4949e1ca12dfSBryan Schumaker }
4950e1ca12dfSBryan Schumaker 
49514c4cd222SNeilBrown static inline int
49524c4cd222SNeilBrown setlkflg (int type)
49534c4cd222SNeilBrown {
49544c4cd222SNeilBrown 	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
49554c4cd222SNeilBrown 		RD_STATE : WR_STATE;
49564c4cd222SNeilBrown }
49571da177e4SLinus Torvalds 
4958dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
4959c0a5d93eSJ. Bruce Fields {
4960c0a5d93eSJ. Bruce Fields 	struct svc_fh *current_fh = &cstate->current_fh;
4961c0a5d93eSJ. Bruce Fields 	struct nfs4_stateowner *sop = stp->st_stateowner;
4962c0a5d93eSJ. Bruce Fields 	__be32 status;
4963c0a5d93eSJ. Bruce Fields 
4964c0a5d93eSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, sop, seqid);
4965c0a5d93eSJ. Bruce Fields 	if (status)
4966c0a5d93eSJ. Bruce Fields 		return status;
49673bd64a5bSJ. Bruce Fields 	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
49683bd64a5bSJ. Bruce Fields 		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
4969f7a4d872SJ. Bruce Fields 		/*
4970f7a4d872SJ. Bruce Fields 		 * "Closed" stateid's exist *only* to return
49713bd64a5bSJ. Bruce Fields 		 * nfserr_replay_me from the previous step, and
49723bd64a5bSJ. Bruce Fields 		 * revoked delegations are kept only for free_stateid.
4973f7a4d872SJ. Bruce Fields 		 */
4974f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
497535a92fe8SJeff Layton 	down_write(&stp->st_rwsem);
4976f7a4d872SJ. Bruce Fields 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
497735a92fe8SJeff Layton 	if (status == nfs_ok)
497835a92fe8SJeff Layton 		status = nfs4_check_fh(current_fh, &stp->st_stid);
497935a92fe8SJeff Layton 	if (status != nfs_ok)
498035a92fe8SJeff Layton 		up_write(&stp->st_rwsem);
4981f7a4d872SJ. Bruce Fields 	return status;
4982c0a5d93eSJ. Bruce Fields }
4983c0a5d93eSJ. Bruce Fields 
49841da177e4SLinus Torvalds /*
49851da177e4SLinus Torvalds  * Checks for sequence id mutating operations.
49861da177e4SLinus Torvalds  */
4987b37ad28bSAl Viro static __be32
4988dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
49892288d0e3SJ. Bruce Fields 			 stateid_t *stateid, char typemask,
49903320fef1SStanislav Kinsbursky 			 struct nfs4_ol_stateid **stpp,
49913320fef1SStanislav Kinsbursky 			 struct nfsd_net *nn)
49921da177e4SLinus Torvalds {
49930836f587SJ. Bruce Fields 	__be32 status;
499438c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
4995e17f99b7STrond Myklebust 	struct nfs4_ol_stateid *stp = NULL;
49961da177e4SLinus Torvalds 
49978c10cbdbSBenny Halevy 	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
49988c10cbdbSBenny Halevy 		seqid, STATEID_VAL(stateid));
49991da177e4SLinus Torvalds 
50001da177e4SLinus Torvalds 	*stpp = NULL;
50012dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn);
5002c0a5d93eSJ. Bruce Fields 	if (status)
5003c0a5d93eSJ. Bruce Fields 		return status;
5004e17f99b7STrond Myklebust 	stp = openlockstateid(s);
500558fb12e6SJeff Layton 	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
50061da177e4SLinus Torvalds 
5007e17f99b7STrond Myklebust 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
5008fd911011STrond Myklebust 	if (!status)
5009e17f99b7STrond Myklebust 		*stpp = stp;
5010fd911011STrond Myklebust 	else
5011fd911011STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
5012e17f99b7STrond Myklebust 	return status;
50131da177e4SLinus Torvalds }
50141da177e4SLinus Torvalds 
50153320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
50163320fef1SStanislav Kinsbursky 						 stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn)
5017c0a5d93eSJ. Bruce Fields {
5018c0a5d93eSJ. Bruce Fields 	__be32 status;
5019c0a5d93eSJ. Bruce Fields 	struct nfs4_openowner *oo;
50204cbfc9f7STrond Myklebust 	struct nfs4_ol_stateid *stp;
50211da177e4SLinus Torvalds 
5022c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
50234cbfc9f7STrond Myklebust 						NFS4_OPEN_STID, &stp, nn);
50240836f587SJ. Bruce Fields 	if (status)
50250836f587SJ. Bruce Fields 		return status;
50264cbfc9f7STrond Myklebust 	oo = openowner(stp->st_stateowner);
50274cbfc9f7STrond Myklebust 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
502835a92fe8SJeff Layton 		up_write(&stp->st_rwsem);
50294cbfc9f7STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
5030c0a5d93eSJ. Bruce Fields 		return nfserr_bad_stateid;
50314cbfc9f7STrond Myklebust 	}
50324cbfc9f7STrond Myklebust 	*stpp = stp;
50333a4f98bbSNeilBrown 	return nfs_ok;
50341da177e4SLinus Torvalds }
50351da177e4SLinus Torvalds 
5036b37ad28bSAl Viro __be32
5037ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5038a4f1706aSJ.Bruce Fields 		   struct nfsd4_open_confirm *oc)
50391da177e4SLinus Torvalds {
5040b37ad28bSAl Viro 	__be32 status;
5041fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
5042dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
50433320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
50441da177e4SLinus Torvalds 
5045a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_confirm on file %pd\n",
5046a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
50471da177e4SLinus Torvalds 
5048ca364317SJ.Bruce Fields 	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
5049a8cddc5dSJ. Bruce Fields 	if (status)
5050a8cddc5dSJ. Bruce Fields 		return status;
50511da177e4SLinus Torvalds 
50529072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate,
5053ca364317SJ.Bruce Fields 					oc->oc_seqid, &oc->oc_req_stateid,
50543320fef1SStanislav Kinsbursky 					NFS4_OPEN_STID, &stp, nn);
50559072d5c6SJ. Bruce Fields 	if (status)
50561da177e4SLinus Torvalds 		goto out;
5057fe0750e5SJ. Bruce Fields 	oo = openowner(stp->st_stateowner);
505868b66e82SJ. Bruce Fields 	status = nfserr_bad_stateid;
505935a92fe8SJeff Layton 	if (oo->oo_flags & NFS4_OO_CONFIRMED) {
506035a92fe8SJeff Layton 		up_write(&stp->st_rwsem);
50612585fc79STrond Myklebust 		goto put_stateid;
506235a92fe8SJeff Layton 	}
5063dad1c067SJ. Bruce Fields 	oo->oo_flags |= NFS4_OO_CONFIRMED;
50649767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid);
506535a92fe8SJeff Layton 	up_write(&stp->st_rwsem);
50668c10cbdbSBenny Halevy 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
5067dcef0413SJ. Bruce Fields 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
5068c7b9a459SNeilBrown 
50692a4317c5SJeff Layton 	nfsd4_client_record_create(oo->oo_owner.so_client);
507068b66e82SJ. Bruce Fields 	status = nfs_ok;
50712585fc79STrond Myklebust put_stateid:
50722585fc79STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
50731da177e4SLinus Torvalds out:
50749411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
50751da177e4SLinus Torvalds 	return status;
50761da177e4SLinus Torvalds }
50771da177e4SLinus Torvalds 
50786409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
50791da177e4SLinus Torvalds {
508082c5ff1bSJeff Layton 	if (!test_access(access, stp))
50816409a5a6SJ. Bruce Fields 		return;
508211b9164aSTrond Myklebust 	nfs4_file_put_access(stp->st_stid.sc_file, access);
508382c5ff1bSJeff Layton 	clear_access(access, stp);
5084f197c271SJ. Bruce Fields }
50856409a5a6SJ. Bruce Fields 
50866409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
50876409a5a6SJ. Bruce Fields {
50886409a5a6SJ. Bruce Fields 	switch (to_access) {
50896409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
50906409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
50916409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
50926409a5a6SJ. Bruce Fields 		break;
50936409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
50946409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
50956409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
50966409a5a6SJ. Bruce Fields 		break;
50976409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
50986409a5a6SJ. Bruce Fields 		break;
50996409a5a6SJ. Bruce Fields 	default:
5100063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
51011da177e4SLinus Torvalds 	}
51021da177e4SLinus Torvalds }
51031da177e4SLinus Torvalds 
5104b37ad28bSAl Viro __be32
5105ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp,
5106ca364317SJ.Bruce Fields 		     struct nfsd4_compound_state *cstate,
5107a4f1706aSJ.Bruce Fields 		     struct nfsd4_open_downgrade *od)
51081da177e4SLinus Torvalds {
5109b37ad28bSAl Viro 	__be32 status;
5110dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
51113320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
51121da177e4SLinus Torvalds 
5113a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_downgrade on file %pd\n",
5114a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
51151da177e4SLinus Torvalds 
5116c30e92dfSJ. Bruce Fields 	/* We don't yet support WANT bits: */
51172c8bd7e0SBenny Halevy 	if (od->od_deleg_want)
51182c8bd7e0SBenny Halevy 		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
51192c8bd7e0SBenny Halevy 			od->od_deleg_want);
51201da177e4SLinus Torvalds 
5121c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
51223320fef1SStanislav Kinsbursky 					&od->od_stateid, &stp, nn);
51239072d5c6SJ. Bruce Fields 	if (status)
51241da177e4SLinus Torvalds 		goto out;
51251da177e4SLinus Torvalds 	status = nfserr_inval;
512682c5ff1bSJeff Layton 	if (!test_access(od->od_share_access, stp)) {
5127c11c591fSJeff Layton 		dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n",
51281da177e4SLinus Torvalds 			stp->st_access_bmap, od->od_share_access);
51290667b1e9STrond Myklebust 		goto put_stateid;
51301da177e4SLinus Torvalds 	}
5131ce0fc43cSJeff Layton 	if (!test_deny(od->od_share_deny, stp)) {
5132c11c591fSJeff Layton 		dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n",
51331da177e4SLinus Torvalds 			stp->st_deny_bmap, od->od_share_deny);
51340667b1e9STrond Myklebust 		goto put_stateid;
51351da177e4SLinus Torvalds 	}
51366409a5a6SJ. Bruce Fields 	nfs4_stateid_downgrade(stp, od->od_share_access);
5137ce0fc43cSJeff Layton 	reset_union_bmap_deny(od->od_share_deny, stp);
51389767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid);
51391da177e4SLinus Torvalds 	status = nfs_ok;
51400667b1e9STrond Myklebust put_stateid:
514135a92fe8SJeff Layton 	up_write(&stp->st_rwsem);
51420667b1e9STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
51431da177e4SLinus Torvalds out:
51449411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
51451da177e4SLinus Torvalds 	return status;
51461da177e4SLinus Torvalds }
51471da177e4SLinus Torvalds 
5148f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
5149f7a4d872SJ. Bruce Fields {
5150acf9295bSTrond Myklebust 	struct nfs4_client *clp = s->st_stid.sc_client;
5151e8568739SJeff Layton 	bool unhashed;
5152d83017f9SJeff Layton 	LIST_HEAD(reaplist);
5153acf9295bSTrond Myklebust 
5154f7a4d872SJ. Bruce Fields 	s->st_stid.sc_type = NFS4_CLOSED_STID;
51552c41beb0SJeff Layton 	spin_lock(&clp->cl_lock);
5156e8568739SJeff Layton 	unhashed = unhash_open_stateid(s, &reaplist);
5157acf9295bSTrond Myklebust 
5158d83017f9SJeff Layton 	if (clp->cl_minorversion) {
5159e8568739SJeff Layton 		if (unhashed)
5160d83017f9SJeff Layton 			put_ol_stateid_locked(s, &reaplist);
5161d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
5162d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
5163d83017f9SJeff Layton 	} else {
5164d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
5165d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
5166e8568739SJeff Layton 		if (unhashed)
5167d3134b10SJeff Layton 			move_to_close_lru(s, clp->net);
516838c387b5SJ. Bruce Fields 	}
5169d83017f9SJeff Layton }
517038c387b5SJ. Bruce Fields 
51711da177e4SLinus Torvalds /*
51721da177e4SLinus Torvalds  * nfs4_unlock_state() called after encode
51731da177e4SLinus Torvalds  */
5174b37ad28bSAl Viro __be32
5175ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5176a4f1706aSJ.Bruce Fields 	    struct nfsd4_close *close)
51771da177e4SLinus Torvalds {
5178b37ad28bSAl Viro 	__be32 status;
5179dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
51803320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
51813320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
51821da177e4SLinus Torvalds 
5183a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_close on file %pd\n",
5184a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
51851da177e4SLinus Torvalds 
5186f7a4d872SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
5187f7a4d872SJ. Bruce Fields 					&close->cl_stateid,
5188f7a4d872SJ. Bruce Fields 					NFS4_OPEN_STID|NFS4_CLOSED_STID,
51893320fef1SStanislav Kinsbursky 					&stp, nn);
51909411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
51919072d5c6SJ. Bruce Fields 	if (status)
51921da177e4SLinus Torvalds 		goto out;
51939767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
519435a92fe8SJeff Layton 	up_write(&stp->st_rwsem);
51951da177e4SLinus Torvalds 
5196f7a4d872SJ. Bruce Fields 	nfsd4_close_open_stateid(stp);
51978a0b589dSTrond Myklebust 
51988a0b589dSTrond Myklebust 	/* put reference from nfs4_preprocess_seqid_op */
51998a0b589dSTrond Myklebust 	nfs4_put_stid(&stp->st_stid);
52001da177e4SLinus Torvalds out:
52011da177e4SLinus Torvalds 	return status;
52021da177e4SLinus Torvalds }
52031da177e4SLinus Torvalds 
5204b37ad28bSAl Viro __be32
5205ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5206ca364317SJ.Bruce Fields 		  struct nfsd4_delegreturn *dr)
52071da177e4SLinus Torvalds {
5208203a8c8eSJ. Bruce Fields 	struct nfs4_delegation *dp;
5209203a8c8eSJ. Bruce Fields 	stateid_t *stateid = &dr->dr_stateid;
521038c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
5211b37ad28bSAl Viro 	__be32 status;
52123320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
52131da177e4SLinus Torvalds 
5214ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
5215203a8c8eSJ. Bruce Fields 		return status;
52161da177e4SLinus Torvalds 
52172dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
521838c2f4b1SJ. Bruce Fields 	if (status)
5219203a8c8eSJ. Bruce Fields 		goto out;
522038c2f4b1SJ. Bruce Fields 	dp = delegstateid(s);
5221d5477a8dSJ. Bruce Fields 	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
5222203a8c8eSJ. Bruce Fields 	if (status)
5223fd911011STrond Myklebust 		goto put_stateid;
5224203a8c8eSJ. Bruce Fields 
52253bd64a5bSJ. Bruce Fields 	destroy_delegation(dp);
5226fd911011STrond Myklebust put_stateid:
5227fd911011STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
52281da177e4SLinus Torvalds out:
52291da177e4SLinus Torvalds 	return status;
52301da177e4SLinus Torvalds }
52311da177e4SLinus Torvalds 
523287df4de8SBenny Halevy static inline u64
523387df4de8SBenny Halevy end_offset(u64 start, u64 len)
523487df4de8SBenny Halevy {
523587df4de8SBenny Halevy 	u64 end;
523687df4de8SBenny Halevy 
523787df4de8SBenny Halevy 	end = start + len;
523887df4de8SBenny Halevy 	return end >= start ? end: NFS4_MAX_UINT64;
523987df4de8SBenny Halevy }
524087df4de8SBenny Halevy 
524187df4de8SBenny Halevy /* last octet in a range */
524287df4de8SBenny Halevy static inline u64
524387df4de8SBenny Halevy last_byte_offset(u64 start, u64 len)
524487df4de8SBenny Halevy {
524587df4de8SBenny Halevy 	u64 end;
524687df4de8SBenny Halevy 
5247063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(!len);
524887df4de8SBenny Halevy 	end = start + len;
524987df4de8SBenny Halevy 	return end > start ? end - 1: NFS4_MAX_UINT64;
525087df4de8SBenny Halevy }
525187df4de8SBenny Halevy 
52521da177e4SLinus Torvalds /*
52531da177e4SLinus Torvalds  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
52541da177e4SLinus Torvalds  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
52551da177e4SLinus Torvalds  * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
52561da177e4SLinus Torvalds  * locking, this prevents us from being completely protocol-compliant.  The
52571da177e4SLinus Torvalds  * real solution to this problem is to start using unsigned file offsets in
52581da177e4SLinus Torvalds  * the VFS, but this is a very deep change!
52591da177e4SLinus Torvalds  */
52601da177e4SLinus Torvalds static inline void
52611da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock)
52621da177e4SLinus Torvalds {
52631da177e4SLinus Torvalds 	if (lock->fl_start < 0)
52641da177e4SLinus Torvalds 		lock->fl_start = OFFSET_MAX;
52651da177e4SLinus Torvalds 	if (lock->fl_end < 0)
52661da177e4SLinus Torvalds 		lock->fl_end = OFFSET_MAX;
52671da177e4SLinus Torvalds }
52681da177e4SLinus Torvalds 
5269cae80b30SJeff Layton static fl_owner_t
5270cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner)
5271aef9583bSKinglong Mee {
5272cae80b30SJeff Layton 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
5273cae80b30SJeff Layton 
5274cae80b30SJeff Layton 	nfs4_get_stateowner(&lo->lo_owner);
5275cae80b30SJeff Layton 	return owner;
5276aef9583bSKinglong Mee }
5277aef9583bSKinglong Mee 
5278cae80b30SJeff Layton static void
5279cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner)
5280aef9583bSKinglong Mee {
5281cae80b30SJeff Layton 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
5282aef9583bSKinglong Mee 
5283cae80b30SJeff Layton 	if (lo)
5284aef9583bSKinglong Mee 		nfs4_put_stateowner(&lo->lo_owner);
5285aef9583bSKinglong Mee }
5286aef9583bSKinglong Mee 
52877b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops  = {
5288aef9583bSKinglong Mee 	.lm_get_owner = nfsd4_fl_get_owner,
5289aef9583bSKinglong Mee 	.lm_put_owner = nfsd4_fl_put_owner,
5290d5b9026aSNeilBrown };
52911da177e4SLinus Torvalds 
52921da177e4SLinus Torvalds static inline void
52931da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
52941da177e4SLinus Torvalds {
5295fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
52961da177e4SLinus Torvalds 
5297d5b9026aSNeilBrown 	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
5298fe0750e5SJ. Bruce Fields 		lo = (struct nfs4_lockowner *) fl->fl_owner;
5299fe0750e5SJ. Bruce Fields 		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
5300fe0750e5SJ. Bruce Fields 					lo->lo_owner.so_owner.len, GFP_KERNEL);
53017c13f344SJ. Bruce Fields 		if (!deny->ld_owner.data)
53027c13f344SJ. Bruce Fields 			/* We just don't care that much */
53037c13f344SJ. Bruce Fields 			goto nevermind;
5304fe0750e5SJ. Bruce Fields 		deny->ld_owner.len = lo->lo_owner.so_owner.len;
5305fe0750e5SJ. Bruce Fields 		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
5306d5b9026aSNeilBrown 	} else {
53077c13f344SJ. Bruce Fields nevermind:
53087c13f344SJ. Bruce Fields 		deny->ld_owner.len = 0;
53097c13f344SJ. Bruce Fields 		deny->ld_owner.data = NULL;
5310d5b9026aSNeilBrown 		deny->ld_clientid.cl_boot = 0;
5311d5b9026aSNeilBrown 		deny->ld_clientid.cl_id = 0;
53121da177e4SLinus Torvalds 	}
53131da177e4SLinus Torvalds 	deny->ld_start = fl->fl_start;
531487df4de8SBenny Halevy 	deny->ld_length = NFS4_MAX_UINT64;
531587df4de8SBenny Halevy 	if (fl->fl_end != NFS4_MAX_UINT64)
53161da177e4SLinus Torvalds 		deny->ld_length = fl->fl_end - fl->fl_start + 1;
53171da177e4SLinus Torvalds 	deny->ld_type = NFS4_READ_LT;
53181da177e4SLinus Torvalds 	if (fl->fl_type != F_RDLCK)
53191da177e4SLinus Torvalds 		deny->ld_type = NFS4_WRITE_LT;
53201da177e4SLinus Torvalds }
53211da177e4SLinus Torvalds 
5322fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
5323c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner)
53241da177e4SLinus Torvalds {
5325d4f0489fSTrond Myklebust 	unsigned int strhashval = ownerstr_hashval(owner);
5326b3c32bcdSTrond Myklebust 	struct nfs4_stateowner *so;
53271da177e4SLinus Torvalds 
53280a880a28STrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
53290a880a28STrond Myklebust 
5330d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval],
5331d4f0489fSTrond Myklebust 			    so_strhash) {
5332b3c32bcdSTrond Myklebust 		if (so->so_is_open_owner)
5333b3c32bcdSTrond Myklebust 			continue;
5334b5971afaSKinglong Mee 		if (same_owner_str(so, owner))
5335b5971afaSKinglong Mee 			return lockowner(nfs4_get_stateowner(so));
53361da177e4SLinus Torvalds 	}
53371da177e4SLinus Torvalds 	return NULL;
53381da177e4SLinus Torvalds }
53391da177e4SLinus Torvalds 
5340c58c6610STrond Myklebust static struct nfs4_lockowner *
5341c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner)
5342c58c6610STrond Myklebust {
5343c58c6610STrond Myklebust 	struct nfs4_lockowner *lo;
5344c58c6610STrond Myklebust 
5345d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5346c8623999SKinglong Mee 	lo = find_lockowner_str_locked(clp, owner);
5347d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5348c58c6610STrond Myklebust 	return lo;
5349c58c6610STrond Myklebust }
5350c58c6610STrond Myklebust 
53518f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
53528f4b54c5SJeff Layton {
5353c58c6610STrond Myklebust 	unhash_lockowner_locked(lockowner(sop));
53548f4b54c5SJeff Layton }
53558f4b54c5SJeff Layton 
53566b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
53576b180f0bSJeff Layton {
53586b180f0bSJeff Layton 	struct nfs4_lockowner *lo = lockowner(sop);
53596b180f0bSJeff Layton 
53606b180f0bSJeff Layton 	kmem_cache_free(lockowner_slab, lo);
53616b180f0bSJeff Layton }
53626b180f0bSJeff Layton 
53636b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = {
53648f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_lockowner,
53656b180f0bSJeff Layton 	.so_free =	nfs4_free_lockowner,
53666b180f0bSJeff Layton };
53676b180f0bSJeff Layton 
53681da177e4SLinus Torvalds /*
53691da177e4SLinus Torvalds  * Alloc a lock owner structure.
53701da177e4SLinus Torvalds  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
537125985edcSLucas De Marchi  * occurred.
53721da177e4SLinus Torvalds  *
537316bfdaafSJ. Bruce Fields  * strhashval = ownerstr_hashval
53741da177e4SLinus Torvalds  */
5375fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
5376c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
5377c58c6610STrond Myklebust 			   struct nfs4_ol_stateid *open_stp,
5378c58c6610STrond Myklebust 			   struct nfsd4_lock *lock)
5379c58c6610STrond Myklebust {
5380c58c6610STrond Myklebust 	struct nfs4_lockowner *lo, *ret;
53811da177e4SLinus Torvalds 
5382fe0750e5SJ. Bruce Fields 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
5383fe0750e5SJ. Bruce Fields 	if (!lo)
53841da177e4SLinus Torvalds 		return NULL;
5385fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
5386fe0750e5SJ. Bruce Fields 	lo->lo_owner.so_is_open_owner = 0;
53875db1c03fSJeff Layton 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
53886b180f0bSJeff Layton 	lo->lo_owner.so_ops = &lockowner_ops;
5389d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5390c8623999SKinglong Mee 	ret = find_lockowner_str_locked(clp, &lock->lk_new_owner);
5391c58c6610STrond Myklebust 	if (ret == NULL) {
5392c58c6610STrond Myklebust 		list_add(&lo->lo_owner.so_strhash,
5393d4f0489fSTrond Myklebust 			 &clp->cl_ownerstr_hashtbl[strhashval]);
5394c58c6610STrond Myklebust 		ret = lo;
5395c58c6610STrond Myklebust 	} else
5396d50ffdedSKinglong Mee 		nfs4_free_stateowner(&lo->lo_owner);
5397d50ffdedSKinglong Mee 
5398d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5399340f0ba1SJ. Bruce Fields 	return ret;
54001da177e4SLinus Torvalds }
54011da177e4SLinus Torvalds 
5402356a95ecSJeff Layton static void
5403356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5404356a95ecSJeff Layton 		  struct nfs4_file *fp, struct inode *inode,
5405f9c00c3aSJeff Layton 		  struct nfs4_ol_stateid *open_stp)
54061da177e4SLinus Torvalds {
5407d3b313a4SJ. Bruce Fields 	struct nfs4_client *clp = lo->lo_owner.so_client;
54081da177e4SLinus Torvalds 
5409356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5410356a95ecSJeff Layton 
54113d0fabd5STrond Myklebust 	atomic_inc(&stp->st_stid.sc_count);
54123abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_LOCK_STID;
5413b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
541413cd2184SNeilBrown 	get_nfs4_file(fp);
541511b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
5416b49e084dSJeff Layton 	stp->st_stid.sc_free = nfs4_free_lock_stateid;
54170997b173SJ. Bruce Fields 	stp->st_access_bmap = 0;
54181da177e4SLinus Torvalds 	stp->st_deny_bmap = open_stp->st_deny_bmap;
54194c4cd222SNeilBrown 	stp->st_openstp = open_stp;
542035a92fe8SJeff Layton 	init_rwsem(&stp->st_rwsem);
54213c87b9b7STrond Myklebust 	list_add(&stp->st_locks, &open_stp->st_locks);
54221c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
54231d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
54241d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
54251d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
54261da177e4SLinus Torvalds }
54271da177e4SLinus Torvalds 
5428c53530daSJeff Layton static struct nfs4_ol_stateid *
5429c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
5430c53530daSJeff Layton {
5431c53530daSJeff Layton 	struct nfs4_ol_stateid *lst;
5432356a95ecSJeff Layton 	struct nfs4_client *clp = lo->lo_owner.so_client;
5433356a95ecSJeff Layton 
5434356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5435c53530daSJeff Layton 
5436c53530daSJeff Layton 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
54373d0fabd5STrond Myklebust 		if (lst->st_stid.sc_file == fp) {
54383d0fabd5STrond Myklebust 			atomic_inc(&lst->st_stid.sc_count);
5439c53530daSJeff Layton 			return lst;
5440c53530daSJeff Layton 		}
54413d0fabd5STrond Myklebust 	}
5442c53530daSJeff Layton 	return NULL;
5443c53530daSJeff Layton }
5444c53530daSJeff Layton 
5445356a95ecSJeff Layton static struct nfs4_ol_stateid *
5446356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
5447356a95ecSJeff Layton 			    struct inode *inode, struct nfs4_ol_stateid *ost,
5448356a95ecSJeff Layton 			    bool *new)
5449356a95ecSJeff Layton {
5450356a95ecSJeff Layton 	struct nfs4_stid *ns = NULL;
5451356a95ecSJeff Layton 	struct nfs4_ol_stateid *lst;
5452356a95ecSJeff Layton 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
5453356a95ecSJeff Layton 	struct nfs4_client *clp = oo->oo_owner.so_client;
5454356a95ecSJeff Layton 
5455356a95ecSJeff Layton 	spin_lock(&clp->cl_lock);
5456356a95ecSJeff Layton 	lst = find_lock_stateid(lo, fi);
5457356a95ecSJeff Layton 	if (lst == NULL) {
5458356a95ecSJeff Layton 		spin_unlock(&clp->cl_lock);
5459356a95ecSJeff Layton 		ns = nfs4_alloc_stid(clp, stateid_slab);
5460356a95ecSJeff Layton 		if (ns == NULL)
5461356a95ecSJeff Layton 			return NULL;
5462356a95ecSJeff Layton 
5463356a95ecSJeff Layton 		spin_lock(&clp->cl_lock);
5464356a95ecSJeff Layton 		lst = find_lock_stateid(lo, fi);
5465356a95ecSJeff Layton 		if (likely(!lst)) {
5466356a95ecSJeff Layton 			lst = openlockstateid(ns);
5467356a95ecSJeff Layton 			init_lock_stateid(lst, lo, fi, inode, ost);
5468356a95ecSJeff Layton 			ns = NULL;
5469356a95ecSJeff Layton 			*new = true;
5470356a95ecSJeff Layton 		}
5471356a95ecSJeff Layton 	}
5472356a95ecSJeff Layton 	spin_unlock(&clp->cl_lock);
5473356a95ecSJeff Layton 	if (ns)
5474356a95ecSJeff Layton 		nfs4_put_stid(ns);
5475356a95ecSJeff Layton 	return lst;
5476356a95ecSJeff Layton }
5477c53530daSJeff Layton 
5478fd39ca9aSNeilBrown static int
54791da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length)
54801da177e4SLinus Torvalds {
548187df4de8SBenny Halevy 	return ((length == 0) || ((length != NFS4_MAX_UINT64) &&
5482e7969315SKinglong Mee 		(length > ~offset)));
54831da177e4SLinus Torvalds }
54841da177e4SLinus Torvalds 
5485dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
54860997b173SJ. Bruce Fields {
548711b9164aSTrond Myklebust 	struct nfs4_file *fp = lock_stp->st_stid.sc_file;
54880997b173SJ. Bruce Fields 
54897214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
54907214e860SJeff Layton 
549182c5ff1bSJeff Layton 	if (test_access(access, lock_stp))
54920997b173SJ. Bruce Fields 		return;
549312659651SJeff Layton 	__nfs4_file_get_access(fp, access);
549482c5ff1bSJeff Layton 	set_access(access, lock_stp);
54950997b173SJ. Bruce Fields }
54960997b173SJ. Bruce Fields 
5497356a95ecSJeff Layton static __be32
5498356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5499356a95ecSJeff Layton 			    struct nfs4_ol_stateid *ost,
5500356a95ecSJeff Layton 			    struct nfsd4_lock *lock,
5501356a95ecSJeff Layton 			    struct nfs4_ol_stateid **lst, bool *new)
550264a284d0SJ. Bruce Fields {
55035db1c03fSJeff Layton 	__be32 status;
550411b9164aSTrond Myklebust 	struct nfs4_file *fi = ost->st_stid.sc_file;
550564a284d0SJ. Bruce Fields 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
550664a284d0SJ. Bruce Fields 	struct nfs4_client *cl = oo->oo_owner.so_client;
55072b0143b5SDavid Howells 	struct inode *inode = d_inode(cstate->current_fh.fh_dentry);
550864a284d0SJ. Bruce Fields 	struct nfs4_lockowner *lo;
550964a284d0SJ. Bruce Fields 	unsigned int strhashval;
551064a284d0SJ. Bruce Fields 
5511c8623999SKinglong Mee 	lo = find_lockowner_str(cl, &lock->lk_new_owner);
5512c53530daSJeff Layton 	if (!lo) {
551376f6c9e1SKinglong Mee 		strhashval = ownerstr_hashval(&lock->lk_new_owner);
551464a284d0SJ. Bruce Fields 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
551564a284d0SJ. Bruce Fields 		if (lo == NULL)
551664a284d0SJ. Bruce Fields 			return nfserr_jukebox;
5517c53530daSJeff Layton 	} else {
5518c53530daSJeff Layton 		/* with an existing lockowner, seqids must be the same */
55195db1c03fSJeff Layton 		status = nfserr_bad_seqid;
5520c53530daSJeff Layton 		if (!cstate->minorversion &&
5521c53530daSJeff Layton 		    lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
55225db1c03fSJeff Layton 			goto out;
5523c53530daSJeff Layton 	}
5524c53530daSJeff Layton 
5525356a95ecSJeff Layton 	*lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
552664a284d0SJ. Bruce Fields 	if (*lst == NULL) {
55275db1c03fSJeff Layton 		status = nfserr_jukebox;
55285db1c03fSJeff Layton 		goto out;
552964a284d0SJ. Bruce Fields 	}
55305db1c03fSJeff Layton 	status = nfs_ok;
55315db1c03fSJeff Layton out:
55325db1c03fSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
55335db1c03fSJeff Layton 	return status;
553464a284d0SJ. Bruce Fields }
553564a284d0SJ. Bruce Fields 
55361da177e4SLinus Torvalds /*
55371da177e4SLinus Torvalds  *  LOCK operation
55381da177e4SLinus Torvalds  */
5539b37ad28bSAl Viro __be32
5540ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5541a4f1706aSJ.Bruce Fields 	   struct nfsd4_lock *lock)
55421da177e4SLinus Torvalds {
5543fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *open_sop = NULL;
5544fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lock_sop = NULL;
55453d0fabd5STrond Myklebust 	struct nfs4_ol_stateid *lock_stp = NULL;
55460667b1e9STrond Myklebust 	struct nfs4_ol_stateid *open_stp = NULL;
55477214e860SJeff Layton 	struct nfs4_file *fp;
55487d947842SJ. Bruce Fields 	struct file *filp = NULL;
554921179d81SJeff Layton 	struct file_lock *file_lock = NULL;
555021179d81SJeff Layton 	struct file_lock *conflock = NULL;
5551b37ad28bSAl Viro 	__be32 status = 0;
5552b34f27aaSJ. Bruce Fields 	int lkflg;
5553b8dd7b9aSAl Viro 	int err;
55545db1c03fSJeff Layton 	bool new = false;
55553320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
55563320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
55571da177e4SLinus Torvalds 
55581da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
55591da177e4SLinus Torvalds 		(long long) lock->lk_offset,
55601da177e4SLinus Torvalds 		(long long) lock->lk_length);
55611da177e4SLinus Torvalds 
55621da177e4SLinus Torvalds 	if (check_lock_length(lock->lk_offset, lock->lk_length))
55631da177e4SLinus Torvalds 		 return nfserr_inval;
55641da177e4SLinus Torvalds 
5565ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh,
55668837abcaSMiklos Szeredi 				S_IFREG, NFSD_MAY_LOCK))) {
5567a6f6ef2fSAndy Adamson 		dprintk("NFSD: nfsd4_lock: permission denied!\n");
5568a6f6ef2fSAndy Adamson 		return status;
5569a6f6ef2fSAndy Adamson 	}
5570a6f6ef2fSAndy Adamson 
55711da177e4SLinus Torvalds 	if (lock->lk_is_new) {
5572684e5638SJ. Bruce Fields 		if (nfsd4_has_session(cstate))
5573684e5638SJ. Bruce Fields 			/* See rfc 5661 18.10.3: given clientid is ignored: */
557476f6c9e1SKinglong Mee 			memcpy(&lock->lk_new_clientid,
5575684e5638SJ. Bruce Fields 				&cstate->session->se_client->cl_clientid,
5576684e5638SJ. Bruce Fields 				sizeof(clientid_t));
5577684e5638SJ. Bruce Fields 
55781da177e4SLinus Torvalds 		status = nfserr_stale_clientid;
55792c142baaSStanislav Kinsbursky 		if (STALE_CLIENTID(&lock->lk_new_clientid, nn))
55801da177e4SLinus Torvalds 			goto out;
55811da177e4SLinus Torvalds 
55821da177e4SLinus Torvalds 		/* validate and update open stateid and open seqid */
5583c0a5d93eSJ. Bruce Fields 		status = nfs4_preprocess_confirmed_seqid_op(cstate,
55841da177e4SLinus Torvalds 				        lock->lk_new_open_seqid,
55851da177e4SLinus Torvalds 		                        &lock->lk_new_open_stateid,
55863320fef1SStanislav Kinsbursky 					&open_stp, nn);
558737515177SNeilBrown 		if (status)
55881da177e4SLinus Torvalds 			goto out;
558935a92fe8SJeff Layton 		up_write(&open_stp->st_rwsem);
5590fe0750e5SJ. Bruce Fields 		open_sop = openowner(open_stp->st_stateowner);
5591b34f27aaSJ. Bruce Fields 		status = nfserr_bad_stateid;
5592684e5638SJ. Bruce Fields 		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
559376f6c9e1SKinglong Mee 						&lock->lk_new_clientid))
5594b34f27aaSJ. Bruce Fields 			goto out;
559564a284d0SJ. Bruce Fields 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
55965db1c03fSJeff Layton 							&lock_stp, &new);
559735a92fe8SJeff Layton 		if (status == nfs_ok)
559835a92fe8SJeff Layton 			down_write(&lock_stp->st_rwsem);
55993d0fabd5STrond Myklebust 	} else {
5600dd453dfdSBenny Halevy 		status = nfs4_preprocess_seqid_op(cstate,
56011da177e4SLinus Torvalds 				       lock->lk_old_lock_seqid,
56021da177e4SLinus Torvalds 				       &lock->lk_old_lock_stateid,
56033320fef1SStanislav Kinsbursky 				       NFS4_LOCK_STID, &lock_stp, nn);
56043d0fabd5STrond Myklebust 	}
56051da177e4SLinus Torvalds 	if (status)
56061da177e4SLinus Torvalds 		goto out;
5607fe0750e5SJ. Bruce Fields 	lock_sop = lockowner(lock_stp->st_stateowner);
56081da177e4SLinus Torvalds 
5609b34f27aaSJ. Bruce Fields 	lkflg = setlkflg(lock->lk_type);
5610b34f27aaSJ. Bruce Fields 	status = nfs4_check_openmode(lock_stp, lkflg);
5611b34f27aaSJ. Bruce Fields 	if (status)
5612b34f27aaSJ. Bruce Fields 		goto out;
5613b34f27aaSJ. Bruce Fields 
56140dd395dcSNeilBrown 	status = nfserr_grace;
56153320fef1SStanislav Kinsbursky 	if (locks_in_grace(net) && !lock->lk_reclaim)
56160dd395dcSNeilBrown 		goto out;
56170dd395dcSNeilBrown 	status = nfserr_no_grace;
56183320fef1SStanislav Kinsbursky 	if (!locks_in_grace(net) && lock->lk_reclaim)
56190dd395dcSNeilBrown 		goto out;
56200dd395dcSNeilBrown 
562121179d81SJeff Layton 	file_lock = locks_alloc_lock();
562221179d81SJeff Layton 	if (!file_lock) {
562321179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
562421179d81SJeff Layton 		status = nfserr_jukebox;
562521179d81SJeff Layton 		goto out;
562621179d81SJeff Layton 	}
562721179d81SJeff Layton 
562811b9164aSTrond Myklebust 	fp = lock_stp->st_stid.sc_file;
56291da177e4SLinus Torvalds 	switch (lock->lk_type) {
56301da177e4SLinus Torvalds 		case NFS4_READ_LT:
56311da177e4SLinus Torvalds 		case NFS4_READW_LT:
56327214e860SJeff Layton 			spin_lock(&fp->fi_lock);
56337214e860SJeff Layton 			filp = find_readable_file_locked(fp);
56340997b173SJ. Bruce Fields 			if (filp)
56350997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
56367214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
563721179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
56381da177e4SLinus Torvalds 			break;
56391da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
56401da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
56417214e860SJeff Layton 			spin_lock(&fp->fi_lock);
56427214e860SJeff Layton 			filp = find_writeable_file_locked(fp);
56430997b173SJ. Bruce Fields 			if (filp)
56440997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
56457214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
564621179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
56471da177e4SLinus Torvalds 			break;
56481da177e4SLinus Torvalds 		default:
56491da177e4SLinus Torvalds 			status = nfserr_inval;
56501da177e4SLinus Torvalds 		goto out;
56511da177e4SLinus Torvalds 	}
5652f9d7562fSJ. Bruce Fields 	if (!filp) {
5653f9d7562fSJ. Bruce Fields 		status = nfserr_openmode;
5654f9d7562fSJ. Bruce Fields 		goto out;
5655f9d7562fSJ. Bruce Fields 	}
5656aef9583bSKinglong Mee 
5657aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
565821179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
565921179d81SJeff Layton 	file_lock->fl_file = filp;
566021179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
566121179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
566221179d81SJeff Layton 	file_lock->fl_start = lock->lk_offset;
566321179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
566421179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
56651da177e4SLinus Torvalds 
566621179d81SJeff Layton 	conflock = locks_alloc_lock();
566721179d81SJeff Layton 	if (!conflock) {
566821179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
566921179d81SJeff Layton 		status = nfserr_jukebox;
567021179d81SJeff Layton 		goto out;
567121179d81SJeff Layton 	}
56721da177e4SLinus Torvalds 
567321179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
5674b8dd7b9aSAl Viro 	switch (-err) {
56751da177e4SLinus Torvalds 	case 0: /* success! */
56769767feb2SJeff Layton 		nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid);
5677b8dd7b9aSAl Viro 		status = 0;
5678eb76b3fdSAndy Adamson 		break;
5679eb76b3fdSAndy Adamson 	case (EAGAIN):		/* conflock holds conflicting lock */
5680eb76b3fdSAndy Adamson 		status = nfserr_denied;
5681eb76b3fdSAndy Adamson 		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
568221179d81SJeff Layton 		nfs4_set_lock_denied(conflock, &lock->lk_denied);
5683eb76b3fdSAndy Adamson 		break;
56841da177e4SLinus Torvalds 	case (EDEADLK):
56851da177e4SLinus Torvalds 		status = nfserr_deadlock;
5686eb76b3fdSAndy Adamson 		break;
56871da177e4SLinus Torvalds 	default:
5688fd85b817SMarc Eshel 		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
56893e772463SJ. Bruce Fields 		status = nfserrno(err);
5690eb76b3fdSAndy Adamson 		break;
56911da177e4SLinus Torvalds 	}
56921da177e4SLinus Torvalds out:
5693de18643dSTrond Myklebust 	if (filp)
5694de18643dSTrond Myklebust 		fput(filp);
56955db1c03fSJeff Layton 	if (lock_stp) {
56965db1c03fSJeff Layton 		/* Bump seqid manually if the 4.0 replay owner is openowner */
56975db1c03fSJeff Layton 		if (cstate->replay_owner &&
56985db1c03fSJeff Layton 		    cstate->replay_owner != &lock_sop->lo_owner &&
56995db1c03fSJeff Layton 		    seqid_mutating_err(ntohl(status)))
57005db1c03fSJeff Layton 			lock_sop->lo_owner.so_seqid++;
57015db1c03fSJeff Layton 
570235a92fe8SJeff Layton 		up_write(&lock_stp->st_rwsem);
570335a92fe8SJeff Layton 
57045db1c03fSJeff Layton 		/*
57055db1c03fSJeff Layton 		 * If this is a new, never-before-used stateid, and we are
57065db1c03fSJeff Layton 		 * returning an error, then just go ahead and release it.
57075db1c03fSJeff Layton 		 */
57085db1c03fSJeff Layton 		if (status && new)
57095db1c03fSJeff Layton 			release_lock_stateid(lock_stp);
57105db1c03fSJeff Layton 
57113d0fabd5STrond Myklebust 		nfs4_put_stid(&lock_stp->st_stid);
57125db1c03fSJeff Layton 	}
57130667b1e9STrond Myklebust 	if (open_stp)
57140667b1e9STrond Myklebust 		nfs4_put_stid(&open_stp->st_stid);
57159411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
571621179d81SJeff Layton 	if (file_lock)
571721179d81SJeff Layton 		locks_free_lock(file_lock);
571821179d81SJeff Layton 	if (conflock)
571921179d81SJeff Layton 		locks_free_lock(conflock);
57201da177e4SLinus Torvalds 	return status;
57211da177e4SLinus Torvalds }
57221da177e4SLinus Torvalds 
57231da177e4SLinus Torvalds /*
572455ef1274SJ. Bruce Fields  * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
572555ef1274SJ. Bruce Fields  * so we do a temporary open here just to get an open file to pass to
572655ef1274SJ. Bruce Fields  * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
572755ef1274SJ. Bruce Fields  * inode operation.)
572855ef1274SJ. Bruce Fields  */
572904da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
573055ef1274SJ. Bruce Fields {
573155ef1274SJ. Bruce Fields 	struct file *file;
573204da6e9dSAl Viro 	__be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
573304da6e9dSAl Viro 	if (!err) {
573404da6e9dSAl Viro 		err = nfserrno(vfs_test_lock(file, lock));
5735fd891454SChristoph Hellwig 		fput(file);
573604da6e9dSAl Viro 	}
573755ef1274SJ. Bruce Fields 	return err;
573855ef1274SJ. Bruce Fields }
573955ef1274SJ. Bruce Fields 
574055ef1274SJ. Bruce Fields /*
57411da177e4SLinus Torvalds  * LOCKT operation
57421da177e4SLinus Torvalds  */
5743b37ad28bSAl Viro __be32
5744ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5745ca364317SJ.Bruce Fields 	    struct nfsd4_lockt *lockt)
57461da177e4SLinus Torvalds {
574721179d81SJeff Layton 	struct file_lock *file_lock = NULL;
57485db1c03fSJeff Layton 	struct nfs4_lockowner *lo = NULL;
5749b37ad28bSAl Viro 	__be32 status;
57507f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
57511da177e4SLinus Torvalds 
57525ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp)))
57531da177e4SLinus Torvalds 		return nfserr_grace;
57541da177e4SLinus Torvalds 
57551da177e4SLinus Torvalds 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
57561da177e4SLinus Torvalds 		 return nfserr_inval;
57571da177e4SLinus Torvalds 
57589b2ef62bSJ. Bruce Fields 	if (!nfsd4_has_session(cstate)) {
57594b24ca7dSJeff Layton 		status = lookup_clientid(&lockt->lt_clientid, cstate, nn);
57609b2ef62bSJ. Bruce Fields 		if (status)
57611da177e4SLinus Torvalds 			goto out;
57629b2ef62bSJ. Bruce Fields 	}
57631da177e4SLinus Torvalds 
576475c096f7SJ. Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
57651da177e4SLinus Torvalds 		goto out;
57661da177e4SLinus Torvalds 
576721179d81SJeff Layton 	file_lock = locks_alloc_lock();
576821179d81SJeff Layton 	if (!file_lock) {
576921179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
577021179d81SJeff Layton 		status = nfserr_jukebox;
577121179d81SJeff Layton 		goto out;
577221179d81SJeff Layton 	}
57736cd90662SKinglong Mee 
57741da177e4SLinus Torvalds 	switch (lockt->lt_type) {
57751da177e4SLinus Torvalds 		case NFS4_READ_LT:
57761da177e4SLinus Torvalds 		case NFS4_READW_LT:
577721179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
57781da177e4SLinus Torvalds 		break;
57791da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
57801da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
578121179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
57821da177e4SLinus Torvalds 		break;
57831da177e4SLinus Torvalds 		default:
57842fdada03SJ. Bruce Fields 			dprintk("NFSD: nfs4_lockt: bad lock type!\n");
57851da177e4SLinus Torvalds 			status = nfserr_inval;
57861da177e4SLinus Torvalds 		goto out;
57871da177e4SLinus Torvalds 	}
57881da177e4SLinus Torvalds 
5789c8623999SKinglong Mee 	lo = find_lockowner_str(cstate->clp, &lockt->lt_owner);
5790fe0750e5SJ. Bruce Fields 	if (lo)
579121179d81SJeff Layton 		file_lock->fl_owner = (fl_owner_t)lo;
579221179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
579321179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
57941da177e4SLinus Torvalds 
579521179d81SJeff Layton 	file_lock->fl_start = lockt->lt_offset;
579621179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
57971da177e4SLinus Torvalds 
579821179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
57991da177e4SLinus Torvalds 
580021179d81SJeff Layton 	status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
580104da6e9dSAl Viro 	if (status)
5802fd85b817SMarc Eshel 		goto out;
580304da6e9dSAl Viro 
580421179d81SJeff Layton 	if (file_lock->fl_type != F_UNLCK) {
58051da177e4SLinus Torvalds 		status = nfserr_denied;
580621179d81SJeff Layton 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
58071da177e4SLinus Torvalds 	}
58081da177e4SLinus Torvalds out:
58095db1c03fSJeff Layton 	if (lo)
58105db1c03fSJeff Layton 		nfs4_put_stateowner(&lo->lo_owner);
581121179d81SJeff Layton 	if (file_lock)
581221179d81SJeff Layton 		locks_free_lock(file_lock);
58131da177e4SLinus Torvalds 	return status;
58141da177e4SLinus Torvalds }
58151da177e4SLinus Torvalds 
5816b37ad28bSAl Viro __be32
5817ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5818a4f1706aSJ.Bruce Fields 	    struct nfsd4_locku *locku)
58191da177e4SLinus Torvalds {
5820dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
58211da177e4SLinus Torvalds 	struct file *filp = NULL;
582221179d81SJeff Layton 	struct file_lock *file_lock = NULL;
5823b37ad28bSAl Viro 	__be32 status;
5824b8dd7b9aSAl Viro 	int err;
58253320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
58261da177e4SLinus Torvalds 
58271da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
58281da177e4SLinus Torvalds 		(long long) locku->lu_offset,
58291da177e4SLinus Torvalds 		(long long) locku->lu_length);
58301da177e4SLinus Torvalds 
58311da177e4SLinus Torvalds 	if (check_lock_length(locku->lu_offset, locku->lu_length))
58321da177e4SLinus Torvalds 		 return nfserr_inval;
58331da177e4SLinus Torvalds 
58349072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
58353320fef1SStanislav Kinsbursky 					&locku->lu_stateid, NFS4_LOCK_STID,
58363320fef1SStanislav Kinsbursky 					&stp, nn);
58379072d5c6SJ. Bruce Fields 	if (status)
58381da177e4SLinus Torvalds 		goto out;
583911b9164aSTrond Myklebust 	filp = find_any_file(stp->st_stid.sc_file);
5840f9d7562fSJ. Bruce Fields 	if (!filp) {
5841f9d7562fSJ. Bruce Fields 		status = nfserr_lock_range;
5842858cc573STrond Myklebust 		goto put_stateid;
5843f9d7562fSJ. Bruce Fields 	}
584421179d81SJeff Layton 	file_lock = locks_alloc_lock();
584521179d81SJeff Layton 	if (!file_lock) {
584621179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
584721179d81SJeff Layton 		status = nfserr_jukebox;
5848de18643dSTrond Myklebust 		goto fput;
584921179d81SJeff Layton 	}
58506cd90662SKinglong Mee 
585121179d81SJeff Layton 	file_lock->fl_type = F_UNLCK;
5852aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
585321179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
585421179d81SJeff Layton 	file_lock->fl_file = filp;
585521179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
585621179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
585721179d81SJeff Layton 	file_lock->fl_start = locku->lu_offset;
58581da177e4SLinus Torvalds 
585921179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(locku->lu_offset,
586021179d81SJeff Layton 						locku->lu_length);
586121179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
58621da177e4SLinus Torvalds 
586321179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
5864b8dd7b9aSAl Viro 	if (err) {
5865fd85b817SMarc Eshel 		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
58661da177e4SLinus Torvalds 		goto out_nfserr;
58671da177e4SLinus Torvalds 	}
58689767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid);
5869de18643dSTrond Myklebust fput:
5870de18643dSTrond Myklebust 	fput(filp);
5871858cc573STrond Myklebust put_stateid:
587235a92fe8SJeff Layton 	up_write(&stp->st_rwsem);
5873858cc573STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
58741da177e4SLinus Torvalds out:
58759411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
587621179d81SJeff Layton 	if (file_lock)
587721179d81SJeff Layton 		locks_free_lock(file_lock);
58781da177e4SLinus Torvalds 	return status;
58791da177e4SLinus Torvalds 
58801da177e4SLinus Torvalds out_nfserr:
5881b8dd7b9aSAl Viro 	status = nfserrno(err);
5882de18643dSTrond Myklebust 	goto fput;
58831da177e4SLinus Torvalds }
58841da177e4SLinus Torvalds 
58851da177e4SLinus Torvalds /*
58861da177e4SLinus Torvalds  * returns
5887f9c00c3aSJeff Layton  * 	true:  locks held by lockowner
5888f9c00c3aSJeff Layton  * 	false: no locks held by lockowner
58891da177e4SLinus Torvalds  */
5890f9c00c3aSJeff Layton static bool
5891f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
58921da177e4SLinus Torvalds {
5893bd61e0a9SJeff Layton 	struct file_lock *fl;
5894f9c00c3aSJeff Layton 	int status = false;
5895f9c00c3aSJeff Layton 	struct file *filp = find_any_file(fp);
5896f9c00c3aSJeff Layton 	struct inode *inode;
5897bd61e0a9SJeff Layton 	struct file_lock_context *flctx;
5898f9c00c3aSJeff Layton 
5899f9c00c3aSJeff Layton 	if (!filp) {
5900f9c00c3aSJeff Layton 		/* Any valid lock stateid should have some sort of access */
5901f9c00c3aSJeff Layton 		WARN_ON_ONCE(1);
5902f9c00c3aSJeff Layton 		return status;
5903f9c00c3aSJeff Layton 	}
5904f9c00c3aSJeff Layton 
5905f9c00c3aSJeff Layton 	inode = file_inode(filp);
5906bd61e0a9SJeff Layton 	flctx = inode->i_flctx;
59071da177e4SLinus Torvalds 
5908bd61e0a9SJeff Layton 	if (flctx && !list_empty_careful(&flctx->flc_posix)) {
59096109c850SJeff Layton 		spin_lock(&flctx->flc_lock);
5910bd61e0a9SJeff Layton 		list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
5911bd61e0a9SJeff Layton 			if (fl->fl_owner == (fl_owner_t)lowner) {
5912f9c00c3aSJeff Layton 				status = true;
5913f9c00c3aSJeff Layton 				break;
59141da177e4SLinus Torvalds 			}
5915796dadfdSJ. Bruce Fields 		}
59166109c850SJeff Layton 		spin_unlock(&flctx->flc_lock);
5917bd61e0a9SJeff Layton 	}
5918f9c00c3aSJeff Layton 	fput(filp);
59191da177e4SLinus Torvalds 	return status;
59201da177e4SLinus Torvalds }
59211da177e4SLinus Torvalds 
5922b37ad28bSAl Viro __be32
5923b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp,
5924b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
5925b591480bSJ.Bruce Fields 			struct nfsd4_release_lockowner *rlockowner)
59261da177e4SLinus Torvalds {
59271da177e4SLinus Torvalds 	clientid_t *clid = &rlockowner->rl_clientid;
5928882e9d25SJeff Layton 	struct nfs4_stateowner *sop;
5929882e9d25SJeff Layton 	struct nfs4_lockowner *lo = NULL;
5930dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
59311da177e4SLinus Torvalds 	struct xdr_netobj *owner = &rlockowner->rl_owner;
5932d4f0489fSTrond Myklebust 	unsigned int hashval = ownerstr_hashval(owner);
5933b37ad28bSAl Viro 	__be32 status;
59347f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
5935c58c6610STrond Myklebust 	struct nfs4_client *clp;
59361da177e4SLinus Torvalds 
59371da177e4SLinus Torvalds 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
59381da177e4SLinus Torvalds 		clid->cl_boot, clid->cl_id);
59391da177e4SLinus Torvalds 
59404b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
59419b2ef62bSJ. Bruce Fields 	if (status)
594251f5e783STrond Myklebust 		return status;
59439b2ef62bSJ. Bruce Fields 
5944d4f0489fSTrond Myklebust 	clp = cstate->clp;
5945fd44907cSJeff Layton 	/* Find the matching lock stateowner */
5946d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5947882e9d25SJeff Layton 	list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval],
5948d4f0489fSTrond Myklebust 			    so_strhash) {
5949882e9d25SJeff Layton 
5950882e9d25SJeff Layton 		if (sop->so_is_open_owner || !same_owner_str(sop, owner))
595116bfdaafSJ. Bruce Fields 			continue;
5952882e9d25SJeff Layton 
5953882e9d25SJeff Layton 		/* see if there are still any locks associated with it */
5954882e9d25SJeff Layton 		lo = lockowner(sop);
5955882e9d25SJeff Layton 		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
5956882e9d25SJeff Layton 			if (check_for_locks(stp->st_stid.sc_file, lo)) {
5957882e9d25SJeff Layton 				status = nfserr_locks_held;
5958882e9d25SJeff Layton 				spin_unlock(&clp->cl_lock);
595951f5e783STrond Myklebust 				return status;
5960882e9d25SJeff Layton 			}
5961882e9d25SJeff Layton 		}
5962882e9d25SJeff Layton 
5963b5971afaSKinglong Mee 		nfs4_get_stateowner(sop);
5964fd44907cSJeff Layton 		break;
5965fd44907cSJeff Layton 	}
5966d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5967882e9d25SJeff Layton 	if (lo)
5968fe0750e5SJ. Bruce Fields 		release_lockowner(lo);
59691da177e4SLinus Torvalds 	return status;
59701da177e4SLinus Torvalds }
59711da177e4SLinus Torvalds 
59721da177e4SLinus Torvalds static inline struct nfs4_client_reclaim *
5973a55370a3SNeilBrown alloc_reclaim(void)
59741da177e4SLinus Torvalds {
5975a55370a3SNeilBrown 	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
59761da177e4SLinus Torvalds }
59771da177e4SLinus Torvalds 
59780ce0c2b5SJeff Layton bool
597952e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
5980c7b9a459SNeilBrown {
59810ce0c2b5SJeff Layton 	struct nfs4_client_reclaim *crp;
5982c7b9a459SNeilBrown 
598352e19c09SStanislav Kinsbursky 	crp = nfsd4_find_reclaim_client(name, nn);
59840ce0c2b5SJeff Layton 	return (crp && crp->cr_clp);
5985c7b9a459SNeilBrown }
5986c7b9a459SNeilBrown 
59871da177e4SLinus Torvalds /*
59881da177e4SLinus Torvalds  * failure => all reset bets are off, nfserr_no_grace...
59891da177e4SLinus Torvalds  */
5990772a9bbbSJeff Layton struct nfs4_client_reclaim *
599152e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
59921da177e4SLinus Torvalds {
59931da177e4SLinus Torvalds 	unsigned int strhashval;
5994772a9bbbSJeff Layton 	struct nfs4_client_reclaim *crp;
59951da177e4SLinus Torvalds 
5996a55370a3SNeilBrown 	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
5997a55370a3SNeilBrown 	crp = alloc_reclaim();
5998772a9bbbSJeff Layton 	if (crp) {
5999a55370a3SNeilBrown 		strhashval = clientstr_hashval(name);
60001da177e4SLinus Torvalds 		INIT_LIST_HEAD(&crp->cr_strhash);
600152e19c09SStanislav Kinsbursky 		list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
6002a55370a3SNeilBrown 		memcpy(crp->cr_recdir, name, HEXDIR_LEN);
60030ce0c2b5SJeff Layton 		crp->cr_clp = NULL;
600452e19c09SStanislav Kinsbursky 		nn->reclaim_str_hashtbl_size++;
6005772a9bbbSJeff Layton 	}
6006772a9bbbSJeff Layton 	return crp;
60071da177e4SLinus Torvalds }
60081da177e4SLinus Torvalds 
60092a4317c5SJeff Layton void
601052e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
6011ce30e539SJeff Layton {
6012ce30e539SJeff Layton 	list_del(&crp->cr_strhash);
6013ce30e539SJeff Layton 	kfree(crp);
601452e19c09SStanislav Kinsbursky 	nn->reclaim_str_hashtbl_size--;
6015ce30e539SJeff Layton }
6016ce30e539SJeff Layton 
6017ce30e539SJeff Layton void
601852e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn)
60191da177e4SLinus Torvalds {
60201da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
60211da177e4SLinus Torvalds 	int i;
60221da177e4SLinus Torvalds 
60231da177e4SLinus Torvalds 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
602452e19c09SStanislav Kinsbursky 		while (!list_empty(&nn->reclaim_str_hashtbl[i])) {
602552e19c09SStanislav Kinsbursky 			crp = list_entry(nn->reclaim_str_hashtbl[i].next,
60261da177e4SLinus Torvalds 			                struct nfs4_client_reclaim, cr_strhash);
602752e19c09SStanislav Kinsbursky 			nfs4_remove_reclaim_record(crp, nn);
60281da177e4SLinus Torvalds 		}
60291da177e4SLinus Torvalds 	}
6030063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(nn->reclaim_str_hashtbl_size);
60311da177e4SLinus Torvalds }
60321da177e4SLinus Torvalds 
60331da177e4SLinus Torvalds /*
60341da177e4SLinus Torvalds  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
60352a4317c5SJeff Layton struct nfs4_client_reclaim *
603652e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
60371da177e4SLinus Torvalds {
60381da177e4SLinus Torvalds 	unsigned int strhashval;
60391da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
60401da177e4SLinus Torvalds 
6041278c931cSJeff Layton 	dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
60421da177e4SLinus Torvalds 
6043278c931cSJeff Layton 	strhashval = clientstr_hashval(recdir);
604452e19c09SStanislav Kinsbursky 	list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
6045278c931cSJeff Layton 		if (same_name(crp->cr_recdir, recdir)) {
60461da177e4SLinus Torvalds 			return crp;
60471da177e4SLinus Torvalds 		}
60481da177e4SLinus Torvalds 	}
60491da177e4SLinus Torvalds 	return NULL;
60501da177e4SLinus Torvalds }
60511da177e4SLinus Torvalds 
60521da177e4SLinus Torvalds /*
60531da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list.
60541da177e4SLinus Torvalds */
6055b37ad28bSAl Viro __be32
60560fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid,
60570fe492dbSTrond Myklebust 		struct nfsd4_compound_state *cstate,
60580fe492dbSTrond Myklebust 		struct nfsd_net *nn)
60591da177e4SLinus Torvalds {
60600fe492dbSTrond Myklebust 	__be32 status;
6061a52d726bSJeff Layton 
6062a52d726bSJeff Layton 	/* find clientid in conf_id_hashtbl */
60630fe492dbSTrond Myklebust 	status = lookup_clientid(clid, cstate, nn);
60640fe492dbSTrond Myklebust 	if (status)
6065a52d726bSJeff Layton 		return nfserr_reclaim_bad;
6066a52d726bSJeff Layton 
60673b3e7b72SJeff Layton 	if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags))
60683b3e7b72SJeff Layton 		return nfserr_no_grace;
60693b3e7b72SJeff Layton 
60700fe492dbSTrond Myklebust 	if (nfsd4_client_record_check(cstate->clp))
60710fe492dbSTrond Myklebust 		return nfserr_reclaim_bad;
60720fe492dbSTrond Myklebust 
60730fe492dbSTrond Myklebust 	return nfs_ok;
60741da177e4SLinus Torvalds }
60751da177e4SLinus Torvalds 
607665178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION
6077016200c3SJeff Layton static inline void
6078016200c3SJeff Layton put_client(struct nfs4_client *clp)
6079016200c3SJeff Layton {
6080016200c3SJeff Layton 	atomic_dec(&clp->cl_refcount);
6081016200c3SJeff Layton }
6082016200c3SJeff Layton 
6083285abdeeSJeff Layton static struct nfs4_client *
6084285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
6085285abdeeSJeff Layton {
6086285abdeeSJeff Layton 	struct nfs4_client *clp;
6087285abdeeSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6088285abdeeSJeff Layton 					  nfsd_net_id);
6089285abdeeSJeff Layton 
6090285abdeeSJeff Layton 	if (!nfsd_netns_ready(nn))
6091285abdeeSJeff Layton 		return NULL;
6092285abdeeSJeff Layton 
6093285abdeeSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
6094285abdeeSJeff Layton 		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
6095285abdeeSJeff Layton 			return clp;
6096285abdeeSJeff Layton 	}
6097285abdeeSJeff Layton 	return NULL;
6098285abdeeSJeff Layton }
6099285abdeeSJeff Layton 
61007ec0e36fSJeff Layton u64
6101285abdeeSJeff Layton nfsd_inject_print_clients(void)
61027ec0e36fSJeff Layton {
61037ec0e36fSJeff Layton 	struct nfs4_client *clp;
61047ec0e36fSJeff Layton 	u64 count = 0;
61057ec0e36fSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
61067ec0e36fSJeff Layton 					  nfsd_net_id);
61077ec0e36fSJeff Layton 	char buf[INET6_ADDRSTRLEN];
61087ec0e36fSJeff Layton 
61097ec0e36fSJeff Layton 	if (!nfsd_netns_ready(nn))
61107ec0e36fSJeff Layton 		return 0;
61117ec0e36fSJeff Layton 
61127ec0e36fSJeff Layton 	spin_lock(&nn->client_lock);
61137ec0e36fSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
61147ec0e36fSJeff Layton 		rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
61157ec0e36fSJeff Layton 		pr_info("NFS Client: %s\n", buf);
61167ec0e36fSJeff Layton 		++count;
61177ec0e36fSJeff Layton 	}
61187ec0e36fSJeff Layton 	spin_unlock(&nn->client_lock);
61197ec0e36fSJeff Layton 
61207ec0e36fSJeff Layton 	return count;
61217ec0e36fSJeff Layton }
612265178db4SBryan Schumaker 
6123a0926d15SJeff Layton u64
6124285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size)
6125a0926d15SJeff Layton {
6126a0926d15SJeff Layton 	u64 count = 0;
6127a0926d15SJeff Layton 	struct nfs4_client *clp;
6128a0926d15SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6129a0926d15SJeff Layton 					  nfsd_net_id);
6130a0926d15SJeff Layton 
6131a0926d15SJeff Layton 	if (!nfsd_netns_ready(nn))
6132a0926d15SJeff Layton 		return count;
6133a0926d15SJeff Layton 
6134a0926d15SJeff Layton 	spin_lock(&nn->client_lock);
6135a0926d15SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
6136a0926d15SJeff Layton 	if (clp) {
6137a0926d15SJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok)
6138a0926d15SJeff Layton 			++count;
6139a0926d15SJeff Layton 		else
6140a0926d15SJeff Layton 			clp = NULL;
6141a0926d15SJeff Layton 	}
6142a0926d15SJeff Layton 	spin_unlock(&nn->client_lock);
6143a0926d15SJeff Layton 
6144a0926d15SJeff Layton 	if (clp)
6145a0926d15SJeff Layton 		expire_client(clp);
6146a0926d15SJeff Layton 
6147a0926d15SJeff Layton 	return count;
6148a0926d15SJeff Layton }
6149a0926d15SJeff Layton 
615069fc9edfSJeff Layton u64
6151285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max)
615269fc9edfSJeff Layton {
615369fc9edfSJeff Layton 	u64 count = 0;
615469fc9edfSJeff Layton 	struct nfs4_client *clp, *next;
615569fc9edfSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
615669fc9edfSJeff Layton 						nfsd_net_id);
615769fc9edfSJeff Layton 	LIST_HEAD(reaplist);
615869fc9edfSJeff Layton 
615969fc9edfSJeff Layton 	if (!nfsd_netns_ready(nn))
616069fc9edfSJeff Layton 		return count;
616169fc9edfSJeff Layton 
616269fc9edfSJeff Layton 	spin_lock(&nn->client_lock);
616369fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
616469fc9edfSJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok) {
616569fc9edfSJeff Layton 			list_add(&clp->cl_lru, &reaplist);
616669fc9edfSJeff Layton 			if (max != 0 && ++count >= max)
616769fc9edfSJeff Layton 				break;
616869fc9edfSJeff Layton 		}
616969fc9edfSJeff Layton 	}
617069fc9edfSJeff Layton 	spin_unlock(&nn->client_lock);
617169fc9edfSJeff Layton 
617269fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
617369fc9edfSJeff Layton 		expire_client(clp);
617469fc9edfSJeff Layton 
617569fc9edfSJeff Layton 	return count;
617669fc9edfSJeff Layton }
617769fc9edfSJeff Layton 
6178184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
6179184c1847SBryan Schumaker 			     const char *type)
6180184c1847SBryan Schumaker {
6181184c1847SBryan Schumaker 	char buf[INET6_ADDRSTRLEN];
61820a5c33e2SBryan Schumaker 	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
6183184c1847SBryan Schumaker 	printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
6184184c1847SBryan Schumaker }
6185184c1847SBryan Schumaker 
6186016200c3SJeff Layton static void
6187016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
6188016200c3SJeff Layton 			     struct list_head *collect)
6189016200c3SJeff Layton {
6190016200c3SJeff Layton 	struct nfs4_client *clp = lst->st_stid.sc_client;
6191016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6192016200c3SJeff Layton 					  nfsd_net_id);
6193016200c3SJeff Layton 
6194016200c3SJeff Layton 	if (!collect)
6195016200c3SJeff Layton 		return;
6196016200c3SJeff Layton 
6197016200c3SJeff Layton 	lockdep_assert_held(&nn->client_lock);
6198016200c3SJeff Layton 	atomic_inc(&clp->cl_refcount);
6199016200c3SJeff Layton 	list_add(&lst->st_locks, collect);
6200016200c3SJeff Layton }
6201016200c3SJeff Layton 
62023c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
62033738d50eSJeff Layton 				    struct list_head *collect,
6204e8568739SJeff Layton 				    bool (*func)(struct nfs4_ol_stateid *))
6205fc29171fSBryan Schumaker {
6206fc29171fSBryan Schumaker 	struct nfs4_openowner *oop;
6207fc29171fSBryan Schumaker 	struct nfs4_ol_stateid *stp, *st_next;
62083c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *lst, *lst_next;
6209fc29171fSBryan Schumaker 	u64 count = 0;
6210fc29171fSBryan Schumaker 
6211016200c3SJeff Layton 	spin_lock(&clp->cl_lock);
6212fc29171fSBryan Schumaker 	list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
62133c87b9b7STrond Myklebust 		list_for_each_entry_safe(stp, st_next,
62143c87b9b7STrond Myklebust 				&oop->oo_owner.so_stateids, st_perstateowner) {
62153c87b9b7STrond Myklebust 			list_for_each_entry_safe(lst, lst_next,
62163c87b9b7STrond Myklebust 					&stp->st_locks, st_locks) {
62173738d50eSJeff Layton 				if (func) {
6218e8568739SJeff Layton 					if (func(lst))
6219016200c3SJeff Layton 						nfsd_inject_add_lock_to_list(lst,
62203738d50eSJeff Layton 									collect);
62213738d50eSJeff Layton 				}
6222016200c3SJeff Layton 				++count;
6223016200c3SJeff Layton 				/*
6224016200c3SJeff Layton 				 * Despite the fact that these functions deal
6225016200c3SJeff Layton 				 * with 64-bit integers for "count", we must
6226016200c3SJeff Layton 				 * ensure that it doesn't blow up the
6227016200c3SJeff Layton 				 * clp->cl_refcount. Throw a warning if we
6228016200c3SJeff Layton 				 * start to approach INT_MAX here.
6229016200c3SJeff Layton 				 */
6230016200c3SJeff Layton 				WARN_ON_ONCE(count == (INT_MAX / 2));
6231016200c3SJeff Layton 				if (count == max)
6232016200c3SJeff Layton 					goto out;
6233fc29171fSBryan Schumaker 			}
6234fc29171fSBryan Schumaker 		}
6235fc29171fSBryan Schumaker 	}
6236016200c3SJeff Layton out:
6237016200c3SJeff Layton 	spin_unlock(&clp->cl_lock);
6238fc29171fSBryan Schumaker 
6239fc29171fSBryan Schumaker 	return count;
6240fc29171fSBryan Schumaker }
6241fc29171fSBryan Schumaker 
6242016200c3SJeff Layton static u64
6243016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
6244016200c3SJeff Layton 			  u64 max)
6245fc29171fSBryan Schumaker {
6246016200c3SJeff Layton 	return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
6247fc29171fSBryan Schumaker }
6248fc29171fSBryan Schumaker 
6249016200c3SJeff Layton static u64
6250016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp)
6251184c1847SBryan Schumaker {
6252016200c3SJeff Layton 	u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
6253184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "locked files");
6254184c1847SBryan Schumaker 	return count;
6255184c1847SBryan Schumaker }
6256184c1847SBryan Schumaker 
6257016200c3SJeff Layton u64
6258285abdeeSJeff Layton nfsd_inject_print_locks(void)
6259016200c3SJeff Layton {
6260016200c3SJeff Layton 	struct nfs4_client *clp;
6261016200c3SJeff Layton 	u64 count = 0;
6262016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6263016200c3SJeff Layton 						nfsd_net_id);
6264016200c3SJeff Layton 
6265016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6266016200c3SJeff Layton 		return 0;
6267016200c3SJeff Layton 
6268016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6269016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
6270016200c3SJeff Layton 		count += nfsd_print_client_locks(clp);
6271016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6272016200c3SJeff Layton 
6273016200c3SJeff Layton 	return count;
6274016200c3SJeff Layton }
6275016200c3SJeff Layton 
6276016200c3SJeff Layton static void
6277016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist)
6278016200c3SJeff Layton {
6279016200c3SJeff Layton 	struct nfs4_client *clp;
6280016200c3SJeff Layton 	struct nfs4_ol_stateid *stp, *next;
6281016200c3SJeff Layton 
6282016200c3SJeff Layton 	list_for_each_entry_safe(stp, next, reaplist, st_locks) {
6283016200c3SJeff Layton 		list_del_init(&stp->st_locks);
6284016200c3SJeff Layton 		clp = stp->st_stid.sc_client;
6285016200c3SJeff Layton 		nfs4_put_stid(&stp->st_stid);
6286016200c3SJeff Layton 		put_client(clp);
6287016200c3SJeff Layton 	}
6288016200c3SJeff Layton }
6289016200c3SJeff Layton 
6290016200c3SJeff Layton u64
6291285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size)
6292016200c3SJeff Layton {
6293016200c3SJeff Layton 	unsigned int count = 0;
6294016200c3SJeff Layton 	struct nfs4_client *clp;
6295016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6296016200c3SJeff Layton 						nfsd_net_id);
6297016200c3SJeff Layton 	LIST_HEAD(reaplist);
6298016200c3SJeff Layton 
6299016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6300016200c3SJeff Layton 		return count;
6301016200c3SJeff Layton 
6302016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6303016200c3SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
6304016200c3SJeff Layton 	if (clp)
6305016200c3SJeff Layton 		count = nfsd_collect_client_locks(clp, &reaplist, 0);
6306016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6307016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
6308016200c3SJeff Layton 	return count;
6309016200c3SJeff Layton }
6310016200c3SJeff Layton 
6311016200c3SJeff Layton u64
6312285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max)
6313016200c3SJeff Layton {
6314016200c3SJeff Layton 	u64 count = 0;
6315016200c3SJeff Layton 	struct nfs4_client *clp;
6316016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6317016200c3SJeff Layton 						nfsd_net_id);
6318016200c3SJeff Layton 	LIST_HEAD(reaplist);
6319016200c3SJeff Layton 
6320016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6321016200c3SJeff Layton 		return count;
6322016200c3SJeff Layton 
6323016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6324016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
6325016200c3SJeff Layton 		count += nfsd_collect_client_locks(clp, &reaplist, max - count);
6326016200c3SJeff Layton 		if (max != 0 && count >= max)
6327016200c3SJeff Layton 			break;
6328016200c3SJeff Layton 	}
6329016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6330016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
6331016200c3SJeff Layton 	return count;
6332016200c3SJeff Layton }
6333016200c3SJeff Layton 
633482e05efaSJeff Layton static u64
633582e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
633682e05efaSJeff Layton 			      struct list_head *collect,
633782e05efaSJeff Layton 			      void (*func)(struct nfs4_openowner *))
63384dbdbda8SBryan Schumaker {
63394dbdbda8SBryan Schumaker 	struct nfs4_openowner *oop, *next;
634082e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
634182e05efaSJeff Layton 						nfsd_net_id);
63424dbdbda8SBryan Schumaker 	u64 count = 0;
63434dbdbda8SBryan Schumaker 
634482e05efaSJeff Layton 	lockdep_assert_held(&nn->client_lock);
634582e05efaSJeff Layton 
634682e05efaSJeff Layton 	spin_lock(&clp->cl_lock);
63474dbdbda8SBryan Schumaker 	list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
634882e05efaSJeff Layton 		if (func) {
63494dbdbda8SBryan Schumaker 			func(oop);
635082e05efaSJeff Layton 			if (collect) {
635182e05efaSJeff Layton 				atomic_inc(&clp->cl_refcount);
635282e05efaSJeff Layton 				list_add(&oop->oo_perclient, collect);
635382e05efaSJeff Layton 			}
635482e05efaSJeff Layton 		}
635582e05efaSJeff Layton 		++count;
635682e05efaSJeff Layton 		/*
635782e05efaSJeff Layton 		 * Despite the fact that these functions deal with
635882e05efaSJeff Layton 		 * 64-bit integers for "count", we must ensure that
635982e05efaSJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
636082e05efaSJeff Layton 		 * warning if we start to approach INT_MAX here.
636182e05efaSJeff Layton 		 */
636282e05efaSJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
636382e05efaSJeff Layton 		if (count == max)
63644dbdbda8SBryan Schumaker 			break;
63654dbdbda8SBryan Schumaker 	}
636682e05efaSJeff Layton 	spin_unlock(&clp->cl_lock);
63674dbdbda8SBryan Schumaker 
63684dbdbda8SBryan Schumaker 	return count;
63694dbdbda8SBryan Schumaker }
63704dbdbda8SBryan Schumaker 
637182e05efaSJeff Layton static u64
637282e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp)
63734dbdbda8SBryan Schumaker {
637482e05efaSJeff Layton 	u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
637582e05efaSJeff Layton 
637682e05efaSJeff Layton 	nfsd_print_count(clp, count, "openowners");
637782e05efaSJeff Layton 	return count;
63784dbdbda8SBryan Schumaker }
63794dbdbda8SBryan Schumaker 
638082e05efaSJeff Layton static u64
638182e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp,
638282e05efaSJeff Layton 			       struct list_head *collect, u64 max)
6383184c1847SBryan Schumaker {
638482e05efaSJeff Layton 	return nfsd_foreach_client_openowner(clp, max, collect,
638582e05efaSJeff Layton 						unhash_openowner_locked);
638682e05efaSJeff Layton }
638782e05efaSJeff Layton 
638882e05efaSJeff Layton u64
6389285abdeeSJeff Layton nfsd_inject_print_openowners(void)
639082e05efaSJeff Layton {
639182e05efaSJeff Layton 	struct nfs4_client *clp;
639282e05efaSJeff Layton 	u64 count = 0;
639382e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
639482e05efaSJeff Layton 						nfsd_net_id);
639582e05efaSJeff Layton 
639682e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
639782e05efaSJeff Layton 		return 0;
639882e05efaSJeff Layton 
639982e05efaSJeff Layton 	spin_lock(&nn->client_lock);
640082e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
640182e05efaSJeff Layton 		count += nfsd_print_client_openowners(clp);
640282e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
640382e05efaSJeff Layton 
640482e05efaSJeff Layton 	return count;
640582e05efaSJeff Layton }
640682e05efaSJeff Layton 
640782e05efaSJeff Layton static void
640882e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist)
640982e05efaSJeff Layton {
641082e05efaSJeff Layton 	struct nfs4_client *clp;
641182e05efaSJeff Layton 	struct nfs4_openowner *oop, *next;
641282e05efaSJeff Layton 
641382e05efaSJeff Layton 	list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
641482e05efaSJeff Layton 		list_del_init(&oop->oo_perclient);
641582e05efaSJeff Layton 		clp = oop->oo_owner.so_client;
641682e05efaSJeff Layton 		release_openowner(oop);
641782e05efaSJeff Layton 		put_client(clp);
641882e05efaSJeff Layton 	}
641982e05efaSJeff Layton }
642082e05efaSJeff Layton 
642182e05efaSJeff Layton u64
6422285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr,
6423285abdeeSJeff Layton 				     size_t addr_size)
642482e05efaSJeff Layton {
642582e05efaSJeff Layton 	unsigned int count = 0;
642682e05efaSJeff Layton 	struct nfs4_client *clp;
642782e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
642882e05efaSJeff Layton 						nfsd_net_id);
642982e05efaSJeff Layton 	LIST_HEAD(reaplist);
643082e05efaSJeff Layton 
643182e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
643282e05efaSJeff Layton 		return count;
643382e05efaSJeff Layton 
643482e05efaSJeff Layton 	spin_lock(&nn->client_lock);
643582e05efaSJeff Layton 	clp = nfsd_find_client(addr, addr_size);
643682e05efaSJeff Layton 	if (clp)
643782e05efaSJeff Layton 		count = nfsd_collect_client_openowners(clp, &reaplist, 0);
643882e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
643982e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
644082e05efaSJeff Layton 	return count;
644182e05efaSJeff Layton }
644282e05efaSJeff Layton 
644382e05efaSJeff Layton u64
6444285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max)
644582e05efaSJeff Layton {
644682e05efaSJeff Layton 	u64 count = 0;
644782e05efaSJeff Layton 	struct nfs4_client *clp;
644882e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
644982e05efaSJeff Layton 						nfsd_net_id);
645082e05efaSJeff Layton 	LIST_HEAD(reaplist);
645182e05efaSJeff Layton 
645282e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
645382e05efaSJeff Layton 		return count;
645482e05efaSJeff Layton 
645582e05efaSJeff Layton 	spin_lock(&nn->client_lock);
645682e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
645782e05efaSJeff Layton 		count += nfsd_collect_client_openowners(clp, &reaplist,
645882e05efaSJeff Layton 							max - count);
645982e05efaSJeff Layton 		if (max != 0 && count >= max)
646082e05efaSJeff Layton 			break;
646182e05efaSJeff Layton 	}
646282e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
646382e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
6464184c1847SBryan Schumaker 	return count;
6465184c1847SBryan Schumaker }
6466184c1847SBryan Schumaker 
6467269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
6468269de30fSBryan Schumaker 				     struct list_head *victims)
6469269de30fSBryan Schumaker {
6470269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
647198d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
647298d5c7c5SJeff Layton 						nfsd_net_id);
6473269de30fSBryan Schumaker 	u64 count = 0;
6474269de30fSBryan Schumaker 
647598d5c7c5SJeff Layton 	lockdep_assert_held(&nn->client_lock);
647698d5c7c5SJeff Layton 
647798d5c7c5SJeff Layton 	spin_lock(&state_lock);
6478269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
6479dff1399fSJeff Layton 		if (victims) {
6480dff1399fSJeff Layton 			/*
6481dff1399fSJeff Layton 			 * It's not safe to mess with delegations that have a
6482dff1399fSJeff Layton 			 * non-zero dl_time. They might have already been broken
6483dff1399fSJeff Layton 			 * and could be processed by the laundromat outside of
6484dff1399fSJeff Layton 			 * the state_lock. Just leave them be.
6485dff1399fSJeff Layton 			 */
6486dff1399fSJeff Layton 			if (dp->dl_time != 0)
6487dff1399fSJeff Layton 				continue;
6488dff1399fSJeff Layton 
648998d5c7c5SJeff Layton 			atomic_inc(&clp->cl_refcount);
64903fcbbd24SJeff Layton 			WARN_ON(!unhash_delegation_locked(dp));
649142690676SJeff Layton 			list_add(&dp->dl_recall_lru, victims);
6492dff1399fSJeff Layton 		}
649398d5c7c5SJeff Layton 		++count;
649498d5c7c5SJeff Layton 		/*
649598d5c7c5SJeff Layton 		 * Despite the fact that these functions deal with
649698d5c7c5SJeff Layton 		 * 64-bit integers for "count", we must ensure that
649798d5c7c5SJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
649898d5c7c5SJeff Layton 		 * warning if we start to approach INT_MAX here.
649998d5c7c5SJeff Layton 		 */
650098d5c7c5SJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
650198d5c7c5SJeff Layton 		if (count == max)
6502269de30fSBryan Schumaker 			break;
6503269de30fSBryan Schumaker 	}
650498d5c7c5SJeff Layton 	spin_unlock(&state_lock);
6505269de30fSBryan Schumaker 	return count;
6506269de30fSBryan Schumaker }
6507269de30fSBryan Schumaker 
650898d5c7c5SJeff Layton static u64
650998d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp)
6510269de30fSBryan Schumaker {
651198d5c7c5SJeff Layton 	u64 count = nfsd_find_all_delegations(clp, 0, NULL);
6512184c1847SBryan Schumaker 
6513184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "delegations");
6514184c1847SBryan Schumaker 	return count;
6515184c1847SBryan Schumaker }
6516184c1847SBryan Schumaker 
651798d5c7c5SJeff Layton u64
6518285abdeeSJeff Layton nfsd_inject_print_delegations(void)
651998d5c7c5SJeff Layton {
652098d5c7c5SJeff Layton 	struct nfs4_client *clp;
652198d5c7c5SJeff Layton 	u64 count = 0;
652298d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
652398d5c7c5SJeff Layton 						nfsd_net_id);
652498d5c7c5SJeff Layton 
652598d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
652698d5c7c5SJeff Layton 		return 0;
652798d5c7c5SJeff Layton 
652898d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
652998d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
653098d5c7c5SJeff Layton 		count += nfsd_print_client_delegations(clp);
653198d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
653298d5c7c5SJeff Layton 
653398d5c7c5SJeff Layton 	return count;
653498d5c7c5SJeff Layton }
653598d5c7c5SJeff Layton 
653698d5c7c5SJeff Layton static void
653798d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist)
653898d5c7c5SJeff Layton {
653998d5c7c5SJeff Layton 	struct nfs4_client *clp;
654098d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
654198d5c7c5SJeff Layton 
654298d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
654398d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
654498d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
654598d5c7c5SJeff Layton 		revoke_delegation(dp);
654698d5c7c5SJeff Layton 		put_client(clp);
654798d5c7c5SJeff Layton 	}
654898d5c7c5SJeff Layton }
654998d5c7c5SJeff Layton 
655098d5c7c5SJeff Layton u64
6551285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr,
6552285abdeeSJeff Layton 				      size_t addr_size)
655398d5c7c5SJeff Layton {
655498d5c7c5SJeff Layton 	u64 count = 0;
655598d5c7c5SJeff Layton 	struct nfs4_client *clp;
655698d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
655798d5c7c5SJeff Layton 						nfsd_net_id);
655898d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
655998d5c7c5SJeff Layton 
656098d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
656198d5c7c5SJeff Layton 		return count;
656298d5c7c5SJeff Layton 
656398d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
656498d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
656598d5c7c5SJeff Layton 	if (clp)
656698d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
656798d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
656898d5c7c5SJeff Layton 
656998d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
657098d5c7c5SJeff Layton 	return count;
657198d5c7c5SJeff Layton }
657298d5c7c5SJeff Layton 
657398d5c7c5SJeff Layton u64
6574285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max)
657598d5c7c5SJeff Layton {
657698d5c7c5SJeff Layton 	u64 count = 0;
657798d5c7c5SJeff Layton 	struct nfs4_client *clp;
657898d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
657998d5c7c5SJeff Layton 						nfsd_net_id);
658098d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
658198d5c7c5SJeff Layton 
658298d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
658398d5c7c5SJeff Layton 		return count;
658498d5c7c5SJeff Layton 
658598d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
658698d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
658798d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
658898d5c7c5SJeff Layton 		if (max != 0 && count >= max)
658998d5c7c5SJeff Layton 			break;
659098d5c7c5SJeff Layton 	}
659198d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
659298d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
659398d5c7c5SJeff Layton 	return count;
659498d5c7c5SJeff Layton }
659598d5c7c5SJeff Layton 
659698d5c7c5SJeff Layton static void
659798d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist)
659898d5c7c5SJeff Layton {
659998d5c7c5SJeff Layton 	struct nfs4_client *clp;
660098d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
660198d5c7c5SJeff Layton 
660298d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
660398d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
660498d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
660598d5c7c5SJeff Layton 		/*
660698d5c7c5SJeff Layton 		 * We skipped all entries that had a zero dl_time before,
660798d5c7c5SJeff Layton 		 * so we can now reset the dl_time back to 0. If a delegation
660898d5c7c5SJeff Layton 		 * break comes in now, then it won't make any difference since
660998d5c7c5SJeff Layton 		 * we're recalling it either way.
661098d5c7c5SJeff Layton 		 */
661198d5c7c5SJeff Layton 		spin_lock(&state_lock);
661298d5c7c5SJeff Layton 		dp->dl_time = 0;
661398d5c7c5SJeff Layton 		spin_unlock(&state_lock);
661498d5c7c5SJeff Layton 		nfsd_break_one_deleg(dp);
661598d5c7c5SJeff Layton 		put_client(clp);
661698d5c7c5SJeff Layton 	}
661798d5c7c5SJeff Layton }
661898d5c7c5SJeff Layton 
661998d5c7c5SJeff Layton u64
6620285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr,
662198d5c7c5SJeff Layton 				      size_t addr_size)
662298d5c7c5SJeff Layton {
662398d5c7c5SJeff Layton 	u64 count = 0;
662498d5c7c5SJeff Layton 	struct nfs4_client *clp;
662598d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
662698d5c7c5SJeff Layton 						nfsd_net_id);
662798d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
662898d5c7c5SJeff Layton 
662998d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
663098d5c7c5SJeff Layton 		return count;
663198d5c7c5SJeff Layton 
663298d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
663398d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
663498d5c7c5SJeff Layton 	if (clp)
663598d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
663698d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
663798d5c7c5SJeff Layton 
663898d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
663998d5c7c5SJeff Layton 	return count;
664098d5c7c5SJeff Layton }
664198d5c7c5SJeff Layton 
664298d5c7c5SJeff Layton u64
6643285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max)
664498d5c7c5SJeff Layton {
664598d5c7c5SJeff Layton 	u64 count = 0;
664698d5c7c5SJeff Layton 	struct nfs4_client *clp, *next;
664798d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
664898d5c7c5SJeff Layton 						nfsd_net_id);
664998d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
665098d5c7c5SJeff Layton 
665198d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
665298d5c7c5SJeff Layton 		return count;
665398d5c7c5SJeff Layton 
665498d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
665598d5c7c5SJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
665698d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
665798d5c7c5SJeff Layton 		if (max != 0 && ++count >= max)
665898d5c7c5SJeff Layton 			break;
665998d5c7c5SJeff Layton 	}
666098d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
666198d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
666298d5c7c5SJeff Layton 	return count;
666398d5c7c5SJeff Layton }
666465178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */
666565178db4SBryan Schumaker 
6666c2f1a551SMeelap Shah /*
6667c2f1a551SMeelap Shah  * Since the lifetime of a delegation isn't limited to that of an open, a
6668c2f1a551SMeelap Shah  * client may quite reasonably hang on to a delegation as long as it has
6669c2f1a551SMeelap Shah  * the inode cached.  This becomes an obvious problem the first time a
6670c2f1a551SMeelap Shah  * client's inode cache approaches the size of the server's total memory.
6671c2f1a551SMeelap Shah  *
6672c2f1a551SMeelap Shah  * For now we avoid this problem by imposing a hard limit on the number
6673c2f1a551SMeelap Shah  * of delegations, which varies according to the server's memory size.
6674c2f1a551SMeelap Shah  */
6675c2f1a551SMeelap Shah static void
6676c2f1a551SMeelap Shah set_max_delegations(void)
6677c2f1a551SMeelap Shah {
6678c2f1a551SMeelap Shah 	/*
6679c2f1a551SMeelap Shah 	 * Allow at most 4 delegations per megabyte of RAM.  Quick
6680c2f1a551SMeelap Shah 	 * estimates suggest that in the worst case (where every delegation
6681c2f1a551SMeelap Shah 	 * is for a different inode), a delegation could take about 1.5K,
6682c2f1a551SMeelap Shah 	 * giving a worst case usage of about 6% of memory.
6683c2f1a551SMeelap Shah 	 */
6684c2f1a551SMeelap Shah 	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
6685c2f1a551SMeelap Shah }
6686c2f1a551SMeelap Shah 
6687d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net)
66888daae4dcSStanislav Kinsbursky {
66898daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
66908daae4dcSStanislav Kinsbursky 	int i;
66918daae4dcSStanislav Kinsbursky 
66928daae4dcSStanislav Kinsbursky 	nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
66938daae4dcSStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
66948daae4dcSStanislav Kinsbursky 	if (!nn->conf_id_hashtbl)
6695382a62e7SStanislav Kinsbursky 		goto err;
66960a7ec377SStanislav Kinsbursky 	nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) *
66970a7ec377SStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
66980a7ec377SStanislav Kinsbursky 	if (!nn->unconf_id_hashtbl)
66990a7ec377SStanislav Kinsbursky 		goto err_unconf_id;
67001872de0eSStanislav Kinsbursky 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
67011872de0eSStanislav Kinsbursky 			SESSION_HASH_SIZE, GFP_KERNEL);
67021872de0eSStanislav Kinsbursky 	if (!nn->sessionid_hashtbl)
67031872de0eSStanislav Kinsbursky 		goto err_sessionid;
67048daae4dcSStanislav Kinsbursky 
6705382a62e7SStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
67068daae4dcSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
67070a7ec377SStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
6708382a62e7SStanislav Kinsbursky 	}
67091872de0eSStanislav Kinsbursky 	for (i = 0; i < SESSION_HASH_SIZE; i++)
67101872de0eSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
6711382a62e7SStanislav Kinsbursky 	nn->conf_name_tree = RB_ROOT;
6712a99454aaSStanislav Kinsbursky 	nn->unconf_name_tree = RB_ROOT;
67135ed58bb2SStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->client_lru);
671473758fedSStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->close_lru);
6715e8c69d17SJ. Bruce Fields 	INIT_LIST_HEAD(&nn->del_recall_lru);
6716c9a49628SStanislav Kinsbursky 	spin_lock_init(&nn->client_lock);
67178daae4dcSStanislav Kinsbursky 
671809121281SStanislav Kinsbursky 	INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
6719d85ed443SStanislav Kinsbursky 	get_net(net);
672009121281SStanislav Kinsbursky 
67218daae4dcSStanislav Kinsbursky 	return 0;
6722382a62e7SStanislav Kinsbursky 
67231872de0eSStanislav Kinsbursky err_sessionid:
67249b531137SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
67250a7ec377SStanislav Kinsbursky err_unconf_id:
67260a7ec377SStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
6727382a62e7SStanislav Kinsbursky err:
6728382a62e7SStanislav Kinsbursky 	return -ENOMEM;
67298daae4dcSStanislav Kinsbursky }
67308daae4dcSStanislav Kinsbursky 
67318daae4dcSStanislav Kinsbursky static void
67324dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net)
67338daae4dcSStanislav Kinsbursky {
67348daae4dcSStanislav Kinsbursky 	int i;
67358daae4dcSStanislav Kinsbursky 	struct nfs4_client *clp = NULL;
67368daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
67378daae4dcSStanislav Kinsbursky 
67388daae4dcSStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
67398daae4dcSStanislav Kinsbursky 		while (!list_empty(&nn->conf_id_hashtbl[i])) {
67408daae4dcSStanislav Kinsbursky 			clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
67418daae4dcSStanislav Kinsbursky 			destroy_client(clp);
67428daae4dcSStanislav Kinsbursky 		}
67438daae4dcSStanislav Kinsbursky 	}
6744a99454aaSStanislav Kinsbursky 
67452b905635SKinglong Mee 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
67462b905635SKinglong Mee 		while (!list_empty(&nn->unconf_id_hashtbl[i])) {
67472b905635SKinglong Mee 			clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
6748a99454aaSStanislav Kinsbursky 			destroy_client(clp);
6749a99454aaSStanislav Kinsbursky 		}
67502b905635SKinglong Mee 	}
6751a99454aaSStanislav Kinsbursky 
67521872de0eSStanislav Kinsbursky 	kfree(nn->sessionid_hashtbl);
67530a7ec377SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
67548daae4dcSStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
67554dce0ac9SStanislav Kinsbursky 	put_net(net);
67568daae4dcSStanislav Kinsbursky }
67578daae4dcSStanislav Kinsbursky 
6758f252bc68SStanislav Kinsbursky int
6759d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net)
6760ac4d8ff2SNeilBrown {
67615e1533c7SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
6762b5a1a81eSJ. Bruce Fields 	int ret;
6763b5a1a81eSJ. Bruce Fields 
6764d85ed443SStanislav Kinsbursky 	ret = nfs4_state_create_net(net);
67658daae4dcSStanislav Kinsbursky 	if (ret)
67668daae4dcSStanislav Kinsbursky 		return ret;
67672c142baaSStanislav Kinsbursky 	nn->boot_time = get_seconds();
6768a51c84edSStanislav Kinsbursky 	nn->grace_ended = false;
6769c87fb4a3SJ. Bruce Fields 	nn->nfsd4_manager.block_opens = true;
6770d4318acdSJeff Layton 	locks_start_grace(net, &nn->nfsd4_manager);
6771d4318acdSJeff Layton 	nfsd4_client_tracking_init(net);
6772d85ed443SStanislav Kinsbursky 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
67735284b44eSStanislav Kinsbursky 	       nn->nfsd4_grace, net);
67745284b44eSStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
6775d85ed443SStanislav Kinsbursky 	return 0;
6776a6d6b781SJeff Layton }
6777d85ed443SStanislav Kinsbursky 
6778d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */
6779d85ed443SStanislav Kinsbursky 
6780d85ed443SStanislav Kinsbursky int
6781d85ed443SStanislav Kinsbursky nfs4_state_start(void)
6782d85ed443SStanislav Kinsbursky {
6783d85ed443SStanislav Kinsbursky 	int ret;
6784d85ed443SStanislav Kinsbursky 
6785d85ed443SStanislav Kinsbursky 	ret = set_callback_cred();
6786d85ed443SStanislav Kinsbursky 	if (ret)
6787d85ed443SStanislav Kinsbursky 		return -ENOMEM;
678851a54568SJeff Layton 	laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
6789a6d6b781SJeff Layton 	if (laundry_wq == NULL) {
6790a6d6b781SJeff Layton 		ret = -ENOMEM;
6791a6d6b781SJeff Layton 		goto out_recovery;
6792a6d6b781SJeff Layton 	}
6793b5a1a81eSJ. Bruce Fields 	ret = nfsd4_create_callback_queue();
6794b5a1a81eSJ. Bruce Fields 	if (ret)
6795b5a1a81eSJ. Bruce Fields 		goto out_free_laundry;
679609121281SStanislav Kinsbursky 
6797c2f1a551SMeelap Shah 	set_max_delegations();
6798d85ed443SStanislav Kinsbursky 
6799b5a1a81eSJ. Bruce Fields 	return 0;
6800d85ed443SStanislav Kinsbursky 
6801b5a1a81eSJ. Bruce Fields out_free_laundry:
6802b5a1a81eSJ. Bruce Fields 	destroy_workqueue(laundry_wq);
6803a6d6b781SJeff Layton out_recovery:
6804b5a1a81eSJ. Bruce Fields 	return ret;
68051da177e4SLinus Torvalds }
68061da177e4SLinus Torvalds 
6807f252bc68SStanislav Kinsbursky void
68084dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net)
68091da177e4SLinus Torvalds {
68101da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
68111da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
68124dce0ac9SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
68131da177e4SLinus Torvalds 
68144dce0ac9SStanislav Kinsbursky 	cancel_delayed_work_sync(&nn->laundromat_work);
68154dce0ac9SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
6816ac55fdc4SJeff Layton 
68171da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
6818cdc97505SBenny Halevy 	spin_lock(&state_lock);
6819e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
68201da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
68213fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
682242690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
68231da177e4SLinus Torvalds 	}
6824cdc97505SBenny Halevy 	spin_unlock(&state_lock);
68251da177e4SLinus Torvalds 	list_for_each_safe(pos, next, &reaplist) {
68261da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
682742690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
68288287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
6829afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
68306011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
68311da177e4SLinus Torvalds 	}
68321da177e4SLinus Torvalds 
68333320fef1SStanislav Kinsbursky 	nfsd4_client_tracking_exit(net);
68344dce0ac9SStanislav Kinsbursky 	nfs4_state_destroy_net(net);
68351da177e4SLinus Torvalds }
68361da177e4SLinus Torvalds 
68371da177e4SLinus Torvalds void
68381da177e4SLinus Torvalds nfs4_state_shutdown(void)
68391da177e4SLinus Torvalds {
68405e8d5c29SNeilBrown 	destroy_workqueue(laundry_wq);
6841c3935e30SJ. Bruce Fields 	nfsd4_destroy_callback_queue();
68421da177e4SLinus Torvalds }
68438b70484cSTigran Mkrtchyan 
68448b70484cSTigran Mkrtchyan static void
68458b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
68468b70484cSTigran Mkrtchyan {
684737c593c5STigran Mkrtchyan 	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
684837c593c5STigran Mkrtchyan 		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
68498b70484cSTigran Mkrtchyan }
68508b70484cSTigran Mkrtchyan 
68518b70484cSTigran Mkrtchyan static void
68528b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
68538b70484cSTigran Mkrtchyan {
685437c593c5STigran Mkrtchyan 	if (cstate->minorversion) {
685537c593c5STigran Mkrtchyan 		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
685637c593c5STigran Mkrtchyan 		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
685737c593c5STigran Mkrtchyan 	}
685837c593c5STigran Mkrtchyan }
685937c593c5STigran Mkrtchyan 
686037c593c5STigran Mkrtchyan void
686137c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate)
686237c593c5STigran Mkrtchyan {
686337c593c5STigran Mkrtchyan 	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
68648b70484cSTigran Mkrtchyan }
68658b70484cSTigran Mkrtchyan 
686662cd4a59STigran Mkrtchyan /*
686762cd4a59STigran Mkrtchyan  * functions to set current state id
686862cd4a59STigran Mkrtchyan  */
68698b70484cSTigran Mkrtchyan void
68709428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
68719428fe1aSTigran Mkrtchyan {
68729428fe1aSTigran Mkrtchyan 	put_stateid(cstate, &odp->od_stateid);
68739428fe1aSTigran Mkrtchyan }
68749428fe1aSTigran Mkrtchyan 
68759428fe1aSTigran Mkrtchyan void
68768b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
68778b70484cSTigran Mkrtchyan {
68788b70484cSTigran Mkrtchyan 	put_stateid(cstate, &open->op_stateid);
68798b70484cSTigran Mkrtchyan }
68808b70484cSTigran Mkrtchyan 
68818b70484cSTigran Mkrtchyan void
688262cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
688362cd4a59STigran Mkrtchyan {
688462cd4a59STigran Mkrtchyan 	put_stateid(cstate, &close->cl_stateid);
688562cd4a59STigran Mkrtchyan }
688662cd4a59STigran Mkrtchyan 
688762cd4a59STigran Mkrtchyan void
688862cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
688962cd4a59STigran Mkrtchyan {
689062cd4a59STigran Mkrtchyan 	put_stateid(cstate, &lock->lk_resp_stateid);
689162cd4a59STigran Mkrtchyan }
689262cd4a59STigran Mkrtchyan 
689362cd4a59STigran Mkrtchyan /*
689462cd4a59STigran Mkrtchyan  * functions to consume current state id
689562cd4a59STigran Mkrtchyan  */
68961e97b519STigran Mkrtchyan 
68971e97b519STigran Mkrtchyan void
68989428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
68999428fe1aSTigran Mkrtchyan {
69009428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &odp->od_stateid);
69019428fe1aSTigran Mkrtchyan }
69029428fe1aSTigran Mkrtchyan 
69039428fe1aSTigran Mkrtchyan void
69049428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
69059428fe1aSTigran Mkrtchyan {
69069428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &drp->dr_stateid);
69079428fe1aSTigran Mkrtchyan }
69089428fe1aSTigran Mkrtchyan 
69099428fe1aSTigran Mkrtchyan void
69101e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
69111e97b519STigran Mkrtchyan {
69121e97b519STigran Mkrtchyan 	get_stateid(cstate, &fsp->fr_stateid);
69131e97b519STigran Mkrtchyan }
69141e97b519STigran Mkrtchyan 
69151e97b519STigran Mkrtchyan void
69161e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
69171e97b519STigran Mkrtchyan {
69181e97b519STigran Mkrtchyan 	get_stateid(cstate, &setattr->sa_stateid);
69191e97b519STigran Mkrtchyan }
69201e97b519STigran Mkrtchyan 
692162cd4a59STigran Mkrtchyan void
69228b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
69238b70484cSTigran Mkrtchyan {
69248b70484cSTigran Mkrtchyan 	get_stateid(cstate, &close->cl_stateid);
69258b70484cSTigran Mkrtchyan }
69268b70484cSTigran Mkrtchyan 
69278b70484cSTigran Mkrtchyan void
692862cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
69298b70484cSTigran Mkrtchyan {
693062cd4a59STigran Mkrtchyan 	get_stateid(cstate, &locku->lu_stateid);
69318b70484cSTigran Mkrtchyan }
693230813e27STigran Mkrtchyan 
693330813e27STigran Mkrtchyan void
693430813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
693530813e27STigran Mkrtchyan {
693630813e27STigran Mkrtchyan 	get_stateid(cstate, &read->rd_stateid);
693730813e27STigran Mkrtchyan }
693830813e27STigran Mkrtchyan 
693930813e27STigran Mkrtchyan void
694030813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
694130813e27STigran Mkrtchyan {
694230813e27STigran Mkrtchyan 	get_stateid(cstate, &write->wr_stateid);
694330813e27STigran Mkrtchyan }
6944