xref: /openbmc/linux/fs/nfsd/nfs4state.c (revision 415b96c5)
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>
446282cd56SNeilBrown #include <linux/hash.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"
515e1533c7SStanislav Kinsbursky 
521da177e4SLinus Torvalds #define NFSDDBG_FACILITY                NFSDDBG_PROC
531da177e4SLinus Torvalds 
54f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0}
55f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = {
56f32f3c2dSJ. Bruce Fields 	.si_generation = ~0,
57f32f3c2dSJ. Bruce Fields 	.si_opaque = all_ones,
58f32f3c2dSJ. Bruce Fields };
59f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = {
60f32f3c2dSJ. Bruce Fields 	/* all fields zero */
61f32f3c2dSJ. Bruce Fields };
6219ff0f28STigran Mkrtchyan static const stateid_t currentstateid = {
6319ff0f28STigran Mkrtchyan 	.si_generation = 1,
6419ff0f28STigran Mkrtchyan };
65f32f3c2dSJ. Bruce Fields 
66ec6b5d7bSAndy Adamson static u64 current_sessionid = 1;
67fd39ca9aSNeilBrown 
68f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
69f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
7019ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds /* forward declarations */
73f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
746011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
751da177e4SLinus Torvalds 
768b671b80SJ. Bruce Fields /* Locking: */
778b671b80SJ. Bruce Fields 
788b671b80SJ. Bruce Fields /*
798b671b80SJ. Bruce Fields  * Currently used for the del_recall_lru and file hash table.  In an
808b671b80SJ. Bruce Fields  * effort to decrease the scope of the client_mutex, this spinlock may
818b671b80SJ. Bruce Fields  * eventually cover more:
828b671b80SJ. Bruce Fields  */
83cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock);
848b671b80SJ. Bruce Fields 
85b401be22SJeff Layton /*
86b401be22SJeff Layton  * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for
87b401be22SJeff Layton  * the refcount on the open stateid to drop.
88b401be22SJeff Layton  */
89b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq);
90b401be22SJeff Layton 
91abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab;
92abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab;
93abf1135bSChristoph Hellwig static struct kmem_cache *file_slab;
94abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab;
95abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab;
96e60d4398SNeilBrown 
9766b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *);
98508dc6e1SBenny Halevy 
9966b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses)
100508dc6e1SBenny Halevy {
10166b2b9b2SJ. Bruce Fields 	return ses->se_flags & NFS4_SESSION_DEAD;
10266b2b9b2SJ. Bruce Fields }
10366b2b9b2SJ. Bruce Fields 
104f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
105f0f51f5cSJ. Bruce Fields {
106f0f51f5cSJ. Bruce Fields 	if (atomic_read(&ses->se_ref) > ref_held_by_me)
10766b2b9b2SJ. Bruce Fields 		return nfserr_jukebox;
10866b2b9b2SJ. Bruce Fields 	ses->se_flags |= NFS4_SESSION_DEAD;
10966b2b9b2SJ. Bruce Fields 	return nfs_ok;
11066b2b9b2SJ. Bruce Fields }
11166b2b9b2SJ. Bruce Fields 
112221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp)
113221a6876SJ. Bruce Fields {
114221a6876SJ. Bruce Fields 	return clp->cl_time == 0;
115221a6876SJ. Bruce Fields }
116221a6876SJ. Bruce Fields 
117221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp)
118221a6876SJ. Bruce Fields {
1190a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1200a880a28STrond Myklebust 
1210a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1220a880a28STrond Myklebust 
123221a6876SJ. Bruce Fields 	if (is_client_expired(clp))
124221a6876SJ. Bruce Fields 		return nfserr_expired;
125221a6876SJ. Bruce Fields 	atomic_inc(&clp->cl_refcount);
126221a6876SJ. Bruce Fields 	return nfs_ok;
127221a6876SJ. Bruce Fields }
128221a6876SJ. Bruce Fields 
129221a6876SJ. Bruce Fields /* must be called under the client_lock */
130221a6876SJ. Bruce Fields static inline void
131221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp)
132221a6876SJ. Bruce Fields {
133221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
134221a6876SJ. Bruce Fields 
135221a6876SJ. Bruce Fields 	if (is_client_expired(clp)) {
136221a6876SJ. Bruce Fields 		WARN_ON(1);
137221a6876SJ. Bruce Fields 		printk("%s: client (clientid %08x/%08x) already expired\n",
138221a6876SJ. Bruce Fields 			__func__,
139221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
140221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
141221a6876SJ. Bruce Fields 		return;
142221a6876SJ. Bruce Fields 	}
143221a6876SJ. Bruce Fields 
144221a6876SJ. Bruce Fields 	dprintk("renewing client (clientid %08x/%08x)\n",
145221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
146221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
147221a6876SJ. Bruce Fields 	list_move_tail(&clp->cl_lru, &nn->client_lru);
148221a6876SJ. Bruce Fields 	clp->cl_time = get_seconds();
149221a6876SJ. Bruce Fields }
150221a6876SJ. Bruce Fields 
151221a6876SJ. Bruce Fields static inline void
152221a6876SJ. Bruce Fields renew_client(struct nfs4_client *clp)
153221a6876SJ. Bruce Fields {
154221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
155221a6876SJ. Bruce Fields 
156221a6876SJ. Bruce Fields 	spin_lock(&nn->client_lock);
157221a6876SJ. Bruce Fields 	renew_client_locked(clp);
158221a6876SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
159221a6876SJ. Bruce Fields }
160221a6876SJ. Bruce Fields 
161ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp)
162221a6876SJ. Bruce Fields {
1630a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1640a880a28STrond Myklebust 
1650a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1660a880a28STrond Myklebust 
167221a6876SJ. Bruce Fields 	if (!atomic_dec_and_test(&clp->cl_refcount))
168221a6876SJ. Bruce Fields 		return;
169221a6876SJ. Bruce Fields 	if (!is_client_expired(clp))
170221a6876SJ. Bruce Fields 		renew_client_locked(clp);
171221a6876SJ. Bruce Fields }
172221a6876SJ. Bruce Fields 
1734b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp)
1744b24ca7dSJeff Layton {
1754b24ca7dSJeff Layton 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1764b24ca7dSJeff Layton 
177d6c249b4SJeff Layton 	if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
178d6c249b4SJeff Layton 		return;
179d6c249b4SJeff Layton 	if (!is_client_expired(clp))
180d6c249b4SJeff Layton 		renew_client_locked(clp);
1814b24ca7dSJeff Layton 	spin_unlock(&nn->client_lock);
1824b24ca7dSJeff Layton }
1834b24ca7dSJeff Layton 
184d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
185d4e19e70STrond Myklebust {
186d4e19e70STrond Myklebust 	__be32 status;
187d4e19e70STrond Myklebust 
188d4e19e70STrond Myklebust 	if (is_session_dead(ses))
189d4e19e70STrond Myklebust 		return nfserr_badsession;
190d4e19e70STrond Myklebust 	status = get_client_locked(ses->se_client);
191d4e19e70STrond Myklebust 	if (status)
192d4e19e70STrond Myklebust 		return status;
193d4e19e70STrond Myklebust 	atomic_inc(&ses->se_ref);
194d4e19e70STrond Myklebust 	return nfs_ok;
195d4e19e70STrond Myklebust }
196d4e19e70STrond Myklebust 
197d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses)
198d4e19e70STrond Myklebust {
199d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
2000a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2010a880a28STrond Myklebust 
2020a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
203d4e19e70STrond Myklebust 
204d4e19e70STrond Myklebust 	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
205d4e19e70STrond Myklebust 		free_session(ses);
206d4e19e70STrond Myklebust 	put_client_renew_locked(clp);
207d4e19e70STrond Myklebust }
208d4e19e70STrond Myklebust 
209d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses)
210d4e19e70STrond Myklebust {
211d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
212d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
213d4e19e70STrond Myklebust 
214d4e19e70STrond Myklebust 	spin_lock(&nn->client_lock);
215d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
216d4e19e70STrond Myklebust 	spin_unlock(&nn->client_lock);
217d4e19e70STrond Myklebust }
218d4e19e70STrond Myklebust 
219b5971afaSKinglong Mee static inline struct nfs4_stateowner *
220b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop)
221b5971afaSKinglong Mee {
222b5971afaSKinglong Mee 	atomic_inc(&sop->so_count);
223b5971afaSKinglong Mee 	return sop;
224b5971afaSKinglong Mee }
225b5971afaSKinglong Mee 
2267ffb5880STrond Myklebust static int
227d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
2287ffb5880STrond Myklebust {
2297ffb5880STrond Myklebust 	return (sop->so_owner.len == owner->len) &&
230d4f0489fSTrond Myklebust 		0 == memcmp(sop->so_owner.data, owner->data, owner->len);
2317ffb5880STrond Myklebust }
2327ffb5880STrond Myklebust 
2337ffb5880STrond Myklebust static struct nfs4_openowner *
2347ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
235d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
2367ffb5880STrond Myklebust {
2377ffb5880STrond Myklebust 	struct nfs4_stateowner *so;
2387ffb5880STrond Myklebust 
239d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
2407ffb5880STrond Myklebust 
241d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval],
242d4f0489fSTrond Myklebust 			    so_strhash) {
2437ffb5880STrond Myklebust 		if (!so->so_is_open_owner)
2447ffb5880STrond Myklebust 			continue;
245b5971afaSKinglong Mee 		if (same_owner_str(so, &open->op_owner))
246b5971afaSKinglong Mee 			return openowner(nfs4_get_stateowner(so));
2477ffb5880STrond Myklebust 	}
2487ffb5880STrond Myklebust 	return NULL;
2497ffb5880STrond Myklebust }
2507ffb5880STrond Myklebust 
2517ffb5880STrond Myklebust static struct nfs4_openowner *
2527ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
253d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
2547ffb5880STrond Myklebust {
2557ffb5880STrond Myklebust 	struct nfs4_openowner *oo;
2567ffb5880STrond Myklebust 
257d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
258d4f0489fSTrond Myklebust 	oo = find_openstateowner_str_locked(hashval, open, clp);
259d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
2607ffb5880STrond Myklebust 	return oo;
2617ffb5880STrond Myklebust }
2627ffb5880STrond Myklebust 
2631da177e4SLinus Torvalds static inline u32
2641da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds 	unsigned char *cptr = (unsigned char *) ptr;
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 	u32 x = 0;
2691da177e4SLinus Torvalds 	while (nbytes--) {
2701da177e4SLinus Torvalds 		x *= 37;
2711da177e4SLinus Torvalds 		x += *cptr++;
2721da177e4SLinus Torvalds 	}
2731da177e4SLinus Torvalds 	return x;
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds 
27632513b40SJ. Bruce Fields static void nfsd4_free_file(struct nfs4_file *f)
27732513b40SJ. Bruce Fields {
27832513b40SJ. Bruce Fields 	kmem_cache_free(file_slab, f);
27932513b40SJ. Bruce Fields }
28032513b40SJ. Bruce Fields 
28113cd2184SNeilBrown static inline void
28213cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi)
28313cd2184SNeilBrown {
28402e1215fSJeff Layton 	might_lock(&state_lock);
28502e1215fSJeff Layton 
286cdc97505SBenny Halevy 	if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
28789876f8cSJeff Layton 		hlist_del(&fi->fi_hash);
288cdc97505SBenny Halevy 		spin_unlock(&state_lock);
28932513b40SJ. Bruce Fields 		nfsd4_free_file(fi);
2908b671b80SJ. Bruce Fields 	}
29113cd2184SNeilBrown }
29213cd2184SNeilBrown 
29313cd2184SNeilBrown static inline void
29413cd2184SNeilBrown get_nfs4_file(struct nfs4_file *fi)
29513cd2184SNeilBrown {
2968b671b80SJ. Bruce Fields 	atomic_inc(&fi->fi_ref);
29713cd2184SNeilBrown }
29813cd2184SNeilBrown 
299de18643dSTrond Myklebust static struct file *
300de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag)
301de18643dSTrond Myklebust {
302de18643dSTrond Myklebust 	if (f->fi_fds[oflag])
303de18643dSTrond Myklebust 		return get_file(f->fi_fds[oflag]);
304de18643dSTrond Myklebust 	return NULL;
305de18643dSTrond Myklebust }
306de18643dSTrond Myklebust 
307de18643dSTrond Myklebust static struct file *
308de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f)
309de18643dSTrond Myklebust {
310de18643dSTrond Myklebust 	struct file *ret;
311de18643dSTrond Myklebust 
312de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
313de18643dSTrond Myklebust 
314de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_WRONLY);
315de18643dSTrond Myklebust 	if (!ret)
316de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
317de18643dSTrond Myklebust 	return ret;
318de18643dSTrond Myklebust }
319de18643dSTrond Myklebust 
320de18643dSTrond Myklebust static struct file *
321de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f)
322de18643dSTrond Myklebust {
323de18643dSTrond Myklebust 	struct file *ret;
324de18643dSTrond Myklebust 
325de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
326de18643dSTrond Myklebust 	ret = find_writeable_file_locked(f);
327de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
328de18643dSTrond Myklebust 
329de18643dSTrond Myklebust 	return ret;
330de18643dSTrond Myklebust }
331de18643dSTrond Myklebust 
332de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f)
333de18643dSTrond Myklebust {
334de18643dSTrond Myklebust 	struct file *ret;
335de18643dSTrond Myklebust 
336de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
337de18643dSTrond Myklebust 
338de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDONLY);
339de18643dSTrond Myklebust 	if (!ret)
340de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
341de18643dSTrond Myklebust 	return ret;
342de18643dSTrond Myklebust }
343de18643dSTrond Myklebust 
344de18643dSTrond Myklebust static struct file *
345de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f)
346de18643dSTrond Myklebust {
347de18643dSTrond Myklebust 	struct file *ret;
348de18643dSTrond Myklebust 
349de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
350de18643dSTrond Myklebust 	ret = find_readable_file_locked(f);
351de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
352de18643dSTrond Myklebust 
353de18643dSTrond Myklebust 	return ret;
354de18643dSTrond Myklebust }
355de18643dSTrond Myklebust 
356de18643dSTrond Myklebust static struct file *
357de18643dSTrond Myklebust find_any_file(struct nfs4_file *f)
358de18643dSTrond Myklebust {
359de18643dSTrond Myklebust 	struct file *ret;
360de18643dSTrond Myklebust 
361de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
362de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDWR);
363de18643dSTrond Myklebust 	if (!ret) {
364de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_WRONLY);
365de18643dSTrond Myklebust 		if (!ret)
366de18643dSTrond Myklebust 			ret = __nfs4_get_fd(f, O_RDONLY);
367de18643dSTrond Myklebust 	}
368de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
369de18643dSTrond Myklebust 	return ret;
370de18643dSTrond Myklebust }
371de18643dSTrond Myklebust 
37202a3508dSTrond Myklebust static atomic_long_t num_delegations;
373697ce9beSZhang Yanfei unsigned long max_delegations;
374ef0f3390SNeilBrown 
375ef0f3390SNeilBrown /*
376ef0f3390SNeilBrown  * Open owner state (share locks)
377ef0f3390SNeilBrown  */
378ef0f3390SNeilBrown 
37916bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */
38016bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS              8
38116bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
38216bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
383ef0f3390SNeilBrown 
384d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername)
385ddc04c41SJ. Bruce Fields {
386ddc04c41SJ. Bruce Fields 	unsigned int ret;
387ddc04c41SJ. Bruce Fields 
388ddc04c41SJ. Bruce Fields 	ret = opaque_hashval(ownername->data, ownername->len);
38916bfdaafSJ. Bruce Fields 	return ret & OWNER_HASH_MASK;
390ddc04c41SJ. Bruce Fields }
391ef0f3390SNeilBrown 
392ef0f3390SNeilBrown /* hash table for nfs4_file */
393ef0f3390SNeilBrown #define FILE_HASH_BITS                   8
394ef0f3390SNeilBrown #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
39535079582SShan Wei 
396ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh)
397ddc04c41SJ. Bruce Fields {
398ca943217STrond Myklebust 	return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0);
399ca943217STrond Myklebust }
400ca943217STrond Myklebust 
401ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh)
402ca943217STrond Myklebust {
403ca943217STrond Myklebust 	return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1);
404ca943217STrond Myklebust }
405ca943217STrond Myklebust 
406ca943217STrond Myklebust static bool nfsd_fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
407ca943217STrond Myklebust {
408ca943217STrond Myklebust 	return fh1->fh_size == fh2->fh_size &&
409ca943217STrond Myklebust 		!memcmp(fh1->fh_base.fh_pad,
410ca943217STrond Myklebust 				fh2->fh_base.fh_pad,
411ca943217STrond Myklebust 				fh1->fh_size);
412ddc04c41SJ. Bruce Fields }
413ddc04c41SJ. Bruce Fields 
41489876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
415ef0f3390SNeilBrown 
41612659651SJeff Layton static void
41712659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
4183477565eSJ. Bruce Fields {
4197214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4207214e860SJeff Layton 
42112659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
42212659651SJeff Layton 		atomic_inc(&fp->fi_access[O_WRONLY]);
42312659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
42412659651SJeff Layton 		atomic_inc(&fp->fi_access[O_RDONLY]);
4253477565eSJ. Bruce Fields }
4263477565eSJ. Bruce Fields 
42712659651SJeff Layton static __be32
42812659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access)
429998db52cSJ. Bruce Fields {
4307214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4317214e860SJeff Layton 
43212659651SJeff Layton 	/* Does this access mode make sense? */
43312659651SJeff Layton 	if (access & ~NFS4_SHARE_ACCESS_BOTH)
43412659651SJeff Layton 		return nfserr_inval;
43512659651SJeff Layton 
436baeb4ff0SJeff Layton 	/* Does it conflict with a deny mode already set? */
437baeb4ff0SJeff Layton 	if ((access & fp->fi_share_deny) != 0)
438baeb4ff0SJeff Layton 		return nfserr_share_denied;
439baeb4ff0SJeff Layton 
44012659651SJeff Layton 	__nfs4_file_get_access(fp, access);
44112659651SJeff Layton 	return nfs_ok;
442998db52cSJ. Bruce Fields }
443998db52cSJ. Bruce Fields 
444baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny)
445baeb4ff0SJeff Layton {
446baeb4ff0SJeff Layton 	/* Common case is that there is no deny mode. */
447baeb4ff0SJeff Layton 	if (deny) {
448baeb4ff0SJeff Layton 		/* Does this deny mode make sense? */
449baeb4ff0SJeff Layton 		if (deny & ~NFS4_SHARE_DENY_BOTH)
450baeb4ff0SJeff Layton 			return nfserr_inval;
451baeb4ff0SJeff Layton 
452baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_READ) &&
453baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_RDONLY]))
454baeb4ff0SJeff Layton 			return nfserr_share_denied;
455baeb4ff0SJeff Layton 
456baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_WRITE) &&
457baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_WRONLY]))
458baeb4ff0SJeff Layton 			return nfserr_share_denied;
459baeb4ff0SJeff Layton 	}
460baeb4ff0SJeff Layton 	return nfs_ok;
461baeb4ff0SJeff Layton }
462baeb4ff0SJeff Layton 
463998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
464f9d7562fSJ. Bruce Fields {
465de18643dSTrond Myklebust 	might_lock(&fp->fi_lock);
466de18643dSTrond Myklebust 
467de18643dSTrond Myklebust 	if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) {
468de18643dSTrond Myklebust 		struct file *f1 = NULL;
469de18643dSTrond Myklebust 		struct file *f2 = NULL;
470de18643dSTrond Myklebust 
4716d338b51SJeff Layton 		swap(f1, fp->fi_fds[oflag]);
4720c7c3e67SJ. Bruce Fields 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
4736d338b51SJeff Layton 			swap(f2, fp->fi_fds[O_RDWR]);
474de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
475de18643dSTrond Myklebust 		if (f1)
476de18643dSTrond Myklebust 			fput(f1);
477de18643dSTrond Myklebust 		if (f2)
478de18643dSTrond Myklebust 			fput(f2);
479f9d7562fSJ. Bruce Fields 	}
480f9d7562fSJ. Bruce Fields }
481f9d7562fSJ. Bruce Fields 
48212659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
483998db52cSJ. Bruce Fields {
48412659651SJeff Layton 	WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH);
48512659651SJeff Layton 
48612659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
487998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, O_WRONLY);
48812659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
48912659651SJeff Layton 		__nfs4_file_put_access(fp, O_RDONLY);
490998db52cSJ. Bruce Fields }
491998db52cSJ. Bruce Fields 
4926011695dSTrond Myklebust static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
4936011695dSTrond Myklebust 					 struct kmem_cache *slab)
494996e0938SJ. Bruce Fields {
4953abdb607SJ. Bruce Fields 	struct nfs4_stid *stid;
4963abdb607SJ. Bruce Fields 	int new_id;
4973abdb607SJ. Bruce Fields 
498f8338834STrond Myklebust 	stid = kmem_cache_zalloc(slab, GFP_KERNEL);
4993abdb607SJ. Bruce Fields 	if (!stid)
5003abdb607SJ. Bruce Fields 		return NULL;
501996e0938SJ. Bruce Fields 
5024770d722SJeff Layton 	idr_preload(GFP_KERNEL);
5034770d722SJeff Layton 	spin_lock(&cl->cl_lock);
5044770d722SJeff Layton 	new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT);
5054770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
5064770d722SJeff Layton 	idr_preload_end();
507ebd6c707STejun Heo 	if (new_id < 0)
5083abdb607SJ. Bruce Fields 		goto out_free;
5093abdb607SJ. Bruce Fields 	stid->sc_client = cl;
5103abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_id = new_id;
5113abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
5123abdb607SJ. Bruce Fields 	/* Will be incremented before return to client: */
51372c0b0fbSTrond Myklebust 	atomic_set(&stid->sc_count, 1);
5143abdb607SJ. Bruce Fields 
515996e0938SJ. Bruce Fields 	/*
5163abdb607SJ. Bruce Fields 	 * It shouldn't be a problem to reuse an opaque stateid value.
5173abdb607SJ. Bruce Fields 	 * I don't think it is for 4.1.  But with 4.0 I worry that, for
5183abdb607SJ. Bruce Fields 	 * example, a stray write retransmission could be accepted by
5193abdb607SJ. Bruce Fields 	 * the server when it should have been rejected.  Therefore,
5203abdb607SJ. Bruce Fields 	 * adopt a trick from the sctp code to attempt to maximize the
5213abdb607SJ. Bruce Fields 	 * amount of time until an id is reused, by ensuring they always
5223abdb607SJ. Bruce Fields 	 * "increase" (mod INT_MAX):
523996e0938SJ. Bruce Fields 	 */
5243abdb607SJ. Bruce Fields 	return stid;
5253abdb607SJ. Bruce Fields out_free:
5262c44a234SWei Yongjun 	kmem_cache_free(slab, stid);
5273abdb607SJ. Bruce Fields 	return NULL;
5282a74aba7SJ. Bruce Fields }
5292a74aba7SJ. Bruce Fields 
530b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
5314cdc951bSJ. Bruce Fields {
5326011695dSTrond Myklebust 	struct nfs4_stid *stid;
5336011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp;
5346011695dSTrond Myklebust 
5356011695dSTrond Myklebust 	stid = nfs4_alloc_stid(clp, stateid_slab);
5366011695dSTrond Myklebust 	if (!stid)
5376011695dSTrond Myklebust 		return NULL;
5386011695dSTrond Myklebust 
5396011695dSTrond Myklebust 	stp = openlockstateid(stid);
5406011695dSTrond Myklebust 	stp->st_stid.sc_free = nfs4_free_ol_stateid;
5416011695dSTrond Myklebust 	return stp;
5426011695dSTrond Myklebust }
5436011695dSTrond Myklebust 
5446011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid)
5456011695dSTrond Myklebust {
5466011695dSTrond Myklebust 	kmem_cache_free(deleg_slab, stid);
5476011695dSTrond Myklebust 	atomic_long_dec(&num_delegations);
5484cdc951bSJ. Bruce Fields }
5494cdc951bSJ. Bruce Fields 
5506282cd56SNeilBrown /*
5516282cd56SNeilBrown  * When we recall a delegation, we should be careful not to hand it
5526282cd56SNeilBrown  * out again straight away.
5536282cd56SNeilBrown  * To ensure this we keep a pair of bloom filters ('new' and 'old')
5546282cd56SNeilBrown  * in which the filehandles of recalled delegations are "stored".
5556282cd56SNeilBrown  * If a filehandle appear in either filter, a delegation is blocked.
5566282cd56SNeilBrown  * When a delegation is recalled, the filehandle is stored in the "new"
5576282cd56SNeilBrown  * filter.
5586282cd56SNeilBrown  * Every 30 seconds we swap the filters and clear the "new" one,
5596282cd56SNeilBrown  * unless both are empty of course.
5606282cd56SNeilBrown  *
5616282cd56SNeilBrown  * Each filter is 256 bits.  We hash the filehandle to 32bit and use the
5626282cd56SNeilBrown  * low 3 bytes as hash-table indices.
5636282cd56SNeilBrown  *
564f54fe962SJeff Layton  * 'blocked_delegations_lock', which is always taken in block_delegations(),
5656282cd56SNeilBrown  * is used to manage concurrent access.  Testing does not need the lock
5666282cd56SNeilBrown  * except when swapping the two filters.
5676282cd56SNeilBrown  */
568f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock);
5696282cd56SNeilBrown static struct bloom_pair {
5706282cd56SNeilBrown 	int	entries, old_entries;
5716282cd56SNeilBrown 	time_t	swap_time;
5726282cd56SNeilBrown 	int	new; /* index into 'set' */
5736282cd56SNeilBrown 	DECLARE_BITMAP(set[2], 256);
5746282cd56SNeilBrown } blocked_delegations;
5756282cd56SNeilBrown 
5766282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh)
5776282cd56SNeilBrown {
5786282cd56SNeilBrown 	u32 hash;
5796282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
5806282cd56SNeilBrown 
5816282cd56SNeilBrown 	if (bd->entries == 0)
5826282cd56SNeilBrown 		return 0;
5836282cd56SNeilBrown 	if (seconds_since_boot() - bd->swap_time > 30) {
584f54fe962SJeff Layton 		spin_lock(&blocked_delegations_lock);
5856282cd56SNeilBrown 		if (seconds_since_boot() - bd->swap_time > 30) {
5866282cd56SNeilBrown 			bd->entries -= bd->old_entries;
5876282cd56SNeilBrown 			bd->old_entries = bd->entries;
5886282cd56SNeilBrown 			memset(bd->set[bd->new], 0,
5896282cd56SNeilBrown 			       sizeof(bd->set[0]));
5906282cd56SNeilBrown 			bd->new = 1-bd->new;
5916282cd56SNeilBrown 			bd->swap_time = seconds_since_boot();
5926282cd56SNeilBrown 		}
593f54fe962SJeff Layton 		spin_unlock(&blocked_delegations_lock);
5946282cd56SNeilBrown 	}
5956282cd56SNeilBrown 	hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0);
5966282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[0]) &&
5976282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[0]) &&
5986282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[0]))
5996282cd56SNeilBrown 		return 1;
6006282cd56SNeilBrown 
6016282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[1]) &&
6026282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[1]) &&
6036282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[1]))
6046282cd56SNeilBrown 		return 1;
6056282cd56SNeilBrown 
6066282cd56SNeilBrown 	return 0;
6076282cd56SNeilBrown }
6086282cd56SNeilBrown 
6096282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh)
6106282cd56SNeilBrown {
6116282cd56SNeilBrown 	u32 hash;
6126282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
6136282cd56SNeilBrown 
6146282cd56SNeilBrown 	hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0);
6156282cd56SNeilBrown 
616f54fe962SJeff Layton 	spin_lock(&blocked_delegations_lock);
6176282cd56SNeilBrown 	__set_bit(hash&255, bd->set[bd->new]);
6186282cd56SNeilBrown 	__set_bit((hash>>8)&255, bd->set[bd->new]);
6196282cd56SNeilBrown 	__set_bit((hash>>16)&255, bd->set[bd->new]);
6206282cd56SNeilBrown 	if (bd->entries == 0)
6216282cd56SNeilBrown 		bd->swap_time = seconds_since_boot();
6226282cd56SNeilBrown 	bd->entries += 1;
623f54fe962SJeff Layton 	spin_unlock(&blocked_delegations_lock);
6246282cd56SNeilBrown }
6256282cd56SNeilBrown 
6261da177e4SLinus Torvalds static struct nfs4_delegation *
627f9416e28SJeff Layton alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh)
6281da177e4SLinus Torvalds {
6291da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
63002a3508dSTrond Myklebust 	long n;
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	dprintk("NFSD alloc_init_deleg\n");
63302a3508dSTrond Myklebust 	n = atomic_long_inc_return(&num_delegations);
63402a3508dSTrond Myklebust 	if (n < 0 || n > max_delegations)
63502a3508dSTrond Myklebust 		goto out_dec;
6366282cd56SNeilBrown 	if (delegation_blocked(&current_fh->fh_handle))
63702a3508dSTrond Myklebust 		goto out_dec;
638996e0938SJ. Bruce Fields 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
6395b2d21c1SNeilBrown 	if (dp == NULL)
64002a3508dSTrond Myklebust 		goto out_dec;
6416011695dSTrond Myklebust 
6426011695dSTrond Myklebust 	dp->dl_stid.sc_free = nfs4_free_deleg;
6432a74aba7SJ. Bruce Fields 	/*
6442a74aba7SJ. Bruce Fields 	 * delegation seqid's are never incremented.  The 4.1 special
6456136d2b4SJ. Bruce Fields 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
6466136d2b4SJ. Bruce Fields 	 * 0 anyway just for consistency and use 1:
6472a74aba7SJ. Bruce Fields 	 */
6482a74aba7SJ. Bruce Fields 	dp->dl_stid.sc_stateid.si_generation = 1;
649ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perfile);
650ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perclnt);
6511da177e4SLinus Torvalds 	INIT_LIST_HEAD(&dp->dl_recall_lru);
65299c41515SJ. Bruce Fields 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
65302e1215fSJeff Layton 	INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall);
6541da177e4SLinus Torvalds 	return dp;
65502a3508dSTrond Myklebust out_dec:
65602a3508dSTrond Myklebust 	atomic_long_dec(&num_delegations);
65702a3508dSTrond Myklebust 	return NULL;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds void
6616011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s)
6621da177e4SLinus Torvalds {
66311b9164aSTrond Myklebust 	struct nfs4_file *fp = s->sc_file;
6646011695dSTrond Myklebust 	struct nfs4_client *clp = s->sc_client;
6656011695dSTrond Myklebust 
6664770d722SJeff Layton 	might_lock(&clp->cl_lock);
6674770d722SJeff Layton 
668b401be22SJeff Layton 	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
669b401be22SJeff Layton 		wake_up_all(&close_wq);
6706011695dSTrond Myklebust 		return;
671b401be22SJeff Layton 	}
6726011695dSTrond Myklebust 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
6734770d722SJeff Layton 	spin_unlock(&clp->cl_lock);
6746011695dSTrond Myklebust 	s->sc_free(s);
67511b9164aSTrond Myklebust 	if (fp)
67611b9164aSTrond Myklebust 		put_nfs4_file(fp);
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds 
679acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp)
6801da177e4SLinus Torvalds {
6816bcc034eSJeff Layton 	struct file *filp = NULL;
6826bcc034eSJeff Layton 	struct file_lock *fl;
683417c6629SJeff Layton 
6846bcc034eSJeff Layton 	spin_lock(&fp->fi_lock);
6856bcc034eSJeff Layton 	if (fp->fi_lease && atomic_dec_and_test(&fp->fi_delegees)) {
6866bcc034eSJeff Layton 		swap(filp, fp->fi_deleg_file);
6876bcc034eSJeff Layton 		fl = fp->fi_lease;
688acfdf5c3SJ. Bruce Fields 		fp->fi_lease = NULL;
6896bcc034eSJeff Layton 	}
6906bcc034eSJeff Layton 	spin_unlock(&fp->fi_lock);
6916bcc034eSJeff Layton 
6926bcc034eSJeff Layton 	if (filp) {
6936bcc034eSJeff Layton 		vfs_setlease(filp, F_UNLCK, &fl);
6946bcc034eSJeff Layton 		fput(filp);
695acfdf5c3SJ. Bruce Fields 	}
6961da177e4SLinus Torvalds }
6971da177e4SLinus Torvalds 
6986136d2b4SJ. Bruce Fields static void unhash_stid(struct nfs4_stid *s)
6996136d2b4SJ. Bruce Fields {
7003abdb607SJ. Bruce Fields 	s->sc_type = 0;
7016136d2b4SJ. Bruce Fields }
7026136d2b4SJ. Bruce Fields 
703931ee56cSBenny Halevy static void
704931ee56cSBenny Halevy hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
705931ee56cSBenny Halevy {
706cdc97505SBenny Halevy 	lockdep_assert_held(&state_lock);
707417c6629SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
708931ee56cSBenny Halevy 
70967cb1279STrond Myklebust 	atomic_inc(&dp->dl_stid.sc_count);
7103fb87d13SBenny Halevy 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
711931ee56cSBenny Halevy 	list_add(&dp->dl_perfile, &fp->fi_delegations);
712931ee56cSBenny Halevy 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
713931ee56cSBenny Halevy }
714931ee56cSBenny Halevy 
7151da177e4SLinus Torvalds static void
71642690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp)
7171da177e4SLinus Torvalds {
71811b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
71902e1215fSJeff Layton 
72042690676SJeff Layton 	lockdep_assert_held(&state_lock);
72142690676SJeff Layton 
722b0fc29d6STrond Myklebust 	dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
723d55a166cSJeff Layton 	/* Ensure that deleg break won't try to requeue it */
724d55a166cSJeff Layton 	++dp->dl_time;
725417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
726931ee56cSBenny Halevy 	list_del_init(&dp->dl_perclnt);
7271da177e4SLinus Torvalds 	list_del_init(&dp->dl_recall_lru);
72802e1215fSJeff Layton 	list_del_init(&dp->dl_perfile);
72902e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
730cbf7a75bSJ. Bruce Fields }
7313bd64a5bSJ. Bruce Fields 
7323bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp)
7333bd64a5bSJ. Bruce Fields {
73442690676SJeff Layton 	spin_lock(&state_lock);
73542690676SJeff Layton 	unhash_delegation_locked(dp);
73642690676SJeff Layton 	spin_unlock(&state_lock);
737afbda402SJeff Layton 	nfs4_put_deleg_lease(dp->dl_stid.sc_file);
7386011695dSTrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
7393bd64a5bSJ. Bruce Fields }
7403bd64a5bSJ. Bruce Fields 
7413bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp)
7423bd64a5bSJ. Bruce Fields {
7433bd64a5bSJ. Bruce Fields 	struct nfs4_client *clp = dp->dl_stid.sc_client;
7443bd64a5bSJ. Bruce Fields 
7452d4a532dSJeff Layton 	WARN_ON(!list_empty(&dp->dl_recall_lru));
7462d4a532dSJeff Layton 
747afbda402SJeff Layton 	nfs4_put_deleg_lease(dp->dl_stid.sc_file);
748afbda402SJeff Layton 
7493bd64a5bSJ. Bruce Fields 	if (clp->cl_minorversion == 0)
7506011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
7513bd64a5bSJ. Bruce Fields 	else {
7523bd64a5bSJ. Bruce Fields 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
7532d4a532dSJeff Layton 		spin_lock(&clp->cl_lock);
7542d4a532dSJeff Layton 		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
7552d4a532dSJeff Layton 		spin_unlock(&clp->cl_lock);
7563bd64a5bSJ. Bruce Fields 	}
7573bd64a5bSJ. Bruce Fields }
7583bd64a5bSJ. Bruce Fields 
7591da177e4SLinus Torvalds /*
7601da177e4SLinus Torvalds  * SETCLIENTID state
7611da177e4SLinus Torvalds  */
7621da177e4SLinus Torvalds 
763ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id)
764ddc04c41SJ. Bruce Fields {
765ddc04c41SJ. Bruce Fields 	return id & CLIENT_HASH_MASK;
766ddc04c41SJ. Bruce Fields }
767ddc04c41SJ. Bruce Fields 
768ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name)
769ddc04c41SJ. Bruce Fields {
770ddc04c41SJ. Bruce Fields 	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
771ddc04c41SJ. Bruce Fields }
772ddc04c41SJ. Bruce Fields 
7731da177e4SLinus Torvalds /*
774f9d7562fSJ. Bruce Fields  * We store the NONE, READ, WRITE, and BOTH bits separately in the
775f9d7562fSJ. Bruce Fields  * st_{access,deny}_bmap field of the stateid, in order to track not
776f9d7562fSJ. Bruce Fields  * only what share bits are currently in force, but also what
777f9d7562fSJ. Bruce Fields  * combinations of share bits previous opens have used.  This allows us
778f9d7562fSJ. Bruce Fields  * to enforce the recommendation of rfc 3530 14.2.19 that the server
779f9d7562fSJ. Bruce Fields  * return an error if the client attempt to downgrade to a combination
780f9d7562fSJ. Bruce Fields  * of share bits not explicable by closing some of its previous opens.
781f9d7562fSJ. Bruce Fields  *
782f9d7562fSJ. Bruce Fields  * XXX: This enforcement is actually incomplete, since we don't keep
783f9d7562fSJ. Bruce Fields  * track of access/deny bit combinations; so, e.g., we allow:
784f9d7562fSJ. Bruce Fields  *
785f9d7562fSJ. Bruce Fields  *	OPEN allow read, deny write
786f9d7562fSJ. Bruce Fields  *	OPEN allow both, deny none
787f9d7562fSJ. Bruce Fields  *	DOWNGRADE allow read, deny none
788f9d7562fSJ. Bruce Fields  *
789f9d7562fSJ. Bruce Fields  * which we should reject.
790f9d7562fSJ. Bruce Fields  */
7915ae037e5SJeff Layton static unsigned int
7925ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) {
793f9d7562fSJ. Bruce Fields 	int i;
7945ae037e5SJeff Layton 	unsigned int access = 0;
795f9d7562fSJ. Bruce Fields 
796f9d7562fSJ. Bruce Fields 	for (i = 1; i < 4; i++) {
797f9d7562fSJ. Bruce Fields 		if (test_bit(i, &bmap))
7985ae037e5SJeff Layton 			access |= i;
799f9d7562fSJ. Bruce Fields 	}
8005ae037e5SJeff Layton 	return access;
801f9d7562fSJ. Bruce Fields }
802f9d7562fSJ. Bruce Fields 
80382c5ff1bSJeff Layton /* set share access for a given stateid */
80482c5ff1bSJeff Layton static inline void
80582c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp)
80682c5ff1bSJeff Layton {
807c11c591fSJeff Layton 	unsigned char mask = 1 << access;
808c11c591fSJeff Layton 
809c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
810c11c591fSJeff Layton 	stp->st_access_bmap |= mask;
81182c5ff1bSJeff Layton }
81282c5ff1bSJeff Layton 
81382c5ff1bSJeff Layton /* clear share access for a given stateid */
81482c5ff1bSJeff Layton static inline void
81582c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp)
81682c5ff1bSJeff Layton {
817c11c591fSJeff Layton 	unsigned char mask = 1 << access;
818c11c591fSJeff Layton 
819c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
820c11c591fSJeff Layton 	stp->st_access_bmap &= ~mask;
82182c5ff1bSJeff Layton }
82282c5ff1bSJeff Layton 
82382c5ff1bSJeff Layton /* test whether a given stateid has access */
82482c5ff1bSJeff Layton static inline bool
82582c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp)
82682c5ff1bSJeff Layton {
827c11c591fSJeff Layton 	unsigned char mask = 1 << access;
828c11c591fSJeff Layton 
829c11c591fSJeff Layton 	return (bool)(stp->st_access_bmap & mask);
83082c5ff1bSJeff Layton }
83182c5ff1bSJeff Layton 
832ce0fc43cSJeff Layton /* set share deny for a given stateid */
833ce0fc43cSJeff Layton static inline void
834c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp)
835ce0fc43cSJeff Layton {
836c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
837c11c591fSJeff Layton 
838c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
839c11c591fSJeff Layton 	stp->st_deny_bmap |= mask;
840ce0fc43cSJeff Layton }
841ce0fc43cSJeff Layton 
842ce0fc43cSJeff Layton /* clear share deny for a given stateid */
843ce0fc43cSJeff Layton static inline void
844c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp)
845ce0fc43cSJeff Layton {
846c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
847c11c591fSJeff Layton 
848c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
849c11c591fSJeff Layton 	stp->st_deny_bmap &= ~mask;
850ce0fc43cSJeff Layton }
851ce0fc43cSJeff Layton 
852ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */
853ce0fc43cSJeff Layton static inline bool
854c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp)
855ce0fc43cSJeff Layton {
856c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
857c11c591fSJeff Layton 
858c11c591fSJeff Layton 	return (bool)(stp->st_deny_bmap & mask);
859f9d7562fSJ. Bruce Fields }
860f9d7562fSJ. Bruce Fields 
861f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access)
862f9d7562fSJ. Bruce Fields {
8638f34a430SJ. Bruce Fields 	switch (access & NFS4_SHARE_ACCESS_BOTH) {
864f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
865f9d7562fSJ. Bruce Fields 		return O_RDONLY;
866f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
867f9d7562fSJ. Bruce Fields 		return O_WRONLY;
868f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
869f9d7562fSJ. Bruce Fields 		return O_RDWR;
870f9d7562fSJ. Bruce Fields 	}
871063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(1);
872063b0fb9SJ. Bruce Fields 	return O_RDONLY;
873f9d7562fSJ. Bruce Fields }
874f9d7562fSJ. Bruce Fields 
875baeb4ff0SJeff Layton /*
876baeb4ff0SJeff Layton  * A stateid that had a deny mode associated with it is being released
877baeb4ff0SJeff Layton  * or downgraded. Recalculate the deny mode on the file.
878baeb4ff0SJeff Layton  */
879baeb4ff0SJeff Layton static void
880baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp)
881baeb4ff0SJeff Layton {
882baeb4ff0SJeff Layton 	struct nfs4_ol_stateid *stp;
883baeb4ff0SJeff Layton 
884baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
885baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
886baeb4ff0SJeff Layton 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile)
887baeb4ff0SJeff Layton 		fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap);
888baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
889baeb4ff0SJeff Layton }
890baeb4ff0SJeff Layton 
891baeb4ff0SJeff Layton static void
892baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp)
893baeb4ff0SJeff Layton {
894baeb4ff0SJeff Layton 	int i;
895baeb4ff0SJeff Layton 	bool change = false;
896baeb4ff0SJeff Layton 
897baeb4ff0SJeff Layton 	for (i = 1; i < 4; i++) {
898baeb4ff0SJeff Layton 		if ((i & deny) != i) {
899baeb4ff0SJeff Layton 			change = true;
900baeb4ff0SJeff Layton 			clear_deny(i, stp);
901baeb4ff0SJeff Layton 		}
902baeb4ff0SJeff Layton 	}
903baeb4ff0SJeff Layton 
904baeb4ff0SJeff Layton 	/* Recalculate per-file deny mode if there was a change */
905baeb4ff0SJeff Layton 	if (change)
90611b9164aSTrond Myklebust 		recalculate_deny_mode(stp->st_stid.sc_file);
907baeb4ff0SJeff Layton }
908baeb4ff0SJeff Layton 
90982c5ff1bSJeff Layton /* release all access and file references for a given stateid */
91082c5ff1bSJeff Layton static void
91182c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp)
91282c5ff1bSJeff Layton {
91382c5ff1bSJeff Layton 	int i;
91411b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
915baeb4ff0SJeff Layton 
916baeb4ff0SJeff Layton 	if (fp && stp->st_deny_bmap != 0)
917baeb4ff0SJeff Layton 		recalculate_deny_mode(fp);
91882c5ff1bSJeff Layton 
91982c5ff1bSJeff Layton 	for (i = 1; i < 4; i++) {
92082c5ff1bSJeff Layton 		if (test_access(i, stp))
92111b9164aSTrond Myklebust 			nfs4_file_put_access(stp->st_stid.sc_file, i);
92282c5ff1bSJeff Layton 		clear_access(i, stp);
92382c5ff1bSJeff Layton 	}
92482c5ff1bSJeff Layton }
92582c5ff1bSJeff Layton 
9266b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
9276b180f0bSJeff Layton {
928a819ecc1SJeff Layton 	struct nfs4_client *clp = sop->so_client;
929a819ecc1SJeff Layton 
930a819ecc1SJeff Layton 	might_lock(&clp->cl_lock);
931a819ecc1SJeff Layton 
932a819ecc1SJeff Layton 	if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock))
9336b180f0bSJeff Layton 		return;
9348f4b54c5SJeff Layton 	sop->so_ops->so_unhash(sop);
935a819ecc1SJeff Layton 	spin_unlock(&clp->cl_lock);
9366b180f0bSJeff Layton 	kfree(sop->so_owner.data);
9376b180f0bSJeff Layton 	sop->so_ops->so_free(sop);
9386b180f0bSJeff Layton }
9396b180f0bSJeff Layton 
9404ae098d3SJeff Layton static void unhash_ol_stateid(struct nfs4_ol_stateid *stp)
941529d7b2aSJ. Bruce Fields {
94211b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
9431d31a253STrond Myklebust 
9441c755dc1SJeff Layton 	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
9451c755dc1SJeff Layton 
9461d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
947529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perfile);
9481d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
949529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perstateowner);
950529d7b2aSJ. Bruce Fields }
951529d7b2aSJ. Bruce Fields 
9526011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
953529d7b2aSJ. Bruce Fields {
9546011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
9554665e2baSJ. Bruce Fields 
9566011695dSTrond Myklebust 	release_all_access(stp);
957d3134b10SJeff Layton 	if (stp->st_stateowner)
958d3134b10SJeff Layton 		nfs4_put_stateowner(stp->st_stateowner);
9596011695dSTrond Myklebust 	kmem_cache_free(stateid_slab, stid);
960529d7b2aSJ. Bruce Fields }
961529d7b2aSJ. Bruce Fields 
962b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid)
963529d7b2aSJ. Bruce Fields {
964b49e084dSJeff Layton 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
965b49e084dSJeff Layton 	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
966529d7b2aSJ. Bruce Fields 	struct file *file;
967529d7b2aSJ. Bruce Fields 
968b49e084dSJeff Layton 	file = find_any_file(stp->st_stid.sc_file);
969b49e084dSJeff Layton 	if (file)
970b49e084dSJeff Layton 		filp_close(file, (fl_owner_t)lo);
971b49e084dSJeff Layton 	nfs4_free_ol_stateid(stid);
972b49e084dSJeff Layton }
973b49e084dSJeff Layton 
9742c41beb0SJeff Layton /*
9752c41beb0SJeff Layton  * Put the persistent reference to an already unhashed generic stateid, while
9762c41beb0SJeff Layton  * holding the cl_lock. If it's the last reference, then put it onto the
9772c41beb0SJeff Layton  * reaplist for later destruction.
9782c41beb0SJeff Layton  */
9792c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
9802c41beb0SJeff Layton 				       struct list_head *reaplist)
9812c41beb0SJeff Layton {
9822c41beb0SJeff Layton 	struct nfs4_stid *s = &stp->st_stid;
9832c41beb0SJeff Layton 	struct nfs4_client *clp = s->sc_client;
9842c41beb0SJeff Layton 
9852c41beb0SJeff Layton 	lockdep_assert_held(&clp->cl_lock);
9862c41beb0SJeff Layton 
9872c41beb0SJeff Layton 	WARN_ON_ONCE(!list_empty(&stp->st_locks));
9882c41beb0SJeff Layton 
9892c41beb0SJeff Layton 	if (!atomic_dec_and_test(&s->sc_count)) {
9902c41beb0SJeff Layton 		wake_up_all(&close_wq);
9912c41beb0SJeff Layton 		return;
9922c41beb0SJeff Layton 	}
9932c41beb0SJeff Layton 
9942c41beb0SJeff Layton 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
9952c41beb0SJeff Layton 	list_add(&stp->st_locks, reaplist);
9962c41beb0SJeff Layton }
9972c41beb0SJeff Layton 
9983c1c995cSJeff Layton static void unhash_lock_stateid(struct nfs4_ol_stateid *stp)
9993c1c995cSJeff Layton {
10003c1c995cSJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
10013c1c995cSJeff Layton 
10023c1c995cSJeff Layton 	lockdep_assert_held(&oo->oo_owner.so_client->cl_lock);
10033c1c995cSJeff Layton 
10043c1c995cSJeff Layton 	list_del_init(&stp->st_locks);
10054ae098d3SJeff Layton 	unhash_ol_stateid(stp);
10063c1c995cSJeff Layton 	unhash_stid(&stp->st_stid);
10073c1c995cSJeff Layton }
10083c1c995cSJeff Layton 
10095adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp)
1010b49e084dSJeff Layton {
10111c755dc1SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
10121c755dc1SJeff Layton 
10131c755dc1SJeff Layton 	spin_lock(&oo->oo_owner.so_client->cl_lock);
10143c1c995cSJeff Layton 	unhash_lock_stateid(stp);
10151c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
10166011695dSTrond Myklebust 	nfs4_put_stid(&stp->st_stid);
1017529d7b2aSJ. Bruce Fields }
1018529d7b2aSJ. Bruce Fields 
1019c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
1020529d7b2aSJ. Bruce Fields {
1021d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
1022c58c6610STrond Myklebust 
1023d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
1024c58c6610STrond Myklebust 
10258f4b54c5SJeff Layton 	list_del_init(&lo->lo_owner.so_strhash);
10268f4b54c5SJeff Layton }
10278f4b54c5SJeff Layton 
10282c41beb0SJeff Layton /*
10292c41beb0SJeff Layton  * Free a list of generic stateids that were collected earlier after being
10302c41beb0SJeff Layton  * fully unhashed.
10312c41beb0SJeff Layton  */
10322c41beb0SJeff Layton static void
10332c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist)
10342c41beb0SJeff Layton {
10352c41beb0SJeff Layton 	struct nfs4_ol_stateid *stp;
1036fb94d766SKinglong Mee 	struct nfs4_file *fp;
10372c41beb0SJeff Layton 
10382c41beb0SJeff Layton 	might_sleep();
10392c41beb0SJeff Layton 
10402c41beb0SJeff Layton 	while (!list_empty(reaplist)) {
10412c41beb0SJeff Layton 		stp = list_first_entry(reaplist, struct nfs4_ol_stateid,
10422c41beb0SJeff Layton 				       st_locks);
10432c41beb0SJeff Layton 		list_del(&stp->st_locks);
1044fb94d766SKinglong Mee 		fp = stp->st_stid.sc_file;
10452c41beb0SJeff Layton 		stp->st_stid.sc_free(&stp->st_stid);
1046fb94d766SKinglong Mee 		if (fp)
1047fb94d766SKinglong Mee 			put_nfs4_file(fp);
10482c41beb0SJeff Layton 	}
10492c41beb0SJeff Layton }
10502c41beb0SJeff Layton 
1051fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo)
1052529d7b2aSJ. Bruce Fields {
1053d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
10543c1c995cSJeff Layton 	struct nfs4_ol_stateid *stp;
10553c1c995cSJeff Layton 	struct list_head reaplist;
10563c1c995cSJeff Layton 
10573c1c995cSJeff Layton 	INIT_LIST_HEAD(&reaplist);
1058c58c6610STrond Myklebust 
1059d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
1060c58c6610STrond Myklebust 	unhash_lockowner_locked(lo);
10613c1c995cSJeff Layton 	while (!list_empty(&lo->lo_owner.so_stateids)) {
10623c1c995cSJeff Layton 		stp = list_first_entry(&lo->lo_owner.so_stateids,
10633c1c995cSJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
10643c1c995cSJeff Layton 		unhash_lock_stateid(stp);
10652c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
10663c1c995cSJeff Layton 	}
1067d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
10682c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
10696b180f0bSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
1070529d7b2aSJ. Bruce Fields }
1071529d7b2aSJ. Bruce Fields 
1072d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
1073d83017f9SJeff Layton 				       struct list_head *reaplist)
10743c87b9b7STrond Myklebust {
10753c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *stp;
10763c87b9b7STrond Myklebust 
10773c87b9b7STrond Myklebust 	while (!list_empty(&open_stp->st_locks)) {
10783c87b9b7STrond Myklebust 		stp = list_entry(open_stp->st_locks.next,
10793c87b9b7STrond Myklebust 				struct nfs4_ol_stateid, st_locks);
1080d83017f9SJeff Layton 		unhash_lock_stateid(stp);
1081d83017f9SJeff Layton 		put_ol_stateid_locked(stp, reaplist);
1082529d7b2aSJ. Bruce Fields 	}
1083529d7b2aSJ. Bruce Fields }
1084529d7b2aSJ. Bruce Fields 
1085d83017f9SJeff Layton static void unhash_open_stateid(struct nfs4_ol_stateid *stp,
1086d83017f9SJeff Layton 				struct list_head *reaplist)
10872283963fSJ. Bruce Fields {
10882c41beb0SJeff Layton 	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
10892c41beb0SJeff Layton 
10904ae098d3SJeff Layton 	unhash_ol_stateid(stp);
1091d83017f9SJeff Layton 	release_open_stateid_locks(stp, reaplist);
109238c387b5SJ. Bruce Fields }
109338c387b5SJ. Bruce Fields 
109438c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp)
109538c387b5SJ. Bruce Fields {
10962c41beb0SJeff Layton 	LIST_HEAD(reaplist);
10972c41beb0SJeff Layton 
10982c41beb0SJeff Layton 	spin_lock(&stp->st_stid.sc_client->cl_lock);
1099d83017f9SJeff Layton 	unhash_open_stateid(stp, &reaplist);
11002c41beb0SJeff Layton 	put_ol_stateid_locked(stp, &reaplist);
11012c41beb0SJeff Layton 	spin_unlock(&stp->st_stid.sc_client->cl_lock);
11022c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
11032283963fSJ. Bruce Fields }
11042283963fSJ. Bruce Fields 
11057ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo)
1106f1d110caSJ. Bruce Fields {
1107d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
11087ffb5880STrond Myklebust 
1109d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
11107ffb5880STrond Myklebust 
11118f4b54c5SJeff Layton 	list_del_init(&oo->oo_owner.so_strhash);
11128f4b54c5SJeff Layton 	list_del_init(&oo->oo_perclient);
1113f1d110caSJ. Bruce Fields }
1114f1d110caSJ. Bruce Fields 
1115f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo)
1116f7a4d872SJ. Bruce Fields {
1117217526e7SJeff Layton 	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1118217526e7SJeff Layton 					  nfsd_net_id);
1119217526e7SJeff Layton 	struct nfs4_ol_stateid *s;
1120f7a4d872SJ. Bruce Fields 
1121217526e7SJeff Layton 	spin_lock(&nn->client_lock);
1122217526e7SJeff Layton 	s = oo->oo_last_closed_stid;
1123f7a4d872SJ. Bruce Fields 	if (s) {
1124d3134b10SJeff Layton 		list_del_init(&oo->oo_close_lru);
1125f7a4d872SJ. Bruce Fields 		oo->oo_last_closed_stid = NULL;
1126f7a4d872SJ. Bruce Fields 	}
1127217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
1128217526e7SJeff Layton 	if (s)
1129217526e7SJeff Layton 		nfs4_put_stid(&s->st_stid);
1130f7a4d872SJ. Bruce Fields }
1131f7a4d872SJ. Bruce Fields 
11322c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo)
11338f4b54c5SJeff Layton {
11348f4b54c5SJeff Layton 	struct nfs4_ol_stateid *stp;
1135d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
11362c41beb0SJeff Layton 	struct list_head reaplist;
11377ffb5880STrond Myklebust 
11382c41beb0SJeff Layton 	INIT_LIST_HEAD(&reaplist);
11397ffb5880STrond Myklebust 
1140d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
11417ffb5880STrond Myklebust 	unhash_openowner_locked(oo);
11422c41beb0SJeff Layton 	while (!list_empty(&oo->oo_owner.so_stateids)) {
11432c41beb0SJeff Layton 		stp = list_first_entry(&oo->oo_owner.so_stateids,
11442c41beb0SJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
1145d83017f9SJeff Layton 		unhash_open_stateid(stp, &reaplist);
11462c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
11472c41beb0SJeff Layton 	}
1148d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
11492c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
1150f7a4d872SJ. Bruce Fields 	release_last_closed_stateid(oo);
11516b180f0bSJeff Layton 	nfs4_put_stateowner(&oo->oo_owner);
1152f1d110caSJ. Bruce Fields }
1153f1d110caSJ. Bruce Fields 
11545282fd72SMarc Eshel static inline int
11555282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid)
11565282fd72SMarc Eshel {
11575282fd72SMarc Eshel 	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
11585282fd72SMarc Eshel 
11595282fd72SMarc Eshel 	return sid->sequence % SESSION_HASH_SIZE;
11605282fd72SMarc Eshel }
11615282fd72SMarc Eshel 
11628f199b82STrond Myklebust #ifdef NFSD_DEBUG
11635282fd72SMarc Eshel static inline void
11645282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
11655282fd72SMarc Eshel {
11665282fd72SMarc Eshel 	u32 *ptr = (u32 *)(&sessionid->data[0]);
11675282fd72SMarc Eshel 	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
11685282fd72SMarc Eshel }
11698f199b82STrond Myklebust #else
11708f199b82STrond Myklebust static inline void
11718f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
11728f199b82STrond Myklebust {
11738f199b82STrond Myklebust }
11748f199b82STrond Myklebust #endif
11758f199b82STrond Myklebust 
11769411b1d4SJ. Bruce Fields /*
11779411b1d4SJ. Bruce Fields  * Bump the seqid on cstate->replay_owner, and clear replay_owner if it
11789411b1d4SJ. Bruce Fields  * won't be used for replay.
11799411b1d4SJ. Bruce Fields  */
11809411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
11819411b1d4SJ. Bruce Fields {
11829411b1d4SJ. Bruce Fields 	struct nfs4_stateowner *so = cstate->replay_owner;
11839411b1d4SJ. Bruce Fields 
11849411b1d4SJ. Bruce Fields 	if (nfserr == nfserr_replay_me)
11859411b1d4SJ. Bruce Fields 		return;
11869411b1d4SJ. Bruce Fields 
11879411b1d4SJ. Bruce Fields 	if (!seqid_mutating_err(ntohl(nfserr))) {
118858fb12e6SJeff Layton 		nfsd4_cstate_clear_replay(cstate);
11899411b1d4SJ. Bruce Fields 		return;
11909411b1d4SJ. Bruce Fields 	}
11919411b1d4SJ. Bruce Fields 	if (!so)
11929411b1d4SJ. Bruce Fields 		return;
11939411b1d4SJ. Bruce Fields 	if (so->so_is_open_owner)
11949411b1d4SJ. Bruce Fields 		release_last_closed_stateid(openowner(so));
11959411b1d4SJ. Bruce Fields 	so->so_seqid++;
11969411b1d4SJ. Bruce Fields 	return;
11979411b1d4SJ. Bruce Fields }
11985282fd72SMarc Eshel 
1199ec6b5d7bSAndy Adamson static void
1200ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses)
1201ec6b5d7bSAndy Adamson {
1202ec6b5d7bSAndy Adamson 	struct nfs4_client *clp = ses->se_client;
1203ec6b5d7bSAndy Adamson 	struct nfsd4_sessionid *sid;
1204ec6b5d7bSAndy Adamson 
1205ec6b5d7bSAndy Adamson 	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
1206ec6b5d7bSAndy Adamson 	sid->clientid = clp->cl_clientid;
1207ec6b5d7bSAndy Adamson 	sid->sequence = current_sessionid++;
1208ec6b5d7bSAndy Adamson 	sid->reserved = 0;
1209ec6b5d7bSAndy Adamson }
1210ec6b5d7bSAndy Adamson 
1211ec6b5d7bSAndy Adamson /*
1212a649637cSAndy Adamson  * The protocol defines ca_maxresponssize_cached to include the size of
1213a649637cSAndy Adamson  * the rpc header, but all we need to cache is the data starting after
1214a649637cSAndy Adamson  * the end of the initial SEQUENCE operation--the rest we regenerate
1215a649637cSAndy Adamson  * each time.  Therefore we can advertise a ca_maxresponssize_cached
1216a649637cSAndy Adamson  * value that is the number of bytes in our cache plus a few additional
1217a649637cSAndy Adamson  * bytes.  In order to stay on the safe side, and not promise more than
1218a649637cSAndy Adamson  * we can cache, those additional bytes must be the minimum possible: 24
1219a649637cSAndy Adamson  * bytes of rpc header (xid through accept state, with AUTH_NULL
1220a649637cSAndy Adamson  * verifier), 12 for the compound header (with zero-length tag), and 44
1221a649637cSAndy Adamson  * for the SEQUENCE op response:
1222ec6b5d7bSAndy Adamson  */
1223a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
1224a649637cSAndy Adamson 
1225557ce264SAndy Adamson static void
1226557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses)
1227557ce264SAndy Adamson {
1228557ce264SAndy Adamson 	int i;
1229557ce264SAndy Adamson 
1230557ce264SAndy Adamson 	for (i = 0; i < ses->se_fchannel.maxreqs; i++)
1231557ce264SAndy Adamson 		kfree(ses->se_slots[i]);
1232557ce264SAndy Adamson }
1233557ce264SAndy Adamson 
1234efe0cb6dSJ. Bruce Fields /*
1235efe0cb6dSJ. Bruce Fields  * We don't actually need to cache the rpc and session headers, so we
1236efe0cb6dSJ. Bruce Fields  * can allocate a little less for each slot:
1237efe0cb6dSJ. Bruce Fields  */
123855c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca)
1239efe0cb6dSJ. Bruce Fields {
124055c760cfSJ. Bruce Fields 	u32 size;
1241efe0cb6dSJ. Bruce Fields 
124255c760cfSJ. Bruce Fields 	if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ)
124355c760cfSJ. Bruce Fields 		size = 0;
124455c760cfSJ. Bruce Fields 	else
124555c760cfSJ. Bruce Fields 		size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
124655c760cfSJ. Bruce Fields 	return size + sizeof(struct nfsd4_slot);
1247557ce264SAndy Adamson }
1248557ce264SAndy Adamson 
12495b6feee9SJ. Bruce Fields /*
12505b6feee9SJ. Bruce Fields  * XXX: If we run out of reserved DRC memory we could (up to a point)
12515b6feee9SJ. Bruce Fields  * re-negotiate active sessions and reduce their slot usage to make
125242b2aa86SJustin P. Mattock  * room for new connections. For now we just fail the create session.
12535b6feee9SJ. Bruce Fields  */
125455c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
12555b6feee9SJ. Bruce Fields {
125655c760cfSJ. Bruce Fields 	u32 slotsize = slot_bytes(ca);
125755c760cfSJ. Bruce Fields 	u32 num = ca->maxreqs;
12585b6feee9SJ. Bruce Fields 	int avail;
12595b6feee9SJ. Bruce Fields 
12605b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
1261697ce9beSZhang Yanfei 	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
12625b6feee9SJ. Bruce Fields 		    nfsd_drc_max_mem - nfsd_drc_mem_used);
12635b6feee9SJ. Bruce Fields 	num = min_t(int, num, avail / slotsize);
12645b6feee9SJ. Bruce Fields 	nfsd_drc_mem_used += num * slotsize;
12655b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
12665b6feee9SJ. Bruce Fields 
12675b6feee9SJ. Bruce Fields 	return num;
12685b6feee9SJ. Bruce Fields }
12695b6feee9SJ. Bruce Fields 
127055c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
12715b6feee9SJ. Bruce Fields {
127255c760cfSJ. Bruce Fields 	int slotsize = slot_bytes(ca);
127355c760cfSJ. Bruce Fields 
12745b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
127555c760cfSJ. Bruce Fields 	nfsd_drc_mem_used -= slotsize * ca->maxreqs;
12765b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
12775b6feee9SJ. Bruce Fields }
12785b6feee9SJ. Bruce Fields 
127960810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
128060810e54SKinglong Mee 					   struct nfsd4_channel_attrs *battrs)
12815b6feee9SJ. Bruce Fields {
128260810e54SKinglong Mee 	int numslots = fattrs->maxreqs;
128360810e54SKinglong Mee 	int slotsize = slot_bytes(fattrs);
12845b6feee9SJ. Bruce Fields 	struct nfsd4_session *new;
12855b6feee9SJ. Bruce Fields 	int mem, i;
1286ec6b5d7bSAndy Adamson 
1287c23753daSJ. Bruce Fields 	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
1288ec6b5d7bSAndy Adamson 			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
12895b6feee9SJ. Bruce Fields 	mem = numslots * sizeof(struct nfsd4_slot *);
1290ec6b5d7bSAndy Adamson 
12915b6feee9SJ. Bruce Fields 	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
12926c18ba9fSAlexandros Batsakis 	if (!new)
12935b6feee9SJ. Bruce Fields 		return NULL;
1294ec6b5d7bSAndy Adamson 	/* allocate each struct nfsd4_slot and data cache in one piece */
12955b6feee9SJ. Bruce Fields 	for (i = 0; i < numslots; i++) {
129655c760cfSJ. Bruce Fields 		new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL);
12975b6feee9SJ. Bruce Fields 		if (!new->se_slots[i])
1298ec6b5d7bSAndy Adamson 			goto out_free;
1299ec6b5d7bSAndy Adamson 	}
130060810e54SKinglong Mee 
130160810e54SKinglong Mee 	memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
130260810e54SKinglong Mee 	memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
130360810e54SKinglong Mee 
13045b6feee9SJ. Bruce Fields 	return new;
13055b6feee9SJ. Bruce Fields out_free:
13065b6feee9SJ. Bruce Fields 	while (i--)
13075b6feee9SJ. Bruce Fields 		kfree(new->se_slots[i]);
13085b6feee9SJ. Bruce Fields 	kfree(new);
13095b6feee9SJ. Bruce Fields 	return NULL;
13105b6feee9SJ. Bruce Fields }
13115b6feee9SJ. Bruce Fields 
131219cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c)
131319cf5c02SJ. Bruce Fields {
131419cf5c02SJ. Bruce Fields 	svc_xprt_put(c->cn_xprt);
131519cf5c02SJ. Bruce Fields 	kfree(c);
131619cf5c02SJ. Bruce Fields }
131719cf5c02SJ. Bruce Fields 
131819cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u)
131919cf5c02SJ. Bruce Fields {
132019cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
132119cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = c->cn_session->se_client;
132219cf5c02SJ. Bruce Fields 
132319cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
132419cf5c02SJ. Bruce Fields 	if (!list_empty(&c->cn_persession)) {
132519cf5c02SJ. Bruce Fields 		list_del(&c->cn_persession);
132619cf5c02SJ. Bruce Fields 		free_conn(c);
132719cf5c02SJ. Bruce Fields 	}
1328eea49806SJ. Bruce Fields 	nfsd4_probe_callback(clp);
13292e4b7239SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
133019cf5c02SJ. Bruce Fields }
133119cf5c02SJ. Bruce Fields 
1332d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
1333c7662518SJ. Bruce Fields {
1334c7662518SJ. Bruce Fields 	struct nfsd4_conn *conn;
1335c7662518SJ. Bruce Fields 
1336c7662518SJ. Bruce Fields 	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
1337c7662518SJ. Bruce Fields 	if (!conn)
1338db90681dSJ. Bruce Fields 		return NULL;
1339c7662518SJ. Bruce Fields 	svc_xprt_get(rqstp->rq_xprt);
1340c7662518SJ. Bruce Fields 	conn->cn_xprt = rqstp->rq_xprt;
1341d29c374cSJ. Bruce Fields 	conn->cn_flags = flags;
1342db90681dSJ. Bruce Fields 	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
1343db90681dSJ. Bruce Fields 	return conn;
1344db90681dSJ. Bruce Fields }
1345db90681dSJ. Bruce Fields 
1346328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1347328ead28SJ. Bruce Fields {
1348328ead28SJ. Bruce Fields 	conn->cn_session = ses;
1349328ead28SJ. Bruce Fields 	list_add(&conn->cn_persession, &ses->se_conns);
1350328ead28SJ. Bruce Fields }
1351328ead28SJ. Bruce Fields 
1352db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1353db90681dSJ. Bruce Fields {
1354db90681dSJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
1355c7662518SJ. Bruce Fields 
1356c7662518SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1357328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(conn, ses);
1358c7662518SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1359db90681dSJ. Bruce Fields }
1360c7662518SJ. Bruce Fields 
136121b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn)
1362db90681dSJ. Bruce Fields {
136319cf5c02SJ. Bruce Fields 	conn->cn_xpt_user.callback = nfsd4_conn_lost;
136421b75b01SJ. Bruce Fields 	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
1365db90681dSJ. Bruce Fields }
1366db90681dSJ. Bruce Fields 
1367e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
1368db90681dSJ. Bruce Fields {
136921b75b01SJ. Bruce Fields 	int ret;
1370db90681dSJ. Bruce Fields 
1371db90681dSJ. Bruce Fields 	nfsd4_hash_conn(conn, ses);
137221b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(conn);
137321b75b01SJ. Bruce Fields 	if (ret)
137421b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
137521b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&conn->cn_xpt_user);
137657a37144SJ. Bruce Fields 	/* We may have gained or lost a callback channel: */
137757a37144SJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
1378c7662518SJ. Bruce Fields }
1379c7662518SJ. Bruce Fields 
1380e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
13811d1bc8f2SJ. Bruce Fields {
13821d1bc8f2SJ. Bruce Fields 	u32 dir = NFS4_CDFC4_FORE;
13831d1bc8f2SJ. Bruce Fields 
1384e1ff371fSJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN)
13851d1bc8f2SJ. Bruce Fields 		dir |= NFS4_CDFC4_BACK;
1386e1ff371fSJ. Bruce Fields 	return alloc_conn(rqstp, dir);
13871d1bc8f2SJ. Bruce Fields }
13881d1bc8f2SJ. Bruce Fields 
13891d1bc8f2SJ. Bruce Fields /* must be called under client_lock */
139019cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s)
1391c7662518SJ. Bruce Fields {
139219cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = s->se_client;
139319cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c;
139419cf5c02SJ. Bruce Fields 
139519cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
139619cf5c02SJ. Bruce Fields 	while (!list_empty(&s->se_conns)) {
139719cf5c02SJ. Bruce Fields 		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
139819cf5c02SJ. Bruce Fields 		list_del_init(&c->cn_persession);
139919cf5c02SJ. Bruce Fields 		spin_unlock(&clp->cl_lock);
140019cf5c02SJ. Bruce Fields 
140119cf5c02SJ. Bruce Fields 		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
140219cf5c02SJ. Bruce Fields 		free_conn(c);
140319cf5c02SJ. Bruce Fields 
140419cf5c02SJ. Bruce Fields 		spin_lock(&clp->cl_lock);
140519cf5c02SJ. Bruce Fields 	}
140619cf5c02SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1407c7662518SJ. Bruce Fields }
1408c7662518SJ. Bruce Fields 
14091377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses)
14101377b69eSJ. Bruce Fields {
14111377b69eSJ. Bruce Fields 	free_session_slots(ses);
14121377b69eSJ. Bruce Fields 	kfree(ses);
14131377b69eSJ. Bruce Fields }
14141377b69eSJ. Bruce Fields 
141566b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses)
1416508dc6e1SBenny Halevy {
1417c7662518SJ. Bruce Fields 	nfsd4_del_conns(ses);
141855c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&ses->se_fchannel);
1419c7662518SJ. Bruce Fields 	__free_session(ses);
1420a827bcb2SJ. Bruce Fields }
1421ec6b5d7bSAndy Adamson 
1422135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
1423a827bcb2SJ. Bruce Fields {
1424a827bcb2SJ. Bruce Fields 	int idx;
14251872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1426a827bcb2SJ. Bruce Fields 
1427ec6b5d7bSAndy Adamson 	new->se_client = clp;
1428ec6b5d7bSAndy Adamson 	gen_sessionid(new);
1429ec6b5d7bSAndy Adamson 
1430c7662518SJ. Bruce Fields 	INIT_LIST_HEAD(&new->se_conns);
1431c7662518SJ. Bruce Fields 
1432ac7c46f2SJ. Bruce Fields 	new->se_cb_seq_nr = 1;
1433ec6b5d7bSAndy Adamson 	new->se_flags = cses->flags;
14348b5ce5cdSJ. Bruce Fields 	new->se_cb_prog = cses->callback_prog;
1435c6bb3ca2SJ. Bruce Fields 	new->se_cb_sec = cses->cb_sec;
143666b2b9b2SJ. Bruce Fields 	atomic_set(&new->se_ref, 0);
14375b6feee9SJ. Bruce Fields 	idx = hash_sessionid(&new->se_sessionid);
14381872de0eSStanislav Kinsbursky 	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
14394c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1440ec6b5d7bSAndy Adamson 	list_add(&new->se_perclnt, &clp->cl_sessions);
14414c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
144260810e54SKinglong Mee 
1443dcbeaa68SJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN) {
1444edd76786SJ. Bruce Fields 		struct sockaddr *sa = svc_addr(rqstp);
1445dcbeaa68SJ. Bruce Fields 		/*
1446dcbeaa68SJ. Bruce Fields 		 * This is a little silly; with sessions there's no real
1447dcbeaa68SJ. Bruce Fields 		 * use for the callback address.  Use the peer address
1448dcbeaa68SJ. Bruce Fields 		 * as a reasonable default for now, but consider fixing
1449dcbeaa68SJ. Bruce Fields 		 * the rpc client not to require an address in the
1450dcbeaa68SJ. Bruce Fields 		 * future:
1451dcbeaa68SJ. Bruce Fields 		 */
1452edd76786SJ. Bruce Fields 		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
1453edd76786SJ. Bruce Fields 		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
1454edd76786SJ. Bruce Fields 	}
1455ec6b5d7bSAndy Adamson }
1456ec6b5d7bSAndy Adamson 
14579089f1b4SBenny Halevy /* caller must hold client_lock */
14585282fd72SMarc Eshel static struct nfsd4_session *
1459d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
14605282fd72SMarc Eshel {
14615282fd72SMarc Eshel 	struct nfsd4_session *elem;
14625282fd72SMarc Eshel 	int idx;
14631872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
14645282fd72SMarc Eshel 
14650a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
14660a880a28STrond Myklebust 
14675282fd72SMarc Eshel 	dump_sessionid(__func__, sessionid);
14685282fd72SMarc Eshel 	idx = hash_sessionid(sessionid);
14695282fd72SMarc Eshel 	/* Search in the appropriate list */
14701872de0eSStanislav Kinsbursky 	list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) {
14715282fd72SMarc Eshel 		if (!memcmp(elem->se_sessionid.data, sessionid->data,
14725282fd72SMarc Eshel 			    NFS4_MAX_SESSIONID_LEN)) {
14735282fd72SMarc Eshel 			return elem;
14745282fd72SMarc Eshel 		}
14755282fd72SMarc Eshel 	}
14765282fd72SMarc Eshel 
14775282fd72SMarc Eshel 	dprintk("%s: session not found\n", __func__);
14785282fd72SMarc Eshel 	return NULL;
14795282fd72SMarc Eshel }
14805282fd72SMarc Eshel 
1481d4e19e70STrond Myklebust static struct nfsd4_session *
1482d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net,
1483d4e19e70STrond Myklebust 		__be32 *ret)
1484d4e19e70STrond Myklebust {
1485d4e19e70STrond Myklebust 	struct nfsd4_session *session;
1486d4e19e70STrond Myklebust 	__be32 status = nfserr_badsession;
1487d4e19e70STrond Myklebust 
1488d4e19e70STrond Myklebust 	session = __find_in_sessionid_hashtbl(sessionid, net);
1489d4e19e70STrond Myklebust 	if (!session)
1490d4e19e70STrond Myklebust 		goto out;
1491d4e19e70STrond Myklebust 	status = nfsd4_get_session_locked(session);
1492d4e19e70STrond Myklebust 	if (status)
1493d4e19e70STrond Myklebust 		session = NULL;
1494d4e19e70STrond Myklebust out:
1495d4e19e70STrond Myklebust 	*ret = status;
1496d4e19e70STrond Myklebust 	return session;
1497d4e19e70STrond Myklebust }
1498d4e19e70STrond Myklebust 
14999089f1b4SBenny Halevy /* caller must hold client_lock */
15007116ed6bSAndy Adamson static void
15015282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses)
15027116ed6bSAndy Adamson {
15030a880a28STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
15040a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
15050a880a28STrond Myklebust 
15060a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
15070a880a28STrond Myklebust 
15087116ed6bSAndy Adamson 	list_del(&ses->se_hash);
15094c649378SJ. Bruce Fields 	spin_lock(&ses->se_client->cl_lock);
15107116ed6bSAndy Adamson 	list_del(&ses->se_perclnt);
15114c649378SJ. Bruce Fields 	spin_unlock(&ses->se_client->cl_lock);
15125282fd72SMarc Eshel }
15135282fd72SMarc Eshel 
15141da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
15151da177e4SLinus Torvalds static int
15162c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
15171da177e4SLinus Torvalds {
15182c142baaSStanislav Kinsbursky 	if (clid->cl_boot == nn->boot_time)
15191da177e4SLinus Torvalds 		return 0;
152060adfc50SAndy Adamson 	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
15212c142baaSStanislav Kinsbursky 		clid->cl_boot, clid->cl_id, nn->boot_time);
15221da177e4SLinus Torvalds 	return 1;
15231da177e4SLinus Torvalds }
15241da177e4SLinus Torvalds 
15251da177e4SLinus Torvalds /*
15261da177e4SLinus Torvalds  * XXX Should we use a slab cache ?
15271da177e4SLinus Torvalds  * This type of memory management is somewhat inefficient, but we use it
15281da177e4SLinus Torvalds  * anyway since SETCLIENTID is not a common operation.
15291da177e4SLinus Torvalds  */
153035bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name)
15311da177e4SLinus Torvalds {
15321da177e4SLinus Torvalds 	struct nfs4_client *clp;
1533d4f0489fSTrond Myklebust 	int i;
15341da177e4SLinus Torvalds 
153535bba9a3SJ. Bruce Fields 	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
153635bba9a3SJ. Bruce Fields 	if (clp == NULL)
153735bba9a3SJ. Bruce Fields 		return NULL;
153867114fe6SThomas Meyer 	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
1539d4f0489fSTrond Myklebust 	if (clp->cl_name.data == NULL)
1540d4f0489fSTrond Myklebust 		goto err_no_name;
1541d4f0489fSTrond Myklebust 	clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
1542d4f0489fSTrond Myklebust 			OWNER_HASH_SIZE, GFP_KERNEL);
1543d4f0489fSTrond Myklebust 	if (!clp->cl_ownerstr_hashtbl)
1544d4f0489fSTrond Myklebust 		goto err_no_hashtbl;
1545d4f0489fSTrond Myklebust 	for (i = 0; i < OWNER_HASH_SIZE; i++)
1546d4f0489fSTrond Myklebust 		INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]);
15471da177e4SLinus Torvalds 	clp->cl_name.len = name.len;
15485694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_sessions);
15495694c93eSTrond Myklebust 	idr_init(&clp->cl_stateids);
15505694c93eSTrond Myklebust 	atomic_set(&clp->cl_refcount, 0);
15515694c93eSTrond Myklebust 	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
15525694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_idhash);
15535694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_openowners);
15545694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_delegations);
15555694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_lru);
15565694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_callbacks);
15575694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_revoked);
15585694c93eSTrond Myklebust 	spin_lock_init(&clp->cl_lock);
15595694c93eSTrond Myklebust 	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
15601da177e4SLinus Torvalds 	return clp;
1561d4f0489fSTrond Myklebust err_no_hashtbl:
1562d4f0489fSTrond Myklebust 	kfree(clp->cl_name.data);
1563d4f0489fSTrond Myklebust err_no_name:
1564d4f0489fSTrond Myklebust 	kfree(clp);
1565d4f0489fSTrond Myklebust 	return NULL;
15661da177e4SLinus Torvalds }
15671da177e4SLinus Torvalds 
15684dd86e15STrond Myklebust static void
15691da177e4SLinus Torvalds free_client(struct nfs4_client *clp)
15701da177e4SLinus Torvalds {
1571792c95ddSJ. Bruce Fields 	while (!list_empty(&clp->cl_sessions)) {
1572792c95ddSJ. Bruce Fields 		struct nfsd4_session *ses;
1573792c95ddSJ. Bruce Fields 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
1574792c95ddSJ. Bruce Fields 				se_perclnt);
1575792c95ddSJ. Bruce Fields 		list_del(&ses->se_perclnt);
157666b2b9b2SJ. Bruce Fields 		WARN_ON_ONCE(atomic_read(&ses->se_ref));
157766b2b9b2SJ. Bruce Fields 		free_session(ses);
1578792c95ddSJ. Bruce Fields 	}
15794cb57e30STrond Myklebust 	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
158003a4e1f6SJ. Bruce Fields 	free_svc_cred(&clp->cl_cred);
1581d4f0489fSTrond Myklebust 	kfree(clp->cl_ownerstr_hashtbl);
15821da177e4SLinus Torvalds 	kfree(clp->cl_name.data);
15832d32b29aSmajianpeng 	idr_destroy(&clp->cl_stateids);
15841da177e4SLinus Torvalds 	kfree(clp);
15851da177e4SLinus Torvalds }
15861da177e4SLinus Torvalds 
158784d38ac9SBenny Halevy /* must be called under the client_lock */
15884beb345bSTrond Myklebust static void
158984d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp)
159084d38ac9SBenny Halevy {
15914beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1592792c95ddSJ. Bruce Fields 	struct nfsd4_session *ses;
1593792c95ddSJ. Bruce Fields 
15940a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
15950a880a28STrond Myklebust 
15964beb345bSTrond Myklebust 	/* Mark the client as expired! */
15974beb345bSTrond Myklebust 	clp->cl_time = 0;
15984beb345bSTrond Myklebust 	/* Make it invisible */
15994beb345bSTrond Myklebust 	if (!list_empty(&clp->cl_idhash)) {
16004beb345bSTrond Myklebust 		list_del_init(&clp->cl_idhash);
16014beb345bSTrond Myklebust 		if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
16024beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
16034beb345bSTrond Myklebust 		else
16044beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
16054beb345bSTrond Myklebust 	}
16064beb345bSTrond Myklebust 	list_del_init(&clp->cl_lru);
16074c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1608792c95ddSJ. Bruce Fields 	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
1609792c95ddSJ. Bruce Fields 		list_del_init(&ses->se_hash);
16104c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
161184d38ac9SBenny Halevy }
161284d38ac9SBenny Halevy 
16131da177e4SLinus Torvalds static void
16144beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp)
16154beb345bSTrond Myklebust {
16164beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
16174beb345bSTrond Myklebust 
16184beb345bSTrond Myklebust 	spin_lock(&nn->client_lock);
16194beb345bSTrond Myklebust 	unhash_client_locked(clp);
16204beb345bSTrond Myklebust 	spin_unlock(&nn->client_lock);
16214beb345bSTrond Myklebust }
16224beb345bSTrond Myklebust 
162397403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp)
162497403d95SJeff Layton {
162597403d95SJeff Layton 	if (atomic_read(&clp->cl_refcount))
162697403d95SJeff Layton 		return nfserr_jukebox;
162797403d95SJeff Layton 	unhash_client_locked(clp);
162897403d95SJeff Layton 	return nfs_ok;
162997403d95SJeff Layton }
163097403d95SJeff Layton 
16314beb345bSTrond Myklebust static void
16324beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp)
16331da177e4SLinus Torvalds {
1634fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
16351da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
16361da177e4SLinus Torvalds 	struct list_head reaplist;
16371da177e4SLinus Torvalds 
16381da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
1639cdc97505SBenny Halevy 	spin_lock(&state_lock);
1640ea1da636SNeilBrown 	while (!list_empty(&clp->cl_delegations)) {
1641ea1da636SNeilBrown 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
164242690676SJeff Layton 		unhash_delegation_locked(dp);
164342690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
16441da177e4SLinus Torvalds 	}
1645cdc97505SBenny Halevy 	spin_unlock(&state_lock);
16461da177e4SLinus Torvalds 	while (!list_empty(&reaplist)) {
16471da177e4SLinus Torvalds 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
164842690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
1649afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
16506011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
16511da177e4SLinus Torvalds 	}
16522d4a532dSJeff Layton 	while (!list_empty(&clp->cl_revoked)) {
1653956c4feeSBenny Halevy 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
16542d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
16556011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
1656956c4feeSBenny Halevy 	}
1657ea1da636SNeilBrown 	while (!list_empty(&clp->cl_openowners)) {
1658fe0750e5SJ. Bruce Fields 		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
1659b5971afaSKinglong Mee 		nfs4_get_stateowner(&oo->oo_owner);
1660fe0750e5SJ. Bruce Fields 		release_openowner(oo);
16611da177e4SLinus Torvalds 	}
16626ff8da08SJ. Bruce Fields 	nfsd4_shutdown_callback(clp);
16632bf23875SJ. Bruce Fields 	if (clp->cl_cb_conn.cb_xprt)
16642bf23875SJ. Bruce Fields 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1665b12a05cbSJ. Bruce Fields 	free_client(clp);
16661da177e4SLinus Torvalds }
16671da177e4SLinus Torvalds 
16684beb345bSTrond Myklebust static void
16694beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp)
16704beb345bSTrond Myklebust {
16714beb345bSTrond Myklebust 	unhash_client(clp);
16724beb345bSTrond Myklebust 	__destroy_client(clp);
16734beb345bSTrond Myklebust }
16744beb345bSTrond Myklebust 
16750d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp)
16760d22f68fSJ. Bruce Fields {
16774beb345bSTrond Myklebust 	unhash_client(clp);
16780d22f68fSJ. Bruce Fields 	nfsd4_client_record_remove(clp);
16794beb345bSTrond Myklebust 	__destroy_client(clp);
16800d22f68fSJ. Bruce Fields }
16810d22f68fSJ. Bruce Fields 
168235bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
168335bba9a3SJ. Bruce Fields {
168435bba9a3SJ. Bruce Fields 	memcpy(target->cl_verifier.data, source->data,
168535bba9a3SJ. Bruce Fields 			sizeof(target->cl_verifier.data));
16861da177e4SLinus Torvalds }
16871da177e4SLinus Torvalds 
168835bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
168935bba9a3SJ. Bruce Fields {
16901da177e4SLinus Torvalds 	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
16911da177e4SLinus Torvalds 	target->cl_clientid.cl_id = source->cl_clientid.cl_id;
16921da177e4SLinus Torvalds }
16931da177e4SLinus Torvalds 
169403a4e1f6SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source)
169535bba9a3SJ. Bruce Fields {
169603a4e1f6SJ. Bruce Fields 	if (source->cr_principal) {
169703a4e1f6SJ. Bruce Fields 		target->cr_principal =
169803a4e1f6SJ. Bruce Fields 				kstrdup(source->cr_principal, GFP_KERNEL);
169903a4e1f6SJ. Bruce Fields 		if (target->cr_principal == NULL)
170003a4e1f6SJ. Bruce Fields 			return -ENOMEM;
170103a4e1f6SJ. Bruce Fields 	} else
170203a4e1f6SJ. Bruce Fields 		target->cr_principal = NULL;
1703d5497fc6SJ. Bruce Fields 	target->cr_flavor = source->cr_flavor;
17041da177e4SLinus Torvalds 	target->cr_uid = source->cr_uid;
17051da177e4SLinus Torvalds 	target->cr_gid = source->cr_gid;
17061da177e4SLinus Torvalds 	target->cr_group_info = source->cr_group_info;
17071da177e4SLinus Torvalds 	get_group_info(target->cr_group_info);
17080dc1531aSJ. Bruce Fields 	target->cr_gss_mech = source->cr_gss_mech;
17090dc1531aSJ. Bruce Fields 	if (source->cr_gss_mech)
17100dc1531aSJ. Bruce Fields 		gss_mech_get(source->cr_gss_mech);
171103a4e1f6SJ. Bruce Fields 	return 0;
17121da177e4SLinus Torvalds }
17131da177e4SLinus Torvalds 
1714ac55fdc4SJeff Layton static long long
1715ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
1716ac55fdc4SJeff Layton {
1717ac55fdc4SJeff Layton 	long long res;
1718ac55fdc4SJeff Layton 
1719ac55fdc4SJeff Layton 	res = o1->len - o2->len;
1720ac55fdc4SJeff Layton 	if (res)
1721ac55fdc4SJeff Layton 		return res;
1722ac55fdc4SJeff Layton 	return (long long)memcmp(o1->data, o2->data, o1->len);
1723ac55fdc4SJeff Layton }
1724ac55fdc4SJeff Layton 
172535bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2)
1726599e0a22SJ. Bruce Fields {
1727a55370a3SNeilBrown 	return 0 == memcmp(n1, n2, HEXDIR_LEN);
17281da177e4SLinus Torvalds }
17291da177e4SLinus Torvalds 
17301da177e4SLinus Torvalds static int
1731599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
1732599e0a22SJ. Bruce Fields {
1733599e0a22SJ. Bruce Fields 	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
17341da177e4SLinus Torvalds }
17351da177e4SLinus Torvalds 
17361da177e4SLinus Torvalds static int
1737599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2)
1738599e0a22SJ. Bruce Fields {
1739599e0a22SJ. Bruce Fields 	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
17401da177e4SLinus Torvalds }
17411da177e4SLinus Torvalds 
17428fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2)
17438fbba96eSJ. Bruce Fields {
17448fbba96eSJ. Bruce Fields 	int i;
17458fbba96eSJ. Bruce Fields 
17468fbba96eSJ. Bruce Fields 	if (g1->ngroups != g2->ngroups)
17478fbba96eSJ. Bruce Fields 		return false;
17488fbba96eSJ. Bruce Fields 	for (i=0; i<g1->ngroups; i++)
17496fab8779SEric W. Biederman 		if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i)))
17508fbba96eSJ. Bruce Fields 			return false;
17518fbba96eSJ. Bruce Fields 	return true;
17528fbba96eSJ. Bruce Fields }
17538fbba96eSJ. Bruce Fields 
175468eb3508SJ. Bruce Fields /*
175568eb3508SJ. Bruce Fields  * RFC 3530 language requires clid_inuse be returned when the
175668eb3508SJ. Bruce Fields  * "principal" associated with a requests differs from that previously
175768eb3508SJ. Bruce Fields  * used.  We use uid, gid's, and gss principal string as our best
175868eb3508SJ. Bruce Fields  * approximation.  We also don't want to allow non-gss use of a client
175968eb3508SJ. Bruce Fields  * established using gss: in theory cr_principal should catch that
176068eb3508SJ. Bruce Fields  * change, but in practice cr_principal can be null even in the gss case
176168eb3508SJ. Bruce Fields  * since gssd doesn't always pass down a principal string.
176268eb3508SJ. Bruce Fields  */
176368eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr)
176468eb3508SJ. Bruce Fields {
176568eb3508SJ. Bruce Fields 	/* Is cr_flavor one of the gss "pseudoflavors"?: */
176668eb3508SJ. Bruce Fields 	return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
176768eb3508SJ. Bruce Fields }
176868eb3508SJ. Bruce Fields 
176968eb3508SJ. Bruce Fields 
17705559b50aSVivek Trivedi static bool
1771599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
1772599e0a22SJ. Bruce Fields {
177368eb3508SJ. Bruce Fields 	if ((is_gss_cred(cr1) != is_gss_cred(cr2))
17746fab8779SEric W. Biederman 		|| (!uid_eq(cr1->cr_uid, cr2->cr_uid))
17756fab8779SEric W. Biederman 		|| (!gid_eq(cr1->cr_gid, cr2->cr_gid))
17768fbba96eSJ. Bruce Fields 		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
17778fbba96eSJ. Bruce Fields 		return false;
17788fbba96eSJ. Bruce Fields 	if (cr1->cr_principal == cr2->cr_principal)
17798fbba96eSJ. Bruce Fields 		return true;
17808fbba96eSJ. Bruce Fields 	if (!cr1->cr_principal || !cr2->cr_principal)
17818fbba96eSJ. Bruce Fields 		return false;
17825559b50aSVivek Trivedi 	return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
17831da177e4SLinus Torvalds }
17841da177e4SLinus Torvalds 
178557266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
178657266a6eSJ. Bruce Fields {
178757266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
178857266a6eSJ. Bruce Fields 	u32 service;
178957266a6eSJ. Bruce Fields 
1790c4720591SJ. Bruce Fields 	if (!cr->cr_gss_mech)
1791c4720591SJ. Bruce Fields 		return false;
179257266a6eSJ. Bruce Fields 	service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
179357266a6eSJ. Bruce Fields 	return service == RPC_GSS_SVC_INTEGRITY ||
179457266a6eSJ. Bruce Fields 	       service == RPC_GSS_SVC_PRIVACY;
179557266a6eSJ. Bruce Fields }
179657266a6eSJ. Bruce Fields 
179757266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
179857266a6eSJ. Bruce Fields {
179957266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
180057266a6eSJ. Bruce Fields 
180157266a6eSJ. Bruce Fields 	if (!cl->cl_mach_cred)
180257266a6eSJ. Bruce Fields 		return true;
180357266a6eSJ. Bruce Fields 	if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
180457266a6eSJ. Bruce Fields 		return false;
180557266a6eSJ. Bruce Fields 	if (!svc_rqst_integrity_protected(rqstp))
180657266a6eSJ. Bruce Fields 		return false;
180757266a6eSJ. Bruce Fields 	if (!cr->cr_principal)
180857266a6eSJ. Bruce Fields 		return false;
180957266a6eSJ. Bruce Fields 	return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
181057266a6eSJ. Bruce Fields }
181157266a6eSJ. Bruce Fields 
1812294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
1813deda2faaSJ. Bruce Fields {
1814ab4684d1SChuck Lever 	__be32 verf[2];
18151da177e4SLinus Torvalds 
1816f419992cSJeff Layton 	/*
1817f419992cSJeff Layton 	 * This is opaque to client, so no need to byte-swap. Use
1818f419992cSJeff Layton 	 * __force to keep sparse happy
1819f419992cSJeff Layton 	 */
1820f419992cSJeff Layton 	verf[0] = (__force __be32)get_seconds();
1821294ac32eSJeff Layton 	verf[1] = (__force __be32)nn->clientid_counter;
1822ab4684d1SChuck Lever 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
18231da177e4SLinus Torvalds }
18241da177e4SLinus Torvalds 
1825294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
1826294ac32eSJeff Layton {
1827294ac32eSJeff Layton 	clp->cl_clientid.cl_boot = nn->boot_time;
1828294ac32eSJeff Layton 	clp->cl_clientid.cl_id = nn->clientid_counter++;
1829294ac32eSJeff Layton 	gen_confirm(clp, nn);
1830294ac32eSJeff Layton }
1831294ac32eSJeff Layton 
18324770d722SJeff Layton static struct nfs4_stid *
18334770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
18344581d140SJ. Bruce Fields {
18353abdb607SJ. Bruce Fields 	struct nfs4_stid *ret;
18363abdb607SJ. Bruce Fields 
18373abdb607SJ. Bruce Fields 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
18383abdb607SJ. Bruce Fields 	if (!ret || !ret->sc_type)
18393abdb607SJ. Bruce Fields 		return NULL;
18403abdb607SJ. Bruce Fields 	return ret;
18414581d140SJ. Bruce Fields }
18424d71ab87SJ. Bruce Fields 
18434770d722SJeff Layton static struct nfs4_stid *
18444770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
1845f459e453SJ. Bruce Fields {
1846f459e453SJ. Bruce Fields 	struct nfs4_stid *s;
1847f459e453SJ. Bruce Fields 
18484770d722SJeff Layton 	spin_lock(&cl->cl_lock);
18494770d722SJeff Layton 	s = find_stateid_locked(cl, t);
18502d3f9668STrond Myklebust 	if (s != NULL) {
18512d3f9668STrond Myklebust 		if (typemask & s->sc_type)
18522d3f9668STrond Myklebust 			atomic_inc(&s->sc_count);
18532d3f9668STrond Myklebust 		else
18544770d722SJeff Layton 			s = NULL;
18552d3f9668STrond Myklebust 	}
18564770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
18574d71ab87SJ. Bruce Fields 	return s;
18584581d140SJ. Bruce Fields }
18594581d140SJ. Bruce Fields 
18602216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name,
1861b09333c4SRicardo Labiaga 		struct svc_rqst *rqstp, nfs4_verifier *verf)
1862b09333c4SRicardo Labiaga {
1863b09333c4SRicardo Labiaga 	struct nfs4_client *clp;
1864b09333c4SRicardo Labiaga 	struct sockaddr *sa = svc_addr(rqstp);
186503a4e1f6SJ. Bruce Fields 	int ret;
1866c212cecfSStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
1867b09333c4SRicardo Labiaga 
1868b09333c4SRicardo Labiaga 	clp = alloc_client(name);
1869b09333c4SRicardo Labiaga 	if (clp == NULL)
1870b09333c4SRicardo Labiaga 		return NULL;
1871b09333c4SRicardo Labiaga 
187203a4e1f6SJ. Bruce Fields 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
187303a4e1f6SJ. Bruce Fields 	if (ret) {
1874b09333c4SRicardo Labiaga 		free_client(clp);
1875b09333c4SRicardo Labiaga 		return NULL;
1876b09333c4SRicardo Labiaga 	}
187702e1215fSJeff Layton 	INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null);
187807cd4909SBenny Halevy 	clp->cl_time = get_seconds();
1879b09333c4SRicardo Labiaga 	clear_bit(0, &clp->cl_cb_slot_busy);
1880b09333c4SRicardo Labiaga 	copy_verf(clp, verf);
1881b09333c4SRicardo Labiaga 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
1882edd76786SJ. Bruce Fields 	clp->cl_cb_session = NULL;
1883c212cecfSStanislav Kinsbursky 	clp->net = net;
1884b09333c4SRicardo Labiaga 	return clp;
1885b09333c4SRicardo Labiaga }
1886b09333c4SRicardo Labiaga 
1887fd39ca9aSNeilBrown static void
1888ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
1889ac55fdc4SJeff Layton {
1890ac55fdc4SJeff Layton 	struct rb_node **new = &(root->rb_node), *parent = NULL;
1891ac55fdc4SJeff Layton 	struct nfs4_client *clp;
1892ac55fdc4SJeff Layton 
1893ac55fdc4SJeff Layton 	while (*new) {
1894ac55fdc4SJeff Layton 		clp = rb_entry(*new, struct nfs4_client, cl_namenode);
1895ac55fdc4SJeff Layton 		parent = *new;
1896ac55fdc4SJeff Layton 
1897ac55fdc4SJeff Layton 		if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
1898ac55fdc4SJeff Layton 			new = &((*new)->rb_left);
1899ac55fdc4SJeff Layton 		else
1900ac55fdc4SJeff Layton 			new = &((*new)->rb_right);
1901ac55fdc4SJeff Layton 	}
1902ac55fdc4SJeff Layton 
1903ac55fdc4SJeff Layton 	rb_link_node(&new_clp->cl_namenode, parent, new);
1904ac55fdc4SJeff Layton 	rb_insert_color(&new_clp->cl_namenode, root);
1905ac55fdc4SJeff Layton }
1906ac55fdc4SJeff Layton 
1907ac55fdc4SJeff Layton static struct nfs4_client *
1908ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
1909ac55fdc4SJeff Layton {
1910ac55fdc4SJeff Layton 	long long cmp;
1911ac55fdc4SJeff Layton 	struct rb_node *node = root->rb_node;
1912ac55fdc4SJeff Layton 	struct nfs4_client *clp;
1913ac55fdc4SJeff Layton 
1914ac55fdc4SJeff Layton 	while (node) {
1915ac55fdc4SJeff Layton 		clp = rb_entry(node, struct nfs4_client, cl_namenode);
1916ac55fdc4SJeff Layton 		cmp = compare_blob(&clp->cl_name, name);
1917ac55fdc4SJeff Layton 		if (cmp > 0)
1918ac55fdc4SJeff Layton 			node = node->rb_left;
1919ac55fdc4SJeff Layton 		else if (cmp < 0)
1920ac55fdc4SJeff Layton 			node = node->rb_right;
1921ac55fdc4SJeff Layton 		else
1922ac55fdc4SJeff Layton 			return clp;
1923ac55fdc4SJeff Layton 	}
1924ac55fdc4SJeff Layton 	return NULL;
1925ac55fdc4SJeff Layton }
1926ac55fdc4SJeff Layton 
1927ac55fdc4SJeff Layton static void
1928ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp)
19291da177e4SLinus Torvalds {
19301da177e4SLinus Torvalds 	unsigned int idhashval;
19310a7ec377SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
19321da177e4SLinus Torvalds 
19330a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
19340a880a28STrond Myklebust 
1935ac55fdc4SJeff Layton 	clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
1936a99454aaSStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
19371da177e4SLinus Torvalds 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
19380a7ec377SStanislav Kinsbursky 	list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
19393dbacee6STrond Myklebust 	renew_client_locked(clp);
19401da177e4SLinus Torvalds }
19411da177e4SLinus Torvalds 
1942fd39ca9aSNeilBrown static void
19431da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp)
19441da177e4SLinus Torvalds {
19451da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
19468daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
19471da177e4SLinus Torvalds 
19480a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
19490a880a28STrond Myklebust 
19501da177e4SLinus Torvalds 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
19518daae4dcSStanislav Kinsbursky 	list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
1952a99454aaSStanislav Kinsbursky 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
1953382a62e7SStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->conf_name_tree);
1954ac55fdc4SJeff Layton 	set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
19553dbacee6STrond Myklebust 	renew_client_locked(clp);
19561da177e4SLinus Torvalds }
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds static struct nfs4_client *
1959bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
19601da177e4SLinus Torvalds {
19611da177e4SLinus Torvalds 	struct nfs4_client *clp;
19621da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clid->cl_id);
19631da177e4SLinus Torvalds 
1964bfa85e83SJ. Bruce Fields 	list_for_each_entry(clp, &tbl[idhashval], cl_idhash) {
1965a50d2ad1SJ. Bruce Fields 		if (same_clid(&clp->cl_clientid, clid)) {
1966d15c077eSJ. Bruce Fields 			if ((bool)clp->cl_minorversion != sessions)
1967d15c077eSJ. Bruce Fields 				return NULL;
19683dbacee6STrond Myklebust 			renew_client_locked(clp);
19691da177e4SLinus Torvalds 			return clp;
19701da177e4SLinus Torvalds 		}
1971a50d2ad1SJ. Bruce Fields 	}
19721da177e4SLinus Torvalds 	return NULL;
19731da177e4SLinus Torvalds }
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds static struct nfs4_client *
1976bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
1977bfa85e83SJ. Bruce Fields {
1978bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->conf_id_hashtbl;
1979bfa85e83SJ. Bruce Fields 
19800a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1981bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
1982bfa85e83SJ. Bruce Fields }
1983bfa85e83SJ. Bruce Fields 
1984bfa85e83SJ. Bruce Fields static struct nfs4_client *
19850a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
19861da177e4SLinus Torvalds {
1987bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->unconf_id_hashtbl;
19881da177e4SLinus Torvalds 
19890a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1990bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
19911da177e4SLinus Torvalds }
19921da177e4SLinus Torvalds 
19936e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp)
1994a1bcecd2SAndy Adamson {
19956e5f15c9SJ. Bruce Fields 	return clp->cl_exchange_flags != 0;
1996a1bcecd2SAndy Adamson }
1997a1bcecd2SAndy Adamson 
199828ce6054SNeilBrown static struct nfs4_client *
1999382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
200028ce6054SNeilBrown {
20010a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2002382a62e7SStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->conf_name_tree);
200328ce6054SNeilBrown }
200428ce6054SNeilBrown 
200528ce6054SNeilBrown static struct nfs4_client *
2006a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
200728ce6054SNeilBrown {
20080a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2009a99454aaSStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->unconf_name_tree);
201028ce6054SNeilBrown }
201128ce6054SNeilBrown 
2012fd39ca9aSNeilBrown static void
20136f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
20141da177e4SLinus Torvalds {
201507263f1eSJ. Bruce Fields 	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
20166f3d772fSTakuma Umeya 	struct sockaddr	*sa = svc_addr(rqstp);
20176f3d772fSTakuma Umeya 	u32 scopeid = rpc_get_scope_id(sa);
20187077ecbaSJeff Layton 	unsigned short expected_family;
20191da177e4SLinus Torvalds 
20207077ecbaSJeff Layton 	/* Currently, we only support tcp and tcp6 for the callback channel */
20217077ecbaSJeff Layton 	if (se->se_callback_netid_len == 3 &&
20227077ecbaSJeff Layton 	    !memcmp(se->se_callback_netid_val, "tcp", 3))
20237077ecbaSJeff Layton 		expected_family = AF_INET;
20247077ecbaSJeff Layton 	else if (se->se_callback_netid_len == 4 &&
20257077ecbaSJeff Layton 		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
20267077ecbaSJeff Layton 		expected_family = AF_INET6;
20277077ecbaSJeff Layton 	else
20281da177e4SLinus Torvalds 		goto out_err;
20291da177e4SLinus Torvalds 
2030c212cecfSStanislav Kinsbursky 	conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val,
2031aa9a4ec7SJeff Layton 					    se->se_callback_addr_len,
203207263f1eSJ. Bruce Fields 					    (struct sockaddr *)&conn->cb_addr,
203307263f1eSJ. Bruce Fields 					    sizeof(conn->cb_addr));
2034aa9a4ec7SJeff Layton 
203507263f1eSJ. Bruce Fields 	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
20361da177e4SLinus Torvalds 		goto out_err;
2037aa9a4ec7SJeff Layton 
203807263f1eSJ. Bruce Fields 	if (conn->cb_addr.ss_family == AF_INET6)
203907263f1eSJ. Bruce Fields 		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
2040fbf4665fSJeff Layton 
204107263f1eSJ. Bruce Fields 	conn->cb_prog = se->se_callback_prog;
204207263f1eSJ. Bruce Fields 	conn->cb_ident = se->se_callback_ident;
2043849a1cf1SMi Jinlong 	memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
20441da177e4SLinus Torvalds 	return;
20451da177e4SLinus Torvalds out_err:
204607263f1eSJ. Bruce Fields 	conn->cb_addr.ss_family = AF_UNSPEC;
204707263f1eSJ. Bruce Fields 	conn->cb_addrlen = 0;
2048849823c5SNeil Brown 	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
20491da177e4SLinus Torvalds 		"will not receive delegations\n",
20501da177e4SLinus Torvalds 		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
20511da177e4SLinus Torvalds 
20521da177e4SLinus Torvalds 	return;
20531da177e4SLinus Torvalds }
20541da177e4SLinus Torvalds 
2055074fe897SAndy Adamson /*
2056067e1aceSJ. Bruce Fields  * Cache a reply. nfsd4_check_resp_size() has bounded the cache size.
2057074fe897SAndy Adamson  */
2058b607664eSTrond Myklebust static void
2059074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
2060074fe897SAndy Adamson {
2061f5236013SJ. Bruce Fields 	struct xdr_buf *buf = resp->xdr.buf;
2062557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2063557ce264SAndy Adamson 	unsigned int base;
2064074fe897SAndy Adamson 
2065557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2066074fe897SAndy Adamson 
2067557ce264SAndy Adamson 	slot->sl_opcnt = resp->opcnt;
2068557ce264SAndy Adamson 	slot->sl_status = resp->cstate.status;
2069bf864a31SAndy Adamson 
2070bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
2071bf864a31SAndy Adamson 	if (nfsd4_not_cached(resp)) {
2072557ce264SAndy Adamson 		slot->sl_datalen = 0;
2073bf864a31SAndy Adamson 		return;
2074bf864a31SAndy Adamson 	}
2075f5236013SJ. Bruce Fields 	base = resp->cstate.data_offset;
2076f5236013SJ. Bruce Fields 	slot->sl_datalen = buf->len - base;
2077f5236013SJ. Bruce Fields 	if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
2078557ce264SAndy Adamson 		WARN("%s: sessions DRC could not cache compound\n", __func__);
2079557ce264SAndy Adamson 	return;
2080074fe897SAndy Adamson }
2081074fe897SAndy Adamson 
2082074fe897SAndy Adamson /*
2083abfabf8cSAndy Adamson  * Encode the replay sequence operation from the slot values.
2084abfabf8cSAndy Adamson  * If cachethis is FALSE encode the uncached rep error on the next
2085abfabf8cSAndy Adamson  * operation which sets resp->p and increments resp->opcnt for
2086abfabf8cSAndy Adamson  * nfs4svc_encode_compoundres.
2087abfabf8cSAndy Adamson  *
2088074fe897SAndy Adamson  */
2089abfabf8cSAndy Adamson static __be32
2090abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
2091abfabf8cSAndy Adamson 			  struct nfsd4_compoundres *resp)
2092074fe897SAndy Adamson {
2093abfabf8cSAndy Adamson 	struct nfsd4_op *op;
2094abfabf8cSAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2095074fe897SAndy Adamson 
2096abfabf8cSAndy Adamson 	/* Encode the replayed sequence operation */
2097abfabf8cSAndy Adamson 	op = &args->ops[resp->opcnt - 1];
2098abfabf8cSAndy Adamson 	nfsd4_encode_operation(resp, op);
2099abfabf8cSAndy Adamson 
2100abfabf8cSAndy Adamson 	/* Return nfserr_retry_uncached_rep in next operation. */
210173e79482SJ. Bruce Fields 	if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
2102abfabf8cSAndy Adamson 		op = &args->ops[resp->opcnt++];
2103abfabf8cSAndy Adamson 		op->status = nfserr_retry_uncached_rep;
2104abfabf8cSAndy Adamson 		nfsd4_encode_operation(resp, op);
2105074fe897SAndy Adamson 	}
2106abfabf8cSAndy Adamson 	return op->status;
2107074fe897SAndy Adamson }
2108074fe897SAndy Adamson 
2109074fe897SAndy Adamson /*
2110557ce264SAndy Adamson  * The sequence operation is not cached because we can use the slot and
2111557ce264SAndy Adamson  * session values.
2112074fe897SAndy Adamson  */
21133ca2eb98SJ. Bruce Fields static __be32
2114bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
2115bf864a31SAndy Adamson 			 struct nfsd4_sequence *seq)
2116074fe897SAndy Adamson {
2117557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2118f5236013SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2119f5236013SJ. Bruce Fields 	__be32 *p;
2120074fe897SAndy Adamson 	__be32 status;
2121074fe897SAndy Adamson 
2122557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2123074fe897SAndy Adamson 
2124abfabf8cSAndy Adamson 	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
21250da7b19cSJ. Bruce Fields 	if (status)
2126abfabf8cSAndy Adamson 		return status;
2127074fe897SAndy Adamson 
2128f5236013SJ. Bruce Fields 	p = xdr_reserve_space(xdr, slot->sl_datalen);
2129f5236013SJ. Bruce Fields 	if (!p) {
2130f5236013SJ. Bruce Fields 		WARN_ON_ONCE(1);
2131f5236013SJ. Bruce Fields 		return nfserr_serverfault;
2132f5236013SJ. Bruce Fields 	}
2133f5236013SJ. Bruce Fields 	xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen);
2134f5236013SJ. Bruce Fields 	xdr_commit_encode(xdr);
2135074fe897SAndy Adamson 
2136557ce264SAndy Adamson 	resp->opcnt = slot->sl_opcnt;
2137f5236013SJ. Bruce Fields 	return slot->sl_status;
2138074fe897SAndy Adamson }
2139074fe897SAndy Adamson 
21400733d213SAndy Adamson /*
21410733d213SAndy Adamson  * Set the exchange_id flags returned by the server.
21420733d213SAndy Adamson  */
21430733d213SAndy Adamson static void
21440733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
21450733d213SAndy Adamson {
21460733d213SAndy Adamson 	/* pNFS is not supported */
21470733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
21480733d213SAndy Adamson 
21490733d213SAndy Adamson 	/* Referrals are supported, Migration is not. */
21500733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
21510733d213SAndy Adamson 
21520733d213SAndy Adamson 	/* set the wire flags to return to client. */
21530733d213SAndy Adamson 	clid->flags = new->cl_exchange_flags;
21540733d213SAndy Adamson }
21550733d213SAndy Adamson 
2156631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp)
2157631fc9eaSJ. Bruce Fields {
2158631fc9eaSJ. Bruce Fields 	/*
2159631fc9eaSJ. Bruce Fields 	 * Note clp->cl_openowners check isn't quite right: there's no
2160631fc9eaSJ. Bruce Fields 	 * need to count owners without stateid's.
2161631fc9eaSJ. Bruce Fields 	 *
2162631fc9eaSJ. Bruce Fields 	 * Also note we should probably be using this in 4.0 case too.
2163631fc9eaSJ. Bruce Fields 	 */
21646eccece9SJ. Bruce Fields 	return !list_empty(&clp->cl_openowners)
21656eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_delegations)
21666eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_sessions);
2167631fc9eaSJ. Bruce Fields }
2168631fc9eaSJ. Bruce Fields 
2169b37ad28bSAl Viro __be32
2170069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp,
2171069b6ad4SAndy Adamson 		  struct nfsd4_compound_state *cstate,
2172069b6ad4SAndy Adamson 		  struct nfsd4_exchange_id *exid)
2173069b6ad4SAndy Adamson {
21743dbacee6STrond Myklebust 	struct nfs4_client *conf, *new;
21753dbacee6STrond Myklebust 	struct nfs4_client *unconf = NULL;
217657b7b43bSJ. Bruce Fields 	__be32 status;
2177363168b4SJeff Layton 	char			addr_str[INET6_ADDRSTRLEN];
21780733d213SAndy Adamson 	nfs4_verifier		verf = exid->verifier;
2179363168b4SJeff Layton 	struct sockaddr		*sa = svc_addr(rqstp);
218083e08fd4SJ. Bruce Fields 	bool	update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A;
2181c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
21820733d213SAndy Adamson 
2183363168b4SJeff Layton 	rpc_ntop(sa, addr_str, sizeof(addr_str));
21840733d213SAndy Adamson 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
2185363168b4SJeff Layton 		"ip_addr=%s flags %x, spa_how %d\n",
21860733d213SAndy Adamson 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
2187363168b4SJeff Layton 		addr_str, exid->flags, exid->spa_how);
21880733d213SAndy Adamson 
2189a084daf5SJ. Bruce Fields 	if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
21900733d213SAndy Adamson 		return nfserr_inval;
21910733d213SAndy Adamson 
21920733d213SAndy Adamson 	switch (exid->spa_how) {
219357266a6eSJ. Bruce Fields 	case SP4_MACH_CRED:
219457266a6eSJ. Bruce Fields 		if (!svc_rqst_integrity_protected(rqstp))
219557266a6eSJ. Bruce Fields 			return nfserr_inval;
21960733d213SAndy Adamson 	case SP4_NONE:
21970733d213SAndy Adamson 		break;
2198063b0fb9SJ. Bruce Fields 	default:				/* checked by xdr code */
2199063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
22000733d213SAndy Adamson 	case SP4_SSV:
2201dd30333cSJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
22020733d213SAndy Adamson 	}
22030733d213SAndy Adamson 
22045cc40fd7STrond Myklebust 	new = create_client(exid->clname, rqstp, &verf);
22055cc40fd7STrond Myklebust 	if (new == NULL)
22065cc40fd7STrond Myklebust 		return nfserr_jukebox;
22075cc40fd7STrond Myklebust 
22082dbb269dSJ. Bruce Fields 	/* Cases below refer to rfc 5661 section 18.35.4: */
22093dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
2210382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&exid->clname, nn);
22110733d213SAndy Adamson 	if (conf) {
221283e08fd4SJ. Bruce Fields 		bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
221383e08fd4SJ. Bruce Fields 		bool verfs_match = same_verf(&verf, &conf->cl_verifier);
221483e08fd4SJ. Bruce Fields 
2215136e658dSJ. Bruce Fields 		if (update) {
2216136e658dSJ. Bruce Fields 			if (!clp_used_exchangeid(conf)) { /* buggy client */
22172dbb269dSJ. Bruce Fields 				status = nfserr_inval;
2218e203d506SJ. Bruce Fields 				goto out;
2219e203d506SJ. Bruce Fields 			}
222057266a6eSJ. Bruce Fields 			if (!mach_creds_match(conf, rqstp)) {
222157266a6eSJ. Bruce Fields 				status = nfserr_wrong_cred;
222257266a6eSJ. Bruce Fields 				goto out;
222357266a6eSJ. Bruce Fields 			}
22242dbb269dSJ. Bruce Fields 			if (!creds_match) { /* case 9 */
22250733d213SAndy Adamson 				status = nfserr_perm;
22260733d213SAndy Adamson 				goto out;
22270733d213SAndy Adamson 			}
22282dbb269dSJ. Bruce Fields 			if (!verfs_match) { /* case 8 */
22290733d213SAndy Adamson 				status = nfserr_not_same;
22300733d213SAndy Adamson 				goto out;
22310733d213SAndy Adamson 			}
2232136e658dSJ. Bruce Fields 			/* case 6 */
22330733d213SAndy Adamson 			exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
22340733d213SAndy Adamson 			goto out_copy;
22356ddbbbfeSMike Sager 		}
2236136e658dSJ. Bruce Fields 		if (!creds_match) { /* case 3 */
2237631fc9eaSJ. Bruce Fields 			if (client_has_state(conf)) {
2238136e658dSJ. Bruce Fields 				status = nfserr_clid_inuse;
2239136e658dSJ. Bruce Fields 				goto out;
2240136e658dSJ. Bruce Fields 			}
2241b9831b59SJ. Bruce Fields 			goto out_new;
2242631fc9eaSJ. Bruce Fields 		}
2243136e658dSJ. Bruce Fields 		if (verfs_match) { /* case 2 */
22440f1ba0efSJ. Bruce Fields 			conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
2245136e658dSJ. Bruce Fields 			goto out_copy;
2246136e658dSJ. Bruce Fields 		}
22472dbb269dSJ. Bruce Fields 		/* case 5, client reboot */
22483dbacee6STrond Myklebust 		conf = NULL;
22490733d213SAndy Adamson 		goto out_new;
22500733d213SAndy Adamson 	}
22516ddbbbfeSMike Sager 
22522dbb269dSJ. Bruce Fields 	if (update) { /* case 7 */
22530733d213SAndy Adamson 		status = nfserr_noent;
22540733d213SAndy Adamson 		goto out;
22550733d213SAndy Adamson 	}
22560733d213SAndy Adamson 
2257a99454aaSStanislav Kinsbursky 	unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
22582dbb269dSJ. Bruce Fields 	if (unconf) /* case 4, possible retry or client restart */
22593dbacee6STrond Myklebust 		unhash_client_locked(unconf);
22600733d213SAndy Adamson 
22612dbb269dSJ. Bruce Fields 	/* case 1 (normal case) */
22620733d213SAndy Adamson out_new:
2263fd699b8aSJeff Layton 	if (conf) {
2264fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
2265fd699b8aSJeff Layton 		if (status)
2266fd699b8aSJeff Layton 			goto out;
2267fd699b8aSJeff Layton 	}
22684f540e29SJ. Bruce Fields 	new->cl_minorversion = cstate->minorversion;
226957266a6eSJ. Bruce Fields 	new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
22700733d213SAndy Adamson 
2271c212cecfSStanislav Kinsbursky 	gen_clid(new, nn);
2272ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
22733dbacee6STrond Myklebust 	swap(new, conf);
22740733d213SAndy Adamson out_copy:
22755cc40fd7STrond Myklebust 	exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
22765cc40fd7STrond Myklebust 	exid->clientid.cl_id = conf->cl_clientid.cl_id;
22770733d213SAndy Adamson 
22785cc40fd7STrond Myklebust 	exid->seqid = conf->cl_cs_slot.sl_seqid + 1;
22795cc40fd7STrond Myklebust 	nfsd4_set_ex_flags(conf, exid);
22800733d213SAndy Adamson 
22810733d213SAndy Adamson 	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
22825cc40fd7STrond Myklebust 		conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags);
22830733d213SAndy Adamson 	status = nfs_ok;
22840733d213SAndy Adamson 
22850733d213SAndy Adamson out:
22863dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
22875cc40fd7STrond Myklebust 	if (new)
22883dbacee6STrond Myklebust 		expire_client(new);
22893dbacee6STrond Myklebust 	if (unconf)
22903dbacee6STrond Myklebust 		expire_client(unconf);
22910733d213SAndy Adamson 	return status;
2292069b6ad4SAndy Adamson }
2293069b6ad4SAndy Adamson 
229457b7b43bSJ. Bruce Fields static __be32
229588e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
2296b85d4c01SBenny Halevy {
229788e588d5SAndy Adamson 	dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
229888e588d5SAndy Adamson 		slot_seqid);
2299b85d4c01SBenny Halevy 
2300b85d4c01SBenny Halevy 	/* The slot is in use, and no response has been sent. */
230188e588d5SAndy Adamson 	if (slot_inuse) {
230288e588d5SAndy Adamson 		if (seqid == slot_seqid)
2303b85d4c01SBenny Halevy 			return nfserr_jukebox;
2304b85d4c01SBenny Halevy 		else
2305b85d4c01SBenny Halevy 			return nfserr_seq_misordered;
2306b85d4c01SBenny Halevy 	}
2307f6d82485SJ. Bruce Fields 	/* Note unsigned 32-bit arithmetic handles wraparound: */
230888e588d5SAndy Adamson 	if (likely(seqid == slot_seqid + 1))
2309b85d4c01SBenny Halevy 		return nfs_ok;
231088e588d5SAndy Adamson 	if (seqid == slot_seqid)
2311b85d4c01SBenny Halevy 		return nfserr_replay_cache;
2312b85d4c01SBenny Halevy 	return nfserr_seq_misordered;
2313b85d4c01SBenny Halevy }
2314b85d4c01SBenny Halevy 
231549557cc7SAndy Adamson /*
231649557cc7SAndy Adamson  * Cache the create session result into the create session single DRC
231749557cc7SAndy Adamson  * slot cache by saving the xdr structure. sl_seqid has been set.
231849557cc7SAndy Adamson  * Do this for solo or embedded create session operations.
231949557cc7SAndy Adamson  */
232049557cc7SAndy Adamson static void
232149557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
232257b7b43bSJ. Bruce Fields 			   struct nfsd4_clid_slot *slot, __be32 nfserr)
232349557cc7SAndy Adamson {
232449557cc7SAndy Adamson 	slot->sl_status = nfserr;
232549557cc7SAndy Adamson 	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
232649557cc7SAndy Adamson }
232749557cc7SAndy Adamson 
232849557cc7SAndy Adamson static __be32
232949557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
233049557cc7SAndy Adamson 			    struct nfsd4_clid_slot *slot)
233149557cc7SAndy Adamson {
233249557cc7SAndy Adamson 	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
233349557cc7SAndy Adamson 	return slot->sl_status;
233449557cc7SAndy Adamson }
233549557cc7SAndy Adamson 
23361b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
23371b74c25bSMi Jinlong 			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
23381b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
23391b74c25bSMi Jinlong 			3 +	/* version, opcount, opcode */ \
23401b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
23411b74c25bSMi Jinlong 				/* seqid, slotID, slotID, cache */ \
23421b74c25bSMi Jinlong 			4 ) * sizeof(__be32))
23431b74c25bSMi Jinlong 
23441b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
23451b74c25bSMi Jinlong 			2 +	/* verifier: AUTH_NULL, length 0 */\
23461b74c25bSMi Jinlong 			1 +	/* status */ \
23471b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
23481b74c25bSMi Jinlong 			3 +	/* opcount, opcode, opstatus*/ \
23491b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
23501b74c25bSMi Jinlong 				/* seqid, slotID, slotID, slotID, status */ \
23511b74c25bSMi Jinlong 			5 ) * sizeof(__be32))
23521b74c25bSMi Jinlong 
235355c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn)
23541b74c25bSMi Jinlong {
235555c760cfSJ. Bruce Fields 	u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
235655c760cfSJ. Bruce Fields 
2357373cd409SJ. Bruce Fields 	if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
2358373cd409SJ. Bruce Fields 		return nfserr_toosmall;
2359373cd409SJ. Bruce Fields 	if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
2360373cd409SJ. Bruce Fields 		return nfserr_toosmall;
236155c760cfSJ. Bruce Fields 	ca->headerpadsz = 0;
236255c760cfSJ. Bruce Fields 	ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
236355c760cfSJ. Bruce Fields 	ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
236455c760cfSJ. Bruce Fields 	ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
236555c760cfSJ. Bruce Fields 	ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
236655c760cfSJ. Bruce Fields 			NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
236755c760cfSJ. Bruce Fields 	ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
236855c760cfSJ. Bruce Fields 	/*
236955c760cfSJ. Bruce Fields 	 * Note decreasing slot size below client's request may make it
237055c760cfSJ. Bruce Fields 	 * difficult for client to function correctly, whereas
237155c760cfSJ. Bruce Fields 	 * decreasing the number of slots will (just?) affect
237255c760cfSJ. Bruce Fields 	 * performance.  When short on memory we therefore prefer to
237355c760cfSJ. Bruce Fields 	 * decrease number of slots instead of their size.  Clients that
237455c760cfSJ. Bruce Fields 	 * request larger slots than they need will get poor results:
237555c760cfSJ. Bruce Fields 	 */
237655c760cfSJ. Bruce Fields 	ca->maxreqs = nfsd4_get_drc_mem(ca);
237755c760cfSJ. Bruce Fields 	if (!ca->maxreqs)
237855c760cfSJ. Bruce Fields 		return nfserr_jukebox;
237955c760cfSJ. Bruce Fields 
2380373cd409SJ. Bruce Fields 	return nfs_ok;
23811b74c25bSMi Jinlong }
23821b74c25bSMi Jinlong 
23838a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ	((NFS4_enc_cb_recall_sz + \
23848a891633SKinglong Mee 				 RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32))
23858a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ	((NFS4_dec_cb_recall_sz + \
23868a891633SKinglong Mee 				 RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32))
23878a891633SKinglong Mee 
238806b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
238906b332a5SJ. Bruce Fields {
239006b332a5SJ. Bruce Fields 	ca->headerpadsz = 0;
239106b332a5SJ. Bruce Fields 
239206b332a5SJ. Bruce Fields 	/*
239306b332a5SJ. Bruce Fields 	 * These RPC_MAX_HEADER macros are overkill, especially since we
239406b332a5SJ. Bruce Fields 	 * don't even do gss on the backchannel yet.  But this is still
239506b332a5SJ. Bruce Fields 	 * less than 1k.  Tighten up this estimate in the unlikely event
239606b332a5SJ. Bruce Fields 	 * it turns out to be a problem for some client:
239706b332a5SJ. Bruce Fields 	 */
23988a891633SKinglong Mee 	if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ)
239906b332a5SJ. Bruce Fields 		return nfserr_toosmall;
24008a891633SKinglong Mee 	if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ)
240106b332a5SJ. Bruce Fields 		return nfserr_toosmall;
240206b332a5SJ. Bruce Fields 	ca->maxresp_cached = 0;
240306b332a5SJ. Bruce Fields 	if (ca->maxops < 2)
240406b332a5SJ. Bruce Fields 		return nfserr_toosmall;
240506b332a5SJ. Bruce Fields 
240606b332a5SJ. Bruce Fields 	return nfs_ok;
2407069b6ad4SAndy Adamson }
2408069b6ad4SAndy Adamson 
2409b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
2410b78724b7SJ. Bruce Fields {
2411b78724b7SJ. Bruce Fields 	switch (cbs->flavor) {
2412b78724b7SJ. Bruce Fields 	case RPC_AUTH_NULL:
2413b78724b7SJ. Bruce Fields 	case RPC_AUTH_UNIX:
2414b78724b7SJ. Bruce Fields 		return nfs_ok;
2415b78724b7SJ. Bruce Fields 	default:
2416b78724b7SJ. Bruce Fields 		/*
2417b78724b7SJ. Bruce Fields 		 * GSS case: the spec doesn't allow us to return this
2418b78724b7SJ. Bruce Fields 		 * error.  But it also doesn't allow us not to support
2419b78724b7SJ. Bruce Fields 		 * GSS.
2420b78724b7SJ. Bruce Fields 		 * I'd rather this fail hard than return some error the
2421b78724b7SJ. Bruce Fields 		 * client might think it can already handle:
2422b78724b7SJ. Bruce Fields 		 */
2423b78724b7SJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
2424b78724b7SJ. Bruce Fields 	}
2425b78724b7SJ. Bruce Fields }
2426b78724b7SJ. Bruce Fields 
2427069b6ad4SAndy Adamson __be32
2428069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp,
2429069b6ad4SAndy Adamson 		     struct nfsd4_compound_state *cstate,
2430069b6ad4SAndy Adamson 		     struct nfsd4_create_session *cr_ses)
2431069b6ad4SAndy Adamson {
2432363168b4SJeff Layton 	struct sockaddr *sa = svc_addr(rqstp);
2433ec6b5d7bSAndy Adamson 	struct nfs4_client *conf, *unconf;
2434d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
2435ac7c46f2SJ. Bruce Fields 	struct nfsd4_session *new;
243681f0b2a4SJ. Bruce Fields 	struct nfsd4_conn *conn;
243749557cc7SAndy Adamson 	struct nfsd4_clid_slot *cs_slot = NULL;
243857b7b43bSJ. Bruce Fields 	__be32 status = 0;
24398daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2440ec6b5d7bSAndy Adamson 
2441a62573dcSMi Jinlong 	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
2442a62573dcSMi Jinlong 		return nfserr_inval;
2443b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
2444b78724b7SJ. Bruce Fields 	if (status)
2445b78724b7SJ. Bruce Fields 		return status;
244655c760cfSJ. Bruce Fields 	status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
2447373cd409SJ. Bruce Fields 	if (status)
2448373cd409SJ. Bruce Fields 		return status;
244906b332a5SJ. Bruce Fields 	status = check_backchannel_attrs(&cr_ses->back_channel);
245006b332a5SJ. Bruce Fields 	if (status)
2451f403e450SKinglong Mee 		goto out_release_drc_mem;
245281f0b2a4SJ. Bruce Fields 	status = nfserr_jukebox;
245360810e54SKinglong Mee 	new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
245455c760cfSJ. Bruce Fields 	if (!new)
245555c760cfSJ. Bruce Fields 		goto out_release_drc_mem;
245681f0b2a4SJ. Bruce Fields 	conn = alloc_conn_from_crses(rqstp, cr_ses);
245781f0b2a4SJ. Bruce Fields 	if (!conn)
245881f0b2a4SJ. Bruce Fields 		goto out_free_session;
2459a62573dcSMi Jinlong 
2460d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
24610a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
24628daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
246378389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2464ec6b5d7bSAndy Adamson 
2465ec6b5d7bSAndy Adamson 	if (conf) {
246657266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
246757266a6eSJ. Bruce Fields 		if (!mach_creds_match(conf, rqstp))
246857266a6eSJ. Bruce Fields 			goto out_free_conn;
246949557cc7SAndy Adamson 		cs_slot = &conf->cl_cs_slot;
247049557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
247138eb76a5SAndy Adamson 		if (status == nfserr_replay_cache) {
247249557cc7SAndy Adamson 			status = nfsd4_replay_create_session(cr_ses, cs_slot);
247381f0b2a4SJ. Bruce Fields 			goto out_free_conn;
247449557cc7SAndy Adamson 		} else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
2475ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
247681f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2477ec6b5d7bSAndy Adamson 		}
2478ec6b5d7bSAndy Adamson 	} else if (unconf) {
2479ec6b5d7bSAndy Adamson 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
2480363168b4SJeff Layton 		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
2481ec6b5d7bSAndy Adamson 			status = nfserr_clid_inuse;
248281f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2483ec6b5d7bSAndy Adamson 		}
248457266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
248557266a6eSJ. Bruce Fields 		if (!mach_creds_match(unconf, rqstp))
248657266a6eSJ. Bruce Fields 			goto out_free_conn;
248749557cc7SAndy Adamson 		cs_slot = &unconf->cl_cs_slot;
248849557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
248938eb76a5SAndy Adamson 		if (status) {
249038eb76a5SAndy Adamson 			/* an unconfirmed replay returns misordered */
2491ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
249281f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2493ec6b5d7bSAndy Adamson 		}
2494382a62e7SStanislav Kinsbursky 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
2495221a6876SJ. Bruce Fields 		if (old) {
2496d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
24977abea1e8SJeff Layton 			if (status) {
24987abea1e8SJeff Layton 				old = NULL;
2499221a6876SJ. Bruce Fields 				goto out_free_conn;
2500221a6876SJ. Bruce Fields 			}
25017abea1e8SJeff Layton 		}
25028f9d3d3bSJ. Bruce Fields 		move_to_confirmed(unconf);
2503ec6b5d7bSAndy Adamson 		conf = unconf;
2504ec6b5d7bSAndy Adamson 	} else {
2505ec6b5d7bSAndy Adamson 		status = nfserr_stale_clientid;
250681f0b2a4SJ. Bruce Fields 		goto out_free_conn;
2507ec6b5d7bSAndy Adamson 	}
250881f0b2a4SJ. Bruce Fields 	status = nfs_ok;
25098323c3b2SJ. Bruce Fields 	/*
2510408b79bcSJ. Bruce Fields 	 * We do not support RDMA or persistent sessions
2511408b79bcSJ. Bruce Fields 	 */
2512408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_PERSIST;
2513408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_RDMA;
2514408b79bcSJ. Bruce Fields 
251581f0b2a4SJ. Bruce Fields 	init_session(rqstp, new, conf, cr_ses);
2516d20c11d8SJeff Layton 	nfsd4_get_session_locked(new);
251781f0b2a4SJ. Bruce Fields 
2518ac7c46f2SJ. Bruce Fields 	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
2519ec6b5d7bSAndy Adamson 	       NFS4_MAX_SESSIONID_LEN);
252086c3e16cSJ. Bruce Fields 	cs_slot->sl_seqid++;
252149557cc7SAndy Adamson 	cr_ses->seqid = cs_slot->sl_seqid;
2522ec6b5d7bSAndy Adamson 
2523d20c11d8SJeff Layton 	/* cache solo and embedded create sessions under the client_lock */
252449557cc7SAndy Adamson 	nfsd4_cache_create_session(cr_ses, cs_slot, status);
2525d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
2526d20c11d8SJeff Layton 	/* init connection and backchannel */
2527d20c11d8SJeff Layton 	nfsd4_init_conn(rqstp, conn, new);
2528d20c11d8SJeff Layton 	nfsd4_put_session(new);
2529d20c11d8SJeff Layton 	if (old)
2530d20c11d8SJeff Layton 		expire_client(old);
2531ec6b5d7bSAndy Adamson 	return status;
253281f0b2a4SJ. Bruce Fields out_free_conn:
2533d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
253481f0b2a4SJ. Bruce Fields 	free_conn(conn);
2535d20c11d8SJeff Layton 	if (old)
2536d20c11d8SJeff Layton 		expire_client(old);
253781f0b2a4SJ. Bruce Fields out_free_session:
253881f0b2a4SJ. Bruce Fields 	__free_session(new);
253955c760cfSJ. Bruce Fields out_release_drc_mem:
254055c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&cr_ses->fore_channel);
25411ca50792SJ. Bruce Fields 	return status;
2542069b6ad4SAndy Adamson }
2543069b6ad4SAndy Adamson 
25441d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir)
25451d1bc8f2SJ. Bruce Fields {
25461d1bc8f2SJ. Bruce Fields 	switch (*dir) {
25471d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE:
25481d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK:
25491d1bc8f2SJ. Bruce Fields 		return nfs_ok;
25501d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE_OR_BOTH:
25511d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK_OR_BOTH:
25521d1bc8f2SJ. Bruce Fields 		*dir = NFS4_CDFC4_BOTH;
25531d1bc8f2SJ. Bruce Fields 		return nfs_ok;
25541d1bc8f2SJ. Bruce Fields 	};
25551d1bc8f2SJ. Bruce Fields 	return nfserr_inval;
25561d1bc8f2SJ. Bruce Fields }
25571d1bc8f2SJ. Bruce Fields 
2558cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc)
2559cb73a9f4SJ. Bruce Fields {
2560cb73a9f4SJ. Bruce Fields 	struct nfsd4_session *session = cstate->session;
2561c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2562b78724b7SJ. Bruce Fields 	__be32 status;
2563cb73a9f4SJ. Bruce Fields 
2564b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
2565b78724b7SJ. Bruce Fields 	if (status)
2566b78724b7SJ. Bruce Fields 		return status;
2567c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2568cb73a9f4SJ. Bruce Fields 	session->se_cb_prog = bc->bc_cb_program;
2569cb73a9f4SJ. Bruce Fields 	session->se_cb_sec = bc->bc_cb_sec;
2570c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2571cb73a9f4SJ. Bruce Fields 
2572cb73a9f4SJ. Bruce Fields 	nfsd4_probe_callback(session->se_client);
2573cb73a9f4SJ. Bruce Fields 
2574cb73a9f4SJ. Bruce Fields 	return nfs_ok;
2575cb73a9f4SJ. Bruce Fields }
2576cb73a9f4SJ. Bruce Fields 
25771d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
25781d1bc8f2SJ. Bruce Fields 		     struct nfsd4_compound_state *cstate,
25791d1bc8f2SJ. Bruce Fields 		     struct nfsd4_bind_conn_to_session *bcts)
25801d1bc8f2SJ. Bruce Fields {
25811d1bc8f2SJ. Bruce Fields 	__be32 status;
25823ba63671SJ. Bruce Fields 	struct nfsd4_conn *conn;
25834f6e6c17SJ. Bruce Fields 	struct nfsd4_session *session;
2584d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2585d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
25861d1bc8f2SJ. Bruce Fields 
25871d1bc8f2SJ. Bruce Fields 	if (!nfsd4_last_compound_op(rqstp))
25881d1bc8f2SJ. Bruce Fields 		return nfserr_not_only_op;
2589c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2590d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status);
2591c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
25924f6e6c17SJ. Bruce Fields 	if (!session)
2593d4e19e70STrond Myklebust 		goto out_no_session;
259457266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
259557266a6eSJ. Bruce Fields 	if (!mach_creds_match(session->se_client, rqstp))
259657266a6eSJ. Bruce Fields 		goto out;
25971d1bc8f2SJ. Bruce Fields 	status = nfsd4_map_bcts_dir(&bcts->dir);
25983ba63671SJ. Bruce Fields 	if (status)
25994f6e6c17SJ. Bruce Fields 		goto out;
26003ba63671SJ. Bruce Fields 	conn = alloc_conn(rqstp, bcts->dir);
26014f6e6c17SJ. Bruce Fields 	status = nfserr_jukebox;
26023ba63671SJ. Bruce Fields 	if (!conn)
26034f6e6c17SJ. Bruce Fields 		goto out;
26044f6e6c17SJ. Bruce Fields 	nfsd4_init_conn(rqstp, conn, session);
26054f6e6c17SJ. Bruce Fields 	status = nfs_ok;
26064f6e6c17SJ. Bruce Fields out:
2607d4e19e70STrond Myklebust 	nfsd4_put_session(session);
2608d4e19e70STrond Myklebust out_no_session:
26094f6e6c17SJ. Bruce Fields 	return status;
26101d1bc8f2SJ. Bruce Fields }
26111d1bc8f2SJ. Bruce Fields 
26125d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
26135d4cec2fSJ. Bruce Fields {
26145d4cec2fSJ. Bruce Fields 	if (!session)
26155d4cec2fSJ. Bruce Fields 		return 0;
26165d4cec2fSJ. Bruce Fields 	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
26175d4cec2fSJ. Bruce Fields }
26185d4cec2fSJ. Bruce Fields 
2619069b6ad4SAndy Adamson __be32
2620069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r,
2621069b6ad4SAndy Adamson 		      struct nfsd4_compound_state *cstate,
2622069b6ad4SAndy Adamson 		      struct nfsd4_destroy_session *sessionid)
2623069b6ad4SAndy Adamson {
2624e10e0cfcSBenny Halevy 	struct nfsd4_session *ses;
2625abcdff09SJ. Bruce Fields 	__be32 status;
2626f0f51f5cSJ. Bruce Fields 	int ref_held_by_me = 0;
2627d4e19e70STrond Myklebust 	struct net *net = SVC_NET(r);
2628d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2629e10e0cfcSBenny Halevy 
2630abcdff09SJ. Bruce Fields 	status = nfserr_not_only_op;
26315d4cec2fSJ. Bruce Fields 	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
263257716355SJ. Bruce Fields 		if (!nfsd4_last_compound_op(r))
2633abcdff09SJ. Bruce Fields 			goto out;
2634f0f51f5cSJ. Bruce Fields 		ref_held_by_me++;
263557716355SJ. Bruce Fields 	}
2636e10e0cfcSBenny Halevy 	dump_sessionid(__func__, &sessionid->sessionid);
2637c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2638d4e19e70STrond Myklebust 	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status);
2639abcdff09SJ. Bruce Fields 	if (!ses)
2640abcdff09SJ. Bruce Fields 		goto out_client_lock;
264157266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
264257266a6eSJ. Bruce Fields 	if (!mach_creds_match(ses->se_client, r))
2643d4e19e70STrond Myklebust 		goto out_put_session;
2644f0f51f5cSJ. Bruce Fields 	status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
264566b2b9b2SJ. Bruce Fields 	if (status)
2646f0f51f5cSJ. Bruce Fields 		goto out_put_session;
2647e10e0cfcSBenny Halevy 	unhash_session(ses);
2648c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2649e10e0cfcSBenny Halevy 
265084f5f7ccSJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
265119cf5c02SJ. Bruce Fields 
2652c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2653e10e0cfcSBenny Halevy 	status = nfs_ok;
2654f0f51f5cSJ. Bruce Fields out_put_session:
2655d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
2656abcdff09SJ. Bruce Fields out_client_lock:
2657abcdff09SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
2658e10e0cfcSBenny Halevy out:
2659e10e0cfcSBenny Halevy 	return status;
2660069b6ad4SAndy Adamson }
2661069b6ad4SAndy Adamson 
2662a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
2663328ead28SJ. Bruce Fields {
2664328ead28SJ. Bruce Fields 	struct nfsd4_conn *c;
2665328ead28SJ. Bruce Fields 
2666328ead28SJ. Bruce Fields 	list_for_each_entry(c, &s->se_conns, cn_persession) {
2667a663bdd8SJ. Bruce Fields 		if (c->cn_xprt == xpt) {
2668328ead28SJ. Bruce Fields 			return c;
2669328ead28SJ. Bruce Fields 		}
2670328ead28SJ. Bruce Fields 	}
2671328ead28SJ. Bruce Fields 	return NULL;
2672328ead28SJ. Bruce Fields }
2673328ead28SJ. Bruce Fields 
267457266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
2675328ead28SJ. Bruce Fields {
2676328ead28SJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
2677a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *c;
267857266a6eSJ. Bruce Fields 	__be32 status = nfs_ok;
267921b75b01SJ. Bruce Fields 	int ret;
2680328ead28SJ. Bruce Fields 
2681328ead28SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
2682a663bdd8SJ. Bruce Fields 	c = __nfsd4_find_conn(new->cn_xprt, ses);
268357266a6eSJ. Bruce Fields 	if (c)
268457266a6eSJ. Bruce Fields 		goto out_free;
268557266a6eSJ. Bruce Fields 	status = nfserr_conn_not_bound_to_session;
268657266a6eSJ. Bruce Fields 	if (clp->cl_mach_cred)
268757266a6eSJ. Bruce Fields 		goto out_free;
2688328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(new, ses);
2689328ead28SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
269021b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(new);
269121b75b01SJ. Bruce Fields 	if (ret)
269221b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
269321b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&new->cn_xpt_user);
269457266a6eSJ. Bruce Fields 	return nfs_ok;
269557266a6eSJ. Bruce Fields out_free:
269657266a6eSJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
269757266a6eSJ. Bruce Fields 	free_conn(new);
269857266a6eSJ. Bruce Fields 	return status;
2699328ead28SJ. Bruce Fields }
2700328ead28SJ. Bruce Fields 
2701868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
2702868b89c3SMi Jinlong {
2703868b89c3SMi Jinlong 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
2704868b89c3SMi Jinlong 
2705868b89c3SMi Jinlong 	return args->opcnt > session->se_fchannel.maxops;
2706868b89c3SMi Jinlong }
2707868b89c3SMi Jinlong 
2708ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
2709ae82a8d0SMi Jinlong 				  struct nfsd4_session *session)
2710ae82a8d0SMi Jinlong {
2711ae82a8d0SMi Jinlong 	struct xdr_buf *xb = &rqstp->rq_arg;
2712ae82a8d0SMi Jinlong 
2713ae82a8d0SMi Jinlong 	return xb->len > session->se_fchannel.maxreq_sz;
2714ae82a8d0SMi Jinlong }
2715ae82a8d0SMi Jinlong 
2716069b6ad4SAndy Adamson __be32
2717b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp,
2718069b6ad4SAndy Adamson 	       struct nfsd4_compound_state *cstate,
2719069b6ad4SAndy Adamson 	       struct nfsd4_sequence *seq)
2720069b6ad4SAndy Adamson {
2721f9bb94c4SAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
272247ee5298SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2723b85d4c01SBenny Halevy 	struct nfsd4_session *session;
2724221a6876SJ. Bruce Fields 	struct nfs4_client *clp;
2725b85d4c01SBenny Halevy 	struct nfsd4_slot *slot;
2726a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *conn;
272757b7b43bSJ. Bruce Fields 	__be32 status;
272847ee5298SJ. Bruce Fields 	int buflen;
2729d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2730d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2731b85d4c01SBenny Halevy 
2732f9bb94c4SAndy Adamson 	if (resp->opcnt != 1)
2733f9bb94c4SAndy Adamson 		return nfserr_sequence_pos;
2734f9bb94c4SAndy Adamson 
2735a663bdd8SJ. Bruce Fields 	/*
2736a663bdd8SJ. Bruce Fields 	 * Will be either used or freed by nfsd4_sequence_check_conn
2737a663bdd8SJ. Bruce Fields 	 * below.
2738a663bdd8SJ. Bruce Fields 	 */
2739a663bdd8SJ. Bruce Fields 	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
2740a663bdd8SJ. Bruce Fields 	if (!conn)
2741a663bdd8SJ. Bruce Fields 		return nfserr_jukebox;
2742a663bdd8SJ. Bruce Fields 
2743c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2744d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status);
2745b85d4c01SBenny Halevy 	if (!session)
2746221a6876SJ. Bruce Fields 		goto out_no_session;
2747221a6876SJ. Bruce Fields 	clp = session->se_client;
2748b85d4c01SBenny Halevy 
2749868b89c3SMi Jinlong 	status = nfserr_too_many_ops;
2750868b89c3SMi Jinlong 	if (nfsd4_session_too_many_ops(rqstp, session))
275166b2b9b2SJ. Bruce Fields 		goto out_put_session;
2752868b89c3SMi Jinlong 
2753ae82a8d0SMi Jinlong 	status = nfserr_req_too_big;
2754ae82a8d0SMi Jinlong 	if (nfsd4_request_too_big(rqstp, session))
275566b2b9b2SJ. Bruce Fields 		goto out_put_session;
2756ae82a8d0SMi Jinlong 
2757b85d4c01SBenny Halevy 	status = nfserr_badslot;
27586c18ba9fSAlexandros Batsakis 	if (seq->slotid >= session->se_fchannel.maxreqs)
275966b2b9b2SJ. Bruce Fields 		goto out_put_session;
2760b85d4c01SBenny Halevy 
2761557ce264SAndy Adamson 	slot = session->se_slots[seq->slotid];
2762b85d4c01SBenny Halevy 	dprintk("%s: slotid %d\n", __func__, seq->slotid);
2763b85d4c01SBenny Halevy 
2764a8dfdaebSAndy Adamson 	/* We do not negotiate the number of slots yet, so set the
2765a8dfdaebSAndy Adamson 	 * maxslots to the session maxreqs which is used to encode
2766a8dfdaebSAndy Adamson 	 * sr_highest_slotid and the sr_target_slot id to maxslots */
2767a8dfdaebSAndy Adamson 	seq->maxslots = session->se_fchannel.maxreqs;
2768a8dfdaebSAndy Adamson 
276973e79482SJ. Bruce Fields 	status = check_slot_seqid(seq->seqid, slot->sl_seqid,
277073e79482SJ. Bruce Fields 					slot->sl_flags & NFSD4_SLOT_INUSE);
2771b85d4c01SBenny Halevy 	if (status == nfserr_replay_cache) {
2772bf5c43c8SJ. Bruce Fields 		status = nfserr_seq_misordered;
2773bf5c43c8SJ. Bruce Fields 		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
277466b2b9b2SJ. Bruce Fields 			goto out_put_session;
2775b85d4c01SBenny Halevy 		cstate->slot = slot;
2776b85d4c01SBenny Halevy 		cstate->session = session;
27774b24ca7dSJeff Layton 		cstate->clp = clp;
2778da3846a2SAndy Adamson 		/* Return the cached reply status and set cstate->status
2779557ce264SAndy Adamson 		 * for nfsd4_proc_compound processing */
2780bf864a31SAndy Adamson 		status = nfsd4_replay_cache_entry(resp, seq);
2781da3846a2SAndy Adamson 		cstate->status = nfserr_replay_cache;
2782aaf84eb9SBenny Halevy 		goto out;
2783b85d4c01SBenny Halevy 	}
2784b85d4c01SBenny Halevy 	if (status)
278566b2b9b2SJ. Bruce Fields 		goto out_put_session;
2786b85d4c01SBenny Halevy 
278757266a6eSJ. Bruce Fields 	status = nfsd4_sequence_check_conn(conn, session);
2788a663bdd8SJ. Bruce Fields 	conn = NULL;
278957266a6eSJ. Bruce Fields 	if (status)
279057266a6eSJ. Bruce Fields 		goto out_put_session;
2791328ead28SJ. Bruce Fields 
279247ee5298SJ. Bruce Fields 	buflen = (seq->cachethis) ?
279347ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_cached :
279447ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_sz;
279547ee5298SJ. Bruce Fields 	status = (seq->cachethis) ? nfserr_rep_too_big_to_cache :
279647ee5298SJ. Bruce Fields 				    nfserr_rep_too_big;
2797a5cddc88SJ. Bruce Fields 	if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack))
279847ee5298SJ. Bruce Fields 		goto out_put_session;
279932aaa62eSJ. Bruce Fields 	svc_reserve(rqstp, buflen);
280047ee5298SJ. Bruce Fields 
280147ee5298SJ. Bruce Fields 	status = nfs_ok;
2802b85d4c01SBenny Halevy 	/* Success! bump slot seqid */
2803b85d4c01SBenny Halevy 	slot->sl_seqid = seq->seqid;
2804bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INUSE;
280573e79482SJ. Bruce Fields 	if (seq->cachethis)
280673e79482SJ. Bruce Fields 		slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
2807bf5c43c8SJ. Bruce Fields 	else
2808bf5c43c8SJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
2809b85d4c01SBenny Halevy 
2810b85d4c01SBenny Halevy 	cstate->slot = slot;
2811b85d4c01SBenny Halevy 	cstate->session = session;
28124b24ca7dSJeff Layton 	cstate->clp = clp;
2813b85d4c01SBenny Halevy 
2814b85d4c01SBenny Halevy out:
28155423732aSBenny Halevy 	switch (clp->cl_cb_state) {
28165423732aSBenny Halevy 	case NFSD4_CB_DOWN:
2817fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
28185423732aSBenny Halevy 		break;
28195423732aSBenny Halevy 	case NFSD4_CB_FAULT:
2820fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
28215423732aSBenny Halevy 		break;
2822fc0c3dd1SBenny Halevy 	default:
2823fc0c3dd1SBenny Halevy 		seq->status_flags = 0;
28245423732aSBenny Halevy 	}
28253bd64a5bSJ. Bruce Fields 	if (!list_empty(&clp->cl_revoked))
28263bd64a5bSJ. Bruce Fields 		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
2827221a6876SJ. Bruce Fields out_no_session:
28283f42d2c4SKinglong Mee 	if (conn)
28293f42d2c4SKinglong Mee 		free_conn(conn);
2830c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2831b85d4c01SBenny Halevy 	return status;
283266b2b9b2SJ. Bruce Fields out_put_session:
2833d4e19e70STrond Myklebust 	nfsd4_put_session_locked(session);
2834221a6876SJ. Bruce Fields 	goto out_no_session;
2835069b6ad4SAndy Adamson }
2836069b6ad4SAndy Adamson 
2837b607664eSTrond Myklebust void
2838b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp)
2839b607664eSTrond Myklebust {
2840b607664eSTrond Myklebust 	struct nfsd4_compound_state *cs = &resp->cstate;
2841b607664eSTrond Myklebust 
2842b607664eSTrond Myklebust 	if (nfsd4_has_session(cs)) {
2843b607664eSTrond Myklebust 		if (cs->status != nfserr_replay_cache) {
2844b607664eSTrond Myklebust 			nfsd4_store_cache_entry(resp);
2845b607664eSTrond Myklebust 			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
2846b607664eSTrond Myklebust 		}
2847d4e19e70STrond Myklebust 		/* Drop session reference that was taken in nfsd4_sequence() */
2848b607664eSTrond Myklebust 		nfsd4_put_session(cs->session);
28494b24ca7dSJeff Layton 	} else if (cs->clp)
28504b24ca7dSJeff Layton 		put_client_renew(cs->clp);
2851b607664eSTrond Myklebust }
2852b607664eSTrond Myklebust 
2853345c2842SMi Jinlong __be32
2854345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
2855345c2842SMi Jinlong {
28566b10ad19STrond Myklebust 	struct nfs4_client *conf, *unconf;
28576b10ad19STrond Myklebust 	struct nfs4_client *clp = NULL;
285857b7b43bSJ. Bruce Fields 	__be32 status = 0;
28598daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2860345c2842SMi Jinlong 
28616b10ad19STrond Myklebust 	spin_lock(&nn->client_lock);
28620a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
28638daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&dc->clientid, true, nn);
286478389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2865345c2842SMi Jinlong 
2866345c2842SMi Jinlong 	if (conf) {
2867c0293b01SJ. Bruce Fields 		if (client_has_state(conf)) {
2868345c2842SMi Jinlong 			status = nfserr_clientid_busy;
2869345c2842SMi Jinlong 			goto out;
2870345c2842SMi Jinlong 		}
2871fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
2872fd699b8aSJeff Layton 		if (status)
2873fd699b8aSJeff Layton 			goto out;
28746b10ad19STrond Myklebust 		clp = conf;
2875345c2842SMi Jinlong 	} else if (unconf)
2876345c2842SMi Jinlong 		clp = unconf;
2877345c2842SMi Jinlong 	else {
2878345c2842SMi Jinlong 		status = nfserr_stale_clientid;
2879345c2842SMi Jinlong 		goto out;
2880345c2842SMi Jinlong 	}
288157266a6eSJ. Bruce Fields 	if (!mach_creds_match(clp, rqstp)) {
28826b10ad19STrond Myklebust 		clp = NULL;
288357266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
288457266a6eSJ. Bruce Fields 		goto out;
288557266a6eSJ. Bruce Fields 	}
28866b10ad19STrond Myklebust 	unhash_client_locked(clp);
2887345c2842SMi Jinlong out:
28886b10ad19STrond Myklebust 	spin_unlock(&nn->client_lock);
28896b10ad19STrond Myklebust 	if (clp)
28906b10ad19STrond Myklebust 		expire_client(clp);
2891345c2842SMi Jinlong 	return status;
2892345c2842SMi Jinlong }
2893345c2842SMi Jinlong 
2894069b6ad4SAndy Adamson __be32
28954dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
28964dc6ec00SJ. Bruce Fields {
289757b7b43bSJ. Bruce Fields 	__be32 status = 0;
2898bcecf1ccSMi Jinlong 
28994dc6ec00SJ. Bruce Fields 	if (rc->rca_one_fs) {
29004dc6ec00SJ. Bruce Fields 		if (!cstate->current_fh.fh_dentry)
29014dc6ec00SJ. Bruce Fields 			return nfserr_nofilehandle;
29024dc6ec00SJ. Bruce Fields 		/*
29034dc6ec00SJ. Bruce Fields 		 * We don't take advantage of the rca_one_fs case.
29044dc6ec00SJ. Bruce Fields 		 * That's OK, it's optional, we can safely ignore it.
29054dc6ec00SJ. Bruce Fields 		 */
29064dc6ec00SJ. Bruce Fields 		 return nfs_ok;
29074dc6ec00SJ. Bruce Fields 	}
2908bcecf1ccSMi Jinlong 
2909bcecf1ccSMi Jinlong 	status = nfserr_complete_already;
2910a52d726bSJeff Layton 	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
2911a52d726bSJeff Layton 			     &cstate->session->se_client->cl_flags))
2912bcecf1ccSMi Jinlong 		goto out;
2913bcecf1ccSMi Jinlong 
2914bcecf1ccSMi Jinlong 	status = nfserr_stale_clientid;
2915bcecf1ccSMi Jinlong 	if (is_client_expired(cstate->session->se_client))
29164dc6ec00SJ. Bruce Fields 		/*
29174dc6ec00SJ. Bruce Fields 		 * The following error isn't really legal.
29184dc6ec00SJ. Bruce Fields 		 * But we only get here if the client just explicitly
29194dc6ec00SJ. Bruce Fields 		 * destroyed the client.  Surely it no longer cares what
29204dc6ec00SJ. Bruce Fields 		 * error it gets back on an operation for the dead
29214dc6ec00SJ. Bruce Fields 		 * client.
29224dc6ec00SJ. Bruce Fields 		 */
2923bcecf1ccSMi Jinlong 		goto out;
2924bcecf1ccSMi Jinlong 
2925bcecf1ccSMi Jinlong 	status = nfs_ok;
29262a4317c5SJeff Layton 	nfsd4_client_record_create(cstate->session->se_client);
2927bcecf1ccSMi Jinlong out:
2928bcecf1ccSMi Jinlong 	return status;
29294dc6ec00SJ. Bruce Fields }
29304dc6ec00SJ. Bruce Fields 
29314dc6ec00SJ. Bruce Fields __be32
2932b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2933b591480bSJ.Bruce Fields 		  struct nfsd4_setclientid *setclid)
29341da177e4SLinus Torvalds {
2935a084daf5SJ. Bruce Fields 	struct xdr_netobj 	clname = setclid->se_name;
29361da177e4SLinus Torvalds 	nfs4_verifier		clverifier = setclid->se_verf;
29373dbacee6STrond Myklebust 	struct nfs4_client	*conf, *new;
29383dbacee6STrond Myklebust 	struct nfs4_client	*unconf = NULL;
2939b37ad28bSAl Viro 	__be32 			status;
2940c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2941a55370a3SNeilBrown 
29425cc40fd7STrond Myklebust 	new = create_client(clname, rqstp, &clverifier);
29435cc40fd7STrond Myklebust 	if (new == NULL)
29445cc40fd7STrond Myklebust 		return nfserr_jukebox;
294563db4632SJ. Bruce Fields 	/* Cases below refer to rfc 3530 section 14.2.33: */
29463dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
2947382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&clname, nn);
294828ce6054SNeilBrown 	if (conf) {
294963db4632SJ. Bruce Fields 		/* case 0: */
29501da177e4SLinus Torvalds 		status = nfserr_clid_inuse;
2951e203d506SJ. Bruce Fields 		if (clp_used_exchangeid(conf))
2952e203d506SJ. Bruce Fields 			goto out;
2953026722c2SJ. Bruce Fields 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
2954363168b4SJeff Layton 			char addr_str[INET6_ADDRSTRLEN];
2955363168b4SJeff Layton 			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
2956363168b4SJeff Layton 				 sizeof(addr_str));
2957026722c2SJ. Bruce Fields 			dprintk("NFSD: setclientid: string in use by client "
2958363168b4SJeff Layton 				"at %s\n", addr_str);
29591da177e4SLinus Torvalds 			goto out;
29601da177e4SLinus Torvalds 		}
29611da177e4SLinus Torvalds 	}
2962a99454aaSStanislav Kinsbursky 	unconf = find_unconfirmed_client_by_name(&clname, nn);
29631da177e4SLinus Torvalds 	if (unconf)
29643dbacee6STrond Myklebust 		unhash_client_locked(unconf);
296534b232bbSJ. Bruce Fields 	if (conf && same_verf(&conf->cl_verifier, &clverifier))
296663db4632SJ. Bruce Fields 		/* case 1: probable callback update */
29671da177e4SLinus Torvalds 		copy_clid(new, conf);
296834b232bbSJ. Bruce Fields 	else /* case 4 (new client) or cases 2, 3 (client reboot): */
2969c212cecfSStanislav Kinsbursky 		gen_clid(new, nn);
29708323c3b2SJ. Bruce Fields 	new->cl_minorversion = 0;
29716f3d772fSTakuma Umeya 	gen_callback(new, setclid, rqstp);
2972ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
29731da177e4SLinus Torvalds 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
29741da177e4SLinus Torvalds 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
29751da177e4SLinus Torvalds 	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
29765cc40fd7STrond Myklebust 	new = NULL;
29771da177e4SLinus Torvalds 	status = nfs_ok;
29781da177e4SLinus Torvalds out:
29793dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
29805cc40fd7STrond Myklebust 	if (new)
29815cc40fd7STrond Myklebust 		free_client(new);
29823dbacee6STrond Myklebust 	if (unconf)
29833dbacee6STrond Myklebust 		expire_client(unconf);
29841da177e4SLinus Torvalds 	return status;
29851da177e4SLinus Torvalds }
29861da177e4SLinus Torvalds 
29871da177e4SLinus Torvalds 
2988b37ad28bSAl Viro __be32
2989b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2990b591480bSJ.Bruce Fields 			 struct nfsd4_compound_state *cstate,
2991b591480bSJ.Bruce Fields 			 struct nfsd4_setclientid_confirm *setclientid_confirm)
29921da177e4SLinus Torvalds {
299321ab45a4SNeilBrown 	struct nfs4_client *conf, *unconf;
2994d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
29951da177e4SLinus Torvalds 	nfs4_verifier confirm = setclientid_confirm->sc_confirm;
29961da177e4SLinus Torvalds 	clientid_t * clid = &setclientid_confirm->sc_clientid;
2997b37ad28bSAl Viro 	__be32 status;
29987f2210faSStanislav Kinsbursky 	struct nfsd_net	*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
29991da177e4SLinus Torvalds 
30002c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(clid, nn))
30011da177e4SLinus Torvalds 		return nfserr_stale_clientid;
300221ab45a4SNeilBrown 
3003d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
30048daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(clid, false, nn);
30050a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(clid, false, nn);
3006a186e767SJ. Bruce Fields 	/*
30078695b90aSJ. Bruce Fields 	 * We try hard to give out unique clientid's, so if we get an
30088695b90aSJ. Bruce Fields 	 * attempt to confirm the same clientid with a different cred,
30098695b90aSJ. Bruce Fields 	 * there's a bug somewhere.  Let's charitably assume it's our
30108695b90aSJ. Bruce Fields 	 * bug.
3011a186e767SJ. Bruce Fields 	 */
30128695b90aSJ. Bruce Fields 	status = nfserr_serverfault;
30138695b90aSJ. Bruce Fields 	if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred))
30148695b90aSJ. Bruce Fields 		goto out;
30158695b90aSJ. Bruce Fields 	if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred))
30168695b90aSJ. Bruce Fields 		goto out;
301763db4632SJ. Bruce Fields 	/* cases below refer to rfc 3530 section 14.2.34: */
301890d700b7SJ. Bruce Fields 	if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) {
301990d700b7SJ. Bruce Fields 		if (conf && !unconf) /* case 2: probable retransmit */
302090d700b7SJ. Bruce Fields 			status = nfs_ok;
302190d700b7SJ. Bruce Fields 		else /* case 4: client hasn't noticed we rebooted yet? */
302290d700b7SJ. Bruce Fields 			status = nfserr_stale_clientid;
302390d700b7SJ. Bruce Fields 		goto out;
302490d700b7SJ. Bruce Fields 	}
302590d700b7SJ. Bruce Fields 	status = nfs_ok;
302690d700b7SJ. Bruce Fields 	if (conf) { /* case 1: callback update */
3027d20c11d8SJeff Layton 		old = unconf;
3028d20c11d8SJeff Layton 		unhash_client_locked(old);
30295a3c9d71SJ. Bruce Fields 		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
303090d700b7SJ. Bruce Fields 	} else { /* case 3: normal case; new or rebooted client */
3031d20c11d8SJeff Layton 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
3032d20c11d8SJeff Layton 		if (old) {
3033d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
30347abea1e8SJeff Layton 			if (status) {
30357abea1e8SJeff Layton 				old = NULL;
3036221a6876SJ. Bruce Fields 				goto out;
3037221a6876SJ. Bruce Fields 			}
30387abea1e8SJeff Layton 		}
30391da177e4SLinus Torvalds 		move_to_confirmed(unconf);
3040d20c11d8SJeff Layton 		conf = unconf;
304108e8987cSNeilBrown 	}
3042d20c11d8SJeff Layton 	get_client_locked(conf);
3043d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3044d20c11d8SJeff Layton 	nfsd4_probe_callback(conf);
3045d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
3046d20c11d8SJeff Layton 	put_client_renew_locked(conf);
30471da177e4SLinus Torvalds out:
3048d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3049d20c11d8SJeff Layton 	if (old)
3050d20c11d8SJeff Layton 		expire_client(old);
30511da177e4SLinus Torvalds 	return status;
30521da177e4SLinus Torvalds }
30531da177e4SLinus Torvalds 
305432513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void)
30551da177e4SLinus Torvalds {
305632513b40SJ. Bruce Fields 	return kmem_cache_alloc(file_slab, GFP_KERNEL);
305732513b40SJ. Bruce Fields }
305832513b40SJ. Bruce Fields 
305932513b40SJ. Bruce Fields /* OPEN Share state helper functions */
3060f9c00c3aSJeff Layton static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh)
306132513b40SJ. Bruce Fields {
3062ca943217STrond Myklebust 	unsigned int hashval = file_hashval(fh);
30631da177e4SLinus Torvalds 
3064950e0118STrond Myklebust 	lockdep_assert_held(&state_lock);
3065950e0118STrond Myklebust 
30668b671b80SJ. Bruce Fields 	atomic_set(&fp->fi_ref, 1);
30671d31a253STrond Myklebust 	spin_lock_init(&fp->fi_lock);
30688beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_stateids);
30698beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_delegations);
3070e2cf80d7STrond Myklebust 	fh_copy_shallow(&fp->fi_fhandle, fh);
307147f9940cSMeelap Shah 	fp->fi_had_conflict = false;
3072acfdf5c3SJ. Bruce Fields 	fp->fi_lease = NULL;
3073baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
3074f9d7562fSJ. Bruce Fields 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
3075f9d7562fSJ. Bruce Fields 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
307689876f8cSJeff Layton 	hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
30771da177e4SLinus Torvalds }
30781da177e4SLinus Torvalds 
3079e8ff2a84SJ. Bruce Fields void
3080e60d4398SNeilBrown nfsd4_free_slabs(void)
3081e60d4398SNeilBrown {
3082abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3083abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3084abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3085abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3086abf1135bSChristoph Hellwig 	kmem_cache_destroy(deleg_slab);
3087e60d4398SNeilBrown }
30881da177e4SLinus Torvalds 
308972083396SBryan Schumaker int
30901da177e4SLinus Torvalds nfsd4_init_slabs(void)
30911da177e4SLinus Torvalds {
3092fe0750e5SJ. Bruce Fields 	openowner_slab = kmem_cache_create("nfsd4_openowners",
3093fe0750e5SJ. Bruce Fields 			sizeof(struct nfs4_openowner), 0, 0, NULL);
3094fe0750e5SJ. Bruce Fields 	if (openowner_slab == NULL)
3095abf1135bSChristoph Hellwig 		goto out;
3096fe0750e5SJ. Bruce Fields 	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
30973c40794bSYanchuan Nian 			sizeof(struct nfs4_lockowner), 0, 0, NULL);
3098fe0750e5SJ. Bruce Fields 	if (lockowner_slab == NULL)
3099abf1135bSChristoph Hellwig 		goto out_free_openowner_slab;
3100e60d4398SNeilBrown 	file_slab = kmem_cache_create("nfsd4_files",
310120c2df83SPaul Mundt 			sizeof(struct nfs4_file), 0, 0, NULL);
3102e60d4398SNeilBrown 	if (file_slab == NULL)
3103abf1135bSChristoph Hellwig 		goto out_free_lockowner_slab;
31045ac049acSNeilBrown 	stateid_slab = kmem_cache_create("nfsd4_stateids",
3105dcef0413SJ. Bruce Fields 			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
31065ac049acSNeilBrown 	if (stateid_slab == NULL)
3107abf1135bSChristoph Hellwig 		goto out_free_file_slab;
31085b2d21c1SNeilBrown 	deleg_slab = kmem_cache_create("nfsd4_delegations",
310920c2df83SPaul Mundt 			sizeof(struct nfs4_delegation), 0, 0, NULL);
31105b2d21c1SNeilBrown 	if (deleg_slab == NULL)
3111abf1135bSChristoph Hellwig 		goto out_free_stateid_slab;
3112e60d4398SNeilBrown 	return 0;
3113abf1135bSChristoph Hellwig 
3114abf1135bSChristoph Hellwig out_free_stateid_slab:
3115abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3116abf1135bSChristoph Hellwig out_free_file_slab:
3117abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3118abf1135bSChristoph Hellwig out_free_lockowner_slab:
3119abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3120abf1135bSChristoph Hellwig out_free_openowner_slab:
3121abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3122abf1135bSChristoph Hellwig out:
31231da177e4SLinus Torvalds 	dprintk("nfsd4: out of memory while initializing nfsv4\n");
31241da177e4SLinus Torvalds 	return -ENOMEM;
31251da177e4SLinus Torvalds }
31261da177e4SLinus Torvalds 
3127ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp)
3128ff194bd9SJ. Bruce Fields {
3129ff194bd9SJ. Bruce Fields 	rp->rp_status = nfserr_serverfault;
3130ff194bd9SJ. Bruce Fields 	rp->rp_buflen = 0;
3131ff194bd9SJ. Bruce Fields 	rp->rp_buf = rp->rp_ibuf;
313258fb12e6SJeff Layton 	mutex_init(&rp->rp_mutex);
313358fb12e6SJeff Layton }
313458fb12e6SJeff Layton 
313558fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
313658fb12e6SJeff Layton 		struct nfs4_stateowner *so)
313758fb12e6SJeff Layton {
313858fb12e6SJeff Layton 	if (!nfsd4_has_session(cstate)) {
313958fb12e6SJeff Layton 		mutex_lock(&so->so_replay.rp_mutex);
3140b5971afaSKinglong Mee 		cstate->replay_owner = nfs4_get_stateowner(so);
314158fb12e6SJeff Layton 	}
314258fb12e6SJeff Layton }
314358fb12e6SJeff Layton 
314458fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate)
314558fb12e6SJeff Layton {
314658fb12e6SJeff Layton 	struct nfs4_stateowner *so = cstate->replay_owner;
314758fb12e6SJeff Layton 
314858fb12e6SJeff Layton 	if (so != NULL) {
314958fb12e6SJeff Layton 		cstate->replay_owner = NULL;
315058fb12e6SJeff Layton 		mutex_unlock(&so->so_replay.rp_mutex);
315158fb12e6SJeff Layton 		nfs4_put_stateowner(so);
315258fb12e6SJeff Layton 	}
3153ff194bd9SJ. Bruce Fields }
3154ff194bd9SJ. Bruce Fields 
3155fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
31561da177e4SLinus Torvalds {
31571da177e4SLinus Torvalds 	struct nfs4_stateowner *sop;
31581da177e4SLinus Torvalds 
3159fe0750e5SJ. Bruce Fields 	sop = kmem_cache_alloc(slab, GFP_KERNEL);
3160ff194bd9SJ. Bruce Fields 	if (!sop)
3161ff194bd9SJ. Bruce Fields 		return NULL;
3162ff194bd9SJ. Bruce Fields 
3163ff194bd9SJ. Bruce Fields 	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
3164ff194bd9SJ. Bruce Fields 	if (!sop->so_owner.data) {
3165fe0750e5SJ. Bruce Fields 		kmem_cache_free(slab, sop);
3166ff194bd9SJ. Bruce Fields 		return NULL;
3167ff194bd9SJ. Bruce Fields 	}
31681da177e4SLinus Torvalds 	sop->so_owner.len = owner->len;
3169ff194bd9SJ. Bruce Fields 
3170ff194bd9SJ. Bruce Fields 	INIT_LIST_HEAD(&sop->so_stateids);
3171ff194bd9SJ. Bruce Fields 	sop->so_client = clp;
3172ff194bd9SJ. Bruce Fields 	init_nfs4_replay(&sop->so_replay);
31736b180f0bSJeff Layton 	atomic_set(&sop->so_count, 1);
31741da177e4SLinus Torvalds 	return sop;
31751da177e4SLinus Torvalds }
3176ff194bd9SJ. Bruce Fields 
3177fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
3178ff194bd9SJ. Bruce Fields {
3179d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
31809b531137SStanislav Kinsbursky 
3181d4f0489fSTrond Myklebust 	list_add(&oo->oo_owner.so_strhash,
3182d4f0489fSTrond Myklebust 		 &clp->cl_ownerstr_hashtbl[strhashval]);
3183fe0750e5SJ. Bruce Fields 	list_add(&oo->oo_perclient, &clp->cl_openowners);
31841da177e4SLinus Torvalds }
31851da177e4SLinus Torvalds 
31868f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
31878f4b54c5SJeff Layton {
3188d4f0489fSTrond Myklebust 	unhash_openowner_locked(openowner(so));
31898f4b54c5SJeff Layton }
31908f4b54c5SJeff Layton 
31916b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so)
31926b180f0bSJeff Layton {
31936b180f0bSJeff Layton 	struct nfs4_openowner *oo = openowner(so);
31946b180f0bSJeff Layton 
31956b180f0bSJeff Layton 	kmem_cache_free(openowner_slab, oo);
31966b180f0bSJeff Layton }
31976b180f0bSJeff Layton 
31986b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = {
31998f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_openowner,
32006b180f0bSJeff Layton 	.so_free =	nfs4_free_openowner,
32016b180f0bSJeff Layton };
32026b180f0bSJeff Layton 
3203fe0750e5SJ. Bruce Fields static struct nfs4_openowner *
320413d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3205db24b3b4SJeff Layton 			   struct nfsd4_compound_state *cstate)
3206db24b3b4SJeff Layton {
320713d6f66bSTrond Myklebust 	struct nfs4_client *clp = cstate->clp;
32087ffb5880STrond Myklebust 	struct nfs4_openowner *oo, *ret;
32091da177e4SLinus Torvalds 
3210fe0750e5SJ. Bruce Fields 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
3211fe0750e5SJ. Bruce Fields 	if (!oo)
32121da177e4SLinus Torvalds 		return NULL;
32136b180f0bSJeff Layton 	oo->oo_owner.so_ops = &openowner_ops;
3214fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_is_open_owner = 1;
3215fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_seqid = open->op_seqid;
3216d3134b10SJeff Layton 	oo->oo_flags = 0;
3217db24b3b4SJeff Layton 	if (nfsd4_has_session(cstate))
3218db24b3b4SJeff Layton 		oo->oo_flags |= NFS4_OO_CONFIRMED;
3219fe0750e5SJ. Bruce Fields 	oo->oo_time = 0;
322038c387b5SJ. Bruce Fields 	oo->oo_last_closed_stid = NULL;
3221fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&oo->oo_close_lru);
3222d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
3223d4f0489fSTrond Myklebust 	ret = find_openstateowner_str_locked(strhashval, open, clp);
32247ffb5880STrond Myklebust 	if (ret == NULL) {
3225fe0750e5SJ. Bruce Fields 		hash_openowner(oo, clp, strhashval);
32267ffb5880STrond Myklebust 		ret = oo;
32277ffb5880STrond Myklebust 	} else
32287ffb5880STrond Myklebust 		nfs4_free_openowner(&oo->oo_owner);
3229d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
3230fe0750e5SJ. Bruce Fields 	return oo;
32311da177e4SLinus Torvalds }
32321da177e4SLinus Torvalds 
3233996e0938SJ. Bruce Fields static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
3234fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = open->op_openowner;
32351da177e4SLinus Torvalds 
3236d6f2bc5dSTrond Myklebust 	atomic_inc(&stp->st_stid.sc_count);
32373abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_OPEN_STID;
32383c87b9b7STrond Myklebust 	INIT_LIST_HEAD(&stp->st_locks);
3239b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
324013cd2184SNeilBrown 	get_nfs4_file(fp);
324111b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
32421da177e4SLinus Torvalds 	stp->st_access_bmap = 0;
32431da177e4SLinus Torvalds 	stp->st_deny_bmap = 0;
32444c4cd222SNeilBrown 	stp->st_openstp = NULL;
32451c755dc1SJeff Layton 	spin_lock(&oo->oo_owner.so_client->cl_lock);
32461c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
32471d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
32481d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
32491d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
32501c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
32511da177e4SLinus Torvalds }
32521da177e4SLinus Torvalds 
3253d3134b10SJeff Layton /*
3254d3134b10SJeff Layton  * In the 4.0 case we need to keep the owners around a little while to handle
3255d3134b10SJeff Layton  * CLOSE replay. We still do need to release any file access that is held by
3256d3134b10SJeff Layton  * them before returning however.
3257d3134b10SJeff Layton  */
32581da177e4SLinus Torvalds static void
3259d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
32601da177e4SLinus Torvalds {
3261217526e7SJeff Layton 	struct nfs4_ol_stateid *last;
3262d3134b10SJeff Layton 	struct nfs4_openowner *oo = openowner(s->st_stateowner);
3263d3134b10SJeff Layton 	struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net,
3264d3134b10SJeff Layton 						nfsd_net_id);
326573758fedSStanislav Kinsbursky 
3266fe0750e5SJ. Bruce Fields 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
32671da177e4SLinus Torvalds 
3268b401be22SJeff Layton 	/*
3269b401be22SJeff Layton 	 * We know that we hold one reference via nfsd4_close, and another
3270b401be22SJeff Layton 	 * "persistent" reference for the client. If the refcount is higher
3271b401be22SJeff Layton 	 * than 2, then there are still calls in progress that are using this
3272b401be22SJeff Layton 	 * stateid. We can't put the sc_file reference until they are finished.
3273b401be22SJeff Layton 	 * Wait for the refcount to drop to 2. Since it has been unhashed,
3274b401be22SJeff Layton 	 * there should be no danger of the refcount going back up again at
3275b401be22SJeff Layton 	 * this point.
3276b401be22SJeff Layton 	 */
3277b401be22SJeff Layton 	wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2);
3278b401be22SJeff Layton 
3279d3134b10SJeff Layton 	release_all_access(s);
3280d3134b10SJeff Layton 	if (s->st_stid.sc_file) {
3281d3134b10SJeff Layton 		put_nfs4_file(s->st_stid.sc_file);
3282d3134b10SJeff Layton 		s->st_stid.sc_file = NULL;
3283d3134b10SJeff Layton 	}
3284217526e7SJeff Layton 
3285217526e7SJeff Layton 	spin_lock(&nn->client_lock);
3286217526e7SJeff Layton 	last = oo->oo_last_closed_stid;
3287d3134b10SJeff Layton 	oo->oo_last_closed_stid = s;
328873758fedSStanislav Kinsbursky 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
3289fe0750e5SJ. Bruce Fields 	oo->oo_time = get_seconds();
3290217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
3291217526e7SJeff Layton 	if (last)
3292217526e7SJeff Layton 		nfs4_put_stid(&last->st_stid);
32931da177e4SLinus Torvalds }
32941da177e4SLinus Torvalds 
32951da177e4SLinus Torvalds /* search file_hashtbl[] for file */
32961da177e4SLinus Torvalds static struct nfs4_file *
3297ca943217STrond Myklebust find_file_locked(struct knfsd_fh *fh)
32981da177e4SLinus Torvalds {
3299ca943217STrond Myklebust 	unsigned int hashval = file_hashval(fh);
33001da177e4SLinus Torvalds 	struct nfs4_file *fp;
33011da177e4SLinus Torvalds 
3302950e0118STrond Myklebust 	lockdep_assert_held(&state_lock);
3303950e0118STrond Myklebust 
330489876f8cSJeff Layton 	hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
3305ca943217STrond Myklebust 		if (nfsd_fh_match(&fp->fi_fhandle, fh)) {
330613cd2184SNeilBrown 			get_nfs4_file(fp);
33071da177e4SLinus Torvalds 			return fp;
33081da177e4SLinus Torvalds 		}
330913cd2184SNeilBrown 	}
33101da177e4SLinus Torvalds 	return NULL;
33111da177e4SLinus Torvalds }
33121da177e4SLinus Torvalds 
3313950e0118STrond Myklebust static struct nfs4_file *
3314ca943217STrond Myklebust find_file(struct knfsd_fh *fh)
3315950e0118STrond Myklebust {
3316950e0118STrond Myklebust 	struct nfs4_file *fp;
3317950e0118STrond Myklebust 
3318950e0118STrond Myklebust 	spin_lock(&state_lock);
3319ca943217STrond Myklebust 	fp = find_file_locked(fh);
3320950e0118STrond Myklebust 	spin_unlock(&state_lock);
3321950e0118STrond Myklebust 	return fp;
3322950e0118STrond Myklebust }
3323950e0118STrond Myklebust 
3324950e0118STrond Myklebust static struct nfs4_file *
3325f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh)
3326950e0118STrond Myklebust {
3327950e0118STrond Myklebust 	struct nfs4_file *fp;
3328950e0118STrond Myklebust 
3329950e0118STrond Myklebust 	spin_lock(&state_lock);
3330ca943217STrond Myklebust 	fp = find_file_locked(fh);
3331950e0118STrond Myklebust 	if (fp == NULL) {
3332f9c00c3aSJeff Layton 		nfsd4_init_file(new, fh);
3333950e0118STrond Myklebust 		fp = new;
3334950e0118STrond Myklebust 	}
3335950e0118STrond Myklebust 	spin_unlock(&state_lock);
3336950e0118STrond Myklebust 
3337950e0118STrond Myklebust 	return fp;
3338950e0118STrond Myklebust }
3339950e0118STrond Myklebust 
33404f83aa30SJ. Bruce Fields /*
33411da177e4SLinus Torvalds  * Called to check deny when READ with all zero stateid or
33421da177e4SLinus Torvalds  * WRITE with all zero or all one stateid
33431da177e4SLinus Torvalds  */
3344b37ad28bSAl Viro static __be32
33451da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
33461da177e4SLinus Torvalds {
33471da177e4SLinus Torvalds 	struct nfs4_file *fp;
3348baeb4ff0SJeff Layton 	__be32 ret = nfs_ok;
33491da177e4SLinus Torvalds 
3350ca943217STrond Myklebust 	fp = find_file(&current_fh->fh_handle);
335113cd2184SNeilBrown 	if (!fp)
3352baeb4ff0SJeff Layton 		return ret;
3353baeb4ff0SJeff Layton 	/* Check for conflicting share reservations */
33541d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
3355baeb4ff0SJeff Layton 	if (fp->fi_share_deny & deny_type)
3356baeb4ff0SJeff Layton 		ret = nfserr_locked;
33571d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
335813cd2184SNeilBrown 	put_nfs4_file(fp);
335913cd2184SNeilBrown 	return ret;
33601da177e4SLinus Torvalds }
33611da177e4SLinus Torvalds 
336202e1215fSJeff Layton void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp)
33631da177e4SLinus Torvalds {
336411b9164aSTrond Myklebust 	struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net,
336511b9164aSTrond Myklebust 					  nfsd_net_id);
3366e8c69d17SJ. Bruce Fields 
336711b9164aSTrond Myklebust 	block_delegations(&dp->dl_stid.sc_file->fi_fhandle);
3368f54fe962SJeff Layton 
336902e1215fSJeff Layton 	/*
337002e1215fSJeff Layton 	 * We can't do this in nfsd_break_deleg_cb because it is
3371f54fe962SJeff Layton 	 * already holding inode->i_lock.
3372f54fe962SJeff Layton 	 *
3373dff1399fSJeff Layton 	 * If the dl_time != 0, then we know that it has already been
3374dff1399fSJeff Layton 	 * queued for a lease break. Don't queue it again.
3375dff1399fSJeff Layton 	 */
3376f54fe962SJeff Layton 	spin_lock(&state_lock);
3377dff1399fSJeff Layton 	if (dp->dl_time == 0) {
33781da177e4SLinus Torvalds 		dp->dl_time = get_seconds();
337902e1215fSJeff Layton 		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
338002e1215fSJeff Layton 	}
338102e1215fSJeff Layton 	spin_unlock(&state_lock);
3382dff1399fSJeff Layton }
33831da177e4SLinus Torvalds 
338402e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
338502e1215fSJeff Layton {
338602e1215fSJeff Layton 	/*
338702e1215fSJeff Layton 	 * We're assuming the state code never drops its reference
338802e1215fSJeff Layton 	 * without first removing the lease.  Since we're in this lease
338902e1215fSJeff Layton 	 * callback (and since the lease code is serialized by the kernel
339002e1215fSJeff Layton 	 * lock) we know the server hasn't removed the lease yet, we know
339102e1215fSJeff Layton 	 * it's safe to take a reference.
339202e1215fSJeff Layton 	 */
339372c0b0fbSTrond Myklebust 	atomic_inc(&dp->dl_stid.sc_count);
33946b57d9c8SJ. Bruce Fields 	nfsd4_cb_recall(dp);
33956b57d9c8SJ. Bruce Fields }
33966b57d9c8SJ. Bruce Fields 
33971c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */
33986b57d9c8SJ. Bruce Fields static void nfsd_break_deleg_cb(struct file_lock *fl)
33996b57d9c8SJ. Bruce Fields {
3400acfdf5c3SJ. Bruce Fields 	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
3401acfdf5c3SJ. Bruce Fields 	struct nfs4_delegation *dp;
34026b57d9c8SJ. Bruce Fields 
34037fa10cd1SJ. Bruce Fields 	if (!fp) {
34047fa10cd1SJ. Bruce Fields 		WARN(1, "(%p)->fl_owner NULL\n", fl);
34057fa10cd1SJ. Bruce Fields 		return;
34067fa10cd1SJ. Bruce Fields 	}
34077fa10cd1SJ. Bruce Fields 	if (fp->fi_had_conflict) {
34087fa10cd1SJ. Bruce Fields 		WARN(1, "duplicate break on %p\n", fp);
34097fa10cd1SJ. Bruce Fields 		return;
34107fa10cd1SJ. Bruce Fields 	}
34110272e1fdSJ. Bruce Fields 	/*
34120272e1fdSJ. Bruce Fields 	 * We don't want the locks code to timeout the lease for us;
3413acfdf5c3SJ. Bruce Fields 	 * we'll remove it ourself if a delegation isn't returned
34146b57d9c8SJ. Bruce Fields 	 * in time:
34150272e1fdSJ. Bruce Fields 	 */
34160272e1fdSJ. Bruce Fields 	fl->fl_break_time = 0;
34171da177e4SLinus Torvalds 
341802e1215fSJeff Layton 	spin_lock(&fp->fi_lock);
3419417c6629SJeff Layton 	fp->fi_had_conflict = true;
3420417c6629SJeff Layton 	/*
3421417c6629SJeff Layton 	 * If there are no delegations on the list, then we can't count on this
3422417c6629SJeff Layton 	 * lease ever being cleaned up. Set the fl_break_time to jiffies so that
3423417c6629SJeff Layton 	 * time_out_leases will do it ASAP. The fact that fi_had_conflict is now
3424417c6629SJeff Layton 	 * true should keep any new delegations from being hashed.
3425417c6629SJeff Layton 	 */
3426417c6629SJeff Layton 	if (list_empty(&fp->fi_delegations))
3427417c6629SJeff Layton 		fl->fl_break_time = jiffies;
3428417c6629SJeff Layton 	else
3429acfdf5c3SJ. Bruce Fields 		list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
34305d926e8cSJ. Bruce Fields 			nfsd_break_one_deleg(dp);
343102e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
34321da177e4SLinus Torvalds }
34331da177e4SLinus Torvalds 
34341da177e4SLinus Torvalds static
34351da177e4SLinus Torvalds int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
34361da177e4SLinus Torvalds {
34371da177e4SLinus Torvalds 	if (arg & F_UNLCK)
34381da177e4SLinus Torvalds 		return lease_modify(onlist, arg);
34391da177e4SLinus Torvalds 	else
34401da177e4SLinus Torvalds 		return -EAGAIN;
34411da177e4SLinus Torvalds }
34421da177e4SLinus Torvalds 
34437b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = {
34448fb47a4fSJ. Bruce Fields 	.lm_break = nfsd_break_deleg_cb,
34458fb47a4fSJ. Bruce Fields 	.lm_change = nfsd_change_deleg_cb,
34461da177e4SLinus Torvalds };
34471da177e4SLinus Torvalds 
34487a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
34497a8711c9SJ. Bruce Fields {
34507a8711c9SJ. Bruce Fields 	if (nfsd4_has_session(cstate))
34517a8711c9SJ. Bruce Fields 		return nfs_ok;
34527a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid - 1)
34537a8711c9SJ. Bruce Fields 		return nfserr_replay_me;
34547a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid)
34557a8711c9SJ. Bruce Fields 		return nfs_ok;
34567a8711c9SJ. Bruce Fields 	return nfserr_bad_seqid;
34577a8711c9SJ. Bruce Fields }
34581da177e4SLinus Torvalds 
34594b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid,
34604b24ca7dSJeff Layton 		struct nfsd4_compound_state *cstate,
34614b24ca7dSJeff Layton 		struct nfsd_net *nn)
34624b24ca7dSJeff Layton {
34634b24ca7dSJeff Layton 	struct nfs4_client *found;
34644b24ca7dSJeff Layton 
34654b24ca7dSJeff Layton 	if (cstate->clp) {
34664b24ca7dSJeff Layton 		found = cstate->clp;
34674b24ca7dSJeff Layton 		if (!same_clid(&found->cl_clientid, clid))
34684b24ca7dSJeff Layton 			return nfserr_stale_clientid;
34694b24ca7dSJeff Layton 		return nfs_ok;
34704b24ca7dSJeff Layton 	}
34714b24ca7dSJeff Layton 
34724b24ca7dSJeff Layton 	if (STALE_CLIENTID(clid, nn))
34734b24ca7dSJeff Layton 		return nfserr_stale_clientid;
34744b24ca7dSJeff Layton 
34754b24ca7dSJeff Layton 	/*
34764b24ca7dSJeff Layton 	 * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
34774b24ca7dSJeff Layton 	 * cached already then we know this is for is for v4.0 and "sessions"
34784b24ca7dSJeff Layton 	 * will be false.
34794b24ca7dSJeff Layton 	 */
34804b24ca7dSJeff Layton 	WARN_ON_ONCE(cstate->session);
34813e339f96STrond Myklebust 	spin_lock(&nn->client_lock);
34824b24ca7dSJeff Layton 	found = find_confirmed_client(clid, false, nn);
34833e339f96STrond Myklebust 	if (!found) {
34843e339f96STrond Myklebust 		spin_unlock(&nn->client_lock);
34854b24ca7dSJeff Layton 		return nfserr_expired;
34863e339f96STrond Myklebust 	}
34873e339f96STrond Myklebust 	atomic_inc(&found->cl_refcount);
34883e339f96STrond Myklebust 	spin_unlock(&nn->client_lock);
34894b24ca7dSJeff Layton 
34904b24ca7dSJeff Layton 	/* Cache the nfs4_client in cstate! */
34914b24ca7dSJeff Layton 	cstate->clp = found;
34924b24ca7dSJeff Layton 	return nfs_ok;
34934b24ca7dSJeff Layton }
34944b24ca7dSJeff Layton 
3495b37ad28bSAl Viro __be32
34966668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate,
34973320fef1SStanislav Kinsbursky 		    struct nfsd4_open *open, struct nfsd_net *nn)
34981da177e4SLinus Torvalds {
34991da177e4SLinus Torvalds 	clientid_t *clientid = &open->op_clientid;
35001da177e4SLinus Torvalds 	struct nfs4_client *clp = NULL;
35011da177e4SLinus Torvalds 	unsigned int strhashval;
3502fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = NULL;
35034cdc951bSJ. Bruce Fields 	__be32 status;
35041da177e4SLinus Torvalds 
35052c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(&open->op_clientid, nn))
35061da177e4SLinus Torvalds 		return nfserr_stale_clientid;
350732513b40SJ. Bruce Fields 	/*
350832513b40SJ. Bruce Fields 	 * In case we need it later, after we've already created the
350932513b40SJ. Bruce Fields 	 * file and don't want to risk a further failure:
351032513b40SJ. Bruce Fields 	 */
351132513b40SJ. Bruce Fields 	open->op_file = nfsd4_alloc_file();
351232513b40SJ. Bruce Fields 	if (open->op_file == NULL)
351332513b40SJ. Bruce Fields 		return nfserr_jukebox;
35141da177e4SLinus Torvalds 
351513d6f66bSTrond Myklebust 	status = lookup_clientid(clientid, cstate, nn);
351613d6f66bSTrond Myklebust 	if (status)
351713d6f66bSTrond Myklebust 		return status;
351813d6f66bSTrond Myklebust 	clp = cstate->clp;
35192d91e895STrond Myklebust 
3520d4f0489fSTrond Myklebust 	strhashval = ownerstr_hashval(&open->op_owner);
3521d4f0489fSTrond Myklebust 	oo = find_openstateowner_str(strhashval, open, clp);
35222d91e895STrond Myklebust 	open->op_openowner = oo;
35232d91e895STrond Myklebust 	if (!oo) {
3524bcf130f9SJ. Bruce Fields 		goto new_owner;
35250f442aa2SJ. Bruce Fields 	}
3526dad1c067SJ. Bruce Fields 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
35270f442aa2SJ. Bruce Fields 		/* Replace unconfirmed owners without checking for replay. */
3528fe0750e5SJ. Bruce Fields 		release_openowner(oo);
3529fe0750e5SJ. Bruce Fields 		open->op_openowner = NULL;
3530bcf130f9SJ. Bruce Fields 		goto new_owner;
35310f442aa2SJ. Bruce Fields 	}
35324cdc951bSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
35334cdc951bSJ. Bruce Fields 	if (status)
35344cdc951bSJ. Bruce Fields 		return status;
35354cdc951bSJ. Bruce Fields 	goto alloc_stateid;
3536bcf130f9SJ. Bruce Fields new_owner:
353713d6f66bSTrond Myklebust 	oo = alloc_init_open_stateowner(strhashval, open, cstate);
3538fe0750e5SJ. Bruce Fields 	if (oo == NULL)
35393e772463SJ. Bruce Fields 		return nfserr_jukebox;
3540fe0750e5SJ. Bruce Fields 	open->op_openowner = oo;
35414cdc951bSJ. Bruce Fields alloc_stateid:
3542b49e084dSJeff Layton 	open->op_stp = nfs4_alloc_open_stateid(clp);
35434cdc951bSJ. Bruce Fields 	if (!open->op_stp)
35444cdc951bSJ. Bruce Fields 		return nfserr_jukebox;
35450f442aa2SJ. Bruce Fields 	return nfs_ok;
35461da177e4SLinus Torvalds }
35471da177e4SLinus Torvalds 
3548b37ad28bSAl Viro static inline __be32
35494a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
35504a6e43e6SNeilBrown {
35514a6e43e6SNeilBrown 	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
35524a6e43e6SNeilBrown 		return nfserr_openmode;
35534a6e43e6SNeilBrown 	else
35544a6e43e6SNeilBrown 		return nfs_ok;
35554a6e43e6SNeilBrown }
35564a6e43e6SNeilBrown 
3557c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access)
355824a0111eSJ. Bruce Fields {
355924a0111eSJ. Bruce Fields 	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
356024a0111eSJ. Bruce Fields }
356124a0111eSJ. Bruce Fields 
356238c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
3563f459e453SJ. Bruce Fields {
3564f459e453SJ. Bruce Fields 	struct nfs4_stid *ret;
3565f459e453SJ. Bruce Fields 
356638c2f4b1SJ. Bruce Fields 	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
3567f459e453SJ. Bruce Fields 	if (!ret)
3568f459e453SJ. Bruce Fields 		return NULL;
3569f459e453SJ. Bruce Fields 	return delegstateid(ret);
3570f459e453SJ. Bruce Fields }
3571f459e453SJ. Bruce Fields 
35728b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
35738b289b2cSJ. Bruce Fields {
35748b289b2cSJ. Bruce Fields 	return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
35758b289b2cSJ. Bruce Fields 	       open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
35768b289b2cSJ. Bruce Fields }
35778b289b2cSJ. Bruce Fields 
3578b37ad28bSAl Viro static __be32
357941d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
3580567d9829SNeilBrown 		struct nfs4_delegation **dp)
3581567d9829SNeilBrown {
3582567d9829SNeilBrown 	int flags;
3583b37ad28bSAl Viro 	__be32 status = nfserr_bad_stateid;
3584dcd94cc2STrond Myklebust 	struct nfs4_delegation *deleg;
3585567d9829SNeilBrown 
3586dcd94cc2STrond Myklebust 	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
3587dcd94cc2STrond Myklebust 	if (deleg == NULL)
3588c44c5eebSNeilBrown 		goto out;
358924a0111eSJ. Bruce Fields 	flags = share_access_to_flags(open->op_share_access);
3590dcd94cc2STrond Myklebust 	status = nfs4_check_delegmode(deleg, flags);
3591dcd94cc2STrond Myklebust 	if (status) {
3592dcd94cc2STrond Myklebust 		nfs4_put_stid(&deleg->dl_stid);
3593dcd94cc2STrond Myklebust 		goto out;
3594dcd94cc2STrond Myklebust 	}
3595dcd94cc2STrond Myklebust 	*dp = deleg;
3596c44c5eebSNeilBrown out:
35978b289b2cSJ. Bruce Fields 	if (!nfsd4_is_deleg_cur(open))
3598c44c5eebSNeilBrown 		return nfs_ok;
3599c44c5eebSNeilBrown 	if (status)
3600c44c5eebSNeilBrown 		return status;
3601dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
3602c44c5eebSNeilBrown 	return nfs_ok;
3603567d9829SNeilBrown }
3604567d9829SNeilBrown 
3605a46cb7f2SJeff Layton static struct nfs4_ol_stateid *
3606a46cb7f2SJeff Layton nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
36071da177e4SLinus Torvalds {
3608a46cb7f2SJeff Layton 	struct nfs4_ol_stateid *local, *ret = NULL;
3609fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = open->op_openowner;
36101da177e4SLinus Torvalds 
36111d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
36128beefa24SNeilBrown 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
36131da177e4SLinus Torvalds 		/* ignore lock owners */
36141da177e4SLinus Torvalds 		if (local->st_stateowner->so_is_open_owner == 0)
36151da177e4SLinus Torvalds 			continue;
3616baeb4ff0SJeff Layton 		if (local->st_stateowner == &oo->oo_owner) {
3617a46cb7f2SJeff Layton 			ret = local;
3618d6f2bc5dSTrond Myklebust 			atomic_inc(&ret->st_stid.sc_count);
3619baeb4ff0SJeff Layton 			break;
36201da177e4SLinus Torvalds 		}
36211d31a253STrond Myklebust 	}
36221d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
3623a46cb7f2SJeff Layton 	return ret;
36241da177e4SLinus Torvalds }
36251da177e4SLinus Torvalds 
362621fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access)
362721fb4016SJ. Bruce Fields {
362821fb4016SJ. Bruce Fields 	int flags = 0;
362921fb4016SJ. Bruce Fields 
363021fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
363121fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_READ;
363221fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
363321fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_WRITE;
363421fb4016SJ. Bruce Fields 	return flags;
363521fb4016SJ. Bruce Fields }
363621fb4016SJ. Bruce Fields 
3637b37ad28bSAl Viro static inline __be32
36381da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
36391da177e4SLinus Torvalds 		struct nfsd4_open *open)
36401da177e4SLinus Torvalds {
36411da177e4SLinus Torvalds 	struct iattr iattr = {
36421da177e4SLinus Torvalds 		.ia_valid = ATTR_SIZE,
36431da177e4SLinus Torvalds 		.ia_size = 0,
36441da177e4SLinus Torvalds 	};
36451da177e4SLinus Torvalds 	if (!open->op_truncate)
36461da177e4SLinus Torvalds 		return 0;
36471da177e4SLinus Torvalds 	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
36489246585aSAl Viro 		return nfserr_inval;
36491da177e4SLinus Torvalds 	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
36501da177e4SLinus Torvalds }
36511da177e4SLinus Torvalds 
36527e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
36536eb3a1d0SJeff Layton 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
36546eb3a1d0SJeff Layton 		struct nfsd4_open *open)
36557e6a72e5SChristoph Hellwig {
3656de18643dSTrond Myklebust 	struct file *filp = NULL;
36577e6a72e5SChristoph Hellwig 	__be32 status;
36587e6a72e5SChristoph Hellwig 	int oflag = nfs4_access_to_omode(open->op_share_access);
36597e6a72e5SChristoph Hellwig 	int access = nfs4_access_to_access(open->op_share_access);
3660baeb4ff0SJeff Layton 	unsigned char old_access_bmap, old_deny_bmap;
36617e6a72e5SChristoph Hellwig 
3662de18643dSTrond Myklebust 	spin_lock(&fp->fi_lock);
3663baeb4ff0SJeff Layton 
3664baeb4ff0SJeff Layton 	/*
3665baeb4ff0SJeff Layton 	 * Are we trying to set a deny mode that would conflict with
3666baeb4ff0SJeff Layton 	 * current access?
3667baeb4ff0SJeff Layton 	 */
3668baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
3669baeb4ff0SJeff Layton 	if (status != nfs_ok) {
3670baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
3671baeb4ff0SJeff Layton 		goto out;
3672baeb4ff0SJeff Layton 	}
3673baeb4ff0SJeff Layton 
3674baeb4ff0SJeff Layton 	/* set access to the file */
3675baeb4ff0SJeff Layton 	status = nfs4_file_get_access(fp, open->op_share_access);
3676baeb4ff0SJeff Layton 	if (status != nfs_ok) {
3677baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
3678baeb4ff0SJeff Layton 		goto out;
3679baeb4ff0SJeff Layton 	}
3680baeb4ff0SJeff Layton 
3681baeb4ff0SJeff Layton 	/* Set access bits in stateid */
3682baeb4ff0SJeff Layton 	old_access_bmap = stp->st_access_bmap;
3683baeb4ff0SJeff Layton 	set_access(open->op_share_access, stp);
3684baeb4ff0SJeff Layton 
3685baeb4ff0SJeff Layton 	/* Set new deny mask */
3686baeb4ff0SJeff Layton 	old_deny_bmap = stp->st_deny_bmap;
3687baeb4ff0SJeff Layton 	set_deny(open->op_share_deny, stp);
3688baeb4ff0SJeff Layton 	fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH);
3689baeb4ff0SJeff Layton 
36907e6a72e5SChristoph Hellwig 	if (!fp->fi_fds[oflag]) {
3691de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
3692de18643dSTrond Myklebust 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
36937e6a72e5SChristoph Hellwig 		if (status)
3694baeb4ff0SJeff Layton 			goto out_put_access;
3695de18643dSTrond Myklebust 		spin_lock(&fp->fi_lock);
3696de18643dSTrond Myklebust 		if (!fp->fi_fds[oflag]) {
3697de18643dSTrond Myklebust 			fp->fi_fds[oflag] = filp;
3698de18643dSTrond Myklebust 			filp = NULL;
3699de18643dSTrond Myklebust 		}
37007e6a72e5SChristoph Hellwig 	}
3701de18643dSTrond Myklebust 	spin_unlock(&fp->fi_lock);
3702de18643dSTrond Myklebust 	if (filp)
3703de18643dSTrond Myklebust 		fput(filp);
37047e6a72e5SChristoph Hellwig 
37057e6a72e5SChristoph Hellwig 	status = nfsd4_truncate(rqstp, cur_fh, open);
37067e6a72e5SChristoph Hellwig 	if (status)
37077e6a72e5SChristoph Hellwig 		goto out_put_access;
37087e6a72e5SChristoph Hellwig out:
37097e6a72e5SChristoph Hellwig 	return status;
3710baeb4ff0SJeff Layton out_put_access:
3711baeb4ff0SJeff Layton 	stp->st_access_bmap = old_access_bmap;
3712baeb4ff0SJeff Layton 	nfs4_file_put_access(fp, open->op_share_access);
3713baeb4ff0SJeff Layton 	reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp);
3714baeb4ff0SJeff Layton 	goto out;
37157e6a72e5SChristoph Hellwig }
37167e6a72e5SChristoph Hellwig 
3717b37ad28bSAl Viro static __be32
3718dcef0413SJ. 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)
37191da177e4SLinus Torvalds {
3720b37ad28bSAl Viro 	__be32 status;
3721baeb4ff0SJeff Layton 	unsigned char old_deny_bmap;
37221da177e4SLinus Torvalds 
37236eb3a1d0SJeff Layton 	if (!test_access(open->op_share_access, stp))
3724baeb4ff0SJeff Layton 		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
37257e6a72e5SChristoph Hellwig 
3726baeb4ff0SJeff Layton 	/* test and set deny mode */
3727baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
3728baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
3729baeb4ff0SJeff Layton 	if (status == nfs_ok) {
3730baeb4ff0SJeff Layton 		old_deny_bmap = stp->st_deny_bmap;
3731baeb4ff0SJeff Layton 		set_deny(open->op_share_deny, stp);
3732baeb4ff0SJeff Layton 		fp->fi_share_deny |=
3733baeb4ff0SJeff Layton 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
37341da177e4SLinus Torvalds 	}
3735baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
37361da177e4SLinus Torvalds 
3737baeb4ff0SJeff Layton 	if (status != nfs_ok)
3738baeb4ff0SJeff Layton 		return status;
3739baeb4ff0SJeff Layton 
3740baeb4ff0SJeff Layton 	status = nfsd4_truncate(rqstp, cur_fh, open);
3741baeb4ff0SJeff Layton 	if (status != nfs_ok)
3742baeb4ff0SJeff Layton 		reset_union_bmap_deny(old_deny_bmap, stp);
3743baeb4ff0SJeff Layton 	return status;
3744baeb4ff0SJeff Layton }
37451da177e4SLinus Torvalds 
37461da177e4SLinus Torvalds static void
37471255a8f3SJ. Bruce Fields nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session)
37481da177e4SLinus Torvalds {
3749dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
37501da177e4SLinus Torvalds }
37511da177e4SLinus Torvalds 
375214a24e99SJ. Bruce Fields /* Should we give out recallable state?: */
375314a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
375414a24e99SJ. Bruce Fields {
375514a24e99SJ. Bruce Fields 	if (clp->cl_cb_state == NFSD4_CB_UP)
375614a24e99SJ. Bruce Fields 		return true;
375714a24e99SJ. Bruce Fields 	/*
375814a24e99SJ. Bruce Fields 	 * In the sessions case, since we don't have to establish a
375914a24e99SJ. Bruce Fields 	 * separate connection for callbacks, we assume it's OK
376014a24e99SJ. Bruce Fields 	 * until we hear otherwise:
376114a24e99SJ. Bruce Fields 	 */
376214a24e99SJ. Bruce Fields 	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
376314a24e99SJ. Bruce Fields }
376414a24e99SJ. Bruce Fields 
3765d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
376622d38c4cSJ. Bruce Fields {
376722d38c4cSJ. Bruce Fields 	struct file_lock *fl;
376822d38c4cSJ. Bruce Fields 
376922d38c4cSJ. Bruce Fields 	fl = locks_alloc_lock();
377022d38c4cSJ. Bruce Fields 	if (!fl)
377122d38c4cSJ. Bruce Fields 		return NULL;
377222d38c4cSJ. Bruce Fields 	fl->fl_lmops = &nfsd_lease_mng_ops;
3773617588d5SJ. Bruce Fields 	fl->fl_flags = FL_DELEG;
377422d38c4cSJ. Bruce Fields 	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
377522d38c4cSJ. Bruce Fields 	fl->fl_end = OFFSET_MAX;
3776d564fbecSJeff Layton 	fl->fl_owner = (fl_owner_t)fp;
377722d38c4cSJ. Bruce Fields 	fl->fl_pid = current->tgid;
377822d38c4cSJ. Bruce Fields 	return fl;
377922d38c4cSJ. Bruce Fields }
378022d38c4cSJ. Bruce Fields 
378199c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp)
3782edab9782SJ. Bruce Fields {
378311b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
3784415b96c5SJeff Layton 	struct file_lock *fl, *ret;
3785417c6629SJeff Layton 	struct file *filp;
3786417c6629SJeff Layton 	int status = 0;
3787edab9782SJ. Bruce Fields 
3788d564fbecSJeff Layton 	fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ);
3789edab9782SJ. Bruce Fields 	if (!fl)
3790edab9782SJ. Bruce Fields 		return -ENOMEM;
3791417c6629SJeff Layton 	filp = find_readable_file(fp);
3792417c6629SJeff Layton 	if (!filp) {
3793417c6629SJeff Layton 		/* We should always have a readable file here */
3794417c6629SJeff Layton 		WARN_ON_ONCE(1);
3795417c6629SJeff Layton 		return -EBADF;
3796417c6629SJeff Layton 	}
3797417c6629SJeff Layton 	fl->fl_file = filp;
3798415b96c5SJeff Layton 	ret = fl;
3799415b96c5SJeff Layton 	status = vfs_setlease(filp, fl->fl_type, &ret);
3800417c6629SJeff Layton 	if (status) {
3801417c6629SJeff Layton 		locks_free_lock(fl);
3802417c6629SJeff Layton 		goto out_fput;
3803417c6629SJeff Layton 	}
3804415b96c5SJeff Layton 	if (ret != fl)
3805415b96c5SJeff Layton 		locks_free_lock(fl);
3806cdc97505SBenny Halevy 	spin_lock(&state_lock);
3807417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
3808417c6629SJeff Layton 	/* Did the lease get broken before we took the lock? */
3809417c6629SJeff Layton 	status = -EAGAIN;
3810417c6629SJeff Layton 	if (fp->fi_had_conflict)
3811417c6629SJeff Layton 		goto out_unlock;
3812417c6629SJeff Layton 	/* Race breaker */
3813417c6629SJeff Layton 	if (fp->fi_lease) {
3814417c6629SJeff Layton 		status = 0;
3815417c6629SJeff Layton 		atomic_inc(&fp->fi_delegees);
3816931ee56cSBenny Halevy 		hash_delegation_locked(dp, fp);
3817417c6629SJeff Layton 		goto out_unlock;
3818417c6629SJeff Layton 	}
3819417c6629SJeff Layton 	fp->fi_lease = fl;
3820417c6629SJeff Layton 	fp->fi_deleg_file = filp;
3821417c6629SJeff Layton 	atomic_set(&fp->fi_delegees, 1);
3822417c6629SJeff Layton 	hash_delegation_locked(dp, fp);
3823417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
3824cdc97505SBenny Halevy 	spin_unlock(&state_lock);
3825acfdf5c3SJ. Bruce Fields 	return 0;
3826417c6629SJeff Layton out_unlock:
3827417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
3828417c6629SJeff Layton 	spin_unlock(&state_lock);
3829417c6629SJeff Layton out_fput:
3830417c6629SJeff Layton 	fput(filp);
3831e873088fSJ. Bruce Fields 	return status;
3832acfdf5c3SJ. Bruce Fields }
3833acfdf5c3SJ. Bruce Fields 
38340b26693cSJeff Layton static struct nfs4_delegation *
38350b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
38360b26693cSJeff Layton 		    struct nfs4_file *fp)
3837acfdf5c3SJ. Bruce Fields {
38380b26693cSJeff Layton 	int status;
38390b26693cSJeff Layton 	struct nfs4_delegation *dp;
3840417c6629SJeff Layton 
3841bf7bd3e9SJ. Bruce Fields 	if (fp->fi_had_conflict)
38420b26693cSJeff Layton 		return ERR_PTR(-EAGAIN);
38430b26693cSJeff Layton 
38440b26693cSJeff Layton 	dp = alloc_init_deleg(clp, fh);
38450b26693cSJeff Layton 	if (!dp)
38460b26693cSJeff Layton 		return ERR_PTR(-ENOMEM);
38470b26693cSJeff Layton 
3848bf7bd3e9SJ. Bruce Fields 	get_nfs4_file(fp);
3849cdc97505SBenny Halevy 	spin_lock(&state_lock);
3850417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
385111b9164aSTrond Myklebust 	dp->dl_stid.sc_file = fp;
3852417c6629SJeff Layton 	if (!fp->fi_lease) {
3853417c6629SJeff Layton 		spin_unlock(&fp->fi_lock);
3854417c6629SJeff Layton 		spin_unlock(&state_lock);
38550b26693cSJeff Layton 		status = nfs4_setlease(dp);
38560b26693cSJeff Layton 		goto out;
3857417c6629SJeff Layton 	}
3858cbf7a75bSJ. Bruce Fields 	atomic_inc(&fp->fi_delegees);
3859acfdf5c3SJ. Bruce Fields 	if (fp->fi_had_conflict) {
3860417c6629SJeff Layton 		status = -EAGAIN;
3861417c6629SJeff Layton 		goto out_unlock;
3862acfdf5c3SJ. Bruce Fields 	}
3863931ee56cSBenny Halevy 	hash_delegation_locked(dp, fp);
38640b26693cSJeff Layton 	status = 0;
3865417c6629SJeff Layton out_unlock:
3866417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
3867cdc97505SBenny Halevy 	spin_unlock(&state_lock);
38680b26693cSJeff Layton out:
38690b26693cSJeff Layton 	if (status) {
38706011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
38710b26693cSJeff Layton 		return ERR_PTR(status);
38720b26693cSJeff Layton 	}
38730b26693cSJeff Layton 	return dp;
3874edab9782SJ. Bruce Fields }
3875edab9782SJ. Bruce Fields 
38764aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
38774aa8913cSBenny Halevy {
38784aa8913cSBenny Halevy 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
38794aa8913cSBenny Halevy 	if (status == -EAGAIN)
38804aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_CONTENTION;
38814aa8913cSBenny Halevy 	else {
38824aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_RESOURCE;
38834aa8913cSBenny Halevy 		switch (open->op_deleg_want) {
38844aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_READ_DELEG:
38854aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_WRITE_DELEG:
38864aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_ANY_DELEG:
38874aa8913cSBenny Halevy 			break;
38884aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_CANCEL:
38894aa8913cSBenny Halevy 			open->op_why_no_deleg = WND4_CANCELLED;
38904aa8913cSBenny Halevy 			break;
38914aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_NO_DELEG:
3892063b0fb9SJ. Bruce Fields 			WARN_ON_ONCE(1);
38934aa8913cSBenny Halevy 		}
38944aa8913cSBenny Halevy 	}
38954aa8913cSBenny Halevy }
38964aa8913cSBenny Halevy 
38971da177e4SLinus Torvalds /*
38981da177e4SLinus Torvalds  * Attempt to hand out a delegation.
389999c41515SJ. Bruce Fields  *
390099c41515SJ. Bruce Fields  * Note we don't support write delegations, and won't until the vfs has
390199c41515SJ. Bruce Fields  * proper support for them.
39021da177e4SLinus Torvalds  */
39031da177e4SLinus Torvalds static void
39044cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
39054cf59221SJeff Layton 			struct nfs4_ol_stateid *stp)
39061da177e4SLinus Torvalds {
39071da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
39084cf59221SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_stateowner);
39094cf59221SJeff Layton 	struct nfs4_client *clp = stp->st_stid.sc_client;
391014a24e99SJ. Bruce Fields 	int cb_up;
391199c41515SJ. Bruce Fields 	int status = 0;
39121da177e4SLinus Torvalds 
3913fe0750e5SJ. Bruce Fields 	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
39147b190fecSNeilBrown 	open->op_recall = 0;
39157b190fecSNeilBrown 	switch (open->op_claim_type) {
39167b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_PREVIOUS:
39172bf23875SJ. Bruce Fields 			if (!cb_up)
39187b190fecSNeilBrown 				open->op_recall = 1;
391999c41515SJ. Bruce Fields 			if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
392099c41515SJ. Bruce Fields 				goto out_no_deleg;
39217b190fecSNeilBrown 			break;
39227b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_NULL:
3923ed47b062SMing Chen 		case NFS4_OPEN_CLAIM_FH:
392499c41515SJ. Bruce Fields 			/*
392599c41515SJ. Bruce Fields 			 * Let's not give out any delegations till everyone's
392699c41515SJ. Bruce Fields 			 * had the chance to reclaim theirs....
392799c41515SJ. Bruce Fields 			 */
39284cf59221SJeff Layton 			if (locks_in_grace(clp->net))
392999c41515SJ. Bruce Fields 				goto out_no_deleg;
3930dad1c067SJ. Bruce Fields 			if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
393199c41515SJ. Bruce Fields 				goto out_no_deleg;
39329a0590aeSSteve Dickson 			/*
39339a0590aeSSteve Dickson 			 * Also, if the file was opened for write or
39349a0590aeSSteve Dickson 			 * create, there's a good chance the client's
39359a0590aeSSteve Dickson 			 * about to write to it, resulting in an
39369a0590aeSSteve Dickson 			 * immediate recall (since we don't support
39379a0590aeSSteve Dickson 			 * write delegations):
39389a0590aeSSteve Dickson 			 */
39391da177e4SLinus Torvalds 			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
394099c41515SJ. Bruce Fields 				goto out_no_deleg;
394199c41515SJ. Bruce Fields 			if (open->op_create == NFS4_OPEN_CREATE)
394299c41515SJ. Bruce Fields 				goto out_no_deleg;
39437b190fecSNeilBrown 			break;
39447b190fecSNeilBrown 		default:
394599c41515SJ. Bruce Fields 			goto out_no_deleg;
39467b190fecSNeilBrown 	}
394711b9164aSTrond Myklebust 	dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file);
39480b26693cSJeff Layton 	if (IS_ERR(dp))
3949dd239cc0SJ. Bruce Fields 		goto out_no_deleg;
39501da177e4SLinus Torvalds 
3951d5477a8dSJ. Bruce Fields 	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
39521da177e4SLinus Torvalds 
39538c10cbdbSBenny Halevy 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
3954d5477a8dSJ. Bruce Fields 		STATEID_VAL(&dp->dl_stid.sc_stateid));
395599c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
395667cb1279STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
3957dd239cc0SJ. Bruce Fields 	return;
3958dd239cc0SJ. Bruce Fields out_no_deleg:
395999c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
39607b190fecSNeilBrown 	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
3961d08d32e6SJ. Bruce Fields 	    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
39621da177e4SLinus Torvalds 		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
3963d08d32e6SJ. Bruce Fields 		open->op_recall = 1;
3964d08d32e6SJ. Bruce Fields 	}
3965dd239cc0SJ. Bruce Fields 
3966dd239cc0SJ. Bruce Fields 	/* 4.1 client asking for a delegation? */
3967dd239cc0SJ. Bruce Fields 	if (open->op_deleg_want)
3968dd239cc0SJ. Bruce Fields 		nfsd4_open_deleg_none_ext(open, status);
3969dd239cc0SJ. Bruce Fields 	return;
39701da177e4SLinus Torvalds }
39711da177e4SLinus Torvalds 
3972e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
3973e27f49c3SBenny Halevy 					struct nfs4_delegation *dp)
3974e27f49c3SBenny Halevy {
3975e27f49c3SBenny Halevy 	if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
3976e27f49c3SBenny Halevy 	    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
3977e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
3978e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
3979e27f49c3SBenny Halevy 	} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
3980e27f49c3SBenny Halevy 		   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
3981e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
3982e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
3983e27f49c3SBenny Halevy 	}
3984e27f49c3SBenny Halevy 	/* Otherwise the client must be confused wanting a delegation
3985e27f49c3SBenny Halevy 	 * it already has, therefore we don't return
3986e27f49c3SBenny Halevy 	 * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
3987e27f49c3SBenny Halevy 	 */
3988e27f49c3SBenny Halevy }
3989e27f49c3SBenny Halevy 
3990b37ad28bSAl Viro __be32
39911da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
39921da177e4SLinus Torvalds {
39936668958fSAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
399438c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
39951da177e4SLinus Torvalds 	struct nfs4_file *fp = NULL;
3996dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
3997567d9829SNeilBrown 	struct nfs4_delegation *dp = NULL;
3998b37ad28bSAl Viro 	__be32 status;
39991da177e4SLinus Torvalds 
40001da177e4SLinus Torvalds 	/*
40011da177e4SLinus Torvalds 	 * Lookup file; if found, lookup stateid and check open request,
40021da177e4SLinus Torvalds 	 * and check for delegations in the process of being recalled.
40031da177e4SLinus Torvalds 	 * If not found, create the nfs4_file struct
40041da177e4SLinus Torvalds 	 */
4005f9c00c3aSJeff Layton 	fp = find_or_add_file(open->op_file, &current_fh->fh_handle);
4006950e0118STrond Myklebust 	if (fp != open->op_file) {
400741d22663SJ. Bruce Fields 		status = nfs4_check_deleg(cl, open, &dp);
4008c44c5eebSNeilBrown 		if (status)
4009c44c5eebSNeilBrown 			goto out;
4010a46cb7f2SJeff Layton 		stp = nfsd4_find_existing_open(fp, open);
40111da177e4SLinus Torvalds 	} else {
4012950e0118STrond Myklebust 		open->op_file = NULL;
4013c44c5eebSNeilBrown 		status = nfserr_bad_stateid;
40148b289b2cSJ. Bruce Fields 		if (nfsd4_is_deleg_cur(open))
4015c44c5eebSNeilBrown 			goto out;
40163e772463SJ. Bruce Fields 		status = nfserr_jukebox;
40171da177e4SLinus Torvalds 	}
40181da177e4SLinus Torvalds 
40191da177e4SLinus Torvalds 	/*
40201da177e4SLinus Torvalds 	 * OPEN the file, or upgrade an existing OPEN.
40211da177e4SLinus Torvalds 	 * If truncate fails, the OPEN fails.
40221da177e4SLinus Torvalds 	 */
40231da177e4SLinus Torvalds 	if (stp) {
40241da177e4SLinus Torvalds 		/* Stateid was found, this is an OPEN upgrade */
4025f9d7562fSJ. Bruce Fields 		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
40261da177e4SLinus Torvalds 		if (status)
40271da177e4SLinus Torvalds 			goto out;
40281da177e4SLinus Torvalds 	} else {
40294cdc951bSJ. Bruce Fields 		stp = open->op_stp;
40304cdc951bSJ. Bruce Fields 		open->op_stp = NULL;
4031996e0938SJ. Bruce Fields 		init_open_stateid(stp, fp, open);
40326eb3a1d0SJeff Layton 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
40336eb3a1d0SJeff Layton 		if (status) {
40346eb3a1d0SJeff Layton 			release_open_stateid(stp);
40356eb3a1d0SJeff Layton 			goto out;
40366eb3a1d0SJeff Layton 		}
40371da177e4SLinus Torvalds 	}
4038dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4039dcef0413SJ. Bruce Fields 	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
40401da177e4SLinus Torvalds 
4041d24433cdSBenny Halevy 	if (nfsd4_has_session(&resp->cstate)) {
4042d24433cdSBenny Halevy 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
4043d24433cdSBenny Halevy 			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4044d24433cdSBenny Halevy 			open->op_why_no_deleg = WND4_NOT_WANTED;
4045d24433cdSBenny Halevy 			goto nodeleg;
4046d24433cdSBenny Halevy 		}
4047d24433cdSBenny Halevy 	}
4048d24433cdSBenny Halevy 
40491da177e4SLinus Torvalds 	/*
40501da177e4SLinus Torvalds 	* Attempt to hand out a delegation. No error return, because the
40511da177e4SLinus Torvalds 	* OPEN succeeds even if we fail.
40521da177e4SLinus Torvalds 	*/
40534cf59221SJeff Layton 	nfs4_open_delegation(current_fh, open, stp);
4054d24433cdSBenny Halevy nodeleg:
40551da177e4SLinus Torvalds 	status = nfs_ok;
40561da177e4SLinus Torvalds 
40578c10cbdbSBenny Halevy 	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
4058dcef0413SJ. Bruce Fields 		STATEID_VAL(&stp->st_stid.sc_stateid));
40591da177e4SLinus Torvalds out:
4060d24433cdSBenny Halevy 	/* 4.1 client trying to upgrade/downgrade delegation? */
4061d24433cdSBenny Halevy 	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
4062e27f49c3SBenny Halevy 	    open->op_deleg_want)
4063e27f49c3SBenny Halevy 		nfsd4_deleg_xgrade_none_ext(open, dp);
4064d24433cdSBenny Halevy 
406513cd2184SNeilBrown 	if (fp)
406613cd2184SNeilBrown 		put_nfs4_file(fp);
406737515177SNeilBrown 	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
40681255a8f3SJ. Bruce Fields 		nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate));
40691da177e4SLinus Torvalds 	/*
40701da177e4SLinus Torvalds 	* To finish the open response, we just need to set the rflags.
40711da177e4SLinus Torvalds 	*/
40721da177e4SLinus Torvalds 	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
4073dad1c067SJ. Bruce Fields 	if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
40746668958fSAndy Adamson 	    !nfsd4_has_session(&resp->cstate))
40751da177e4SLinus Torvalds 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
4076dcd94cc2STrond Myklebust 	if (dp)
4077dcd94cc2STrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
4078d6f2bc5dSTrond Myklebust 	if (stp)
4079d6f2bc5dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
40801da177e4SLinus Torvalds 
40811da177e4SLinus Torvalds 	return status;
40821da177e4SLinus Torvalds }
40831da177e4SLinus Torvalds 
408458fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
408558fb12e6SJeff Layton 			      struct nfsd4_open *open, __be32 status)
4086d29b20cdSJ. Bruce Fields {
4087d29b20cdSJ. Bruce Fields 	if (open->op_openowner) {
4088d3134b10SJeff Layton 		struct nfs4_stateowner *so = &open->op_openowner->oo_owner;
4089d29b20cdSJ. Bruce Fields 
4090d3134b10SJeff Layton 		nfsd4_cstate_assign_replay(cstate, so);
4091d3134b10SJeff Layton 		nfs4_put_stateowner(so);
4092d29b20cdSJ. Bruce Fields 	}
409332513b40SJ. Bruce Fields 	if (open->op_file)
409432513b40SJ. Bruce Fields 		nfsd4_free_file(open->op_file);
40954cdc951bSJ. Bruce Fields 	if (open->op_stp)
40966011695dSTrond Myklebust 		nfs4_put_stid(&open->op_stp->st_stid);
4097d29b20cdSJ. Bruce Fields }
4098d29b20cdSJ. Bruce Fields 
4099b37ad28bSAl Viro __be32
4100b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4101b591480bSJ.Bruce Fields 	    clientid_t *clid)
41021da177e4SLinus Torvalds {
41031da177e4SLinus Torvalds 	struct nfs4_client *clp;
4104b37ad28bSAl Viro 	__be32 status;
41057f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
41061da177e4SLinus Torvalds 
41071da177e4SLinus Torvalds 	dprintk("process_renew(%08x/%08x): starting\n",
41081da177e4SLinus Torvalds 			clid->cl_boot, clid->cl_id);
41094b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
41109b2ef62bSJ. Bruce Fields 	if (status)
41111da177e4SLinus Torvalds 		goto out;
41124b24ca7dSJeff Layton 	clp = cstate->clp;
41131da177e4SLinus Torvalds 	status = nfserr_cb_path_down;
4114ea1da636SNeilBrown 	if (!list_empty(&clp->cl_delegations)
411577a3569dSJ. Bruce Fields 			&& clp->cl_cb_state != NFSD4_CB_UP)
41161da177e4SLinus Torvalds 		goto out;
41171da177e4SLinus Torvalds 	status = nfs_ok;
41181da177e4SLinus Torvalds out:
41191da177e4SLinus Torvalds 	return status;
41201da177e4SLinus Torvalds }
41211da177e4SLinus Torvalds 
4122a76b4319SNeilBrown static void
412312760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn)
4124a76b4319SNeilBrown {
412533dcc481SJeff Layton 	/* do nothing if grace period already ended */
4126a51c84edSStanislav Kinsbursky 	if (nn->grace_ended)
412733dcc481SJeff Layton 		return;
412833dcc481SJeff Layton 
4129a76b4319SNeilBrown 	dprintk("NFSD: end of grace period\n");
4130a51c84edSStanislav Kinsbursky 	nn->grace_ended = true;
413112760c66SStanislav Kinsbursky 	nfsd4_record_grace_done(nn, nn->boot_time);
41325e1533c7SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
4133e46b498cSJ. Bruce Fields 	/*
4134e46b498cSJ. Bruce Fields 	 * Now that every NFSv4 client has had the chance to recover and
4135e46b498cSJ. Bruce Fields 	 * to see the (possibly new, possibly shorter) lease time, we
4136e46b498cSJ. Bruce Fields 	 * can safely set the next grace time to the current lease time:
4137e46b498cSJ. Bruce Fields 	 */
41385284b44eSStanislav Kinsbursky 	nn->nfsd4_grace = nn->nfsd4_lease;
4139a76b4319SNeilBrown }
4140a76b4319SNeilBrown 
4141fd39ca9aSNeilBrown static time_t
414209121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn)
41431da177e4SLinus Torvalds {
41441da177e4SLinus Torvalds 	struct nfs4_client *clp;
4145fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
41461da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
4147217526e7SJeff Layton 	struct nfs4_ol_stateid *stp;
41481da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
41493d733711SStanislav Kinsbursky 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
4150a832e7aeSJeff Layton 	time_t t, new_timeo = nn->nfsd4_lease;
41511da177e4SLinus Torvalds 
41521da177e4SLinus Torvalds 	dprintk("NFSD: laundromat service - starting\n");
415312760c66SStanislav Kinsbursky 	nfsd4_end_grace(nn);
415436acb66bSBenny Halevy 	INIT_LIST_HEAD(&reaplist);
4155c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
41565ed58bb2SStanislav Kinsbursky 	list_for_each_safe(pos, next, &nn->client_lru) {
41571da177e4SLinus Torvalds 		clp = list_entry(pos, struct nfs4_client, cl_lru);
41581da177e4SLinus Torvalds 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
41591da177e4SLinus Torvalds 			t = clp->cl_time - cutoff;
4160a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
41611da177e4SLinus Torvalds 			break;
41621da177e4SLinus Torvalds 		}
4163221a6876SJ. Bruce Fields 		if (mark_client_expired_locked(clp)) {
4164d7682988SBenny Halevy 			dprintk("NFSD: client in use (clientid %08x)\n",
4165d7682988SBenny Halevy 				clp->cl_clientid.cl_id);
4166d7682988SBenny Halevy 			continue;
4167d7682988SBenny Halevy 		}
41684864af97STrond Myklebust 		list_add(&clp->cl_lru, &reaplist);
416936acb66bSBenny Halevy 	}
4170c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
417136acb66bSBenny Halevy 	list_for_each_safe(pos, next, &reaplist) {
417236acb66bSBenny Halevy 		clp = list_entry(pos, struct nfs4_client, cl_lru);
41731da177e4SLinus Torvalds 		dprintk("NFSD: purging unused client (clientid %08x)\n",
41741da177e4SLinus Torvalds 			clp->cl_clientid.cl_id);
41754864af97STrond Myklebust 		list_del_init(&clp->cl_lru);
41761da177e4SLinus Torvalds 		expire_client(clp);
41771da177e4SLinus Torvalds 	}
4178cdc97505SBenny Halevy 	spin_lock(&state_lock);
4179e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
41801da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
41814e37a7c2SStanislav Kinsbursky 		if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn)
41824e37a7c2SStanislav Kinsbursky 			continue;
41831da177e4SLinus Torvalds 		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
4184a832e7aeSJeff Layton 			t = dp->dl_time - cutoff;
4185a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
41861da177e4SLinus Torvalds 			break;
41871da177e4SLinus Torvalds 		}
418842690676SJeff Layton 		unhash_delegation_locked(dp);
418942690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
41901da177e4SLinus Torvalds 	}
4191cdc97505SBenny Halevy 	spin_unlock(&state_lock);
41922d4a532dSJeff Layton 	while (!list_empty(&reaplist)) {
41932d4a532dSJeff Layton 		dp = list_first_entry(&reaplist, struct nfs4_delegation,
41942d4a532dSJeff Layton 					dl_recall_lru);
41952d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
41963bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
41971da177e4SLinus Torvalds 	}
4198217526e7SJeff Layton 
4199217526e7SJeff Layton 	spin_lock(&nn->client_lock);
4200217526e7SJeff Layton 	while (!list_empty(&nn->close_lru)) {
4201217526e7SJeff Layton 		oo = list_first_entry(&nn->close_lru, struct nfs4_openowner,
4202217526e7SJeff Layton 					oo_close_lru);
4203217526e7SJeff Layton 		if (time_after((unsigned long)oo->oo_time,
4204217526e7SJeff Layton 			       (unsigned long)cutoff)) {
4205a832e7aeSJeff Layton 			t = oo->oo_time - cutoff;
4206a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
42071da177e4SLinus Torvalds 			break;
42081da177e4SLinus Torvalds 		}
4209217526e7SJeff Layton 		list_del_init(&oo->oo_close_lru);
4210217526e7SJeff Layton 		stp = oo->oo_last_closed_stid;
4211217526e7SJeff Layton 		oo->oo_last_closed_stid = NULL;
4212217526e7SJeff Layton 		spin_unlock(&nn->client_lock);
4213217526e7SJeff Layton 		nfs4_put_stid(&stp->st_stid);
4214217526e7SJeff Layton 		spin_lock(&nn->client_lock);
42151da177e4SLinus Torvalds 	}
4216217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
4217217526e7SJeff Layton 
4218a832e7aeSJeff Layton 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
4219a832e7aeSJeff Layton 	return new_timeo;
42201da177e4SLinus Torvalds }
42211da177e4SLinus Torvalds 
4222a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq;
4223a254b246SHarvey Harrison static void laundromat_main(struct work_struct *);
4224a254b246SHarvey Harrison 
4225a254b246SHarvey Harrison static void
422609121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry)
42271da177e4SLinus Torvalds {
42281da177e4SLinus Torvalds 	time_t t;
422909121281SStanislav Kinsbursky 	struct delayed_work *dwork = container_of(laundry, struct delayed_work,
423009121281SStanislav Kinsbursky 						  work);
423109121281SStanislav Kinsbursky 	struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
423209121281SStanislav Kinsbursky 					   laundromat_work);
42331da177e4SLinus Torvalds 
423409121281SStanislav Kinsbursky 	t = nfs4_laundromat(nn);
42351da177e4SLinus Torvalds 	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
423609121281SStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
42371da177e4SLinus Torvalds }
42381da177e4SLinus Torvalds 
4239f7a4d872SJ. Bruce Fields static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
4240f8816512SNeilBrown {
424111b9164aSTrond Myklebust 	if (!nfsd_fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle))
4242f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
4243f7a4d872SJ. Bruce Fields 	return nfs_ok;
42441da177e4SLinus Torvalds }
42451da177e4SLinus Torvalds 
42461da177e4SLinus Torvalds static inline int
424782c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp)
42481da177e4SLinus Torvalds {
424982c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_READ, stp) ||
425082c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp) ||
425182c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_WRITE, stp);
42521da177e4SLinus Torvalds }
42531da177e4SLinus Torvalds 
42541da177e4SLinus Torvalds static inline int
425582c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp)
42561da177e4SLinus Torvalds {
425782c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_WRITE, stp) ||
425882c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp);
42591da177e4SLinus Torvalds }
42601da177e4SLinus Torvalds 
42611da177e4SLinus Torvalds static
4262dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
42631da177e4SLinus Torvalds {
4264b37ad28bSAl Viro         __be32 status = nfserr_openmode;
42651da177e4SLinus Torvalds 
426602921914SJ. Bruce Fields 	/* For lock stateid's, we test the parent open, not the lock: */
426702921914SJ. Bruce Fields 	if (stp->st_openstp)
426802921914SJ. Bruce Fields 		stp = stp->st_openstp;
426982c5ff1bSJeff Layton 	if ((flags & WR_STATE) && !access_permit_write(stp))
42701da177e4SLinus Torvalds                 goto out;
427182c5ff1bSJeff Layton 	if ((flags & RD_STATE) && !access_permit_read(stp))
42721da177e4SLinus Torvalds                 goto out;
42731da177e4SLinus Torvalds 	status = nfs_ok;
42741da177e4SLinus Torvalds out:
42751da177e4SLinus Torvalds 	return status;
42761da177e4SLinus Torvalds }
42771da177e4SLinus Torvalds 
4278b37ad28bSAl Viro static inline __be32
42795ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags)
42801da177e4SLinus Torvalds {
4281203a8c8eSJ. Bruce Fields 	if (ONE_STATEID(stateid) && (flags & RD_STATE))
42821da177e4SLinus Torvalds 		return nfs_ok;
42835ccb0066SStanislav Kinsbursky 	else if (locks_in_grace(net)) {
428425985edcSLucas De Marchi 		/* Answer in remaining cases depends on existence of
42851da177e4SLinus Torvalds 		 * conflicting state; so we must wait out the grace period. */
42861da177e4SLinus Torvalds 		return nfserr_grace;
42871da177e4SLinus Torvalds 	} else if (flags & WR_STATE)
42881da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
42891da177e4SLinus Torvalds 				NFS4_SHARE_DENY_WRITE);
42901da177e4SLinus Torvalds 	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
42911da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
42921da177e4SLinus Torvalds 				NFS4_SHARE_DENY_READ);
42931da177e4SLinus Torvalds }
42941da177e4SLinus Torvalds 
42951da177e4SLinus Torvalds /*
42961da177e4SLinus Torvalds  * Allow READ/WRITE during grace period on recovered state only for files
42971da177e4SLinus Torvalds  * that are not able to provide mandatory locking.
42981da177e4SLinus Torvalds  */
42991da177e4SLinus Torvalds static inline int
43005ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode)
43011da177e4SLinus Torvalds {
43025ccb0066SStanislav Kinsbursky 	return locks_in_grace(net) && mandatory_lock(inode);
43031da177e4SLinus Torvalds }
43041da177e4SLinus Torvalds 
430581b82965SJ. Bruce Fields /* Returns true iff a is later than b: */
430681b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b)
430781b82965SJ. Bruce Fields {
43081a9357f4SJim Rees 	return (s32)(a->si_generation - b->si_generation) > 0;
430981b82965SJ. Bruce Fields }
431081b82965SJ. Bruce Fields 
431157b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
43120836f587SJ. Bruce Fields {
43136668958fSAndy Adamson 	/*
43146668958fSAndy Adamson 	 * When sessions are used the stateid generation number is ignored
43156668958fSAndy Adamson 	 * when it is zero.
43166668958fSAndy Adamson 	 */
431728dde241SJ. Bruce Fields 	if (has_session && in->si_generation == 0)
431881b82965SJ. Bruce Fields 		return nfs_ok;
431981b82965SJ. Bruce Fields 
432081b82965SJ. Bruce Fields 	if (in->si_generation == ref->si_generation)
432181b82965SJ. Bruce Fields 		return nfs_ok;
43226668958fSAndy Adamson 
43230836f587SJ. Bruce Fields 	/* If the client sends us a stateid from the future, it's buggy: */
432481b82965SJ. Bruce Fields 	if (stateid_generation_after(in, ref))
43250836f587SJ. Bruce Fields 		return nfserr_bad_stateid;
43260836f587SJ. Bruce Fields 	/*
432781b82965SJ. Bruce Fields 	 * However, we could see a stateid from the past, even from a
432881b82965SJ. Bruce Fields 	 * non-buggy client.  For example, if the client sends a lock
432981b82965SJ. Bruce Fields 	 * while some IO is outstanding, the lock may bump si_generation
433081b82965SJ. Bruce Fields 	 * while the IO is still in flight.  The client could avoid that
433181b82965SJ. Bruce Fields 	 * situation by waiting for responses on all the IO requests,
433281b82965SJ. Bruce Fields 	 * but better performance may result in retrying IO that
433381b82965SJ. Bruce Fields 	 * receives an old_stateid error if requests are rarely
433481b82965SJ. Bruce Fields 	 * reordered in flight:
43350836f587SJ. Bruce Fields 	 */
43360836f587SJ. Bruce Fields 	return nfserr_old_stateid;
43370836f587SJ. Bruce Fields }
43380836f587SJ. Bruce Fields 
43397df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
434017456804SBryan Schumaker {
434197b7e3b6SJ. Bruce Fields 	struct nfs4_stid *s;
434297b7e3b6SJ. Bruce Fields 	struct nfs4_ol_stateid *ols;
43431af71cc8SJeff Layton 	__be32 status = nfserr_bad_stateid;
434417456804SBryan Schumaker 
43457df302f7SChuck Lever 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
43461af71cc8SJeff Layton 		return status;
43477df302f7SChuck Lever 	/* Client debugging aid. */
43487df302f7SChuck Lever 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
43497df302f7SChuck Lever 		char addr_str[INET6_ADDRSTRLEN];
43507df302f7SChuck Lever 		rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
43517df302f7SChuck Lever 				 sizeof(addr_str));
43527df302f7SChuck Lever 		pr_warn_ratelimited("NFSD: client %s testing state ID "
43537df302f7SChuck Lever 					"with incorrect client ID\n", addr_str);
43541af71cc8SJeff Layton 		return status;
43557df302f7SChuck Lever 	}
43561af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
43571af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
435897b7e3b6SJ. Bruce Fields 	if (!s)
43591af71cc8SJeff Layton 		goto out_unlock;
436036279ac1SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
436117456804SBryan Schumaker 	if (status)
43621af71cc8SJeff Layton 		goto out_unlock;
436323340032SJ. Bruce Fields 	switch (s->sc_type) {
436423340032SJ. Bruce Fields 	case NFS4_DELEG_STID:
43651af71cc8SJeff Layton 		status = nfs_ok;
43661af71cc8SJeff Layton 		break;
43673bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
43681af71cc8SJeff Layton 		status = nfserr_deleg_revoked;
43691af71cc8SJeff Layton 		break;
437023340032SJ. Bruce Fields 	case NFS4_OPEN_STID:
437123340032SJ. Bruce Fields 	case NFS4_LOCK_STID:
437297b7e3b6SJ. Bruce Fields 		ols = openlockstateid(s);
437397b7e3b6SJ. Bruce Fields 		if (ols->st_stateowner->so_is_open_owner
437423340032SJ. Bruce Fields 	    			&& !(openowner(ols->st_stateowner)->oo_flags
437523340032SJ. Bruce Fields 						& NFS4_OO_CONFIRMED))
43761af71cc8SJeff Layton 			status = nfserr_bad_stateid;
43771af71cc8SJeff Layton 		else
43781af71cc8SJeff Layton 			status = nfs_ok;
43791af71cc8SJeff Layton 		break;
438023340032SJ. Bruce Fields 	default:
438123340032SJ. Bruce Fields 		printk("unknown stateid type %x\n", s->sc_type);
4382b0fc29d6STrond Myklebust 		/* Fallthrough */
438323340032SJ. Bruce Fields 	case NFS4_CLOSED_STID:
4384b0fc29d6STrond Myklebust 	case NFS4_CLOSED_DELEG_STID:
43851af71cc8SJeff Layton 		status = nfserr_bad_stateid;
438623340032SJ. Bruce Fields 	}
43871af71cc8SJeff Layton out_unlock:
43881af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
43891af71cc8SJeff Layton 	return status;
439017456804SBryan Schumaker }
439117456804SBryan Schumaker 
43922dd6e458STrond Myklebust static __be32
43932dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
43942dd6e458STrond Myklebust 		     stateid_t *stateid, unsigned char typemask,
43952dd6e458STrond Myklebust 		     struct nfs4_stid **s, struct nfsd_net *nn)
439638c2f4b1SJ. Bruce Fields {
43970eb6f20aSJ. Bruce Fields 	__be32 status;
439838c2f4b1SJ. Bruce Fields 
439938c2f4b1SJ. Bruce Fields 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
440038c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
44014b24ca7dSJeff Layton 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
4402a8a7c677STrond Myklebust 	if (status == nfserr_stale_clientid) {
44034b24ca7dSJeff Layton 		if (cstate->session)
4404a8a7c677STrond Myklebust 			return nfserr_bad_stateid;
440538c2f4b1SJ. Bruce Fields 		return nfserr_stale_stateid;
4406a8a7c677STrond Myklebust 	}
44070eb6f20aSJ. Bruce Fields 	if (status)
44080eb6f20aSJ. Bruce Fields 		return status;
44094b24ca7dSJeff Layton 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
441038c2f4b1SJ. Bruce Fields 	if (!*s)
441138c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
441238c2f4b1SJ. Bruce Fields 	return nfs_ok;
441338c2f4b1SJ. Bruce Fields }
441438c2f4b1SJ. Bruce Fields 
44151da177e4SLinus Torvalds /*
44161da177e4SLinus Torvalds * Checks for stateid operations
44171da177e4SLinus Torvalds */
4418b37ad28bSAl Viro __be32
44195ccb0066SStanislav Kinsbursky nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
4420dd453dfdSBenny Halevy 			   stateid_t *stateid, int flags, struct file **filpp)
44211da177e4SLinus Torvalds {
442269064a27SJ. Bruce Fields 	struct nfs4_stid *s;
4423dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
44241da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
4425dd453dfdSBenny Halevy 	struct svc_fh *current_fh = &cstate->current_fh;
44261da177e4SLinus Torvalds 	struct inode *ino = current_fh->fh_dentry->d_inode;
44273320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
442814bcab1aSTrond Myklebust 	struct file *file = NULL;
4429b37ad28bSAl Viro 	__be32 status;
44301da177e4SLinus Torvalds 
44311da177e4SLinus Torvalds 	if (filpp)
44321da177e4SLinus Torvalds 		*filpp = NULL;
44331da177e4SLinus Torvalds 
44345ccb0066SStanislav Kinsbursky 	if (grace_disallows_io(net, ino))
44351da177e4SLinus Torvalds 		return nfserr_grace;
44361da177e4SLinus Torvalds 
44371da177e4SLinus Torvalds 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
44385ccb0066SStanislav Kinsbursky 		return check_special_stateids(net, current_fh, stateid, flags);
44391da177e4SLinus Torvalds 
44402dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid,
4441db24b3b4SJeff Layton 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
44422dd6e458STrond Myklebust 				&s, nn);
444338c2f4b1SJ. Bruce Fields 	if (status)
4444c2d1d6a8STrond Myklebust 		return status;
444569064a27SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
44460c2a498fSJ. Bruce Fields 	if (status)
44470c2a498fSJ. Bruce Fields 		goto out;
4448f7a4d872SJ. Bruce Fields 	switch (s->sc_type) {
4449f7a4d872SJ. Bruce Fields 	case NFS4_DELEG_STID:
445069064a27SJ. Bruce Fields 		dp = delegstateid(s);
4451dc9bf700SJ. Bruce Fields 		status = nfs4_check_delegmode(dp, flags);
4452dc9bf700SJ. Bruce Fields 		if (status)
4453dc9bf700SJ. Bruce Fields 			goto out;
445443b0178eSDan Carpenter 		if (filpp) {
445511b9164aSTrond Myklebust 			file = dp->dl_stid.sc_file->fi_deleg_file;
445614bcab1aSTrond Myklebust 			if (!file) {
4457063b0fb9SJ. Bruce Fields 				WARN_ON_ONCE(1);
4458063b0fb9SJ. Bruce Fields 				status = nfserr_serverfault;
4459063b0fb9SJ. Bruce Fields 				goto out;
4460063b0fb9SJ. Bruce Fields 			}
4461de18643dSTrond Myklebust 			get_file(file);
446243b0178eSDan Carpenter 		}
4463f7a4d872SJ. Bruce Fields 		break;
4464f7a4d872SJ. Bruce Fields 	case NFS4_OPEN_STID:
4465f7a4d872SJ. Bruce Fields 	case NFS4_LOCK_STID:
446669064a27SJ. Bruce Fields 		stp = openlockstateid(s);
4467f7a4d872SJ. Bruce Fields 		status = nfs4_check_fh(current_fh, stp);
4468f7a4d872SJ. Bruce Fields 		if (status)
44691da177e4SLinus Torvalds 			goto out;
4470fe0750e5SJ. Bruce Fields 		if (stp->st_stateowner->so_is_open_owner
4471dad1c067SJ. Bruce Fields 		    && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
44721da177e4SLinus Torvalds 			goto out;
4473a4455be0SJ. Bruce Fields 		status = nfs4_check_openmode(stp, flags);
4474a4455be0SJ. Bruce Fields 		if (status)
44751da177e4SLinus Torvalds 			goto out;
4476f9d7562fSJ. Bruce Fields 		if (filpp) {
447711b9164aSTrond Myklebust 			struct nfs4_file *fp = stp->st_stid.sc_file;
447811b9164aSTrond Myklebust 
4479f9d7562fSJ. Bruce Fields 			if (flags & RD_STATE)
448011b9164aSTrond Myklebust 				file = find_readable_file(fp);
4481f9d7562fSJ. Bruce Fields 			else
448211b9164aSTrond Myklebust 				file = find_writeable_file(fp);
4483f9d7562fSJ. Bruce Fields 		}
4484f7a4d872SJ. Bruce Fields 		break;
4485f7a4d872SJ. Bruce Fields 	default:
448614bcab1aSTrond Myklebust 		status = nfserr_bad_stateid;
448714bcab1aSTrond Myklebust 		goto out;
44881da177e4SLinus Torvalds 	}
44891da177e4SLinus Torvalds 	status = nfs_ok;
449014bcab1aSTrond Myklebust 	if (file)
4491de18643dSTrond Myklebust 		*filpp = file;
44921da177e4SLinus Torvalds out:
4493fd911011STrond Myklebust 	nfs4_put_stid(s);
44941da177e4SLinus Torvalds 	return status;
44951da177e4SLinus Torvalds }
44961da177e4SLinus Torvalds 
4497e1ca12dfSBryan Schumaker /*
449817456804SBryan Schumaker  * Test if the stateid is valid
449917456804SBryan Schumaker  */
450017456804SBryan Schumaker __be32
450117456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
450217456804SBryan Schumaker 		   struct nfsd4_test_stateid *test_stateid)
450317456804SBryan Schumaker {
450403cfb420SBryan Schumaker 	struct nfsd4_test_stateid_id *stateid;
450503cfb420SBryan Schumaker 	struct nfs4_client *cl = cstate->session->se_client;
450603cfb420SBryan Schumaker 
450703cfb420SBryan Schumaker 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
45087df302f7SChuck Lever 		stateid->ts_id_status =
45097df302f7SChuck Lever 			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
451003cfb420SBryan Schumaker 
451117456804SBryan Schumaker 	return nfs_ok;
451217456804SBryan Schumaker }
451317456804SBryan Schumaker 
4514e1ca12dfSBryan Schumaker __be32
4515e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4516e1ca12dfSBryan Schumaker 		   struct nfsd4_free_stateid *free_stateid)
4517e1ca12dfSBryan Schumaker {
4518e1ca12dfSBryan Schumaker 	stateid_t *stateid = &free_stateid->fr_stateid;
45192da1cec7SJ. Bruce Fields 	struct nfs4_stid *s;
45203bd64a5bSJ. Bruce Fields 	struct nfs4_delegation *dp;
4521fc5a96c3SJeff Layton 	struct nfs4_ol_stateid *stp;
452238c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = cstate->session->se_client;
45232da1cec7SJ. Bruce Fields 	__be32 ret = nfserr_bad_stateid;
4524e1ca12dfSBryan Schumaker 
45251af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
45261af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
45272da1cec7SJ. Bruce Fields 	if (!s)
45281af71cc8SJeff Layton 		goto out_unlock;
45292da1cec7SJ. Bruce Fields 	switch (s->sc_type) {
45302da1cec7SJ. Bruce Fields 	case NFS4_DELEG_STID:
4531e1ca12dfSBryan Schumaker 		ret = nfserr_locks_held;
45321af71cc8SJeff Layton 		break;
45332da1cec7SJ. Bruce Fields 	case NFS4_OPEN_STID:
45341af71cc8SJeff Layton 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
45351af71cc8SJeff Layton 		if (ret)
45361af71cc8SJeff Layton 			break;
45371af71cc8SJeff Layton 		ret = nfserr_locks_held;
45381af71cc8SJeff Layton 		break;
45392da1cec7SJ. Bruce Fields 	case NFS4_LOCK_STID:
45402da1cec7SJ. Bruce Fields 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
45412da1cec7SJ. Bruce Fields 		if (ret)
4542f7a4d872SJ. Bruce Fields 			break;
4543fc5a96c3SJeff Layton 		stp = openlockstateid(s);
4544fc5a96c3SJeff Layton 		ret = nfserr_locks_held;
4545fc5a96c3SJeff Layton 		if (check_for_locks(stp->st_stid.sc_file,
4546fc5a96c3SJeff Layton 				    lockowner(stp->st_stateowner)))
4547fc5a96c3SJeff Layton 			break;
4548fc5a96c3SJeff Layton 		unhash_lock_stateid(stp);
45491af71cc8SJeff Layton 		spin_unlock(&cl->cl_lock);
4550fc5a96c3SJeff Layton 		nfs4_put_stid(s);
4551fc5a96c3SJeff Layton 		ret = nfs_ok;
45521af71cc8SJeff Layton 		goto out;
45533bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
45543bd64a5bSJ. Bruce Fields 		dp = delegstateid(s);
45552d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
45562d4a532dSJeff Layton 		spin_unlock(&cl->cl_lock);
45576011695dSTrond Myklebust 		nfs4_put_stid(s);
45583bd64a5bSJ. Bruce Fields 		ret = nfs_ok;
45591af71cc8SJeff Layton 		goto out;
45601af71cc8SJeff Layton 	/* Default falls through and returns nfserr_bad_stateid */
4561e1ca12dfSBryan Schumaker 	}
45621af71cc8SJeff Layton out_unlock:
45631af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
4564e1ca12dfSBryan Schumaker out:
4565e1ca12dfSBryan Schumaker 	return ret;
4566e1ca12dfSBryan Schumaker }
4567e1ca12dfSBryan Schumaker 
45684c4cd222SNeilBrown static inline int
45694c4cd222SNeilBrown setlkflg (int type)
45704c4cd222SNeilBrown {
45714c4cd222SNeilBrown 	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
45724c4cd222SNeilBrown 		RD_STATE : WR_STATE;
45734c4cd222SNeilBrown }
45741da177e4SLinus Torvalds 
4575dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
4576c0a5d93eSJ. Bruce Fields {
4577c0a5d93eSJ. Bruce Fields 	struct svc_fh *current_fh = &cstate->current_fh;
4578c0a5d93eSJ. Bruce Fields 	struct nfs4_stateowner *sop = stp->st_stateowner;
4579c0a5d93eSJ. Bruce Fields 	__be32 status;
4580c0a5d93eSJ. Bruce Fields 
4581c0a5d93eSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, sop, seqid);
4582c0a5d93eSJ. Bruce Fields 	if (status)
4583c0a5d93eSJ. Bruce Fields 		return status;
45843bd64a5bSJ. Bruce Fields 	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
45853bd64a5bSJ. Bruce Fields 		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
4586f7a4d872SJ. Bruce Fields 		/*
4587f7a4d872SJ. Bruce Fields 		 * "Closed" stateid's exist *only* to return
45883bd64a5bSJ. Bruce Fields 		 * nfserr_replay_me from the previous step, and
45893bd64a5bSJ. Bruce Fields 		 * revoked delegations are kept only for free_stateid.
4590f7a4d872SJ. Bruce Fields 		 */
4591f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
4592f7a4d872SJ. Bruce Fields 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
4593f7a4d872SJ. Bruce Fields 	if (status)
4594f7a4d872SJ. Bruce Fields 		return status;
4595f7a4d872SJ. Bruce Fields 	return nfs4_check_fh(current_fh, stp);
4596c0a5d93eSJ. Bruce Fields }
4597c0a5d93eSJ. Bruce Fields 
45981da177e4SLinus Torvalds /*
45991da177e4SLinus Torvalds  * Checks for sequence id mutating operations.
46001da177e4SLinus Torvalds  */
4601b37ad28bSAl Viro static __be32
4602dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
46032288d0e3SJ. Bruce Fields 			 stateid_t *stateid, char typemask,
46043320fef1SStanislav Kinsbursky 			 struct nfs4_ol_stateid **stpp,
46053320fef1SStanislav Kinsbursky 			 struct nfsd_net *nn)
46061da177e4SLinus Torvalds {
46070836f587SJ. Bruce Fields 	__be32 status;
460838c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
4609e17f99b7STrond Myklebust 	struct nfs4_ol_stateid *stp = NULL;
46101da177e4SLinus Torvalds 
46118c10cbdbSBenny Halevy 	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
46128c10cbdbSBenny Halevy 		seqid, STATEID_VAL(stateid));
46131da177e4SLinus Torvalds 
46141da177e4SLinus Torvalds 	*stpp = NULL;
46152dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn);
4616c0a5d93eSJ. Bruce Fields 	if (status)
4617c0a5d93eSJ. Bruce Fields 		return status;
4618e17f99b7STrond Myklebust 	stp = openlockstateid(s);
461958fb12e6SJeff Layton 	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
46201da177e4SLinus Torvalds 
4621e17f99b7STrond Myklebust 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
4622fd911011STrond Myklebust 	if (!status)
4623e17f99b7STrond Myklebust 		*stpp = stp;
4624fd911011STrond Myklebust 	else
4625fd911011STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
4626e17f99b7STrond Myklebust 	return status;
46271da177e4SLinus Torvalds }
46281da177e4SLinus Torvalds 
46293320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
46303320fef1SStanislav Kinsbursky 						 stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn)
4631c0a5d93eSJ. Bruce Fields {
4632c0a5d93eSJ. Bruce Fields 	__be32 status;
4633c0a5d93eSJ. Bruce Fields 	struct nfs4_openowner *oo;
46344cbfc9f7STrond Myklebust 	struct nfs4_ol_stateid *stp;
46351da177e4SLinus Torvalds 
4636c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
46374cbfc9f7STrond Myklebust 						NFS4_OPEN_STID, &stp, nn);
46380836f587SJ. Bruce Fields 	if (status)
46390836f587SJ. Bruce Fields 		return status;
46404cbfc9f7STrond Myklebust 	oo = openowner(stp->st_stateowner);
46414cbfc9f7STrond Myklebust 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
46424cbfc9f7STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
4643c0a5d93eSJ. Bruce Fields 		return nfserr_bad_stateid;
46444cbfc9f7STrond Myklebust 	}
46454cbfc9f7STrond Myklebust 	*stpp = stp;
46463a4f98bbSNeilBrown 	return nfs_ok;
46471da177e4SLinus Torvalds }
46481da177e4SLinus Torvalds 
4649b37ad28bSAl Viro __be32
4650ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4651a4f1706aSJ.Bruce Fields 		   struct nfsd4_open_confirm *oc)
46521da177e4SLinus Torvalds {
4653b37ad28bSAl Viro 	__be32 status;
4654fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
4655dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
46563320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
46571da177e4SLinus Torvalds 
4658a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_confirm on file %pd\n",
4659a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
46601da177e4SLinus Torvalds 
4661ca364317SJ.Bruce Fields 	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
4662a8cddc5dSJ. Bruce Fields 	if (status)
4663a8cddc5dSJ. Bruce Fields 		return status;
46641da177e4SLinus Torvalds 
46659072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate,
4666ca364317SJ.Bruce Fields 					oc->oc_seqid, &oc->oc_req_stateid,
46673320fef1SStanislav Kinsbursky 					NFS4_OPEN_STID, &stp, nn);
46689072d5c6SJ. Bruce Fields 	if (status)
46691da177e4SLinus Torvalds 		goto out;
4670fe0750e5SJ. Bruce Fields 	oo = openowner(stp->st_stateowner);
467168b66e82SJ. Bruce Fields 	status = nfserr_bad_stateid;
4672dad1c067SJ. Bruce Fields 	if (oo->oo_flags & NFS4_OO_CONFIRMED)
46732585fc79STrond Myklebust 		goto put_stateid;
4674dad1c067SJ. Bruce Fields 	oo->oo_flags |= NFS4_OO_CONFIRMED;
4675dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4676dcef0413SJ. Bruce Fields 	memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
46778c10cbdbSBenny Halevy 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
4678dcef0413SJ. Bruce Fields 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
4679c7b9a459SNeilBrown 
46802a4317c5SJeff Layton 	nfsd4_client_record_create(oo->oo_owner.so_client);
468168b66e82SJ. Bruce Fields 	status = nfs_ok;
46822585fc79STrond Myklebust put_stateid:
46832585fc79STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
46841da177e4SLinus Torvalds out:
46859411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
46861da177e4SLinus Torvalds 	return status;
46871da177e4SLinus Torvalds }
46881da177e4SLinus Torvalds 
46896409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
46901da177e4SLinus Torvalds {
469182c5ff1bSJeff Layton 	if (!test_access(access, stp))
46926409a5a6SJ. Bruce Fields 		return;
469311b9164aSTrond Myklebust 	nfs4_file_put_access(stp->st_stid.sc_file, access);
469482c5ff1bSJeff Layton 	clear_access(access, stp);
4695f197c271SJ. Bruce Fields }
46966409a5a6SJ. Bruce Fields 
46976409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
46986409a5a6SJ. Bruce Fields {
46996409a5a6SJ. Bruce Fields 	switch (to_access) {
47006409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
47016409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
47026409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
47036409a5a6SJ. Bruce Fields 		break;
47046409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
47056409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
47066409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
47076409a5a6SJ. Bruce Fields 		break;
47086409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
47096409a5a6SJ. Bruce Fields 		break;
47106409a5a6SJ. Bruce Fields 	default:
4711063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
47121da177e4SLinus Torvalds 	}
47131da177e4SLinus Torvalds }
47141da177e4SLinus Torvalds 
4715b37ad28bSAl Viro __be32
4716ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp,
4717ca364317SJ.Bruce Fields 		     struct nfsd4_compound_state *cstate,
4718a4f1706aSJ.Bruce Fields 		     struct nfsd4_open_downgrade *od)
47191da177e4SLinus Torvalds {
4720b37ad28bSAl Viro 	__be32 status;
4721dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
47223320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
47231da177e4SLinus Torvalds 
4724a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_downgrade on file %pd\n",
4725a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
47261da177e4SLinus Torvalds 
4727c30e92dfSJ. Bruce Fields 	/* We don't yet support WANT bits: */
47282c8bd7e0SBenny Halevy 	if (od->od_deleg_want)
47292c8bd7e0SBenny Halevy 		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
47302c8bd7e0SBenny Halevy 			od->od_deleg_want);
47311da177e4SLinus Torvalds 
4732c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
47333320fef1SStanislav Kinsbursky 					&od->od_stateid, &stp, nn);
47349072d5c6SJ. Bruce Fields 	if (status)
47351da177e4SLinus Torvalds 		goto out;
47361da177e4SLinus Torvalds 	status = nfserr_inval;
473782c5ff1bSJeff Layton 	if (!test_access(od->od_share_access, stp)) {
4738c11c591fSJeff Layton 		dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n",
47391da177e4SLinus Torvalds 			stp->st_access_bmap, od->od_share_access);
47400667b1e9STrond Myklebust 		goto put_stateid;
47411da177e4SLinus Torvalds 	}
4742ce0fc43cSJeff Layton 	if (!test_deny(od->od_share_deny, stp)) {
4743c11c591fSJeff Layton 		dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n",
47441da177e4SLinus Torvalds 			stp->st_deny_bmap, od->od_share_deny);
47450667b1e9STrond Myklebust 		goto put_stateid;
47461da177e4SLinus Torvalds 	}
47476409a5a6SJ. Bruce Fields 	nfs4_stateid_downgrade(stp, od->od_share_access);
47481da177e4SLinus Torvalds 
4749ce0fc43cSJeff Layton 	reset_union_bmap_deny(od->od_share_deny, stp);
47501da177e4SLinus Torvalds 
4751dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4752dcef0413SJ. Bruce Fields 	memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
47531da177e4SLinus Torvalds 	status = nfs_ok;
47540667b1e9STrond Myklebust put_stateid:
47550667b1e9STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
47561da177e4SLinus Torvalds out:
47579411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
47581da177e4SLinus Torvalds 	return status;
47591da177e4SLinus Torvalds }
47601da177e4SLinus Torvalds 
4761f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
4762f7a4d872SJ. Bruce Fields {
4763acf9295bSTrond Myklebust 	struct nfs4_client *clp = s->st_stid.sc_client;
4764d83017f9SJeff Layton 	LIST_HEAD(reaplist);
4765acf9295bSTrond Myklebust 
4766f7a4d872SJ. Bruce Fields 	s->st_stid.sc_type = NFS4_CLOSED_STID;
47672c41beb0SJeff Layton 	spin_lock(&clp->cl_lock);
4768d83017f9SJeff Layton 	unhash_open_stateid(s, &reaplist);
4769acf9295bSTrond Myklebust 
4770d83017f9SJeff Layton 	if (clp->cl_minorversion) {
4771d83017f9SJeff Layton 		put_ol_stateid_locked(s, &reaplist);
4772d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
4773d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
4774d83017f9SJeff Layton 	} else {
4775d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
4776d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
4777d3134b10SJeff Layton 		move_to_close_lru(s, clp->net);
477838c387b5SJ. Bruce Fields 	}
4779d83017f9SJeff Layton }
478038c387b5SJ. Bruce Fields 
47811da177e4SLinus Torvalds /*
47821da177e4SLinus Torvalds  * nfs4_unlock_state() called after encode
47831da177e4SLinus Torvalds  */
4784b37ad28bSAl Viro __be32
4785ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4786a4f1706aSJ.Bruce Fields 	    struct nfsd4_close *close)
47871da177e4SLinus Torvalds {
4788b37ad28bSAl Viro 	__be32 status;
4789dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
47903320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
47913320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
47921da177e4SLinus Torvalds 
4793a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_close on file %pd\n",
4794a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
47951da177e4SLinus Torvalds 
4796f7a4d872SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
4797f7a4d872SJ. Bruce Fields 					&close->cl_stateid,
4798f7a4d872SJ. Bruce Fields 					NFS4_OPEN_STID|NFS4_CLOSED_STID,
47993320fef1SStanislav Kinsbursky 					&stp, nn);
48009411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
48019072d5c6SJ. Bruce Fields 	if (status)
48021da177e4SLinus Torvalds 		goto out;
4803dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4804dcef0413SJ. Bruce Fields 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
48051da177e4SLinus Torvalds 
4806f7a4d872SJ. Bruce Fields 	nfsd4_close_open_stateid(stp);
48078a0b589dSTrond Myklebust 
48088a0b589dSTrond Myklebust 	/* put reference from nfs4_preprocess_seqid_op */
48098a0b589dSTrond Myklebust 	nfs4_put_stid(&stp->st_stid);
48101da177e4SLinus Torvalds out:
48111da177e4SLinus Torvalds 	return status;
48121da177e4SLinus Torvalds }
48131da177e4SLinus Torvalds 
4814b37ad28bSAl Viro __be32
4815ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4816ca364317SJ.Bruce Fields 		  struct nfsd4_delegreturn *dr)
48171da177e4SLinus Torvalds {
4818203a8c8eSJ. Bruce Fields 	struct nfs4_delegation *dp;
4819203a8c8eSJ. Bruce Fields 	stateid_t *stateid = &dr->dr_stateid;
482038c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
4821b37ad28bSAl Viro 	__be32 status;
48223320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
48231da177e4SLinus Torvalds 
4824ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
4825203a8c8eSJ. Bruce Fields 		return status;
48261da177e4SLinus Torvalds 
48272dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
482838c2f4b1SJ. Bruce Fields 	if (status)
4829203a8c8eSJ. Bruce Fields 		goto out;
483038c2f4b1SJ. Bruce Fields 	dp = delegstateid(s);
4831d5477a8dSJ. Bruce Fields 	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
4832203a8c8eSJ. Bruce Fields 	if (status)
4833fd911011STrond Myklebust 		goto put_stateid;
4834203a8c8eSJ. Bruce Fields 
48353bd64a5bSJ. Bruce Fields 	destroy_delegation(dp);
4836fd911011STrond Myklebust put_stateid:
4837fd911011STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
48381da177e4SLinus Torvalds out:
48391da177e4SLinus Torvalds 	return status;
48401da177e4SLinus Torvalds }
48411da177e4SLinus Torvalds 
48421da177e4SLinus Torvalds 
48431da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
48441da177e4SLinus Torvalds 
484587df4de8SBenny Halevy static inline u64
484687df4de8SBenny Halevy end_offset(u64 start, u64 len)
484787df4de8SBenny Halevy {
484887df4de8SBenny Halevy 	u64 end;
484987df4de8SBenny Halevy 
485087df4de8SBenny Halevy 	end = start + len;
485187df4de8SBenny Halevy 	return end >= start ? end: NFS4_MAX_UINT64;
485287df4de8SBenny Halevy }
485387df4de8SBenny Halevy 
485487df4de8SBenny Halevy /* last octet in a range */
485587df4de8SBenny Halevy static inline u64
485687df4de8SBenny Halevy last_byte_offset(u64 start, u64 len)
485787df4de8SBenny Halevy {
485887df4de8SBenny Halevy 	u64 end;
485987df4de8SBenny Halevy 
4860063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(!len);
486187df4de8SBenny Halevy 	end = start + len;
486287df4de8SBenny Halevy 	return end > start ? end - 1: NFS4_MAX_UINT64;
486387df4de8SBenny Halevy }
486487df4de8SBenny Halevy 
48651da177e4SLinus Torvalds /*
48661da177e4SLinus Torvalds  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
48671da177e4SLinus Torvalds  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
48681da177e4SLinus Torvalds  * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
48691da177e4SLinus Torvalds  * locking, this prevents us from being completely protocol-compliant.  The
48701da177e4SLinus Torvalds  * real solution to this problem is to start using unsigned file offsets in
48711da177e4SLinus Torvalds  * the VFS, but this is a very deep change!
48721da177e4SLinus Torvalds  */
48731da177e4SLinus Torvalds static inline void
48741da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock)
48751da177e4SLinus Torvalds {
48761da177e4SLinus Torvalds 	if (lock->fl_start < 0)
48771da177e4SLinus Torvalds 		lock->fl_start = OFFSET_MAX;
48781da177e4SLinus Torvalds 	if (lock->fl_end < 0)
48791da177e4SLinus Torvalds 		lock->fl_end = OFFSET_MAX;
48801da177e4SLinus Torvalds }
48811da177e4SLinus Torvalds 
4882aef9583bSKinglong Mee static void nfsd4_fl_get_owner(struct file_lock *dst, struct file_lock *src)
4883aef9583bSKinglong Mee {
4884aef9583bSKinglong Mee 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)src->fl_owner;
4885aef9583bSKinglong Mee 	dst->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lo->lo_owner));
4886aef9583bSKinglong Mee }
4887aef9583bSKinglong Mee 
4888aef9583bSKinglong Mee static void nfsd4_fl_put_owner(struct file_lock *fl)
4889aef9583bSKinglong Mee {
4890aef9583bSKinglong Mee 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner;
4891aef9583bSKinglong Mee 
4892aef9583bSKinglong Mee 	if (lo) {
4893aef9583bSKinglong Mee 		nfs4_put_stateowner(&lo->lo_owner);
4894aef9583bSKinglong Mee 		fl->fl_owner = NULL;
4895aef9583bSKinglong Mee 	}
4896aef9583bSKinglong Mee }
4897aef9583bSKinglong Mee 
48987b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops  = {
4899aef9583bSKinglong Mee 	.lm_get_owner = nfsd4_fl_get_owner,
4900aef9583bSKinglong Mee 	.lm_put_owner = nfsd4_fl_put_owner,
4901d5b9026aSNeilBrown };
49021da177e4SLinus Torvalds 
49031da177e4SLinus Torvalds static inline void
49041da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
49051da177e4SLinus Torvalds {
4906fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
49071da177e4SLinus Torvalds 
4908d5b9026aSNeilBrown 	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
4909fe0750e5SJ. Bruce Fields 		lo = (struct nfs4_lockowner *) fl->fl_owner;
4910fe0750e5SJ. Bruce Fields 		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
4911fe0750e5SJ. Bruce Fields 					lo->lo_owner.so_owner.len, GFP_KERNEL);
49127c13f344SJ. Bruce Fields 		if (!deny->ld_owner.data)
49137c13f344SJ. Bruce Fields 			/* We just don't care that much */
49147c13f344SJ. Bruce Fields 			goto nevermind;
4915fe0750e5SJ. Bruce Fields 		deny->ld_owner.len = lo->lo_owner.so_owner.len;
4916fe0750e5SJ. Bruce Fields 		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
4917d5b9026aSNeilBrown 	} else {
49187c13f344SJ. Bruce Fields nevermind:
49197c13f344SJ. Bruce Fields 		deny->ld_owner.len = 0;
49207c13f344SJ. Bruce Fields 		deny->ld_owner.data = NULL;
4921d5b9026aSNeilBrown 		deny->ld_clientid.cl_boot = 0;
4922d5b9026aSNeilBrown 		deny->ld_clientid.cl_id = 0;
49231da177e4SLinus Torvalds 	}
49241da177e4SLinus Torvalds 	deny->ld_start = fl->fl_start;
492587df4de8SBenny Halevy 	deny->ld_length = NFS4_MAX_UINT64;
492687df4de8SBenny Halevy 	if (fl->fl_end != NFS4_MAX_UINT64)
49271da177e4SLinus Torvalds 		deny->ld_length = fl->fl_end - fl->fl_start + 1;
49281da177e4SLinus Torvalds 	deny->ld_type = NFS4_READ_LT;
49291da177e4SLinus Torvalds 	if (fl->fl_type != F_RDLCK)
49301da177e4SLinus Torvalds 		deny->ld_type = NFS4_WRITE_LT;
49311da177e4SLinus Torvalds }
49321da177e4SLinus Torvalds 
4933fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
4934c58c6610STrond Myklebust find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
4935d4f0489fSTrond Myklebust 		struct nfs4_client *clp)
49361da177e4SLinus Torvalds {
4937d4f0489fSTrond Myklebust 	unsigned int strhashval = ownerstr_hashval(owner);
4938b3c32bcdSTrond Myklebust 	struct nfs4_stateowner *so;
49391da177e4SLinus Torvalds 
49400a880a28STrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
49410a880a28STrond Myklebust 
4942d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval],
4943d4f0489fSTrond Myklebust 			    so_strhash) {
4944b3c32bcdSTrond Myklebust 		if (so->so_is_open_owner)
4945b3c32bcdSTrond Myklebust 			continue;
4946b5971afaSKinglong Mee 		if (same_owner_str(so, owner))
4947b5971afaSKinglong Mee 			return lockowner(nfs4_get_stateowner(so));
49481da177e4SLinus Torvalds 	}
49491da177e4SLinus Torvalds 	return NULL;
49501da177e4SLinus Torvalds }
49511da177e4SLinus Torvalds 
4952c58c6610STrond Myklebust static struct nfs4_lockowner *
4953c58c6610STrond Myklebust find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
4954d4f0489fSTrond Myklebust 		struct nfs4_client *clp)
4955c58c6610STrond Myklebust {
4956c58c6610STrond Myklebust 	struct nfs4_lockowner *lo;
4957c58c6610STrond Myklebust 
4958d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
4959d4f0489fSTrond Myklebust 	lo = find_lockowner_str_locked(clid, owner, clp);
4960d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
4961c58c6610STrond Myklebust 	return lo;
4962c58c6610STrond Myklebust }
4963c58c6610STrond Myklebust 
49648f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
49658f4b54c5SJeff Layton {
4966c58c6610STrond Myklebust 	unhash_lockowner_locked(lockowner(sop));
49678f4b54c5SJeff Layton }
49688f4b54c5SJeff Layton 
49696b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
49706b180f0bSJeff Layton {
49716b180f0bSJeff Layton 	struct nfs4_lockowner *lo = lockowner(sop);
49726b180f0bSJeff Layton 
49736b180f0bSJeff Layton 	kmem_cache_free(lockowner_slab, lo);
49746b180f0bSJeff Layton }
49756b180f0bSJeff Layton 
49766b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = {
49778f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_lockowner,
49786b180f0bSJeff Layton 	.so_free =	nfs4_free_lockowner,
49796b180f0bSJeff Layton };
49806b180f0bSJeff Layton 
49811da177e4SLinus Torvalds /*
49821da177e4SLinus Torvalds  * Alloc a lock owner structure.
49831da177e4SLinus Torvalds  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
498425985edcSLucas De Marchi  * occurred.
49851da177e4SLinus Torvalds  *
498616bfdaafSJ. Bruce Fields  * strhashval = ownerstr_hashval
49871da177e4SLinus Torvalds  */
4988fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
4989c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
4990c58c6610STrond Myklebust 			   struct nfs4_ol_stateid *open_stp,
4991c58c6610STrond Myklebust 			   struct nfsd4_lock *lock)
4992c58c6610STrond Myklebust {
4993c58c6610STrond Myklebust 	struct nfs4_lockowner *lo, *ret;
49941da177e4SLinus Torvalds 
4995fe0750e5SJ. Bruce Fields 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
4996fe0750e5SJ. Bruce Fields 	if (!lo)
49971da177e4SLinus Torvalds 		return NULL;
4998fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
4999fe0750e5SJ. Bruce Fields 	lo->lo_owner.so_is_open_owner = 0;
50005db1c03fSJeff Layton 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
50016b180f0bSJeff Layton 	lo->lo_owner.so_ops = &lockowner_ops;
5002d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5003c58c6610STrond Myklebust 	ret = find_lockowner_str_locked(&clp->cl_clientid,
5004d4f0489fSTrond Myklebust 			&lock->lk_new_owner, clp);
5005c58c6610STrond Myklebust 	if (ret == NULL) {
5006c58c6610STrond Myklebust 		list_add(&lo->lo_owner.so_strhash,
5007d4f0489fSTrond Myklebust 			 &clp->cl_ownerstr_hashtbl[strhashval]);
5008c58c6610STrond Myklebust 		ret = lo;
5009c58c6610STrond Myklebust 	} else
5010c58c6610STrond Myklebust 		nfs4_free_lockowner(&lo->lo_owner);
5011d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5012fe0750e5SJ. Bruce Fields 	return lo;
50131da177e4SLinus Torvalds }
50141da177e4SLinus Torvalds 
5015356a95ecSJeff Layton static void
5016356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5017356a95ecSJeff Layton 		  struct nfs4_file *fp, struct inode *inode,
5018f9c00c3aSJeff Layton 		  struct nfs4_ol_stateid *open_stp)
50191da177e4SLinus Torvalds {
5020d3b313a4SJ. Bruce Fields 	struct nfs4_client *clp = lo->lo_owner.so_client;
50211da177e4SLinus Torvalds 
5022356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5023356a95ecSJeff Layton 
50243d0fabd5STrond Myklebust 	atomic_inc(&stp->st_stid.sc_count);
50253abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_LOCK_STID;
5026b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
502713cd2184SNeilBrown 	get_nfs4_file(fp);
502811b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
5029b49e084dSJeff Layton 	stp->st_stid.sc_free = nfs4_free_lock_stateid;
50300997b173SJ. Bruce Fields 	stp->st_access_bmap = 0;
50311da177e4SLinus Torvalds 	stp->st_deny_bmap = open_stp->st_deny_bmap;
50324c4cd222SNeilBrown 	stp->st_openstp = open_stp;
50333c87b9b7STrond Myklebust 	list_add(&stp->st_locks, &open_stp->st_locks);
50341c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
50351d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
50361d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
50371d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
50381da177e4SLinus Torvalds }
50391da177e4SLinus Torvalds 
5040c53530daSJeff Layton static struct nfs4_ol_stateid *
5041c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
5042c53530daSJeff Layton {
5043c53530daSJeff Layton 	struct nfs4_ol_stateid *lst;
5044356a95ecSJeff Layton 	struct nfs4_client *clp = lo->lo_owner.so_client;
5045356a95ecSJeff Layton 
5046356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5047c53530daSJeff Layton 
5048c53530daSJeff Layton 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
50493d0fabd5STrond Myklebust 		if (lst->st_stid.sc_file == fp) {
50503d0fabd5STrond Myklebust 			atomic_inc(&lst->st_stid.sc_count);
5051c53530daSJeff Layton 			return lst;
5052c53530daSJeff Layton 		}
50533d0fabd5STrond Myklebust 	}
5054c53530daSJeff Layton 	return NULL;
5055c53530daSJeff Layton }
5056c53530daSJeff Layton 
5057356a95ecSJeff Layton static struct nfs4_ol_stateid *
5058356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
5059356a95ecSJeff Layton 			    struct inode *inode, struct nfs4_ol_stateid *ost,
5060356a95ecSJeff Layton 			    bool *new)
5061356a95ecSJeff Layton {
5062356a95ecSJeff Layton 	struct nfs4_stid *ns = NULL;
5063356a95ecSJeff Layton 	struct nfs4_ol_stateid *lst;
5064356a95ecSJeff Layton 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
5065356a95ecSJeff Layton 	struct nfs4_client *clp = oo->oo_owner.so_client;
5066356a95ecSJeff Layton 
5067356a95ecSJeff Layton 	spin_lock(&clp->cl_lock);
5068356a95ecSJeff Layton 	lst = find_lock_stateid(lo, fi);
5069356a95ecSJeff Layton 	if (lst == NULL) {
5070356a95ecSJeff Layton 		spin_unlock(&clp->cl_lock);
5071356a95ecSJeff Layton 		ns = nfs4_alloc_stid(clp, stateid_slab);
5072356a95ecSJeff Layton 		if (ns == NULL)
5073356a95ecSJeff Layton 			return NULL;
5074356a95ecSJeff Layton 
5075356a95ecSJeff Layton 		spin_lock(&clp->cl_lock);
5076356a95ecSJeff Layton 		lst = find_lock_stateid(lo, fi);
5077356a95ecSJeff Layton 		if (likely(!lst)) {
5078356a95ecSJeff Layton 			lst = openlockstateid(ns);
5079356a95ecSJeff Layton 			init_lock_stateid(lst, lo, fi, inode, ost);
5080356a95ecSJeff Layton 			ns = NULL;
5081356a95ecSJeff Layton 			*new = true;
5082356a95ecSJeff Layton 		}
5083356a95ecSJeff Layton 	}
5084356a95ecSJeff Layton 	spin_unlock(&clp->cl_lock);
5085356a95ecSJeff Layton 	if (ns)
5086356a95ecSJeff Layton 		nfs4_put_stid(ns);
5087356a95ecSJeff Layton 	return lst;
5088356a95ecSJeff Layton }
5089c53530daSJeff Layton 
5090fd39ca9aSNeilBrown static int
50911da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length)
50921da177e4SLinus Torvalds {
509387df4de8SBenny Halevy 	return ((length == 0)  || ((length != NFS4_MAX_UINT64) &&
50941da177e4SLinus Torvalds 	     LOFF_OVERFLOW(offset, length)));
50951da177e4SLinus Torvalds }
50961da177e4SLinus Torvalds 
5097dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
50980997b173SJ. Bruce Fields {
509911b9164aSTrond Myklebust 	struct nfs4_file *fp = lock_stp->st_stid.sc_file;
51000997b173SJ. Bruce Fields 
51017214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
51027214e860SJeff Layton 
510382c5ff1bSJeff Layton 	if (test_access(access, lock_stp))
51040997b173SJ. Bruce Fields 		return;
510512659651SJeff Layton 	__nfs4_file_get_access(fp, access);
510682c5ff1bSJeff Layton 	set_access(access, lock_stp);
51070997b173SJ. Bruce Fields }
51080997b173SJ. Bruce Fields 
5109356a95ecSJeff Layton static __be32
5110356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5111356a95ecSJeff Layton 			    struct nfs4_ol_stateid *ost,
5112356a95ecSJeff Layton 			    struct nfsd4_lock *lock,
5113356a95ecSJeff Layton 			    struct nfs4_ol_stateid **lst, bool *new)
511464a284d0SJ. Bruce Fields {
51155db1c03fSJeff Layton 	__be32 status;
511611b9164aSTrond Myklebust 	struct nfs4_file *fi = ost->st_stid.sc_file;
511764a284d0SJ. Bruce Fields 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
511864a284d0SJ. Bruce Fields 	struct nfs4_client *cl = oo->oo_owner.so_client;
5119f9c00c3aSJeff Layton 	struct inode *inode = cstate->current_fh.fh_dentry->d_inode;
512064a284d0SJ. Bruce Fields 	struct nfs4_lockowner *lo;
512164a284d0SJ. Bruce Fields 	unsigned int strhashval;
512264a284d0SJ. Bruce Fields 
5123d4f0489fSTrond Myklebust 	lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, cl);
5124c53530daSJeff Layton 	if (!lo) {
5125d4f0489fSTrond Myklebust 		strhashval = ownerstr_hashval(&lock->v.new.owner);
512664a284d0SJ. Bruce Fields 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
512764a284d0SJ. Bruce Fields 		if (lo == NULL)
512864a284d0SJ. Bruce Fields 			return nfserr_jukebox;
5129c53530daSJeff Layton 	} else {
5130c53530daSJeff Layton 		/* with an existing lockowner, seqids must be the same */
51315db1c03fSJeff Layton 		status = nfserr_bad_seqid;
5132c53530daSJeff Layton 		if (!cstate->minorversion &&
5133c53530daSJeff Layton 		    lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
51345db1c03fSJeff Layton 			goto out;
5135c53530daSJeff Layton 	}
5136c53530daSJeff Layton 
5137356a95ecSJeff Layton 	*lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
513864a284d0SJ. Bruce Fields 	if (*lst == NULL) {
51395db1c03fSJeff Layton 		status = nfserr_jukebox;
51405db1c03fSJeff Layton 		goto out;
514164a284d0SJ. Bruce Fields 	}
51425db1c03fSJeff Layton 	status = nfs_ok;
51435db1c03fSJeff Layton out:
51445db1c03fSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
51455db1c03fSJeff Layton 	return status;
514664a284d0SJ. Bruce Fields }
514764a284d0SJ. Bruce Fields 
51481da177e4SLinus Torvalds /*
51491da177e4SLinus Torvalds  *  LOCK operation
51501da177e4SLinus Torvalds  */
5151b37ad28bSAl Viro __be32
5152ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5153a4f1706aSJ.Bruce Fields 	   struct nfsd4_lock *lock)
51541da177e4SLinus Torvalds {
5155fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *open_sop = NULL;
5156fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lock_sop = NULL;
51573d0fabd5STrond Myklebust 	struct nfs4_ol_stateid *lock_stp = NULL;
51580667b1e9STrond Myklebust 	struct nfs4_ol_stateid *open_stp = NULL;
51597214e860SJeff Layton 	struct nfs4_file *fp;
51607d947842SJ. Bruce Fields 	struct file *filp = NULL;
516121179d81SJeff Layton 	struct file_lock *file_lock = NULL;
516221179d81SJeff Layton 	struct file_lock *conflock = NULL;
5163b37ad28bSAl Viro 	__be32 status = 0;
5164b34f27aaSJ. Bruce Fields 	int lkflg;
5165b8dd7b9aSAl Viro 	int err;
51665db1c03fSJeff Layton 	bool new = false;
51673320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
51683320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
51691da177e4SLinus Torvalds 
51701da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
51711da177e4SLinus Torvalds 		(long long) lock->lk_offset,
51721da177e4SLinus Torvalds 		(long long) lock->lk_length);
51731da177e4SLinus Torvalds 
51741da177e4SLinus Torvalds 	if (check_lock_length(lock->lk_offset, lock->lk_length))
51751da177e4SLinus Torvalds 		 return nfserr_inval;
51761da177e4SLinus Torvalds 
5177ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh,
51788837abcaSMiklos Szeredi 				S_IFREG, NFSD_MAY_LOCK))) {
5179a6f6ef2fSAndy Adamson 		dprintk("NFSD: nfsd4_lock: permission denied!\n");
5180a6f6ef2fSAndy Adamson 		return status;
5181a6f6ef2fSAndy Adamson 	}
5182a6f6ef2fSAndy Adamson 
51831da177e4SLinus Torvalds 	if (lock->lk_is_new) {
5184684e5638SJ. Bruce Fields 		if (nfsd4_has_session(cstate))
5185684e5638SJ. Bruce Fields 			/* See rfc 5661 18.10.3: given clientid is ignored: */
5186684e5638SJ. Bruce Fields 			memcpy(&lock->v.new.clientid,
5187684e5638SJ. Bruce Fields 				&cstate->session->se_client->cl_clientid,
5188684e5638SJ. Bruce Fields 				sizeof(clientid_t));
5189684e5638SJ. Bruce Fields 
51901da177e4SLinus Torvalds 		status = nfserr_stale_clientid;
51912c142baaSStanislav Kinsbursky 		if (STALE_CLIENTID(&lock->lk_new_clientid, nn))
51921da177e4SLinus Torvalds 			goto out;
51931da177e4SLinus Torvalds 
51941da177e4SLinus Torvalds 		/* validate and update open stateid and open seqid */
5195c0a5d93eSJ. Bruce Fields 		status = nfs4_preprocess_confirmed_seqid_op(cstate,
51961da177e4SLinus Torvalds 				        lock->lk_new_open_seqid,
51971da177e4SLinus Torvalds 		                        &lock->lk_new_open_stateid,
51983320fef1SStanislav Kinsbursky 					&open_stp, nn);
519937515177SNeilBrown 		if (status)
52001da177e4SLinus Torvalds 			goto out;
5201fe0750e5SJ. Bruce Fields 		open_sop = openowner(open_stp->st_stateowner);
5202b34f27aaSJ. Bruce Fields 		status = nfserr_bad_stateid;
5203684e5638SJ. Bruce Fields 		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
5204b34f27aaSJ. Bruce Fields 						&lock->v.new.clientid))
5205b34f27aaSJ. Bruce Fields 			goto out;
520664a284d0SJ. Bruce Fields 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
52075db1c03fSJeff Layton 							&lock_stp, &new);
52083d0fabd5STrond Myklebust 	} else {
5209dd453dfdSBenny Halevy 		status = nfs4_preprocess_seqid_op(cstate,
52101da177e4SLinus Torvalds 				       lock->lk_old_lock_seqid,
52111da177e4SLinus Torvalds 				       &lock->lk_old_lock_stateid,
52123320fef1SStanislav Kinsbursky 				       NFS4_LOCK_STID, &lock_stp, nn);
52133d0fabd5STrond Myklebust 	}
52141da177e4SLinus Torvalds 	if (status)
52151da177e4SLinus Torvalds 		goto out;
5216fe0750e5SJ. Bruce Fields 	lock_sop = lockowner(lock_stp->st_stateowner);
52171da177e4SLinus Torvalds 
5218b34f27aaSJ. Bruce Fields 	lkflg = setlkflg(lock->lk_type);
5219b34f27aaSJ. Bruce Fields 	status = nfs4_check_openmode(lock_stp, lkflg);
5220b34f27aaSJ. Bruce Fields 	if (status)
5221b34f27aaSJ. Bruce Fields 		goto out;
5222b34f27aaSJ. Bruce Fields 
52230dd395dcSNeilBrown 	status = nfserr_grace;
52243320fef1SStanislav Kinsbursky 	if (locks_in_grace(net) && !lock->lk_reclaim)
52250dd395dcSNeilBrown 		goto out;
52260dd395dcSNeilBrown 	status = nfserr_no_grace;
52273320fef1SStanislav Kinsbursky 	if (!locks_in_grace(net) && lock->lk_reclaim)
52280dd395dcSNeilBrown 		goto out;
52290dd395dcSNeilBrown 
523021179d81SJeff Layton 	file_lock = locks_alloc_lock();
523121179d81SJeff Layton 	if (!file_lock) {
523221179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
523321179d81SJeff Layton 		status = nfserr_jukebox;
523421179d81SJeff Layton 		goto out;
523521179d81SJeff Layton 	}
523621179d81SJeff Layton 
523711b9164aSTrond Myklebust 	fp = lock_stp->st_stid.sc_file;
52381da177e4SLinus Torvalds 	switch (lock->lk_type) {
52391da177e4SLinus Torvalds 		case NFS4_READ_LT:
52401da177e4SLinus Torvalds 		case NFS4_READW_LT:
52417214e860SJeff Layton 			spin_lock(&fp->fi_lock);
52427214e860SJeff Layton 			filp = find_readable_file_locked(fp);
52430997b173SJ. Bruce Fields 			if (filp)
52440997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
52457214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
524621179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
52471da177e4SLinus Torvalds 			break;
52481da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
52491da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
52507214e860SJeff Layton 			spin_lock(&fp->fi_lock);
52517214e860SJeff Layton 			filp = find_writeable_file_locked(fp);
52520997b173SJ. Bruce Fields 			if (filp)
52530997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
52547214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
525521179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
52561da177e4SLinus Torvalds 			break;
52571da177e4SLinus Torvalds 		default:
52581da177e4SLinus Torvalds 			status = nfserr_inval;
52591da177e4SLinus Torvalds 		goto out;
52601da177e4SLinus Torvalds 	}
5261f9d7562fSJ. Bruce Fields 	if (!filp) {
5262f9d7562fSJ. Bruce Fields 		status = nfserr_openmode;
5263f9d7562fSJ. Bruce Fields 		goto out;
5264f9d7562fSJ. Bruce Fields 	}
5265aef9583bSKinglong Mee 
5266aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
526721179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
526821179d81SJeff Layton 	file_lock->fl_file = filp;
526921179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
527021179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
527121179d81SJeff Layton 	file_lock->fl_start = lock->lk_offset;
527221179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
527321179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
52741da177e4SLinus Torvalds 
527521179d81SJeff Layton 	conflock = locks_alloc_lock();
527621179d81SJeff Layton 	if (!conflock) {
527721179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
527821179d81SJeff Layton 		status = nfserr_jukebox;
527921179d81SJeff Layton 		goto out;
528021179d81SJeff Layton 	}
52811da177e4SLinus Torvalds 
528221179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
5283b8dd7b9aSAl Viro 	switch (-err) {
52841da177e4SLinus Torvalds 	case 0: /* success! */
5285dcef0413SJ. Bruce Fields 		update_stateid(&lock_stp->st_stid.sc_stateid);
5286dcef0413SJ. Bruce Fields 		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
52871da177e4SLinus Torvalds 				sizeof(stateid_t));
5288b8dd7b9aSAl Viro 		status = 0;
5289eb76b3fdSAndy Adamson 		break;
5290eb76b3fdSAndy Adamson 	case (EAGAIN):		/* conflock holds conflicting lock */
5291eb76b3fdSAndy Adamson 		status = nfserr_denied;
5292eb76b3fdSAndy Adamson 		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
529321179d81SJeff Layton 		nfs4_set_lock_denied(conflock, &lock->lk_denied);
5294eb76b3fdSAndy Adamson 		break;
52951da177e4SLinus Torvalds 	case (EDEADLK):
52961da177e4SLinus Torvalds 		status = nfserr_deadlock;
5297eb76b3fdSAndy Adamson 		break;
52981da177e4SLinus Torvalds 	default:
5299fd85b817SMarc Eshel 		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
53003e772463SJ. Bruce Fields 		status = nfserrno(err);
5301eb76b3fdSAndy Adamson 		break;
53021da177e4SLinus Torvalds 	}
53031da177e4SLinus Torvalds out:
5304de18643dSTrond Myklebust 	if (filp)
5305de18643dSTrond Myklebust 		fput(filp);
53065db1c03fSJeff Layton 	if (lock_stp) {
53075db1c03fSJeff Layton 		/* Bump seqid manually if the 4.0 replay owner is openowner */
53085db1c03fSJeff Layton 		if (cstate->replay_owner &&
53095db1c03fSJeff Layton 		    cstate->replay_owner != &lock_sop->lo_owner &&
53105db1c03fSJeff Layton 		    seqid_mutating_err(ntohl(status)))
53115db1c03fSJeff Layton 			lock_sop->lo_owner.so_seqid++;
53125db1c03fSJeff Layton 
53135db1c03fSJeff Layton 		/*
53145db1c03fSJeff Layton 		 * If this is a new, never-before-used stateid, and we are
53155db1c03fSJeff Layton 		 * returning an error, then just go ahead and release it.
53165db1c03fSJeff Layton 		 */
53175db1c03fSJeff Layton 		if (status && new)
53185db1c03fSJeff Layton 			release_lock_stateid(lock_stp);
53195db1c03fSJeff Layton 
53203d0fabd5STrond Myklebust 		nfs4_put_stid(&lock_stp->st_stid);
53215db1c03fSJeff Layton 	}
53220667b1e9STrond Myklebust 	if (open_stp)
53230667b1e9STrond Myklebust 		nfs4_put_stid(&open_stp->st_stid);
53249411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
532521179d81SJeff Layton 	if (file_lock)
532621179d81SJeff Layton 		locks_free_lock(file_lock);
532721179d81SJeff Layton 	if (conflock)
532821179d81SJeff Layton 		locks_free_lock(conflock);
53291da177e4SLinus Torvalds 	return status;
53301da177e4SLinus Torvalds }
53311da177e4SLinus Torvalds 
53321da177e4SLinus Torvalds /*
533355ef1274SJ. Bruce Fields  * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
533455ef1274SJ. Bruce Fields  * so we do a temporary open here just to get an open file to pass to
533555ef1274SJ. Bruce Fields  * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
533655ef1274SJ. Bruce Fields  * inode operation.)
533755ef1274SJ. Bruce Fields  */
533804da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
533955ef1274SJ. Bruce Fields {
534055ef1274SJ. Bruce Fields 	struct file *file;
534104da6e9dSAl Viro 	__be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
534204da6e9dSAl Viro 	if (!err) {
534304da6e9dSAl Viro 		err = nfserrno(vfs_test_lock(file, lock));
534455ef1274SJ. Bruce Fields 		nfsd_close(file);
534504da6e9dSAl Viro 	}
534655ef1274SJ. Bruce Fields 	return err;
534755ef1274SJ. Bruce Fields }
534855ef1274SJ. Bruce Fields 
534955ef1274SJ. Bruce Fields /*
53501da177e4SLinus Torvalds  * LOCKT operation
53511da177e4SLinus Torvalds  */
5352b37ad28bSAl Viro __be32
5353ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5354ca364317SJ.Bruce Fields 	    struct nfsd4_lockt *lockt)
53551da177e4SLinus Torvalds {
535621179d81SJeff Layton 	struct file_lock *file_lock = NULL;
53575db1c03fSJeff Layton 	struct nfs4_lockowner *lo = NULL;
5358b37ad28bSAl Viro 	__be32 status;
53597f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
53601da177e4SLinus Torvalds 
53615ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp)))
53621da177e4SLinus Torvalds 		return nfserr_grace;
53631da177e4SLinus Torvalds 
53641da177e4SLinus Torvalds 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
53651da177e4SLinus Torvalds 		 return nfserr_inval;
53661da177e4SLinus Torvalds 
53679b2ef62bSJ. Bruce Fields 	if (!nfsd4_has_session(cstate)) {
53684b24ca7dSJeff Layton 		status = lookup_clientid(&lockt->lt_clientid, cstate, nn);
53699b2ef62bSJ. Bruce Fields 		if (status)
53701da177e4SLinus Torvalds 			goto out;
53719b2ef62bSJ. Bruce Fields 	}
53721da177e4SLinus Torvalds 
537375c096f7SJ. Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
53741da177e4SLinus Torvalds 		goto out;
53751da177e4SLinus Torvalds 
537621179d81SJeff Layton 	file_lock = locks_alloc_lock();
537721179d81SJeff Layton 	if (!file_lock) {
537821179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
537921179d81SJeff Layton 		status = nfserr_jukebox;
538021179d81SJeff Layton 		goto out;
538121179d81SJeff Layton 	}
53826cd90662SKinglong Mee 
53831da177e4SLinus Torvalds 	switch (lockt->lt_type) {
53841da177e4SLinus Torvalds 		case NFS4_READ_LT:
53851da177e4SLinus Torvalds 		case NFS4_READW_LT:
538621179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
53871da177e4SLinus Torvalds 		break;
53881da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
53891da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
539021179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
53911da177e4SLinus Torvalds 		break;
53921da177e4SLinus Torvalds 		default:
53932fdada03SJ. Bruce Fields 			dprintk("NFSD: nfs4_lockt: bad lock type!\n");
53941da177e4SLinus Torvalds 			status = nfserr_inval;
53951da177e4SLinus Torvalds 		goto out;
53961da177e4SLinus Torvalds 	}
53971da177e4SLinus Torvalds 
5398d4f0489fSTrond Myklebust 	lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner,
5399d4f0489fSTrond Myklebust 				cstate->clp);
5400fe0750e5SJ. Bruce Fields 	if (lo)
540121179d81SJeff Layton 		file_lock->fl_owner = (fl_owner_t)lo;
540221179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
540321179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
54041da177e4SLinus Torvalds 
540521179d81SJeff Layton 	file_lock->fl_start = lockt->lt_offset;
540621179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
54071da177e4SLinus Torvalds 
540821179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
54091da177e4SLinus Torvalds 
541021179d81SJeff Layton 	status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
541104da6e9dSAl Viro 	if (status)
5412fd85b817SMarc Eshel 		goto out;
541304da6e9dSAl Viro 
541421179d81SJeff Layton 	if (file_lock->fl_type != F_UNLCK) {
54151da177e4SLinus Torvalds 		status = nfserr_denied;
541621179d81SJeff Layton 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
54171da177e4SLinus Torvalds 	}
54181da177e4SLinus Torvalds out:
54195db1c03fSJeff Layton 	if (lo)
54205db1c03fSJeff Layton 		nfs4_put_stateowner(&lo->lo_owner);
542121179d81SJeff Layton 	if (file_lock)
542221179d81SJeff Layton 		locks_free_lock(file_lock);
54231da177e4SLinus Torvalds 	return status;
54241da177e4SLinus Torvalds }
54251da177e4SLinus Torvalds 
5426b37ad28bSAl Viro __be32
5427ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5428a4f1706aSJ.Bruce Fields 	    struct nfsd4_locku *locku)
54291da177e4SLinus Torvalds {
5430dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
54311da177e4SLinus Torvalds 	struct file *filp = NULL;
543221179d81SJeff Layton 	struct file_lock *file_lock = NULL;
5433b37ad28bSAl Viro 	__be32 status;
5434b8dd7b9aSAl Viro 	int err;
54353320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
54361da177e4SLinus Torvalds 
54371da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
54381da177e4SLinus Torvalds 		(long long) locku->lu_offset,
54391da177e4SLinus Torvalds 		(long long) locku->lu_length);
54401da177e4SLinus Torvalds 
54411da177e4SLinus Torvalds 	if (check_lock_length(locku->lu_offset, locku->lu_length))
54421da177e4SLinus Torvalds 		 return nfserr_inval;
54431da177e4SLinus Torvalds 
54449072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
54453320fef1SStanislav Kinsbursky 					&locku->lu_stateid, NFS4_LOCK_STID,
54463320fef1SStanislav Kinsbursky 					&stp, nn);
54479072d5c6SJ. Bruce Fields 	if (status)
54481da177e4SLinus Torvalds 		goto out;
544911b9164aSTrond Myklebust 	filp = find_any_file(stp->st_stid.sc_file);
5450f9d7562fSJ. Bruce Fields 	if (!filp) {
5451f9d7562fSJ. Bruce Fields 		status = nfserr_lock_range;
5452858cc573STrond Myklebust 		goto put_stateid;
5453f9d7562fSJ. Bruce Fields 	}
545421179d81SJeff Layton 	file_lock = locks_alloc_lock();
545521179d81SJeff Layton 	if (!file_lock) {
545621179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
545721179d81SJeff Layton 		status = nfserr_jukebox;
5458de18643dSTrond Myklebust 		goto fput;
545921179d81SJeff Layton 	}
54606cd90662SKinglong Mee 
546121179d81SJeff Layton 	file_lock->fl_type = F_UNLCK;
5462aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
546321179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
546421179d81SJeff Layton 	file_lock->fl_file = filp;
546521179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
546621179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
546721179d81SJeff Layton 	file_lock->fl_start = locku->lu_offset;
54681da177e4SLinus Torvalds 
546921179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(locku->lu_offset,
547021179d81SJeff Layton 						locku->lu_length);
547121179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
54721da177e4SLinus Torvalds 
547321179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
5474b8dd7b9aSAl Viro 	if (err) {
5475fd85b817SMarc Eshel 		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
54761da177e4SLinus Torvalds 		goto out_nfserr;
54771da177e4SLinus Torvalds 	}
5478dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
5479dcef0413SJ. Bruce Fields 	memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
5480de18643dSTrond Myklebust fput:
5481de18643dSTrond Myklebust 	fput(filp);
5482858cc573STrond Myklebust put_stateid:
5483858cc573STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
54841da177e4SLinus Torvalds out:
54859411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
548621179d81SJeff Layton 	if (file_lock)
548721179d81SJeff Layton 		locks_free_lock(file_lock);
54881da177e4SLinus Torvalds 	return status;
54891da177e4SLinus Torvalds 
54901da177e4SLinus Torvalds out_nfserr:
5491b8dd7b9aSAl Viro 	status = nfserrno(err);
5492de18643dSTrond Myklebust 	goto fput;
54931da177e4SLinus Torvalds }
54941da177e4SLinus Torvalds 
54951da177e4SLinus Torvalds /*
54961da177e4SLinus Torvalds  * returns
5497f9c00c3aSJeff Layton  * 	true:  locks held by lockowner
5498f9c00c3aSJeff Layton  * 	false: no locks held by lockowner
54991da177e4SLinus Torvalds  */
5500f9c00c3aSJeff Layton static bool
5501f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
55021da177e4SLinus Torvalds {
55031da177e4SLinus Torvalds 	struct file_lock **flpp;
5504f9c00c3aSJeff Layton 	int status = false;
5505f9c00c3aSJeff Layton 	struct file *filp = find_any_file(fp);
5506f9c00c3aSJeff Layton 	struct inode *inode;
5507f9c00c3aSJeff Layton 
5508f9c00c3aSJeff Layton 	if (!filp) {
5509f9c00c3aSJeff Layton 		/* Any valid lock stateid should have some sort of access */
5510f9c00c3aSJeff Layton 		WARN_ON_ONCE(1);
5511f9c00c3aSJeff Layton 		return status;
5512f9c00c3aSJeff Layton 	}
5513f9c00c3aSJeff Layton 
5514f9c00c3aSJeff Layton 	inode = file_inode(filp);
55151da177e4SLinus Torvalds 
55161c8c601aSJeff Layton 	spin_lock(&inode->i_lock);
55171da177e4SLinus Torvalds 	for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
5518796dadfdSJ. Bruce Fields 		if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
5519f9c00c3aSJeff Layton 			status = true;
5520f9c00c3aSJeff Layton 			break;
55211da177e4SLinus Torvalds 		}
5522796dadfdSJ. Bruce Fields 	}
55231c8c601aSJeff Layton 	spin_unlock(&inode->i_lock);
5524f9c00c3aSJeff Layton 	fput(filp);
55251da177e4SLinus Torvalds 	return status;
55261da177e4SLinus Torvalds }
55271da177e4SLinus Torvalds 
5528b37ad28bSAl Viro __be32
5529b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp,
5530b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
5531b591480bSJ.Bruce Fields 			struct nfsd4_release_lockowner *rlockowner)
55321da177e4SLinus Torvalds {
55331da177e4SLinus Torvalds 	clientid_t *clid = &rlockowner->rl_clientid;
5534882e9d25SJeff Layton 	struct nfs4_stateowner *sop;
5535882e9d25SJeff Layton 	struct nfs4_lockowner *lo = NULL;
5536dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
55371da177e4SLinus Torvalds 	struct xdr_netobj *owner = &rlockowner->rl_owner;
5538d4f0489fSTrond Myklebust 	unsigned int hashval = ownerstr_hashval(owner);
5539b37ad28bSAl Viro 	__be32 status;
55407f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
5541c58c6610STrond Myklebust 	struct nfs4_client *clp;
55421da177e4SLinus Torvalds 
55431da177e4SLinus Torvalds 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
55441da177e4SLinus Torvalds 		clid->cl_boot, clid->cl_id);
55451da177e4SLinus Torvalds 
55464b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
55479b2ef62bSJ. Bruce Fields 	if (status)
554851f5e783STrond Myklebust 		return status;
55499b2ef62bSJ. Bruce Fields 
5550d4f0489fSTrond Myklebust 	clp = cstate->clp;
5551fd44907cSJeff Layton 	/* Find the matching lock stateowner */
5552d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5553882e9d25SJeff Layton 	list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval],
5554d4f0489fSTrond Myklebust 			    so_strhash) {
5555882e9d25SJeff Layton 
5556882e9d25SJeff Layton 		if (sop->so_is_open_owner || !same_owner_str(sop, owner))
555716bfdaafSJ. Bruce Fields 			continue;
5558882e9d25SJeff Layton 
5559882e9d25SJeff Layton 		/* see if there are still any locks associated with it */
5560882e9d25SJeff Layton 		lo = lockowner(sop);
5561882e9d25SJeff Layton 		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
5562882e9d25SJeff Layton 			if (check_for_locks(stp->st_stid.sc_file, lo)) {
5563882e9d25SJeff Layton 				status = nfserr_locks_held;
5564882e9d25SJeff Layton 				spin_unlock(&clp->cl_lock);
556551f5e783STrond Myklebust 				return status;
5566882e9d25SJeff Layton 			}
5567882e9d25SJeff Layton 		}
5568882e9d25SJeff Layton 
5569b5971afaSKinglong Mee 		nfs4_get_stateowner(sop);
5570fd44907cSJeff Layton 		break;
5571fd44907cSJeff Layton 	}
5572d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5573882e9d25SJeff Layton 	if (lo)
5574fe0750e5SJ. Bruce Fields 		release_lockowner(lo);
55751da177e4SLinus Torvalds 	return status;
55761da177e4SLinus Torvalds }
55771da177e4SLinus Torvalds 
55781da177e4SLinus Torvalds static inline struct nfs4_client_reclaim *
5579a55370a3SNeilBrown alloc_reclaim(void)
55801da177e4SLinus Torvalds {
5581a55370a3SNeilBrown 	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
55821da177e4SLinus Torvalds }
55831da177e4SLinus Torvalds 
55840ce0c2b5SJeff Layton bool
558552e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
5586c7b9a459SNeilBrown {
55870ce0c2b5SJeff Layton 	struct nfs4_client_reclaim *crp;
5588c7b9a459SNeilBrown 
558952e19c09SStanislav Kinsbursky 	crp = nfsd4_find_reclaim_client(name, nn);
55900ce0c2b5SJeff Layton 	return (crp && crp->cr_clp);
5591c7b9a459SNeilBrown }
5592c7b9a459SNeilBrown 
55931da177e4SLinus Torvalds /*
55941da177e4SLinus Torvalds  * failure => all reset bets are off, nfserr_no_grace...
55951da177e4SLinus Torvalds  */
5596772a9bbbSJeff Layton struct nfs4_client_reclaim *
559752e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
55981da177e4SLinus Torvalds {
55991da177e4SLinus Torvalds 	unsigned int strhashval;
5600772a9bbbSJeff Layton 	struct nfs4_client_reclaim *crp;
56011da177e4SLinus Torvalds 
5602a55370a3SNeilBrown 	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
5603a55370a3SNeilBrown 	crp = alloc_reclaim();
5604772a9bbbSJeff Layton 	if (crp) {
5605a55370a3SNeilBrown 		strhashval = clientstr_hashval(name);
56061da177e4SLinus Torvalds 		INIT_LIST_HEAD(&crp->cr_strhash);
560752e19c09SStanislav Kinsbursky 		list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
5608a55370a3SNeilBrown 		memcpy(crp->cr_recdir, name, HEXDIR_LEN);
56090ce0c2b5SJeff Layton 		crp->cr_clp = NULL;
561052e19c09SStanislav Kinsbursky 		nn->reclaim_str_hashtbl_size++;
5611772a9bbbSJeff Layton 	}
5612772a9bbbSJeff Layton 	return crp;
56131da177e4SLinus Torvalds }
56141da177e4SLinus Torvalds 
56152a4317c5SJeff Layton void
561652e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
5617ce30e539SJeff Layton {
5618ce30e539SJeff Layton 	list_del(&crp->cr_strhash);
5619ce30e539SJeff Layton 	kfree(crp);
562052e19c09SStanislav Kinsbursky 	nn->reclaim_str_hashtbl_size--;
5621ce30e539SJeff Layton }
5622ce30e539SJeff Layton 
5623ce30e539SJeff Layton void
562452e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn)
56251da177e4SLinus Torvalds {
56261da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
56271da177e4SLinus Torvalds 	int i;
56281da177e4SLinus Torvalds 
56291da177e4SLinus Torvalds 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
563052e19c09SStanislav Kinsbursky 		while (!list_empty(&nn->reclaim_str_hashtbl[i])) {
563152e19c09SStanislav Kinsbursky 			crp = list_entry(nn->reclaim_str_hashtbl[i].next,
56321da177e4SLinus Torvalds 			                struct nfs4_client_reclaim, cr_strhash);
563352e19c09SStanislav Kinsbursky 			nfs4_remove_reclaim_record(crp, nn);
56341da177e4SLinus Torvalds 		}
56351da177e4SLinus Torvalds 	}
5636063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(nn->reclaim_str_hashtbl_size);
56371da177e4SLinus Torvalds }
56381da177e4SLinus Torvalds 
56391da177e4SLinus Torvalds /*
56401da177e4SLinus Torvalds  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
56412a4317c5SJeff Layton struct nfs4_client_reclaim *
564252e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
56431da177e4SLinus Torvalds {
56441da177e4SLinus Torvalds 	unsigned int strhashval;
56451da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
56461da177e4SLinus Torvalds 
5647278c931cSJeff Layton 	dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
56481da177e4SLinus Torvalds 
5649278c931cSJeff Layton 	strhashval = clientstr_hashval(recdir);
565052e19c09SStanislav Kinsbursky 	list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
5651278c931cSJeff Layton 		if (same_name(crp->cr_recdir, recdir)) {
56521da177e4SLinus Torvalds 			return crp;
56531da177e4SLinus Torvalds 		}
56541da177e4SLinus Torvalds 	}
56551da177e4SLinus Torvalds 	return NULL;
56561da177e4SLinus Torvalds }
56571da177e4SLinus Torvalds 
56581da177e4SLinus Torvalds /*
56591da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list.
56601da177e4SLinus Torvalds */
5661b37ad28bSAl Viro __be32
56620fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid,
56630fe492dbSTrond Myklebust 		struct nfsd4_compound_state *cstate,
56640fe492dbSTrond Myklebust 		struct nfsd_net *nn)
56651da177e4SLinus Torvalds {
56660fe492dbSTrond Myklebust 	__be32 status;
5667a52d726bSJeff Layton 
5668a52d726bSJeff Layton 	/* find clientid in conf_id_hashtbl */
56690fe492dbSTrond Myklebust 	status = lookup_clientid(clid, cstate, nn);
56700fe492dbSTrond Myklebust 	if (status)
5671a52d726bSJeff Layton 		return nfserr_reclaim_bad;
5672a52d726bSJeff Layton 
56730fe492dbSTrond Myklebust 	if (nfsd4_client_record_check(cstate->clp))
56740fe492dbSTrond Myklebust 		return nfserr_reclaim_bad;
56750fe492dbSTrond Myklebust 
56760fe492dbSTrond Myklebust 	return nfs_ok;
56771da177e4SLinus Torvalds }
56781da177e4SLinus Torvalds 
567965178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION
5680016200c3SJeff Layton static inline void
5681016200c3SJeff Layton put_client(struct nfs4_client *clp)
5682016200c3SJeff Layton {
5683016200c3SJeff Layton 	atomic_dec(&clp->cl_refcount);
5684016200c3SJeff Layton }
5685016200c3SJeff Layton 
5686285abdeeSJeff Layton static struct nfs4_client *
5687285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
5688285abdeeSJeff Layton {
5689285abdeeSJeff Layton 	struct nfs4_client *clp;
5690285abdeeSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5691285abdeeSJeff Layton 					  nfsd_net_id);
5692285abdeeSJeff Layton 
5693285abdeeSJeff Layton 	if (!nfsd_netns_ready(nn))
5694285abdeeSJeff Layton 		return NULL;
5695285abdeeSJeff Layton 
5696285abdeeSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
5697285abdeeSJeff Layton 		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
5698285abdeeSJeff Layton 			return clp;
5699285abdeeSJeff Layton 	}
5700285abdeeSJeff Layton 	return NULL;
5701285abdeeSJeff Layton }
5702285abdeeSJeff Layton 
57037ec0e36fSJeff Layton u64
5704285abdeeSJeff Layton nfsd_inject_print_clients(void)
57057ec0e36fSJeff Layton {
57067ec0e36fSJeff Layton 	struct nfs4_client *clp;
57077ec0e36fSJeff Layton 	u64 count = 0;
57087ec0e36fSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
57097ec0e36fSJeff Layton 					  nfsd_net_id);
57107ec0e36fSJeff Layton 	char buf[INET6_ADDRSTRLEN];
57117ec0e36fSJeff Layton 
57127ec0e36fSJeff Layton 	if (!nfsd_netns_ready(nn))
57137ec0e36fSJeff Layton 		return 0;
57147ec0e36fSJeff Layton 
57157ec0e36fSJeff Layton 	spin_lock(&nn->client_lock);
57167ec0e36fSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
57177ec0e36fSJeff Layton 		rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
57187ec0e36fSJeff Layton 		pr_info("NFS Client: %s\n", buf);
57197ec0e36fSJeff Layton 		++count;
57207ec0e36fSJeff Layton 	}
57217ec0e36fSJeff Layton 	spin_unlock(&nn->client_lock);
57227ec0e36fSJeff Layton 
57237ec0e36fSJeff Layton 	return count;
57247ec0e36fSJeff Layton }
572565178db4SBryan Schumaker 
5726a0926d15SJeff Layton u64
5727285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size)
5728a0926d15SJeff Layton {
5729a0926d15SJeff Layton 	u64 count = 0;
5730a0926d15SJeff Layton 	struct nfs4_client *clp;
5731a0926d15SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5732a0926d15SJeff Layton 					  nfsd_net_id);
5733a0926d15SJeff Layton 
5734a0926d15SJeff Layton 	if (!nfsd_netns_ready(nn))
5735a0926d15SJeff Layton 		return count;
5736a0926d15SJeff Layton 
5737a0926d15SJeff Layton 	spin_lock(&nn->client_lock);
5738a0926d15SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
5739a0926d15SJeff Layton 	if (clp) {
5740a0926d15SJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok)
5741a0926d15SJeff Layton 			++count;
5742a0926d15SJeff Layton 		else
5743a0926d15SJeff Layton 			clp = NULL;
5744a0926d15SJeff Layton 	}
5745a0926d15SJeff Layton 	spin_unlock(&nn->client_lock);
5746a0926d15SJeff Layton 
5747a0926d15SJeff Layton 	if (clp)
5748a0926d15SJeff Layton 		expire_client(clp);
5749a0926d15SJeff Layton 
5750a0926d15SJeff Layton 	return count;
5751a0926d15SJeff Layton }
5752a0926d15SJeff Layton 
575369fc9edfSJeff Layton u64
5754285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max)
575569fc9edfSJeff Layton {
575669fc9edfSJeff Layton 	u64 count = 0;
575769fc9edfSJeff Layton 	struct nfs4_client *clp, *next;
575869fc9edfSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
575969fc9edfSJeff Layton 						nfsd_net_id);
576069fc9edfSJeff Layton 	LIST_HEAD(reaplist);
576169fc9edfSJeff Layton 
576269fc9edfSJeff Layton 	if (!nfsd_netns_ready(nn))
576369fc9edfSJeff Layton 		return count;
576469fc9edfSJeff Layton 
576569fc9edfSJeff Layton 	spin_lock(&nn->client_lock);
576669fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
576769fc9edfSJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok) {
576869fc9edfSJeff Layton 			list_add(&clp->cl_lru, &reaplist);
576969fc9edfSJeff Layton 			if (max != 0 && ++count >= max)
577069fc9edfSJeff Layton 				break;
577169fc9edfSJeff Layton 		}
577269fc9edfSJeff Layton 	}
577369fc9edfSJeff Layton 	spin_unlock(&nn->client_lock);
577469fc9edfSJeff Layton 
577569fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
577669fc9edfSJeff Layton 		expire_client(clp);
577769fc9edfSJeff Layton 
577869fc9edfSJeff Layton 	return count;
577969fc9edfSJeff Layton }
578069fc9edfSJeff Layton 
5781184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
5782184c1847SBryan Schumaker 			     const char *type)
5783184c1847SBryan Schumaker {
5784184c1847SBryan Schumaker 	char buf[INET6_ADDRSTRLEN];
57850a5c33e2SBryan Schumaker 	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
5786184c1847SBryan Schumaker 	printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
5787184c1847SBryan Schumaker }
5788184c1847SBryan Schumaker 
5789016200c3SJeff Layton static void
5790016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
5791016200c3SJeff Layton 			     struct list_head *collect)
5792016200c3SJeff Layton {
5793016200c3SJeff Layton 	struct nfs4_client *clp = lst->st_stid.sc_client;
5794016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5795016200c3SJeff Layton 					  nfsd_net_id);
5796016200c3SJeff Layton 
5797016200c3SJeff Layton 	if (!collect)
5798016200c3SJeff Layton 		return;
5799016200c3SJeff Layton 
5800016200c3SJeff Layton 	lockdep_assert_held(&nn->client_lock);
5801016200c3SJeff Layton 	atomic_inc(&clp->cl_refcount);
5802016200c3SJeff Layton 	list_add(&lst->st_locks, collect);
5803016200c3SJeff Layton }
5804016200c3SJeff Layton 
58053c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
58063738d50eSJeff Layton 				    struct list_head *collect,
58073c87b9b7STrond Myklebust 				    void (*func)(struct nfs4_ol_stateid *))
5808fc29171fSBryan Schumaker {
5809fc29171fSBryan Schumaker 	struct nfs4_openowner *oop;
5810fc29171fSBryan Schumaker 	struct nfs4_ol_stateid *stp, *st_next;
58113c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *lst, *lst_next;
5812fc29171fSBryan Schumaker 	u64 count = 0;
5813fc29171fSBryan Schumaker 
5814016200c3SJeff Layton 	spin_lock(&clp->cl_lock);
5815fc29171fSBryan Schumaker 	list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
58163c87b9b7STrond Myklebust 		list_for_each_entry_safe(stp, st_next,
58173c87b9b7STrond Myklebust 				&oop->oo_owner.so_stateids, st_perstateowner) {
58183c87b9b7STrond Myklebust 			list_for_each_entry_safe(lst, lst_next,
58193c87b9b7STrond Myklebust 					&stp->st_locks, st_locks) {
58203738d50eSJeff Layton 				if (func) {
58213c87b9b7STrond Myklebust 					func(lst);
5822016200c3SJeff Layton 					nfsd_inject_add_lock_to_list(lst,
58233738d50eSJeff Layton 								collect);
58243738d50eSJeff Layton 				}
5825016200c3SJeff Layton 				++count;
5826016200c3SJeff Layton 				/*
5827016200c3SJeff Layton 				 * Despite the fact that these functions deal
5828016200c3SJeff Layton 				 * with 64-bit integers for "count", we must
5829016200c3SJeff Layton 				 * ensure that it doesn't blow up the
5830016200c3SJeff Layton 				 * clp->cl_refcount. Throw a warning if we
5831016200c3SJeff Layton 				 * start to approach INT_MAX here.
5832016200c3SJeff Layton 				 */
5833016200c3SJeff Layton 				WARN_ON_ONCE(count == (INT_MAX / 2));
5834016200c3SJeff Layton 				if (count == max)
5835016200c3SJeff Layton 					goto out;
5836fc29171fSBryan Schumaker 			}
5837fc29171fSBryan Schumaker 		}
5838fc29171fSBryan Schumaker 	}
5839016200c3SJeff Layton out:
5840016200c3SJeff Layton 	spin_unlock(&clp->cl_lock);
5841fc29171fSBryan Schumaker 
5842fc29171fSBryan Schumaker 	return count;
5843fc29171fSBryan Schumaker }
5844fc29171fSBryan Schumaker 
5845016200c3SJeff Layton static u64
5846016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
5847016200c3SJeff Layton 			  u64 max)
5848fc29171fSBryan Schumaker {
5849016200c3SJeff Layton 	return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
5850fc29171fSBryan Schumaker }
5851fc29171fSBryan Schumaker 
5852016200c3SJeff Layton static u64
5853016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp)
5854184c1847SBryan Schumaker {
5855016200c3SJeff Layton 	u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
5856184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "locked files");
5857184c1847SBryan Schumaker 	return count;
5858184c1847SBryan Schumaker }
5859184c1847SBryan Schumaker 
5860016200c3SJeff Layton u64
5861285abdeeSJeff Layton nfsd_inject_print_locks(void)
5862016200c3SJeff Layton {
5863016200c3SJeff Layton 	struct nfs4_client *clp;
5864016200c3SJeff Layton 	u64 count = 0;
5865016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5866016200c3SJeff Layton 						nfsd_net_id);
5867016200c3SJeff Layton 
5868016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
5869016200c3SJeff Layton 		return 0;
5870016200c3SJeff Layton 
5871016200c3SJeff Layton 	spin_lock(&nn->client_lock);
5872016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
5873016200c3SJeff Layton 		count += nfsd_print_client_locks(clp);
5874016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
5875016200c3SJeff Layton 
5876016200c3SJeff Layton 	return count;
5877016200c3SJeff Layton }
5878016200c3SJeff Layton 
5879016200c3SJeff Layton static void
5880016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist)
5881016200c3SJeff Layton {
5882016200c3SJeff Layton 	struct nfs4_client *clp;
5883016200c3SJeff Layton 	struct nfs4_ol_stateid *stp, *next;
5884016200c3SJeff Layton 
5885016200c3SJeff Layton 	list_for_each_entry_safe(stp, next, reaplist, st_locks) {
5886016200c3SJeff Layton 		list_del_init(&stp->st_locks);
5887016200c3SJeff Layton 		clp = stp->st_stid.sc_client;
5888016200c3SJeff Layton 		nfs4_put_stid(&stp->st_stid);
5889016200c3SJeff Layton 		put_client(clp);
5890016200c3SJeff Layton 	}
5891016200c3SJeff Layton }
5892016200c3SJeff Layton 
5893016200c3SJeff Layton u64
5894285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size)
5895016200c3SJeff Layton {
5896016200c3SJeff Layton 	unsigned int count = 0;
5897016200c3SJeff Layton 	struct nfs4_client *clp;
5898016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5899016200c3SJeff Layton 						nfsd_net_id);
5900016200c3SJeff Layton 	LIST_HEAD(reaplist);
5901016200c3SJeff Layton 
5902016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
5903016200c3SJeff Layton 		return count;
5904016200c3SJeff Layton 
5905016200c3SJeff Layton 	spin_lock(&nn->client_lock);
5906016200c3SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
5907016200c3SJeff Layton 	if (clp)
5908016200c3SJeff Layton 		count = nfsd_collect_client_locks(clp, &reaplist, 0);
5909016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
5910016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
5911016200c3SJeff Layton 	return count;
5912016200c3SJeff Layton }
5913016200c3SJeff Layton 
5914016200c3SJeff Layton u64
5915285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max)
5916016200c3SJeff Layton {
5917016200c3SJeff Layton 	u64 count = 0;
5918016200c3SJeff Layton 	struct nfs4_client *clp;
5919016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5920016200c3SJeff Layton 						nfsd_net_id);
5921016200c3SJeff Layton 	LIST_HEAD(reaplist);
5922016200c3SJeff Layton 
5923016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
5924016200c3SJeff Layton 		return count;
5925016200c3SJeff Layton 
5926016200c3SJeff Layton 	spin_lock(&nn->client_lock);
5927016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
5928016200c3SJeff Layton 		count += nfsd_collect_client_locks(clp, &reaplist, max - count);
5929016200c3SJeff Layton 		if (max != 0 && count >= max)
5930016200c3SJeff Layton 			break;
5931016200c3SJeff Layton 	}
5932016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
5933016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
5934016200c3SJeff Layton 	return count;
5935016200c3SJeff Layton }
5936016200c3SJeff Layton 
593782e05efaSJeff Layton static u64
593882e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
593982e05efaSJeff Layton 			      struct list_head *collect,
594082e05efaSJeff Layton 			      void (*func)(struct nfs4_openowner *))
59414dbdbda8SBryan Schumaker {
59424dbdbda8SBryan Schumaker 	struct nfs4_openowner *oop, *next;
594382e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
594482e05efaSJeff Layton 						nfsd_net_id);
59454dbdbda8SBryan Schumaker 	u64 count = 0;
59464dbdbda8SBryan Schumaker 
594782e05efaSJeff Layton 	lockdep_assert_held(&nn->client_lock);
594882e05efaSJeff Layton 
594982e05efaSJeff Layton 	spin_lock(&clp->cl_lock);
59504dbdbda8SBryan Schumaker 	list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
595182e05efaSJeff Layton 		if (func) {
59524dbdbda8SBryan Schumaker 			func(oop);
595382e05efaSJeff Layton 			if (collect) {
595482e05efaSJeff Layton 				atomic_inc(&clp->cl_refcount);
595582e05efaSJeff Layton 				list_add(&oop->oo_perclient, collect);
595682e05efaSJeff Layton 			}
595782e05efaSJeff Layton 		}
595882e05efaSJeff Layton 		++count;
595982e05efaSJeff Layton 		/*
596082e05efaSJeff Layton 		 * Despite the fact that these functions deal with
596182e05efaSJeff Layton 		 * 64-bit integers for "count", we must ensure that
596282e05efaSJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
596382e05efaSJeff Layton 		 * warning if we start to approach INT_MAX here.
596482e05efaSJeff Layton 		 */
596582e05efaSJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
596682e05efaSJeff Layton 		if (count == max)
59674dbdbda8SBryan Schumaker 			break;
59684dbdbda8SBryan Schumaker 	}
596982e05efaSJeff Layton 	spin_unlock(&clp->cl_lock);
59704dbdbda8SBryan Schumaker 
59714dbdbda8SBryan Schumaker 	return count;
59724dbdbda8SBryan Schumaker }
59734dbdbda8SBryan Schumaker 
597482e05efaSJeff Layton static u64
597582e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp)
59764dbdbda8SBryan Schumaker {
597782e05efaSJeff Layton 	u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
597882e05efaSJeff Layton 
597982e05efaSJeff Layton 	nfsd_print_count(clp, count, "openowners");
598082e05efaSJeff Layton 	return count;
59814dbdbda8SBryan Schumaker }
59824dbdbda8SBryan Schumaker 
598382e05efaSJeff Layton static u64
598482e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp,
598582e05efaSJeff Layton 			       struct list_head *collect, u64 max)
5986184c1847SBryan Schumaker {
598782e05efaSJeff Layton 	return nfsd_foreach_client_openowner(clp, max, collect,
598882e05efaSJeff Layton 						unhash_openowner_locked);
598982e05efaSJeff Layton }
599082e05efaSJeff Layton 
599182e05efaSJeff Layton u64
5992285abdeeSJeff Layton nfsd_inject_print_openowners(void)
599382e05efaSJeff Layton {
599482e05efaSJeff Layton 	struct nfs4_client *clp;
599582e05efaSJeff Layton 	u64 count = 0;
599682e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
599782e05efaSJeff Layton 						nfsd_net_id);
599882e05efaSJeff Layton 
599982e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
600082e05efaSJeff Layton 		return 0;
600182e05efaSJeff Layton 
600282e05efaSJeff Layton 	spin_lock(&nn->client_lock);
600382e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
600482e05efaSJeff Layton 		count += nfsd_print_client_openowners(clp);
600582e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
600682e05efaSJeff Layton 
600782e05efaSJeff Layton 	return count;
600882e05efaSJeff Layton }
600982e05efaSJeff Layton 
601082e05efaSJeff Layton static void
601182e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist)
601282e05efaSJeff Layton {
601382e05efaSJeff Layton 	struct nfs4_client *clp;
601482e05efaSJeff Layton 	struct nfs4_openowner *oop, *next;
601582e05efaSJeff Layton 
601682e05efaSJeff Layton 	list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
601782e05efaSJeff Layton 		list_del_init(&oop->oo_perclient);
601882e05efaSJeff Layton 		clp = oop->oo_owner.so_client;
601982e05efaSJeff Layton 		release_openowner(oop);
602082e05efaSJeff Layton 		put_client(clp);
602182e05efaSJeff Layton 	}
602282e05efaSJeff Layton }
602382e05efaSJeff Layton 
602482e05efaSJeff Layton u64
6025285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr,
6026285abdeeSJeff Layton 				     size_t addr_size)
602782e05efaSJeff Layton {
602882e05efaSJeff Layton 	unsigned int count = 0;
602982e05efaSJeff Layton 	struct nfs4_client *clp;
603082e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
603182e05efaSJeff Layton 						nfsd_net_id);
603282e05efaSJeff Layton 	LIST_HEAD(reaplist);
603382e05efaSJeff Layton 
603482e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
603582e05efaSJeff Layton 		return count;
603682e05efaSJeff Layton 
603782e05efaSJeff Layton 	spin_lock(&nn->client_lock);
603882e05efaSJeff Layton 	clp = nfsd_find_client(addr, addr_size);
603982e05efaSJeff Layton 	if (clp)
604082e05efaSJeff Layton 		count = nfsd_collect_client_openowners(clp, &reaplist, 0);
604182e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
604282e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
604382e05efaSJeff Layton 	return count;
604482e05efaSJeff Layton }
604582e05efaSJeff Layton 
604682e05efaSJeff Layton u64
6047285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max)
604882e05efaSJeff Layton {
604982e05efaSJeff Layton 	u64 count = 0;
605082e05efaSJeff Layton 	struct nfs4_client *clp;
605182e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
605282e05efaSJeff Layton 						nfsd_net_id);
605382e05efaSJeff Layton 	LIST_HEAD(reaplist);
605482e05efaSJeff Layton 
605582e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
605682e05efaSJeff Layton 		return count;
605782e05efaSJeff Layton 
605882e05efaSJeff Layton 	spin_lock(&nn->client_lock);
605982e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
606082e05efaSJeff Layton 		count += nfsd_collect_client_openowners(clp, &reaplist,
606182e05efaSJeff Layton 							max - count);
606282e05efaSJeff Layton 		if (max != 0 && count >= max)
606382e05efaSJeff Layton 			break;
606482e05efaSJeff Layton 	}
606582e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
606682e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
6067184c1847SBryan Schumaker 	return count;
6068184c1847SBryan Schumaker }
6069184c1847SBryan Schumaker 
6070269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
6071269de30fSBryan Schumaker 				     struct list_head *victims)
6072269de30fSBryan Schumaker {
6073269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
607498d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
607598d5c7c5SJeff Layton 						nfsd_net_id);
6076269de30fSBryan Schumaker 	u64 count = 0;
6077269de30fSBryan Schumaker 
607898d5c7c5SJeff Layton 	lockdep_assert_held(&nn->client_lock);
607998d5c7c5SJeff Layton 
608098d5c7c5SJeff Layton 	spin_lock(&state_lock);
6081269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
6082dff1399fSJeff Layton 		if (victims) {
6083dff1399fSJeff Layton 			/*
6084dff1399fSJeff Layton 			 * It's not safe to mess with delegations that have a
6085dff1399fSJeff Layton 			 * non-zero dl_time. They might have already been broken
6086dff1399fSJeff Layton 			 * and could be processed by the laundromat outside of
6087dff1399fSJeff Layton 			 * the state_lock. Just leave them be.
6088dff1399fSJeff Layton 			 */
6089dff1399fSJeff Layton 			if (dp->dl_time != 0)
6090dff1399fSJeff Layton 				continue;
6091dff1399fSJeff Layton 
609298d5c7c5SJeff Layton 			atomic_inc(&clp->cl_refcount);
609342690676SJeff Layton 			unhash_delegation_locked(dp);
609442690676SJeff Layton 			list_add(&dp->dl_recall_lru, victims);
6095dff1399fSJeff Layton 		}
609698d5c7c5SJeff Layton 		++count;
609798d5c7c5SJeff Layton 		/*
609898d5c7c5SJeff Layton 		 * Despite the fact that these functions deal with
609998d5c7c5SJeff Layton 		 * 64-bit integers for "count", we must ensure that
610098d5c7c5SJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
610198d5c7c5SJeff Layton 		 * warning if we start to approach INT_MAX here.
610298d5c7c5SJeff Layton 		 */
610398d5c7c5SJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
610498d5c7c5SJeff Layton 		if (count == max)
6105269de30fSBryan Schumaker 			break;
6106269de30fSBryan Schumaker 	}
610798d5c7c5SJeff Layton 	spin_unlock(&state_lock);
6108269de30fSBryan Schumaker 	return count;
6109269de30fSBryan Schumaker }
6110269de30fSBryan Schumaker 
611198d5c7c5SJeff Layton static u64
611298d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp)
6113269de30fSBryan Schumaker {
611498d5c7c5SJeff Layton 	u64 count = nfsd_find_all_delegations(clp, 0, NULL);
6115184c1847SBryan Schumaker 
6116184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "delegations");
6117184c1847SBryan Schumaker 	return count;
6118184c1847SBryan Schumaker }
6119184c1847SBryan Schumaker 
612098d5c7c5SJeff Layton u64
6121285abdeeSJeff Layton nfsd_inject_print_delegations(void)
612298d5c7c5SJeff Layton {
612398d5c7c5SJeff Layton 	struct nfs4_client *clp;
612498d5c7c5SJeff Layton 	u64 count = 0;
612598d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
612698d5c7c5SJeff Layton 						nfsd_net_id);
612798d5c7c5SJeff Layton 
612898d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
612998d5c7c5SJeff Layton 		return 0;
613098d5c7c5SJeff Layton 
613198d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
613298d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
613398d5c7c5SJeff Layton 		count += nfsd_print_client_delegations(clp);
613498d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
613598d5c7c5SJeff Layton 
613698d5c7c5SJeff Layton 	return count;
613798d5c7c5SJeff Layton }
613898d5c7c5SJeff Layton 
613998d5c7c5SJeff Layton static void
614098d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist)
614198d5c7c5SJeff Layton {
614298d5c7c5SJeff Layton 	struct nfs4_client *clp;
614398d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
614498d5c7c5SJeff Layton 
614598d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
614698d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
614798d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
614898d5c7c5SJeff Layton 		revoke_delegation(dp);
614998d5c7c5SJeff Layton 		put_client(clp);
615098d5c7c5SJeff Layton 	}
615198d5c7c5SJeff Layton }
615298d5c7c5SJeff Layton 
615398d5c7c5SJeff Layton u64
6154285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr,
6155285abdeeSJeff Layton 				      size_t addr_size)
615698d5c7c5SJeff Layton {
615798d5c7c5SJeff Layton 	u64 count = 0;
615898d5c7c5SJeff Layton 	struct nfs4_client *clp;
615998d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
616098d5c7c5SJeff Layton 						nfsd_net_id);
616198d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
616298d5c7c5SJeff Layton 
616398d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
616498d5c7c5SJeff Layton 		return count;
616598d5c7c5SJeff Layton 
616698d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
616798d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
616898d5c7c5SJeff Layton 	if (clp)
616998d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
617098d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
617198d5c7c5SJeff Layton 
617298d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
617398d5c7c5SJeff Layton 	return count;
617498d5c7c5SJeff Layton }
617598d5c7c5SJeff Layton 
617698d5c7c5SJeff Layton u64
6177285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max)
617898d5c7c5SJeff Layton {
617998d5c7c5SJeff Layton 	u64 count = 0;
618098d5c7c5SJeff Layton 	struct nfs4_client *clp;
618198d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
618298d5c7c5SJeff Layton 						nfsd_net_id);
618398d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
618498d5c7c5SJeff Layton 
618598d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
618698d5c7c5SJeff Layton 		return count;
618798d5c7c5SJeff Layton 
618898d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
618998d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
619098d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
619198d5c7c5SJeff Layton 		if (max != 0 && count >= max)
619298d5c7c5SJeff Layton 			break;
619398d5c7c5SJeff Layton 	}
619498d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
619598d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
619698d5c7c5SJeff Layton 	return count;
619798d5c7c5SJeff Layton }
619898d5c7c5SJeff Layton 
619998d5c7c5SJeff Layton static void
620098d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist)
620198d5c7c5SJeff Layton {
620298d5c7c5SJeff Layton 	struct nfs4_client *clp;
620398d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
620498d5c7c5SJeff Layton 
620598d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
620698d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
620798d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
620898d5c7c5SJeff Layton 		/*
620998d5c7c5SJeff Layton 		 * We skipped all entries that had a zero dl_time before,
621098d5c7c5SJeff Layton 		 * so we can now reset the dl_time back to 0. If a delegation
621198d5c7c5SJeff Layton 		 * break comes in now, then it won't make any difference since
621298d5c7c5SJeff Layton 		 * we're recalling it either way.
621398d5c7c5SJeff Layton 		 */
621498d5c7c5SJeff Layton 		spin_lock(&state_lock);
621598d5c7c5SJeff Layton 		dp->dl_time = 0;
621698d5c7c5SJeff Layton 		spin_unlock(&state_lock);
621798d5c7c5SJeff Layton 		nfsd_break_one_deleg(dp);
621898d5c7c5SJeff Layton 		put_client(clp);
621998d5c7c5SJeff Layton 	}
622098d5c7c5SJeff Layton }
622198d5c7c5SJeff Layton 
622298d5c7c5SJeff Layton u64
6223285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr,
622498d5c7c5SJeff Layton 				      size_t addr_size)
622598d5c7c5SJeff Layton {
622698d5c7c5SJeff Layton 	u64 count = 0;
622798d5c7c5SJeff Layton 	struct nfs4_client *clp;
622898d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
622998d5c7c5SJeff Layton 						nfsd_net_id);
623098d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
623198d5c7c5SJeff Layton 
623298d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
623398d5c7c5SJeff Layton 		return count;
623498d5c7c5SJeff Layton 
623598d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
623698d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
623798d5c7c5SJeff Layton 	if (clp)
623898d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
623998d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
624098d5c7c5SJeff Layton 
624198d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
624298d5c7c5SJeff Layton 	return count;
624398d5c7c5SJeff Layton }
624498d5c7c5SJeff Layton 
624598d5c7c5SJeff Layton u64
6246285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max)
624798d5c7c5SJeff Layton {
624898d5c7c5SJeff Layton 	u64 count = 0;
624998d5c7c5SJeff Layton 	struct nfs4_client *clp, *next;
625098d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
625198d5c7c5SJeff Layton 						nfsd_net_id);
625298d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
625398d5c7c5SJeff Layton 
625498d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
625598d5c7c5SJeff Layton 		return count;
625698d5c7c5SJeff Layton 
625798d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
625898d5c7c5SJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
625998d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
626098d5c7c5SJeff Layton 		if (max != 0 && ++count >= max)
626198d5c7c5SJeff Layton 			break;
626298d5c7c5SJeff Layton 	}
626398d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
626498d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
626598d5c7c5SJeff Layton 	return count;
626698d5c7c5SJeff Layton }
626765178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */
626865178db4SBryan Schumaker 
6269c2f1a551SMeelap Shah /*
6270c2f1a551SMeelap Shah  * Since the lifetime of a delegation isn't limited to that of an open, a
6271c2f1a551SMeelap Shah  * client may quite reasonably hang on to a delegation as long as it has
6272c2f1a551SMeelap Shah  * the inode cached.  This becomes an obvious problem the first time a
6273c2f1a551SMeelap Shah  * client's inode cache approaches the size of the server's total memory.
6274c2f1a551SMeelap Shah  *
6275c2f1a551SMeelap Shah  * For now we avoid this problem by imposing a hard limit on the number
6276c2f1a551SMeelap Shah  * of delegations, which varies according to the server's memory size.
6277c2f1a551SMeelap Shah  */
6278c2f1a551SMeelap Shah static void
6279c2f1a551SMeelap Shah set_max_delegations(void)
6280c2f1a551SMeelap Shah {
6281c2f1a551SMeelap Shah 	/*
6282c2f1a551SMeelap Shah 	 * Allow at most 4 delegations per megabyte of RAM.  Quick
6283c2f1a551SMeelap Shah 	 * estimates suggest that in the worst case (where every delegation
6284c2f1a551SMeelap Shah 	 * is for a different inode), a delegation could take about 1.5K,
6285c2f1a551SMeelap Shah 	 * giving a worst case usage of about 6% of memory.
6286c2f1a551SMeelap Shah 	 */
6287c2f1a551SMeelap Shah 	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
6288c2f1a551SMeelap Shah }
6289c2f1a551SMeelap Shah 
6290d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net)
62918daae4dcSStanislav Kinsbursky {
62928daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
62938daae4dcSStanislav Kinsbursky 	int i;
62948daae4dcSStanislav Kinsbursky 
62958daae4dcSStanislav Kinsbursky 	nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
62968daae4dcSStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
62978daae4dcSStanislav Kinsbursky 	if (!nn->conf_id_hashtbl)
6298382a62e7SStanislav Kinsbursky 		goto err;
62990a7ec377SStanislav Kinsbursky 	nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) *
63000a7ec377SStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
63010a7ec377SStanislav Kinsbursky 	if (!nn->unconf_id_hashtbl)
63020a7ec377SStanislav Kinsbursky 		goto err_unconf_id;
63031872de0eSStanislav Kinsbursky 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
63041872de0eSStanislav Kinsbursky 			SESSION_HASH_SIZE, GFP_KERNEL);
63051872de0eSStanislav Kinsbursky 	if (!nn->sessionid_hashtbl)
63061872de0eSStanislav Kinsbursky 		goto err_sessionid;
63078daae4dcSStanislav Kinsbursky 
6308382a62e7SStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
63098daae4dcSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
63100a7ec377SStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
6311382a62e7SStanislav Kinsbursky 	}
63121872de0eSStanislav Kinsbursky 	for (i = 0; i < SESSION_HASH_SIZE; i++)
63131872de0eSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
6314382a62e7SStanislav Kinsbursky 	nn->conf_name_tree = RB_ROOT;
6315a99454aaSStanislav Kinsbursky 	nn->unconf_name_tree = RB_ROOT;
63165ed58bb2SStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->client_lru);
631773758fedSStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->close_lru);
6318e8c69d17SJ. Bruce Fields 	INIT_LIST_HEAD(&nn->del_recall_lru);
6319c9a49628SStanislav Kinsbursky 	spin_lock_init(&nn->client_lock);
63208daae4dcSStanislav Kinsbursky 
632109121281SStanislav Kinsbursky 	INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
6322d85ed443SStanislav Kinsbursky 	get_net(net);
632309121281SStanislav Kinsbursky 
63248daae4dcSStanislav Kinsbursky 	return 0;
6325382a62e7SStanislav Kinsbursky 
63261872de0eSStanislav Kinsbursky err_sessionid:
63279b531137SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
63280a7ec377SStanislav Kinsbursky err_unconf_id:
63290a7ec377SStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
6330382a62e7SStanislav Kinsbursky err:
6331382a62e7SStanislav Kinsbursky 	return -ENOMEM;
63328daae4dcSStanislav Kinsbursky }
63338daae4dcSStanislav Kinsbursky 
63348daae4dcSStanislav Kinsbursky static void
63354dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net)
63368daae4dcSStanislav Kinsbursky {
63378daae4dcSStanislav Kinsbursky 	int i;
63388daae4dcSStanislav Kinsbursky 	struct nfs4_client *clp = NULL;
63398daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
63408daae4dcSStanislav Kinsbursky 
63418daae4dcSStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
63428daae4dcSStanislav Kinsbursky 		while (!list_empty(&nn->conf_id_hashtbl[i])) {
63438daae4dcSStanislav Kinsbursky 			clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
63448daae4dcSStanislav Kinsbursky 			destroy_client(clp);
63458daae4dcSStanislav Kinsbursky 		}
63468daae4dcSStanislav Kinsbursky 	}
6347a99454aaSStanislav Kinsbursky 
63482b905635SKinglong Mee 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
63492b905635SKinglong Mee 		while (!list_empty(&nn->unconf_id_hashtbl[i])) {
63502b905635SKinglong Mee 			clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
6351a99454aaSStanislav Kinsbursky 			destroy_client(clp);
6352a99454aaSStanislav Kinsbursky 		}
63532b905635SKinglong Mee 	}
6354a99454aaSStanislav Kinsbursky 
63551872de0eSStanislav Kinsbursky 	kfree(nn->sessionid_hashtbl);
63560a7ec377SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
63578daae4dcSStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
63584dce0ac9SStanislav Kinsbursky 	put_net(net);
63598daae4dcSStanislav Kinsbursky }
63608daae4dcSStanislav Kinsbursky 
6361f252bc68SStanislav Kinsbursky int
6362d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net)
6363ac4d8ff2SNeilBrown {
63645e1533c7SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
6365b5a1a81eSJ. Bruce Fields 	int ret;
6366b5a1a81eSJ. Bruce Fields 
6367d85ed443SStanislav Kinsbursky 	ret = nfs4_state_create_net(net);
63688daae4dcSStanislav Kinsbursky 	if (ret)
63698daae4dcSStanislav Kinsbursky 		return ret;
63705e1533c7SStanislav Kinsbursky 	nfsd4_client_tracking_init(net);
63712c142baaSStanislav Kinsbursky 	nn->boot_time = get_seconds();
63725ccb0066SStanislav Kinsbursky 	locks_start_grace(net, &nn->nfsd4_manager);
6373a51c84edSStanislav Kinsbursky 	nn->grace_ended = false;
6374d85ed443SStanislav Kinsbursky 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
63755284b44eSStanislav Kinsbursky 	       nn->nfsd4_grace, net);
63765284b44eSStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
6377d85ed443SStanislav Kinsbursky 	return 0;
6378a6d6b781SJeff Layton }
6379d85ed443SStanislav Kinsbursky 
6380d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */
6381d85ed443SStanislav Kinsbursky 
6382d85ed443SStanislav Kinsbursky int
6383d85ed443SStanislav Kinsbursky nfs4_state_start(void)
6384d85ed443SStanislav Kinsbursky {
6385d85ed443SStanislav Kinsbursky 	int ret;
6386d85ed443SStanislav Kinsbursky 
6387d85ed443SStanislav Kinsbursky 	ret = set_callback_cred();
6388d85ed443SStanislav Kinsbursky 	if (ret)
6389d85ed443SStanislav Kinsbursky 		return -ENOMEM;
639058da282bSNeilBrown 	laundry_wq = create_singlethread_workqueue("nfsd4");
6391a6d6b781SJeff Layton 	if (laundry_wq == NULL) {
6392a6d6b781SJeff Layton 		ret = -ENOMEM;
6393a6d6b781SJeff Layton 		goto out_recovery;
6394a6d6b781SJeff Layton 	}
6395b5a1a81eSJ. Bruce Fields 	ret = nfsd4_create_callback_queue();
6396b5a1a81eSJ. Bruce Fields 	if (ret)
6397b5a1a81eSJ. Bruce Fields 		goto out_free_laundry;
639809121281SStanislav Kinsbursky 
6399c2f1a551SMeelap Shah 	set_max_delegations();
6400d85ed443SStanislav Kinsbursky 
6401b5a1a81eSJ. Bruce Fields 	return 0;
6402d85ed443SStanislav Kinsbursky 
6403b5a1a81eSJ. Bruce Fields out_free_laundry:
6404b5a1a81eSJ. Bruce Fields 	destroy_workqueue(laundry_wq);
6405a6d6b781SJeff Layton out_recovery:
6406b5a1a81eSJ. Bruce Fields 	return ret;
64071da177e4SLinus Torvalds }
64081da177e4SLinus Torvalds 
6409f252bc68SStanislav Kinsbursky void
64104dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net)
64111da177e4SLinus Torvalds {
64121da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
64131da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
64144dce0ac9SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
64151da177e4SLinus Torvalds 
64164dce0ac9SStanislav Kinsbursky 	cancel_delayed_work_sync(&nn->laundromat_work);
64174dce0ac9SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
6418ac55fdc4SJeff Layton 
64191da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
6420cdc97505SBenny Halevy 	spin_lock(&state_lock);
6421e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
64221da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
642342690676SJeff Layton 		unhash_delegation_locked(dp);
642442690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
64251da177e4SLinus Torvalds 	}
6426cdc97505SBenny Halevy 	spin_unlock(&state_lock);
64271da177e4SLinus Torvalds 	list_for_each_safe(pos, next, &reaplist) {
64281da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
642942690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
6430afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
64316011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
64321da177e4SLinus Torvalds 	}
64331da177e4SLinus Torvalds 
64343320fef1SStanislav Kinsbursky 	nfsd4_client_tracking_exit(net);
64354dce0ac9SStanislav Kinsbursky 	nfs4_state_destroy_net(net);
64361da177e4SLinus Torvalds }
64371da177e4SLinus Torvalds 
64381da177e4SLinus Torvalds void
64391da177e4SLinus Torvalds nfs4_state_shutdown(void)
64401da177e4SLinus Torvalds {
64415e8d5c29SNeilBrown 	destroy_workqueue(laundry_wq);
6442c3935e30SJ. Bruce Fields 	nfsd4_destroy_callback_queue();
64431da177e4SLinus Torvalds }
64448b70484cSTigran Mkrtchyan 
64458b70484cSTigran Mkrtchyan static void
64468b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
64478b70484cSTigran Mkrtchyan {
644837c593c5STigran Mkrtchyan 	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
644937c593c5STigran Mkrtchyan 		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
64508b70484cSTigran Mkrtchyan }
64518b70484cSTigran Mkrtchyan 
64528b70484cSTigran Mkrtchyan static void
64538b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
64548b70484cSTigran Mkrtchyan {
645537c593c5STigran Mkrtchyan 	if (cstate->minorversion) {
645637c593c5STigran Mkrtchyan 		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
645737c593c5STigran Mkrtchyan 		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
645837c593c5STigran Mkrtchyan 	}
645937c593c5STigran Mkrtchyan }
646037c593c5STigran Mkrtchyan 
646137c593c5STigran Mkrtchyan void
646237c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate)
646337c593c5STigran Mkrtchyan {
646437c593c5STigran Mkrtchyan 	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
64658b70484cSTigran Mkrtchyan }
64668b70484cSTigran Mkrtchyan 
646762cd4a59STigran Mkrtchyan /*
646862cd4a59STigran Mkrtchyan  * functions to set current state id
646962cd4a59STigran Mkrtchyan  */
64708b70484cSTigran Mkrtchyan void
64719428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
64729428fe1aSTigran Mkrtchyan {
64739428fe1aSTigran Mkrtchyan 	put_stateid(cstate, &odp->od_stateid);
64749428fe1aSTigran Mkrtchyan }
64759428fe1aSTigran Mkrtchyan 
64769428fe1aSTigran Mkrtchyan void
64778b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
64788b70484cSTigran Mkrtchyan {
64798b70484cSTigran Mkrtchyan 	put_stateid(cstate, &open->op_stateid);
64808b70484cSTigran Mkrtchyan }
64818b70484cSTigran Mkrtchyan 
64828b70484cSTigran Mkrtchyan void
648362cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
648462cd4a59STigran Mkrtchyan {
648562cd4a59STigran Mkrtchyan 	put_stateid(cstate, &close->cl_stateid);
648662cd4a59STigran Mkrtchyan }
648762cd4a59STigran Mkrtchyan 
648862cd4a59STigran Mkrtchyan void
648962cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
649062cd4a59STigran Mkrtchyan {
649162cd4a59STigran Mkrtchyan 	put_stateid(cstate, &lock->lk_resp_stateid);
649262cd4a59STigran Mkrtchyan }
649362cd4a59STigran Mkrtchyan 
649462cd4a59STigran Mkrtchyan /*
649562cd4a59STigran Mkrtchyan  * functions to consume current state id
649662cd4a59STigran Mkrtchyan  */
64971e97b519STigran Mkrtchyan 
64981e97b519STigran Mkrtchyan void
64999428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
65009428fe1aSTigran Mkrtchyan {
65019428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &odp->od_stateid);
65029428fe1aSTigran Mkrtchyan }
65039428fe1aSTigran Mkrtchyan 
65049428fe1aSTigran Mkrtchyan void
65059428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
65069428fe1aSTigran Mkrtchyan {
65079428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &drp->dr_stateid);
65089428fe1aSTigran Mkrtchyan }
65099428fe1aSTigran Mkrtchyan 
65109428fe1aSTigran Mkrtchyan void
65111e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
65121e97b519STigran Mkrtchyan {
65131e97b519STigran Mkrtchyan 	get_stateid(cstate, &fsp->fr_stateid);
65141e97b519STigran Mkrtchyan }
65151e97b519STigran Mkrtchyan 
65161e97b519STigran Mkrtchyan void
65171e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
65181e97b519STigran Mkrtchyan {
65191e97b519STigran Mkrtchyan 	get_stateid(cstate, &setattr->sa_stateid);
65201e97b519STigran Mkrtchyan }
65211e97b519STigran Mkrtchyan 
652262cd4a59STigran Mkrtchyan void
65238b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
65248b70484cSTigran Mkrtchyan {
65258b70484cSTigran Mkrtchyan 	get_stateid(cstate, &close->cl_stateid);
65268b70484cSTigran Mkrtchyan }
65278b70484cSTigran Mkrtchyan 
65288b70484cSTigran Mkrtchyan void
652962cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
65308b70484cSTigran Mkrtchyan {
653162cd4a59STigran Mkrtchyan 	get_stateid(cstate, &locku->lu_stateid);
65328b70484cSTigran Mkrtchyan }
653330813e27STigran Mkrtchyan 
653430813e27STigran Mkrtchyan void
653530813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
653630813e27STigran Mkrtchyan {
653730813e27STigran Mkrtchyan 	get_stateid(cstate, &read->rd_stateid);
653830813e27STigran Mkrtchyan }
653930813e27STigran Mkrtchyan 
654030813e27STigran Mkrtchyan void
654130813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
654230813e27STigran Mkrtchyan {
654330813e27STigran Mkrtchyan 	get_stateid(cstate, &write->wr_stateid);
654430813e27STigran Mkrtchyan }
6545