xref: /openbmc/linux/fs/nfsd/nfs4state.c (revision 15ca08d3)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds *  Copyright (c) 2001 The Regents of the University of Michigan.
31da177e4SLinus Torvalds *  All rights reserved.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *  Kendrick Smith <kmsmith@umich.edu>
61da177e4SLinus Torvalds *  Andy Adamson <kandros@umich.edu>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds *  Redistribution and use in source and binary forms, with or without
91da177e4SLinus Torvalds *  modification, are permitted provided that the following conditions
101da177e4SLinus Torvalds *  are met:
111da177e4SLinus Torvalds *
121da177e4SLinus Torvalds *  1. Redistributions of source code must retain the above copyright
131da177e4SLinus Torvalds *     notice, this list of conditions and the following disclaimer.
141da177e4SLinus Torvalds *  2. Redistributions in binary form must reproduce the above copyright
151da177e4SLinus Torvalds *     notice, this list of conditions and the following disclaimer in the
161da177e4SLinus Torvalds *     documentation and/or other materials provided with the distribution.
171da177e4SLinus Torvalds *  3. Neither the name of the University nor the names of its
181da177e4SLinus Torvalds *     contributors may be used to endorse or promote products derived
191da177e4SLinus Torvalds *     from this software without specific prior written permission.
201da177e4SLinus Torvalds *
211da177e4SLinus Torvalds *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
221da177e4SLinus Torvalds *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
231da177e4SLinus Torvalds *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
241da177e4SLinus Torvalds *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251da177e4SLinus Torvalds *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
261da177e4SLinus Torvalds *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
271da177e4SLinus Torvalds *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
281da177e4SLinus Torvalds *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
291da177e4SLinus Torvalds *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
301da177e4SLinus Torvalds *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
311da177e4SLinus Torvalds *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
321da177e4SLinus Torvalds *
331da177e4SLinus Torvalds */
341da177e4SLinus Torvalds 
35aceaf78dSDave Hansen #include <linux/file.h>
36b89f4321SArnd Bergmann #include <linux/fs.h>
375a0e3ad6STejun Heo #include <linux/slab.h>
380964a3d3SNeilBrown #include <linux/namei.h>
39c2f1a551SMeelap Shah #include <linux/swap.h>
4017456804SBryan Schumaker #include <linux/pagemap.h>
417df302f7SChuck Lever #include <linux/ratelimit.h>
4268e76ad0SOlga Kornievskaia #include <linux/sunrpc/svcauth_gss.h>
435976687aSJeff Layton #include <linux/sunrpc/addr.h>
4487545899SDaniel Borkmann #include <linux/jhash.h>
459a74af21SBoaz Harrosh #include "xdr4.h"
4606b332a5SJ. Bruce Fields #include "xdr4cb.h"
470a3adadeSJ. Bruce Fields #include "vfs.h"
48bfa4b365SJ. Bruce Fields #include "current_stateid.h"
491da177e4SLinus Torvalds 
505e1533c7SStanislav Kinsbursky #include "netns.h"
519cf514ccSChristoph Hellwig #include "pnfs.h"
525e1533c7SStanislav Kinsbursky 
531da177e4SLinus Torvalds #define NFSDDBG_FACILITY                NFSDDBG_PROC
541da177e4SLinus Torvalds 
55f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0}
56f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = {
57f32f3c2dSJ. Bruce Fields 	.si_generation = ~0,
58f32f3c2dSJ. Bruce Fields 	.si_opaque = all_ones,
59f32f3c2dSJ. Bruce Fields };
60f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = {
61f32f3c2dSJ. Bruce Fields 	/* all fields zero */
62f32f3c2dSJ. Bruce Fields };
6319ff0f28STigran Mkrtchyan static const stateid_t currentstateid = {
6419ff0f28STigran Mkrtchyan 	.si_generation = 1,
6519ff0f28STigran Mkrtchyan };
66f32f3c2dSJ. Bruce Fields 
67ec6b5d7bSAndy Adamson static u64 current_sessionid = 1;
68fd39ca9aSNeilBrown 
69f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
70f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
7119ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds /* forward declarations */
74f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
756011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
761da177e4SLinus Torvalds 
778b671b80SJ. Bruce Fields /* Locking: */
788b671b80SJ. Bruce Fields 
798b671b80SJ. Bruce Fields /*
808b671b80SJ. Bruce Fields  * Currently used for the del_recall_lru and file hash table.  In an
818b671b80SJ. Bruce Fields  * effort to decrease the scope of the client_mutex, this spinlock may
828b671b80SJ. Bruce Fields  * eventually cover more:
838b671b80SJ. Bruce Fields  */
84cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock);
858b671b80SJ. Bruce Fields 
86b401be22SJeff Layton /*
87b401be22SJeff Layton  * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for
88b401be22SJeff Layton  * the refcount on the open stateid to drop.
89b401be22SJeff Layton  */
90b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq);
91b401be22SJeff Layton 
92abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab;
93abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab;
94abf1135bSChristoph Hellwig static struct kmem_cache *file_slab;
95abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab;
96abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab;
978287f009SSachin Bhamare static struct kmem_cache *odstate_slab;
98e60d4398SNeilBrown 
9966b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *);
100508dc6e1SBenny Halevy 
101c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
10276d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;
1030162ac2bSChristoph Hellwig 
10466b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses)
105508dc6e1SBenny Halevy {
10666b2b9b2SJ. Bruce Fields 	return ses->se_flags & NFS4_SESSION_DEAD;
10766b2b9b2SJ. Bruce Fields }
10866b2b9b2SJ. Bruce Fields 
109f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
110f0f51f5cSJ. Bruce Fields {
111f0f51f5cSJ. Bruce Fields 	if (atomic_read(&ses->se_ref) > ref_held_by_me)
11266b2b9b2SJ. Bruce Fields 		return nfserr_jukebox;
11366b2b9b2SJ. Bruce Fields 	ses->se_flags |= NFS4_SESSION_DEAD;
11466b2b9b2SJ. Bruce Fields 	return nfs_ok;
11566b2b9b2SJ. Bruce Fields }
11666b2b9b2SJ. Bruce Fields 
117221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp)
118221a6876SJ. Bruce Fields {
119221a6876SJ. Bruce Fields 	return clp->cl_time == 0;
120221a6876SJ. Bruce Fields }
121221a6876SJ. Bruce Fields 
122221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp)
123221a6876SJ. Bruce Fields {
1240a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1250a880a28STrond Myklebust 
1260a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1270a880a28STrond Myklebust 
128221a6876SJ. Bruce Fields 	if (is_client_expired(clp))
129221a6876SJ. Bruce Fields 		return nfserr_expired;
130221a6876SJ. Bruce Fields 	atomic_inc(&clp->cl_refcount);
131221a6876SJ. Bruce Fields 	return nfs_ok;
132221a6876SJ. Bruce Fields }
133221a6876SJ. Bruce Fields 
134221a6876SJ. Bruce Fields /* must be called under the client_lock */
135221a6876SJ. Bruce Fields static inline void
136221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp)
137221a6876SJ. Bruce Fields {
138221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
139221a6876SJ. Bruce Fields 
140221a6876SJ. Bruce Fields 	if (is_client_expired(clp)) {
141221a6876SJ. Bruce Fields 		WARN_ON(1);
142221a6876SJ. Bruce Fields 		printk("%s: client (clientid %08x/%08x) already expired\n",
143221a6876SJ. Bruce Fields 			__func__,
144221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
145221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
146221a6876SJ. Bruce Fields 		return;
147221a6876SJ. Bruce Fields 	}
148221a6876SJ. Bruce Fields 
149221a6876SJ. Bruce Fields 	dprintk("renewing client (clientid %08x/%08x)\n",
150221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
151221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
152221a6876SJ. Bruce Fields 	list_move_tail(&clp->cl_lru, &nn->client_lru);
153221a6876SJ. Bruce Fields 	clp->cl_time = get_seconds();
154221a6876SJ. Bruce Fields }
155221a6876SJ. Bruce Fields 
156ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp)
157221a6876SJ. Bruce Fields {
1580a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1590a880a28STrond Myklebust 
1600a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1610a880a28STrond Myklebust 
162221a6876SJ. Bruce Fields 	if (!atomic_dec_and_test(&clp->cl_refcount))
163221a6876SJ. Bruce Fields 		return;
164221a6876SJ. Bruce Fields 	if (!is_client_expired(clp))
165221a6876SJ. Bruce Fields 		renew_client_locked(clp);
166221a6876SJ. Bruce Fields }
167221a6876SJ. Bruce Fields 
1684b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp)
1694b24ca7dSJeff Layton {
1704b24ca7dSJeff Layton 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1714b24ca7dSJeff Layton 
172d6c249b4SJeff Layton 	if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
173d6c249b4SJeff Layton 		return;
174d6c249b4SJeff Layton 	if (!is_client_expired(clp))
175d6c249b4SJeff Layton 		renew_client_locked(clp);
1764b24ca7dSJeff Layton 	spin_unlock(&nn->client_lock);
1774b24ca7dSJeff Layton }
1784b24ca7dSJeff Layton 
179d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
180d4e19e70STrond Myklebust {
181d4e19e70STrond Myklebust 	__be32 status;
182d4e19e70STrond Myklebust 
183d4e19e70STrond Myklebust 	if (is_session_dead(ses))
184d4e19e70STrond Myklebust 		return nfserr_badsession;
185d4e19e70STrond Myklebust 	status = get_client_locked(ses->se_client);
186d4e19e70STrond Myklebust 	if (status)
187d4e19e70STrond Myklebust 		return status;
188d4e19e70STrond Myklebust 	atomic_inc(&ses->se_ref);
189d4e19e70STrond Myklebust 	return nfs_ok;
190d4e19e70STrond Myklebust }
191d4e19e70STrond Myklebust 
192d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses)
193d4e19e70STrond Myklebust {
194d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
1950a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1960a880a28STrond Myklebust 
1970a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
198d4e19e70STrond Myklebust 
199d4e19e70STrond Myklebust 	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
200d4e19e70STrond Myklebust 		free_session(ses);
201d4e19e70STrond Myklebust 	put_client_renew_locked(clp);
202d4e19e70STrond Myklebust }
203d4e19e70STrond Myklebust 
204d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses)
205d4e19e70STrond Myklebust {
206d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
207d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
208d4e19e70STrond Myklebust 
209d4e19e70STrond Myklebust 	spin_lock(&nn->client_lock);
210d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
211d4e19e70STrond Myklebust 	spin_unlock(&nn->client_lock);
212d4e19e70STrond Myklebust }
213d4e19e70STrond Myklebust 
21476d348faSJeff Layton static struct nfsd4_blocked_lock *
21576d348faSJeff Layton find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
21676d348faSJeff Layton 			struct nfsd_net *nn)
21776d348faSJeff Layton {
21876d348faSJeff Layton 	struct nfsd4_blocked_lock *cur, *found = NULL;
21976d348faSJeff Layton 
2200cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
22176d348faSJeff Layton 	list_for_each_entry(cur, &lo->lo_blocked, nbl_list) {
22276d348faSJeff Layton 		if (fh_match(fh, &cur->nbl_fh)) {
22376d348faSJeff Layton 			list_del_init(&cur->nbl_list);
2247919d0a2SJeff Layton 			list_del_init(&cur->nbl_lru);
22576d348faSJeff Layton 			found = cur;
22676d348faSJeff Layton 			break;
22776d348faSJeff Layton 		}
22876d348faSJeff Layton 	}
2290cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
23076d348faSJeff Layton 	if (found)
23176d348faSJeff Layton 		posix_unblock_lock(&found->nbl_lock);
23276d348faSJeff Layton 	return found;
23376d348faSJeff Layton }
23476d348faSJeff Layton 
23576d348faSJeff Layton static struct nfsd4_blocked_lock *
23676d348faSJeff Layton find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
23776d348faSJeff Layton 			struct nfsd_net *nn)
23876d348faSJeff Layton {
23976d348faSJeff Layton 	struct nfsd4_blocked_lock *nbl;
24076d348faSJeff Layton 
24176d348faSJeff Layton 	nbl = find_blocked_lock(lo, fh, nn);
24276d348faSJeff Layton 	if (!nbl) {
24376d348faSJeff Layton 		nbl= kmalloc(sizeof(*nbl), GFP_KERNEL);
24476d348faSJeff Layton 		if (nbl) {
24576d348faSJeff Layton 			fh_copy_shallow(&nbl->nbl_fh, fh);
24676d348faSJeff Layton 			locks_init_lock(&nbl->nbl_lock);
24776d348faSJeff Layton 			nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client,
24876d348faSJeff Layton 					&nfsd4_cb_notify_lock_ops,
24976d348faSJeff Layton 					NFSPROC4_CLNT_CB_NOTIFY_LOCK);
25076d348faSJeff Layton 		}
25176d348faSJeff Layton 	}
25276d348faSJeff Layton 	return nbl;
25376d348faSJeff Layton }
25476d348faSJeff Layton 
25576d348faSJeff Layton static void
25676d348faSJeff Layton free_blocked_lock(struct nfsd4_blocked_lock *nbl)
25776d348faSJeff Layton {
25876d348faSJeff Layton 	locks_release_private(&nbl->nbl_lock);
25976d348faSJeff Layton 	kfree(nbl);
26076d348faSJeff Layton }
26176d348faSJeff Layton 
26276d348faSJeff Layton static int
26376d348faSJeff Layton nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task)
26476d348faSJeff Layton {
26576d348faSJeff Layton 	/*
26676d348faSJeff Layton 	 * Since this is just an optimization, we don't try very hard if it
26776d348faSJeff Layton 	 * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and
26876d348faSJeff Layton 	 * just quit trying on anything else.
26976d348faSJeff Layton 	 */
27076d348faSJeff Layton 	switch (task->tk_status) {
27176d348faSJeff Layton 	case -NFS4ERR_DELAY:
27276d348faSJeff Layton 		rpc_delay(task, 1 * HZ);
27376d348faSJeff Layton 		return 0;
27476d348faSJeff Layton 	default:
27576d348faSJeff Layton 		return 1;
27676d348faSJeff Layton 	}
27776d348faSJeff Layton }
27876d348faSJeff Layton 
27976d348faSJeff Layton static void
28076d348faSJeff Layton nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb)
28176d348faSJeff Layton {
28276d348faSJeff Layton 	struct nfsd4_blocked_lock	*nbl = container_of(cb,
28376d348faSJeff Layton 						struct nfsd4_blocked_lock, nbl_cb);
28476d348faSJeff Layton 
28576d348faSJeff Layton 	free_blocked_lock(nbl);
28676d348faSJeff Layton }
28776d348faSJeff Layton 
28876d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = {
28976d348faSJeff Layton 	.done		= nfsd4_cb_notify_lock_done,
29076d348faSJeff Layton 	.release	= nfsd4_cb_notify_lock_release,
29176d348faSJeff Layton };
29276d348faSJeff Layton 
293b5971afaSKinglong Mee static inline struct nfs4_stateowner *
294b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop)
295b5971afaSKinglong Mee {
296b5971afaSKinglong Mee 	atomic_inc(&sop->so_count);
297b5971afaSKinglong Mee 	return sop;
298b5971afaSKinglong Mee }
299b5971afaSKinglong Mee 
3007ffb5880STrond Myklebust static int
301d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
3027ffb5880STrond Myklebust {
3037ffb5880STrond Myklebust 	return (sop->so_owner.len == owner->len) &&
304d4f0489fSTrond Myklebust 		0 == memcmp(sop->so_owner.data, owner->data, owner->len);
3057ffb5880STrond Myklebust }
3067ffb5880STrond Myklebust 
3077ffb5880STrond Myklebust static struct nfs4_openowner *
3087ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
309d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
3107ffb5880STrond Myklebust {
3117ffb5880STrond Myklebust 	struct nfs4_stateowner *so;
3127ffb5880STrond Myklebust 
313d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
3147ffb5880STrond Myklebust 
315d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval],
316d4f0489fSTrond Myklebust 			    so_strhash) {
3177ffb5880STrond Myklebust 		if (!so->so_is_open_owner)
3187ffb5880STrond Myklebust 			continue;
319b5971afaSKinglong Mee 		if (same_owner_str(so, &open->op_owner))
320b5971afaSKinglong Mee 			return openowner(nfs4_get_stateowner(so));
3217ffb5880STrond Myklebust 	}
3227ffb5880STrond Myklebust 	return NULL;
3237ffb5880STrond Myklebust }
3247ffb5880STrond Myklebust 
3257ffb5880STrond Myklebust static struct nfs4_openowner *
3267ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
327d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
3287ffb5880STrond Myklebust {
3297ffb5880STrond Myklebust 	struct nfs4_openowner *oo;
3307ffb5880STrond Myklebust 
331d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
332d4f0489fSTrond Myklebust 	oo = find_openstateowner_str_locked(hashval, open, clp);
333d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
3347ffb5880STrond Myklebust 	return oo;
3357ffb5880STrond Myklebust }
3367ffb5880STrond Myklebust 
3371da177e4SLinus Torvalds static inline u32
3381da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes)
3391da177e4SLinus Torvalds {
3401da177e4SLinus Torvalds 	unsigned char *cptr = (unsigned char *) ptr;
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 	u32 x = 0;
3431da177e4SLinus Torvalds 	while (nbytes--) {
3441da177e4SLinus Torvalds 		x *= 37;
3451da177e4SLinus Torvalds 		x += *cptr++;
3461da177e4SLinus Torvalds 	}
3471da177e4SLinus Torvalds 	return x;
3481da177e4SLinus Torvalds }
3491da177e4SLinus Torvalds 
3505b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu)
35132513b40SJ. Bruce Fields {
3525b095e99SJeff Layton 	struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu);
3535b095e99SJeff Layton 
3545b095e99SJeff Layton 	kmem_cache_free(file_slab, fp);
35532513b40SJ. Bruce Fields }
35632513b40SJ. Bruce Fields 
357e6ba76e1SChristoph Hellwig void
35813cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi)
35913cd2184SNeilBrown {
36002e1215fSJeff Layton 	might_lock(&state_lock);
36102e1215fSJeff Layton 
362818a34ebSElena Reshetova 	if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) {
3635b095e99SJeff Layton 		hlist_del_rcu(&fi->fi_hash);
364cdc97505SBenny Halevy 		spin_unlock(&state_lock);
3658287f009SSachin Bhamare 		WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
3665b095e99SJeff Layton 		WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
3675b095e99SJeff Layton 		call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
3688b671b80SJ. Bruce Fields 	}
36913cd2184SNeilBrown }
37013cd2184SNeilBrown 
371de18643dSTrond Myklebust static struct file *
372de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag)
373de18643dSTrond Myklebust {
374de18643dSTrond Myklebust 	if (f->fi_fds[oflag])
375de18643dSTrond Myklebust 		return get_file(f->fi_fds[oflag]);
376de18643dSTrond Myklebust 	return NULL;
377de18643dSTrond Myklebust }
378de18643dSTrond Myklebust 
379de18643dSTrond Myklebust static struct file *
380de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f)
381de18643dSTrond Myklebust {
382de18643dSTrond Myklebust 	struct file *ret;
383de18643dSTrond Myklebust 
384de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
385de18643dSTrond Myklebust 
386de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_WRONLY);
387de18643dSTrond Myklebust 	if (!ret)
388de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
389de18643dSTrond Myklebust 	return ret;
390de18643dSTrond Myklebust }
391de18643dSTrond Myklebust 
392de18643dSTrond Myklebust static struct file *
393de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f)
394de18643dSTrond Myklebust {
395de18643dSTrond Myklebust 	struct file *ret;
396de18643dSTrond Myklebust 
397de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
398de18643dSTrond Myklebust 	ret = find_writeable_file_locked(f);
399de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
400de18643dSTrond Myklebust 
401de18643dSTrond Myklebust 	return ret;
402de18643dSTrond Myklebust }
403de18643dSTrond Myklebust 
404de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f)
405de18643dSTrond Myklebust {
406de18643dSTrond Myklebust 	struct file *ret;
407de18643dSTrond Myklebust 
408de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
409de18643dSTrond Myklebust 
410de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDONLY);
411de18643dSTrond Myklebust 	if (!ret)
412de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
413de18643dSTrond Myklebust 	return ret;
414de18643dSTrond Myklebust }
415de18643dSTrond Myklebust 
416de18643dSTrond Myklebust static struct file *
417de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f)
418de18643dSTrond Myklebust {
419de18643dSTrond Myklebust 	struct file *ret;
420de18643dSTrond Myklebust 
421de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
422de18643dSTrond Myklebust 	ret = find_readable_file_locked(f);
423de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
424de18643dSTrond Myklebust 
425de18643dSTrond Myklebust 	return ret;
426de18643dSTrond Myklebust }
427de18643dSTrond Myklebust 
4284d227fcaSChristoph Hellwig struct file *
429de18643dSTrond Myklebust find_any_file(struct nfs4_file *f)
430de18643dSTrond Myklebust {
431de18643dSTrond Myklebust 	struct file *ret;
432de18643dSTrond Myklebust 
433de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
434de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDWR);
435de18643dSTrond Myklebust 	if (!ret) {
436de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_WRONLY);
437de18643dSTrond Myklebust 		if (!ret)
438de18643dSTrond Myklebust 			ret = __nfs4_get_fd(f, O_RDONLY);
439de18643dSTrond Myklebust 	}
440de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
441de18643dSTrond Myklebust 	return ret;
442de18643dSTrond Myklebust }
443de18643dSTrond Myklebust 
44402a3508dSTrond Myklebust static atomic_long_t num_delegations;
445697ce9beSZhang Yanfei unsigned long max_delegations;
446ef0f3390SNeilBrown 
447ef0f3390SNeilBrown /*
448ef0f3390SNeilBrown  * Open owner state (share locks)
449ef0f3390SNeilBrown  */
450ef0f3390SNeilBrown 
45116bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */
45216bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS              8
45316bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
45416bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
455ef0f3390SNeilBrown 
456d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername)
457ddc04c41SJ. Bruce Fields {
458ddc04c41SJ. Bruce Fields 	unsigned int ret;
459ddc04c41SJ. Bruce Fields 
460ddc04c41SJ. Bruce Fields 	ret = opaque_hashval(ownername->data, ownername->len);
46116bfdaafSJ. Bruce Fields 	return ret & OWNER_HASH_MASK;
462ddc04c41SJ. Bruce Fields }
463ef0f3390SNeilBrown 
464ef0f3390SNeilBrown /* hash table for nfs4_file */
465ef0f3390SNeilBrown #define FILE_HASH_BITS                   8
466ef0f3390SNeilBrown #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
46735079582SShan Wei 
468ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh)
469ddc04c41SJ. Bruce Fields {
470ca943217STrond Myklebust 	return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0);
471ca943217STrond Myklebust }
472ca943217STrond Myklebust 
473ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh)
474ca943217STrond Myklebust {
475ca943217STrond Myklebust 	return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1);
476ca943217STrond Myklebust }
477ca943217STrond Myklebust 
47889876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
479ef0f3390SNeilBrown 
48012659651SJeff Layton static void
48112659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
4823477565eSJ. Bruce Fields {
4837214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4847214e860SJeff Layton 
48512659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
48612659651SJeff Layton 		atomic_inc(&fp->fi_access[O_WRONLY]);
48712659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
48812659651SJeff Layton 		atomic_inc(&fp->fi_access[O_RDONLY]);
4893477565eSJ. Bruce Fields }
4903477565eSJ. Bruce Fields 
49112659651SJeff Layton static __be32
49212659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access)
493998db52cSJ. Bruce Fields {
4947214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4957214e860SJeff Layton 
49612659651SJeff Layton 	/* Does this access mode make sense? */
49712659651SJeff Layton 	if (access & ~NFS4_SHARE_ACCESS_BOTH)
49812659651SJeff Layton 		return nfserr_inval;
49912659651SJeff Layton 
500baeb4ff0SJeff Layton 	/* Does it conflict with a deny mode already set? */
501baeb4ff0SJeff Layton 	if ((access & fp->fi_share_deny) != 0)
502baeb4ff0SJeff Layton 		return nfserr_share_denied;
503baeb4ff0SJeff Layton 
50412659651SJeff Layton 	__nfs4_file_get_access(fp, access);
50512659651SJeff Layton 	return nfs_ok;
506998db52cSJ. Bruce Fields }
507998db52cSJ. Bruce Fields 
508baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny)
509baeb4ff0SJeff Layton {
510baeb4ff0SJeff Layton 	/* Common case is that there is no deny mode. */
511baeb4ff0SJeff Layton 	if (deny) {
512baeb4ff0SJeff Layton 		/* Does this deny mode make sense? */
513baeb4ff0SJeff Layton 		if (deny & ~NFS4_SHARE_DENY_BOTH)
514baeb4ff0SJeff Layton 			return nfserr_inval;
515baeb4ff0SJeff Layton 
516baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_READ) &&
517baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_RDONLY]))
518baeb4ff0SJeff Layton 			return nfserr_share_denied;
519baeb4ff0SJeff Layton 
520baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_WRITE) &&
521baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_WRONLY]))
522baeb4ff0SJeff Layton 			return nfserr_share_denied;
523baeb4ff0SJeff Layton 	}
524baeb4ff0SJeff Layton 	return nfs_ok;
525baeb4ff0SJeff Layton }
526baeb4ff0SJeff Layton 
527998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
528f9d7562fSJ. Bruce Fields {
529de18643dSTrond Myklebust 	might_lock(&fp->fi_lock);
530de18643dSTrond Myklebust 
531de18643dSTrond Myklebust 	if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) {
532de18643dSTrond Myklebust 		struct file *f1 = NULL;
533de18643dSTrond Myklebust 		struct file *f2 = NULL;
534de18643dSTrond Myklebust 
5356d338b51SJeff Layton 		swap(f1, fp->fi_fds[oflag]);
5360c7c3e67SJ. Bruce Fields 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
5376d338b51SJeff Layton 			swap(f2, fp->fi_fds[O_RDWR]);
538de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
539de18643dSTrond Myklebust 		if (f1)
540de18643dSTrond Myklebust 			fput(f1);
541de18643dSTrond Myklebust 		if (f2)
542de18643dSTrond Myklebust 			fput(f2);
543f9d7562fSJ. Bruce Fields 	}
544f9d7562fSJ. Bruce Fields }
545f9d7562fSJ. Bruce Fields 
54612659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
547998db52cSJ. Bruce Fields {
54812659651SJeff Layton 	WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH);
54912659651SJeff Layton 
55012659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
551998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, O_WRONLY);
55212659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
55312659651SJeff Layton 		__nfs4_file_put_access(fp, O_RDONLY);
554998db52cSJ. Bruce Fields }
555998db52cSJ. Bruce Fields 
5568287f009SSachin Bhamare /*
5578287f009SSachin Bhamare  * Allocate a new open/delegation state counter. This is needed for
5588287f009SSachin Bhamare  * pNFS for proper return on close semantics.
5598287f009SSachin Bhamare  *
5608287f009SSachin Bhamare  * Note that we only allocate it for pNFS-enabled exports, otherwise
5618287f009SSachin Bhamare  * all pointers to struct nfs4_clnt_odstate are always NULL.
5628287f009SSachin Bhamare  */
5638287f009SSachin Bhamare static struct nfs4_clnt_odstate *
5648287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp)
5658287f009SSachin Bhamare {
5668287f009SSachin Bhamare 	struct nfs4_clnt_odstate *co;
5678287f009SSachin Bhamare 
5688287f009SSachin Bhamare 	co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL);
5698287f009SSachin Bhamare 	if (co) {
5708287f009SSachin Bhamare 		co->co_client = clp;
571cff7cb2eSElena Reshetova 		refcount_set(&co->co_odcount, 1);
5728287f009SSachin Bhamare 	}
5738287f009SSachin Bhamare 	return co;
5748287f009SSachin Bhamare }
5758287f009SSachin Bhamare 
5768287f009SSachin Bhamare static void
5778287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co)
5788287f009SSachin Bhamare {
5798287f009SSachin Bhamare 	struct nfs4_file *fp = co->co_file;
5808287f009SSachin Bhamare 
5818287f009SSachin Bhamare 	lockdep_assert_held(&fp->fi_lock);
5828287f009SSachin Bhamare 	list_add(&co->co_perfile, &fp->fi_clnt_odstate);
5838287f009SSachin Bhamare }
5848287f009SSachin Bhamare 
5858287f009SSachin Bhamare static inline void
5868287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co)
5878287f009SSachin Bhamare {
5888287f009SSachin Bhamare 	if (co)
589cff7cb2eSElena Reshetova 		refcount_inc(&co->co_odcount);
5908287f009SSachin Bhamare }
5918287f009SSachin Bhamare 
5928287f009SSachin Bhamare static void
5938287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co)
5948287f009SSachin Bhamare {
5958287f009SSachin Bhamare 	struct nfs4_file *fp;
5968287f009SSachin Bhamare 
5978287f009SSachin Bhamare 	if (!co)
5988287f009SSachin Bhamare 		return;
5998287f009SSachin Bhamare 
6008287f009SSachin Bhamare 	fp = co->co_file;
601cff7cb2eSElena Reshetova 	if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
6028287f009SSachin Bhamare 		list_del(&co->co_perfile);
6038287f009SSachin Bhamare 		spin_unlock(&fp->fi_lock);
6048287f009SSachin Bhamare 
6058287f009SSachin Bhamare 		nfsd4_return_all_file_layouts(co->co_client, fp);
6068287f009SSachin Bhamare 		kmem_cache_free(odstate_slab, co);
6078287f009SSachin Bhamare 	}
6088287f009SSachin Bhamare }
6098287f009SSachin Bhamare 
6108287f009SSachin Bhamare static struct nfs4_clnt_odstate *
6118287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new)
6128287f009SSachin Bhamare {
6138287f009SSachin Bhamare 	struct nfs4_clnt_odstate *co;
6148287f009SSachin Bhamare 	struct nfs4_client *cl;
6158287f009SSachin Bhamare 
6168287f009SSachin Bhamare 	if (!new)
6178287f009SSachin Bhamare 		return NULL;
6188287f009SSachin Bhamare 
6198287f009SSachin Bhamare 	cl = new->co_client;
6208287f009SSachin Bhamare 
6218287f009SSachin Bhamare 	spin_lock(&fp->fi_lock);
6228287f009SSachin Bhamare 	list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) {
6238287f009SSachin Bhamare 		if (co->co_client == cl) {
6248287f009SSachin Bhamare 			get_clnt_odstate(co);
6258287f009SSachin Bhamare 			goto out;
6268287f009SSachin Bhamare 		}
6278287f009SSachin Bhamare 	}
6288287f009SSachin Bhamare 	co = new;
6298287f009SSachin Bhamare 	co->co_file = fp;
6308287f009SSachin Bhamare 	hash_clnt_odstate_locked(new);
6318287f009SSachin Bhamare out:
6328287f009SSachin Bhamare 	spin_unlock(&fp->fi_lock);
6338287f009SSachin Bhamare 	return co;
6348287f009SSachin Bhamare }
6358287f009SSachin Bhamare 
636d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
637d19fb70dSKinglong Mee 				  void (*sc_free)(struct nfs4_stid *))
638996e0938SJ. Bruce Fields {
6393abdb607SJ. Bruce Fields 	struct nfs4_stid *stid;
6403abdb607SJ. Bruce Fields 	int new_id;
6413abdb607SJ. Bruce Fields 
642f8338834STrond Myklebust 	stid = kmem_cache_zalloc(slab, GFP_KERNEL);
6433abdb607SJ. Bruce Fields 	if (!stid)
6443abdb607SJ. Bruce Fields 		return NULL;
645996e0938SJ. Bruce Fields 
6464770d722SJeff Layton 	idr_preload(GFP_KERNEL);
6474770d722SJeff Layton 	spin_lock(&cl->cl_lock);
6484770d722SJeff Layton 	new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT);
6494770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
6504770d722SJeff Layton 	idr_preload_end();
651ebd6c707STejun Heo 	if (new_id < 0)
6523abdb607SJ. Bruce Fields 		goto out_free;
653d19fb70dSKinglong Mee 
654d19fb70dSKinglong Mee 	stid->sc_free = sc_free;
6553abdb607SJ. Bruce Fields 	stid->sc_client = cl;
6563abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_id = new_id;
6573abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
6583abdb607SJ. Bruce Fields 	/* Will be incremented before return to client: */
659a15dfcd5SElena Reshetova 	refcount_set(&stid->sc_count, 1);
6609767feb2SJeff Layton 	spin_lock_init(&stid->sc_lock);
6613abdb607SJ. Bruce Fields 
662996e0938SJ. Bruce Fields 	/*
6633abdb607SJ. Bruce Fields 	 * It shouldn't be a problem to reuse an opaque stateid value.
6643abdb607SJ. Bruce Fields 	 * I don't think it is for 4.1.  But with 4.0 I worry that, for
6653abdb607SJ. Bruce Fields 	 * example, a stray write retransmission could be accepted by
6663abdb607SJ. Bruce Fields 	 * the server when it should have been rejected.  Therefore,
6673abdb607SJ. Bruce Fields 	 * adopt a trick from the sctp code to attempt to maximize the
6683abdb607SJ. Bruce Fields 	 * amount of time until an id is reused, by ensuring they always
6693abdb607SJ. Bruce Fields 	 * "increase" (mod INT_MAX):
670996e0938SJ. Bruce Fields 	 */
6713abdb607SJ. Bruce Fields 	return stid;
6723abdb607SJ. Bruce Fields out_free:
6732c44a234SWei Yongjun 	kmem_cache_free(slab, stid);
6743abdb607SJ. Bruce Fields 	return NULL;
6752a74aba7SJ. Bruce Fields }
6762a74aba7SJ. Bruce Fields 
677b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
6784cdc951bSJ. Bruce Fields {
6796011695dSTrond Myklebust 	struct nfs4_stid *stid;
6806011695dSTrond Myklebust 
681d19fb70dSKinglong Mee 	stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
6826011695dSTrond Myklebust 	if (!stid)
6836011695dSTrond Myklebust 		return NULL;
6846011695dSTrond Myklebust 
685d19fb70dSKinglong Mee 	return openlockstateid(stid);
6866011695dSTrond Myklebust }
6876011695dSTrond Myklebust 
6886011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid)
6896011695dSTrond Myklebust {
6906011695dSTrond Myklebust 	kmem_cache_free(deleg_slab, stid);
6916011695dSTrond Myklebust 	atomic_long_dec(&num_delegations);
6924cdc951bSJ. Bruce Fields }
6934cdc951bSJ. Bruce Fields 
6946282cd56SNeilBrown /*
6956282cd56SNeilBrown  * When we recall a delegation, we should be careful not to hand it
6966282cd56SNeilBrown  * out again straight away.
6976282cd56SNeilBrown  * To ensure this we keep a pair of bloom filters ('new' and 'old')
6986282cd56SNeilBrown  * in which the filehandles of recalled delegations are "stored".
6996282cd56SNeilBrown  * If a filehandle appear in either filter, a delegation is blocked.
7006282cd56SNeilBrown  * When a delegation is recalled, the filehandle is stored in the "new"
7016282cd56SNeilBrown  * filter.
7026282cd56SNeilBrown  * Every 30 seconds we swap the filters and clear the "new" one,
7036282cd56SNeilBrown  * unless both are empty of course.
7046282cd56SNeilBrown  *
7056282cd56SNeilBrown  * Each filter is 256 bits.  We hash the filehandle to 32bit and use the
7066282cd56SNeilBrown  * low 3 bytes as hash-table indices.
7076282cd56SNeilBrown  *
708f54fe962SJeff Layton  * 'blocked_delegations_lock', which is always taken in block_delegations(),
7096282cd56SNeilBrown  * is used to manage concurrent access.  Testing does not need the lock
7106282cd56SNeilBrown  * except when swapping the two filters.
7116282cd56SNeilBrown  */
712f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock);
7136282cd56SNeilBrown static struct bloom_pair {
7146282cd56SNeilBrown 	int	entries, old_entries;
7156282cd56SNeilBrown 	time_t	swap_time;
7166282cd56SNeilBrown 	int	new; /* index into 'set' */
7176282cd56SNeilBrown 	DECLARE_BITMAP(set[2], 256);
7186282cd56SNeilBrown } blocked_delegations;
7196282cd56SNeilBrown 
7206282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh)
7216282cd56SNeilBrown {
7226282cd56SNeilBrown 	u32 hash;
7236282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
7246282cd56SNeilBrown 
7256282cd56SNeilBrown 	if (bd->entries == 0)
7266282cd56SNeilBrown 		return 0;
7276282cd56SNeilBrown 	if (seconds_since_boot() - bd->swap_time > 30) {
728f54fe962SJeff Layton 		spin_lock(&blocked_delegations_lock);
7296282cd56SNeilBrown 		if (seconds_since_boot() - bd->swap_time > 30) {
7306282cd56SNeilBrown 			bd->entries -= bd->old_entries;
7316282cd56SNeilBrown 			bd->old_entries = bd->entries;
7326282cd56SNeilBrown 			memset(bd->set[bd->new], 0,
7336282cd56SNeilBrown 			       sizeof(bd->set[0]));
7346282cd56SNeilBrown 			bd->new = 1-bd->new;
7356282cd56SNeilBrown 			bd->swap_time = seconds_since_boot();
7366282cd56SNeilBrown 		}
737f54fe962SJeff Layton 		spin_unlock(&blocked_delegations_lock);
7386282cd56SNeilBrown 	}
73987545899SDaniel Borkmann 	hash = jhash(&fh->fh_base, fh->fh_size, 0);
7406282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[0]) &&
7416282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[0]) &&
7426282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[0]))
7436282cd56SNeilBrown 		return 1;
7446282cd56SNeilBrown 
7456282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[1]) &&
7466282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[1]) &&
7476282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[1]))
7486282cd56SNeilBrown 		return 1;
7496282cd56SNeilBrown 
7506282cd56SNeilBrown 	return 0;
7516282cd56SNeilBrown }
7526282cd56SNeilBrown 
7536282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh)
7546282cd56SNeilBrown {
7556282cd56SNeilBrown 	u32 hash;
7566282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
7576282cd56SNeilBrown 
75887545899SDaniel Borkmann 	hash = jhash(&fh->fh_base, fh->fh_size, 0);
7596282cd56SNeilBrown 
760f54fe962SJeff Layton 	spin_lock(&blocked_delegations_lock);
7616282cd56SNeilBrown 	__set_bit(hash&255, bd->set[bd->new]);
7626282cd56SNeilBrown 	__set_bit((hash>>8)&255, bd->set[bd->new]);
7636282cd56SNeilBrown 	__set_bit((hash>>16)&255, bd->set[bd->new]);
7646282cd56SNeilBrown 	if (bd->entries == 0)
7656282cd56SNeilBrown 		bd->swap_time = seconds_since_boot();
7666282cd56SNeilBrown 	bd->entries += 1;
767f54fe962SJeff Layton 	spin_unlock(&blocked_delegations_lock);
7686282cd56SNeilBrown }
7696282cd56SNeilBrown 
7701da177e4SLinus Torvalds static struct nfs4_delegation *
7718287f009SSachin Bhamare alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
7728287f009SSachin Bhamare 		 struct nfs4_clnt_odstate *odstate)
7731da177e4SLinus Torvalds {
7741da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
77502a3508dSTrond Myklebust 	long n;
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds 	dprintk("NFSD alloc_init_deleg\n");
77802a3508dSTrond Myklebust 	n = atomic_long_inc_return(&num_delegations);
77902a3508dSTrond Myklebust 	if (n < 0 || n > max_delegations)
78002a3508dSTrond Myklebust 		goto out_dec;
7816282cd56SNeilBrown 	if (delegation_blocked(&current_fh->fh_handle))
78202a3508dSTrond Myklebust 		goto out_dec;
783d19fb70dSKinglong Mee 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
7845b2d21c1SNeilBrown 	if (dp == NULL)
78502a3508dSTrond Myklebust 		goto out_dec;
7866011695dSTrond Myklebust 
7872a74aba7SJ. Bruce Fields 	/*
7882a74aba7SJ. Bruce Fields 	 * delegation seqid's are never incremented.  The 4.1 special
7896136d2b4SJ. Bruce Fields 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
7906136d2b4SJ. Bruce Fields 	 * 0 anyway just for consistency and use 1:
7912a74aba7SJ. Bruce Fields 	 */
7922a74aba7SJ. Bruce Fields 	dp->dl_stid.sc_stateid.si_generation = 1;
793ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perfile);
794ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perclnt);
7951da177e4SLinus Torvalds 	INIT_LIST_HEAD(&dp->dl_recall_lru);
7968287f009SSachin Bhamare 	dp->dl_clnt_odstate = odstate;
7978287f009SSachin Bhamare 	get_clnt_odstate(odstate);
79899c41515SJ. Bruce Fields 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
799f0b5de1bSChristoph Hellwig 	dp->dl_retries = 1;
800f0b5de1bSChristoph Hellwig 	nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client,
8010162ac2bSChristoph Hellwig 		      &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL);
8021da177e4SLinus Torvalds 	return dp;
80302a3508dSTrond Myklebust out_dec:
80402a3508dSTrond Myklebust 	atomic_long_dec(&num_delegations);
80502a3508dSTrond Myklebust 	return NULL;
8061da177e4SLinus Torvalds }
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds void
8096011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s)
8101da177e4SLinus Torvalds {
81111b9164aSTrond Myklebust 	struct nfs4_file *fp = s->sc_file;
8126011695dSTrond Myklebust 	struct nfs4_client *clp = s->sc_client;
8136011695dSTrond Myklebust 
8144770d722SJeff Layton 	might_lock(&clp->cl_lock);
8154770d722SJeff Layton 
816a15dfcd5SElena Reshetova 	if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
817b401be22SJeff Layton 		wake_up_all(&close_wq);
8186011695dSTrond Myklebust 		return;
819b401be22SJeff Layton 	}
8206011695dSTrond Myklebust 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
8214770d722SJeff Layton 	spin_unlock(&clp->cl_lock);
8226011695dSTrond Myklebust 	s->sc_free(s);
82311b9164aSTrond Myklebust 	if (fp)
82411b9164aSTrond Myklebust 		put_nfs4_file(fp);
8251da177e4SLinus Torvalds }
8261da177e4SLinus Torvalds 
8279767feb2SJeff Layton void
8289767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid)
8299767feb2SJeff Layton {
8309767feb2SJeff Layton 	stateid_t *src = &stid->sc_stateid;
8319767feb2SJeff Layton 
8329767feb2SJeff Layton 	spin_lock(&stid->sc_lock);
8339767feb2SJeff Layton 	if (unlikely(++src->si_generation == 0))
8349767feb2SJeff Layton 		src->si_generation = 1;
8359767feb2SJeff Layton 	memcpy(dst, src, sizeof(*dst));
8369767feb2SJeff Layton 	spin_unlock(&stid->sc_lock);
8379767feb2SJeff Layton }
8389767feb2SJeff Layton 
839acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp)
8401da177e4SLinus Torvalds {
8416bcc034eSJeff Layton 	struct file *filp = NULL;
842417c6629SJeff Layton 
8436bcc034eSJeff Layton 	spin_lock(&fp->fi_lock);
84467db1034SJeff Layton 	if (fp->fi_deleg_file && --fp->fi_delegees == 0)
8456bcc034eSJeff Layton 		swap(filp, fp->fi_deleg_file);
8466bcc034eSJeff Layton 	spin_unlock(&fp->fi_lock);
8476bcc034eSJeff Layton 
8486bcc034eSJeff Layton 	if (filp) {
8492ab99ee1SChristoph Hellwig 		vfs_setlease(filp, F_UNLCK, NULL, (void **)&fp);
8506bcc034eSJeff Layton 		fput(filp);
851acfdf5c3SJ. Bruce Fields 	}
8521da177e4SLinus Torvalds }
8531da177e4SLinus Torvalds 
854cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s)
8556136d2b4SJ. Bruce Fields {
8563abdb607SJ. Bruce Fields 	s->sc_type = 0;
8576136d2b4SJ. Bruce Fields }
8586136d2b4SJ. Bruce Fields 
85934ed9872SAndrew Elble /**
86034ed9872SAndrew Elble  * nfs4_get_existing_delegation - Discover if this delegation already exists
86134ed9872SAndrew Elble  * @clp:     a pointer to the nfs4_client we're granting a delegation to
86234ed9872SAndrew Elble  * @fp:      a pointer to the nfs4_file we're granting a delegation on
86334ed9872SAndrew Elble  *
86434ed9872SAndrew Elble  * Return:
86534ed9872SAndrew Elble  *      On success: NULL if an existing delegation was not found.
86634ed9872SAndrew Elble  *
86734ed9872SAndrew Elble  *      On error: -EAGAIN if one was previously granted to this nfs4_client
86834ed9872SAndrew Elble  *                 for this nfs4_file.
86934ed9872SAndrew Elble  *
87034ed9872SAndrew Elble  */
87134ed9872SAndrew Elble 
87234ed9872SAndrew Elble static int
87334ed9872SAndrew Elble nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
874931ee56cSBenny Halevy {
87534ed9872SAndrew Elble 	struct nfs4_delegation *searchdp = NULL;
87634ed9872SAndrew Elble 	struct nfs4_client *searchclp = NULL;
87734ed9872SAndrew Elble 
878cdc97505SBenny Halevy 	lockdep_assert_held(&state_lock);
879417c6629SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
880931ee56cSBenny Halevy 
88134ed9872SAndrew Elble 	list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) {
88234ed9872SAndrew Elble 		searchclp = searchdp->dl_stid.sc_client;
88334ed9872SAndrew Elble 		if (clp == searchclp) {
88434ed9872SAndrew Elble 			return -EAGAIN;
88534ed9872SAndrew Elble 		}
88634ed9872SAndrew Elble 	}
88734ed9872SAndrew Elble 	return 0;
88834ed9872SAndrew Elble }
88934ed9872SAndrew Elble 
89034ed9872SAndrew Elble /**
89134ed9872SAndrew Elble  * hash_delegation_locked - Add a delegation to the appropriate lists
89234ed9872SAndrew Elble  * @dp:     a pointer to the nfs4_delegation we are adding.
89334ed9872SAndrew Elble  * @fp:     a pointer to the nfs4_file we're granting a delegation on
89434ed9872SAndrew Elble  *
89534ed9872SAndrew Elble  * Return:
89634ed9872SAndrew Elble  *      On success: NULL if the delegation was successfully hashed.
89734ed9872SAndrew Elble  *
89834ed9872SAndrew Elble  *      On error: -EAGAIN if one was previously granted to this
89934ed9872SAndrew Elble  *                 nfs4_client for this nfs4_file. Delegation is not hashed.
90034ed9872SAndrew Elble  *
90134ed9872SAndrew Elble  */
90234ed9872SAndrew Elble 
90334ed9872SAndrew Elble static int
90434ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
90534ed9872SAndrew Elble {
90634ed9872SAndrew Elble 	int status;
90734ed9872SAndrew Elble 	struct nfs4_client *clp = dp->dl_stid.sc_client;
90834ed9872SAndrew Elble 
90934ed9872SAndrew Elble 	lockdep_assert_held(&state_lock);
91034ed9872SAndrew Elble 	lockdep_assert_held(&fp->fi_lock);
91134ed9872SAndrew Elble 
91234ed9872SAndrew Elble 	status = nfs4_get_existing_delegation(clp, fp);
91334ed9872SAndrew Elble 	if (status)
91434ed9872SAndrew Elble 		return status;
91534ed9872SAndrew Elble 	++fp->fi_delegees;
916a15dfcd5SElena Reshetova 	refcount_inc(&dp->dl_stid.sc_count);
9173fb87d13SBenny Halevy 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
918931ee56cSBenny Halevy 	list_add(&dp->dl_perfile, &fp->fi_delegations);
91934ed9872SAndrew Elble 	list_add(&dp->dl_perclnt, &clp->cl_delegations);
92034ed9872SAndrew Elble 	return 0;
921931ee56cSBenny Halevy }
922931ee56cSBenny Halevy 
9233fcbbd24SJeff Layton static bool
92442690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp)
9251da177e4SLinus Torvalds {
92611b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
92702e1215fSJeff Layton 
92842690676SJeff Layton 	lockdep_assert_held(&state_lock);
92942690676SJeff Layton 
9303fcbbd24SJeff Layton 	if (list_empty(&dp->dl_perfile))
9313fcbbd24SJeff Layton 		return false;
9323fcbbd24SJeff Layton 
933b0fc29d6STrond Myklebust 	dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
934d55a166cSJeff Layton 	/* Ensure that deleg break won't try to requeue it */
935d55a166cSJeff Layton 	++dp->dl_time;
936417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
937931ee56cSBenny Halevy 	list_del_init(&dp->dl_perclnt);
9381da177e4SLinus Torvalds 	list_del_init(&dp->dl_recall_lru);
93902e1215fSJeff Layton 	list_del_init(&dp->dl_perfile);
94002e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
9413fcbbd24SJeff Layton 	return true;
942cbf7a75bSJ. Bruce Fields }
9433bd64a5bSJ. Bruce Fields 
9443bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp)
9453bd64a5bSJ. Bruce Fields {
9463fcbbd24SJeff Layton 	bool unhashed;
9473fcbbd24SJeff Layton 
94842690676SJeff Layton 	spin_lock(&state_lock);
9493fcbbd24SJeff Layton 	unhashed = unhash_delegation_locked(dp);
95042690676SJeff Layton 	spin_unlock(&state_lock);
9513fcbbd24SJeff Layton 	if (unhashed) {
9528287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
953afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
9546011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
9553bd64a5bSJ. Bruce Fields 	}
9563fcbbd24SJeff Layton }
9573bd64a5bSJ. Bruce Fields 
9583bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp)
9593bd64a5bSJ. Bruce Fields {
9603bd64a5bSJ. Bruce Fields 	struct nfs4_client *clp = dp->dl_stid.sc_client;
9613bd64a5bSJ. Bruce Fields 
9622d4a532dSJeff Layton 	WARN_ON(!list_empty(&dp->dl_recall_lru));
9632d4a532dSJeff Layton 
9648287f009SSachin Bhamare 	put_clnt_odstate(dp->dl_clnt_odstate);
965afbda402SJeff Layton 	nfs4_put_deleg_lease(dp->dl_stid.sc_file);
966afbda402SJeff Layton 
9673bd64a5bSJ. Bruce Fields 	if (clp->cl_minorversion == 0)
9686011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
9693bd64a5bSJ. Bruce Fields 	else {
9703bd64a5bSJ. Bruce Fields 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
9712d4a532dSJeff Layton 		spin_lock(&clp->cl_lock);
9722d4a532dSJeff Layton 		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
9732d4a532dSJeff Layton 		spin_unlock(&clp->cl_lock);
9743bd64a5bSJ. Bruce Fields 	}
9753bd64a5bSJ. Bruce Fields }
9763bd64a5bSJ. Bruce Fields 
9771da177e4SLinus Torvalds /*
9781da177e4SLinus Torvalds  * SETCLIENTID state
9791da177e4SLinus Torvalds  */
9801da177e4SLinus Torvalds 
981ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id)
982ddc04c41SJ. Bruce Fields {
983ddc04c41SJ. Bruce Fields 	return id & CLIENT_HASH_MASK;
984ddc04c41SJ. Bruce Fields }
985ddc04c41SJ. Bruce Fields 
986ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name)
987ddc04c41SJ. Bruce Fields {
988ddc04c41SJ. Bruce Fields 	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
989ddc04c41SJ. Bruce Fields }
990ddc04c41SJ. Bruce Fields 
9911da177e4SLinus Torvalds /*
992f9d7562fSJ. Bruce Fields  * We store the NONE, READ, WRITE, and BOTH bits separately in the
993f9d7562fSJ. Bruce Fields  * st_{access,deny}_bmap field of the stateid, in order to track not
994f9d7562fSJ. Bruce Fields  * only what share bits are currently in force, but also what
995f9d7562fSJ. Bruce Fields  * combinations of share bits previous opens have used.  This allows us
996f9d7562fSJ. Bruce Fields  * to enforce the recommendation of rfc 3530 14.2.19 that the server
997f9d7562fSJ. Bruce Fields  * return an error if the client attempt to downgrade to a combination
998f9d7562fSJ. Bruce Fields  * of share bits not explicable by closing some of its previous opens.
999f9d7562fSJ. Bruce Fields  *
1000f9d7562fSJ. Bruce Fields  * XXX: This enforcement is actually incomplete, since we don't keep
1001f9d7562fSJ. Bruce Fields  * track of access/deny bit combinations; so, e.g., we allow:
1002f9d7562fSJ. Bruce Fields  *
1003f9d7562fSJ. Bruce Fields  *	OPEN allow read, deny write
1004f9d7562fSJ. Bruce Fields  *	OPEN allow both, deny none
1005f9d7562fSJ. Bruce Fields  *	DOWNGRADE allow read, deny none
1006f9d7562fSJ. Bruce Fields  *
1007f9d7562fSJ. Bruce Fields  * which we should reject.
1008f9d7562fSJ. Bruce Fields  */
10095ae037e5SJeff Layton static unsigned int
10105ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) {
1011f9d7562fSJ. Bruce Fields 	int i;
10125ae037e5SJeff Layton 	unsigned int access = 0;
1013f9d7562fSJ. Bruce Fields 
1014f9d7562fSJ. Bruce Fields 	for (i = 1; i < 4; i++) {
1015f9d7562fSJ. Bruce Fields 		if (test_bit(i, &bmap))
10165ae037e5SJeff Layton 			access |= i;
1017f9d7562fSJ. Bruce Fields 	}
10185ae037e5SJeff Layton 	return access;
1019f9d7562fSJ. Bruce Fields }
1020f9d7562fSJ. Bruce Fields 
102182c5ff1bSJeff Layton /* set share access for a given stateid */
102282c5ff1bSJeff Layton static inline void
102382c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp)
102482c5ff1bSJeff Layton {
1025c11c591fSJeff Layton 	unsigned char mask = 1 << access;
1026c11c591fSJeff Layton 
1027c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
1028c11c591fSJeff Layton 	stp->st_access_bmap |= mask;
102982c5ff1bSJeff Layton }
103082c5ff1bSJeff Layton 
103182c5ff1bSJeff Layton /* clear share access for a given stateid */
103282c5ff1bSJeff Layton static inline void
103382c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp)
103482c5ff1bSJeff Layton {
1035c11c591fSJeff Layton 	unsigned char mask = 1 << access;
1036c11c591fSJeff Layton 
1037c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
1038c11c591fSJeff Layton 	stp->st_access_bmap &= ~mask;
103982c5ff1bSJeff Layton }
104082c5ff1bSJeff Layton 
104182c5ff1bSJeff Layton /* test whether a given stateid has access */
104282c5ff1bSJeff Layton static inline bool
104382c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp)
104482c5ff1bSJeff Layton {
1045c11c591fSJeff Layton 	unsigned char mask = 1 << access;
1046c11c591fSJeff Layton 
1047c11c591fSJeff Layton 	return (bool)(stp->st_access_bmap & mask);
104882c5ff1bSJeff Layton }
104982c5ff1bSJeff Layton 
1050ce0fc43cSJeff Layton /* set share deny for a given stateid */
1051ce0fc43cSJeff Layton static inline void
1052c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp)
1053ce0fc43cSJeff Layton {
1054c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
1055c11c591fSJeff Layton 
1056c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
1057c11c591fSJeff Layton 	stp->st_deny_bmap |= mask;
1058ce0fc43cSJeff Layton }
1059ce0fc43cSJeff Layton 
1060ce0fc43cSJeff Layton /* clear share deny for a given stateid */
1061ce0fc43cSJeff Layton static inline void
1062c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp)
1063ce0fc43cSJeff Layton {
1064c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
1065c11c591fSJeff Layton 
1066c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
1067c11c591fSJeff Layton 	stp->st_deny_bmap &= ~mask;
1068ce0fc43cSJeff Layton }
1069ce0fc43cSJeff Layton 
1070ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */
1071ce0fc43cSJeff Layton static inline bool
1072c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp)
1073ce0fc43cSJeff Layton {
1074c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
1075c11c591fSJeff Layton 
1076c11c591fSJeff Layton 	return (bool)(stp->st_deny_bmap & mask);
1077f9d7562fSJ. Bruce Fields }
1078f9d7562fSJ. Bruce Fields 
1079f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access)
1080f9d7562fSJ. Bruce Fields {
10818f34a430SJ. Bruce Fields 	switch (access & NFS4_SHARE_ACCESS_BOTH) {
1082f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
1083f9d7562fSJ. Bruce Fields 		return O_RDONLY;
1084f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
1085f9d7562fSJ. Bruce Fields 		return O_WRONLY;
1086f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
1087f9d7562fSJ. Bruce Fields 		return O_RDWR;
1088f9d7562fSJ. Bruce Fields 	}
1089063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(1);
1090063b0fb9SJ. Bruce Fields 	return O_RDONLY;
1091f9d7562fSJ. Bruce Fields }
1092f9d7562fSJ. Bruce Fields 
1093baeb4ff0SJeff Layton /*
1094baeb4ff0SJeff Layton  * A stateid that had a deny mode associated with it is being released
1095baeb4ff0SJeff Layton  * or downgraded. Recalculate the deny mode on the file.
1096baeb4ff0SJeff Layton  */
1097baeb4ff0SJeff Layton static void
1098baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp)
1099baeb4ff0SJeff Layton {
1100baeb4ff0SJeff Layton 	struct nfs4_ol_stateid *stp;
1101baeb4ff0SJeff Layton 
1102baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
1103baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
1104baeb4ff0SJeff Layton 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile)
1105baeb4ff0SJeff Layton 		fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap);
1106baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
1107baeb4ff0SJeff Layton }
1108baeb4ff0SJeff Layton 
1109baeb4ff0SJeff Layton static void
1110baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp)
1111baeb4ff0SJeff Layton {
1112baeb4ff0SJeff Layton 	int i;
1113baeb4ff0SJeff Layton 	bool change = false;
1114baeb4ff0SJeff Layton 
1115baeb4ff0SJeff Layton 	for (i = 1; i < 4; i++) {
1116baeb4ff0SJeff Layton 		if ((i & deny) != i) {
1117baeb4ff0SJeff Layton 			change = true;
1118baeb4ff0SJeff Layton 			clear_deny(i, stp);
1119baeb4ff0SJeff Layton 		}
1120baeb4ff0SJeff Layton 	}
1121baeb4ff0SJeff Layton 
1122baeb4ff0SJeff Layton 	/* Recalculate per-file deny mode if there was a change */
1123baeb4ff0SJeff Layton 	if (change)
112411b9164aSTrond Myklebust 		recalculate_deny_mode(stp->st_stid.sc_file);
1125baeb4ff0SJeff Layton }
1126baeb4ff0SJeff Layton 
112782c5ff1bSJeff Layton /* release all access and file references for a given stateid */
112882c5ff1bSJeff Layton static void
112982c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp)
113082c5ff1bSJeff Layton {
113182c5ff1bSJeff Layton 	int i;
113211b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
1133baeb4ff0SJeff Layton 
1134baeb4ff0SJeff Layton 	if (fp && stp->st_deny_bmap != 0)
1135baeb4ff0SJeff Layton 		recalculate_deny_mode(fp);
113682c5ff1bSJeff Layton 
113782c5ff1bSJeff Layton 	for (i = 1; i < 4; i++) {
113882c5ff1bSJeff Layton 		if (test_access(i, stp))
113911b9164aSTrond Myklebust 			nfs4_file_put_access(stp->st_stid.sc_file, i);
114082c5ff1bSJeff Layton 		clear_access(i, stp);
114182c5ff1bSJeff Layton 	}
114282c5ff1bSJeff Layton }
114382c5ff1bSJeff Layton 
1144d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop)
1145d50ffdedSKinglong Mee {
1146d50ffdedSKinglong Mee 	kfree(sop->so_owner.data);
1147d50ffdedSKinglong Mee 	sop->so_ops->so_free(sop);
1148d50ffdedSKinglong Mee }
1149d50ffdedSKinglong Mee 
11506b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
11516b180f0bSJeff Layton {
1152a819ecc1SJeff Layton 	struct nfs4_client *clp = sop->so_client;
1153a819ecc1SJeff Layton 
1154a819ecc1SJeff Layton 	might_lock(&clp->cl_lock);
1155a819ecc1SJeff Layton 
1156a819ecc1SJeff Layton 	if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock))
11576b180f0bSJeff Layton 		return;
11588f4b54c5SJeff Layton 	sop->so_ops->so_unhash(sop);
1159a819ecc1SJeff Layton 	spin_unlock(&clp->cl_lock);
1160d50ffdedSKinglong Mee 	nfs4_free_stateowner(sop);
11616b180f0bSJeff Layton }
11626b180f0bSJeff Layton 
1163e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp)
1164529d7b2aSJ. Bruce Fields {
116511b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
11661d31a253STrond Myklebust 
11671c755dc1SJeff Layton 	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
11681c755dc1SJeff Layton 
1169e8568739SJeff Layton 	if (list_empty(&stp->st_perfile))
1170e8568739SJeff Layton 		return false;
1171e8568739SJeff Layton 
11721d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
1173e8568739SJeff Layton 	list_del_init(&stp->st_perfile);
11741d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
1175529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perstateowner);
1176e8568739SJeff Layton 	return true;
1177529d7b2aSJ. Bruce Fields }
1178529d7b2aSJ. Bruce Fields 
11796011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
1180529d7b2aSJ. Bruce Fields {
11816011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
11824665e2baSJ. Bruce Fields 
11838287f009SSachin Bhamare 	put_clnt_odstate(stp->st_clnt_odstate);
11846011695dSTrond Myklebust 	release_all_access(stp);
1185d3134b10SJeff Layton 	if (stp->st_stateowner)
1186d3134b10SJeff Layton 		nfs4_put_stateowner(stp->st_stateowner);
11876011695dSTrond Myklebust 	kmem_cache_free(stateid_slab, stid);
1188529d7b2aSJ. Bruce Fields }
1189529d7b2aSJ. Bruce Fields 
1190b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid)
1191529d7b2aSJ. Bruce Fields {
1192b49e084dSJeff Layton 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
1193b49e084dSJeff Layton 	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
1194529d7b2aSJ. Bruce Fields 	struct file *file;
1195529d7b2aSJ. Bruce Fields 
1196b49e084dSJeff Layton 	file = find_any_file(stp->st_stid.sc_file);
1197b49e084dSJeff Layton 	if (file)
1198b49e084dSJeff Layton 		filp_close(file, (fl_owner_t)lo);
1199b49e084dSJeff Layton 	nfs4_free_ol_stateid(stid);
1200b49e084dSJeff Layton }
1201b49e084dSJeff Layton 
12022c41beb0SJeff Layton /*
12032c41beb0SJeff Layton  * Put the persistent reference to an already unhashed generic stateid, while
12042c41beb0SJeff Layton  * holding the cl_lock. If it's the last reference, then put it onto the
12052c41beb0SJeff Layton  * reaplist for later destruction.
12062c41beb0SJeff Layton  */
12072c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
12082c41beb0SJeff Layton 				       struct list_head *reaplist)
12092c41beb0SJeff Layton {
12102c41beb0SJeff Layton 	struct nfs4_stid *s = &stp->st_stid;
12112c41beb0SJeff Layton 	struct nfs4_client *clp = s->sc_client;
12122c41beb0SJeff Layton 
12132c41beb0SJeff Layton 	lockdep_assert_held(&clp->cl_lock);
12142c41beb0SJeff Layton 
12152c41beb0SJeff Layton 	WARN_ON_ONCE(!list_empty(&stp->st_locks));
12162c41beb0SJeff Layton 
1217a15dfcd5SElena Reshetova 	if (!refcount_dec_and_test(&s->sc_count)) {
12182c41beb0SJeff Layton 		wake_up_all(&close_wq);
12192c41beb0SJeff Layton 		return;
12202c41beb0SJeff Layton 	}
12212c41beb0SJeff Layton 
12222c41beb0SJeff Layton 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
12232c41beb0SJeff Layton 	list_add(&stp->st_locks, reaplist);
12242c41beb0SJeff Layton }
12252c41beb0SJeff Layton 
1226e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
12273c1c995cSJeff Layton {
1228f46c445bSChuck Lever 	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
12293c1c995cSJeff Layton 
12303c1c995cSJeff Layton 	list_del_init(&stp->st_locks);
1231cd61c522SChristoph Hellwig 	nfs4_unhash_stid(&stp->st_stid);
1232e8568739SJeff Layton 	return unhash_ol_stateid(stp);
12333c1c995cSJeff Layton }
12343c1c995cSJeff Layton 
12355adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp)
1236b49e084dSJeff Layton {
1237f46c445bSChuck Lever 	struct nfs4_client *clp = stp->st_stid.sc_client;
1238e8568739SJeff Layton 	bool unhashed;
12391c755dc1SJeff Layton 
1240f46c445bSChuck Lever 	spin_lock(&clp->cl_lock);
1241e8568739SJeff Layton 	unhashed = unhash_lock_stateid(stp);
1242f46c445bSChuck Lever 	spin_unlock(&clp->cl_lock);
1243e8568739SJeff Layton 	if (unhashed)
12446011695dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
1245529d7b2aSJ. Bruce Fields }
1246529d7b2aSJ. Bruce Fields 
1247c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
1248529d7b2aSJ. Bruce Fields {
1249d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
1250c58c6610STrond Myklebust 
1251d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
1252c58c6610STrond Myklebust 
12538f4b54c5SJeff Layton 	list_del_init(&lo->lo_owner.so_strhash);
12548f4b54c5SJeff Layton }
12558f4b54c5SJeff Layton 
12562c41beb0SJeff Layton /*
12572c41beb0SJeff Layton  * Free a list of generic stateids that were collected earlier after being
12582c41beb0SJeff Layton  * fully unhashed.
12592c41beb0SJeff Layton  */
12602c41beb0SJeff Layton static void
12612c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist)
12622c41beb0SJeff Layton {
12632c41beb0SJeff Layton 	struct nfs4_ol_stateid *stp;
1264fb94d766SKinglong Mee 	struct nfs4_file *fp;
12652c41beb0SJeff Layton 
12662c41beb0SJeff Layton 	might_sleep();
12672c41beb0SJeff Layton 
12682c41beb0SJeff Layton 	while (!list_empty(reaplist)) {
12692c41beb0SJeff Layton 		stp = list_first_entry(reaplist, struct nfs4_ol_stateid,
12702c41beb0SJeff Layton 				       st_locks);
12712c41beb0SJeff Layton 		list_del(&stp->st_locks);
1272fb94d766SKinglong Mee 		fp = stp->st_stid.sc_file;
12732c41beb0SJeff Layton 		stp->st_stid.sc_free(&stp->st_stid);
1274fb94d766SKinglong Mee 		if (fp)
1275fb94d766SKinglong Mee 			put_nfs4_file(fp);
12762c41beb0SJeff Layton 	}
12772c41beb0SJeff Layton }
12782c41beb0SJeff Layton 
1279d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
1280d83017f9SJeff Layton 				       struct list_head *reaplist)
12813c87b9b7STrond Myklebust {
12823c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *stp;
12833c87b9b7STrond Myklebust 
1284e8568739SJeff Layton 	lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock);
1285e8568739SJeff Layton 
12863c87b9b7STrond Myklebust 	while (!list_empty(&open_stp->st_locks)) {
12873c87b9b7STrond Myklebust 		stp = list_entry(open_stp->st_locks.next,
12883c87b9b7STrond Myklebust 				struct nfs4_ol_stateid, st_locks);
1289e8568739SJeff Layton 		WARN_ON(!unhash_lock_stateid(stp));
1290d83017f9SJeff Layton 		put_ol_stateid_locked(stp, reaplist);
1291529d7b2aSJ. Bruce Fields 	}
1292529d7b2aSJ. Bruce Fields }
1293529d7b2aSJ. Bruce Fields 
1294e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp,
1295d83017f9SJeff Layton 				struct list_head *reaplist)
12962283963fSJ. Bruce Fields {
1297e8568739SJeff Layton 	bool unhashed;
1298e8568739SJeff Layton 
12992c41beb0SJeff Layton 	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
13002c41beb0SJeff Layton 
1301e8568739SJeff Layton 	unhashed = unhash_ol_stateid(stp);
1302d83017f9SJeff Layton 	release_open_stateid_locks(stp, reaplist);
1303e8568739SJeff Layton 	return unhashed;
130438c387b5SJ. Bruce Fields }
130538c387b5SJ. Bruce Fields 
130638c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp)
130738c387b5SJ. Bruce Fields {
13082c41beb0SJeff Layton 	LIST_HEAD(reaplist);
13092c41beb0SJeff Layton 
13102c41beb0SJeff Layton 	spin_lock(&stp->st_stid.sc_client->cl_lock);
1311e8568739SJeff Layton 	if (unhash_open_stateid(stp, &reaplist))
13122c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
13132c41beb0SJeff Layton 	spin_unlock(&stp->st_stid.sc_client->cl_lock);
13142c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
13152283963fSJ. Bruce Fields }
13162283963fSJ. Bruce Fields 
13177ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo)
1318f1d110caSJ. Bruce Fields {
1319d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
13207ffb5880STrond Myklebust 
1321d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
13227ffb5880STrond Myklebust 
13238f4b54c5SJeff Layton 	list_del_init(&oo->oo_owner.so_strhash);
13248f4b54c5SJeff Layton 	list_del_init(&oo->oo_perclient);
1325f1d110caSJ. Bruce Fields }
1326f1d110caSJ. Bruce Fields 
1327f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo)
1328f7a4d872SJ. Bruce Fields {
1329217526e7SJeff Layton 	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1330217526e7SJeff Layton 					  nfsd_net_id);
1331217526e7SJeff Layton 	struct nfs4_ol_stateid *s;
1332f7a4d872SJ. Bruce Fields 
1333217526e7SJeff Layton 	spin_lock(&nn->client_lock);
1334217526e7SJeff Layton 	s = oo->oo_last_closed_stid;
1335f7a4d872SJ. Bruce Fields 	if (s) {
1336d3134b10SJeff Layton 		list_del_init(&oo->oo_close_lru);
1337f7a4d872SJ. Bruce Fields 		oo->oo_last_closed_stid = NULL;
1338f7a4d872SJ. Bruce Fields 	}
1339217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
1340217526e7SJeff Layton 	if (s)
1341217526e7SJeff Layton 		nfs4_put_stid(&s->st_stid);
1342f7a4d872SJ. Bruce Fields }
1343f7a4d872SJ. Bruce Fields 
13442c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo)
13458f4b54c5SJeff Layton {
13468f4b54c5SJeff Layton 	struct nfs4_ol_stateid *stp;
1347d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
13482c41beb0SJeff Layton 	struct list_head reaplist;
13497ffb5880STrond Myklebust 
13502c41beb0SJeff Layton 	INIT_LIST_HEAD(&reaplist);
13517ffb5880STrond Myklebust 
1352d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
13537ffb5880STrond Myklebust 	unhash_openowner_locked(oo);
13542c41beb0SJeff Layton 	while (!list_empty(&oo->oo_owner.so_stateids)) {
13552c41beb0SJeff Layton 		stp = list_first_entry(&oo->oo_owner.so_stateids,
13562c41beb0SJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
1357e8568739SJeff Layton 		if (unhash_open_stateid(stp, &reaplist))
13582c41beb0SJeff Layton 			put_ol_stateid_locked(stp, &reaplist);
13592c41beb0SJeff Layton 	}
1360d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
13612c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
1362f7a4d872SJ. Bruce Fields 	release_last_closed_stateid(oo);
13636b180f0bSJeff Layton 	nfs4_put_stateowner(&oo->oo_owner);
1364f1d110caSJ. Bruce Fields }
1365f1d110caSJ. Bruce Fields 
13665282fd72SMarc Eshel static inline int
13675282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid)
13685282fd72SMarc Eshel {
13695282fd72SMarc Eshel 	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
13705282fd72SMarc Eshel 
13715282fd72SMarc Eshel 	return sid->sequence % SESSION_HASH_SIZE;
13725282fd72SMarc Eshel }
13735282fd72SMarc Eshel 
1374135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG
13755282fd72SMarc Eshel static inline void
13765282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
13775282fd72SMarc Eshel {
13785282fd72SMarc Eshel 	u32 *ptr = (u32 *)(&sessionid->data[0]);
13795282fd72SMarc Eshel 	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
13805282fd72SMarc Eshel }
13818f199b82STrond Myklebust #else
13828f199b82STrond Myklebust static inline void
13838f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
13848f199b82STrond Myklebust {
13858f199b82STrond Myklebust }
13868f199b82STrond Myklebust #endif
13878f199b82STrond Myklebust 
13889411b1d4SJ. Bruce Fields /*
13899411b1d4SJ. Bruce Fields  * Bump the seqid on cstate->replay_owner, and clear replay_owner if it
13909411b1d4SJ. Bruce Fields  * won't be used for replay.
13919411b1d4SJ. Bruce Fields  */
13929411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
13939411b1d4SJ. Bruce Fields {
13949411b1d4SJ. Bruce Fields 	struct nfs4_stateowner *so = cstate->replay_owner;
13959411b1d4SJ. Bruce Fields 
13969411b1d4SJ. Bruce Fields 	if (nfserr == nfserr_replay_me)
13979411b1d4SJ. Bruce Fields 		return;
13989411b1d4SJ. Bruce Fields 
13999411b1d4SJ. Bruce Fields 	if (!seqid_mutating_err(ntohl(nfserr))) {
140058fb12e6SJeff Layton 		nfsd4_cstate_clear_replay(cstate);
14019411b1d4SJ. Bruce Fields 		return;
14029411b1d4SJ. Bruce Fields 	}
14039411b1d4SJ. Bruce Fields 	if (!so)
14049411b1d4SJ. Bruce Fields 		return;
14059411b1d4SJ. Bruce Fields 	if (so->so_is_open_owner)
14069411b1d4SJ. Bruce Fields 		release_last_closed_stateid(openowner(so));
14079411b1d4SJ. Bruce Fields 	so->so_seqid++;
14089411b1d4SJ. Bruce Fields 	return;
14099411b1d4SJ. Bruce Fields }
14105282fd72SMarc Eshel 
1411ec6b5d7bSAndy Adamson static void
1412ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses)
1413ec6b5d7bSAndy Adamson {
1414ec6b5d7bSAndy Adamson 	struct nfs4_client *clp = ses->se_client;
1415ec6b5d7bSAndy Adamson 	struct nfsd4_sessionid *sid;
1416ec6b5d7bSAndy Adamson 
1417ec6b5d7bSAndy Adamson 	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
1418ec6b5d7bSAndy Adamson 	sid->clientid = clp->cl_clientid;
1419ec6b5d7bSAndy Adamson 	sid->sequence = current_sessionid++;
1420ec6b5d7bSAndy Adamson 	sid->reserved = 0;
1421ec6b5d7bSAndy Adamson }
1422ec6b5d7bSAndy Adamson 
1423ec6b5d7bSAndy Adamson /*
1424a649637cSAndy Adamson  * The protocol defines ca_maxresponssize_cached to include the size of
1425a649637cSAndy Adamson  * the rpc header, but all we need to cache is the data starting after
1426a649637cSAndy Adamson  * the end of the initial SEQUENCE operation--the rest we regenerate
1427a649637cSAndy Adamson  * each time.  Therefore we can advertise a ca_maxresponssize_cached
1428a649637cSAndy Adamson  * value that is the number of bytes in our cache plus a few additional
1429a649637cSAndy Adamson  * bytes.  In order to stay on the safe side, and not promise more than
1430a649637cSAndy Adamson  * we can cache, those additional bytes must be the minimum possible: 24
1431a649637cSAndy Adamson  * bytes of rpc header (xid through accept state, with AUTH_NULL
1432a649637cSAndy Adamson  * verifier), 12 for the compound header (with zero-length tag), and 44
1433a649637cSAndy Adamson  * for the SEQUENCE op response:
1434ec6b5d7bSAndy Adamson  */
1435a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
1436a649637cSAndy Adamson 
1437557ce264SAndy Adamson static void
1438557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses)
1439557ce264SAndy Adamson {
1440557ce264SAndy Adamson 	int i;
1441557ce264SAndy Adamson 
144253da6a53SJ. Bruce Fields 	for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
144353da6a53SJ. Bruce Fields 		free_svc_cred(&ses->se_slots[i]->sl_cred);
1444557ce264SAndy Adamson 		kfree(ses->se_slots[i]);
1445557ce264SAndy Adamson 	}
144653da6a53SJ. Bruce Fields }
1447557ce264SAndy Adamson 
1448efe0cb6dSJ. Bruce Fields /*
1449efe0cb6dSJ. Bruce Fields  * We don't actually need to cache the rpc and session headers, so we
1450efe0cb6dSJ. Bruce Fields  * can allocate a little less for each slot:
1451efe0cb6dSJ. Bruce Fields  */
145255c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca)
1453efe0cb6dSJ. Bruce Fields {
145455c760cfSJ. Bruce Fields 	u32 size;
1455efe0cb6dSJ. Bruce Fields 
145655c760cfSJ. Bruce Fields 	if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ)
145755c760cfSJ. Bruce Fields 		size = 0;
145855c760cfSJ. Bruce Fields 	else
145955c760cfSJ. Bruce Fields 		size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
146055c760cfSJ. Bruce Fields 	return size + sizeof(struct nfsd4_slot);
1461557ce264SAndy Adamson }
1462557ce264SAndy Adamson 
14635b6feee9SJ. Bruce Fields /*
14645b6feee9SJ. Bruce Fields  * XXX: If we run out of reserved DRC memory we could (up to a point)
14655b6feee9SJ. Bruce Fields  * re-negotiate active sessions and reduce their slot usage to make
146642b2aa86SJustin P. Mattock  * room for new connections. For now we just fail the create session.
14675b6feee9SJ. Bruce Fields  */
146855c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
14695b6feee9SJ. Bruce Fields {
147055c760cfSJ. Bruce Fields 	u32 slotsize = slot_bytes(ca);
147155c760cfSJ. Bruce Fields 	u32 num = ca->maxreqs;
14725b6feee9SJ. Bruce Fields 	int avail;
14735b6feee9SJ. Bruce Fields 
14745b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
1475697ce9beSZhang Yanfei 	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
14765b6feee9SJ. Bruce Fields 		    nfsd_drc_max_mem - nfsd_drc_mem_used);
1477de766e57SJ. Bruce Fields 	/*
1478de766e57SJ. Bruce Fields 	 * Never use more than a third of the remaining memory,
1479de766e57SJ. Bruce Fields 	 * unless it's the only way to give this client a slot:
1480de766e57SJ. Bruce Fields 	 */
1481de766e57SJ. Bruce Fields 	avail = clamp_t(int, avail, slotsize, avail/3);
14825b6feee9SJ. Bruce Fields 	num = min_t(int, num, avail / slotsize);
14835b6feee9SJ. Bruce Fields 	nfsd_drc_mem_used += num * slotsize;
14845b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
14855b6feee9SJ. Bruce Fields 
14865b6feee9SJ. Bruce Fields 	return num;
14875b6feee9SJ. Bruce Fields }
14885b6feee9SJ. Bruce Fields 
148955c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
14905b6feee9SJ. Bruce Fields {
149155c760cfSJ. Bruce Fields 	int slotsize = slot_bytes(ca);
149255c760cfSJ. Bruce Fields 
14935b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
149455c760cfSJ. Bruce Fields 	nfsd_drc_mem_used -= slotsize * ca->maxreqs;
14955b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
14965b6feee9SJ. Bruce Fields }
14975b6feee9SJ. Bruce Fields 
149860810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
149960810e54SKinglong Mee 					   struct nfsd4_channel_attrs *battrs)
15005b6feee9SJ. Bruce Fields {
150160810e54SKinglong Mee 	int numslots = fattrs->maxreqs;
150260810e54SKinglong Mee 	int slotsize = slot_bytes(fattrs);
15035b6feee9SJ. Bruce Fields 	struct nfsd4_session *new;
15045b6feee9SJ. Bruce Fields 	int mem, i;
1505ec6b5d7bSAndy Adamson 
1506c23753daSJ. Bruce Fields 	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
1507ec6b5d7bSAndy Adamson 			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
15085b6feee9SJ. Bruce Fields 	mem = numslots * sizeof(struct nfsd4_slot *);
1509ec6b5d7bSAndy Adamson 
15105b6feee9SJ. Bruce Fields 	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
15116c18ba9fSAlexandros Batsakis 	if (!new)
15125b6feee9SJ. Bruce Fields 		return NULL;
1513ec6b5d7bSAndy Adamson 	/* allocate each struct nfsd4_slot and data cache in one piece */
15145b6feee9SJ. Bruce Fields 	for (i = 0; i < numslots; i++) {
151555c760cfSJ. Bruce Fields 		new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL);
15165b6feee9SJ. Bruce Fields 		if (!new->se_slots[i])
1517ec6b5d7bSAndy Adamson 			goto out_free;
1518ec6b5d7bSAndy Adamson 	}
151960810e54SKinglong Mee 
152060810e54SKinglong Mee 	memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
152160810e54SKinglong Mee 	memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
152260810e54SKinglong Mee 
15235b6feee9SJ. Bruce Fields 	return new;
15245b6feee9SJ. Bruce Fields out_free:
15255b6feee9SJ. Bruce Fields 	while (i--)
15265b6feee9SJ. Bruce Fields 		kfree(new->se_slots[i]);
15275b6feee9SJ. Bruce Fields 	kfree(new);
15285b6feee9SJ. Bruce Fields 	return NULL;
15295b6feee9SJ. Bruce Fields }
15305b6feee9SJ. Bruce Fields 
153119cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c)
153219cf5c02SJ. Bruce Fields {
153319cf5c02SJ. Bruce Fields 	svc_xprt_put(c->cn_xprt);
153419cf5c02SJ. Bruce Fields 	kfree(c);
153519cf5c02SJ. Bruce Fields }
153619cf5c02SJ. Bruce Fields 
153719cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u)
153819cf5c02SJ. Bruce Fields {
153919cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
154019cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = c->cn_session->se_client;
154119cf5c02SJ. Bruce Fields 
154219cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
154319cf5c02SJ. Bruce Fields 	if (!list_empty(&c->cn_persession)) {
154419cf5c02SJ. Bruce Fields 		list_del(&c->cn_persession);
154519cf5c02SJ. Bruce Fields 		free_conn(c);
154619cf5c02SJ. Bruce Fields 	}
1547eea49806SJ. Bruce Fields 	nfsd4_probe_callback(clp);
15482e4b7239SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
154919cf5c02SJ. Bruce Fields }
155019cf5c02SJ. Bruce Fields 
1551d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
1552c7662518SJ. Bruce Fields {
1553c7662518SJ. Bruce Fields 	struct nfsd4_conn *conn;
1554c7662518SJ. Bruce Fields 
1555c7662518SJ. Bruce Fields 	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
1556c7662518SJ. Bruce Fields 	if (!conn)
1557db90681dSJ. Bruce Fields 		return NULL;
1558c7662518SJ. Bruce Fields 	svc_xprt_get(rqstp->rq_xprt);
1559c7662518SJ. Bruce Fields 	conn->cn_xprt = rqstp->rq_xprt;
1560d29c374cSJ. Bruce Fields 	conn->cn_flags = flags;
1561db90681dSJ. Bruce Fields 	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
1562db90681dSJ. Bruce Fields 	return conn;
1563db90681dSJ. Bruce Fields }
1564db90681dSJ. Bruce Fields 
1565328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1566328ead28SJ. Bruce Fields {
1567328ead28SJ. Bruce Fields 	conn->cn_session = ses;
1568328ead28SJ. Bruce Fields 	list_add(&conn->cn_persession, &ses->se_conns);
1569328ead28SJ. Bruce Fields }
1570328ead28SJ. Bruce Fields 
1571db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1572db90681dSJ. Bruce Fields {
1573db90681dSJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
1574c7662518SJ. Bruce Fields 
1575c7662518SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1576328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(conn, ses);
1577c7662518SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1578db90681dSJ. Bruce Fields }
1579c7662518SJ. Bruce Fields 
158021b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn)
1581db90681dSJ. Bruce Fields {
158219cf5c02SJ. Bruce Fields 	conn->cn_xpt_user.callback = nfsd4_conn_lost;
158321b75b01SJ. Bruce Fields 	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
1584db90681dSJ. Bruce Fields }
1585db90681dSJ. Bruce Fields 
1586e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
1587db90681dSJ. Bruce Fields {
158821b75b01SJ. Bruce Fields 	int ret;
1589db90681dSJ. Bruce Fields 
1590db90681dSJ. Bruce Fields 	nfsd4_hash_conn(conn, ses);
159121b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(conn);
159221b75b01SJ. Bruce Fields 	if (ret)
159321b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
159421b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&conn->cn_xpt_user);
159557a37144SJ. Bruce Fields 	/* We may have gained or lost a callback channel: */
159657a37144SJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
1597c7662518SJ. Bruce Fields }
1598c7662518SJ. Bruce Fields 
1599e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
16001d1bc8f2SJ. Bruce Fields {
16011d1bc8f2SJ. Bruce Fields 	u32 dir = NFS4_CDFC4_FORE;
16021d1bc8f2SJ. Bruce Fields 
1603e1ff371fSJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN)
16041d1bc8f2SJ. Bruce Fields 		dir |= NFS4_CDFC4_BACK;
1605e1ff371fSJ. Bruce Fields 	return alloc_conn(rqstp, dir);
16061d1bc8f2SJ. Bruce Fields }
16071d1bc8f2SJ. Bruce Fields 
16081d1bc8f2SJ. Bruce Fields /* must be called under client_lock */
160919cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s)
1610c7662518SJ. Bruce Fields {
161119cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = s->se_client;
161219cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c;
161319cf5c02SJ. Bruce Fields 
161419cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
161519cf5c02SJ. Bruce Fields 	while (!list_empty(&s->se_conns)) {
161619cf5c02SJ. Bruce Fields 		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
161719cf5c02SJ. Bruce Fields 		list_del_init(&c->cn_persession);
161819cf5c02SJ. Bruce Fields 		spin_unlock(&clp->cl_lock);
161919cf5c02SJ. Bruce Fields 
162019cf5c02SJ. Bruce Fields 		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
162119cf5c02SJ. Bruce Fields 		free_conn(c);
162219cf5c02SJ. Bruce Fields 
162319cf5c02SJ. Bruce Fields 		spin_lock(&clp->cl_lock);
162419cf5c02SJ. Bruce Fields 	}
162519cf5c02SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1626c7662518SJ. Bruce Fields }
1627c7662518SJ. Bruce Fields 
16281377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses)
16291377b69eSJ. Bruce Fields {
16301377b69eSJ. Bruce Fields 	free_session_slots(ses);
16311377b69eSJ. Bruce Fields 	kfree(ses);
16321377b69eSJ. Bruce Fields }
16331377b69eSJ. Bruce Fields 
163466b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses)
1635508dc6e1SBenny Halevy {
1636c7662518SJ. Bruce Fields 	nfsd4_del_conns(ses);
163755c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&ses->se_fchannel);
1638c7662518SJ. Bruce Fields 	__free_session(ses);
1639a827bcb2SJ. Bruce Fields }
1640ec6b5d7bSAndy Adamson 
1641135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
1642a827bcb2SJ. Bruce Fields {
1643a827bcb2SJ. Bruce Fields 	int idx;
16441872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1645a827bcb2SJ. Bruce Fields 
1646ec6b5d7bSAndy Adamson 	new->se_client = clp;
1647ec6b5d7bSAndy Adamson 	gen_sessionid(new);
1648ec6b5d7bSAndy Adamson 
1649c7662518SJ. Bruce Fields 	INIT_LIST_HEAD(&new->se_conns);
1650c7662518SJ. Bruce Fields 
1651ac7c46f2SJ. Bruce Fields 	new->se_cb_seq_nr = 1;
1652ec6b5d7bSAndy Adamson 	new->se_flags = cses->flags;
16538b5ce5cdSJ. Bruce Fields 	new->se_cb_prog = cses->callback_prog;
1654c6bb3ca2SJ. Bruce Fields 	new->se_cb_sec = cses->cb_sec;
165566b2b9b2SJ. Bruce Fields 	atomic_set(&new->se_ref, 0);
16565b6feee9SJ. Bruce Fields 	idx = hash_sessionid(&new->se_sessionid);
16571872de0eSStanislav Kinsbursky 	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
16584c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1659ec6b5d7bSAndy Adamson 	list_add(&new->se_perclnt, &clp->cl_sessions);
16604c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
166160810e54SKinglong Mee 
1662b0d2e42cSChuck Lever 	{
1663edd76786SJ. Bruce Fields 		struct sockaddr *sa = svc_addr(rqstp);
1664dcbeaa68SJ. Bruce Fields 		/*
1665dcbeaa68SJ. Bruce Fields 		 * This is a little silly; with sessions there's no real
1666dcbeaa68SJ. Bruce Fields 		 * use for the callback address.  Use the peer address
1667dcbeaa68SJ. Bruce Fields 		 * as a reasonable default for now, but consider fixing
1668dcbeaa68SJ. Bruce Fields 		 * the rpc client not to require an address in the
1669dcbeaa68SJ. Bruce Fields 		 * future:
1670dcbeaa68SJ. Bruce Fields 		 */
1671edd76786SJ. Bruce Fields 		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
1672edd76786SJ. Bruce Fields 		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
1673edd76786SJ. Bruce Fields 	}
1674ec6b5d7bSAndy Adamson }
1675ec6b5d7bSAndy Adamson 
16769089f1b4SBenny Halevy /* caller must hold client_lock */
16775282fd72SMarc Eshel static struct nfsd4_session *
1678d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
16795282fd72SMarc Eshel {
16805282fd72SMarc Eshel 	struct nfsd4_session *elem;
16815282fd72SMarc Eshel 	int idx;
16821872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
16835282fd72SMarc Eshel 
16840a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
16850a880a28STrond Myklebust 
16865282fd72SMarc Eshel 	dump_sessionid(__func__, sessionid);
16875282fd72SMarc Eshel 	idx = hash_sessionid(sessionid);
16885282fd72SMarc Eshel 	/* Search in the appropriate list */
16891872de0eSStanislav Kinsbursky 	list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) {
16905282fd72SMarc Eshel 		if (!memcmp(elem->se_sessionid.data, sessionid->data,
16915282fd72SMarc Eshel 			    NFS4_MAX_SESSIONID_LEN)) {
16925282fd72SMarc Eshel 			return elem;
16935282fd72SMarc Eshel 		}
16945282fd72SMarc Eshel 	}
16955282fd72SMarc Eshel 
16965282fd72SMarc Eshel 	dprintk("%s: session not found\n", __func__);
16975282fd72SMarc Eshel 	return NULL;
16985282fd72SMarc Eshel }
16995282fd72SMarc Eshel 
1700d4e19e70STrond Myklebust static struct nfsd4_session *
1701d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net,
1702d4e19e70STrond Myklebust 		__be32 *ret)
1703d4e19e70STrond Myklebust {
1704d4e19e70STrond Myklebust 	struct nfsd4_session *session;
1705d4e19e70STrond Myklebust 	__be32 status = nfserr_badsession;
1706d4e19e70STrond Myklebust 
1707d4e19e70STrond Myklebust 	session = __find_in_sessionid_hashtbl(sessionid, net);
1708d4e19e70STrond Myklebust 	if (!session)
1709d4e19e70STrond Myklebust 		goto out;
1710d4e19e70STrond Myklebust 	status = nfsd4_get_session_locked(session);
1711d4e19e70STrond Myklebust 	if (status)
1712d4e19e70STrond Myklebust 		session = NULL;
1713d4e19e70STrond Myklebust out:
1714d4e19e70STrond Myklebust 	*ret = status;
1715d4e19e70STrond Myklebust 	return session;
1716d4e19e70STrond Myklebust }
1717d4e19e70STrond Myklebust 
17189089f1b4SBenny Halevy /* caller must hold client_lock */
17197116ed6bSAndy Adamson static void
17205282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses)
17217116ed6bSAndy Adamson {
17220a880a28STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
17230a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
17240a880a28STrond Myklebust 
17250a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
17260a880a28STrond Myklebust 
17277116ed6bSAndy Adamson 	list_del(&ses->se_hash);
17284c649378SJ. Bruce Fields 	spin_lock(&ses->se_client->cl_lock);
17297116ed6bSAndy Adamson 	list_del(&ses->se_perclnt);
17304c649378SJ. Bruce Fields 	spin_unlock(&ses->se_client->cl_lock);
17315282fd72SMarc Eshel }
17325282fd72SMarc Eshel 
17331da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
17341da177e4SLinus Torvalds static int
17352c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
17361da177e4SLinus Torvalds {
1737bbc7f33aSJ. Bruce Fields 	/*
1738bbc7f33aSJ. Bruce Fields 	 * We're assuming the clid was not given out from a boot
1739bbc7f33aSJ. Bruce Fields 	 * precisely 2^32 (about 136 years) before this one.  That seems
1740bbc7f33aSJ. Bruce Fields 	 * a safe assumption:
1741bbc7f33aSJ. Bruce Fields 	 */
1742bbc7f33aSJ. Bruce Fields 	if (clid->cl_boot == (u32)nn->boot_time)
17431da177e4SLinus Torvalds 		return 0;
174460adfc50SAndy Adamson 	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
17452c142baaSStanislav Kinsbursky 		clid->cl_boot, clid->cl_id, nn->boot_time);
17461da177e4SLinus Torvalds 	return 1;
17471da177e4SLinus Torvalds }
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds /*
17501da177e4SLinus Torvalds  * XXX Should we use a slab cache ?
17511da177e4SLinus Torvalds  * This type of memory management is somewhat inefficient, but we use it
17521da177e4SLinus Torvalds  * anyway since SETCLIENTID is not a common operation.
17531da177e4SLinus Torvalds  */
175435bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name)
17551da177e4SLinus Torvalds {
17561da177e4SLinus Torvalds 	struct nfs4_client *clp;
1757d4f0489fSTrond Myklebust 	int i;
17581da177e4SLinus Torvalds 
175935bba9a3SJ. Bruce Fields 	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
176035bba9a3SJ. Bruce Fields 	if (clp == NULL)
176135bba9a3SJ. Bruce Fields 		return NULL;
176267114fe6SThomas Meyer 	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
1763d4f0489fSTrond Myklebust 	if (clp->cl_name.data == NULL)
1764d4f0489fSTrond Myklebust 		goto err_no_name;
1765d4f0489fSTrond Myklebust 	clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
1766d4f0489fSTrond Myklebust 			OWNER_HASH_SIZE, GFP_KERNEL);
1767d4f0489fSTrond Myklebust 	if (!clp->cl_ownerstr_hashtbl)
1768d4f0489fSTrond Myklebust 		goto err_no_hashtbl;
1769d4f0489fSTrond Myklebust 	for (i = 0; i < OWNER_HASH_SIZE; i++)
1770d4f0489fSTrond Myklebust 		INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]);
17711da177e4SLinus Torvalds 	clp->cl_name.len = name.len;
17725694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_sessions);
17735694c93eSTrond Myklebust 	idr_init(&clp->cl_stateids);
17745694c93eSTrond Myklebust 	atomic_set(&clp->cl_refcount, 0);
17755694c93eSTrond Myklebust 	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
17765694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_idhash);
17775694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_openowners);
17785694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_delegations);
17795694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_lru);
17805694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_revoked);
17819cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
17829cf514ccSChristoph Hellwig 	INIT_LIST_HEAD(&clp->cl_lo_states);
17839cf514ccSChristoph Hellwig #endif
17845694c93eSTrond Myklebust 	spin_lock_init(&clp->cl_lock);
17855694c93eSTrond Myklebust 	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
17861da177e4SLinus Torvalds 	return clp;
1787d4f0489fSTrond Myklebust err_no_hashtbl:
1788d4f0489fSTrond Myklebust 	kfree(clp->cl_name.data);
1789d4f0489fSTrond Myklebust err_no_name:
1790d4f0489fSTrond Myklebust 	kfree(clp);
1791d4f0489fSTrond Myklebust 	return NULL;
17921da177e4SLinus Torvalds }
17931da177e4SLinus Torvalds 
17944dd86e15STrond Myklebust static void
17951da177e4SLinus Torvalds free_client(struct nfs4_client *clp)
17961da177e4SLinus Torvalds {
1797792c95ddSJ. Bruce Fields 	while (!list_empty(&clp->cl_sessions)) {
1798792c95ddSJ. Bruce Fields 		struct nfsd4_session *ses;
1799792c95ddSJ. Bruce Fields 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
1800792c95ddSJ. Bruce Fields 				se_perclnt);
1801792c95ddSJ. Bruce Fields 		list_del(&ses->se_perclnt);
180266b2b9b2SJ. Bruce Fields 		WARN_ON_ONCE(atomic_read(&ses->se_ref));
180366b2b9b2SJ. Bruce Fields 		free_session(ses);
1804792c95ddSJ. Bruce Fields 	}
18054cb57e30STrond Myklebust 	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
180603a4e1f6SJ. Bruce Fields 	free_svc_cred(&clp->cl_cred);
1807d4f0489fSTrond Myklebust 	kfree(clp->cl_ownerstr_hashtbl);
18081da177e4SLinus Torvalds 	kfree(clp->cl_name.data);
18092d32b29aSmajianpeng 	idr_destroy(&clp->cl_stateids);
18101da177e4SLinus Torvalds 	kfree(clp);
18111da177e4SLinus Torvalds }
18121da177e4SLinus Torvalds 
181384d38ac9SBenny Halevy /* must be called under the client_lock */
18144beb345bSTrond Myklebust static void
181584d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp)
181684d38ac9SBenny Halevy {
18174beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1818792c95ddSJ. Bruce Fields 	struct nfsd4_session *ses;
1819792c95ddSJ. Bruce Fields 
18200a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
18210a880a28STrond Myklebust 
18224beb345bSTrond Myklebust 	/* Mark the client as expired! */
18234beb345bSTrond Myklebust 	clp->cl_time = 0;
18244beb345bSTrond Myklebust 	/* Make it invisible */
18254beb345bSTrond Myklebust 	if (!list_empty(&clp->cl_idhash)) {
18264beb345bSTrond Myklebust 		list_del_init(&clp->cl_idhash);
18274beb345bSTrond Myklebust 		if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
18284beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
18294beb345bSTrond Myklebust 		else
18304beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
18314beb345bSTrond Myklebust 	}
18324beb345bSTrond Myklebust 	list_del_init(&clp->cl_lru);
18334c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1834792c95ddSJ. Bruce Fields 	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
1835792c95ddSJ. Bruce Fields 		list_del_init(&ses->se_hash);
18364c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
183784d38ac9SBenny Halevy }
183884d38ac9SBenny Halevy 
18391da177e4SLinus Torvalds static void
18404beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp)
18414beb345bSTrond Myklebust {
18424beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
18434beb345bSTrond Myklebust 
18444beb345bSTrond Myklebust 	spin_lock(&nn->client_lock);
18454beb345bSTrond Myklebust 	unhash_client_locked(clp);
18464beb345bSTrond Myklebust 	spin_unlock(&nn->client_lock);
18474beb345bSTrond Myklebust }
18484beb345bSTrond Myklebust 
184997403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp)
185097403d95SJeff Layton {
185197403d95SJeff Layton 	if (atomic_read(&clp->cl_refcount))
185297403d95SJeff Layton 		return nfserr_jukebox;
185397403d95SJeff Layton 	unhash_client_locked(clp);
185497403d95SJeff Layton 	return nfs_ok;
185597403d95SJeff Layton }
185697403d95SJeff Layton 
18574beb345bSTrond Myklebust static void
18584beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp)
18591da177e4SLinus Torvalds {
1860fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
18611da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
18621da177e4SLinus Torvalds 	struct list_head reaplist;
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
1865cdc97505SBenny Halevy 	spin_lock(&state_lock);
1866ea1da636SNeilBrown 	while (!list_empty(&clp->cl_delegations)) {
1867ea1da636SNeilBrown 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
18683fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
186942690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
18701da177e4SLinus Torvalds 	}
1871cdc97505SBenny Halevy 	spin_unlock(&state_lock);
18721da177e4SLinus Torvalds 	while (!list_empty(&reaplist)) {
18731da177e4SLinus Torvalds 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
187442690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
18758287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
1876afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
18776011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
18781da177e4SLinus Torvalds 	}
18792d4a532dSJeff Layton 	while (!list_empty(&clp->cl_revoked)) {
1880c876486bSAndrew Elble 		dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru);
18812d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
18826011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
1883956c4feeSBenny Halevy 	}
1884ea1da636SNeilBrown 	while (!list_empty(&clp->cl_openowners)) {
1885fe0750e5SJ. Bruce Fields 		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
1886b5971afaSKinglong Mee 		nfs4_get_stateowner(&oo->oo_owner);
1887fe0750e5SJ. Bruce Fields 		release_openowner(oo);
18881da177e4SLinus Torvalds 	}
18899cf514ccSChristoph Hellwig 	nfsd4_return_all_client_layouts(clp);
18906ff8da08SJ. Bruce Fields 	nfsd4_shutdown_callback(clp);
18912bf23875SJ. Bruce Fields 	if (clp->cl_cb_conn.cb_xprt)
18922bf23875SJ. Bruce Fields 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1893b12a05cbSJ. Bruce Fields 	free_client(clp);
18941da177e4SLinus Torvalds }
18951da177e4SLinus Torvalds 
18964beb345bSTrond Myklebust static void
18974beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp)
18984beb345bSTrond Myklebust {
18994beb345bSTrond Myklebust 	unhash_client(clp);
19004beb345bSTrond Myklebust 	__destroy_client(clp);
19014beb345bSTrond Myklebust }
19024beb345bSTrond Myklebust 
19030d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp)
19040d22f68fSJ. Bruce Fields {
19054beb345bSTrond Myklebust 	unhash_client(clp);
19060d22f68fSJ. Bruce Fields 	nfsd4_client_record_remove(clp);
19074beb345bSTrond Myklebust 	__destroy_client(clp);
19080d22f68fSJ. Bruce Fields }
19090d22f68fSJ. Bruce Fields 
191035bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
191135bba9a3SJ. Bruce Fields {
191235bba9a3SJ. Bruce Fields 	memcpy(target->cl_verifier.data, source->data,
191335bba9a3SJ. Bruce Fields 			sizeof(target->cl_verifier.data));
19141da177e4SLinus Torvalds }
19151da177e4SLinus Torvalds 
191635bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
191735bba9a3SJ. Bruce Fields {
19181da177e4SLinus Torvalds 	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
19191da177e4SLinus Torvalds 	target->cl_clientid.cl_id = source->cl_clientid.cl_id;
19201da177e4SLinus Torvalds }
19211da177e4SLinus Torvalds 
192250043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source)
192350043859SJ. Bruce Fields {
19242f10fdcbSNeilBrown 	target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL);
19252f10fdcbSNeilBrown 	target->cr_raw_principal = kstrdup(source->cr_raw_principal,
19262f10fdcbSNeilBrown 								GFP_KERNEL);
19272f10fdcbSNeilBrown 	if ((source->cr_principal && ! target->cr_principal) ||
19282f10fdcbSNeilBrown 	    (source->cr_raw_principal && ! target->cr_raw_principal))
19292f10fdcbSNeilBrown 		return -ENOMEM;
193050043859SJ. Bruce Fields 
1931d5497fc6SJ. Bruce Fields 	target->cr_flavor = source->cr_flavor;
19321da177e4SLinus Torvalds 	target->cr_uid = source->cr_uid;
19331da177e4SLinus Torvalds 	target->cr_gid = source->cr_gid;
19341da177e4SLinus Torvalds 	target->cr_group_info = source->cr_group_info;
19351da177e4SLinus Torvalds 	get_group_info(target->cr_group_info);
19360dc1531aSJ. Bruce Fields 	target->cr_gss_mech = source->cr_gss_mech;
19370dc1531aSJ. Bruce Fields 	if (source->cr_gss_mech)
19380dc1531aSJ. Bruce Fields 		gss_mech_get(source->cr_gss_mech);
193903a4e1f6SJ. Bruce Fields 	return 0;
19401da177e4SLinus Torvalds }
19411da177e4SLinus Torvalds 
1942ef17af2aSRasmus Villemoes static int
1943ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
1944ac55fdc4SJeff Layton {
1945ef17af2aSRasmus Villemoes 	if (o1->len < o2->len)
1946ef17af2aSRasmus Villemoes 		return -1;
1947ef17af2aSRasmus Villemoes 	if (o1->len > o2->len)
1948ef17af2aSRasmus Villemoes 		return 1;
1949ef17af2aSRasmus Villemoes 	return memcmp(o1->data, o2->data, o1->len);
1950ac55fdc4SJeff Layton }
1951ac55fdc4SJeff Layton 
195235bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2)
1953599e0a22SJ. Bruce Fields {
1954a55370a3SNeilBrown 	return 0 == memcmp(n1, n2, HEXDIR_LEN);
19551da177e4SLinus Torvalds }
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds static int
1958599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
1959599e0a22SJ. Bruce Fields {
1960599e0a22SJ. Bruce Fields 	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
19611da177e4SLinus Torvalds }
19621da177e4SLinus Torvalds 
19631da177e4SLinus Torvalds static int
1964599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2)
1965599e0a22SJ. Bruce Fields {
1966599e0a22SJ. Bruce Fields 	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
19671da177e4SLinus Torvalds }
19681da177e4SLinus Torvalds 
19698fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2)
19708fbba96eSJ. Bruce Fields {
19718fbba96eSJ. Bruce Fields 	int i;
19728fbba96eSJ. Bruce Fields 
19738fbba96eSJ. Bruce Fields 	if (g1->ngroups != g2->ngroups)
19748fbba96eSJ. Bruce Fields 		return false;
19758fbba96eSJ. Bruce Fields 	for (i=0; i<g1->ngroups; i++)
197681243eacSAlexey Dobriyan 		if (!gid_eq(g1->gid[i], g2->gid[i]))
19778fbba96eSJ. Bruce Fields 			return false;
19788fbba96eSJ. Bruce Fields 	return true;
19798fbba96eSJ. Bruce Fields }
19808fbba96eSJ. Bruce Fields 
198168eb3508SJ. Bruce Fields /*
198268eb3508SJ. Bruce Fields  * RFC 3530 language requires clid_inuse be returned when the
198368eb3508SJ. Bruce Fields  * "principal" associated with a requests differs from that previously
198468eb3508SJ. Bruce Fields  * used.  We use uid, gid's, and gss principal string as our best
198568eb3508SJ. Bruce Fields  * approximation.  We also don't want to allow non-gss use of a client
198668eb3508SJ. Bruce Fields  * established using gss: in theory cr_principal should catch that
198768eb3508SJ. Bruce Fields  * change, but in practice cr_principal can be null even in the gss case
198868eb3508SJ. Bruce Fields  * since gssd doesn't always pass down a principal string.
198968eb3508SJ. Bruce Fields  */
199068eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr)
199168eb3508SJ. Bruce Fields {
199268eb3508SJ. Bruce Fields 	/* Is cr_flavor one of the gss "pseudoflavors"?: */
199368eb3508SJ. Bruce Fields 	return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
199468eb3508SJ. Bruce Fields }
199568eb3508SJ. Bruce Fields 
199668eb3508SJ. Bruce Fields 
19975559b50aSVivek Trivedi static bool
1998599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
1999599e0a22SJ. Bruce Fields {
200068eb3508SJ. Bruce Fields 	if ((is_gss_cred(cr1) != is_gss_cred(cr2))
20016fab8779SEric W. Biederman 		|| (!uid_eq(cr1->cr_uid, cr2->cr_uid))
20026fab8779SEric W. Biederman 		|| (!gid_eq(cr1->cr_gid, cr2->cr_gid))
20038fbba96eSJ. Bruce Fields 		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
20048fbba96eSJ. Bruce Fields 		return false;
20058fbba96eSJ. Bruce Fields 	if (cr1->cr_principal == cr2->cr_principal)
20068fbba96eSJ. Bruce Fields 		return true;
20078fbba96eSJ. Bruce Fields 	if (!cr1->cr_principal || !cr2->cr_principal)
20088fbba96eSJ. Bruce Fields 		return false;
20095559b50aSVivek Trivedi 	return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
20101da177e4SLinus Torvalds }
20111da177e4SLinus Torvalds 
201257266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
201357266a6eSJ. Bruce Fields {
201457266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
201557266a6eSJ. Bruce Fields 	u32 service;
201657266a6eSJ. Bruce Fields 
2017c4720591SJ. Bruce Fields 	if (!cr->cr_gss_mech)
2018c4720591SJ. Bruce Fields 		return false;
201957266a6eSJ. Bruce Fields 	service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
202057266a6eSJ. Bruce Fields 	return service == RPC_GSS_SVC_INTEGRITY ||
202157266a6eSJ. Bruce Fields 	       service == RPC_GSS_SVC_PRIVACY;
202257266a6eSJ. Bruce Fields }
202357266a6eSJ. Bruce Fields 
2024dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
202557266a6eSJ. Bruce Fields {
202657266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
202757266a6eSJ. Bruce Fields 
202857266a6eSJ. Bruce Fields 	if (!cl->cl_mach_cred)
202957266a6eSJ. Bruce Fields 		return true;
203057266a6eSJ. Bruce Fields 	if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
203157266a6eSJ. Bruce Fields 		return false;
203257266a6eSJ. Bruce Fields 	if (!svc_rqst_integrity_protected(rqstp))
203357266a6eSJ. Bruce Fields 		return false;
2034414ca017SJ. Bruce Fields 	if (cl->cl_cred.cr_raw_principal)
2035414ca017SJ. Bruce Fields 		return 0 == strcmp(cl->cl_cred.cr_raw_principal,
2036414ca017SJ. Bruce Fields 						cr->cr_raw_principal);
203757266a6eSJ. Bruce Fields 	if (!cr->cr_principal)
203857266a6eSJ. Bruce Fields 		return false;
203957266a6eSJ. Bruce Fields 	return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
204057266a6eSJ. Bruce Fields }
204157266a6eSJ. Bruce Fields 
2042294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
2043deda2faaSJ. Bruce Fields {
2044ab4684d1SChuck Lever 	__be32 verf[2];
20451da177e4SLinus Torvalds 
2046f419992cSJeff Layton 	/*
2047f419992cSJeff Layton 	 * This is opaque to client, so no need to byte-swap. Use
2048f419992cSJeff Layton 	 * __force to keep sparse happy
2049f419992cSJeff Layton 	 */
2050f419992cSJeff Layton 	verf[0] = (__force __be32)get_seconds();
205119311aa8SKinglong Mee 	verf[1] = (__force __be32)nn->clverifier_counter++;
2052ab4684d1SChuck Lever 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
20531da177e4SLinus Torvalds }
20541da177e4SLinus Torvalds 
2055294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
2056294ac32eSJeff Layton {
2057294ac32eSJeff Layton 	clp->cl_clientid.cl_boot = nn->boot_time;
2058294ac32eSJeff Layton 	clp->cl_clientid.cl_id = nn->clientid_counter++;
2059294ac32eSJeff Layton 	gen_confirm(clp, nn);
2060294ac32eSJeff Layton }
2061294ac32eSJeff Layton 
20624770d722SJeff Layton static struct nfs4_stid *
20634770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
20644581d140SJ. Bruce Fields {
20653abdb607SJ. Bruce Fields 	struct nfs4_stid *ret;
20663abdb607SJ. Bruce Fields 
20673abdb607SJ. Bruce Fields 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
20683abdb607SJ. Bruce Fields 	if (!ret || !ret->sc_type)
20693abdb607SJ. Bruce Fields 		return NULL;
20703abdb607SJ. Bruce Fields 	return ret;
20714581d140SJ. Bruce Fields }
20724d71ab87SJ. Bruce Fields 
20734770d722SJeff Layton static struct nfs4_stid *
20744770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
2075f459e453SJ. Bruce Fields {
2076f459e453SJ. Bruce Fields 	struct nfs4_stid *s;
2077f459e453SJ. Bruce Fields 
20784770d722SJeff Layton 	spin_lock(&cl->cl_lock);
20794770d722SJeff Layton 	s = find_stateid_locked(cl, t);
20802d3f9668STrond Myklebust 	if (s != NULL) {
20812d3f9668STrond Myklebust 		if (typemask & s->sc_type)
2082a15dfcd5SElena Reshetova 			refcount_inc(&s->sc_count);
20832d3f9668STrond Myklebust 		else
20844770d722SJeff Layton 			s = NULL;
20852d3f9668STrond Myklebust 	}
20864770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
20874d71ab87SJ. Bruce Fields 	return s;
20884581d140SJ. Bruce Fields }
20894581d140SJ. Bruce Fields 
20902216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name,
2091b09333c4SRicardo Labiaga 		struct svc_rqst *rqstp, nfs4_verifier *verf)
2092b09333c4SRicardo Labiaga {
2093b09333c4SRicardo Labiaga 	struct nfs4_client *clp;
2094b09333c4SRicardo Labiaga 	struct sockaddr *sa = svc_addr(rqstp);
209503a4e1f6SJ. Bruce Fields 	int ret;
2096c212cecfSStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
2097b09333c4SRicardo Labiaga 
2098b09333c4SRicardo Labiaga 	clp = alloc_client(name);
2099b09333c4SRicardo Labiaga 	if (clp == NULL)
2100b09333c4SRicardo Labiaga 		return NULL;
2101b09333c4SRicardo Labiaga 
210203a4e1f6SJ. Bruce Fields 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
210303a4e1f6SJ. Bruce Fields 	if (ret) {
2104b09333c4SRicardo Labiaga 		free_client(clp);
2105b09333c4SRicardo Labiaga 		return NULL;
2106b09333c4SRicardo Labiaga 	}
21070162ac2bSChristoph Hellwig 	nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL);
210807cd4909SBenny Halevy 	clp->cl_time = get_seconds();
2109b09333c4SRicardo Labiaga 	clear_bit(0, &clp->cl_cb_slot_busy);
2110b09333c4SRicardo Labiaga 	copy_verf(clp, verf);
2111b09333c4SRicardo Labiaga 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
2112edd76786SJ. Bruce Fields 	clp->cl_cb_session = NULL;
2113c212cecfSStanislav Kinsbursky 	clp->net = net;
2114b09333c4SRicardo Labiaga 	return clp;
2115b09333c4SRicardo Labiaga }
2116b09333c4SRicardo Labiaga 
2117fd39ca9aSNeilBrown static void
2118ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
2119ac55fdc4SJeff Layton {
2120ac55fdc4SJeff Layton 	struct rb_node **new = &(root->rb_node), *parent = NULL;
2121ac55fdc4SJeff Layton 	struct nfs4_client *clp;
2122ac55fdc4SJeff Layton 
2123ac55fdc4SJeff Layton 	while (*new) {
2124ac55fdc4SJeff Layton 		clp = rb_entry(*new, struct nfs4_client, cl_namenode);
2125ac55fdc4SJeff Layton 		parent = *new;
2126ac55fdc4SJeff Layton 
2127ac55fdc4SJeff Layton 		if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
2128ac55fdc4SJeff Layton 			new = &((*new)->rb_left);
2129ac55fdc4SJeff Layton 		else
2130ac55fdc4SJeff Layton 			new = &((*new)->rb_right);
2131ac55fdc4SJeff Layton 	}
2132ac55fdc4SJeff Layton 
2133ac55fdc4SJeff Layton 	rb_link_node(&new_clp->cl_namenode, parent, new);
2134ac55fdc4SJeff Layton 	rb_insert_color(&new_clp->cl_namenode, root);
2135ac55fdc4SJeff Layton }
2136ac55fdc4SJeff Layton 
2137ac55fdc4SJeff Layton static struct nfs4_client *
2138ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
2139ac55fdc4SJeff Layton {
2140ef17af2aSRasmus Villemoes 	int cmp;
2141ac55fdc4SJeff Layton 	struct rb_node *node = root->rb_node;
2142ac55fdc4SJeff Layton 	struct nfs4_client *clp;
2143ac55fdc4SJeff Layton 
2144ac55fdc4SJeff Layton 	while (node) {
2145ac55fdc4SJeff Layton 		clp = rb_entry(node, struct nfs4_client, cl_namenode);
2146ac55fdc4SJeff Layton 		cmp = compare_blob(&clp->cl_name, name);
2147ac55fdc4SJeff Layton 		if (cmp > 0)
2148ac55fdc4SJeff Layton 			node = node->rb_left;
2149ac55fdc4SJeff Layton 		else if (cmp < 0)
2150ac55fdc4SJeff Layton 			node = node->rb_right;
2151ac55fdc4SJeff Layton 		else
2152ac55fdc4SJeff Layton 			return clp;
2153ac55fdc4SJeff Layton 	}
2154ac55fdc4SJeff Layton 	return NULL;
2155ac55fdc4SJeff Layton }
2156ac55fdc4SJeff Layton 
2157ac55fdc4SJeff Layton static void
2158ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp)
21591da177e4SLinus Torvalds {
21601da177e4SLinus Torvalds 	unsigned int idhashval;
21610a7ec377SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
21621da177e4SLinus Torvalds 
21630a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
21640a880a28STrond Myklebust 
2165ac55fdc4SJeff Layton 	clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
2166a99454aaSStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
21671da177e4SLinus Torvalds 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
21680a7ec377SStanislav Kinsbursky 	list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
21693dbacee6STrond Myklebust 	renew_client_locked(clp);
21701da177e4SLinus Torvalds }
21711da177e4SLinus Torvalds 
2172fd39ca9aSNeilBrown static void
21731da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp)
21741da177e4SLinus Torvalds {
21751da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
21768daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
21771da177e4SLinus Torvalds 
21780a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
21790a880a28STrond Myklebust 
21801da177e4SLinus Torvalds 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
21818daae4dcSStanislav Kinsbursky 	list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
2182a99454aaSStanislav Kinsbursky 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
2183382a62e7SStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->conf_name_tree);
2184ac55fdc4SJeff Layton 	set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
21853dbacee6STrond Myklebust 	renew_client_locked(clp);
21861da177e4SLinus Torvalds }
21871da177e4SLinus Torvalds 
21881da177e4SLinus Torvalds static struct nfs4_client *
2189bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
21901da177e4SLinus Torvalds {
21911da177e4SLinus Torvalds 	struct nfs4_client *clp;
21921da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clid->cl_id);
21931da177e4SLinus Torvalds 
2194bfa85e83SJ. Bruce Fields 	list_for_each_entry(clp, &tbl[idhashval], cl_idhash) {
2195a50d2ad1SJ. Bruce Fields 		if (same_clid(&clp->cl_clientid, clid)) {
2196d15c077eSJ. Bruce Fields 			if ((bool)clp->cl_minorversion != sessions)
2197d15c077eSJ. Bruce Fields 				return NULL;
21983dbacee6STrond Myklebust 			renew_client_locked(clp);
21991da177e4SLinus Torvalds 			return clp;
22001da177e4SLinus Torvalds 		}
2201a50d2ad1SJ. Bruce Fields 	}
22021da177e4SLinus Torvalds 	return NULL;
22031da177e4SLinus Torvalds }
22041da177e4SLinus Torvalds 
22051da177e4SLinus Torvalds static struct nfs4_client *
2206bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
2207bfa85e83SJ. Bruce Fields {
2208bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->conf_id_hashtbl;
2209bfa85e83SJ. Bruce Fields 
22100a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2211bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
2212bfa85e83SJ. Bruce Fields }
2213bfa85e83SJ. Bruce Fields 
2214bfa85e83SJ. Bruce Fields static struct nfs4_client *
22150a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
22161da177e4SLinus Torvalds {
2217bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->unconf_id_hashtbl;
22181da177e4SLinus Torvalds 
22190a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2220bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
22211da177e4SLinus Torvalds }
22221da177e4SLinus Torvalds 
22236e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp)
2224a1bcecd2SAndy Adamson {
22256e5f15c9SJ. Bruce Fields 	return clp->cl_exchange_flags != 0;
2226a1bcecd2SAndy Adamson }
2227a1bcecd2SAndy Adamson 
222828ce6054SNeilBrown static struct nfs4_client *
2229382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
223028ce6054SNeilBrown {
22310a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2232382a62e7SStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->conf_name_tree);
223328ce6054SNeilBrown }
223428ce6054SNeilBrown 
223528ce6054SNeilBrown static struct nfs4_client *
2236a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
223728ce6054SNeilBrown {
22380a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2239a99454aaSStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->unconf_name_tree);
224028ce6054SNeilBrown }
224128ce6054SNeilBrown 
2242fd39ca9aSNeilBrown static void
22436f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
22441da177e4SLinus Torvalds {
224507263f1eSJ. Bruce Fields 	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
22466f3d772fSTakuma Umeya 	struct sockaddr	*sa = svc_addr(rqstp);
22476f3d772fSTakuma Umeya 	u32 scopeid = rpc_get_scope_id(sa);
22487077ecbaSJeff Layton 	unsigned short expected_family;
22491da177e4SLinus Torvalds 
22507077ecbaSJeff Layton 	/* Currently, we only support tcp and tcp6 for the callback channel */
22517077ecbaSJeff Layton 	if (se->se_callback_netid_len == 3 &&
22527077ecbaSJeff Layton 	    !memcmp(se->se_callback_netid_val, "tcp", 3))
22537077ecbaSJeff Layton 		expected_family = AF_INET;
22547077ecbaSJeff Layton 	else if (se->se_callback_netid_len == 4 &&
22557077ecbaSJeff Layton 		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
22567077ecbaSJeff Layton 		expected_family = AF_INET6;
22577077ecbaSJeff Layton 	else
22581da177e4SLinus Torvalds 		goto out_err;
22591da177e4SLinus Torvalds 
2260c212cecfSStanislav Kinsbursky 	conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val,
2261aa9a4ec7SJeff Layton 					    se->se_callback_addr_len,
226207263f1eSJ. Bruce Fields 					    (struct sockaddr *)&conn->cb_addr,
226307263f1eSJ. Bruce Fields 					    sizeof(conn->cb_addr));
2264aa9a4ec7SJeff Layton 
226507263f1eSJ. Bruce Fields 	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
22661da177e4SLinus Torvalds 		goto out_err;
2267aa9a4ec7SJeff Layton 
226807263f1eSJ. Bruce Fields 	if (conn->cb_addr.ss_family == AF_INET6)
226907263f1eSJ. Bruce Fields 		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
2270fbf4665fSJeff Layton 
227107263f1eSJ. Bruce Fields 	conn->cb_prog = se->se_callback_prog;
227207263f1eSJ. Bruce Fields 	conn->cb_ident = se->se_callback_ident;
2273849a1cf1SMi Jinlong 	memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
22741da177e4SLinus Torvalds 	return;
22751da177e4SLinus Torvalds out_err:
227607263f1eSJ. Bruce Fields 	conn->cb_addr.ss_family = AF_UNSPEC;
227707263f1eSJ. Bruce Fields 	conn->cb_addrlen = 0;
22784ab495bfSRasmus Villemoes 	dprintk("NFSD: this client (clientid %08x/%08x) "
22791da177e4SLinus Torvalds 		"will not receive delegations\n",
22801da177e4SLinus Torvalds 		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
22811da177e4SLinus Torvalds 
22821da177e4SLinus Torvalds 	return;
22831da177e4SLinus Torvalds }
22841da177e4SLinus Torvalds 
2285074fe897SAndy Adamson /*
2286067e1aceSJ. Bruce Fields  * Cache a reply. nfsd4_check_resp_size() has bounded the cache size.
2287074fe897SAndy Adamson  */
2288b607664eSTrond Myklebust static void
2289074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
2290074fe897SAndy Adamson {
2291f5236013SJ. Bruce Fields 	struct xdr_buf *buf = resp->xdr.buf;
2292557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2293557ce264SAndy Adamson 	unsigned int base;
2294074fe897SAndy Adamson 
2295557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2296074fe897SAndy Adamson 
2297085def3aSJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
2298557ce264SAndy Adamson 	slot->sl_opcnt = resp->opcnt;
2299557ce264SAndy Adamson 	slot->sl_status = resp->cstate.status;
230053da6a53SJ. Bruce Fields 	free_svc_cred(&slot->sl_cred);
230153da6a53SJ. Bruce Fields 	copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred);
2302bf864a31SAndy Adamson 
2303085def3aSJ. Bruce Fields 	if (!nfsd4_cache_this(resp)) {
2304085def3aSJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHED;
2305bf864a31SAndy Adamson 		return;
2306bf864a31SAndy Adamson 	}
2307085def3aSJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_CACHED;
2308085def3aSJ. Bruce Fields 
2309f5236013SJ. Bruce Fields 	base = resp->cstate.data_offset;
2310f5236013SJ. Bruce Fields 	slot->sl_datalen = buf->len - base;
2311f5236013SJ. Bruce Fields 	if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
2312d3f03403SDan Carpenter 		WARN(1, "%s: sessions DRC could not cache compound\n",
2313d3f03403SDan Carpenter 		     __func__);
2314557ce264SAndy Adamson 	return;
2315074fe897SAndy Adamson }
2316074fe897SAndy Adamson 
2317074fe897SAndy Adamson /*
2318abfabf8cSAndy Adamson  * Encode the replay sequence operation from the slot values.
2319abfabf8cSAndy Adamson  * If cachethis is FALSE encode the uncached rep error on the next
2320abfabf8cSAndy Adamson  * operation which sets resp->p and increments resp->opcnt for
2321abfabf8cSAndy Adamson  * nfs4svc_encode_compoundres.
2322abfabf8cSAndy Adamson  *
2323074fe897SAndy Adamson  */
2324abfabf8cSAndy Adamson static __be32
2325abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
2326abfabf8cSAndy Adamson 			  struct nfsd4_compoundres *resp)
2327074fe897SAndy Adamson {
2328abfabf8cSAndy Adamson 	struct nfsd4_op *op;
2329abfabf8cSAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2330074fe897SAndy Adamson 
2331abfabf8cSAndy Adamson 	/* Encode the replayed sequence operation */
2332abfabf8cSAndy Adamson 	op = &args->ops[resp->opcnt - 1];
2333abfabf8cSAndy Adamson 	nfsd4_encode_operation(resp, op);
2334abfabf8cSAndy Adamson 
2335085def3aSJ. Bruce Fields 	if (slot->sl_flags & NFSD4_SLOT_CACHED)
2336085def3aSJ. Bruce Fields 		return op->status;
2337085def3aSJ. Bruce Fields 	if (args->opcnt == 1) {
2338085def3aSJ. Bruce Fields 		/*
2339085def3aSJ. Bruce Fields 		 * The original operation wasn't a solo sequence--we
2340085def3aSJ. Bruce Fields 		 * always cache those--so this retry must not match the
2341085def3aSJ. Bruce Fields 		 * original:
2342085def3aSJ. Bruce Fields 		 */
2343085def3aSJ. Bruce Fields 		op->status = nfserr_seq_false_retry;
2344085def3aSJ. Bruce Fields 	} else {
2345abfabf8cSAndy Adamson 		op = &args->ops[resp->opcnt++];
2346abfabf8cSAndy Adamson 		op->status = nfserr_retry_uncached_rep;
2347abfabf8cSAndy Adamson 		nfsd4_encode_operation(resp, op);
2348074fe897SAndy Adamson 	}
2349abfabf8cSAndy Adamson 	return op->status;
2350074fe897SAndy Adamson }
2351074fe897SAndy Adamson 
2352074fe897SAndy Adamson /*
2353557ce264SAndy Adamson  * The sequence operation is not cached because we can use the slot and
2354557ce264SAndy Adamson  * session values.
2355074fe897SAndy Adamson  */
23563ca2eb98SJ. Bruce Fields static __be32
2357bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
2358bf864a31SAndy Adamson 			 struct nfsd4_sequence *seq)
2359074fe897SAndy Adamson {
2360557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2361f5236013SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2362f5236013SJ. Bruce Fields 	__be32 *p;
2363074fe897SAndy Adamson 	__be32 status;
2364074fe897SAndy Adamson 
2365557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2366074fe897SAndy Adamson 
2367abfabf8cSAndy Adamson 	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
23680da7b19cSJ. Bruce Fields 	if (status)
2369abfabf8cSAndy Adamson 		return status;
2370074fe897SAndy Adamson 
2371f5236013SJ. Bruce Fields 	p = xdr_reserve_space(xdr, slot->sl_datalen);
2372f5236013SJ. Bruce Fields 	if (!p) {
2373f5236013SJ. Bruce Fields 		WARN_ON_ONCE(1);
2374f5236013SJ. Bruce Fields 		return nfserr_serverfault;
2375f5236013SJ. Bruce Fields 	}
2376f5236013SJ. Bruce Fields 	xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen);
2377f5236013SJ. Bruce Fields 	xdr_commit_encode(xdr);
2378074fe897SAndy Adamson 
2379557ce264SAndy Adamson 	resp->opcnt = slot->sl_opcnt;
2380f5236013SJ. Bruce Fields 	return slot->sl_status;
2381074fe897SAndy Adamson }
2382074fe897SAndy Adamson 
23830733d213SAndy Adamson /*
23840733d213SAndy Adamson  * Set the exchange_id flags returned by the server.
23850733d213SAndy Adamson  */
23860733d213SAndy Adamson static void
23870733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
23880733d213SAndy Adamson {
23899cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
23909cf514ccSChristoph Hellwig 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS;
23919cf514ccSChristoph Hellwig #else
23920733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
23939cf514ccSChristoph Hellwig #endif
23940733d213SAndy Adamson 
23950733d213SAndy Adamson 	/* Referrals are supported, Migration is not. */
23960733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
23970733d213SAndy Adamson 
23980733d213SAndy Adamson 	/* set the wire flags to return to client. */
23990733d213SAndy Adamson 	clid->flags = new->cl_exchange_flags;
24000733d213SAndy Adamson }
24010733d213SAndy Adamson 
24024eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp)
24034eaea134SJ. Bruce Fields {
24044eaea134SJ. Bruce Fields 	struct nfs4_openowner *oo;
24054eaea134SJ. Bruce Fields 
24064eaea134SJ. Bruce Fields 	list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) {
24074eaea134SJ. Bruce Fields 		if (!list_empty(&oo->oo_owner.so_stateids))
24084eaea134SJ. Bruce Fields 			return true;
24094eaea134SJ. Bruce Fields 	}
24104eaea134SJ. Bruce Fields 	return false;
24114eaea134SJ. Bruce Fields }
24124eaea134SJ. Bruce Fields 
2413631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp)
2414631fc9eaSJ. Bruce Fields {
24154eaea134SJ. Bruce Fields 	return client_has_openowners(clp)
241647e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS
241747e970beSKinglong Mee 		|| !list_empty(&clp->cl_lo_states)
241847e970beSKinglong Mee #endif
24196eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_delegations)
24206eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_sessions);
2421631fc9eaSJ. Bruce Fields }
2422631fc9eaSJ. Bruce Fields 
2423b37ad28bSAl Viro __be32
2424eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2425eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
2426069b6ad4SAndy Adamson {
2427eb69853dSChristoph Hellwig 	struct nfsd4_exchange_id *exid = &u->exchange_id;
24283dbacee6STrond Myklebust 	struct nfs4_client *conf, *new;
24293dbacee6STrond Myklebust 	struct nfs4_client *unconf = NULL;
243057b7b43bSJ. Bruce Fields 	__be32 status;
2431363168b4SJeff Layton 	char			addr_str[INET6_ADDRSTRLEN];
24320733d213SAndy Adamson 	nfs4_verifier		verf = exid->verifier;
2433363168b4SJeff Layton 	struct sockaddr		*sa = svc_addr(rqstp);
243483e08fd4SJ. Bruce Fields 	bool	update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A;
2435c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
24360733d213SAndy Adamson 
2437363168b4SJeff Layton 	rpc_ntop(sa, addr_str, sizeof(addr_str));
24380733d213SAndy Adamson 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
2439363168b4SJeff Layton 		"ip_addr=%s flags %x, spa_how %d\n",
24400733d213SAndy Adamson 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
2441363168b4SJeff Layton 		addr_str, exid->flags, exid->spa_how);
24420733d213SAndy Adamson 
2443a084daf5SJ. Bruce Fields 	if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
24440733d213SAndy Adamson 		return nfserr_inval;
24450733d213SAndy Adamson 
244650c7b948SJ. Bruce Fields 	new = create_client(exid->clname, rqstp, &verf);
244750c7b948SJ. Bruce Fields 	if (new == NULL)
244850c7b948SJ. Bruce Fields 		return nfserr_jukebox;
244950c7b948SJ. Bruce Fields 
24500733d213SAndy Adamson 	switch (exid->spa_how) {
245157266a6eSJ. Bruce Fields 	case SP4_MACH_CRED:
2452ed941643SAndrew Elble 		exid->spo_must_enforce[0] = 0;
2453ed941643SAndrew Elble 		exid->spo_must_enforce[1] = (
2454ed941643SAndrew Elble 			1 << (OP_BIND_CONN_TO_SESSION - 32) |
2455ed941643SAndrew Elble 			1 << (OP_EXCHANGE_ID - 32) |
2456ed941643SAndrew Elble 			1 << (OP_CREATE_SESSION - 32) |
2457ed941643SAndrew Elble 			1 << (OP_DESTROY_SESSION - 32) |
2458ed941643SAndrew Elble 			1 << (OP_DESTROY_CLIENTID - 32));
2459ed941643SAndrew Elble 
2460ed941643SAndrew Elble 		exid->spo_must_allow[0] &= (1 << (OP_CLOSE) |
2461ed941643SAndrew Elble 					1 << (OP_OPEN_DOWNGRADE) |
2462ed941643SAndrew Elble 					1 << (OP_LOCKU) |
2463ed941643SAndrew Elble 					1 << (OP_DELEGRETURN));
2464ed941643SAndrew Elble 
2465ed941643SAndrew Elble 		exid->spo_must_allow[1] &= (
2466ed941643SAndrew Elble 					1 << (OP_TEST_STATEID - 32) |
2467ed941643SAndrew Elble 					1 << (OP_FREE_STATEID - 32));
246850c7b948SJ. Bruce Fields 		if (!svc_rqst_integrity_protected(rqstp)) {
246950c7b948SJ. Bruce Fields 			status = nfserr_inval;
247050c7b948SJ. Bruce Fields 			goto out_nolock;
247150c7b948SJ. Bruce Fields 		}
2472920dd9bbSJ. Bruce Fields 		/*
2473920dd9bbSJ. Bruce Fields 		 * Sometimes userspace doesn't give us a principal.
2474920dd9bbSJ. Bruce Fields 		 * Which is a bug, really.  Anyway, we can't enforce
2475920dd9bbSJ. Bruce Fields 		 * MACH_CRED in that case, better to give up now:
2476920dd9bbSJ. Bruce Fields 		 */
2477414ca017SJ. Bruce Fields 		if (!new->cl_cred.cr_principal &&
2478414ca017SJ. Bruce Fields 					!new->cl_cred.cr_raw_principal) {
2479920dd9bbSJ. Bruce Fields 			status = nfserr_serverfault;
2480920dd9bbSJ. Bruce Fields 			goto out_nolock;
2481920dd9bbSJ. Bruce Fields 		}
248250c7b948SJ. Bruce Fields 		new->cl_mach_cred = true;
24830733d213SAndy Adamson 	case SP4_NONE:
24840733d213SAndy Adamson 		break;
2485063b0fb9SJ. Bruce Fields 	default:				/* checked by xdr code */
2486063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
24870733d213SAndy Adamson 	case SP4_SSV:
24888edf4b02SKinglong Mee 		status = nfserr_encr_alg_unsupp;
24898edf4b02SKinglong Mee 		goto out_nolock;
24900733d213SAndy Adamson 	}
24910733d213SAndy Adamson 
24922dbb269dSJ. Bruce Fields 	/* Cases below refer to rfc 5661 section 18.35.4: */
24933dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
2494382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&exid->clname, nn);
24950733d213SAndy Adamson 	if (conf) {
249683e08fd4SJ. Bruce Fields 		bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
249783e08fd4SJ. Bruce Fields 		bool verfs_match = same_verf(&verf, &conf->cl_verifier);
249883e08fd4SJ. Bruce Fields 
2499136e658dSJ. Bruce Fields 		if (update) {
2500136e658dSJ. Bruce Fields 			if (!clp_used_exchangeid(conf)) { /* buggy client */
25012dbb269dSJ. Bruce Fields 				status = nfserr_inval;
2502e203d506SJ. Bruce Fields 				goto out;
2503e203d506SJ. Bruce Fields 			}
2504dedeb13fSAndrew Elble 			if (!nfsd4_mach_creds_match(conf, rqstp)) {
250557266a6eSJ. Bruce Fields 				status = nfserr_wrong_cred;
250657266a6eSJ. Bruce Fields 				goto out;
250757266a6eSJ. Bruce Fields 			}
25082dbb269dSJ. Bruce Fields 			if (!creds_match) { /* case 9 */
25090733d213SAndy Adamson 				status = nfserr_perm;
25100733d213SAndy Adamson 				goto out;
25110733d213SAndy Adamson 			}
25122dbb269dSJ. Bruce Fields 			if (!verfs_match) { /* case 8 */
25130733d213SAndy Adamson 				status = nfserr_not_same;
25140733d213SAndy Adamson 				goto out;
25150733d213SAndy Adamson 			}
2516136e658dSJ. Bruce Fields 			/* case 6 */
25170733d213SAndy Adamson 			exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
25180733d213SAndy Adamson 			goto out_copy;
25196ddbbbfeSMike Sager 		}
2520136e658dSJ. Bruce Fields 		if (!creds_match) { /* case 3 */
2521631fc9eaSJ. Bruce Fields 			if (client_has_state(conf)) {
2522136e658dSJ. Bruce Fields 				status = nfserr_clid_inuse;
2523136e658dSJ. Bruce Fields 				goto out;
2524136e658dSJ. Bruce Fields 			}
2525b9831b59SJ. Bruce Fields 			goto out_new;
2526631fc9eaSJ. Bruce Fields 		}
2527136e658dSJ. Bruce Fields 		if (verfs_match) { /* case 2 */
25280f1ba0efSJ. Bruce Fields 			conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
2529136e658dSJ. Bruce Fields 			goto out_copy;
2530136e658dSJ. Bruce Fields 		}
25312dbb269dSJ. Bruce Fields 		/* case 5, client reboot */
25323dbacee6STrond Myklebust 		conf = NULL;
25330733d213SAndy Adamson 		goto out_new;
25340733d213SAndy Adamson 	}
25356ddbbbfeSMike Sager 
25362dbb269dSJ. Bruce Fields 	if (update) { /* case 7 */
25370733d213SAndy Adamson 		status = nfserr_noent;
25380733d213SAndy Adamson 		goto out;
25390733d213SAndy Adamson 	}
25400733d213SAndy Adamson 
2541a99454aaSStanislav Kinsbursky 	unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
25422dbb269dSJ. Bruce Fields 	if (unconf) /* case 4, possible retry or client restart */
25433dbacee6STrond Myklebust 		unhash_client_locked(unconf);
25440733d213SAndy Adamson 
25452dbb269dSJ. Bruce Fields 	/* case 1 (normal case) */
25460733d213SAndy Adamson out_new:
2547fd699b8aSJeff Layton 	if (conf) {
2548fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
2549fd699b8aSJeff Layton 		if (status)
2550fd699b8aSJeff Layton 			goto out;
2551fd699b8aSJeff Layton 	}
25524f540e29SJ. Bruce Fields 	new->cl_minorversion = cstate->minorversion;
2553ed941643SAndrew Elble 	new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0];
2554ed941643SAndrew Elble 	new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1];
25550733d213SAndy Adamson 
2556c212cecfSStanislav Kinsbursky 	gen_clid(new, nn);
2557ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
25583dbacee6STrond Myklebust 	swap(new, conf);
25590733d213SAndy Adamson out_copy:
25605cc40fd7STrond Myklebust 	exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
25615cc40fd7STrond Myklebust 	exid->clientid.cl_id = conf->cl_clientid.cl_id;
25620733d213SAndy Adamson 
25635cc40fd7STrond Myklebust 	exid->seqid = conf->cl_cs_slot.sl_seqid + 1;
25645cc40fd7STrond Myklebust 	nfsd4_set_ex_flags(conf, exid);
25650733d213SAndy Adamson 
25660733d213SAndy Adamson 	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
25675cc40fd7STrond Myklebust 		conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags);
25680733d213SAndy Adamson 	status = nfs_ok;
25690733d213SAndy Adamson 
25700733d213SAndy Adamson out:
25713dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
257250c7b948SJ. Bruce Fields out_nolock:
25735cc40fd7STrond Myklebust 	if (new)
25743dbacee6STrond Myklebust 		expire_client(new);
25753dbacee6STrond Myklebust 	if (unconf)
25763dbacee6STrond Myklebust 		expire_client(unconf);
25770733d213SAndy Adamson 	return status;
2578069b6ad4SAndy Adamson }
2579069b6ad4SAndy Adamson 
258057b7b43bSJ. Bruce Fields static __be32
258188e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
2582b85d4c01SBenny Halevy {
258388e588d5SAndy Adamson 	dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
258488e588d5SAndy Adamson 		slot_seqid);
2585b85d4c01SBenny Halevy 
2586b85d4c01SBenny Halevy 	/* The slot is in use, and no response has been sent. */
258788e588d5SAndy Adamson 	if (slot_inuse) {
258888e588d5SAndy Adamson 		if (seqid == slot_seqid)
2589b85d4c01SBenny Halevy 			return nfserr_jukebox;
2590b85d4c01SBenny Halevy 		else
2591b85d4c01SBenny Halevy 			return nfserr_seq_misordered;
2592b85d4c01SBenny Halevy 	}
2593f6d82485SJ. Bruce Fields 	/* Note unsigned 32-bit arithmetic handles wraparound: */
259488e588d5SAndy Adamson 	if (likely(seqid == slot_seqid + 1))
2595b85d4c01SBenny Halevy 		return nfs_ok;
259688e588d5SAndy Adamson 	if (seqid == slot_seqid)
2597b85d4c01SBenny Halevy 		return nfserr_replay_cache;
2598b85d4c01SBenny Halevy 	return nfserr_seq_misordered;
2599b85d4c01SBenny Halevy }
2600b85d4c01SBenny Halevy 
260149557cc7SAndy Adamson /*
260249557cc7SAndy Adamson  * Cache the create session result into the create session single DRC
260349557cc7SAndy Adamson  * slot cache by saving the xdr structure. sl_seqid has been set.
260449557cc7SAndy Adamson  * Do this for solo or embedded create session operations.
260549557cc7SAndy Adamson  */
260649557cc7SAndy Adamson static void
260749557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
260857b7b43bSJ. Bruce Fields 			   struct nfsd4_clid_slot *slot, __be32 nfserr)
260949557cc7SAndy Adamson {
261049557cc7SAndy Adamson 	slot->sl_status = nfserr;
261149557cc7SAndy Adamson 	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
261249557cc7SAndy Adamson }
261349557cc7SAndy Adamson 
261449557cc7SAndy Adamson static __be32
261549557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
261649557cc7SAndy Adamson 			    struct nfsd4_clid_slot *slot)
261749557cc7SAndy Adamson {
261849557cc7SAndy Adamson 	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
261949557cc7SAndy Adamson 	return slot->sl_status;
262049557cc7SAndy Adamson }
262149557cc7SAndy Adamson 
26221b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
26231b74c25bSMi Jinlong 			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
26241b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
26251b74c25bSMi Jinlong 			3 +	/* version, opcount, opcode */ \
26261b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
26271b74c25bSMi Jinlong 				/* seqid, slotID, slotID, cache */ \
26281b74c25bSMi Jinlong 			4 ) * sizeof(__be32))
26291b74c25bSMi Jinlong 
26301b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
26311b74c25bSMi Jinlong 			2 +	/* verifier: AUTH_NULL, length 0 */\
26321b74c25bSMi Jinlong 			1 +	/* status */ \
26331b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
26341b74c25bSMi Jinlong 			3 +	/* opcount, opcode, opstatus*/ \
26351b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
26361b74c25bSMi Jinlong 				/* seqid, slotID, slotID, slotID, status */ \
26371b74c25bSMi Jinlong 			5 ) * sizeof(__be32))
26381b74c25bSMi Jinlong 
263955c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn)
26401b74c25bSMi Jinlong {
264155c760cfSJ. Bruce Fields 	u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
264255c760cfSJ. Bruce Fields 
2643373cd409SJ. Bruce Fields 	if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
2644373cd409SJ. Bruce Fields 		return nfserr_toosmall;
2645373cd409SJ. Bruce Fields 	if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
2646373cd409SJ. Bruce Fields 		return nfserr_toosmall;
264755c760cfSJ. Bruce Fields 	ca->headerpadsz = 0;
264855c760cfSJ. Bruce Fields 	ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
264955c760cfSJ. Bruce Fields 	ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
265055c760cfSJ. Bruce Fields 	ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
265155c760cfSJ. Bruce Fields 	ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
265255c760cfSJ. Bruce Fields 			NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
265355c760cfSJ. Bruce Fields 	ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
265455c760cfSJ. Bruce Fields 	/*
265555c760cfSJ. Bruce Fields 	 * Note decreasing slot size below client's request may make it
265655c760cfSJ. Bruce Fields 	 * difficult for client to function correctly, whereas
265755c760cfSJ. Bruce Fields 	 * decreasing the number of slots will (just?) affect
265855c760cfSJ. Bruce Fields 	 * performance.  When short on memory we therefore prefer to
265955c760cfSJ. Bruce Fields 	 * decrease number of slots instead of their size.  Clients that
266055c760cfSJ. Bruce Fields 	 * request larger slots than they need will get poor results:
266155c760cfSJ. Bruce Fields 	 */
266255c760cfSJ. Bruce Fields 	ca->maxreqs = nfsd4_get_drc_mem(ca);
266355c760cfSJ. Bruce Fields 	if (!ca->maxreqs)
266455c760cfSJ. Bruce Fields 		return nfserr_jukebox;
266555c760cfSJ. Bruce Fields 
2666373cd409SJ. Bruce Fields 	return nfs_ok;
26671b74c25bSMi Jinlong }
26681b74c25bSMi Jinlong 
26694500632fSChuck Lever /*
26704500632fSChuck Lever  * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now.
26714500632fSChuck Lever  * These are based on similar macros in linux/sunrpc/msg_prot.h .
26724500632fSChuck Lever  */
26734500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \
26744500632fSChuck Lever 	(RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK))
26754500632fSChuck Lever 
26764500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \
26774500632fSChuck Lever 	(RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK))
26784500632fSChuck Lever 
26798a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ	((NFS4_enc_cb_recall_sz + \
26804500632fSChuck Lever 				 RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32))
26818a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ	((NFS4_dec_cb_recall_sz + \
26824500632fSChuck Lever 				 RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \
26834500632fSChuck Lever 				 sizeof(__be32))
26848a891633SKinglong Mee 
268506b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
268606b332a5SJ. Bruce Fields {
268706b332a5SJ. Bruce Fields 	ca->headerpadsz = 0;
268806b332a5SJ. Bruce Fields 
26898a891633SKinglong Mee 	if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ)
269006b332a5SJ. Bruce Fields 		return nfserr_toosmall;
26918a891633SKinglong Mee 	if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ)
269206b332a5SJ. Bruce Fields 		return nfserr_toosmall;
269306b332a5SJ. Bruce Fields 	ca->maxresp_cached = 0;
269406b332a5SJ. Bruce Fields 	if (ca->maxops < 2)
269506b332a5SJ. Bruce Fields 		return nfserr_toosmall;
269606b332a5SJ. Bruce Fields 
269706b332a5SJ. Bruce Fields 	return nfs_ok;
2698069b6ad4SAndy Adamson }
2699069b6ad4SAndy Adamson 
2700b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
2701b78724b7SJ. Bruce Fields {
2702b78724b7SJ. Bruce Fields 	switch (cbs->flavor) {
2703b78724b7SJ. Bruce Fields 	case RPC_AUTH_NULL:
2704b78724b7SJ. Bruce Fields 	case RPC_AUTH_UNIX:
2705b78724b7SJ. Bruce Fields 		return nfs_ok;
2706b78724b7SJ. Bruce Fields 	default:
2707b78724b7SJ. Bruce Fields 		/*
2708b78724b7SJ. Bruce Fields 		 * GSS case: the spec doesn't allow us to return this
2709b78724b7SJ. Bruce Fields 		 * error.  But it also doesn't allow us not to support
2710b78724b7SJ. Bruce Fields 		 * GSS.
2711b78724b7SJ. Bruce Fields 		 * I'd rather this fail hard than return some error the
2712b78724b7SJ. Bruce Fields 		 * client might think it can already handle:
2713b78724b7SJ. Bruce Fields 		 */
2714b78724b7SJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
2715b78724b7SJ. Bruce Fields 	}
2716b78724b7SJ. Bruce Fields }
2717b78724b7SJ. Bruce Fields 
2718069b6ad4SAndy Adamson __be32
2719069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp,
2720eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
2721069b6ad4SAndy Adamson {
2722eb69853dSChristoph Hellwig 	struct nfsd4_create_session *cr_ses = &u->create_session;
2723363168b4SJeff Layton 	struct sockaddr *sa = svc_addr(rqstp);
2724ec6b5d7bSAndy Adamson 	struct nfs4_client *conf, *unconf;
2725d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
2726ac7c46f2SJ. Bruce Fields 	struct nfsd4_session *new;
272781f0b2a4SJ. Bruce Fields 	struct nfsd4_conn *conn;
272849557cc7SAndy Adamson 	struct nfsd4_clid_slot *cs_slot = NULL;
272957b7b43bSJ. Bruce Fields 	__be32 status = 0;
27308daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2731ec6b5d7bSAndy Adamson 
2732a62573dcSMi Jinlong 	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
2733a62573dcSMi Jinlong 		return nfserr_inval;
2734b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
2735b78724b7SJ. Bruce Fields 	if (status)
2736b78724b7SJ. Bruce Fields 		return status;
273755c760cfSJ. Bruce Fields 	status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
2738373cd409SJ. Bruce Fields 	if (status)
2739373cd409SJ. Bruce Fields 		return status;
274006b332a5SJ. Bruce Fields 	status = check_backchannel_attrs(&cr_ses->back_channel);
274106b332a5SJ. Bruce Fields 	if (status)
2742f403e450SKinglong Mee 		goto out_release_drc_mem;
274381f0b2a4SJ. Bruce Fields 	status = nfserr_jukebox;
274460810e54SKinglong Mee 	new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
274555c760cfSJ. Bruce Fields 	if (!new)
274655c760cfSJ. Bruce Fields 		goto out_release_drc_mem;
274781f0b2a4SJ. Bruce Fields 	conn = alloc_conn_from_crses(rqstp, cr_ses);
274881f0b2a4SJ. Bruce Fields 	if (!conn)
274981f0b2a4SJ. Bruce Fields 		goto out_free_session;
2750a62573dcSMi Jinlong 
2751d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
27520a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
27538daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
275478389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2755ec6b5d7bSAndy Adamson 
2756ec6b5d7bSAndy Adamson 	if (conf) {
275757266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
2758dedeb13fSAndrew Elble 		if (!nfsd4_mach_creds_match(conf, rqstp))
275957266a6eSJ. Bruce Fields 			goto out_free_conn;
276049557cc7SAndy Adamson 		cs_slot = &conf->cl_cs_slot;
276149557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
2762f5e22bb6SKinglong Mee 		if (status) {
2763f5e22bb6SKinglong Mee 			if (status == nfserr_replay_cache)
276449557cc7SAndy Adamson 				status = nfsd4_replay_create_session(cr_ses, cs_slot);
276581f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2766ec6b5d7bSAndy Adamson 		}
2767ec6b5d7bSAndy Adamson 	} else if (unconf) {
2768ec6b5d7bSAndy Adamson 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
2769363168b4SJeff Layton 		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
2770ec6b5d7bSAndy Adamson 			status = nfserr_clid_inuse;
277181f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2772ec6b5d7bSAndy Adamson 		}
277357266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
2774dedeb13fSAndrew Elble 		if (!nfsd4_mach_creds_match(unconf, rqstp))
277557266a6eSJ. Bruce Fields 			goto out_free_conn;
277649557cc7SAndy Adamson 		cs_slot = &unconf->cl_cs_slot;
277749557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
277838eb76a5SAndy Adamson 		if (status) {
277938eb76a5SAndy Adamson 			/* an unconfirmed replay returns misordered */
2780ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
278181f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2782ec6b5d7bSAndy Adamson 		}
2783382a62e7SStanislav Kinsbursky 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
2784221a6876SJ. Bruce Fields 		if (old) {
2785d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
27867abea1e8SJeff Layton 			if (status) {
27877abea1e8SJeff Layton 				old = NULL;
2788221a6876SJ. Bruce Fields 				goto out_free_conn;
2789221a6876SJ. Bruce Fields 			}
27907abea1e8SJeff Layton 		}
27918f9d3d3bSJ. Bruce Fields 		move_to_confirmed(unconf);
2792ec6b5d7bSAndy Adamson 		conf = unconf;
2793ec6b5d7bSAndy Adamson 	} else {
2794ec6b5d7bSAndy Adamson 		status = nfserr_stale_clientid;
279581f0b2a4SJ. Bruce Fields 		goto out_free_conn;
2796ec6b5d7bSAndy Adamson 	}
279781f0b2a4SJ. Bruce Fields 	status = nfs_ok;
27984ce85c8cSChuck Lever 	/* Persistent sessions are not supported */
2799408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_PERSIST;
28004ce85c8cSChuck Lever 	/* Upshifting from TCP to RDMA is not supported */
2801408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_RDMA;
2802408b79bcSJ. Bruce Fields 
280381f0b2a4SJ. Bruce Fields 	init_session(rqstp, new, conf, cr_ses);
2804d20c11d8SJeff Layton 	nfsd4_get_session_locked(new);
280581f0b2a4SJ. Bruce Fields 
2806ac7c46f2SJ. Bruce Fields 	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
2807ec6b5d7bSAndy Adamson 	       NFS4_MAX_SESSIONID_LEN);
280886c3e16cSJ. Bruce Fields 	cs_slot->sl_seqid++;
280949557cc7SAndy Adamson 	cr_ses->seqid = cs_slot->sl_seqid;
2810ec6b5d7bSAndy Adamson 
2811d20c11d8SJeff Layton 	/* cache solo and embedded create sessions under the client_lock */
281249557cc7SAndy Adamson 	nfsd4_cache_create_session(cr_ses, cs_slot, status);
2813d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
2814d20c11d8SJeff Layton 	/* init connection and backchannel */
2815d20c11d8SJeff Layton 	nfsd4_init_conn(rqstp, conn, new);
2816d20c11d8SJeff Layton 	nfsd4_put_session(new);
2817d20c11d8SJeff Layton 	if (old)
2818d20c11d8SJeff Layton 		expire_client(old);
2819ec6b5d7bSAndy Adamson 	return status;
282081f0b2a4SJ. Bruce Fields out_free_conn:
2821d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
282281f0b2a4SJ. Bruce Fields 	free_conn(conn);
2823d20c11d8SJeff Layton 	if (old)
2824d20c11d8SJeff Layton 		expire_client(old);
282581f0b2a4SJ. Bruce Fields out_free_session:
282681f0b2a4SJ. Bruce Fields 	__free_session(new);
282755c760cfSJ. Bruce Fields out_release_drc_mem:
282855c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&cr_ses->fore_channel);
28291ca50792SJ. Bruce Fields 	return status;
2830069b6ad4SAndy Adamson }
2831069b6ad4SAndy Adamson 
28321d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir)
28331d1bc8f2SJ. Bruce Fields {
28341d1bc8f2SJ. Bruce Fields 	switch (*dir) {
28351d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE:
28361d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK:
28371d1bc8f2SJ. Bruce Fields 		return nfs_ok;
28381d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE_OR_BOTH:
28391d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK_OR_BOTH:
28401d1bc8f2SJ. Bruce Fields 		*dir = NFS4_CDFC4_BOTH;
28411d1bc8f2SJ. Bruce Fields 		return nfs_ok;
28421d1bc8f2SJ. Bruce Fields 	};
28431d1bc8f2SJ. Bruce Fields 	return nfserr_inval;
28441d1bc8f2SJ. Bruce Fields }
28451d1bc8f2SJ. Bruce Fields 
2846eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp,
2847eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate,
2848eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
2849cb73a9f4SJ. Bruce Fields {
2850eb69853dSChristoph Hellwig 	struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl;
2851cb73a9f4SJ. Bruce Fields 	struct nfsd4_session *session = cstate->session;
2852c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2853b78724b7SJ. Bruce Fields 	__be32 status;
2854cb73a9f4SJ. Bruce Fields 
2855b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
2856b78724b7SJ. Bruce Fields 	if (status)
2857b78724b7SJ. Bruce Fields 		return status;
2858c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2859cb73a9f4SJ. Bruce Fields 	session->se_cb_prog = bc->bc_cb_program;
2860cb73a9f4SJ. Bruce Fields 	session->se_cb_sec = bc->bc_cb_sec;
2861c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2862cb73a9f4SJ. Bruce Fields 
2863cb73a9f4SJ. Bruce Fields 	nfsd4_probe_callback(session->se_client);
2864cb73a9f4SJ. Bruce Fields 
2865cb73a9f4SJ. Bruce Fields 	return nfs_ok;
2866cb73a9f4SJ. Bruce Fields }
2867cb73a9f4SJ. Bruce Fields 
28681d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
28691d1bc8f2SJ. Bruce Fields 		     struct nfsd4_compound_state *cstate,
2870eb69853dSChristoph Hellwig 		     union nfsd4_op_u *u)
28711d1bc8f2SJ. Bruce Fields {
2872eb69853dSChristoph Hellwig 	struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
28731d1bc8f2SJ. Bruce Fields 	__be32 status;
28743ba63671SJ. Bruce Fields 	struct nfsd4_conn *conn;
28754f6e6c17SJ. Bruce Fields 	struct nfsd4_session *session;
2876d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2877d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
28781d1bc8f2SJ. Bruce Fields 
28791d1bc8f2SJ. Bruce Fields 	if (!nfsd4_last_compound_op(rqstp))
28801d1bc8f2SJ. Bruce Fields 		return nfserr_not_only_op;
2881c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2882d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status);
2883c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
28844f6e6c17SJ. Bruce Fields 	if (!session)
2885d4e19e70STrond Myklebust 		goto out_no_session;
288657266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
2887dedeb13fSAndrew Elble 	if (!nfsd4_mach_creds_match(session->se_client, rqstp))
288857266a6eSJ. Bruce Fields 		goto out;
28891d1bc8f2SJ. Bruce Fields 	status = nfsd4_map_bcts_dir(&bcts->dir);
28903ba63671SJ. Bruce Fields 	if (status)
28914f6e6c17SJ. Bruce Fields 		goto out;
28923ba63671SJ. Bruce Fields 	conn = alloc_conn(rqstp, bcts->dir);
28934f6e6c17SJ. Bruce Fields 	status = nfserr_jukebox;
28943ba63671SJ. Bruce Fields 	if (!conn)
28954f6e6c17SJ. Bruce Fields 		goto out;
28964f6e6c17SJ. Bruce Fields 	nfsd4_init_conn(rqstp, conn, session);
28974f6e6c17SJ. Bruce Fields 	status = nfs_ok;
28984f6e6c17SJ. Bruce Fields out:
2899d4e19e70STrond Myklebust 	nfsd4_put_session(session);
2900d4e19e70STrond Myklebust out_no_session:
29014f6e6c17SJ. Bruce Fields 	return status;
29021d1bc8f2SJ. Bruce Fields }
29031d1bc8f2SJ. Bruce Fields 
29045d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
29055d4cec2fSJ. Bruce Fields {
29065d4cec2fSJ. Bruce Fields 	if (!session)
29075d4cec2fSJ. Bruce Fields 		return 0;
29085d4cec2fSJ. Bruce Fields 	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
29095d4cec2fSJ. Bruce Fields }
29105d4cec2fSJ. Bruce Fields 
2911069b6ad4SAndy Adamson __be32
2912eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate,
2913eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
2914069b6ad4SAndy Adamson {
2915eb69853dSChristoph Hellwig 	struct nfsd4_destroy_session *sessionid = &u->destroy_session;
2916e10e0cfcSBenny Halevy 	struct nfsd4_session *ses;
2917abcdff09SJ. Bruce Fields 	__be32 status;
2918f0f51f5cSJ. Bruce Fields 	int ref_held_by_me = 0;
2919d4e19e70STrond Myklebust 	struct net *net = SVC_NET(r);
2920d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2921e10e0cfcSBenny Halevy 
2922abcdff09SJ. Bruce Fields 	status = nfserr_not_only_op;
29235d4cec2fSJ. Bruce Fields 	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
292457716355SJ. Bruce Fields 		if (!nfsd4_last_compound_op(r))
2925abcdff09SJ. Bruce Fields 			goto out;
2926f0f51f5cSJ. Bruce Fields 		ref_held_by_me++;
292757716355SJ. Bruce Fields 	}
2928e10e0cfcSBenny Halevy 	dump_sessionid(__func__, &sessionid->sessionid);
2929c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2930d4e19e70STrond Myklebust 	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status);
2931abcdff09SJ. Bruce Fields 	if (!ses)
2932abcdff09SJ. Bruce Fields 		goto out_client_lock;
293357266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
2934dedeb13fSAndrew Elble 	if (!nfsd4_mach_creds_match(ses->se_client, r))
2935d4e19e70STrond Myklebust 		goto out_put_session;
2936f0f51f5cSJ. Bruce Fields 	status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
293766b2b9b2SJ. Bruce Fields 	if (status)
2938f0f51f5cSJ. Bruce Fields 		goto out_put_session;
2939e10e0cfcSBenny Halevy 	unhash_session(ses);
2940c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2941e10e0cfcSBenny Halevy 
294284f5f7ccSJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
294319cf5c02SJ. Bruce Fields 
2944c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2945e10e0cfcSBenny Halevy 	status = nfs_ok;
2946f0f51f5cSJ. Bruce Fields out_put_session:
2947d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
2948abcdff09SJ. Bruce Fields out_client_lock:
2949abcdff09SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
2950e10e0cfcSBenny Halevy out:
2951e10e0cfcSBenny Halevy 	return status;
2952069b6ad4SAndy Adamson }
2953069b6ad4SAndy Adamson 
2954a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
2955328ead28SJ. Bruce Fields {
2956328ead28SJ. Bruce Fields 	struct nfsd4_conn *c;
2957328ead28SJ. Bruce Fields 
2958328ead28SJ. Bruce Fields 	list_for_each_entry(c, &s->se_conns, cn_persession) {
2959a663bdd8SJ. Bruce Fields 		if (c->cn_xprt == xpt) {
2960328ead28SJ. Bruce Fields 			return c;
2961328ead28SJ. Bruce Fields 		}
2962328ead28SJ. Bruce Fields 	}
2963328ead28SJ. Bruce Fields 	return NULL;
2964328ead28SJ. Bruce Fields }
2965328ead28SJ. Bruce Fields 
296657266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
2967328ead28SJ. Bruce Fields {
2968328ead28SJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
2969a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *c;
297057266a6eSJ. Bruce Fields 	__be32 status = nfs_ok;
297121b75b01SJ. Bruce Fields 	int ret;
2972328ead28SJ. Bruce Fields 
2973328ead28SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
2974a663bdd8SJ. Bruce Fields 	c = __nfsd4_find_conn(new->cn_xprt, ses);
297557266a6eSJ. Bruce Fields 	if (c)
297657266a6eSJ. Bruce Fields 		goto out_free;
297757266a6eSJ. Bruce Fields 	status = nfserr_conn_not_bound_to_session;
297857266a6eSJ. Bruce Fields 	if (clp->cl_mach_cred)
297957266a6eSJ. Bruce Fields 		goto out_free;
2980328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(new, ses);
2981328ead28SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
298221b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(new);
298321b75b01SJ. Bruce Fields 	if (ret)
298421b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
298521b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&new->cn_xpt_user);
298657266a6eSJ. Bruce Fields 	return nfs_ok;
298757266a6eSJ. Bruce Fields out_free:
298857266a6eSJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
298957266a6eSJ. Bruce Fields 	free_conn(new);
299057266a6eSJ. Bruce Fields 	return status;
2991328ead28SJ. Bruce Fields }
2992328ead28SJ. Bruce Fields 
2993868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
2994868b89c3SMi Jinlong {
2995868b89c3SMi Jinlong 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
2996868b89c3SMi Jinlong 
2997868b89c3SMi Jinlong 	return args->opcnt > session->se_fchannel.maxops;
2998868b89c3SMi Jinlong }
2999868b89c3SMi Jinlong 
3000ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
3001ae82a8d0SMi Jinlong 				  struct nfsd4_session *session)
3002ae82a8d0SMi Jinlong {
3003ae82a8d0SMi Jinlong 	struct xdr_buf *xb = &rqstp->rq_arg;
3004ae82a8d0SMi Jinlong 
3005ae82a8d0SMi Jinlong 	return xb->len > session->se_fchannel.maxreq_sz;
3006ae82a8d0SMi Jinlong }
3007ae82a8d0SMi Jinlong 
300853da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp,
300953da6a53SJ. Bruce Fields 		 struct nfsd4_sequence *seq, struct nfsd4_slot *slot)
301053da6a53SJ. Bruce Fields {
301153da6a53SJ. Bruce Fields 	struct nfsd4_compoundargs *argp = rqstp->rq_argp;
301253da6a53SJ. Bruce Fields 
301353da6a53SJ. Bruce Fields 	if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) !=
301453da6a53SJ. Bruce Fields 	    (bool)seq->cachethis)
301553da6a53SJ. Bruce Fields 		return false;
301653da6a53SJ. Bruce Fields 	/*
301753da6a53SJ. Bruce Fields 	 * If there's an error than the reply can have fewer ops than
301853da6a53SJ. Bruce Fields 	 * the call.  But if we cached a reply with *more* ops than the
301953da6a53SJ. Bruce Fields 	 * call you're sending us now, then this new call is clearly not
302053da6a53SJ. Bruce Fields 	 * really a replay of the old one:
302153da6a53SJ. Bruce Fields 	 */
302253da6a53SJ. Bruce Fields 	if (slot->sl_opcnt < argp->opcnt)
302353da6a53SJ. Bruce Fields 		return false;
302453da6a53SJ. Bruce Fields 	/* This is the only check explicitly called by spec: */
302553da6a53SJ. Bruce Fields 	if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
302653da6a53SJ. Bruce Fields 		return false;
302753da6a53SJ. Bruce Fields 	/*
302853da6a53SJ. Bruce Fields 	 * There may be more comparisons we could actually do, but the
302953da6a53SJ. Bruce Fields 	 * spec doesn't require us to catch every case where the calls
303053da6a53SJ. Bruce Fields 	 * don't match (that would require caching the call as well as
303153da6a53SJ. Bruce Fields 	 * the reply), so we don't bother.
303253da6a53SJ. Bruce Fields 	 */
303353da6a53SJ. Bruce Fields 	return true;
303453da6a53SJ. Bruce Fields }
303553da6a53SJ. Bruce Fields 
3036069b6ad4SAndy Adamson __be32
3037eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3038eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
3039069b6ad4SAndy Adamson {
3040eb69853dSChristoph Hellwig 	struct nfsd4_sequence *seq = &u->sequence;
3041f9bb94c4SAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
304247ee5298SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
3043b85d4c01SBenny Halevy 	struct nfsd4_session *session;
3044221a6876SJ. Bruce Fields 	struct nfs4_client *clp;
3045b85d4c01SBenny Halevy 	struct nfsd4_slot *slot;
3046a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *conn;
304757b7b43bSJ. Bruce Fields 	__be32 status;
304847ee5298SJ. Bruce Fields 	int buflen;
3049d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
3050d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
3051b85d4c01SBenny Halevy 
3052f9bb94c4SAndy Adamson 	if (resp->opcnt != 1)
3053f9bb94c4SAndy Adamson 		return nfserr_sequence_pos;
3054f9bb94c4SAndy Adamson 
3055a663bdd8SJ. Bruce Fields 	/*
3056a663bdd8SJ. Bruce Fields 	 * Will be either used or freed by nfsd4_sequence_check_conn
3057a663bdd8SJ. Bruce Fields 	 * below.
3058a663bdd8SJ. Bruce Fields 	 */
3059a663bdd8SJ. Bruce Fields 	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
3060a663bdd8SJ. Bruce Fields 	if (!conn)
3061a663bdd8SJ. Bruce Fields 		return nfserr_jukebox;
3062a663bdd8SJ. Bruce Fields 
3063c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
3064d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status);
3065b85d4c01SBenny Halevy 	if (!session)
3066221a6876SJ. Bruce Fields 		goto out_no_session;
3067221a6876SJ. Bruce Fields 	clp = session->se_client;
3068b85d4c01SBenny Halevy 
3069868b89c3SMi Jinlong 	status = nfserr_too_many_ops;
3070868b89c3SMi Jinlong 	if (nfsd4_session_too_many_ops(rqstp, session))
307166b2b9b2SJ. Bruce Fields 		goto out_put_session;
3072868b89c3SMi Jinlong 
3073ae82a8d0SMi Jinlong 	status = nfserr_req_too_big;
3074ae82a8d0SMi Jinlong 	if (nfsd4_request_too_big(rqstp, session))
307566b2b9b2SJ. Bruce Fields 		goto out_put_session;
3076ae82a8d0SMi Jinlong 
3077b85d4c01SBenny Halevy 	status = nfserr_badslot;
30786c18ba9fSAlexandros Batsakis 	if (seq->slotid >= session->se_fchannel.maxreqs)
307966b2b9b2SJ. Bruce Fields 		goto out_put_session;
3080b85d4c01SBenny Halevy 
3081557ce264SAndy Adamson 	slot = session->se_slots[seq->slotid];
3082b85d4c01SBenny Halevy 	dprintk("%s: slotid %d\n", __func__, seq->slotid);
3083b85d4c01SBenny Halevy 
3084a8dfdaebSAndy Adamson 	/* We do not negotiate the number of slots yet, so set the
3085a8dfdaebSAndy Adamson 	 * maxslots to the session maxreqs which is used to encode
3086a8dfdaebSAndy Adamson 	 * sr_highest_slotid and the sr_target_slot id to maxslots */
3087a8dfdaebSAndy Adamson 	seq->maxslots = session->se_fchannel.maxreqs;
3088a8dfdaebSAndy Adamson 
308973e79482SJ. Bruce Fields 	status = check_slot_seqid(seq->seqid, slot->sl_seqid,
309073e79482SJ. Bruce Fields 					slot->sl_flags & NFSD4_SLOT_INUSE);
3091b85d4c01SBenny Halevy 	if (status == nfserr_replay_cache) {
3092bf5c43c8SJ. Bruce Fields 		status = nfserr_seq_misordered;
3093bf5c43c8SJ. Bruce Fields 		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
309466b2b9b2SJ. Bruce Fields 			goto out_put_session;
309553da6a53SJ. Bruce Fields 		status = nfserr_seq_false_retry;
309653da6a53SJ. Bruce Fields 		if (!replay_matches_cache(rqstp, seq, slot))
309753da6a53SJ. Bruce Fields 			goto out_put_session;
3098b85d4c01SBenny Halevy 		cstate->slot = slot;
3099b85d4c01SBenny Halevy 		cstate->session = session;
31004b24ca7dSJeff Layton 		cstate->clp = clp;
3101da3846a2SAndy Adamson 		/* Return the cached reply status and set cstate->status
3102557ce264SAndy Adamson 		 * for nfsd4_proc_compound processing */
3103bf864a31SAndy Adamson 		status = nfsd4_replay_cache_entry(resp, seq);
3104da3846a2SAndy Adamson 		cstate->status = nfserr_replay_cache;
3105aaf84eb9SBenny Halevy 		goto out;
3106b85d4c01SBenny Halevy 	}
3107b85d4c01SBenny Halevy 	if (status)
310866b2b9b2SJ. Bruce Fields 		goto out_put_session;
3109b85d4c01SBenny Halevy 
311057266a6eSJ. Bruce Fields 	status = nfsd4_sequence_check_conn(conn, session);
3111a663bdd8SJ. Bruce Fields 	conn = NULL;
311257266a6eSJ. Bruce Fields 	if (status)
311357266a6eSJ. Bruce Fields 		goto out_put_session;
3114328ead28SJ. Bruce Fields 
311547ee5298SJ. Bruce Fields 	buflen = (seq->cachethis) ?
311647ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_cached :
311747ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_sz;
311847ee5298SJ. Bruce Fields 	status = (seq->cachethis) ? nfserr_rep_too_big_to_cache :
311947ee5298SJ. Bruce Fields 				    nfserr_rep_too_big;
3120a5cddc88SJ. Bruce Fields 	if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack))
312147ee5298SJ. Bruce Fields 		goto out_put_session;
312232aaa62eSJ. Bruce Fields 	svc_reserve(rqstp, buflen);
312347ee5298SJ. Bruce Fields 
312447ee5298SJ. Bruce Fields 	status = nfs_ok;
3125b85d4c01SBenny Halevy 	/* Success! bump slot seqid */
3126b85d4c01SBenny Halevy 	slot->sl_seqid = seq->seqid;
3127bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INUSE;
312873e79482SJ. Bruce Fields 	if (seq->cachethis)
312973e79482SJ. Bruce Fields 		slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
3130bf5c43c8SJ. Bruce Fields 	else
3131bf5c43c8SJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
3132b85d4c01SBenny Halevy 
3133b85d4c01SBenny Halevy 	cstate->slot = slot;
3134b85d4c01SBenny Halevy 	cstate->session = session;
31354b24ca7dSJeff Layton 	cstate->clp = clp;
3136b85d4c01SBenny Halevy 
3137b85d4c01SBenny Halevy out:
31385423732aSBenny Halevy 	switch (clp->cl_cb_state) {
31395423732aSBenny Halevy 	case NFSD4_CB_DOWN:
3140fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
31415423732aSBenny Halevy 		break;
31425423732aSBenny Halevy 	case NFSD4_CB_FAULT:
3143fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
31445423732aSBenny Halevy 		break;
3145fc0c3dd1SBenny Halevy 	default:
3146fc0c3dd1SBenny Halevy 		seq->status_flags = 0;
31475423732aSBenny Halevy 	}
31483bd64a5bSJ. Bruce Fields 	if (!list_empty(&clp->cl_revoked))
31493bd64a5bSJ. Bruce Fields 		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
3150221a6876SJ. Bruce Fields out_no_session:
31513f42d2c4SKinglong Mee 	if (conn)
31523f42d2c4SKinglong Mee 		free_conn(conn);
3153c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
3154b85d4c01SBenny Halevy 	return status;
315566b2b9b2SJ. Bruce Fields out_put_session:
3156d4e19e70STrond Myklebust 	nfsd4_put_session_locked(session);
3157221a6876SJ. Bruce Fields 	goto out_no_session;
3158069b6ad4SAndy Adamson }
3159069b6ad4SAndy Adamson 
3160b607664eSTrond Myklebust void
3161b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp)
3162b607664eSTrond Myklebust {
3163b607664eSTrond Myklebust 	struct nfsd4_compound_state *cs = &resp->cstate;
3164b607664eSTrond Myklebust 
3165b607664eSTrond Myklebust 	if (nfsd4_has_session(cs)) {
3166b607664eSTrond Myklebust 		if (cs->status != nfserr_replay_cache) {
3167b607664eSTrond Myklebust 			nfsd4_store_cache_entry(resp);
3168b607664eSTrond Myklebust 			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
3169b607664eSTrond Myklebust 		}
3170d4e19e70STrond Myklebust 		/* Drop session reference that was taken in nfsd4_sequence() */
3171b607664eSTrond Myklebust 		nfsd4_put_session(cs->session);
31724b24ca7dSJeff Layton 	} else if (cs->clp)
31734b24ca7dSJeff Layton 		put_client_renew(cs->clp);
3174b607664eSTrond Myklebust }
3175b607664eSTrond Myklebust 
3176345c2842SMi Jinlong __be32
3177eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp,
3178eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate,
3179eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
3180345c2842SMi Jinlong {
3181eb69853dSChristoph Hellwig 	struct nfsd4_destroy_clientid *dc = &u->destroy_clientid;
31826b10ad19STrond Myklebust 	struct nfs4_client *conf, *unconf;
31836b10ad19STrond Myklebust 	struct nfs4_client *clp = NULL;
318457b7b43bSJ. Bruce Fields 	__be32 status = 0;
31858daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
3186345c2842SMi Jinlong 
31876b10ad19STrond Myklebust 	spin_lock(&nn->client_lock);
31880a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
31898daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&dc->clientid, true, nn);
319078389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
3191345c2842SMi Jinlong 
3192345c2842SMi Jinlong 	if (conf) {
3193c0293b01SJ. Bruce Fields 		if (client_has_state(conf)) {
3194345c2842SMi Jinlong 			status = nfserr_clientid_busy;
3195345c2842SMi Jinlong 			goto out;
3196345c2842SMi Jinlong 		}
3197fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
3198fd699b8aSJeff Layton 		if (status)
3199fd699b8aSJeff Layton 			goto out;
32006b10ad19STrond Myklebust 		clp = conf;
3201345c2842SMi Jinlong 	} else if (unconf)
3202345c2842SMi Jinlong 		clp = unconf;
3203345c2842SMi Jinlong 	else {
3204345c2842SMi Jinlong 		status = nfserr_stale_clientid;
3205345c2842SMi Jinlong 		goto out;
3206345c2842SMi Jinlong 	}
3207dedeb13fSAndrew Elble 	if (!nfsd4_mach_creds_match(clp, rqstp)) {
32086b10ad19STrond Myklebust 		clp = NULL;
320957266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
321057266a6eSJ. Bruce Fields 		goto out;
321157266a6eSJ. Bruce Fields 	}
32126b10ad19STrond Myklebust 	unhash_client_locked(clp);
3213345c2842SMi Jinlong out:
32146b10ad19STrond Myklebust 	spin_unlock(&nn->client_lock);
32156b10ad19STrond Myklebust 	if (clp)
32166b10ad19STrond Myklebust 		expire_client(clp);
3217345c2842SMi Jinlong 	return status;
3218345c2842SMi Jinlong }
3219345c2842SMi Jinlong 
3220069b6ad4SAndy Adamson __be32
3221eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp,
3222eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
32234dc6ec00SJ. Bruce Fields {
3224eb69853dSChristoph Hellwig 	struct nfsd4_reclaim_complete *rc = &u->reclaim_complete;
322557b7b43bSJ. Bruce Fields 	__be32 status = 0;
3226bcecf1ccSMi Jinlong 
32274dc6ec00SJ. Bruce Fields 	if (rc->rca_one_fs) {
32284dc6ec00SJ. Bruce Fields 		if (!cstate->current_fh.fh_dentry)
32294dc6ec00SJ. Bruce Fields 			return nfserr_nofilehandle;
32304dc6ec00SJ. Bruce Fields 		/*
32314dc6ec00SJ. Bruce Fields 		 * We don't take advantage of the rca_one_fs case.
32324dc6ec00SJ. Bruce Fields 		 * That's OK, it's optional, we can safely ignore it.
32334dc6ec00SJ. Bruce Fields 		 */
32344dc6ec00SJ. Bruce Fields 		return nfs_ok;
32354dc6ec00SJ. Bruce Fields 	}
3236bcecf1ccSMi Jinlong 
3237bcecf1ccSMi Jinlong 	status = nfserr_complete_already;
3238a52d726bSJeff Layton 	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
3239a52d726bSJeff Layton 			     &cstate->session->se_client->cl_flags))
3240bcecf1ccSMi Jinlong 		goto out;
3241bcecf1ccSMi Jinlong 
3242bcecf1ccSMi Jinlong 	status = nfserr_stale_clientid;
3243bcecf1ccSMi Jinlong 	if (is_client_expired(cstate->session->se_client))
32444dc6ec00SJ. Bruce Fields 		/*
32454dc6ec00SJ. Bruce Fields 		 * The following error isn't really legal.
32464dc6ec00SJ. Bruce Fields 		 * But we only get here if the client just explicitly
32474dc6ec00SJ. Bruce Fields 		 * destroyed the client.  Surely it no longer cares what
32484dc6ec00SJ. Bruce Fields 		 * error it gets back on an operation for the dead
32494dc6ec00SJ. Bruce Fields 		 * client.
32504dc6ec00SJ. Bruce Fields 		 */
3251bcecf1ccSMi Jinlong 		goto out;
3252bcecf1ccSMi Jinlong 
3253bcecf1ccSMi Jinlong 	status = nfs_ok;
32542a4317c5SJeff Layton 	nfsd4_client_record_create(cstate->session->se_client);
3255bcecf1ccSMi Jinlong out:
3256bcecf1ccSMi Jinlong 	return status;
32574dc6ec00SJ. Bruce Fields }
32584dc6ec00SJ. Bruce Fields 
32594dc6ec00SJ. Bruce Fields __be32
3260b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3261eb69853dSChristoph Hellwig 		  union nfsd4_op_u *u)
32621da177e4SLinus Torvalds {
3263eb69853dSChristoph Hellwig 	struct nfsd4_setclientid *setclid = &u->setclientid;
3264a084daf5SJ. Bruce Fields 	struct xdr_netobj 	clname = setclid->se_name;
32651da177e4SLinus Torvalds 	nfs4_verifier		clverifier = setclid->se_verf;
32663dbacee6STrond Myklebust 	struct nfs4_client	*conf, *new;
32673dbacee6STrond Myklebust 	struct nfs4_client	*unconf = NULL;
3268b37ad28bSAl Viro 	__be32 			status;
3269c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
3270a55370a3SNeilBrown 
32715cc40fd7STrond Myklebust 	new = create_client(clname, rqstp, &clverifier);
32725cc40fd7STrond Myklebust 	if (new == NULL)
32735cc40fd7STrond Myklebust 		return nfserr_jukebox;
327463db4632SJ. Bruce Fields 	/* Cases below refer to rfc 3530 section 14.2.33: */
32753dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
3276382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&clname, nn);
32772b634821SJ. Bruce Fields 	if (conf && client_has_state(conf)) {
327863db4632SJ. Bruce Fields 		/* case 0: */
32791da177e4SLinus Torvalds 		status = nfserr_clid_inuse;
3280e203d506SJ. Bruce Fields 		if (clp_used_exchangeid(conf))
3281e203d506SJ. Bruce Fields 			goto out;
3282026722c2SJ. Bruce Fields 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
3283363168b4SJeff Layton 			char addr_str[INET6_ADDRSTRLEN];
3284363168b4SJeff Layton 			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
3285363168b4SJeff Layton 				 sizeof(addr_str));
3286026722c2SJ. Bruce Fields 			dprintk("NFSD: setclientid: string in use by client "
3287363168b4SJeff Layton 				"at %s\n", addr_str);
32881da177e4SLinus Torvalds 			goto out;
32891da177e4SLinus Torvalds 		}
32901da177e4SLinus Torvalds 	}
3291a99454aaSStanislav Kinsbursky 	unconf = find_unconfirmed_client_by_name(&clname, nn);
32921da177e4SLinus Torvalds 	if (unconf)
32933dbacee6STrond Myklebust 		unhash_client_locked(unconf);
329441eb1670SKinglong Mee 	if (conf && same_verf(&conf->cl_verifier, &clverifier)) {
329563db4632SJ. Bruce Fields 		/* case 1: probable callback update */
32961da177e4SLinus Torvalds 		copy_clid(new, conf);
329741eb1670SKinglong Mee 		gen_confirm(new, nn);
329841eb1670SKinglong Mee 	} else /* case 4 (new client) or cases 2, 3 (client reboot): */
3299c212cecfSStanislav Kinsbursky 		gen_clid(new, nn);
33008323c3b2SJ. Bruce Fields 	new->cl_minorversion = 0;
33016f3d772fSTakuma Umeya 	gen_callback(new, setclid, rqstp);
3302ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
33031da177e4SLinus Torvalds 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
33041da177e4SLinus Torvalds 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
33051da177e4SLinus Torvalds 	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
33065cc40fd7STrond Myklebust 	new = NULL;
33071da177e4SLinus Torvalds 	status = nfs_ok;
33081da177e4SLinus Torvalds out:
33093dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
33105cc40fd7STrond Myklebust 	if (new)
33115cc40fd7STrond Myklebust 		free_client(new);
33123dbacee6STrond Myklebust 	if (unconf)
33133dbacee6STrond Myklebust 		expire_client(unconf);
33141da177e4SLinus Torvalds 	return status;
33151da177e4SLinus Torvalds }
33161da177e4SLinus Torvalds 
33171da177e4SLinus Torvalds 
3318b37ad28bSAl Viro __be32
3319b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
3320b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
3321eb69853dSChristoph Hellwig 			union nfsd4_op_u *u)
33221da177e4SLinus Torvalds {
3323eb69853dSChristoph Hellwig 	struct nfsd4_setclientid_confirm *setclientid_confirm =
3324eb69853dSChristoph Hellwig 			&u->setclientid_confirm;
332521ab45a4SNeilBrown 	struct nfs4_client *conf, *unconf;
3326d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
33271da177e4SLinus Torvalds 	nfs4_verifier confirm = setclientid_confirm->sc_confirm;
33281da177e4SLinus Torvalds 	clientid_t * clid = &setclientid_confirm->sc_clientid;
3329b37ad28bSAl Viro 	__be32 status;
33307f2210faSStanislav Kinsbursky 	struct nfsd_net	*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
33311da177e4SLinus Torvalds 
33322c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(clid, nn))
33331da177e4SLinus Torvalds 		return nfserr_stale_clientid;
333421ab45a4SNeilBrown 
3335d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
33368daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(clid, false, nn);
33370a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(clid, false, nn);
3338a186e767SJ. Bruce Fields 	/*
33398695b90aSJ. Bruce Fields 	 * We try hard to give out unique clientid's, so if we get an
33408695b90aSJ. Bruce Fields 	 * attempt to confirm the same clientid with a different cred,
3341f984a7ceSJ. Bruce Fields 	 * the client may be buggy; this should never happen.
3342f984a7ceSJ. Bruce Fields 	 *
3343f984a7ceSJ. Bruce Fields 	 * Nevertheless, RFC 7530 recommends INUSE for this case:
3344a186e767SJ. Bruce Fields 	 */
3345f984a7ceSJ. Bruce Fields 	status = nfserr_clid_inuse;
33468695b90aSJ. Bruce Fields 	if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred))
33478695b90aSJ. Bruce Fields 		goto out;
33488695b90aSJ. Bruce Fields 	if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred))
33498695b90aSJ. Bruce Fields 		goto out;
335063db4632SJ. Bruce Fields 	/* cases below refer to rfc 3530 section 14.2.34: */
335190d700b7SJ. Bruce Fields 	if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) {
33527d22fc11SJ. Bruce Fields 		if (conf && same_verf(&confirm, &conf->cl_confirm)) {
33537d22fc11SJ. Bruce Fields 			/* case 2: probable retransmit */
335490d700b7SJ. Bruce Fields 			status = nfs_ok;
33557d22fc11SJ. Bruce Fields 		} else /* case 4: client hasn't noticed we rebooted yet? */
335690d700b7SJ. Bruce Fields 			status = nfserr_stale_clientid;
335790d700b7SJ. Bruce Fields 		goto out;
335890d700b7SJ. Bruce Fields 	}
335990d700b7SJ. Bruce Fields 	status = nfs_ok;
336090d700b7SJ. Bruce Fields 	if (conf) { /* case 1: callback update */
3361d20c11d8SJeff Layton 		old = unconf;
3362d20c11d8SJeff Layton 		unhash_client_locked(old);
33635a3c9d71SJ. Bruce Fields 		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
336490d700b7SJ. Bruce Fields 	} else { /* case 3: normal case; new or rebooted client */
3365d20c11d8SJeff Layton 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
3366d20c11d8SJeff Layton 		if (old) {
33672b634821SJ. Bruce Fields 			status = nfserr_clid_inuse;
33682b634821SJ. Bruce Fields 			if (client_has_state(old)
33692b634821SJ. Bruce Fields 					&& !same_creds(&unconf->cl_cred,
33702b634821SJ. Bruce Fields 							&old->cl_cred))
33712b634821SJ. Bruce Fields 				goto out;
3372d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
33737abea1e8SJeff Layton 			if (status) {
33747abea1e8SJeff Layton 				old = NULL;
3375221a6876SJ. Bruce Fields 				goto out;
3376221a6876SJ. Bruce Fields 			}
33777abea1e8SJeff Layton 		}
33781da177e4SLinus Torvalds 		move_to_confirmed(unconf);
3379d20c11d8SJeff Layton 		conf = unconf;
338008e8987cSNeilBrown 	}
3381d20c11d8SJeff Layton 	get_client_locked(conf);
3382d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3383d20c11d8SJeff Layton 	nfsd4_probe_callback(conf);
3384d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
3385d20c11d8SJeff Layton 	put_client_renew_locked(conf);
33861da177e4SLinus Torvalds out:
3387d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3388d20c11d8SJeff Layton 	if (old)
3389d20c11d8SJeff Layton 		expire_client(old);
33901da177e4SLinus Torvalds 	return status;
33911da177e4SLinus Torvalds }
33921da177e4SLinus Torvalds 
339332513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void)
33941da177e4SLinus Torvalds {
339532513b40SJ. Bruce Fields 	return kmem_cache_alloc(file_slab, GFP_KERNEL);
339632513b40SJ. Bruce Fields }
339732513b40SJ. Bruce Fields 
339832513b40SJ. Bruce Fields /* OPEN Share state helper functions */
33995b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
34005b095e99SJeff Layton 				struct nfs4_file *fp)
340132513b40SJ. Bruce Fields {
3402950e0118STrond Myklebust 	lockdep_assert_held(&state_lock);
3403950e0118STrond Myklebust 
3404818a34ebSElena Reshetova 	refcount_set(&fp->fi_ref, 1);
34051d31a253STrond Myklebust 	spin_lock_init(&fp->fi_lock);
34068beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_stateids);
34078beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_delegations);
34088287f009SSachin Bhamare 	INIT_LIST_HEAD(&fp->fi_clnt_odstate);
3409e2cf80d7STrond Myklebust 	fh_copy_shallow(&fp->fi_fhandle, fh);
34100c637be8SJeff Layton 	fp->fi_deleg_file = NULL;
341147f9940cSMeelap Shah 	fp->fi_had_conflict = false;
3412baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
3413f9d7562fSJ. Bruce Fields 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
3414f9d7562fSJ. Bruce Fields 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
34159cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
34169cf514ccSChristoph Hellwig 	INIT_LIST_HEAD(&fp->fi_lo_states);
3417c5c707f9SChristoph Hellwig 	atomic_set(&fp->fi_lo_recalls, 0);
34189cf514ccSChristoph Hellwig #endif
34195b095e99SJeff Layton 	hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]);
34201da177e4SLinus Torvalds }
34211da177e4SLinus Torvalds 
3422e8ff2a84SJ. Bruce Fields void
3423e60d4398SNeilBrown nfsd4_free_slabs(void)
3424e60d4398SNeilBrown {
34258287f009SSachin Bhamare 	kmem_cache_destroy(odstate_slab);
3426abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3427abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3428abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3429abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3430abf1135bSChristoph Hellwig 	kmem_cache_destroy(deleg_slab);
3431e60d4398SNeilBrown }
34321da177e4SLinus Torvalds 
343372083396SBryan Schumaker int
34341da177e4SLinus Torvalds nfsd4_init_slabs(void)
34351da177e4SLinus Torvalds {
3436fe0750e5SJ. Bruce Fields 	openowner_slab = kmem_cache_create("nfsd4_openowners",
3437fe0750e5SJ. Bruce Fields 			sizeof(struct nfs4_openowner), 0, 0, NULL);
3438fe0750e5SJ. Bruce Fields 	if (openowner_slab == NULL)
3439abf1135bSChristoph Hellwig 		goto out;
3440fe0750e5SJ. Bruce Fields 	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
34413c40794bSYanchuan Nian 			sizeof(struct nfs4_lockowner), 0, 0, NULL);
3442fe0750e5SJ. Bruce Fields 	if (lockowner_slab == NULL)
3443abf1135bSChristoph Hellwig 		goto out_free_openowner_slab;
3444e60d4398SNeilBrown 	file_slab = kmem_cache_create("nfsd4_files",
344520c2df83SPaul Mundt 			sizeof(struct nfs4_file), 0, 0, NULL);
3446e60d4398SNeilBrown 	if (file_slab == NULL)
3447abf1135bSChristoph Hellwig 		goto out_free_lockowner_slab;
34485ac049acSNeilBrown 	stateid_slab = kmem_cache_create("nfsd4_stateids",
3449dcef0413SJ. Bruce Fields 			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
34505ac049acSNeilBrown 	if (stateid_slab == NULL)
3451abf1135bSChristoph Hellwig 		goto out_free_file_slab;
34525b2d21c1SNeilBrown 	deleg_slab = kmem_cache_create("nfsd4_delegations",
345320c2df83SPaul Mundt 			sizeof(struct nfs4_delegation), 0, 0, NULL);
34545b2d21c1SNeilBrown 	if (deleg_slab == NULL)
3455abf1135bSChristoph Hellwig 		goto out_free_stateid_slab;
34568287f009SSachin Bhamare 	odstate_slab = kmem_cache_create("nfsd4_odstate",
34578287f009SSachin Bhamare 			sizeof(struct nfs4_clnt_odstate), 0, 0, NULL);
34588287f009SSachin Bhamare 	if (odstate_slab == NULL)
34598287f009SSachin Bhamare 		goto out_free_deleg_slab;
3460e60d4398SNeilBrown 	return 0;
3461abf1135bSChristoph Hellwig 
34628287f009SSachin Bhamare out_free_deleg_slab:
34638287f009SSachin Bhamare 	kmem_cache_destroy(deleg_slab);
3464abf1135bSChristoph Hellwig out_free_stateid_slab:
3465abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3466abf1135bSChristoph Hellwig out_free_file_slab:
3467abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3468abf1135bSChristoph Hellwig out_free_lockowner_slab:
3469abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3470abf1135bSChristoph Hellwig out_free_openowner_slab:
3471abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3472abf1135bSChristoph Hellwig out:
34731da177e4SLinus Torvalds 	dprintk("nfsd4: out of memory while initializing nfsv4\n");
34741da177e4SLinus Torvalds 	return -ENOMEM;
34751da177e4SLinus Torvalds }
34761da177e4SLinus Torvalds 
3477ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp)
3478ff194bd9SJ. Bruce Fields {
3479ff194bd9SJ. Bruce Fields 	rp->rp_status = nfserr_serverfault;
3480ff194bd9SJ. Bruce Fields 	rp->rp_buflen = 0;
3481ff194bd9SJ. Bruce Fields 	rp->rp_buf = rp->rp_ibuf;
348258fb12e6SJeff Layton 	mutex_init(&rp->rp_mutex);
348358fb12e6SJeff Layton }
348458fb12e6SJeff Layton 
348558fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
348658fb12e6SJeff Layton 		struct nfs4_stateowner *so)
348758fb12e6SJeff Layton {
348858fb12e6SJeff Layton 	if (!nfsd4_has_session(cstate)) {
348958fb12e6SJeff Layton 		mutex_lock(&so->so_replay.rp_mutex);
3490b5971afaSKinglong Mee 		cstate->replay_owner = nfs4_get_stateowner(so);
349158fb12e6SJeff Layton 	}
349258fb12e6SJeff Layton }
349358fb12e6SJeff Layton 
349458fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate)
349558fb12e6SJeff Layton {
349658fb12e6SJeff Layton 	struct nfs4_stateowner *so = cstate->replay_owner;
349758fb12e6SJeff Layton 
349858fb12e6SJeff Layton 	if (so != NULL) {
349958fb12e6SJeff Layton 		cstate->replay_owner = NULL;
350058fb12e6SJeff Layton 		mutex_unlock(&so->so_replay.rp_mutex);
350158fb12e6SJeff Layton 		nfs4_put_stateowner(so);
350258fb12e6SJeff Layton 	}
3503ff194bd9SJ. Bruce Fields }
3504ff194bd9SJ. Bruce Fields 
3505fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
35061da177e4SLinus Torvalds {
35071da177e4SLinus Torvalds 	struct nfs4_stateowner *sop;
35081da177e4SLinus Torvalds 
3509fe0750e5SJ. Bruce Fields 	sop = kmem_cache_alloc(slab, GFP_KERNEL);
3510ff194bd9SJ. Bruce Fields 	if (!sop)
3511ff194bd9SJ. Bruce Fields 		return NULL;
3512ff194bd9SJ. Bruce Fields 
3513ff194bd9SJ. Bruce Fields 	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
3514ff194bd9SJ. Bruce Fields 	if (!sop->so_owner.data) {
3515fe0750e5SJ. Bruce Fields 		kmem_cache_free(slab, sop);
3516ff194bd9SJ. Bruce Fields 		return NULL;
3517ff194bd9SJ. Bruce Fields 	}
35181da177e4SLinus Torvalds 	sop->so_owner.len = owner->len;
3519ff194bd9SJ. Bruce Fields 
3520ff194bd9SJ. Bruce Fields 	INIT_LIST_HEAD(&sop->so_stateids);
3521ff194bd9SJ. Bruce Fields 	sop->so_client = clp;
3522ff194bd9SJ. Bruce Fields 	init_nfs4_replay(&sop->so_replay);
35236b180f0bSJeff Layton 	atomic_set(&sop->so_count, 1);
35241da177e4SLinus Torvalds 	return sop;
35251da177e4SLinus Torvalds }
3526ff194bd9SJ. Bruce Fields 
3527fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
3528ff194bd9SJ. Bruce Fields {
3529d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
35309b531137SStanislav Kinsbursky 
3531d4f0489fSTrond Myklebust 	list_add(&oo->oo_owner.so_strhash,
3532d4f0489fSTrond Myklebust 		 &clp->cl_ownerstr_hashtbl[strhashval]);
3533fe0750e5SJ. Bruce Fields 	list_add(&oo->oo_perclient, &clp->cl_openowners);
35341da177e4SLinus Torvalds }
35351da177e4SLinus Torvalds 
35368f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
35378f4b54c5SJeff Layton {
3538d4f0489fSTrond Myklebust 	unhash_openowner_locked(openowner(so));
35398f4b54c5SJeff Layton }
35408f4b54c5SJeff Layton 
35416b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so)
35426b180f0bSJeff Layton {
35436b180f0bSJeff Layton 	struct nfs4_openowner *oo = openowner(so);
35446b180f0bSJeff Layton 
35456b180f0bSJeff Layton 	kmem_cache_free(openowner_slab, oo);
35466b180f0bSJeff Layton }
35476b180f0bSJeff Layton 
35486b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = {
35498f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_openowner,
35506b180f0bSJeff Layton 	.so_free =	nfs4_free_openowner,
35516b180f0bSJeff Layton };
35526b180f0bSJeff Layton 
35537fc0564eSAndrew Elble static struct nfs4_ol_stateid *
35547fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
35557fc0564eSAndrew Elble {
35567fc0564eSAndrew Elble 	struct nfs4_ol_stateid *local, *ret = NULL;
35577fc0564eSAndrew Elble 	struct nfs4_openowner *oo = open->op_openowner;
35587fc0564eSAndrew Elble 
35597fc0564eSAndrew Elble 	lockdep_assert_held(&fp->fi_lock);
35607fc0564eSAndrew Elble 
35617fc0564eSAndrew Elble 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
35627fc0564eSAndrew Elble 		/* ignore lock owners */
35637fc0564eSAndrew Elble 		if (local->st_stateowner->so_is_open_owner == 0)
35647fc0564eSAndrew Elble 			continue;
356515ca08d3STrond Myklebust 		if (local->st_stateowner != &oo->oo_owner)
356615ca08d3STrond Myklebust 			continue;
356715ca08d3STrond Myklebust 		if (local->st_stid.sc_type == NFS4_OPEN_STID) {
35687fc0564eSAndrew Elble 			ret = local;
3569a15dfcd5SElena Reshetova 			refcount_inc(&ret->st_stid.sc_count);
35707fc0564eSAndrew Elble 			break;
35717fc0564eSAndrew Elble 		}
35727fc0564eSAndrew Elble 	}
35737fc0564eSAndrew Elble 	return ret;
35747fc0564eSAndrew Elble }
35757fc0564eSAndrew Elble 
357615ca08d3STrond Myklebust static __be32
357715ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s)
357815ca08d3STrond Myklebust {
357915ca08d3STrond Myklebust 	__be32 ret = nfs_ok;
358015ca08d3STrond Myklebust 
358115ca08d3STrond Myklebust 	switch (s->sc_type) {
358215ca08d3STrond Myklebust 	default:
358315ca08d3STrond Myklebust 		break;
358415ca08d3STrond Myklebust 	case NFS4_CLOSED_STID:
358515ca08d3STrond Myklebust 	case NFS4_CLOSED_DELEG_STID:
358615ca08d3STrond Myklebust 		ret = nfserr_bad_stateid;
358715ca08d3STrond Myklebust 		break;
358815ca08d3STrond Myklebust 	case NFS4_REVOKED_DELEG_STID:
358915ca08d3STrond Myklebust 		ret = nfserr_deleg_revoked;
359015ca08d3STrond Myklebust 	}
359115ca08d3STrond Myklebust 	return ret;
359215ca08d3STrond Myklebust }
359315ca08d3STrond Myklebust 
359415ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */
359515ca08d3STrond Myklebust static __be32
359615ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp)
359715ca08d3STrond Myklebust {
359815ca08d3STrond Myklebust 	__be32 ret;
359915ca08d3STrond Myklebust 
360015ca08d3STrond Myklebust 	mutex_lock(&stp->st_mutex);
360115ca08d3STrond Myklebust 	ret = nfsd4_verify_open_stid(&stp->st_stid);
360215ca08d3STrond Myklebust 	if (ret != nfs_ok)
360315ca08d3STrond Myklebust 		mutex_unlock(&stp->st_mutex);
360415ca08d3STrond Myklebust 	return ret;
360515ca08d3STrond Myklebust }
360615ca08d3STrond Myklebust 
360715ca08d3STrond Myklebust static struct nfs4_ol_stateid *
360815ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
360915ca08d3STrond Myklebust {
361015ca08d3STrond Myklebust 	struct nfs4_ol_stateid *stp;
361115ca08d3STrond Myklebust 	for (;;) {
361215ca08d3STrond Myklebust 		spin_lock(&fp->fi_lock);
361315ca08d3STrond Myklebust 		stp = nfsd4_find_existing_open(fp, open);
361415ca08d3STrond Myklebust 		spin_unlock(&fp->fi_lock);
361515ca08d3STrond Myklebust 		if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok)
361615ca08d3STrond Myklebust 			break;
361715ca08d3STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
361815ca08d3STrond Myklebust 	}
361915ca08d3STrond Myklebust 	return stp;
362015ca08d3STrond Myklebust }
362115ca08d3STrond Myklebust 
3622fe0750e5SJ. Bruce Fields static struct nfs4_openowner *
362313d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3624db24b3b4SJeff Layton 			   struct nfsd4_compound_state *cstate)
3625db24b3b4SJeff Layton {
362613d6f66bSTrond Myklebust 	struct nfs4_client *clp = cstate->clp;
36277ffb5880STrond Myklebust 	struct nfs4_openowner *oo, *ret;
36281da177e4SLinus Torvalds 
3629fe0750e5SJ. Bruce Fields 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
3630fe0750e5SJ. Bruce Fields 	if (!oo)
36311da177e4SLinus Torvalds 		return NULL;
36326b180f0bSJeff Layton 	oo->oo_owner.so_ops = &openowner_ops;
3633fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_is_open_owner = 1;
3634fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_seqid = open->op_seqid;
3635d3134b10SJeff Layton 	oo->oo_flags = 0;
3636db24b3b4SJeff Layton 	if (nfsd4_has_session(cstate))
3637db24b3b4SJeff Layton 		oo->oo_flags |= NFS4_OO_CONFIRMED;
3638fe0750e5SJ. Bruce Fields 	oo->oo_time = 0;
363938c387b5SJ. Bruce Fields 	oo->oo_last_closed_stid = NULL;
3640fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&oo->oo_close_lru);
3641d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
3642d4f0489fSTrond Myklebust 	ret = find_openstateowner_str_locked(strhashval, open, clp);
36437ffb5880STrond Myklebust 	if (ret == NULL) {
3644fe0750e5SJ. Bruce Fields 		hash_openowner(oo, clp, strhashval);
36457ffb5880STrond Myklebust 		ret = oo;
36467ffb5880STrond Myklebust 	} else
3647d50ffdedSKinglong Mee 		nfs4_free_stateowner(&oo->oo_owner);
3648d50ffdedSKinglong Mee 
3649d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
3650c5952338SJeff Layton 	return ret;
36511da177e4SLinus Torvalds }
36521da177e4SLinus Torvalds 
36537fc0564eSAndrew Elble static struct nfs4_ol_stateid *
36548c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open)
36557fc0564eSAndrew Elble {
36561da177e4SLinus Torvalds 
36577fc0564eSAndrew Elble 	struct nfs4_openowner *oo = open->op_openowner;
36587fc0564eSAndrew Elble 	struct nfs4_ol_stateid *retstp = NULL;
36598c7245abSOleg Drokin 	struct nfs4_ol_stateid *stp;
36607fc0564eSAndrew Elble 
36618c7245abSOleg Drokin 	stp = open->op_stp;
36625cc1fb2aSOleg Drokin 	/* We are moving these outside of the spinlocks to avoid the warnings */
36635cc1fb2aSOleg Drokin 	mutex_init(&stp->st_mutex);
36645cc1fb2aSOleg Drokin 	mutex_lock(&stp->st_mutex);
36655cc1fb2aSOleg Drokin 
366615ca08d3STrond Myklebust retry:
36677fc0564eSAndrew Elble 	spin_lock(&oo->oo_owner.so_client->cl_lock);
36687fc0564eSAndrew Elble 	spin_lock(&fp->fi_lock);
36697fc0564eSAndrew Elble 
36707fc0564eSAndrew Elble 	retstp = nfsd4_find_existing_open(fp, open);
36717fc0564eSAndrew Elble 	if (retstp)
36727fc0564eSAndrew Elble 		goto out_unlock;
36738c7245abSOleg Drokin 
36748c7245abSOleg Drokin 	open->op_stp = NULL;
3675a15dfcd5SElena Reshetova 	refcount_inc(&stp->st_stid.sc_count);
36763abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_OPEN_STID;
36773c87b9b7STrond Myklebust 	INIT_LIST_HEAD(&stp->st_locks);
3678b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
367913cd2184SNeilBrown 	get_nfs4_file(fp);
368011b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
36811da177e4SLinus Torvalds 	stp->st_access_bmap = 0;
36821da177e4SLinus Torvalds 	stp->st_deny_bmap = 0;
36834c4cd222SNeilBrown 	stp->st_openstp = NULL;
36841c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
36851d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
36867fc0564eSAndrew Elble 
36877fc0564eSAndrew Elble out_unlock:
36881d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
36891c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
36905cc1fb2aSOleg Drokin 	if (retstp) {
369115ca08d3STrond Myklebust 		/* Handle races with CLOSE */
369215ca08d3STrond Myklebust 		if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
369315ca08d3STrond Myklebust 			nfs4_put_stid(&retstp->st_stid);
369415ca08d3STrond Myklebust 			goto retry;
369515ca08d3STrond Myklebust 		}
36968c7245abSOleg Drokin 		/* To keep mutex tracking happy */
36975cc1fb2aSOleg Drokin 		mutex_unlock(&stp->st_mutex);
36988c7245abSOleg Drokin 		stp = retstp;
36995cc1fb2aSOleg Drokin 	}
37008c7245abSOleg Drokin 	return stp;
37011da177e4SLinus Torvalds }
37021da177e4SLinus Torvalds 
3703d3134b10SJeff Layton /*
3704d3134b10SJeff Layton  * In the 4.0 case we need to keep the owners around a little while to handle
3705d3134b10SJeff Layton  * CLOSE replay. We still do need to release any file access that is held by
3706d3134b10SJeff Layton  * them before returning however.
3707d3134b10SJeff Layton  */
37081da177e4SLinus Torvalds static void
3709d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
37101da177e4SLinus Torvalds {
3711217526e7SJeff Layton 	struct nfs4_ol_stateid *last;
3712d3134b10SJeff Layton 	struct nfs4_openowner *oo = openowner(s->st_stateowner);
3713d3134b10SJeff Layton 	struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net,
3714d3134b10SJeff Layton 						nfsd_net_id);
371573758fedSStanislav Kinsbursky 
3716fe0750e5SJ. Bruce Fields 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
37171da177e4SLinus Torvalds 
3718b401be22SJeff Layton 	/*
3719b401be22SJeff Layton 	 * We know that we hold one reference via nfsd4_close, and another
3720b401be22SJeff Layton 	 * "persistent" reference for the client. If the refcount is higher
3721b401be22SJeff Layton 	 * than 2, then there are still calls in progress that are using this
3722b401be22SJeff Layton 	 * stateid. We can't put the sc_file reference until they are finished.
3723b401be22SJeff Layton 	 * Wait for the refcount to drop to 2. Since it has been unhashed,
3724b401be22SJeff Layton 	 * there should be no danger of the refcount going back up again at
3725b401be22SJeff Layton 	 * this point.
3726b401be22SJeff Layton 	 */
3727a15dfcd5SElena Reshetova 	wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2);
3728b401be22SJeff Layton 
3729d3134b10SJeff Layton 	release_all_access(s);
3730d3134b10SJeff Layton 	if (s->st_stid.sc_file) {
3731d3134b10SJeff Layton 		put_nfs4_file(s->st_stid.sc_file);
3732d3134b10SJeff Layton 		s->st_stid.sc_file = NULL;
3733d3134b10SJeff Layton 	}
3734217526e7SJeff Layton 
3735217526e7SJeff Layton 	spin_lock(&nn->client_lock);
3736217526e7SJeff Layton 	last = oo->oo_last_closed_stid;
3737d3134b10SJeff Layton 	oo->oo_last_closed_stid = s;
373873758fedSStanislav Kinsbursky 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
3739fe0750e5SJ. Bruce Fields 	oo->oo_time = get_seconds();
3740217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
3741217526e7SJeff Layton 	if (last)
3742217526e7SJeff Layton 		nfs4_put_stid(&last->st_stid);
37431da177e4SLinus Torvalds }
37441da177e4SLinus Torvalds 
37451da177e4SLinus Torvalds /* search file_hashtbl[] for file */
37461da177e4SLinus Torvalds static struct nfs4_file *
37475b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval)
37481da177e4SLinus Torvalds {
37491da177e4SLinus Torvalds 	struct nfs4_file *fp;
37501da177e4SLinus Torvalds 
37515b095e99SJeff Layton 	hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) {
37524d94c2efSChristoph Hellwig 		if (fh_match(&fp->fi_fhandle, fh)) {
3753818a34ebSElena Reshetova 			if (refcount_inc_not_zero(&fp->fi_ref))
37541da177e4SLinus Torvalds 				return fp;
37551da177e4SLinus Torvalds 		}
375613cd2184SNeilBrown 	}
37571da177e4SLinus Torvalds 	return NULL;
37581da177e4SLinus Torvalds }
37591da177e4SLinus Torvalds 
3760e6ba76e1SChristoph Hellwig struct nfs4_file *
3761ca943217STrond Myklebust find_file(struct knfsd_fh *fh)
3762950e0118STrond Myklebust {
3763950e0118STrond Myklebust 	struct nfs4_file *fp;
37645b095e99SJeff Layton 	unsigned int hashval = file_hashval(fh);
3765950e0118STrond Myklebust 
37665b095e99SJeff Layton 	rcu_read_lock();
37675b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
37685b095e99SJeff Layton 	rcu_read_unlock();
3769950e0118STrond Myklebust 	return fp;
3770950e0118STrond Myklebust }
3771950e0118STrond Myklebust 
3772950e0118STrond Myklebust static struct nfs4_file *
3773f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh)
3774950e0118STrond Myklebust {
3775950e0118STrond Myklebust 	struct nfs4_file *fp;
37765b095e99SJeff Layton 	unsigned int hashval = file_hashval(fh);
37775b095e99SJeff Layton 
37785b095e99SJeff Layton 	rcu_read_lock();
37795b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
37805b095e99SJeff Layton 	rcu_read_unlock();
37815b095e99SJeff Layton 	if (fp)
37825b095e99SJeff Layton 		return fp;
3783950e0118STrond Myklebust 
3784950e0118STrond Myklebust 	spin_lock(&state_lock);
37855b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
37865b095e99SJeff Layton 	if (likely(fp == NULL)) {
37875b095e99SJeff Layton 		nfsd4_init_file(fh, hashval, new);
3788950e0118STrond Myklebust 		fp = new;
3789950e0118STrond Myklebust 	}
3790950e0118STrond Myklebust 	spin_unlock(&state_lock);
3791950e0118STrond Myklebust 
3792950e0118STrond Myklebust 	return fp;
3793950e0118STrond Myklebust }
3794950e0118STrond Myklebust 
37954f83aa30SJ. Bruce Fields /*
37961da177e4SLinus Torvalds  * Called to check deny when READ with all zero stateid or
37971da177e4SLinus Torvalds  * WRITE with all zero or all one stateid
37981da177e4SLinus Torvalds  */
3799b37ad28bSAl Viro static __be32
38001da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
38011da177e4SLinus Torvalds {
38021da177e4SLinus Torvalds 	struct nfs4_file *fp;
3803baeb4ff0SJeff Layton 	__be32 ret = nfs_ok;
38041da177e4SLinus Torvalds 
3805ca943217STrond Myklebust 	fp = find_file(&current_fh->fh_handle);
380613cd2184SNeilBrown 	if (!fp)
3807baeb4ff0SJeff Layton 		return ret;
3808baeb4ff0SJeff Layton 	/* Check for conflicting share reservations */
38091d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
3810baeb4ff0SJeff Layton 	if (fp->fi_share_deny & deny_type)
3811baeb4ff0SJeff Layton 		ret = nfserr_locked;
38121d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
381313cd2184SNeilBrown 	put_nfs4_file(fp);
381413cd2184SNeilBrown 	return ret;
38151da177e4SLinus Torvalds }
38161da177e4SLinus Torvalds 
38170162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb)
38181da177e4SLinus Torvalds {
38190162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
382011b9164aSTrond Myklebust 	struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net,
382111b9164aSTrond Myklebust 					  nfsd_net_id);
3822e8c69d17SJ. Bruce Fields 
382311b9164aSTrond Myklebust 	block_delegations(&dp->dl_stid.sc_file->fi_fhandle);
3824f54fe962SJeff Layton 
382502e1215fSJeff Layton 	/*
382602e1215fSJeff Layton 	 * We can't do this in nfsd_break_deleg_cb because it is
3827f54fe962SJeff Layton 	 * already holding inode->i_lock.
3828f54fe962SJeff Layton 	 *
3829dff1399fSJeff Layton 	 * If the dl_time != 0, then we know that it has already been
3830dff1399fSJeff Layton 	 * queued for a lease break. Don't queue it again.
3831dff1399fSJeff Layton 	 */
3832f54fe962SJeff Layton 	spin_lock(&state_lock);
3833dff1399fSJeff Layton 	if (dp->dl_time == 0) {
38341da177e4SLinus Torvalds 		dp->dl_time = get_seconds();
383502e1215fSJeff Layton 		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
383602e1215fSJeff Layton 	}
383702e1215fSJeff Layton 	spin_unlock(&state_lock);
3838dff1399fSJeff Layton }
38391da177e4SLinus Torvalds 
38400162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
38410162ac2bSChristoph Hellwig 		struct rpc_task *task)
38420162ac2bSChristoph Hellwig {
38430162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
38440162ac2bSChristoph Hellwig 
3845a457974fSAndrew Elble 	if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID)
3846a457974fSAndrew Elble 	        return 1;
3847a457974fSAndrew Elble 
38480162ac2bSChristoph Hellwig 	switch (task->tk_status) {
38490162ac2bSChristoph Hellwig 	case 0:
38500162ac2bSChristoph Hellwig 		return 1;
38510162ac2bSChristoph Hellwig 	case -EBADHANDLE:
38520162ac2bSChristoph Hellwig 	case -NFS4ERR_BAD_STATEID:
38530162ac2bSChristoph Hellwig 		/*
38540162ac2bSChristoph Hellwig 		 * Race: client probably got cb_recall before open reply
38550162ac2bSChristoph Hellwig 		 * granting delegation.
38560162ac2bSChristoph Hellwig 		 */
38570162ac2bSChristoph Hellwig 		if (dp->dl_retries--) {
38580162ac2bSChristoph Hellwig 			rpc_delay(task, 2 * HZ);
38590162ac2bSChristoph Hellwig 			return 0;
38600162ac2bSChristoph Hellwig 		}
38610162ac2bSChristoph Hellwig 		/*FALLTHRU*/
38620162ac2bSChristoph Hellwig 	default:
38630162ac2bSChristoph Hellwig 		return -1;
38640162ac2bSChristoph Hellwig 	}
38650162ac2bSChristoph Hellwig }
38660162ac2bSChristoph Hellwig 
38670162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb)
38680162ac2bSChristoph Hellwig {
38690162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
38700162ac2bSChristoph Hellwig 
38710162ac2bSChristoph Hellwig 	nfs4_put_stid(&dp->dl_stid);
38720162ac2bSChristoph Hellwig }
38730162ac2bSChristoph Hellwig 
3874c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
38750162ac2bSChristoph Hellwig 	.prepare	= nfsd4_cb_recall_prepare,
38760162ac2bSChristoph Hellwig 	.done		= nfsd4_cb_recall_done,
38770162ac2bSChristoph Hellwig 	.release	= nfsd4_cb_recall_release,
38780162ac2bSChristoph Hellwig };
38790162ac2bSChristoph Hellwig 
388002e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
388102e1215fSJeff Layton {
388202e1215fSJeff Layton 	/*
388302e1215fSJeff Layton 	 * We're assuming the state code never drops its reference
388402e1215fSJeff Layton 	 * without first removing the lease.  Since we're in this lease
388502e1215fSJeff Layton 	 * callback (and since the lease code is serialized by the kernel
388602e1215fSJeff Layton 	 * lock) we know the server hasn't removed the lease yet, we know
388702e1215fSJeff Layton 	 * it's safe to take a reference.
388802e1215fSJeff Layton 	 */
3889a15dfcd5SElena Reshetova 	refcount_inc(&dp->dl_stid.sc_count);
3890f0b5de1bSChristoph Hellwig 	nfsd4_run_cb(&dp->dl_recall);
38916b57d9c8SJ. Bruce Fields }
38926b57d9c8SJ. Bruce Fields 
38931c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */
38944d01b7f5SJeff Layton static bool
38954d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl)
38966b57d9c8SJ. Bruce Fields {
38974d01b7f5SJeff Layton 	bool ret = false;
3898acfdf5c3SJ. Bruce Fields 	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
3899acfdf5c3SJ. Bruce Fields 	struct nfs4_delegation *dp;
39006b57d9c8SJ. Bruce Fields 
39017fa10cd1SJ. Bruce Fields 	if (!fp) {
39027fa10cd1SJ. Bruce Fields 		WARN(1, "(%p)->fl_owner NULL\n", fl);
39034d01b7f5SJeff Layton 		return ret;
39047fa10cd1SJ. Bruce Fields 	}
39057fa10cd1SJ. Bruce Fields 	if (fp->fi_had_conflict) {
39067fa10cd1SJ. Bruce Fields 		WARN(1, "duplicate break on %p\n", fp);
39074d01b7f5SJeff Layton 		return ret;
39087fa10cd1SJ. Bruce Fields 	}
39090272e1fdSJ. Bruce Fields 	/*
39100272e1fdSJ. Bruce Fields 	 * We don't want the locks code to timeout the lease for us;
3911acfdf5c3SJ. Bruce Fields 	 * we'll remove it ourself if a delegation isn't returned
39126b57d9c8SJ. Bruce Fields 	 * in time:
39130272e1fdSJ. Bruce Fields 	 */
39140272e1fdSJ. Bruce Fields 	fl->fl_break_time = 0;
39151da177e4SLinus Torvalds 
391602e1215fSJeff Layton 	spin_lock(&fp->fi_lock);
3917417c6629SJeff Layton 	fp->fi_had_conflict = true;
3918417c6629SJeff Layton 	/*
39194d01b7f5SJeff Layton 	 * If there are no delegations on the list, then return true
39204d01b7f5SJeff Layton 	 * so that the lease code will go ahead and delete it.
3921417c6629SJeff Layton 	 */
3922417c6629SJeff Layton 	if (list_empty(&fp->fi_delegations))
39234d01b7f5SJeff Layton 		ret = true;
3924417c6629SJeff Layton 	else
3925acfdf5c3SJ. Bruce Fields 		list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
39265d926e8cSJ. Bruce Fields 			nfsd_break_one_deleg(dp);
392702e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
39284d01b7f5SJeff Layton 	return ret;
39291da177e4SLinus Torvalds }
39301da177e4SLinus Torvalds 
3931c45198edSJeff Layton static int
39327448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
39337448cc37SJeff Layton 		     struct list_head *dispose)
39341da177e4SLinus Torvalds {
39351da177e4SLinus Torvalds 	if (arg & F_UNLCK)
3936c45198edSJeff Layton 		return lease_modify(onlist, arg, dispose);
39371da177e4SLinus Torvalds 	else
39381da177e4SLinus Torvalds 		return -EAGAIN;
39391da177e4SLinus Torvalds }
39401da177e4SLinus Torvalds 
39417b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = {
39428fb47a4fSJ. Bruce Fields 	.lm_break = nfsd_break_deleg_cb,
39438fb47a4fSJ. Bruce Fields 	.lm_change = nfsd_change_deleg_cb,
39441da177e4SLinus Torvalds };
39451da177e4SLinus Torvalds 
39467a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
39477a8711c9SJ. Bruce Fields {
39487a8711c9SJ. Bruce Fields 	if (nfsd4_has_session(cstate))
39497a8711c9SJ. Bruce Fields 		return nfs_ok;
39507a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid - 1)
39517a8711c9SJ. Bruce Fields 		return nfserr_replay_me;
39527a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid)
39537a8711c9SJ. Bruce Fields 		return nfs_ok;
39547a8711c9SJ. Bruce Fields 	return nfserr_bad_seqid;
39557a8711c9SJ. Bruce Fields }
39561da177e4SLinus Torvalds 
39574b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid,
39584b24ca7dSJeff Layton 		struct nfsd4_compound_state *cstate,
39594b24ca7dSJeff Layton 		struct nfsd_net *nn)
39604b24ca7dSJeff Layton {
39614b24ca7dSJeff Layton 	struct nfs4_client *found;
39624b24ca7dSJeff Layton 
39634b24ca7dSJeff Layton 	if (cstate->clp) {
39644b24ca7dSJeff Layton 		found = cstate->clp;
39654b24ca7dSJeff Layton 		if (!same_clid(&found->cl_clientid, clid))
39664b24ca7dSJeff Layton 			return nfserr_stale_clientid;
39674b24ca7dSJeff Layton 		return nfs_ok;
39684b24ca7dSJeff Layton 	}
39694b24ca7dSJeff Layton 
39704b24ca7dSJeff Layton 	if (STALE_CLIENTID(clid, nn))
39714b24ca7dSJeff Layton 		return nfserr_stale_clientid;
39724b24ca7dSJeff Layton 
39734b24ca7dSJeff Layton 	/*
39744b24ca7dSJeff Layton 	 * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
39754b24ca7dSJeff Layton 	 * cached already then we know this is for is for v4.0 and "sessions"
39764b24ca7dSJeff Layton 	 * will be false.
39774b24ca7dSJeff Layton 	 */
39784b24ca7dSJeff Layton 	WARN_ON_ONCE(cstate->session);
39793e339f96STrond Myklebust 	spin_lock(&nn->client_lock);
39804b24ca7dSJeff Layton 	found = find_confirmed_client(clid, false, nn);
39813e339f96STrond Myklebust 	if (!found) {
39823e339f96STrond Myklebust 		spin_unlock(&nn->client_lock);
39834b24ca7dSJeff Layton 		return nfserr_expired;
39843e339f96STrond Myklebust 	}
39853e339f96STrond Myklebust 	atomic_inc(&found->cl_refcount);
39863e339f96STrond Myklebust 	spin_unlock(&nn->client_lock);
39874b24ca7dSJeff Layton 
39884b24ca7dSJeff Layton 	/* Cache the nfs4_client in cstate! */
39894b24ca7dSJeff Layton 	cstate->clp = found;
39904b24ca7dSJeff Layton 	return nfs_ok;
39914b24ca7dSJeff Layton }
39924b24ca7dSJeff Layton 
3993b37ad28bSAl Viro __be32
39946668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate,
39953320fef1SStanislav Kinsbursky 		    struct nfsd4_open *open, struct nfsd_net *nn)
39961da177e4SLinus Torvalds {
39971da177e4SLinus Torvalds 	clientid_t *clientid = &open->op_clientid;
39981da177e4SLinus Torvalds 	struct nfs4_client *clp = NULL;
39991da177e4SLinus Torvalds 	unsigned int strhashval;
4000fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = NULL;
40014cdc951bSJ. Bruce Fields 	__be32 status;
40021da177e4SLinus Torvalds 
40032c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(&open->op_clientid, nn))
40041da177e4SLinus Torvalds 		return nfserr_stale_clientid;
400532513b40SJ. Bruce Fields 	/*
400632513b40SJ. Bruce Fields 	 * In case we need it later, after we've already created the
400732513b40SJ. Bruce Fields 	 * file and don't want to risk a further failure:
400832513b40SJ. Bruce Fields 	 */
400932513b40SJ. Bruce Fields 	open->op_file = nfsd4_alloc_file();
401032513b40SJ. Bruce Fields 	if (open->op_file == NULL)
401132513b40SJ. Bruce Fields 		return nfserr_jukebox;
40121da177e4SLinus Torvalds 
401313d6f66bSTrond Myklebust 	status = lookup_clientid(clientid, cstate, nn);
401413d6f66bSTrond Myklebust 	if (status)
401513d6f66bSTrond Myklebust 		return status;
401613d6f66bSTrond Myklebust 	clp = cstate->clp;
40172d91e895STrond Myklebust 
4018d4f0489fSTrond Myklebust 	strhashval = ownerstr_hashval(&open->op_owner);
4019d4f0489fSTrond Myklebust 	oo = find_openstateowner_str(strhashval, open, clp);
40202d91e895STrond Myklebust 	open->op_openowner = oo;
40212d91e895STrond Myklebust 	if (!oo) {
4022bcf130f9SJ. Bruce Fields 		goto new_owner;
40230f442aa2SJ. Bruce Fields 	}
4024dad1c067SJ. Bruce Fields 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
40250f442aa2SJ. Bruce Fields 		/* Replace unconfirmed owners without checking for replay. */
4026fe0750e5SJ. Bruce Fields 		release_openowner(oo);
4027fe0750e5SJ. Bruce Fields 		open->op_openowner = NULL;
4028bcf130f9SJ. Bruce Fields 		goto new_owner;
40290f442aa2SJ. Bruce Fields 	}
40304cdc951bSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
40314cdc951bSJ. Bruce Fields 	if (status)
40324cdc951bSJ. Bruce Fields 		return status;
40334cdc951bSJ. Bruce Fields 	goto alloc_stateid;
4034bcf130f9SJ. Bruce Fields new_owner:
403513d6f66bSTrond Myklebust 	oo = alloc_init_open_stateowner(strhashval, open, cstate);
4036fe0750e5SJ. Bruce Fields 	if (oo == NULL)
40373e772463SJ. Bruce Fields 		return nfserr_jukebox;
4038fe0750e5SJ. Bruce Fields 	open->op_openowner = oo;
40394cdc951bSJ. Bruce Fields alloc_stateid:
4040b49e084dSJeff Layton 	open->op_stp = nfs4_alloc_open_stateid(clp);
40414cdc951bSJ. Bruce Fields 	if (!open->op_stp)
40424cdc951bSJ. Bruce Fields 		return nfserr_jukebox;
40438287f009SSachin Bhamare 
40448287f009SSachin Bhamare 	if (nfsd4_has_session(cstate) &&
40458287f009SSachin Bhamare 	    (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) {
40468287f009SSachin Bhamare 		open->op_odstate = alloc_clnt_odstate(clp);
40478287f009SSachin Bhamare 		if (!open->op_odstate)
40488287f009SSachin Bhamare 			return nfserr_jukebox;
40498287f009SSachin Bhamare 	}
40508287f009SSachin Bhamare 
40510f442aa2SJ. Bruce Fields 	return nfs_ok;
40521da177e4SLinus Torvalds }
40531da177e4SLinus Torvalds 
4054b37ad28bSAl Viro static inline __be32
40554a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
40564a6e43e6SNeilBrown {
40574a6e43e6SNeilBrown 	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
40584a6e43e6SNeilBrown 		return nfserr_openmode;
40594a6e43e6SNeilBrown 	else
40604a6e43e6SNeilBrown 		return nfs_ok;
40614a6e43e6SNeilBrown }
40624a6e43e6SNeilBrown 
4063c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access)
406424a0111eSJ. Bruce Fields {
406524a0111eSJ. Bruce Fields 	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
406624a0111eSJ. Bruce Fields }
406724a0111eSJ. Bruce Fields 
406838c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
4069f459e453SJ. Bruce Fields {
4070f459e453SJ. Bruce Fields 	struct nfs4_stid *ret;
4071f459e453SJ. Bruce Fields 
407295da1b3aSAndrew Elble 	ret = find_stateid_by_type(cl, s,
407395da1b3aSAndrew Elble 				NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID);
4074f459e453SJ. Bruce Fields 	if (!ret)
4075f459e453SJ. Bruce Fields 		return NULL;
4076f459e453SJ. Bruce Fields 	return delegstateid(ret);
4077f459e453SJ. Bruce Fields }
4078f459e453SJ. Bruce Fields 
40798b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
40808b289b2cSJ. Bruce Fields {
40818b289b2cSJ. Bruce Fields 	return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
40828b289b2cSJ. Bruce Fields 	       open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
40838b289b2cSJ. Bruce Fields }
40848b289b2cSJ. Bruce Fields 
4085b37ad28bSAl Viro static __be32
408641d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
4087567d9829SNeilBrown 		struct nfs4_delegation **dp)
4088567d9829SNeilBrown {
4089567d9829SNeilBrown 	int flags;
4090b37ad28bSAl Viro 	__be32 status = nfserr_bad_stateid;
4091dcd94cc2STrond Myklebust 	struct nfs4_delegation *deleg;
4092567d9829SNeilBrown 
4093dcd94cc2STrond Myklebust 	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
4094dcd94cc2STrond Myklebust 	if (deleg == NULL)
4095c44c5eebSNeilBrown 		goto out;
409695da1b3aSAndrew Elble 	if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
409795da1b3aSAndrew Elble 		nfs4_put_stid(&deleg->dl_stid);
409895da1b3aSAndrew Elble 		if (cl->cl_minorversion)
409995da1b3aSAndrew Elble 			status = nfserr_deleg_revoked;
410095da1b3aSAndrew Elble 		goto out;
410195da1b3aSAndrew Elble 	}
410224a0111eSJ. Bruce Fields 	flags = share_access_to_flags(open->op_share_access);
4103dcd94cc2STrond Myklebust 	status = nfs4_check_delegmode(deleg, flags);
4104dcd94cc2STrond Myklebust 	if (status) {
4105dcd94cc2STrond Myklebust 		nfs4_put_stid(&deleg->dl_stid);
4106dcd94cc2STrond Myklebust 		goto out;
4107dcd94cc2STrond Myklebust 	}
4108dcd94cc2STrond Myklebust 	*dp = deleg;
4109c44c5eebSNeilBrown out:
41108b289b2cSJ. Bruce Fields 	if (!nfsd4_is_deleg_cur(open))
4111c44c5eebSNeilBrown 		return nfs_ok;
4112c44c5eebSNeilBrown 	if (status)
4113c44c5eebSNeilBrown 		return status;
4114dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
4115c44c5eebSNeilBrown 	return nfs_ok;
4116567d9829SNeilBrown }
4117567d9829SNeilBrown 
411821fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access)
411921fb4016SJ. Bruce Fields {
412021fb4016SJ. Bruce Fields 	int flags = 0;
412121fb4016SJ. Bruce Fields 
412221fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
412321fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_READ;
412421fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
412521fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_WRITE;
412621fb4016SJ. Bruce Fields 	return flags;
412721fb4016SJ. Bruce Fields }
412821fb4016SJ. Bruce Fields 
4129b37ad28bSAl Viro static inline __be32
41301da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
41311da177e4SLinus Torvalds 		struct nfsd4_open *open)
41321da177e4SLinus Torvalds {
41331da177e4SLinus Torvalds 	struct iattr iattr = {
41341da177e4SLinus Torvalds 		.ia_valid = ATTR_SIZE,
41351da177e4SLinus Torvalds 		.ia_size = 0,
41361da177e4SLinus Torvalds 	};
41371da177e4SLinus Torvalds 	if (!open->op_truncate)
41381da177e4SLinus Torvalds 		return 0;
41391da177e4SLinus Torvalds 	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
41409246585aSAl Viro 		return nfserr_inval;
41411da177e4SLinus Torvalds 	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
41421da177e4SLinus Torvalds }
41431da177e4SLinus Torvalds 
41447e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
41456eb3a1d0SJeff Layton 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
41466eb3a1d0SJeff Layton 		struct nfsd4_open *open)
41477e6a72e5SChristoph Hellwig {
4148de18643dSTrond Myklebust 	struct file *filp = NULL;
41497e6a72e5SChristoph Hellwig 	__be32 status;
41507e6a72e5SChristoph Hellwig 	int oflag = nfs4_access_to_omode(open->op_share_access);
41517e6a72e5SChristoph Hellwig 	int access = nfs4_access_to_access(open->op_share_access);
4152baeb4ff0SJeff Layton 	unsigned char old_access_bmap, old_deny_bmap;
41537e6a72e5SChristoph Hellwig 
4154de18643dSTrond Myklebust 	spin_lock(&fp->fi_lock);
4155baeb4ff0SJeff Layton 
4156baeb4ff0SJeff Layton 	/*
4157baeb4ff0SJeff Layton 	 * Are we trying to set a deny mode that would conflict with
4158baeb4ff0SJeff Layton 	 * current access?
4159baeb4ff0SJeff Layton 	 */
4160baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
4161baeb4ff0SJeff Layton 	if (status != nfs_ok) {
4162baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
4163baeb4ff0SJeff Layton 		goto out;
4164baeb4ff0SJeff Layton 	}
4165baeb4ff0SJeff Layton 
4166baeb4ff0SJeff Layton 	/* set access to the file */
4167baeb4ff0SJeff Layton 	status = nfs4_file_get_access(fp, open->op_share_access);
4168baeb4ff0SJeff Layton 	if (status != nfs_ok) {
4169baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
4170baeb4ff0SJeff Layton 		goto out;
4171baeb4ff0SJeff Layton 	}
4172baeb4ff0SJeff Layton 
4173baeb4ff0SJeff Layton 	/* Set access bits in stateid */
4174baeb4ff0SJeff Layton 	old_access_bmap = stp->st_access_bmap;
4175baeb4ff0SJeff Layton 	set_access(open->op_share_access, stp);
4176baeb4ff0SJeff Layton 
4177baeb4ff0SJeff Layton 	/* Set new deny mask */
4178baeb4ff0SJeff Layton 	old_deny_bmap = stp->st_deny_bmap;
4179baeb4ff0SJeff Layton 	set_deny(open->op_share_deny, stp);
4180baeb4ff0SJeff Layton 	fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH);
4181baeb4ff0SJeff Layton 
41827e6a72e5SChristoph Hellwig 	if (!fp->fi_fds[oflag]) {
4183de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
4184de18643dSTrond Myklebust 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
41857e6a72e5SChristoph Hellwig 		if (status)
4186baeb4ff0SJeff Layton 			goto out_put_access;
4187de18643dSTrond Myklebust 		spin_lock(&fp->fi_lock);
4188de18643dSTrond Myklebust 		if (!fp->fi_fds[oflag]) {
4189de18643dSTrond Myklebust 			fp->fi_fds[oflag] = filp;
4190de18643dSTrond Myklebust 			filp = NULL;
4191de18643dSTrond Myklebust 		}
41927e6a72e5SChristoph Hellwig 	}
4193de18643dSTrond Myklebust 	spin_unlock(&fp->fi_lock);
4194de18643dSTrond Myklebust 	if (filp)
4195de18643dSTrond Myklebust 		fput(filp);
41967e6a72e5SChristoph Hellwig 
41977e6a72e5SChristoph Hellwig 	status = nfsd4_truncate(rqstp, cur_fh, open);
41987e6a72e5SChristoph Hellwig 	if (status)
41997e6a72e5SChristoph Hellwig 		goto out_put_access;
42007e6a72e5SChristoph Hellwig out:
42017e6a72e5SChristoph Hellwig 	return status;
4202baeb4ff0SJeff Layton out_put_access:
4203baeb4ff0SJeff Layton 	stp->st_access_bmap = old_access_bmap;
4204baeb4ff0SJeff Layton 	nfs4_file_put_access(fp, open->op_share_access);
4205baeb4ff0SJeff Layton 	reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp);
4206baeb4ff0SJeff Layton 	goto out;
42077e6a72e5SChristoph Hellwig }
42087e6a72e5SChristoph Hellwig 
4209b37ad28bSAl Viro static __be32
4210dcef0413SJ. 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)
42111da177e4SLinus Torvalds {
4212b37ad28bSAl Viro 	__be32 status;
42136ac75368SArnd Bergmann 	unsigned char old_deny_bmap = stp->st_deny_bmap;
42141da177e4SLinus Torvalds 
42156eb3a1d0SJeff Layton 	if (!test_access(open->op_share_access, stp))
4216baeb4ff0SJeff Layton 		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
42177e6a72e5SChristoph Hellwig 
4218baeb4ff0SJeff Layton 	/* test and set deny mode */
4219baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
4220baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
4221baeb4ff0SJeff Layton 	if (status == nfs_ok) {
4222baeb4ff0SJeff Layton 		set_deny(open->op_share_deny, stp);
4223baeb4ff0SJeff Layton 		fp->fi_share_deny |=
4224baeb4ff0SJeff Layton 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
42251da177e4SLinus Torvalds 	}
4226baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
42271da177e4SLinus Torvalds 
4228baeb4ff0SJeff Layton 	if (status != nfs_ok)
4229baeb4ff0SJeff Layton 		return status;
4230baeb4ff0SJeff Layton 
4231baeb4ff0SJeff Layton 	status = nfsd4_truncate(rqstp, cur_fh, open);
4232baeb4ff0SJeff Layton 	if (status != nfs_ok)
4233baeb4ff0SJeff Layton 		reset_union_bmap_deny(old_deny_bmap, stp);
4234baeb4ff0SJeff Layton 	return status;
4235baeb4ff0SJeff Layton }
42361da177e4SLinus Torvalds 
423714a24e99SJ. Bruce Fields /* Should we give out recallable state?: */
423814a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
423914a24e99SJ. Bruce Fields {
424014a24e99SJ. Bruce Fields 	if (clp->cl_cb_state == NFSD4_CB_UP)
424114a24e99SJ. Bruce Fields 		return true;
424214a24e99SJ. Bruce Fields 	/*
424314a24e99SJ. Bruce Fields 	 * In the sessions case, since we don't have to establish a
424414a24e99SJ. Bruce Fields 	 * separate connection for callbacks, we assume it's OK
424514a24e99SJ. Bruce Fields 	 * until we hear otherwise:
424614a24e99SJ. Bruce Fields 	 */
424714a24e99SJ. Bruce Fields 	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
424814a24e99SJ. Bruce Fields }
424914a24e99SJ. Bruce Fields 
4250d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
425122d38c4cSJ. Bruce Fields {
425222d38c4cSJ. Bruce Fields 	struct file_lock *fl;
425322d38c4cSJ. Bruce Fields 
425422d38c4cSJ. Bruce Fields 	fl = locks_alloc_lock();
425522d38c4cSJ. Bruce Fields 	if (!fl)
425622d38c4cSJ. Bruce Fields 		return NULL;
425722d38c4cSJ. Bruce Fields 	fl->fl_lmops = &nfsd_lease_mng_ops;
4258617588d5SJ. Bruce Fields 	fl->fl_flags = FL_DELEG;
425922d38c4cSJ. Bruce Fields 	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
426022d38c4cSJ. Bruce Fields 	fl->fl_end = OFFSET_MAX;
4261d564fbecSJeff Layton 	fl->fl_owner = (fl_owner_t)fp;
426222d38c4cSJ. Bruce Fields 	fl->fl_pid = current->tgid;
426322d38c4cSJ. Bruce Fields 	return fl;
426422d38c4cSJ. Bruce Fields }
426522d38c4cSJ. Bruce Fields 
426634ed9872SAndrew Elble /**
426734ed9872SAndrew Elble  * nfs4_setlease - Obtain a delegation by requesting lease from vfs layer
426834ed9872SAndrew Elble  * @dp:   a pointer to the nfs4_delegation we're adding.
426934ed9872SAndrew Elble  *
427034ed9872SAndrew Elble  * Return:
427134ed9872SAndrew Elble  *      On success: Return code will be 0 on success.
427234ed9872SAndrew Elble  *
427334ed9872SAndrew Elble  *      On error: -EAGAIN if there was an existing delegation.
427434ed9872SAndrew Elble  *                 nonzero if there is an error in other cases.
427534ed9872SAndrew Elble  *
427634ed9872SAndrew Elble  */
427734ed9872SAndrew Elble 
427899c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp)
4279edab9782SJ. Bruce Fields {
428011b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
4281efde6b4dSKinglong Mee 	struct file_lock *fl;
4282417c6629SJeff Layton 	struct file *filp;
4283417c6629SJeff Layton 	int status = 0;
4284edab9782SJ. Bruce Fields 
4285d564fbecSJeff Layton 	fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ);
4286edab9782SJ. Bruce Fields 	if (!fl)
4287edab9782SJ. Bruce Fields 		return -ENOMEM;
4288417c6629SJeff Layton 	filp = find_readable_file(fp);
4289417c6629SJeff Layton 	if (!filp) {
4290417c6629SJeff Layton 		/* We should always have a readable file here */
4291417c6629SJeff Layton 		WARN_ON_ONCE(1);
4292af9dbaf4SKinglong Mee 		locks_free_lock(fl);
4293417c6629SJeff Layton 		return -EBADF;
4294417c6629SJeff Layton 	}
4295417c6629SJeff Layton 	fl->fl_file = filp;
4296e6f5c789SJeff Layton 	status = vfs_setlease(filp, fl->fl_type, &fl, NULL);
42971c7dd2ffSJeff Layton 	if (fl)
4298417c6629SJeff Layton 		locks_free_lock(fl);
42991c7dd2ffSJeff Layton 	if (status)
4300417c6629SJeff Layton 		goto out_fput;
4301cdc97505SBenny Halevy 	spin_lock(&state_lock);
4302417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
4303417c6629SJeff Layton 	/* Did the lease get broken before we took the lock? */
4304417c6629SJeff Layton 	status = -EAGAIN;
4305417c6629SJeff Layton 	if (fp->fi_had_conflict)
4306417c6629SJeff Layton 		goto out_unlock;
4307417c6629SJeff Layton 	/* Race breaker */
43080c637be8SJeff Layton 	if (fp->fi_deleg_file) {
430934ed9872SAndrew Elble 		status = hash_delegation_locked(dp, fp);
4310417c6629SJeff Layton 		goto out_unlock;
4311417c6629SJeff Layton 	}
4312417c6629SJeff Layton 	fp->fi_deleg_file = filp;
431334ed9872SAndrew Elble 	fp->fi_delegees = 0;
431434ed9872SAndrew Elble 	status = hash_delegation_locked(dp, fp);
4315417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4316cdc97505SBenny Halevy 	spin_unlock(&state_lock);
431734ed9872SAndrew Elble 	if (status) {
431834ed9872SAndrew Elble 		/* Should never happen, this is a new fi_deleg_file  */
431934ed9872SAndrew Elble 		WARN_ON_ONCE(1);
432034ed9872SAndrew Elble 		goto out_fput;
432134ed9872SAndrew Elble 	}
4322acfdf5c3SJ. Bruce Fields 	return 0;
4323417c6629SJeff Layton out_unlock:
4324417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4325417c6629SJeff Layton 	spin_unlock(&state_lock);
4326417c6629SJeff Layton out_fput:
4327417c6629SJeff Layton 	fput(filp);
4328e873088fSJ. Bruce Fields 	return status;
4329acfdf5c3SJ. Bruce Fields }
4330acfdf5c3SJ. Bruce Fields 
43310b26693cSJeff Layton static struct nfs4_delegation *
43320b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
43338287f009SSachin Bhamare 		    struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
4334acfdf5c3SJ. Bruce Fields {
43350b26693cSJeff Layton 	int status;
43360b26693cSJeff Layton 	struct nfs4_delegation *dp;
4337417c6629SJeff Layton 
4338bf7bd3e9SJ. Bruce Fields 	if (fp->fi_had_conflict)
43390b26693cSJeff Layton 		return ERR_PTR(-EAGAIN);
43400b26693cSJeff Layton 
434134ed9872SAndrew Elble 	spin_lock(&state_lock);
434234ed9872SAndrew Elble 	spin_lock(&fp->fi_lock);
434334ed9872SAndrew Elble 	status = nfs4_get_existing_delegation(clp, fp);
434434ed9872SAndrew Elble 	spin_unlock(&fp->fi_lock);
434534ed9872SAndrew Elble 	spin_unlock(&state_lock);
434634ed9872SAndrew Elble 
434734ed9872SAndrew Elble 	if (status)
434834ed9872SAndrew Elble 		return ERR_PTR(status);
434934ed9872SAndrew Elble 
43508287f009SSachin Bhamare 	dp = alloc_init_deleg(clp, fh, odstate);
43510b26693cSJeff Layton 	if (!dp)
43520b26693cSJeff Layton 		return ERR_PTR(-ENOMEM);
43530b26693cSJeff Layton 
4354bf7bd3e9SJ. Bruce Fields 	get_nfs4_file(fp);
4355cdc97505SBenny Halevy 	spin_lock(&state_lock);
4356417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
435711b9164aSTrond Myklebust 	dp->dl_stid.sc_file = fp;
43580c637be8SJeff Layton 	if (!fp->fi_deleg_file) {
4359417c6629SJeff Layton 		spin_unlock(&fp->fi_lock);
4360417c6629SJeff Layton 		spin_unlock(&state_lock);
43610b26693cSJeff Layton 		status = nfs4_setlease(dp);
43620b26693cSJeff Layton 		goto out;
4363417c6629SJeff Layton 	}
4364acfdf5c3SJ. Bruce Fields 	if (fp->fi_had_conflict) {
4365417c6629SJeff Layton 		status = -EAGAIN;
4366417c6629SJeff Layton 		goto out_unlock;
4367acfdf5c3SJ. Bruce Fields 	}
436834ed9872SAndrew Elble 	status = hash_delegation_locked(dp, fp);
4369417c6629SJeff Layton out_unlock:
4370417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4371cdc97505SBenny Halevy 	spin_unlock(&state_lock);
43720b26693cSJeff Layton out:
43730b26693cSJeff Layton 	if (status) {
43748287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
43756011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
43760b26693cSJeff Layton 		return ERR_PTR(status);
43770b26693cSJeff Layton 	}
43780b26693cSJeff Layton 	return dp;
4379edab9782SJ. Bruce Fields }
4380edab9782SJ. Bruce Fields 
43814aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
43824aa8913cSBenny Halevy {
43834aa8913cSBenny Halevy 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
43844aa8913cSBenny Halevy 	if (status == -EAGAIN)
43854aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_CONTENTION;
43864aa8913cSBenny Halevy 	else {
43874aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_RESOURCE;
43884aa8913cSBenny Halevy 		switch (open->op_deleg_want) {
43894aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_READ_DELEG:
43904aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_WRITE_DELEG:
43914aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_ANY_DELEG:
43924aa8913cSBenny Halevy 			break;
43934aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_CANCEL:
43944aa8913cSBenny Halevy 			open->op_why_no_deleg = WND4_CANCELLED;
43954aa8913cSBenny Halevy 			break;
43964aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_NO_DELEG:
4397063b0fb9SJ. Bruce Fields 			WARN_ON_ONCE(1);
43984aa8913cSBenny Halevy 		}
43994aa8913cSBenny Halevy 	}
44004aa8913cSBenny Halevy }
44014aa8913cSBenny Halevy 
44021da177e4SLinus Torvalds /*
44031da177e4SLinus Torvalds  * Attempt to hand out a delegation.
440499c41515SJ. Bruce Fields  *
440599c41515SJ. Bruce Fields  * Note we don't support write delegations, and won't until the vfs has
440699c41515SJ. Bruce Fields  * proper support for them.
44071da177e4SLinus Torvalds  */
44081da177e4SLinus Torvalds static void
44094cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
44104cf59221SJeff Layton 			struct nfs4_ol_stateid *stp)
44111da177e4SLinus Torvalds {
44121da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
44134cf59221SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_stateowner);
44144cf59221SJeff Layton 	struct nfs4_client *clp = stp->st_stid.sc_client;
441514a24e99SJ. Bruce Fields 	int cb_up;
441699c41515SJ. Bruce Fields 	int status = 0;
44171da177e4SLinus Torvalds 
4418fe0750e5SJ. Bruce Fields 	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
44197b190fecSNeilBrown 	open->op_recall = 0;
44207b190fecSNeilBrown 	switch (open->op_claim_type) {
44217b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_PREVIOUS:
44222bf23875SJ. Bruce Fields 			if (!cb_up)
44237b190fecSNeilBrown 				open->op_recall = 1;
442499c41515SJ. Bruce Fields 			if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
442599c41515SJ. Bruce Fields 				goto out_no_deleg;
44267b190fecSNeilBrown 			break;
44277b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_NULL:
4428ed47b062SMing Chen 		case NFS4_OPEN_CLAIM_FH:
442999c41515SJ. Bruce Fields 			/*
443099c41515SJ. Bruce Fields 			 * Let's not give out any delegations till everyone's
4431c87fb4a3SJ. Bruce Fields 			 * had the chance to reclaim theirs, *and* until
4432c87fb4a3SJ. Bruce Fields 			 * NLM locks have all been reclaimed:
443399c41515SJ. Bruce Fields 			 */
44344cf59221SJeff Layton 			if (locks_in_grace(clp->net))
443599c41515SJ. Bruce Fields 				goto out_no_deleg;
4436dad1c067SJ. Bruce Fields 			if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
443799c41515SJ. Bruce Fields 				goto out_no_deleg;
44389a0590aeSSteve Dickson 			/*
44399a0590aeSSteve Dickson 			 * Also, if the file was opened for write or
44409a0590aeSSteve Dickson 			 * create, there's a good chance the client's
44419a0590aeSSteve Dickson 			 * about to write to it, resulting in an
44429a0590aeSSteve Dickson 			 * immediate recall (since we don't support
44439a0590aeSSteve Dickson 			 * write delegations):
44449a0590aeSSteve Dickson 			 */
44451da177e4SLinus Torvalds 			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
444699c41515SJ. Bruce Fields 				goto out_no_deleg;
444799c41515SJ. Bruce Fields 			if (open->op_create == NFS4_OPEN_CREATE)
444899c41515SJ. Bruce Fields 				goto out_no_deleg;
44497b190fecSNeilBrown 			break;
44507b190fecSNeilBrown 		default:
445199c41515SJ. Bruce Fields 			goto out_no_deleg;
44527b190fecSNeilBrown 	}
44538287f009SSachin Bhamare 	dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
44540b26693cSJeff Layton 	if (IS_ERR(dp))
4455dd239cc0SJ. Bruce Fields 		goto out_no_deleg;
44561da177e4SLinus Torvalds 
4457d5477a8dSJ. Bruce Fields 	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
44581da177e4SLinus Torvalds 
44598c10cbdbSBenny Halevy 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
4460d5477a8dSJ. Bruce Fields 		STATEID_VAL(&dp->dl_stid.sc_stateid));
446199c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
446267cb1279STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
4463dd239cc0SJ. Bruce Fields 	return;
4464dd239cc0SJ. Bruce Fields out_no_deleg:
446599c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
44667b190fecSNeilBrown 	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
4467d08d32e6SJ. Bruce Fields 	    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
44681da177e4SLinus Torvalds 		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
4469d08d32e6SJ. Bruce Fields 		open->op_recall = 1;
4470d08d32e6SJ. Bruce Fields 	}
4471dd239cc0SJ. Bruce Fields 
4472dd239cc0SJ. Bruce Fields 	/* 4.1 client asking for a delegation? */
4473dd239cc0SJ. Bruce Fields 	if (open->op_deleg_want)
4474dd239cc0SJ. Bruce Fields 		nfsd4_open_deleg_none_ext(open, status);
4475dd239cc0SJ. Bruce Fields 	return;
44761da177e4SLinus Torvalds }
44771da177e4SLinus Torvalds 
4478e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
4479e27f49c3SBenny Halevy 					struct nfs4_delegation *dp)
4480e27f49c3SBenny Halevy {
4481e27f49c3SBenny Halevy 	if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
4482e27f49c3SBenny Halevy 	    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
4483e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4484e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
4485e27f49c3SBenny Halevy 	} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
4486e27f49c3SBenny Halevy 		   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
4487e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4488e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
4489e27f49c3SBenny Halevy 	}
4490e27f49c3SBenny Halevy 	/* Otherwise the client must be confused wanting a delegation
4491e27f49c3SBenny Halevy 	 * it already has, therefore we don't return
4492e27f49c3SBenny Halevy 	 * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
4493e27f49c3SBenny Halevy 	 */
4494e27f49c3SBenny Halevy }
4495e27f49c3SBenny Halevy 
4496b37ad28bSAl Viro __be32
44971da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
44981da177e4SLinus Torvalds {
44996668958fSAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
450038c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
45011da177e4SLinus Torvalds 	struct nfs4_file *fp = NULL;
4502dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
4503567d9829SNeilBrown 	struct nfs4_delegation *dp = NULL;
4504b37ad28bSAl Viro 	__be32 status;
45051da177e4SLinus Torvalds 
45061da177e4SLinus Torvalds 	/*
45071da177e4SLinus Torvalds 	 * Lookup file; if found, lookup stateid and check open request,
45081da177e4SLinus Torvalds 	 * and check for delegations in the process of being recalled.
45091da177e4SLinus Torvalds 	 * If not found, create the nfs4_file struct
45101da177e4SLinus Torvalds 	 */
4511f9c00c3aSJeff Layton 	fp = find_or_add_file(open->op_file, &current_fh->fh_handle);
4512950e0118STrond Myklebust 	if (fp != open->op_file) {
451341d22663SJ. Bruce Fields 		status = nfs4_check_deleg(cl, open, &dp);
4514c44c5eebSNeilBrown 		if (status)
4515c44c5eebSNeilBrown 			goto out;
451615ca08d3STrond Myklebust 		stp = nfsd4_find_and_lock_existing_open(fp, open);
45171da177e4SLinus Torvalds 	} else {
4518950e0118STrond Myklebust 		open->op_file = NULL;
4519c44c5eebSNeilBrown 		status = nfserr_bad_stateid;
45208b289b2cSJ. Bruce Fields 		if (nfsd4_is_deleg_cur(open))
4521c44c5eebSNeilBrown 			goto out;
45221da177e4SLinus Torvalds 	}
45231da177e4SLinus Torvalds 
45241da177e4SLinus Torvalds 	/*
45251da177e4SLinus Torvalds 	 * OPEN the file, or upgrade an existing OPEN.
45261da177e4SLinus Torvalds 	 * If truncate fails, the OPEN fails.
45271da177e4SLinus Torvalds 	 */
45281da177e4SLinus Torvalds 	if (stp) {
45291da177e4SLinus Torvalds 		/* Stateid was found, this is an OPEN upgrade */
4530f9d7562fSJ. Bruce Fields 		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
453135a92fe8SJeff Layton 		if (status) {
4532feb9dad5SOleg Drokin 			mutex_unlock(&stp->st_mutex);
45331da177e4SLinus Torvalds 			goto out;
453435a92fe8SJeff Layton 		}
45351da177e4SLinus Torvalds 	} else {
45368c7245abSOleg Drokin 		/* stp is returned locked. */
45378c7245abSOleg Drokin 		stp = init_open_stateid(fp, open);
45388c7245abSOleg Drokin 		/* See if we lost the race to some other thread */
45398c7245abSOleg Drokin 		if (stp->st_access_bmap != 0) {
45407fc0564eSAndrew Elble 			status = nfs4_upgrade_open(rqstp, fp, current_fh,
45417fc0564eSAndrew Elble 						stp, open);
45427fc0564eSAndrew Elble 			if (status) {
4543feb9dad5SOleg Drokin 				mutex_unlock(&stp->st_mutex);
45447fc0564eSAndrew Elble 				goto out;
45457fc0564eSAndrew Elble 			}
45467fc0564eSAndrew Elble 			goto upgrade_out;
45477fc0564eSAndrew Elble 		}
45486eb3a1d0SJeff Layton 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
45496eb3a1d0SJeff Layton 		if (status) {
4550feb9dad5SOleg Drokin 			mutex_unlock(&stp->st_mutex);
45516eb3a1d0SJeff Layton 			release_open_stateid(stp);
45526eb3a1d0SJeff Layton 			goto out;
45536eb3a1d0SJeff Layton 		}
45548287f009SSachin Bhamare 
45558287f009SSachin Bhamare 		stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp,
45568287f009SSachin Bhamare 							open->op_odstate);
45578287f009SSachin Bhamare 		if (stp->st_clnt_odstate == open->op_odstate)
45588287f009SSachin Bhamare 			open->op_odstate = NULL;
45591da177e4SLinus Torvalds 	}
45607fc0564eSAndrew Elble upgrade_out:
45619767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
4562feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
45631da177e4SLinus Torvalds 
4564d24433cdSBenny Halevy 	if (nfsd4_has_session(&resp->cstate)) {
4565d24433cdSBenny Halevy 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
4566d24433cdSBenny Halevy 			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4567d24433cdSBenny Halevy 			open->op_why_no_deleg = WND4_NOT_WANTED;
4568d24433cdSBenny Halevy 			goto nodeleg;
4569d24433cdSBenny Halevy 		}
4570d24433cdSBenny Halevy 	}
4571d24433cdSBenny Halevy 
45721da177e4SLinus Torvalds 	/*
45731da177e4SLinus Torvalds 	* Attempt to hand out a delegation. No error return, because the
45741da177e4SLinus Torvalds 	* OPEN succeeds even if we fail.
45751da177e4SLinus Torvalds 	*/
45764cf59221SJeff Layton 	nfs4_open_delegation(current_fh, open, stp);
4577d24433cdSBenny Halevy nodeleg:
45781da177e4SLinus Torvalds 	status = nfs_ok;
45791da177e4SLinus Torvalds 
45808c10cbdbSBenny Halevy 	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
4581dcef0413SJ. Bruce Fields 		STATEID_VAL(&stp->st_stid.sc_stateid));
45821da177e4SLinus Torvalds out:
4583d24433cdSBenny Halevy 	/* 4.1 client trying to upgrade/downgrade delegation? */
4584d24433cdSBenny Halevy 	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
4585e27f49c3SBenny Halevy 	    open->op_deleg_want)
4586e27f49c3SBenny Halevy 		nfsd4_deleg_xgrade_none_ext(open, dp);
4587d24433cdSBenny Halevy 
458813cd2184SNeilBrown 	if (fp)
458913cd2184SNeilBrown 		put_nfs4_file(fp);
459037515177SNeilBrown 	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
459187186022SKinglong Mee 		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
45921da177e4SLinus Torvalds 	/*
45931da177e4SLinus Torvalds 	* To finish the open response, we just need to set the rflags.
45941da177e4SLinus Torvalds 	*/
45951da177e4SLinus Torvalds 	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
459619e4c347SJeff Layton 	if (nfsd4_has_session(&resp->cstate))
459719e4c347SJeff Layton 		open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK;
459819e4c347SJeff Layton 	else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED))
45991da177e4SLinus Torvalds 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
460019e4c347SJeff Layton 
4601dcd94cc2STrond Myklebust 	if (dp)
4602dcd94cc2STrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
4603d6f2bc5dSTrond Myklebust 	if (stp)
4604d6f2bc5dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
46051da177e4SLinus Torvalds 
46061da177e4SLinus Torvalds 	return status;
46071da177e4SLinus Torvalds }
46081da177e4SLinus Torvalds 
460958fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
461042297899SJeff Layton 			      struct nfsd4_open *open)
4611d29b20cdSJ. Bruce Fields {
4612d29b20cdSJ. Bruce Fields 	if (open->op_openowner) {
4613d3134b10SJeff Layton 		struct nfs4_stateowner *so = &open->op_openowner->oo_owner;
4614d29b20cdSJ. Bruce Fields 
4615d3134b10SJeff Layton 		nfsd4_cstate_assign_replay(cstate, so);
4616d3134b10SJeff Layton 		nfs4_put_stateowner(so);
4617d29b20cdSJ. Bruce Fields 	}
461832513b40SJ. Bruce Fields 	if (open->op_file)
46195b095e99SJeff Layton 		kmem_cache_free(file_slab, open->op_file);
46204cdc951bSJ. Bruce Fields 	if (open->op_stp)
46216011695dSTrond Myklebust 		nfs4_put_stid(&open->op_stp->st_stid);
46228287f009SSachin Bhamare 	if (open->op_odstate)
46238287f009SSachin Bhamare 		kmem_cache_free(odstate_slab, open->op_odstate);
4624d29b20cdSJ. Bruce Fields }
4625d29b20cdSJ. Bruce Fields 
4626b37ad28bSAl Viro __be32
4627b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4628eb69853dSChristoph Hellwig 	    union nfsd4_op_u *u)
46291da177e4SLinus Torvalds {
4630eb69853dSChristoph Hellwig 	clientid_t *clid = &u->renew;
46311da177e4SLinus Torvalds 	struct nfs4_client *clp;
4632b37ad28bSAl Viro 	__be32 status;
46337f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
46341da177e4SLinus Torvalds 
46351da177e4SLinus Torvalds 	dprintk("process_renew(%08x/%08x): starting\n",
46361da177e4SLinus Torvalds 			clid->cl_boot, clid->cl_id);
46374b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
46389b2ef62bSJ. Bruce Fields 	if (status)
46391da177e4SLinus Torvalds 		goto out;
46404b24ca7dSJeff Layton 	clp = cstate->clp;
46411da177e4SLinus Torvalds 	status = nfserr_cb_path_down;
4642ea1da636SNeilBrown 	if (!list_empty(&clp->cl_delegations)
464377a3569dSJ. Bruce Fields 			&& clp->cl_cb_state != NFSD4_CB_UP)
46441da177e4SLinus Torvalds 		goto out;
46451da177e4SLinus Torvalds 	status = nfs_ok;
46461da177e4SLinus Torvalds out:
46471da177e4SLinus Torvalds 	return status;
46481da177e4SLinus Torvalds }
46491da177e4SLinus Torvalds 
46507f5ef2e9SJeff Layton void
465112760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn)
4652a76b4319SNeilBrown {
465333dcc481SJeff Layton 	/* do nothing if grace period already ended */
4654a51c84edSStanislav Kinsbursky 	if (nn->grace_ended)
465533dcc481SJeff Layton 		return;
465633dcc481SJeff Layton 
4657a76b4319SNeilBrown 	dprintk("NFSD: end of grace period\n");
4658a51c84edSStanislav Kinsbursky 	nn->grace_ended = true;
465970b28235SJ. Bruce Fields 	/*
466070b28235SJ. Bruce Fields 	 * If the server goes down again right now, an NFSv4
466170b28235SJ. Bruce Fields 	 * client will still be allowed to reclaim after it comes back up,
466270b28235SJ. Bruce Fields 	 * even if it hasn't yet had a chance to reclaim state this time.
466370b28235SJ. Bruce Fields 	 *
466470b28235SJ. Bruce Fields 	 */
4665919b8049SJeff Layton 	nfsd4_record_grace_done(nn);
466670b28235SJ. Bruce Fields 	/*
466770b28235SJ. Bruce Fields 	 * At this point, NFSv4 clients can still reclaim.  But if the
466870b28235SJ. Bruce Fields 	 * server crashes, any that have not yet reclaimed will be out
466970b28235SJ. Bruce Fields 	 * of luck on the next boot.
467070b28235SJ. Bruce Fields 	 *
467170b28235SJ. Bruce Fields 	 * (NFSv4.1+ clients are considered to have reclaimed once they
467270b28235SJ. Bruce Fields 	 * call RECLAIM_COMPLETE.  NFSv4.0 clients are considered to
467370b28235SJ. Bruce Fields 	 * have reclaimed after their first OPEN.)
467470b28235SJ. Bruce Fields 	 */
46755e1533c7SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
467670b28235SJ. Bruce Fields 	/*
467770b28235SJ. Bruce Fields 	 * At this point, and once lockd and/or any other containers
467870b28235SJ. Bruce Fields 	 * exit their grace period, further reclaims will fail and
467970b28235SJ. Bruce Fields 	 * regular locking can resume.
468070b28235SJ. Bruce Fields 	 */
4681a76b4319SNeilBrown }
4682a76b4319SNeilBrown 
4683fd39ca9aSNeilBrown static time_t
468409121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn)
46851da177e4SLinus Torvalds {
46861da177e4SLinus Torvalds 	struct nfs4_client *clp;
4687fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
46881da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
4689217526e7SJeff Layton 	struct nfs4_ol_stateid *stp;
46907919d0a2SJeff Layton 	struct nfsd4_blocked_lock *nbl;
46911da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
46923d733711SStanislav Kinsbursky 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
4693a832e7aeSJeff Layton 	time_t t, new_timeo = nn->nfsd4_lease;
46941da177e4SLinus Torvalds 
46951da177e4SLinus Torvalds 	dprintk("NFSD: laundromat service - starting\n");
469612760c66SStanislav Kinsbursky 	nfsd4_end_grace(nn);
469736acb66bSBenny Halevy 	INIT_LIST_HEAD(&reaplist);
4698c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
46995ed58bb2SStanislav Kinsbursky 	list_for_each_safe(pos, next, &nn->client_lru) {
47001da177e4SLinus Torvalds 		clp = list_entry(pos, struct nfs4_client, cl_lru);
47011da177e4SLinus Torvalds 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
47021da177e4SLinus Torvalds 			t = clp->cl_time - cutoff;
4703a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
47041da177e4SLinus Torvalds 			break;
47051da177e4SLinus Torvalds 		}
4706221a6876SJ. Bruce Fields 		if (mark_client_expired_locked(clp)) {
4707d7682988SBenny Halevy 			dprintk("NFSD: client in use (clientid %08x)\n",
4708d7682988SBenny Halevy 				clp->cl_clientid.cl_id);
4709d7682988SBenny Halevy 			continue;
4710d7682988SBenny Halevy 		}
47114864af97STrond Myklebust 		list_add(&clp->cl_lru, &reaplist);
471236acb66bSBenny Halevy 	}
4713c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
471436acb66bSBenny Halevy 	list_for_each_safe(pos, next, &reaplist) {
471536acb66bSBenny Halevy 		clp = list_entry(pos, struct nfs4_client, cl_lru);
47161da177e4SLinus Torvalds 		dprintk("NFSD: purging unused client (clientid %08x)\n",
47171da177e4SLinus Torvalds 			clp->cl_clientid.cl_id);
47184864af97STrond Myklebust 		list_del_init(&clp->cl_lru);
47191da177e4SLinus Torvalds 		expire_client(clp);
47201da177e4SLinus Torvalds 	}
4721cdc97505SBenny Halevy 	spin_lock(&state_lock);
4722e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
47231da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
47241da177e4SLinus Torvalds 		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
4725a832e7aeSJeff Layton 			t = dp->dl_time - cutoff;
4726a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
47271da177e4SLinus Torvalds 			break;
47281da177e4SLinus Torvalds 		}
47293fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
473042690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
47311da177e4SLinus Torvalds 	}
4732cdc97505SBenny Halevy 	spin_unlock(&state_lock);
47332d4a532dSJeff Layton 	while (!list_empty(&reaplist)) {
47342d4a532dSJeff Layton 		dp = list_first_entry(&reaplist, struct nfs4_delegation,
47352d4a532dSJeff Layton 					dl_recall_lru);
47362d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
47373bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
47381da177e4SLinus Torvalds 	}
4739217526e7SJeff Layton 
4740217526e7SJeff Layton 	spin_lock(&nn->client_lock);
4741217526e7SJeff Layton 	while (!list_empty(&nn->close_lru)) {
4742217526e7SJeff Layton 		oo = list_first_entry(&nn->close_lru, struct nfs4_openowner,
4743217526e7SJeff Layton 					oo_close_lru);
4744217526e7SJeff Layton 		if (time_after((unsigned long)oo->oo_time,
4745217526e7SJeff Layton 			       (unsigned long)cutoff)) {
4746a832e7aeSJeff Layton 			t = oo->oo_time - cutoff;
4747a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
47481da177e4SLinus Torvalds 			break;
47491da177e4SLinus Torvalds 		}
4750217526e7SJeff Layton 		list_del_init(&oo->oo_close_lru);
4751217526e7SJeff Layton 		stp = oo->oo_last_closed_stid;
4752217526e7SJeff Layton 		oo->oo_last_closed_stid = NULL;
4753217526e7SJeff Layton 		spin_unlock(&nn->client_lock);
4754217526e7SJeff Layton 		nfs4_put_stid(&stp->st_stid);
4755217526e7SJeff Layton 		spin_lock(&nn->client_lock);
47561da177e4SLinus Torvalds 	}
4757217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
4758217526e7SJeff Layton 
47597919d0a2SJeff Layton 	/*
47607919d0a2SJeff Layton 	 * It's possible for a client to try and acquire an already held lock
47617919d0a2SJeff Layton 	 * that is being held for a long time, and then lose interest in it.
47627919d0a2SJeff Layton 	 * So, we clean out any un-revisited request after a lease period
47637919d0a2SJeff Layton 	 * under the assumption that the client is no longer interested.
47647919d0a2SJeff Layton 	 *
47657919d0a2SJeff Layton 	 * RFC5661, sec. 9.6 states that the client must not rely on getting
47667919d0a2SJeff Layton 	 * notifications and must continue to poll for locks, even when the
47677919d0a2SJeff Layton 	 * server supports them. Thus this shouldn't lead to clients blocking
47687919d0a2SJeff Layton 	 * indefinitely once the lock does become free.
47697919d0a2SJeff Layton 	 */
47707919d0a2SJeff Layton 	BUG_ON(!list_empty(&reaplist));
47710cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
47727919d0a2SJeff Layton 	while (!list_empty(&nn->blocked_locks_lru)) {
47737919d0a2SJeff Layton 		nbl = list_first_entry(&nn->blocked_locks_lru,
47747919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
47757919d0a2SJeff Layton 		if (time_after((unsigned long)nbl->nbl_time,
47767919d0a2SJeff Layton 			       (unsigned long)cutoff)) {
47777919d0a2SJeff Layton 			t = nbl->nbl_time - cutoff;
47787919d0a2SJeff Layton 			new_timeo = min(new_timeo, t);
47797919d0a2SJeff Layton 			break;
47807919d0a2SJeff Layton 		}
47817919d0a2SJeff Layton 		list_move(&nbl->nbl_lru, &reaplist);
47827919d0a2SJeff Layton 		list_del_init(&nbl->nbl_list);
47837919d0a2SJeff Layton 	}
47840cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
47857919d0a2SJeff Layton 
47867919d0a2SJeff Layton 	while (!list_empty(&reaplist)) {
47877919d0a2SJeff Layton 		nbl = list_first_entry(&nn->blocked_locks_lru,
47887919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
47897919d0a2SJeff Layton 		list_del_init(&nbl->nbl_lru);
47907919d0a2SJeff Layton 		posix_unblock_lock(&nbl->nbl_lock);
47917919d0a2SJeff Layton 		free_blocked_lock(nbl);
47927919d0a2SJeff Layton 	}
47937919d0a2SJeff Layton 
4794a832e7aeSJeff Layton 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
4795a832e7aeSJeff Layton 	return new_timeo;
47961da177e4SLinus Torvalds }
47971da177e4SLinus Torvalds 
4798a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq;
4799a254b246SHarvey Harrison static void laundromat_main(struct work_struct *);
4800a254b246SHarvey Harrison 
4801a254b246SHarvey Harrison static void
480209121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry)
48031da177e4SLinus Torvalds {
48041da177e4SLinus Torvalds 	time_t t;
48052e55f3abSGeliang Tang 	struct delayed_work *dwork = to_delayed_work(laundry);
480609121281SStanislav Kinsbursky 	struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
480709121281SStanislav Kinsbursky 					   laundromat_work);
48081da177e4SLinus Torvalds 
480909121281SStanislav Kinsbursky 	t = nfs4_laundromat(nn);
48101da177e4SLinus Torvalds 	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
481109121281SStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
48121da177e4SLinus Torvalds }
48131da177e4SLinus Torvalds 
48148fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
4815f8816512SNeilBrown {
48168fcd461dSJeff Layton 	if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
4817f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
4818f7a4d872SJ. Bruce Fields 	return nfs_ok;
48191da177e4SLinus Torvalds }
48201da177e4SLinus Torvalds 
48211da177e4SLinus Torvalds static inline int
482282c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp)
48231da177e4SLinus Torvalds {
482482c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_READ, stp) ||
482582c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp) ||
482682c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_WRITE, stp);
48271da177e4SLinus Torvalds }
48281da177e4SLinus Torvalds 
48291da177e4SLinus Torvalds static inline int
483082c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp)
48311da177e4SLinus Torvalds {
483282c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_WRITE, stp) ||
483382c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp);
48341da177e4SLinus Torvalds }
48351da177e4SLinus Torvalds 
48361da177e4SLinus Torvalds static
4837dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
48381da177e4SLinus Torvalds {
4839b37ad28bSAl Viro         __be32 status = nfserr_openmode;
48401da177e4SLinus Torvalds 
484102921914SJ. Bruce Fields 	/* For lock stateid's, we test the parent open, not the lock: */
484202921914SJ. Bruce Fields 	if (stp->st_openstp)
484302921914SJ. Bruce Fields 		stp = stp->st_openstp;
484482c5ff1bSJeff Layton 	if ((flags & WR_STATE) && !access_permit_write(stp))
48451da177e4SLinus Torvalds                 goto out;
484682c5ff1bSJeff Layton 	if ((flags & RD_STATE) && !access_permit_read(stp))
48471da177e4SLinus Torvalds                 goto out;
48481da177e4SLinus Torvalds 	status = nfs_ok;
48491da177e4SLinus Torvalds out:
48501da177e4SLinus Torvalds 	return status;
48511da177e4SLinus Torvalds }
48521da177e4SLinus Torvalds 
4853b37ad28bSAl Viro static inline __be32
48545ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags)
48551da177e4SLinus Torvalds {
4856203a8c8eSJ. Bruce Fields 	if (ONE_STATEID(stateid) && (flags & RD_STATE))
48571da177e4SLinus Torvalds 		return nfs_ok;
4858c87fb4a3SJ. Bruce Fields 	else if (opens_in_grace(net)) {
485925985edcSLucas De Marchi 		/* Answer in remaining cases depends on existence of
48601da177e4SLinus Torvalds 		 * conflicting state; so we must wait out the grace period. */
48611da177e4SLinus Torvalds 		return nfserr_grace;
48621da177e4SLinus Torvalds 	} else if (flags & WR_STATE)
48631da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
48641da177e4SLinus Torvalds 				NFS4_SHARE_DENY_WRITE);
48651da177e4SLinus Torvalds 	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
48661da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
48671da177e4SLinus Torvalds 				NFS4_SHARE_DENY_READ);
48681da177e4SLinus Torvalds }
48691da177e4SLinus Torvalds 
48701da177e4SLinus Torvalds /*
48711da177e4SLinus Torvalds  * Allow READ/WRITE during grace period on recovered state only for files
48721da177e4SLinus Torvalds  * that are not able to provide mandatory locking.
48731da177e4SLinus Torvalds  */
48741da177e4SLinus Torvalds static inline int
48755ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode)
48761da177e4SLinus Torvalds {
4877c87fb4a3SJ. Bruce Fields 	return opens_in_grace(net) && mandatory_lock(inode);
48781da177e4SLinus Torvalds }
48791da177e4SLinus Torvalds 
488057b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
48810836f587SJ. Bruce Fields {
48826668958fSAndy Adamson 	/*
48836668958fSAndy Adamson 	 * When sessions are used the stateid generation number is ignored
48846668958fSAndy Adamson 	 * when it is zero.
48856668958fSAndy Adamson 	 */
488628dde241SJ. Bruce Fields 	if (has_session && in->si_generation == 0)
488781b82965SJ. Bruce Fields 		return nfs_ok;
488881b82965SJ. Bruce Fields 
488981b82965SJ. Bruce Fields 	if (in->si_generation == ref->si_generation)
489081b82965SJ. Bruce Fields 		return nfs_ok;
48916668958fSAndy Adamson 
48920836f587SJ. Bruce Fields 	/* If the client sends us a stateid from the future, it's buggy: */
489314b7f4a1SJeff Layton 	if (nfsd4_stateid_generation_after(in, ref))
48940836f587SJ. Bruce Fields 		return nfserr_bad_stateid;
48950836f587SJ. Bruce Fields 	/*
489681b82965SJ. Bruce Fields 	 * However, we could see a stateid from the past, even from a
489781b82965SJ. Bruce Fields 	 * non-buggy client.  For example, if the client sends a lock
489881b82965SJ. Bruce Fields 	 * while some IO is outstanding, the lock may bump si_generation
489981b82965SJ. Bruce Fields 	 * while the IO is still in flight.  The client could avoid that
490081b82965SJ. Bruce Fields 	 * situation by waiting for responses on all the IO requests,
490181b82965SJ. Bruce Fields 	 * but better performance may result in retrying IO that
490281b82965SJ. Bruce Fields 	 * receives an old_stateid error if requests are rarely
490381b82965SJ. Bruce Fields 	 * reordered in flight:
49040836f587SJ. Bruce Fields 	 */
49050836f587SJ. Bruce Fields 	return nfserr_old_stateid;
49060836f587SJ. Bruce Fields }
49070836f587SJ. Bruce Fields 
4908ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols)
4909ebe9cb3bSChristoph Hellwig {
4910ebe9cb3bSChristoph Hellwig 	if (ols->st_stateowner->so_is_open_owner &&
4911ebe9cb3bSChristoph Hellwig 	    !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
4912ebe9cb3bSChristoph Hellwig 		return nfserr_bad_stateid;
4913ebe9cb3bSChristoph Hellwig 	return nfs_ok;
4914ebe9cb3bSChristoph Hellwig }
4915ebe9cb3bSChristoph Hellwig 
49167df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
491717456804SBryan Schumaker {
491897b7e3b6SJ. Bruce Fields 	struct nfs4_stid *s;
49191af71cc8SJeff Layton 	__be32 status = nfserr_bad_stateid;
492017456804SBryan Schumaker 
49217df302f7SChuck Lever 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
49221af71cc8SJeff Layton 		return status;
49237df302f7SChuck Lever 	/* Client debugging aid. */
49247df302f7SChuck Lever 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
49257df302f7SChuck Lever 		char addr_str[INET6_ADDRSTRLEN];
49267df302f7SChuck Lever 		rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
49277df302f7SChuck Lever 				 sizeof(addr_str));
49287df302f7SChuck Lever 		pr_warn_ratelimited("NFSD: client %s testing state ID "
49297df302f7SChuck Lever 					"with incorrect client ID\n", addr_str);
49301af71cc8SJeff Layton 		return status;
49317df302f7SChuck Lever 	}
49321af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
49331af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
493497b7e3b6SJ. Bruce Fields 	if (!s)
49351af71cc8SJeff Layton 		goto out_unlock;
493636279ac1SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
493717456804SBryan Schumaker 	if (status)
49381af71cc8SJeff Layton 		goto out_unlock;
493923340032SJ. Bruce Fields 	switch (s->sc_type) {
494023340032SJ. Bruce Fields 	case NFS4_DELEG_STID:
49411af71cc8SJeff Layton 		status = nfs_ok;
49421af71cc8SJeff Layton 		break;
49433bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
49441af71cc8SJeff Layton 		status = nfserr_deleg_revoked;
49451af71cc8SJeff Layton 		break;
494623340032SJ. Bruce Fields 	case NFS4_OPEN_STID:
494723340032SJ. Bruce Fields 	case NFS4_LOCK_STID:
4948ebe9cb3bSChristoph Hellwig 		status = nfsd4_check_openowner_confirmed(openlockstateid(s));
49491af71cc8SJeff Layton 		break;
495023340032SJ. Bruce Fields 	default:
495123340032SJ. Bruce Fields 		printk("unknown stateid type %x\n", s->sc_type);
4952b0fc29d6STrond Myklebust 		/* Fallthrough */
495323340032SJ. Bruce Fields 	case NFS4_CLOSED_STID:
4954b0fc29d6STrond Myklebust 	case NFS4_CLOSED_DELEG_STID:
49551af71cc8SJeff Layton 		status = nfserr_bad_stateid;
495623340032SJ. Bruce Fields 	}
49571af71cc8SJeff Layton out_unlock:
49581af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
49591af71cc8SJeff Layton 	return status;
496017456804SBryan Schumaker }
496117456804SBryan Schumaker 
4962cd61c522SChristoph Hellwig __be32
49632dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
49642dd6e458STrond Myklebust 		     stateid_t *stateid, unsigned char typemask,
49652dd6e458STrond Myklebust 		     struct nfs4_stid **s, struct nfsd_net *nn)
496638c2f4b1SJ. Bruce Fields {
49670eb6f20aSJ. Bruce Fields 	__be32 status;
496895da1b3aSAndrew Elble 	bool return_revoked = false;
496995da1b3aSAndrew Elble 
497095da1b3aSAndrew Elble 	/*
497195da1b3aSAndrew Elble 	 *  only return revoked delegations if explicitly asked.
497295da1b3aSAndrew Elble 	 *  otherwise we report revoked or bad_stateid status.
497395da1b3aSAndrew Elble 	 */
497495da1b3aSAndrew Elble 	if (typemask & NFS4_REVOKED_DELEG_STID)
497595da1b3aSAndrew Elble 		return_revoked = true;
497695da1b3aSAndrew Elble 	else if (typemask & NFS4_DELEG_STID)
497795da1b3aSAndrew Elble 		typemask |= NFS4_REVOKED_DELEG_STID;
497838c2f4b1SJ. Bruce Fields 
497938c2f4b1SJ. Bruce Fields 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
498038c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
49814b24ca7dSJeff Layton 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
4982a8a7c677STrond Myklebust 	if (status == nfserr_stale_clientid) {
49834b24ca7dSJeff Layton 		if (cstate->session)
4984a8a7c677STrond Myklebust 			return nfserr_bad_stateid;
498538c2f4b1SJ. Bruce Fields 		return nfserr_stale_stateid;
4986a8a7c677STrond Myklebust 	}
49870eb6f20aSJ. Bruce Fields 	if (status)
49880eb6f20aSJ. Bruce Fields 		return status;
49894b24ca7dSJeff Layton 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
499038c2f4b1SJ. Bruce Fields 	if (!*s)
499138c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
499295da1b3aSAndrew Elble 	if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) {
499395da1b3aSAndrew Elble 		nfs4_put_stid(*s);
499495da1b3aSAndrew Elble 		if (cstate->minorversion)
499595da1b3aSAndrew Elble 			return nfserr_deleg_revoked;
499695da1b3aSAndrew Elble 		return nfserr_bad_stateid;
499795da1b3aSAndrew Elble 	}
499838c2f4b1SJ. Bruce Fields 	return nfs_ok;
499938c2f4b1SJ. Bruce Fields }
500038c2f4b1SJ. Bruce Fields 
5001a0649b2dSChristoph Hellwig static struct file *
5002a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags)
5003a0649b2dSChristoph Hellwig {
5004af90f707SChristoph Hellwig 	if (!s)
5005af90f707SChristoph Hellwig 		return NULL;
5006af90f707SChristoph Hellwig 
5007a0649b2dSChristoph Hellwig 	switch (s->sc_type) {
5008a0649b2dSChristoph Hellwig 	case NFS4_DELEG_STID:
5009a0649b2dSChristoph Hellwig 		if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file))
5010a0649b2dSChristoph Hellwig 			return NULL;
5011a0649b2dSChristoph Hellwig 		return get_file(s->sc_file->fi_deleg_file);
5012a0649b2dSChristoph Hellwig 	case NFS4_OPEN_STID:
5013a0649b2dSChristoph Hellwig 	case NFS4_LOCK_STID:
5014a0649b2dSChristoph Hellwig 		if (flags & RD_STATE)
5015a0649b2dSChristoph Hellwig 			return find_readable_file(s->sc_file);
5016a0649b2dSChristoph Hellwig 		else
5017a0649b2dSChristoph Hellwig 			return find_writeable_file(s->sc_file);
5018a0649b2dSChristoph Hellwig 		break;
5019a0649b2dSChristoph Hellwig 	}
5020a0649b2dSChristoph Hellwig 
5021a0649b2dSChristoph Hellwig 	return NULL;
5022a0649b2dSChristoph Hellwig }
5023a0649b2dSChristoph Hellwig 
5024a0649b2dSChristoph Hellwig static __be32
5025a0649b2dSChristoph Hellwig nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags)
5026a0649b2dSChristoph Hellwig {
5027a0649b2dSChristoph Hellwig 	__be32 status;
5028a0649b2dSChristoph Hellwig 
5029a0649b2dSChristoph Hellwig 	status = nfsd4_check_openowner_confirmed(ols);
5030a0649b2dSChristoph Hellwig 	if (status)
5031a0649b2dSChristoph Hellwig 		return status;
5032a0649b2dSChristoph Hellwig 	return nfs4_check_openmode(ols, flags);
5033a0649b2dSChristoph Hellwig }
5034a0649b2dSChristoph Hellwig 
5035af90f707SChristoph Hellwig static __be32
5036af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s,
5037af90f707SChristoph Hellwig 		struct file **filpp, bool *tmp_file, int flags)
5038af90f707SChristoph Hellwig {
5039af90f707SChristoph Hellwig 	int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE;
5040af90f707SChristoph Hellwig 	struct file *file;
5041af90f707SChristoph Hellwig 	__be32 status;
5042af90f707SChristoph Hellwig 
5043af90f707SChristoph Hellwig 	file = nfs4_find_file(s, flags);
5044af90f707SChristoph Hellwig 	if (file) {
5045af90f707SChristoph Hellwig 		status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
5046af90f707SChristoph Hellwig 				acc | NFSD_MAY_OWNER_OVERRIDE);
5047af90f707SChristoph Hellwig 		if (status) {
5048af90f707SChristoph Hellwig 			fput(file);
5049af90f707SChristoph Hellwig 			return status;
5050af90f707SChristoph Hellwig 		}
5051af90f707SChristoph Hellwig 
5052af90f707SChristoph Hellwig 		*filpp = file;
5053af90f707SChristoph Hellwig 	} else {
5054af90f707SChristoph Hellwig 		status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp);
5055af90f707SChristoph Hellwig 		if (status)
5056af90f707SChristoph Hellwig 			return status;
5057af90f707SChristoph Hellwig 
5058af90f707SChristoph Hellwig 		if (tmp_file)
5059af90f707SChristoph Hellwig 			*tmp_file = true;
5060af90f707SChristoph Hellwig 	}
5061af90f707SChristoph Hellwig 
5062af90f707SChristoph Hellwig 	return 0;
5063af90f707SChristoph Hellwig }
5064af90f707SChristoph Hellwig 
50651da177e4SLinus Torvalds /*
50661da177e4SLinus Torvalds  * Checks for stateid operations
50671da177e4SLinus Torvalds  */
5068b37ad28bSAl Viro __be32
5069af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
5070aa0d6aedSAnna Schumaker 		struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
5071aa0d6aedSAnna Schumaker 		stateid_t *stateid, int flags, struct file **filpp, bool *tmp_file)
50721da177e4SLinus Torvalds {
5073a0649b2dSChristoph Hellwig 	struct inode *ino = d_inode(fhp->fh_dentry);
5074af90f707SChristoph Hellwig 	struct net *net = SVC_NET(rqstp);
50753320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
5076af90f707SChristoph Hellwig 	struct nfs4_stid *s = NULL;
5077b37ad28bSAl Viro 	__be32 status;
50781da177e4SLinus Torvalds 
50791da177e4SLinus Torvalds 	if (filpp)
50801da177e4SLinus Torvalds 		*filpp = NULL;
5081af90f707SChristoph Hellwig 	if (tmp_file)
5082af90f707SChristoph Hellwig 		*tmp_file = false;
50831da177e4SLinus Torvalds 
50845ccb0066SStanislav Kinsbursky 	if (grace_disallows_io(net, ino))
50851da177e4SLinus Torvalds 		return nfserr_grace;
50861da177e4SLinus Torvalds 
5087af90f707SChristoph Hellwig 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
5088af90f707SChristoph Hellwig 		status = check_special_stateids(net, fhp, stateid, flags);
5089af90f707SChristoph Hellwig 		goto done;
5090af90f707SChristoph Hellwig 	}
50911da177e4SLinus Torvalds 
50922dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid,
5093db24b3b4SJeff Layton 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
50942dd6e458STrond Myklebust 				&s, nn);
509538c2f4b1SJ. Bruce Fields 	if (status)
5096c2d1d6a8STrond Myklebust 		return status;
5097a0649b2dSChristoph Hellwig 	status = check_stateid_generation(stateid, &s->sc_stateid,
5098a0649b2dSChristoph Hellwig 			nfsd4_has_session(cstate));
50990c2a498fSJ. Bruce Fields 	if (status)
51000c2a498fSJ. Bruce Fields 		goto out;
5101a0649b2dSChristoph Hellwig 
5102f7a4d872SJ. Bruce Fields 	switch (s->sc_type) {
5103f7a4d872SJ. Bruce Fields 	case NFS4_DELEG_STID:
5104a0649b2dSChristoph Hellwig 		status = nfs4_check_delegmode(delegstateid(s), flags);
5105f7a4d872SJ. Bruce Fields 		break;
5106f7a4d872SJ. Bruce Fields 	case NFS4_OPEN_STID:
5107f7a4d872SJ. Bruce Fields 	case NFS4_LOCK_STID:
5108a0649b2dSChristoph Hellwig 		status = nfs4_check_olstateid(fhp, openlockstateid(s), flags);
5109f7a4d872SJ. Bruce Fields 		break;
5110f7a4d872SJ. Bruce Fields 	default:
511114bcab1aSTrond Myklebust 		status = nfserr_bad_stateid;
5112a0649b2dSChristoph Hellwig 		break;
51131da177e4SLinus Torvalds 	}
51148fcd461dSJeff Layton 	if (status)
51158fcd461dSJeff Layton 		goto out;
51168fcd461dSJeff Layton 	status = nfs4_check_fh(fhp, s);
5117a0649b2dSChristoph Hellwig 
5118af90f707SChristoph Hellwig done:
5119af90f707SChristoph Hellwig 	if (!status && filpp)
5120af90f707SChristoph Hellwig 		status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags);
51211da177e4SLinus Torvalds out:
5122af90f707SChristoph Hellwig 	if (s)
5123fd911011STrond Myklebust 		nfs4_put_stid(s);
51241da177e4SLinus Torvalds 	return status;
51251da177e4SLinus Torvalds }
51261da177e4SLinus Torvalds 
5127e1ca12dfSBryan Schumaker /*
512817456804SBryan Schumaker  * Test if the stateid is valid
512917456804SBryan Schumaker  */
513017456804SBryan Schumaker __be32
513117456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5132eb69853dSChristoph Hellwig 		   union nfsd4_op_u *u)
513317456804SBryan Schumaker {
5134eb69853dSChristoph Hellwig 	struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
513503cfb420SBryan Schumaker 	struct nfsd4_test_stateid_id *stateid;
513603cfb420SBryan Schumaker 	struct nfs4_client *cl = cstate->session->se_client;
513703cfb420SBryan Schumaker 
513803cfb420SBryan Schumaker 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
51397df302f7SChuck Lever 		stateid->ts_id_status =
51407df302f7SChuck Lever 			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
514103cfb420SBryan Schumaker 
514217456804SBryan Schumaker 	return nfs_ok;
514317456804SBryan Schumaker }
514417456804SBryan Schumaker 
514542691398SChuck Lever static __be32
514642691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
514742691398SChuck Lever {
514842691398SChuck Lever 	struct nfs4_ol_stateid *stp = openlockstateid(s);
514942691398SChuck Lever 	__be32 ret;
515042691398SChuck Lever 
515142691398SChuck Lever 	mutex_lock(&stp->st_mutex);
515242691398SChuck Lever 
515342691398SChuck Lever 	ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
515442691398SChuck Lever 	if (ret)
515542691398SChuck Lever 		goto out;
515642691398SChuck Lever 
515742691398SChuck Lever 	ret = nfserr_locks_held;
515842691398SChuck Lever 	if (check_for_locks(stp->st_stid.sc_file,
515942691398SChuck Lever 			    lockowner(stp->st_stateowner)))
516042691398SChuck Lever 		goto out;
516142691398SChuck Lever 
516242691398SChuck Lever 	release_lock_stateid(stp);
516342691398SChuck Lever 	ret = nfs_ok;
516442691398SChuck Lever 
516542691398SChuck Lever out:
516642691398SChuck Lever 	mutex_unlock(&stp->st_mutex);
516742691398SChuck Lever 	nfs4_put_stid(s);
516842691398SChuck Lever 	return ret;
516942691398SChuck Lever }
517042691398SChuck Lever 
5171e1ca12dfSBryan Schumaker __be32
5172e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5173eb69853dSChristoph Hellwig 		   union nfsd4_op_u *u)
5174e1ca12dfSBryan Schumaker {
5175eb69853dSChristoph Hellwig 	struct nfsd4_free_stateid *free_stateid = &u->free_stateid;
5176e1ca12dfSBryan Schumaker 	stateid_t *stateid = &free_stateid->fr_stateid;
51772da1cec7SJ. Bruce Fields 	struct nfs4_stid *s;
51783bd64a5bSJ. Bruce Fields 	struct nfs4_delegation *dp;
517938c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = cstate->session->se_client;
51802da1cec7SJ. Bruce Fields 	__be32 ret = nfserr_bad_stateid;
5181e1ca12dfSBryan Schumaker 
51821af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
51831af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
51842da1cec7SJ. Bruce Fields 	if (!s)
51851af71cc8SJeff Layton 		goto out_unlock;
51862da1cec7SJ. Bruce Fields 	switch (s->sc_type) {
51872da1cec7SJ. Bruce Fields 	case NFS4_DELEG_STID:
5188e1ca12dfSBryan Schumaker 		ret = nfserr_locks_held;
51891af71cc8SJeff Layton 		break;
51902da1cec7SJ. Bruce Fields 	case NFS4_OPEN_STID:
51911af71cc8SJeff Layton 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
51921af71cc8SJeff Layton 		if (ret)
51931af71cc8SJeff Layton 			break;
51941af71cc8SJeff Layton 		ret = nfserr_locks_held;
51951af71cc8SJeff Layton 		break;
51962da1cec7SJ. Bruce Fields 	case NFS4_LOCK_STID:
5197a15dfcd5SElena Reshetova 		refcount_inc(&s->sc_count);
51981af71cc8SJeff Layton 		spin_unlock(&cl->cl_lock);
519942691398SChuck Lever 		ret = nfsd4_free_lock_stateid(stateid, s);
52001af71cc8SJeff Layton 		goto out;
52013bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
52023bd64a5bSJ. Bruce Fields 		dp = delegstateid(s);
52032d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
52042d4a532dSJeff Layton 		spin_unlock(&cl->cl_lock);
52056011695dSTrond Myklebust 		nfs4_put_stid(s);
52063bd64a5bSJ. Bruce Fields 		ret = nfs_ok;
52071af71cc8SJeff Layton 		goto out;
52081af71cc8SJeff Layton 	/* Default falls through and returns nfserr_bad_stateid */
5209e1ca12dfSBryan Schumaker 	}
52101af71cc8SJeff Layton out_unlock:
52111af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
5212e1ca12dfSBryan Schumaker out:
5213e1ca12dfSBryan Schumaker 	return ret;
5214e1ca12dfSBryan Schumaker }
5215e1ca12dfSBryan Schumaker 
52164c4cd222SNeilBrown static inline int
52174c4cd222SNeilBrown setlkflg (int type)
52184c4cd222SNeilBrown {
52194c4cd222SNeilBrown 	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
52204c4cd222SNeilBrown 		RD_STATE : WR_STATE;
52214c4cd222SNeilBrown }
52221da177e4SLinus Torvalds 
5223dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
5224c0a5d93eSJ. Bruce Fields {
5225c0a5d93eSJ. Bruce Fields 	struct svc_fh *current_fh = &cstate->current_fh;
5226c0a5d93eSJ. Bruce Fields 	struct nfs4_stateowner *sop = stp->st_stateowner;
5227c0a5d93eSJ. Bruce Fields 	__be32 status;
5228c0a5d93eSJ. Bruce Fields 
5229c0a5d93eSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, sop, seqid);
5230c0a5d93eSJ. Bruce Fields 	if (status)
5231c0a5d93eSJ. Bruce Fields 		return status;
52323bd64a5bSJ. Bruce Fields 	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
52333bd64a5bSJ. Bruce Fields 		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
5234f7a4d872SJ. Bruce Fields 		/*
5235f7a4d872SJ. Bruce Fields 		 * "Closed" stateid's exist *only* to return
52363bd64a5bSJ. Bruce Fields 		 * nfserr_replay_me from the previous step, and
52373bd64a5bSJ. Bruce Fields 		 * revoked delegations are kept only for free_stateid.
5238f7a4d872SJ. Bruce Fields 		 */
5239f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
5240feb9dad5SOleg Drokin 	mutex_lock(&stp->st_mutex);
5241f7a4d872SJ. Bruce Fields 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
524235a92fe8SJeff Layton 	if (status == nfs_ok)
524335a92fe8SJeff Layton 		status = nfs4_check_fh(current_fh, &stp->st_stid);
524435a92fe8SJeff Layton 	if (status != nfs_ok)
5245feb9dad5SOleg Drokin 		mutex_unlock(&stp->st_mutex);
5246f7a4d872SJ. Bruce Fields 	return status;
5247c0a5d93eSJ. Bruce Fields }
5248c0a5d93eSJ. Bruce Fields 
52491da177e4SLinus Torvalds /*
52501da177e4SLinus Torvalds  * Checks for sequence id mutating operations.
52511da177e4SLinus Torvalds  */
5252b37ad28bSAl Viro static __be32
5253dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
52542288d0e3SJ. Bruce Fields 			 stateid_t *stateid, char typemask,
52553320fef1SStanislav Kinsbursky 			 struct nfs4_ol_stateid **stpp,
52563320fef1SStanislav Kinsbursky 			 struct nfsd_net *nn)
52571da177e4SLinus Torvalds {
52580836f587SJ. Bruce Fields 	__be32 status;
525938c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
5260e17f99b7STrond Myklebust 	struct nfs4_ol_stateid *stp = NULL;
52611da177e4SLinus Torvalds 
52628c10cbdbSBenny Halevy 	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
52638c10cbdbSBenny Halevy 		seqid, STATEID_VAL(stateid));
52641da177e4SLinus Torvalds 
52651da177e4SLinus Torvalds 	*stpp = NULL;
52662dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn);
5267c0a5d93eSJ. Bruce Fields 	if (status)
5268c0a5d93eSJ. Bruce Fields 		return status;
5269e17f99b7STrond Myklebust 	stp = openlockstateid(s);
527058fb12e6SJeff Layton 	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
52711da177e4SLinus Torvalds 
5272e17f99b7STrond Myklebust 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
5273fd911011STrond Myklebust 	if (!status)
5274e17f99b7STrond Myklebust 		*stpp = stp;
5275fd911011STrond Myklebust 	else
5276fd911011STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
5277e17f99b7STrond Myklebust 	return status;
52781da177e4SLinus Torvalds }
52791da177e4SLinus Torvalds 
52803320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
52813320fef1SStanislav Kinsbursky 						 stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn)
5282c0a5d93eSJ. Bruce Fields {
5283c0a5d93eSJ. Bruce Fields 	__be32 status;
5284c0a5d93eSJ. Bruce Fields 	struct nfs4_openowner *oo;
52854cbfc9f7STrond Myklebust 	struct nfs4_ol_stateid *stp;
52861da177e4SLinus Torvalds 
5287c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
52884cbfc9f7STrond Myklebust 						NFS4_OPEN_STID, &stp, nn);
52890836f587SJ. Bruce Fields 	if (status)
52900836f587SJ. Bruce Fields 		return status;
52914cbfc9f7STrond Myklebust 	oo = openowner(stp->st_stateowner);
52924cbfc9f7STrond Myklebust 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
5293feb9dad5SOleg Drokin 		mutex_unlock(&stp->st_mutex);
52944cbfc9f7STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
5295c0a5d93eSJ. Bruce Fields 		return nfserr_bad_stateid;
52964cbfc9f7STrond Myklebust 	}
52974cbfc9f7STrond Myklebust 	*stpp = stp;
52983a4f98bbSNeilBrown 	return nfs_ok;
52991da177e4SLinus Torvalds }
53001da177e4SLinus Torvalds 
5301b37ad28bSAl Viro __be32
5302ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5303eb69853dSChristoph Hellwig 		   union nfsd4_op_u *u)
53041da177e4SLinus Torvalds {
5305eb69853dSChristoph Hellwig 	struct nfsd4_open_confirm *oc = &u->open_confirm;
5306b37ad28bSAl Viro 	__be32 status;
5307fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
5308dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
53093320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
53101da177e4SLinus Torvalds 
5311a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_confirm on file %pd\n",
5312a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
53131da177e4SLinus Torvalds 
5314ca364317SJ.Bruce Fields 	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
5315a8cddc5dSJ. Bruce Fields 	if (status)
5316a8cddc5dSJ. Bruce Fields 		return status;
53171da177e4SLinus Torvalds 
53189072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate,
5319ca364317SJ.Bruce Fields 					oc->oc_seqid, &oc->oc_req_stateid,
53203320fef1SStanislav Kinsbursky 					NFS4_OPEN_STID, &stp, nn);
53219072d5c6SJ. Bruce Fields 	if (status)
53221da177e4SLinus Torvalds 		goto out;
5323fe0750e5SJ. Bruce Fields 	oo = openowner(stp->st_stateowner);
532468b66e82SJ. Bruce Fields 	status = nfserr_bad_stateid;
532535a92fe8SJeff Layton 	if (oo->oo_flags & NFS4_OO_CONFIRMED) {
5326feb9dad5SOleg Drokin 		mutex_unlock(&stp->st_mutex);
53272585fc79STrond Myklebust 		goto put_stateid;
532835a92fe8SJeff Layton 	}
5329dad1c067SJ. Bruce Fields 	oo->oo_flags |= NFS4_OO_CONFIRMED;
53309767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid);
5331feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
53328c10cbdbSBenny Halevy 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
5333dcef0413SJ. Bruce Fields 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
5334c7b9a459SNeilBrown 
53352a4317c5SJeff Layton 	nfsd4_client_record_create(oo->oo_owner.so_client);
533668b66e82SJ. Bruce Fields 	status = nfs_ok;
53372585fc79STrond Myklebust put_stateid:
53382585fc79STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
53391da177e4SLinus Torvalds out:
53409411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
53411da177e4SLinus Torvalds 	return status;
53421da177e4SLinus Torvalds }
53431da177e4SLinus Torvalds 
53446409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
53451da177e4SLinus Torvalds {
534682c5ff1bSJeff Layton 	if (!test_access(access, stp))
53476409a5a6SJ. Bruce Fields 		return;
534811b9164aSTrond Myklebust 	nfs4_file_put_access(stp->st_stid.sc_file, access);
534982c5ff1bSJeff Layton 	clear_access(access, stp);
5350f197c271SJ. Bruce Fields }
53516409a5a6SJ. Bruce Fields 
53526409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
53536409a5a6SJ. Bruce Fields {
53546409a5a6SJ. Bruce Fields 	switch (to_access) {
53556409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
53566409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
53576409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
53586409a5a6SJ. Bruce Fields 		break;
53596409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
53606409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
53616409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
53626409a5a6SJ. Bruce Fields 		break;
53636409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
53646409a5a6SJ. Bruce Fields 		break;
53656409a5a6SJ. Bruce Fields 	default:
5366063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
53671da177e4SLinus Torvalds 	}
53681da177e4SLinus Torvalds }
53691da177e4SLinus Torvalds 
5370b37ad28bSAl Viro __be32
5371ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp,
5372eb69853dSChristoph Hellwig 		     struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
53731da177e4SLinus Torvalds {
5374eb69853dSChristoph Hellwig 	struct nfsd4_open_downgrade *od = &u->open_downgrade;
5375b37ad28bSAl Viro 	__be32 status;
5376dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
53773320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
53781da177e4SLinus Torvalds 
5379a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_downgrade on file %pd\n",
5380a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
53811da177e4SLinus Torvalds 
5382c30e92dfSJ. Bruce Fields 	/* We don't yet support WANT bits: */
53832c8bd7e0SBenny Halevy 	if (od->od_deleg_want)
53842c8bd7e0SBenny Halevy 		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
53852c8bd7e0SBenny Halevy 			od->od_deleg_want);
53861da177e4SLinus Torvalds 
5387c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
53883320fef1SStanislav Kinsbursky 					&od->od_stateid, &stp, nn);
53899072d5c6SJ. Bruce Fields 	if (status)
53901da177e4SLinus Torvalds 		goto out;
53911da177e4SLinus Torvalds 	status = nfserr_inval;
539282c5ff1bSJeff Layton 	if (!test_access(od->od_share_access, stp)) {
5393c11c591fSJeff Layton 		dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n",
53941da177e4SLinus Torvalds 			stp->st_access_bmap, od->od_share_access);
53950667b1e9STrond Myklebust 		goto put_stateid;
53961da177e4SLinus Torvalds 	}
5397ce0fc43cSJeff Layton 	if (!test_deny(od->od_share_deny, stp)) {
5398c11c591fSJeff Layton 		dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n",
53991da177e4SLinus Torvalds 			stp->st_deny_bmap, od->od_share_deny);
54000667b1e9STrond Myklebust 		goto put_stateid;
54011da177e4SLinus Torvalds 	}
54026409a5a6SJ. Bruce Fields 	nfs4_stateid_downgrade(stp, od->od_share_access);
5403ce0fc43cSJeff Layton 	reset_union_bmap_deny(od->od_share_deny, stp);
54049767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid);
54051da177e4SLinus Torvalds 	status = nfs_ok;
54060667b1e9STrond Myklebust put_stateid:
5407feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
54080667b1e9STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
54091da177e4SLinus Torvalds out:
54109411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
54111da177e4SLinus Torvalds 	return status;
54121da177e4SLinus Torvalds }
54131da177e4SLinus Torvalds 
5414f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
5415f7a4d872SJ. Bruce Fields {
5416acf9295bSTrond Myklebust 	struct nfs4_client *clp = s->st_stid.sc_client;
5417e8568739SJeff Layton 	bool unhashed;
5418d83017f9SJeff Layton 	LIST_HEAD(reaplist);
5419acf9295bSTrond Myklebust 
54202c41beb0SJeff Layton 	spin_lock(&clp->cl_lock);
5421e8568739SJeff Layton 	unhashed = unhash_open_stateid(s, &reaplist);
5422acf9295bSTrond Myklebust 
5423d83017f9SJeff Layton 	if (clp->cl_minorversion) {
5424e8568739SJeff Layton 		if (unhashed)
5425d83017f9SJeff Layton 			put_ol_stateid_locked(s, &reaplist);
5426d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
5427d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
5428d83017f9SJeff Layton 	} else {
5429d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
5430d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
5431e8568739SJeff Layton 		if (unhashed)
5432d3134b10SJeff Layton 			move_to_close_lru(s, clp->net);
543338c387b5SJ. Bruce Fields 	}
5434d83017f9SJeff Layton }
543538c387b5SJ. Bruce Fields 
54361da177e4SLinus Torvalds /*
54371da177e4SLinus Torvalds  * nfs4_unlock_state() called after encode
54381da177e4SLinus Torvalds  */
5439b37ad28bSAl Viro __be32
5440ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5441eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
54421da177e4SLinus Torvalds {
5443eb69853dSChristoph Hellwig 	struct nfsd4_close *close = &u->close;
5444b37ad28bSAl Viro 	__be32 status;
5445dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
54463320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
54473320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
54481da177e4SLinus Torvalds 
5449a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_close on file %pd\n",
5450a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
54511da177e4SLinus Torvalds 
5452f7a4d872SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
5453f7a4d872SJ. Bruce Fields 					&close->cl_stateid,
5454f7a4d872SJ. Bruce Fields 					NFS4_OPEN_STID|NFS4_CLOSED_STID,
54553320fef1SStanislav Kinsbursky 					&stp, nn);
54569411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
54579072d5c6SJ. Bruce Fields 	if (status)
54581da177e4SLinus Torvalds 		goto out;
545915ca08d3STrond Myklebust 
546015ca08d3STrond Myklebust 	stp->st_stid.sc_type = NFS4_CLOSED_STID;
54619767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
54621da177e4SLinus Torvalds 
5463f7a4d872SJ. Bruce Fields 	nfsd4_close_open_stateid(stp);
546415ca08d3STrond Myklebust 	mutex_unlock(&stp->st_mutex);
54658a0b589dSTrond Myklebust 
54668a0b589dSTrond Myklebust 	/* put reference from nfs4_preprocess_seqid_op */
54678a0b589dSTrond Myklebust 	nfs4_put_stid(&stp->st_stid);
54681da177e4SLinus Torvalds out:
54691da177e4SLinus Torvalds 	return status;
54701da177e4SLinus Torvalds }
54711da177e4SLinus Torvalds 
5472b37ad28bSAl Viro __be32
5473ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5474eb69853dSChristoph Hellwig 		  union nfsd4_op_u *u)
54751da177e4SLinus Torvalds {
5476eb69853dSChristoph Hellwig 	struct nfsd4_delegreturn *dr = &u->delegreturn;
5477203a8c8eSJ. Bruce Fields 	struct nfs4_delegation *dp;
5478203a8c8eSJ. Bruce Fields 	stateid_t *stateid = &dr->dr_stateid;
547938c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
5480b37ad28bSAl Viro 	__be32 status;
54813320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
54821da177e4SLinus Torvalds 
5483ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
5484203a8c8eSJ. Bruce Fields 		return status;
54851da177e4SLinus Torvalds 
54862dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
548738c2f4b1SJ. Bruce Fields 	if (status)
5488203a8c8eSJ. Bruce Fields 		goto out;
548938c2f4b1SJ. Bruce Fields 	dp = delegstateid(s);
5490d5477a8dSJ. Bruce Fields 	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
5491203a8c8eSJ. Bruce Fields 	if (status)
5492fd911011STrond Myklebust 		goto put_stateid;
5493203a8c8eSJ. Bruce Fields 
54943bd64a5bSJ. Bruce Fields 	destroy_delegation(dp);
5495fd911011STrond Myklebust put_stateid:
5496fd911011STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
54971da177e4SLinus Torvalds out:
54981da177e4SLinus Torvalds 	return status;
54991da177e4SLinus Torvalds }
55001da177e4SLinus Torvalds 
550187df4de8SBenny Halevy static inline u64
550287df4de8SBenny Halevy end_offset(u64 start, u64 len)
550387df4de8SBenny Halevy {
550487df4de8SBenny Halevy 	u64 end;
550587df4de8SBenny Halevy 
550687df4de8SBenny Halevy 	end = start + len;
550787df4de8SBenny Halevy 	return end >= start ? end: NFS4_MAX_UINT64;
550887df4de8SBenny Halevy }
550987df4de8SBenny Halevy 
551087df4de8SBenny Halevy /* last octet in a range */
551187df4de8SBenny Halevy static inline u64
551287df4de8SBenny Halevy last_byte_offset(u64 start, u64 len)
551387df4de8SBenny Halevy {
551487df4de8SBenny Halevy 	u64 end;
551587df4de8SBenny Halevy 
5516063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(!len);
551787df4de8SBenny Halevy 	end = start + len;
551887df4de8SBenny Halevy 	return end > start ? end - 1: NFS4_MAX_UINT64;
551987df4de8SBenny Halevy }
552087df4de8SBenny Halevy 
55211da177e4SLinus Torvalds /*
55221da177e4SLinus Torvalds  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
55231da177e4SLinus Torvalds  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
55241da177e4SLinus Torvalds  * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
55251da177e4SLinus Torvalds  * locking, this prevents us from being completely protocol-compliant.  The
55261da177e4SLinus Torvalds  * real solution to this problem is to start using unsigned file offsets in
55271da177e4SLinus Torvalds  * the VFS, but this is a very deep change!
55281da177e4SLinus Torvalds  */
55291da177e4SLinus Torvalds static inline void
55301da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock)
55311da177e4SLinus Torvalds {
55321da177e4SLinus Torvalds 	if (lock->fl_start < 0)
55331da177e4SLinus Torvalds 		lock->fl_start = OFFSET_MAX;
55341da177e4SLinus Torvalds 	if (lock->fl_end < 0)
55351da177e4SLinus Torvalds 		lock->fl_end = OFFSET_MAX;
55361da177e4SLinus Torvalds }
55371da177e4SLinus Torvalds 
5538cae80b30SJeff Layton static fl_owner_t
5539cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner)
5540aef9583bSKinglong Mee {
5541cae80b30SJeff Layton 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
5542cae80b30SJeff Layton 
5543cae80b30SJeff Layton 	nfs4_get_stateowner(&lo->lo_owner);
5544cae80b30SJeff Layton 	return owner;
5545aef9583bSKinglong Mee }
5546aef9583bSKinglong Mee 
5547cae80b30SJeff Layton static void
5548cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner)
5549aef9583bSKinglong Mee {
5550cae80b30SJeff Layton 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
5551aef9583bSKinglong Mee 
5552cae80b30SJeff Layton 	if (lo)
5553aef9583bSKinglong Mee 		nfs4_put_stateowner(&lo->lo_owner);
5554aef9583bSKinglong Mee }
5555aef9583bSKinglong Mee 
555676d348faSJeff Layton static void
555776d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl)
555876d348faSJeff Layton {
555976d348faSJeff Layton 	struct nfs4_lockowner		*lo = (struct nfs4_lockowner *)fl->fl_owner;
556076d348faSJeff Layton 	struct net			*net = lo->lo_owner.so_client->net;
556176d348faSJeff Layton 	struct nfsd_net			*nn = net_generic(net, nfsd_net_id);
556276d348faSJeff Layton 	struct nfsd4_blocked_lock	*nbl = container_of(fl,
556376d348faSJeff Layton 						struct nfsd4_blocked_lock, nbl_lock);
556476d348faSJeff Layton 	bool queue = false;
556576d348faSJeff Layton 
55667919d0a2SJeff Layton 	/* An empty list means that something else is going to be using it */
55670cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
556876d348faSJeff Layton 	if (!list_empty(&nbl->nbl_list)) {
556976d348faSJeff Layton 		list_del_init(&nbl->nbl_list);
55707919d0a2SJeff Layton 		list_del_init(&nbl->nbl_lru);
557176d348faSJeff Layton 		queue = true;
557276d348faSJeff Layton 	}
55730cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
557476d348faSJeff Layton 
557576d348faSJeff Layton 	if (queue)
557676d348faSJeff Layton 		nfsd4_run_cb(&nbl->nbl_cb);
557776d348faSJeff Layton }
557876d348faSJeff Layton 
55797b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops  = {
558076d348faSJeff Layton 	.lm_notify = nfsd4_lm_notify,
5581aef9583bSKinglong Mee 	.lm_get_owner = nfsd4_fl_get_owner,
5582aef9583bSKinglong Mee 	.lm_put_owner = nfsd4_fl_put_owner,
5583d5b9026aSNeilBrown };
55841da177e4SLinus Torvalds 
55851da177e4SLinus Torvalds static inline void
55861da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
55871da177e4SLinus Torvalds {
5588fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
55891da177e4SLinus Torvalds 
5590d5b9026aSNeilBrown 	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
5591fe0750e5SJ. Bruce Fields 		lo = (struct nfs4_lockowner *) fl->fl_owner;
5592fe0750e5SJ. Bruce Fields 		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
5593fe0750e5SJ. Bruce Fields 					lo->lo_owner.so_owner.len, GFP_KERNEL);
55947c13f344SJ. Bruce Fields 		if (!deny->ld_owner.data)
55957c13f344SJ. Bruce Fields 			/* We just don't care that much */
55967c13f344SJ. Bruce Fields 			goto nevermind;
5597fe0750e5SJ. Bruce Fields 		deny->ld_owner.len = lo->lo_owner.so_owner.len;
5598fe0750e5SJ. Bruce Fields 		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
5599d5b9026aSNeilBrown 	} else {
56007c13f344SJ. Bruce Fields nevermind:
56017c13f344SJ. Bruce Fields 		deny->ld_owner.len = 0;
56027c13f344SJ. Bruce Fields 		deny->ld_owner.data = NULL;
5603d5b9026aSNeilBrown 		deny->ld_clientid.cl_boot = 0;
5604d5b9026aSNeilBrown 		deny->ld_clientid.cl_id = 0;
56051da177e4SLinus Torvalds 	}
56061da177e4SLinus Torvalds 	deny->ld_start = fl->fl_start;
560787df4de8SBenny Halevy 	deny->ld_length = NFS4_MAX_UINT64;
560887df4de8SBenny Halevy 	if (fl->fl_end != NFS4_MAX_UINT64)
56091da177e4SLinus Torvalds 		deny->ld_length = fl->fl_end - fl->fl_start + 1;
56101da177e4SLinus Torvalds 	deny->ld_type = NFS4_READ_LT;
56111da177e4SLinus Torvalds 	if (fl->fl_type != F_RDLCK)
56121da177e4SLinus Torvalds 		deny->ld_type = NFS4_WRITE_LT;
56131da177e4SLinus Torvalds }
56141da177e4SLinus Torvalds 
5615fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
5616c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner)
56171da177e4SLinus Torvalds {
5618d4f0489fSTrond Myklebust 	unsigned int strhashval = ownerstr_hashval(owner);
5619b3c32bcdSTrond Myklebust 	struct nfs4_stateowner *so;
56201da177e4SLinus Torvalds 
56210a880a28STrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
56220a880a28STrond Myklebust 
5623d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval],
5624d4f0489fSTrond Myklebust 			    so_strhash) {
5625b3c32bcdSTrond Myklebust 		if (so->so_is_open_owner)
5626b3c32bcdSTrond Myklebust 			continue;
5627b5971afaSKinglong Mee 		if (same_owner_str(so, owner))
5628b5971afaSKinglong Mee 			return lockowner(nfs4_get_stateowner(so));
56291da177e4SLinus Torvalds 	}
56301da177e4SLinus Torvalds 	return NULL;
56311da177e4SLinus Torvalds }
56321da177e4SLinus Torvalds 
5633c58c6610STrond Myklebust static struct nfs4_lockowner *
5634c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner)
5635c58c6610STrond Myklebust {
5636c58c6610STrond Myklebust 	struct nfs4_lockowner *lo;
5637c58c6610STrond Myklebust 
5638d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5639c8623999SKinglong Mee 	lo = find_lockowner_str_locked(clp, owner);
5640d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5641c58c6610STrond Myklebust 	return lo;
5642c58c6610STrond Myklebust }
5643c58c6610STrond Myklebust 
56448f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
56458f4b54c5SJeff Layton {
5646c58c6610STrond Myklebust 	unhash_lockowner_locked(lockowner(sop));
56478f4b54c5SJeff Layton }
56488f4b54c5SJeff Layton 
56496b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
56506b180f0bSJeff Layton {
56516b180f0bSJeff Layton 	struct nfs4_lockowner *lo = lockowner(sop);
56526b180f0bSJeff Layton 
56536b180f0bSJeff Layton 	kmem_cache_free(lockowner_slab, lo);
56546b180f0bSJeff Layton }
56556b180f0bSJeff Layton 
56566b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = {
56578f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_lockowner,
56586b180f0bSJeff Layton 	.so_free =	nfs4_free_lockowner,
56596b180f0bSJeff Layton };
56606b180f0bSJeff Layton 
56611da177e4SLinus Torvalds /*
56621da177e4SLinus Torvalds  * Alloc a lock owner structure.
56631da177e4SLinus Torvalds  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
566425985edcSLucas De Marchi  * occurred.
56651da177e4SLinus Torvalds  *
566616bfdaafSJ. Bruce Fields  * strhashval = ownerstr_hashval
56671da177e4SLinus Torvalds  */
5668fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
5669c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
5670c58c6610STrond Myklebust 			   struct nfs4_ol_stateid *open_stp,
5671c58c6610STrond Myklebust 			   struct nfsd4_lock *lock)
5672c58c6610STrond Myklebust {
5673c58c6610STrond Myklebust 	struct nfs4_lockowner *lo, *ret;
56741da177e4SLinus Torvalds 
5675fe0750e5SJ. Bruce Fields 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
5676fe0750e5SJ. Bruce Fields 	if (!lo)
56771da177e4SLinus Torvalds 		return NULL;
567876d348faSJeff Layton 	INIT_LIST_HEAD(&lo->lo_blocked);
5679fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
5680fe0750e5SJ. Bruce Fields 	lo->lo_owner.so_is_open_owner = 0;
56815db1c03fSJeff Layton 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
56826b180f0bSJeff Layton 	lo->lo_owner.so_ops = &lockowner_ops;
5683d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5684c8623999SKinglong Mee 	ret = find_lockowner_str_locked(clp, &lock->lk_new_owner);
5685c58c6610STrond Myklebust 	if (ret == NULL) {
5686c58c6610STrond Myklebust 		list_add(&lo->lo_owner.so_strhash,
5687d4f0489fSTrond Myklebust 			 &clp->cl_ownerstr_hashtbl[strhashval]);
5688c58c6610STrond Myklebust 		ret = lo;
5689c58c6610STrond Myklebust 	} else
5690d50ffdedSKinglong Mee 		nfs4_free_stateowner(&lo->lo_owner);
5691d50ffdedSKinglong Mee 
5692d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5693340f0ba1SJ. Bruce Fields 	return ret;
56941da177e4SLinus Torvalds }
56951da177e4SLinus Torvalds 
5696356a95ecSJeff Layton static void
5697356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5698356a95ecSJeff Layton 		  struct nfs4_file *fp, struct inode *inode,
5699f9c00c3aSJeff Layton 		  struct nfs4_ol_stateid *open_stp)
57001da177e4SLinus Torvalds {
5701d3b313a4SJ. Bruce Fields 	struct nfs4_client *clp = lo->lo_owner.so_client;
57021da177e4SLinus Torvalds 
5703356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5704356a95ecSJeff Layton 
5705a15dfcd5SElena Reshetova 	refcount_inc(&stp->st_stid.sc_count);
57063abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_LOCK_STID;
5707b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
570813cd2184SNeilBrown 	get_nfs4_file(fp);
570911b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
57100997b173SJ. Bruce Fields 	stp->st_access_bmap = 0;
57111da177e4SLinus Torvalds 	stp->st_deny_bmap = open_stp->st_deny_bmap;
57124c4cd222SNeilBrown 	stp->st_openstp = open_stp;
5713feb9dad5SOleg Drokin 	mutex_init(&stp->st_mutex);
57143c87b9b7STrond Myklebust 	list_add(&stp->st_locks, &open_stp->st_locks);
57151c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
57161d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
57171d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
57181d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
57191da177e4SLinus Torvalds }
57201da177e4SLinus Torvalds 
5721c53530daSJeff Layton static struct nfs4_ol_stateid *
5722c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
5723c53530daSJeff Layton {
5724c53530daSJeff Layton 	struct nfs4_ol_stateid *lst;
5725356a95ecSJeff Layton 	struct nfs4_client *clp = lo->lo_owner.so_client;
5726356a95ecSJeff Layton 
5727356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5728c53530daSJeff Layton 
5729c53530daSJeff Layton 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
57303d0fabd5STrond Myklebust 		if (lst->st_stid.sc_file == fp) {
5731a15dfcd5SElena Reshetova 			refcount_inc(&lst->st_stid.sc_count);
5732c53530daSJeff Layton 			return lst;
5733c53530daSJeff Layton 		}
57343d0fabd5STrond Myklebust 	}
5735c53530daSJeff Layton 	return NULL;
5736c53530daSJeff Layton }
5737c53530daSJeff Layton 
5738356a95ecSJeff Layton static struct nfs4_ol_stateid *
5739356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
5740356a95ecSJeff Layton 			    struct inode *inode, struct nfs4_ol_stateid *ost,
5741356a95ecSJeff Layton 			    bool *new)
5742356a95ecSJeff Layton {
5743356a95ecSJeff Layton 	struct nfs4_stid *ns = NULL;
5744356a95ecSJeff Layton 	struct nfs4_ol_stateid *lst;
5745356a95ecSJeff Layton 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
5746356a95ecSJeff Layton 	struct nfs4_client *clp = oo->oo_owner.so_client;
5747356a95ecSJeff Layton 
5748356a95ecSJeff Layton 	spin_lock(&clp->cl_lock);
5749356a95ecSJeff Layton 	lst = find_lock_stateid(lo, fi);
5750356a95ecSJeff Layton 	if (lst == NULL) {
5751356a95ecSJeff Layton 		spin_unlock(&clp->cl_lock);
5752d19fb70dSKinglong Mee 		ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
5753356a95ecSJeff Layton 		if (ns == NULL)
5754356a95ecSJeff Layton 			return NULL;
5755356a95ecSJeff Layton 
5756356a95ecSJeff Layton 		spin_lock(&clp->cl_lock);
5757356a95ecSJeff Layton 		lst = find_lock_stateid(lo, fi);
5758356a95ecSJeff Layton 		if (likely(!lst)) {
5759356a95ecSJeff Layton 			lst = openlockstateid(ns);
5760356a95ecSJeff Layton 			init_lock_stateid(lst, lo, fi, inode, ost);
5761356a95ecSJeff Layton 			ns = NULL;
5762356a95ecSJeff Layton 			*new = true;
5763356a95ecSJeff Layton 		}
5764356a95ecSJeff Layton 	}
5765356a95ecSJeff Layton 	spin_unlock(&clp->cl_lock);
5766356a95ecSJeff Layton 	if (ns)
5767356a95ecSJeff Layton 		nfs4_put_stid(ns);
5768356a95ecSJeff Layton 	return lst;
5769356a95ecSJeff Layton }
5770c53530daSJeff Layton 
5771fd39ca9aSNeilBrown static int
57721da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length)
57731da177e4SLinus Torvalds {
577487df4de8SBenny Halevy 	return ((length == 0) || ((length != NFS4_MAX_UINT64) &&
5775e7969315SKinglong Mee 		(length > ~offset)));
57761da177e4SLinus Torvalds }
57771da177e4SLinus Torvalds 
5778dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
57790997b173SJ. Bruce Fields {
578011b9164aSTrond Myklebust 	struct nfs4_file *fp = lock_stp->st_stid.sc_file;
57810997b173SJ. Bruce Fields 
57827214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
57837214e860SJeff Layton 
578482c5ff1bSJeff Layton 	if (test_access(access, lock_stp))
57850997b173SJ. Bruce Fields 		return;
578612659651SJeff Layton 	__nfs4_file_get_access(fp, access);
578782c5ff1bSJeff Layton 	set_access(access, lock_stp);
57880997b173SJ. Bruce Fields }
57890997b173SJ. Bruce Fields 
5790356a95ecSJeff Layton static __be32
5791356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5792356a95ecSJeff Layton 			    struct nfs4_ol_stateid *ost,
5793356a95ecSJeff Layton 			    struct nfsd4_lock *lock,
5794dd257933SJeff Layton 			    struct nfs4_ol_stateid **plst, bool *new)
579564a284d0SJ. Bruce Fields {
57965db1c03fSJeff Layton 	__be32 status;
579711b9164aSTrond Myklebust 	struct nfs4_file *fi = ost->st_stid.sc_file;
579864a284d0SJ. Bruce Fields 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
579964a284d0SJ. Bruce Fields 	struct nfs4_client *cl = oo->oo_owner.so_client;
58002b0143b5SDavid Howells 	struct inode *inode = d_inode(cstate->current_fh.fh_dentry);
580164a284d0SJ. Bruce Fields 	struct nfs4_lockowner *lo;
5802dd257933SJeff Layton 	struct nfs4_ol_stateid *lst;
580364a284d0SJ. Bruce Fields 	unsigned int strhashval;
5804dd257933SJeff Layton 	bool hashed;
580564a284d0SJ. Bruce Fields 
5806c8623999SKinglong Mee 	lo = find_lockowner_str(cl, &lock->lk_new_owner);
5807c53530daSJeff Layton 	if (!lo) {
580876f6c9e1SKinglong Mee 		strhashval = ownerstr_hashval(&lock->lk_new_owner);
580964a284d0SJ. Bruce Fields 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
581064a284d0SJ. Bruce Fields 		if (lo == NULL)
581164a284d0SJ. Bruce Fields 			return nfserr_jukebox;
5812c53530daSJeff Layton 	} else {
5813c53530daSJeff Layton 		/* with an existing lockowner, seqids must be the same */
58145db1c03fSJeff Layton 		status = nfserr_bad_seqid;
5815c53530daSJeff Layton 		if (!cstate->minorversion &&
5816c53530daSJeff Layton 		    lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
58175db1c03fSJeff Layton 			goto out;
5818c53530daSJeff Layton 	}
5819c53530daSJeff Layton 
5820dd257933SJeff Layton retry:
5821dd257933SJeff Layton 	lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
5822dd257933SJeff Layton 	if (lst == NULL) {
58235db1c03fSJeff Layton 		status = nfserr_jukebox;
58245db1c03fSJeff Layton 		goto out;
582564a284d0SJ. Bruce Fields 	}
5826dd257933SJeff Layton 
5827dd257933SJeff Layton 	mutex_lock(&lst->st_mutex);
5828dd257933SJeff Layton 
5829dd257933SJeff Layton 	/* See if it's still hashed to avoid race with FREE_STATEID */
5830dd257933SJeff Layton 	spin_lock(&cl->cl_lock);
5831dd257933SJeff Layton 	hashed = !list_empty(&lst->st_perfile);
5832dd257933SJeff Layton 	spin_unlock(&cl->cl_lock);
5833dd257933SJeff Layton 
5834dd257933SJeff Layton 	if (!hashed) {
5835dd257933SJeff Layton 		mutex_unlock(&lst->st_mutex);
5836dd257933SJeff Layton 		nfs4_put_stid(&lst->st_stid);
5837dd257933SJeff Layton 		goto retry;
5838dd257933SJeff Layton 	}
58395db1c03fSJeff Layton 	status = nfs_ok;
5840dd257933SJeff Layton 	*plst = lst;
58415db1c03fSJeff Layton out:
58425db1c03fSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
58435db1c03fSJeff Layton 	return status;
584464a284d0SJ. Bruce Fields }
584564a284d0SJ. Bruce Fields 
58461da177e4SLinus Torvalds /*
58471da177e4SLinus Torvalds  *  LOCK operation
58481da177e4SLinus Torvalds  */
5849b37ad28bSAl Viro __be32
5850ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5851eb69853dSChristoph Hellwig 	   union nfsd4_op_u *u)
58521da177e4SLinus Torvalds {
5853eb69853dSChristoph Hellwig 	struct nfsd4_lock *lock = &u->lock;
5854fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *open_sop = NULL;
5855fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lock_sop = NULL;
58563d0fabd5STrond Myklebust 	struct nfs4_ol_stateid *lock_stp = NULL;
58570667b1e9STrond Myklebust 	struct nfs4_ol_stateid *open_stp = NULL;
58587214e860SJeff Layton 	struct nfs4_file *fp;
58597d947842SJ. Bruce Fields 	struct file *filp = NULL;
586076d348faSJeff Layton 	struct nfsd4_blocked_lock *nbl = NULL;
586121179d81SJeff Layton 	struct file_lock *file_lock = NULL;
586221179d81SJeff Layton 	struct file_lock *conflock = NULL;
5863b37ad28bSAl Viro 	__be32 status = 0;
5864b34f27aaSJ. Bruce Fields 	int lkflg;
5865b8dd7b9aSAl Viro 	int err;
58665db1c03fSJeff Layton 	bool new = false;
586776d348faSJeff Layton 	unsigned char fl_type;
586876d348faSJeff Layton 	unsigned int fl_flags = FL_POSIX;
58693320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
58703320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
58711da177e4SLinus Torvalds 
58721da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
58731da177e4SLinus Torvalds 		(long long) lock->lk_offset,
58741da177e4SLinus Torvalds 		(long long) lock->lk_length);
58751da177e4SLinus Torvalds 
58761da177e4SLinus Torvalds 	if (check_lock_length(lock->lk_offset, lock->lk_length))
58771da177e4SLinus Torvalds 		 return nfserr_inval;
58781da177e4SLinus Torvalds 
5879ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh,
58808837abcaSMiklos Szeredi 				S_IFREG, NFSD_MAY_LOCK))) {
5881a6f6ef2fSAndy Adamson 		dprintk("NFSD: nfsd4_lock: permission denied!\n");
5882a6f6ef2fSAndy Adamson 		return status;
5883a6f6ef2fSAndy Adamson 	}
5884a6f6ef2fSAndy Adamson 
58851da177e4SLinus Torvalds 	if (lock->lk_is_new) {
5886684e5638SJ. Bruce Fields 		if (nfsd4_has_session(cstate))
5887684e5638SJ. Bruce Fields 			/* See rfc 5661 18.10.3: given clientid is ignored: */
588876f6c9e1SKinglong Mee 			memcpy(&lock->lk_new_clientid,
5889684e5638SJ. Bruce Fields 				&cstate->session->se_client->cl_clientid,
5890684e5638SJ. Bruce Fields 				sizeof(clientid_t));
5891684e5638SJ. Bruce Fields 
58921da177e4SLinus Torvalds 		status = nfserr_stale_clientid;
58932c142baaSStanislav Kinsbursky 		if (STALE_CLIENTID(&lock->lk_new_clientid, nn))
58941da177e4SLinus Torvalds 			goto out;
58951da177e4SLinus Torvalds 
58961da177e4SLinus Torvalds 		/* validate and update open stateid and open seqid */
5897c0a5d93eSJ. Bruce Fields 		status = nfs4_preprocess_confirmed_seqid_op(cstate,
58981da177e4SLinus Torvalds 				        lock->lk_new_open_seqid,
58991da177e4SLinus Torvalds 		                        &lock->lk_new_open_stateid,
59003320fef1SStanislav Kinsbursky 					&open_stp, nn);
590137515177SNeilBrown 		if (status)
59021da177e4SLinus Torvalds 			goto out;
5903feb9dad5SOleg Drokin 		mutex_unlock(&open_stp->st_mutex);
5904fe0750e5SJ. Bruce Fields 		open_sop = openowner(open_stp->st_stateowner);
5905b34f27aaSJ. Bruce Fields 		status = nfserr_bad_stateid;
5906684e5638SJ. Bruce Fields 		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
590776f6c9e1SKinglong Mee 						&lock->lk_new_clientid))
5908b34f27aaSJ. Bruce Fields 			goto out;
590964a284d0SJ. Bruce Fields 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
59105db1c03fSJeff Layton 							&lock_stp, &new);
59113d0fabd5STrond Myklebust 	} else {
5912dd453dfdSBenny Halevy 		status = nfs4_preprocess_seqid_op(cstate,
59131da177e4SLinus Torvalds 				       lock->lk_old_lock_seqid,
59141da177e4SLinus Torvalds 				       &lock->lk_old_lock_stateid,
59153320fef1SStanislav Kinsbursky 				       NFS4_LOCK_STID, &lock_stp, nn);
59163d0fabd5STrond Myklebust 	}
59171da177e4SLinus Torvalds 	if (status)
59181da177e4SLinus Torvalds 		goto out;
5919fe0750e5SJ. Bruce Fields 	lock_sop = lockowner(lock_stp->st_stateowner);
59201da177e4SLinus Torvalds 
5921b34f27aaSJ. Bruce Fields 	lkflg = setlkflg(lock->lk_type);
5922b34f27aaSJ. Bruce Fields 	status = nfs4_check_openmode(lock_stp, lkflg);
5923b34f27aaSJ. Bruce Fields 	if (status)
5924b34f27aaSJ. Bruce Fields 		goto out;
5925b34f27aaSJ. Bruce Fields 
59260dd395dcSNeilBrown 	status = nfserr_grace;
59273320fef1SStanislav Kinsbursky 	if (locks_in_grace(net) && !lock->lk_reclaim)
59280dd395dcSNeilBrown 		goto out;
59290dd395dcSNeilBrown 	status = nfserr_no_grace;
59303320fef1SStanislav Kinsbursky 	if (!locks_in_grace(net) && lock->lk_reclaim)
59310dd395dcSNeilBrown 		goto out;
59320dd395dcSNeilBrown 
593311b9164aSTrond Myklebust 	fp = lock_stp->st_stid.sc_file;
59341da177e4SLinus Torvalds 	switch (lock->lk_type) {
59351da177e4SLinus Torvalds 		case NFS4_READW_LT:
593676d348faSJeff Layton 			if (nfsd4_has_session(cstate))
593776d348faSJeff Layton 				fl_flags |= FL_SLEEP;
593876d348faSJeff Layton 			/* Fallthrough */
593976d348faSJeff Layton 		case NFS4_READ_LT:
59407214e860SJeff Layton 			spin_lock(&fp->fi_lock);
59417214e860SJeff Layton 			filp = find_readable_file_locked(fp);
59420997b173SJ. Bruce Fields 			if (filp)
59430997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
59447214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
594576d348faSJeff Layton 			fl_type = F_RDLCK;
59461da177e4SLinus Torvalds 			break;
59471da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
594876d348faSJeff Layton 			if (nfsd4_has_session(cstate))
594976d348faSJeff Layton 				fl_flags |= FL_SLEEP;
595076d348faSJeff Layton 			/* Fallthrough */
595176d348faSJeff Layton 		case NFS4_WRITE_LT:
59527214e860SJeff Layton 			spin_lock(&fp->fi_lock);
59537214e860SJeff Layton 			filp = find_writeable_file_locked(fp);
59540997b173SJ. Bruce Fields 			if (filp)
59550997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
59567214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
595776d348faSJeff Layton 			fl_type = F_WRLCK;
59581da177e4SLinus Torvalds 			break;
59591da177e4SLinus Torvalds 		default:
59601da177e4SLinus Torvalds 			status = nfserr_inval;
59611da177e4SLinus Torvalds 		goto out;
59621da177e4SLinus Torvalds 	}
596376d348faSJeff Layton 
5964f9d7562fSJ. Bruce Fields 	if (!filp) {
5965f9d7562fSJ. Bruce Fields 		status = nfserr_openmode;
5966f9d7562fSJ. Bruce Fields 		goto out;
5967f9d7562fSJ. Bruce Fields 	}
5968aef9583bSKinglong Mee 
596976d348faSJeff Layton 	nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn);
597076d348faSJeff Layton 	if (!nbl) {
597176d348faSJeff Layton 		dprintk("NFSD: %s: unable to allocate block!\n", __func__);
597276d348faSJeff Layton 		status = nfserr_jukebox;
597376d348faSJeff Layton 		goto out;
597476d348faSJeff Layton 	}
597576d348faSJeff Layton 
597676d348faSJeff Layton 	file_lock = &nbl->nbl_lock;
597776d348faSJeff Layton 	file_lock->fl_type = fl_type;
5978aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
597921179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
598021179d81SJeff Layton 	file_lock->fl_file = filp;
598176d348faSJeff Layton 	file_lock->fl_flags = fl_flags;
598221179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
598321179d81SJeff Layton 	file_lock->fl_start = lock->lk_offset;
598421179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
598521179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
59861da177e4SLinus Torvalds 
598721179d81SJeff Layton 	conflock = locks_alloc_lock();
598821179d81SJeff Layton 	if (!conflock) {
598921179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
599021179d81SJeff Layton 		status = nfserr_jukebox;
599121179d81SJeff Layton 		goto out;
599221179d81SJeff Layton 	}
59931da177e4SLinus Torvalds 
599476d348faSJeff Layton 	if (fl_flags & FL_SLEEP) {
59957919d0a2SJeff Layton 		nbl->nbl_time = jiffies;
59960cc11a61SJeff Layton 		spin_lock(&nn->blocked_locks_lock);
599776d348faSJeff Layton 		list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked);
59987919d0a2SJeff Layton 		list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru);
59990cc11a61SJeff Layton 		spin_unlock(&nn->blocked_locks_lock);
600076d348faSJeff Layton 	}
600176d348faSJeff Layton 
600221179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
600376d348faSJeff Layton 	switch (err) {
60041da177e4SLinus Torvalds 	case 0: /* success! */
60059767feb2SJeff Layton 		nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid);
6006b8dd7b9aSAl Viro 		status = 0;
6007eb76b3fdSAndy Adamson 		break;
600876d348faSJeff Layton 	case FILE_LOCK_DEFERRED:
600976d348faSJeff Layton 		nbl = NULL;
601076d348faSJeff Layton 		/* Fallthrough */
601176d348faSJeff Layton 	case -EAGAIN:		/* conflock holds conflicting lock */
6012eb76b3fdSAndy Adamson 		status = nfserr_denied;
6013eb76b3fdSAndy Adamson 		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
601421179d81SJeff Layton 		nfs4_set_lock_denied(conflock, &lock->lk_denied);
6015eb76b3fdSAndy Adamson 		break;
601676d348faSJeff Layton 	case -EDEADLK:
60171da177e4SLinus Torvalds 		status = nfserr_deadlock;
6018eb76b3fdSAndy Adamson 		break;
60191da177e4SLinus Torvalds 	default:
6020fd85b817SMarc Eshel 		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
60213e772463SJ. Bruce Fields 		status = nfserrno(err);
6022eb76b3fdSAndy Adamson 		break;
60231da177e4SLinus Torvalds 	}
60241da177e4SLinus Torvalds out:
602576d348faSJeff Layton 	if (nbl) {
602676d348faSJeff Layton 		/* dequeue it if we queued it before */
602776d348faSJeff Layton 		if (fl_flags & FL_SLEEP) {
60280cc11a61SJeff Layton 			spin_lock(&nn->blocked_locks_lock);
602976d348faSJeff Layton 			list_del_init(&nbl->nbl_list);
60307919d0a2SJeff Layton 			list_del_init(&nbl->nbl_lru);
60310cc11a61SJeff Layton 			spin_unlock(&nn->blocked_locks_lock);
603276d348faSJeff Layton 		}
603376d348faSJeff Layton 		free_blocked_lock(nbl);
603476d348faSJeff Layton 	}
6035de18643dSTrond Myklebust 	if (filp)
6036de18643dSTrond Myklebust 		fput(filp);
60375db1c03fSJeff Layton 	if (lock_stp) {
60385db1c03fSJeff Layton 		/* Bump seqid manually if the 4.0 replay owner is openowner */
60395db1c03fSJeff Layton 		if (cstate->replay_owner &&
60405db1c03fSJeff Layton 		    cstate->replay_owner != &lock_sop->lo_owner &&
60415db1c03fSJeff Layton 		    seqid_mutating_err(ntohl(status)))
60425db1c03fSJeff Layton 			lock_sop->lo_owner.so_seqid++;
60435db1c03fSJeff Layton 
6044feb9dad5SOleg Drokin 		mutex_unlock(&lock_stp->st_mutex);
604535a92fe8SJeff Layton 
60465db1c03fSJeff Layton 		/*
60475db1c03fSJeff Layton 		 * If this is a new, never-before-used stateid, and we are
60485db1c03fSJeff Layton 		 * returning an error, then just go ahead and release it.
60495db1c03fSJeff Layton 		 */
60505db1c03fSJeff Layton 		if (status && new)
60515db1c03fSJeff Layton 			release_lock_stateid(lock_stp);
60525db1c03fSJeff Layton 
60533d0fabd5STrond Myklebust 		nfs4_put_stid(&lock_stp->st_stid);
60545db1c03fSJeff Layton 	}
60550667b1e9STrond Myklebust 	if (open_stp)
60560667b1e9STrond Myklebust 		nfs4_put_stid(&open_stp->st_stid);
60579411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
605821179d81SJeff Layton 	if (conflock)
605921179d81SJeff Layton 		locks_free_lock(conflock);
60601da177e4SLinus Torvalds 	return status;
60611da177e4SLinus Torvalds }
60621da177e4SLinus Torvalds 
60631da177e4SLinus Torvalds /*
606455ef1274SJ. Bruce Fields  * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
606555ef1274SJ. Bruce Fields  * so we do a temporary open here just to get an open file to pass to
606655ef1274SJ. Bruce Fields  * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
606755ef1274SJ. Bruce Fields  * inode operation.)
606855ef1274SJ. Bruce Fields  */
606904da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
607055ef1274SJ. Bruce Fields {
607155ef1274SJ. Bruce Fields 	struct file *file;
607204da6e9dSAl Viro 	__be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
607304da6e9dSAl Viro 	if (!err) {
607404da6e9dSAl Viro 		err = nfserrno(vfs_test_lock(file, lock));
6075fd891454SChristoph Hellwig 		fput(file);
607604da6e9dSAl Viro 	}
607755ef1274SJ. Bruce Fields 	return err;
607855ef1274SJ. Bruce Fields }
607955ef1274SJ. Bruce Fields 
608055ef1274SJ. Bruce Fields /*
60811da177e4SLinus Torvalds  * LOCKT operation
60821da177e4SLinus Torvalds  */
6083b37ad28bSAl Viro __be32
6084ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
6085eb69853dSChristoph Hellwig 	    union nfsd4_op_u *u)
60861da177e4SLinus Torvalds {
6087eb69853dSChristoph Hellwig 	struct nfsd4_lockt *lockt = &u->lockt;
608821179d81SJeff Layton 	struct file_lock *file_lock = NULL;
60895db1c03fSJeff Layton 	struct nfs4_lockowner *lo = NULL;
6090b37ad28bSAl Viro 	__be32 status;
60917f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
60921da177e4SLinus Torvalds 
60935ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp)))
60941da177e4SLinus Torvalds 		return nfserr_grace;
60951da177e4SLinus Torvalds 
60961da177e4SLinus Torvalds 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
60971da177e4SLinus Torvalds 		 return nfserr_inval;
60981da177e4SLinus Torvalds 
60999b2ef62bSJ. Bruce Fields 	if (!nfsd4_has_session(cstate)) {
61004b24ca7dSJeff Layton 		status = lookup_clientid(&lockt->lt_clientid, cstate, nn);
61019b2ef62bSJ. Bruce Fields 		if (status)
61021da177e4SLinus Torvalds 			goto out;
61039b2ef62bSJ. Bruce Fields 	}
61041da177e4SLinus Torvalds 
610575c096f7SJ. Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
61061da177e4SLinus Torvalds 		goto out;
61071da177e4SLinus Torvalds 
610821179d81SJeff Layton 	file_lock = locks_alloc_lock();
610921179d81SJeff Layton 	if (!file_lock) {
611021179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
611121179d81SJeff Layton 		status = nfserr_jukebox;
611221179d81SJeff Layton 		goto out;
611321179d81SJeff Layton 	}
61146cd90662SKinglong Mee 
61151da177e4SLinus Torvalds 	switch (lockt->lt_type) {
61161da177e4SLinus Torvalds 		case NFS4_READ_LT:
61171da177e4SLinus Torvalds 		case NFS4_READW_LT:
611821179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
61191da177e4SLinus Torvalds 		break;
61201da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
61211da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
612221179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
61231da177e4SLinus Torvalds 		break;
61241da177e4SLinus Torvalds 		default:
61252fdada03SJ. Bruce Fields 			dprintk("NFSD: nfs4_lockt: bad lock type!\n");
61261da177e4SLinus Torvalds 			status = nfserr_inval;
61271da177e4SLinus Torvalds 		goto out;
61281da177e4SLinus Torvalds 	}
61291da177e4SLinus Torvalds 
6130c8623999SKinglong Mee 	lo = find_lockowner_str(cstate->clp, &lockt->lt_owner);
6131fe0750e5SJ. Bruce Fields 	if (lo)
613221179d81SJeff Layton 		file_lock->fl_owner = (fl_owner_t)lo;
613321179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
613421179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
61351da177e4SLinus Torvalds 
613621179d81SJeff Layton 	file_lock->fl_start = lockt->lt_offset;
613721179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
61381da177e4SLinus Torvalds 
613921179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
61401da177e4SLinus Torvalds 
614121179d81SJeff Layton 	status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
614204da6e9dSAl Viro 	if (status)
6143fd85b817SMarc Eshel 		goto out;
614404da6e9dSAl Viro 
614521179d81SJeff Layton 	if (file_lock->fl_type != F_UNLCK) {
61461da177e4SLinus Torvalds 		status = nfserr_denied;
614721179d81SJeff Layton 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
61481da177e4SLinus Torvalds 	}
61491da177e4SLinus Torvalds out:
61505db1c03fSJeff Layton 	if (lo)
61515db1c03fSJeff Layton 		nfs4_put_stateowner(&lo->lo_owner);
615221179d81SJeff Layton 	if (file_lock)
615321179d81SJeff Layton 		locks_free_lock(file_lock);
61541da177e4SLinus Torvalds 	return status;
61551da177e4SLinus Torvalds }
61561da177e4SLinus Torvalds 
6157b37ad28bSAl Viro __be32
6158ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
6159eb69853dSChristoph Hellwig 	    union nfsd4_op_u *u)
61601da177e4SLinus Torvalds {
6161eb69853dSChristoph Hellwig 	struct nfsd4_locku *locku = &u->locku;
6162dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
61631da177e4SLinus Torvalds 	struct file *filp = NULL;
616421179d81SJeff Layton 	struct file_lock *file_lock = NULL;
6165b37ad28bSAl Viro 	__be32 status;
6166b8dd7b9aSAl Viro 	int err;
61673320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
61681da177e4SLinus Torvalds 
61691da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
61701da177e4SLinus Torvalds 		(long long) locku->lu_offset,
61711da177e4SLinus Torvalds 		(long long) locku->lu_length);
61721da177e4SLinus Torvalds 
61731da177e4SLinus Torvalds 	if (check_lock_length(locku->lu_offset, locku->lu_length))
61741da177e4SLinus Torvalds 		 return nfserr_inval;
61751da177e4SLinus Torvalds 
61769072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
61773320fef1SStanislav Kinsbursky 					&locku->lu_stateid, NFS4_LOCK_STID,
61783320fef1SStanislav Kinsbursky 					&stp, nn);
61799072d5c6SJ. Bruce Fields 	if (status)
61801da177e4SLinus Torvalds 		goto out;
618111b9164aSTrond Myklebust 	filp = find_any_file(stp->st_stid.sc_file);
6182f9d7562fSJ. Bruce Fields 	if (!filp) {
6183f9d7562fSJ. Bruce Fields 		status = nfserr_lock_range;
6184858cc573STrond Myklebust 		goto put_stateid;
6185f9d7562fSJ. Bruce Fields 	}
618621179d81SJeff Layton 	file_lock = locks_alloc_lock();
618721179d81SJeff Layton 	if (!file_lock) {
618821179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
618921179d81SJeff Layton 		status = nfserr_jukebox;
6190de18643dSTrond Myklebust 		goto fput;
619121179d81SJeff Layton 	}
61926cd90662SKinglong Mee 
619321179d81SJeff Layton 	file_lock->fl_type = F_UNLCK;
6194aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
619521179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
619621179d81SJeff Layton 	file_lock->fl_file = filp;
619721179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
619821179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
619921179d81SJeff Layton 	file_lock->fl_start = locku->lu_offset;
62001da177e4SLinus Torvalds 
620121179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(locku->lu_offset,
620221179d81SJeff Layton 						locku->lu_length);
620321179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
62041da177e4SLinus Torvalds 
620521179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
6206b8dd7b9aSAl Viro 	if (err) {
6207fd85b817SMarc Eshel 		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
62081da177e4SLinus Torvalds 		goto out_nfserr;
62091da177e4SLinus Torvalds 	}
62109767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid);
6211de18643dSTrond Myklebust fput:
6212de18643dSTrond Myklebust 	fput(filp);
6213858cc573STrond Myklebust put_stateid:
6214feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
6215858cc573STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
62161da177e4SLinus Torvalds out:
62179411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
621821179d81SJeff Layton 	if (file_lock)
621921179d81SJeff Layton 		locks_free_lock(file_lock);
62201da177e4SLinus Torvalds 	return status;
62211da177e4SLinus Torvalds 
62221da177e4SLinus Torvalds out_nfserr:
6223b8dd7b9aSAl Viro 	status = nfserrno(err);
6224de18643dSTrond Myklebust 	goto fput;
62251da177e4SLinus Torvalds }
62261da177e4SLinus Torvalds 
62271da177e4SLinus Torvalds /*
62281da177e4SLinus Torvalds  * returns
6229f9c00c3aSJeff Layton  * 	true:  locks held by lockowner
6230f9c00c3aSJeff Layton  * 	false: no locks held by lockowner
62311da177e4SLinus Torvalds  */
6232f9c00c3aSJeff Layton static bool
6233f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
62341da177e4SLinus Torvalds {
6235bd61e0a9SJeff Layton 	struct file_lock *fl;
6236f9c00c3aSJeff Layton 	int status = false;
6237f9c00c3aSJeff Layton 	struct file *filp = find_any_file(fp);
6238f9c00c3aSJeff Layton 	struct inode *inode;
6239bd61e0a9SJeff Layton 	struct file_lock_context *flctx;
6240f9c00c3aSJeff Layton 
6241f9c00c3aSJeff Layton 	if (!filp) {
6242f9c00c3aSJeff Layton 		/* Any valid lock stateid should have some sort of access */
6243f9c00c3aSJeff Layton 		WARN_ON_ONCE(1);
6244f9c00c3aSJeff Layton 		return status;
6245f9c00c3aSJeff Layton 	}
6246f9c00c3aSJeff Layton 
6247f9c00c3aSJeff Layton 	inode = file_inode(filp);
6248bd61e0a9SJeff Layton 	flctx = inode->i_flctx;
62491da177e4SLinus Torvalds 
6250bd61e0a9SJeff Layton 	if (flctx && !list_empty_careful(&flctx->flc_posix)) {
62516109c850SJeff Layton 		spin_lock(&flctx->flc_lock);
6252bd61e0a9SJeff Layton 		list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
6253bd61e0a9SJeff Layton 			if (fl->fl_owner == (fl_owner_t)lowner) {
6254f9c00c3aSJeff Layton 				status = true;
6255f9c00c3aSJeff Layton 				break;
62561da177e4SLinus Torvalds 			}
6257796dadfdSJ. Bruce Fields 		}
62586109c850SJeff Layton 		spin_unlock(&flctx->flc_lock);
6259bd61e0a9SJeff Layton 	}
6260f9c00c3aSJeff Layton 	fput(filp);
62611da177e4SLinus Torvalds 	return status;
62621da177e4SLinus Torvalds }
62631da177e4SLinus Torvalds 
6264b37ad28bSAl Viro __be32
6265b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp,
6266b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
6267eb69853dSChristoph Hellwig 			union nfsd4_op_u *u)
62681da177e4SLinus Torvalds {
6269eb69853dSChristoph Hellwig 	struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
62701da177e4SLinus Torvalds 	clientid_t *clid = &rlockowner->rl_clientid;
6271882e9d25SJeff Layton 	struct nfs4_stateowner *sop;
6272882e9d25SJeff Layton 	struct nfs4_lockowner *lo = NULL;
6273dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
62741da177e4SLinus Torvalds 	struct xdr_netobj *owner = &rlockowner->rl_owner;
6275d4f0489fSTrond Myklebust 	unsigned int hashval = ownerstr_hashval(owner);
6276b37ad28bSAl Viro 	__be32 status;
62777f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
6278c58c6610STrond Myklebust 	struct nfs4_client *clp;
627988584818SChuck Lever 	LIST_HEAD (reaplist);
62801da177e4SLinus Torvalds 
62811da177e4SLinus Torvalds 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
62821da177e4SLinus Torvalds 		clid->cl_boot, clid->cl_id);
62831da177e4SLinus Torvalds 
62844b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
62859b2ef62bSJ. Bruce Fields 	if (status)
628651f5e783STrond Myklebust 		return status;
62879b2ef62bSJ. Bruce Fields 
6288d4f0489fSTrond Myklebust 	clp = cstate->clp;
6289fd44907cSJeff Layton 	/* Find the matching lock stateowner */
6290d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
6291882e9d25SJeff Layton 	list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval],
6292d4f0489fSTrond Myklebust 			    so_strhash) {
6293882e9d25SJeff Layton 
6294882e9d25SJeff Layton 		if (sop->so_is_open_owner || !same_owner_str(sop, owner))
629516bfdaafSJ. Bruce Fields 			continue;
6296882e9d25SJeff Layton 
6297882e9d25SJeff Layton 		/* see if there are still any locks associated with it */
6298882e9d25SJeff Layton 		lo = lockowner(sop);
6299882e9d25SJeff Layton 		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
6300882e9d25SJeff Layton 			if (check_for_locks(stp->st_stid.sc_file, lo)) {
6301882e9d25SJeff Layton 				status = nfserr_locks_held;
6302882e9d25SJeff Layton 				spin_unlock(&clp->cl_lock);
630351f5e783STrond Myklebust 				return status;
6304882e9d25SJeff Layton 			}
6305882e9d25SJeff Layton 		}
6306882e9d25SJeff Layton 
6307b5971afaSKinglong Mee 		nfs4_get_stateowner(sop);
6308fd44907cSJeff Layton 		break;
6309fd44907cSJeff Layton 	}
631088584818SChuck Lever 	if (!lo) {
6311d4f0489fSTrond Myklebust 		spin_unlock(&clp->cl_lock);
631288584818SChuck Lever 		return status;
631388584818SChuck Lever 	}
631488584818SChuck Lever 
631588584818SChuck Lever 	unhash_lockowner_locked(lo);
631688584818SChuck Lever 	while (!list_empty(&lo->lo_owner.so_stateids)) {
631788584818SChuck Lever 		stp = list_first_entry(&lo->lo_owner.so_stateids,
631888584818SChuck Lever 				       struct nfs4_ol_stateid,
631988584818SChuck Lever 				       st_perstateowner);
632088584818SChuck Lever 		WARN_ON(!unhash_lock_stateid(stp));
632188584818SChuck Lever 		put_ol_stateid_locked(stp, &reaplist);
632288584818SChuck Lever 	}
632388584818SChuck Lever 	spin_unlock(&clp->cl_lock);
632488584818SChuck Lever 	free_ol_stateid_reaplist(&reaplist);
632588584818SChuck Lever 	nfs4_put_stateowner(&lo->lo_owner);
632688584818SChuck Lever 
63271da177e4SLinus Torvalds 	return status;
63281da177e4SLinus Torvalds }
63291da177e4SLinus Torvalds 
63301da177e4SLinus Torvalds static inline struct nfs4_client_reclaim *
6331a55370a3SNeilBrown alloc_reclaim(void)
63321da177e4SLinus Torvalds {
6333a55370a3SNeilBrown 	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
63341da177e4SLinus Torvalds }
63351da177e4SLinus Torvalds 
63360ce0c2b5SJeff Layton bool
633752e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
6338c7b9a459SNeilBrown {
63390ce0c2b5SJeff Layton 	struct nfs4_client_reclaim *crp;
6340c7b9a459SNeilBrown 
634152e19c09SStanislav Kinsbursky 	crp = nfsd4_find_reclaim_client(name, nn);
63420ce0c2b5SJeff Layton 	return (crp && crp->cr_clp);
6343c7b9a459SNeilBrown }
6344c7b9a459SNeilBrown 
63451da177e4SLinus Torvalds /*
63461da177e4SLinus Torvalds  * failure => all reset bets are off, nfserr_no_grace...
63471da177e4SLinus Torvalds  */
6348772a9bbbSJeff Layton struct nfs4_client_reclaim *
634952e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
63501da177e4SLinus Torvalds {
63511da177e4SLinus Torvalds 	unsigned int strhashval;
6352772a9bbbSJeff Layton 	struct nfs4_client_reclaim *crp;
63531da177e4SLinus Torvalds 
6354a55370a3SNeilBrown 	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
6355a55370a3SNeilBrown 	crp = alloc_reclaim();
6356772a9bbbSJeff Layton 	if (crp) {
6357a55370a3SNeilBrown 		strhashval = clientstr_hashval(name);
63581da177e4SLinus Torvalds 		INIT_LIST_HEAD(&crp->cr_strhash);
635952e19c09SStanislav Kinsbursky 		list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
6360a55370a3SNeilBrown 		memcpy(crp->cr_recdir, name, HEXDIR_LEN);
63610ce0c2b5SJeff Layton 		crp->cr_clp = NULL;
636252e19c09SStanislav Kinsbursky 		nn->reclaim_str_hashtbl_size++;
6363772a9bbbSJeff Layton 	}
6364772a9bbbSJeff Layton 	return crp;
63651da177e4SLinus Torvalds }
63661da177e4SLinus Torvalds 
63672a4317c5SJeff Layton void
636852e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
6369ce30e539SJeff Layton {
6370ce30e539SJeff Layton 	list_del(&crp->cr_strhash);
6371ce30e539SJeff Layton 	kfree(crp);
637252e19c09SStanislav Kinsbursky 	nn->reclaim_str_hashtbl_size--;
6373ce30e539SJeff Layton }
6374ce30e539SJeff Layton 
6375ce30e539SJeff Layton void
637652e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn)
63771da177e4SLinus Torvalds {
63781da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
63791da177e4SLinus Torvalds 	int i;
63801da177e4SLinus Torvalds 
63811da177e4SLinus Torvalds 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
638252e19c09SStanislav Kinsbursky 		while (!list_empty(&nn->reclaim_str_hashtbl[i])) {
638352e19c09SStanislav Kinsbursky 			crp = list_entry(nn->reclaim_str_hashtbl[i].next,
63841da177e4SLinus Torvalds 			                struct nfs4_client_reclaim, cr_strhash);
638552e19c09SStanislav Kinsbursky 			nfs4_remove_reclaim_record(crp, nn);
63861da177e4SLinus Torvalds 		}
63871da177e4SLinus Torvalds 	}
6388063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(nn->reclaim_str_hashtbl_size);
63891da177e4SLinus Torvalds }
63901da177e4SLinus Torvalds 
63911da177e4SLinus Torvalds /*
63921da177e4SLinus Torvalds  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
63932a4317c5SJeff Layton struct nfs4_client_reclaim *
639452e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
63951da177e4SLinus Torvalds {
63961da177e4SLinus Torvalds 	unsigned int strhashval;
63971da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
63981da177e4SLinus Torvalds 
6399278c931cSJeff Layton 	dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
64001da177e4SLinus Torvalds 
6401278c931cSJeff Layton 	strhashval = clientstr_hashval(recdir);
640252e19c09SStanislav Kinsbursky 	list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
6403278c931cSJeff Layton 		if (same_name(crp->cr_recdir, recdir)) {
64041da177e4SLinus Torvalds 			return crp;
64051da177e4SLinus Torvalds 		}
64061da177e4SLinus Torvalds 	}
64071da177e4SLinus Torvalds 	return NULL;
64081da177e4SLinus Torvalds }
64091da177e4SLinus Torvalds 
64101da177e4SLinus Torvalds /*
64111da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list.
64121da177e4SLinus Torvalds */
6413b37ad28bSAl Viro __be32
64140fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid,
64150fe492dbSTrond Myklebust 		struct nfsd4_compound_state *cstate,
64160fe492dbSTrond Myklebust 		struct nfsd_net *nn)
64171da177e4SLinus Torvalds {
64180fe492dbSTrond Myklebust 	__be32 status;
6419a52d726bSJeff Layton 
6420a52d726bSJeff Layton 	/* find clientid in conf_id_hashtbl */
64210fe492dbSTrond Myklebust 	status = lookup_clientid(clid, cstate, nn);
64220fe492dbSTrond Myklebust 	if (status)
6423a52d726bSJeff Layton 		return nfserr_reclaim_bad;
6424a52d726bSJeff Layton 
64253b3e7b72SJeff Layton 	if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags))
64263b3e7b72SJeff Layton 		return nfserr_no_grace;
64273b3e7b72SJeff Layton 
64280fe492dbSTrond Myklebust 	if (nfsd4_client_record_check(cstate->clp))
64290fe492dbSTrond Myklebust 		return nfserr_reclaim_bad;
64300fe492dbSTrond Myklebust 
64310fe492dbSTrond Myklebust 	return nfs_ok;
64321da177e4SLinus Torvalds }
64331da177e4SLinus Torvalds 
643465178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION
6435016200c3SJeff Layton static inline void
6436016200c3SJeff Layton put_client(struct nfs4_client *clp)
6437016200c3SJeff Layton {
6438016200c3SJeff Layton 	atomic_dec(&clp->cl_refcount);
6439016200c3SJeff Layton }
6440016200c3SJeff Layton 
6441285abdeeSJeff Layton static struct nfs4_client *
6442285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
6443285abdeeSJeff Layton {
6444285abdeeSJeff Layton 	struct nfs4_client *clp;
6445285abdeeSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6446285abdeeSJeff Layton 					  nfsd_net_id);
6447285abdeeSJeff Layton 
6448285abdeeSJeff Layton 	if (!nfsd_netns_ready(nn))
6449285abdeeSJeff Layton 		return NULL;
6450285abdeeSJeff Layton 
6451285abdeeSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
6452285abdeeSJeff Layton 		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
6453285abdeeSJeff Layton 			return clp;
6454285abdeeSJeff Layton 	}
6455285abdeeSJeff Layton 	return NULL;
6456285abdeeSJeff Layton }
6457285abdeeSJeff Layton 
64587ec0e36fSJeff Layton u64
6459285abdeeSJeff Layton nfsd_inject_print_clients(void)
64607ec0e36fSJeff Layton {
64617ec0e36fSJeff Layton 	struct nfs4_client *clp;
64627ec0e36fSJeff Layton 	u64 count = 0;
64637ec0e36fSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
64647ec0e36fSJeff Layton 					  nfsd_net_id);
64657ec0e36fSJeff Layton 	char buf[INET6_ADDRSTRLEN];
64667ec0e36fSJeff Layton 
64677ec0e36fSJeff Layton 	if (!nfsd_netns_ready(nn))
64687ec0e36fSJeff Layton 		return 0;
64697ec0e36fSJeff Layton 
64707ec0e36fSJeff Layton 	spin_lock(&nn->client_lock);
64717ec0e36fSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
64727ec0e36fSJeff Layton 		rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
64737ec0e36fSJeff Layton 		pr_info("NFS Client: %s\n", buf);
64747ec0e36fSJeff Layton 		++count;
64757ec0e36fSJeff Layton 	}
64767ec0e36fSJeff Layton 	spin_unlock(&nn->client_lock);
64777ec0e36fSJeff Layton 
64787ec0e36fSJeff Layton 	return count;
64797ec0e36fSJeff Layton }
648065178db4SBryan Schumaker 
6481a0926d15SJeff Layton u64
6482285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size)
6483a0926d15SJeff Layton {
6484a0926d15SJeff Layton 	u64 count = 0;
6485a0926d15SJeff Layton 	struct nfs4_client *clp;
6486a0926d15SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6487a0926d15SJeff Layton 					  nfsd_net_id);
6488a0926d15SJeff Layton 
6489a0926d15SJeff Layton 	if (!nfsd_netns_ready(nn))
6490a0926d15SJeff Layton 		return count;
6491a0926d15SJeff Layton 
6492a0926d15SJeff Layton 	spin_lock(&nn->client_lock);
6493a0926d15SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
6494a0926d15SJeff Layton 	if (clp) {
6495a0926d15SJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok)
6496a0926d15SJeff Layton 			++count;
6497a0926d15SJeff Layton 		else
6498a0926d15SJeff Layton 			clp = NULL;
6499a0926d15SJeff Layton 	}
6500a0926d15SJeff Layton 	spin_unlock(&nn->client_lock);
6501a0926d15SJeff Layton 
6502a0926d15SJeff Layton 	if (clp)
6503a0926d15SJeff Layton 		expire_client(clp);
6504a0926d15SJeff Layton 
6505a0926d15SJeff Layton 	return count;
6506a0926d15SJeff Layton }
6507a0926d15SJeff Layton 
650869fc9edfSJeff Layton u64
6509285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max)
651069fc9edfSJeff Layton {
651169fc9edfSJeff Layton 	u64 count = 0;
651269fc9edfSJeff Layton 	struct nfs4_client *clp, *next;
651369fc9edfSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
651469fc9edfSJeff Layton 						nfsd_net_id);
651569fc9edfSJeff Layton 	LIST_HEAD(reaplist);
651669fc9edfSJeff Layton 
651769fc9edfSJeff Layton 	if (!nfsd_netns_ready(nn))
651869fc9edfSJeff Layton 		return count;
651969fc9edfSJeff Layton 
652069fc9edfSJeff Layton 	spin_lock(&nn->client_lock);
652169fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
652269fc9edfSJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok) {
652369fc9edfSJeff Layton 			list_add(&clp->cl_lru, &reaplist);
652469fc9edfSJeff Layton 			if (max != 0 && ++count >= max)
652569fc9edfSJeff Layton 				break;
652669fc9edfSJeff Layton 		}
652769fc9edfSJeff Layton 	}
652869fc9edfSJeff Layton 	spin_unlock(&nn->client_lock);
652969fc9edfSJeff Layton 
653069fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
653169fc9edfSJeff Layton 		expire_client(clp);
653269fc9edfSJeff Layton 
653369fc9edfSJeff Layton 	return count;
653469fc9edfSJeff Layton }
653569fc9edfSJeff Layton 
6536184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
6537184c1847SBryan Schumaker 			     const char *type)
6538184c1847SBryan Schumaker {
6539184c1847SBryan Schumaker 	char buf[INET6_ADDRSTRLEN];
65400a5c33e2SBryan Schumaker 	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
6541184c1847SBryan Schumaker 	printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
6542184c1847SBryan Schumaker }
6543184c1847SBryan Schumaker 
6544016200c3SJeff Layton static void
6545016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
6546016200c3SJeff Layton 			     struct list_head *collect)
6547016200c3SJeff Layton {
6548016200c3SJeff Layton 	struct nfs4_client *clp = lst->st_stid.sc_client;
6549016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6550016200c3SJeff Layton 					  nfsd_net_id);
6551016200c3SJeff Layton 
6552016200c3SJeff Layton 	if (!collect)
6553016200c3SJeff Layton 		return;
6554016200c3SJeff Layton 
6555016200c3SJeff Layton 	lockdep_assert_held(&nn->client_lock);
6556016200c3SJeff Layton 	atomic_inc(&clp->cl_refcount);
6557016200c3SJeff Layton 	list_add(&lst->st_locks, collect);
6558016200c3SJeff Layton }
6559016200c3SJeff Layton 
65603c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
65613738d50eSJeff Layton 				    struct list_head *collect,
6562e8568739SJeff Layton 				    bool (*func)(struct nfs4_ol_stateid *))
6563fc29171fSBryan Schumaker {
6564fc29171fSBryan Schumaker 	struct nfs4_openowner *oop;
6565fc29171fSBryan Schumaker 	struct nfs4_ol_stateid *stp, *st_next;
65663c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *lst, *lst_next;
6567fc29171fSBryan Schumaker 	u64 count = 0;
6568fc29171fSBryan Schumaker 
6569016200c3SJeff Layton 	spin_lock(&clp->cl_lock);
6570fc29171fSBryan Schumaker 	list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
65713c87b9b7STrond Myklebust 		list_for_each_entry_safe(stp, st_next,
65723c87b9b7STrond Myklebust 				&oop->oo_owner.so_stateids, st_perstateowner) {
65733c87b9b7STrond Myklebust 			list_for_each_entry_safe(lst, lst_next,
65743c87b9b7STrond Myklebust 					&stp->st_locks, st_locks) {
65753738d50eSJeff Layton 				if (func) {
6576e8568739SJeff Layton 					if (func(lst))
6577016200c3SJeff Layton 						nfsd_inject_add_lock_to_list(lst,
65783738d50eSJeff Layton 									collect);
65793738d50eSJeff Layton 				}
6580016200c3SJeff Layton 				++count;
6581016200c3SJeff Layton 				/*
6582016200c3SJeff Layton 				 * Despite the fact that these functions deal
6583016200c3SJeff Layton 				 * with 64-bit integers for "count", we must
6584016200c3SJeff Layton 				 * ensure that it doesn't blow up the
6585016200c3SJeff Layton 				 * clp->cl_refcount. Throw a warning if we
6586016200c3SJeff Layton 				 * start to approach INT_MAX here.
6587016200c3SJeff Layton 				 */
6588016200c3SJeff Layton 				WARN_ON_ONCE(count == (INT_MAX / 2));
6589016200c3SJeff Layton 				if (count == max)
6590016200c3SJeff Layton 					goto out;
6591fc29171fSBryan Schumaker 			}
6592fc29171fSBryan Schumaker 		}
6593fc29171fSBryan Schumaker 	}
6594016200c3SJeff Layton out:
6595016200c3SJeff Layton 	spin_unlock(&clp->cl_lock);
6596fc29171fSBryan Schumaker 
6597fc29171fSBryan Schumaker 	return count;
6598fc29171fSBryan Schumaker }
6599fc29171fSBryan Schumaker 
6600016200c3SJeff Layton static u64
6601016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
6602016200c3SJeff Layton 			  u64 max)
6603fc29171fSBryan Schumaker {
6604016200c3SJeff Layton 	return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
6605fc29171fSBryan Schumaker }
6606fc29171fSBryan Schumaker 
6607016200c3SJeff Layton static u64
6608016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp)
6609184c1847SBryan Schumaker {
6610016200c3SJeff Layton 	u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
6611184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "locked files");
6612184c1847SBryan Schumaker 	return count;
6613184c1847SBryan Schumaker }
6614184c1847SBryan Schumaker 
6615016200c3SJeff Layton u64
6616285abdeeSJeff Layton nfsd_inject_print_locks(void)
6617016200c3SJeff Layton {
6618016200c3SJeff Layton 	struct nfs4_client *clp;
6619016200c3SJeff Layton 	u64 count = 0;
6620016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6621016200c3SJeff Layton 						nfsd_net_id);
6622016200c3SJeff Layton 
6623016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6624016200c3SJeff Layton 		return 0;
6625016200c3SJeff Layton 
6626016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6627016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
6628016200c3SJeff Layton 		count += nfsd_print_client_locks(clp);
6629016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6630016200c3SJeff Layton 
6631016200c3SJeff Layton 	return count;
6632016200c3SJeff Layton }
6633016200c3SJeff Layton 
6634016200c3SJeff Layton static void
6635016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist)
6636016200c3SJeff Layton {
6637016200c3SJeff Layton 	struct nfs4_client *clp;
6638016200c3SJeff Layton 	struct nfs4_ol_stateid *stp, *next;
6639016200c3SJeff Layton 
6640016200c3SJeff Layton 	list_for_each_entry_safe(stp, next, reaplist, st_locks) {
6641016200c3SJeff Layton 		list_del_init(&stp->st_locks);
6642016200c3SJeff Layton 		clp = stp->st_stid.sc_client;
6643016200c3SJeff Layton 		nfs4_put_stid(&stp->st_stid);
6644016200c3SJeff Layton 		put_client(clp);
6645016200c3SJeff Layton 	}
6646016200c3SJeff Layton }
6647016200c3SJeff Layton 
6648016200c3SJeff Layton u64
6649285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size)
6650016200c3SJeff Layton {
6651016200c3SJeff Layton 	unsigned int count = 0;
6652016200c3SJeff Layton 	struct nfs4_client *clp;
6653016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6654016200c3SJeff Layton 						nfsd_net_id);
6655016200c3SJeff Layton 	LIST_HEAD(reaplist);
6656016200c3SJeff Layton 
6657016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6658016200c3SJeff Layton 		return count;
6659016200c3SJeff Layton 
6660016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6661016200c3SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
6662016200c3SJeff Layton 	if (clp)
6663016200c3SJeff Layton 		count = nfsd_collect_client_locks(clp, &reaplist, 0);
6664016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6665016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
6666016200c3SJeff Layton 	return count;
6667016200c3SJeff Layton }
6668016200c3SJeff Layton 
6669016200c3SJeff Layton u64
6670285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max)
6671016200c3SJeff Layton {
6672016200c3SJeff Layton 	u64 count = 0;
6673016200c3SJeff Layton 	struct nfs4_client *clp;
6674016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6675016200c3SJeff Layton 						nfsd_net_id);
6676016200c3SJeff Layton 	LIST_HEAD(reaplist);
6677016200c3SJeff Layton 
6678016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6679016200c3SJeff Layton 		return count;
6680016200c3SJeff Layton 
6681016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6682016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
6683016200c3SJeff Layton 		count += nfsd_collect_client_locks(clp, &reaplist, max - count);
6684016200c3SJeff Layton 		if (max != 0 && count >= max)
6685016200c3SJeff Layton 			break;
6686016200c3SJeff Layton 	}
6687016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6688016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
6689016200c3SJeff Layton 	return count;
6690016200c3SJeff Layton }
6691016200c3SJeff Layton 
669282e05efaSJeff Layton static u64
669382e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
669482e05efaSJeff Layton 			      struct list_head *collect,
669582e05efaSJeff Layton 			      void (*func)(struct nfs4_openowner *))
66964dbdbda8SBryan Schumaker {
66974dbdbda8SBryan Schumaker 	struct nfs4_openowner *oop, *next;
669882e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
669982e05efaSJeff Layton 						nfsd_net_id);
67004dbdbda8SBryan Schumaker 	u64 count = 0;
67014dbdbda8SBryan Schumaker 
670282e05efaSJeff Layton 	lockdep_assert_held(&nn->client_lock);
670382e05efaSJeff Layton 
670482e05efaSJeff Layton 	spin_lock(&clp->cl_lock);
67054dbdbda8SBryan Schumaker 	list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
670682e05efaSJeff Layton 		if (func) {
67074dbdbda8SBryan Schumaker 			func(oop);
670882e05efaSJeff Layton 			if (collect) {
670982e05efaSJeff Layton 				atomic_inc(&clp->cl_refcount);
671082e05efaSJeff Layton 				list_add(&oop->oo_perclient, collect);
671182e05efaSJeff Layton 			}
671282e05efaSJeff Layton 		}
671382e05efaSJeff Layton 		++count;
671482e05efaSJeff Layton 		/*
671582e05efaSJeff Layton 		 * Despite the fact that these functions deal with
671682e05efaSJeff Layton 		 * 64-bit integers for "count", we must ensure that
671782e05efaSJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
671882e05efaSJeff Layton 		 * warning if we start to approach INT_MAX here.
671982e05efaSJeff Layton 		 */
672082e05efaSJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
672182e05efaSJeff Layton 		if (count == max)
67224dbdbda8SBryan Schumaker 			break;
67234dbdbda8SBryan Schumaker 	}
672482e05efaSJeff Layton 	spin_unlock(&clp->cl_lock);
67254dbdbda8SBryan Schumaker 
67264dbdbda8SBryan Schumaker 	return count;
67274dbdbda8SBryan Schumaker }
67284dbdbda8SBryan Schumaker 
672982e05efaSJeff Layton static u64
673082e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp)
67314dbdbda8SBryan Schumaker {
673282e05efaSJeff Layton 	u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
673382e05efaSJeff Layton 
673482e05efaSJeff Layton 	nfsd_print_count(clp, count, "openowners");
673582e05efaSJeff Layton 	return count;
67364dbdbda8SBryan Schumaker }
67374dbdbda8SBryan Schumaker 
673882e05efaSJeff Layton static u64
673982e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp,
674082e05efaSJeff Layton 			       struct list_head *collect, u64 max)
6741184c1847SBryan Schumaker {
674282e05efaSJeff Layton 	return nfsd_foreach_client_openowner(clp, max, collect,
674382e05efaSJeff Layton 						unhash_openowner_locked);
674482e05efaSJeff Layton }
674582e05efaSJeff Layton 
674682e05efaSJeff Layton u64
6747285abdeeSJeff Layton nfsd_inject_print_openowners(void)
674882e05efaSJeff Layton {
674982e05efaSJeff Layton 	struct nfs4_client *clp;
675082e05efaSJeff Layton 	u64 count = 0;
675182e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
675282e05efaSJeff Layton 						nfsd_net_id);
675382e05efaSJeff Layton 
675482e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
675582e05efaSJeff Layton 		return 0;
675682e05efaSJeff Layton 
675782e05efaSJeff Layton 	spin_lock(&nn->client_lock);
675882e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
675982e05efaSJeff Layton 		count += nfsd_print_client_openowners(clp);
676082e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
676182e05efaSJeff Layton 
676282e05efaSJeff Layton 	return count;
676382e05efaSJeff Layton }
676482e05efaSJeff Layton 
676582e05efaSJeff Layton static void
676682e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist)
676782e05efaSJeff Layton {
676882e05efaSJeff Layton 	struct nfs4_client *clp;
676982e05efaSJeff Layton 	struct nfs4_openowner *oop, *next;
677082e05efaSJeff Layton 
677182e05efaSJeff Layton 	list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
677282e05efaSJeff Layton 		list_del_init(&oop->oo_perclient);
677382e05efaSJeff Layton 		clp = oop->oo_owner.so_client;
677482e05efaSJeff Layton 		release_openowner(oop);
677582e05efaSJeff Layton 		put_client(clp);
677682e05efaSJeff Layton 	}
677782e05efaSJeff Layton }
677882e05efaSJeff Layton 
677982e05efaSJeff Layton u64
6780285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr,
6781285abdeeSJeff Layton 				     size_t addr_size)
678282e05efaSJeff Layton {
678382e05efaSJeff Layton 	unsigned int count = 0;
678482e05efaSJeff Layton 	struct nfs4_client *clp;
678582e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
678682e05efaSJeff Layton 						nfsd_net_id);
678782e05efaSJeff Layton 	LIST_HEAD(reaplist);
678882e05efaSJeff Layton 
678982e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
679082e05efaSJeff Layton 		return count;
679182e05efaSJeff Layton 
679282e05efaSJeff Layton 	spin_lock(&nn->client_lock);
679382e05efaSJeff Layton 	clp = nfsd_find_client(addr, addr_size);
679482e05efaSJeff Layton 	if (clp)
679582e05efaSJeff Layton 		count = nfsd_collect_client_openowners(clp, &reaplist, 0);
679682e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
679782e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
679882e05efaSJeff Layton 	return count;
679982e05efaSJeff Layton }
680082e05efaSJeff Layton 
680182e05efaSJeff Layton u64
6802285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max)
680382e05efaSJeff Layton {
680482e05efaSJeff Layton 	u64 count = 0;
680582e05efaSJeff Layton 	struct nfs4_client *clp;
680682e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
680782e05efaSJeff Layton 						nfsd_net_id);
680882e05efaSJeff Layton 	LIST_HEAD(reaplist);
680982e05efaSJeff Layton 
681082e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
681182e05efaSJeff Layton 		return count;
681282e05efaSJeff Layton 
681382e05efaSJeff Layton 	spin_lock(&nn->client_lock);
681482e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
681582e05efaSJeff Layton 		count += nfsd_collect_client_openowners(clp, &reaplist,
681682e05efaSJeff Layton 							max - count);
681782e05efaSJeff Layton 		if (max != 0 && count >= max)
681882e05efaSJeff Layton 			break;
681982e05efaSJeff Layton 	}
682082e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
682182e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
6822184c1847SBryan Schumaker 	return count;
6823184c1847SBryan Schumaker }
6824184c1847SBryan Schumaker 
6825269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
6826269de30fSBryan Schumaker 				     struct list_head *victims)
6827269de30fSBryan Schumaker {
6828269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
682998d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
683098d5c7c5SJeff Layton 						nfsd_net_id);
6831269de30fSBryan Schumaker 	u64 count = 0;
6832269de30fSBryan Schumaker 
683398d5c7c5SJeff Layton 	lockdep_assert_held(&nn->client_lock);
683498d5c7c5SJeff Layton 
683598d5c7c5SJeff Layton 	spin_lock(&state_lock);
6836269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
6837dff1399fSJeff Layton 		if (victims) {
6838dff1399fSJeff Layton 			/*
6839dff1399fSJeff Layton 			 * It's not safe to mess with delegations that have a
6840dff1399fSJeff Layton 			 * non-zero dl_time. They might have already been broken
6841dff1399fSJeff Layton 			 * and could be processed by the laundromat outside of
6842dff1399fSJeff Layton 			 * the state_lock. Just leave them be.
6843dff1399fSJeff Layton 			 */
6844dff1399fSJeff Layton 			if (dp->dl_time != 0)
6845dff1399fSJeff Layton 				continue;
6846dff1399fSJeff Layton 
684798d5c7c5SJeff Layton 			atomic_inc(&clp->cl_refcount);
68483fcbbd24SJeff Layton 			WARN_ON(!unhash_delegation_locked(dp));
684942690676SJeff Layton 			list_add(&dp->dl_recall_lru, victims);
6850dff1399fSJeff Layton 		}
685198d5c7c5SJeff Layton 		++count;
685298d5c7c5SJeff Layton 		/*
685398d5c7c5SJeff Layton 		 * Despite the fact that these functions deal with
685498d5c7c5SJeff Layton 		 * 64-bit integers for "count", we must ensure that
685598d5c7c5SJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
685698d5c7c5SJeff Layton 		 * warning if we start to approach INT_MAX here.
685798d5c7c5SJeff Layton 		 */
685898d5c7c5SJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
685998d5c7c5SJeff Layton 		if (count == max)
6860269de30fSBryan Schumaker 			break;
6861269de30fSBryan Schumaker 	}
686298d5c7c5SJeff Layton 	spin_unlock(&state_lock);
6863269de30fSBryan Schumaker 	return count;
6864269de30fSBryan Schumaker }
6865269de30fSBryan Schumaker 
686698d5c7c5SJeff Layton static u64
686798d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp)
6868269de30fSBryan Schumaker {
686998d5c7c5SJeff Layton 	u64 count = nfsd_find_all_delegations(clp, 0, NULL);
6870184c1847SBryan Schumaker 
6871184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "delegations");
6872184c1847SBryan Schumaker 	return count;
6873184c1847SBryan Schumaker }
6874184c1847SBryan Schumaker 
687598d5c7c5SJeff Layton u64
6876285abdeeSJeff Layton nfsd_inject_print_delegations(void)
687798d5c7c5SJeff Layton {
687898d5c7c5SJeff Layton 	struct nfs4_client *clp;
687998d5c7c5SJeff Layton 	u64 count = 0;
688098d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
688198d5c7c5SJeff Layton 						nfsd_net_id);
688298d5c7c5SJeff Layton 
688398d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
688498d5c7c5SJeff Layton 		return 0;
688598d5c7c5SJeff Layton 
688698d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
688798d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
688898d5c7c5SJeff Layton 		count += nfsd_print_client_delegations(clp);
688998d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
689098d5c7c5SJeff Layton 
689198d5c7c5SJeff Layton 	return count;
689298d5c7c5SJeff Layton }
689398d5c7c5SJeff Layton 
689498d5c7c5SJeff Layton static void
689598d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist)
689698d5c7c5SJeff Layton {
689798d5c7c5SJeff Layton 	struct nfs4_client *clp;
689898d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
689998d5c7c5SJeff Layton 
690098d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
690198d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
690298d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
690398d5c7c5SJeff Layton 		revoke_delegation(dp);
690498d5c7c5SJeff Layton 		put_client(clp);
690598d5c7c5SJeff Layton 	}
690698d5c7c5SJeff Layton }
690798d5c7c5SJeff Layton 
690898d5c7c5SJeff Layton u64
6909285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr,
6910285abdeeSJeff Layton 				      size_t addr_size)
691198d5c7c5SJeff Layton {
691298d5c7c5SJeff Layton 	u64 count = 0;
691398d5c7c5SJeff Layton 	struct nfs4_client *clp;
691498d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
691598d5c7c5SJeff Layton 						nfsd_net_id);
691698d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
691798d5c7c5SJeff Layton 
691898d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
691998d5c7c5SJeff Layton 		return count;
692098d5c7c5SJeff Layton 
692198d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
692298d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
692398d5c7c5SJeff Layton 	if (clp)
692498d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
692598d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
692698d5c7c5SJeff Layton 
692798d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
692898d5c7c5SJeff Layton 	return count;
692998d5c7c5SJeff Layton }
693098d5c7c5SJeff Layton 
693198d5c7c5SJeff Layton u64
6932285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max)
693398d5c7c5SJeff Layton {
693498d5c7c5SJeff Layton 	u64 count = 0;
693598d5c7c5SJeff Layton 	struct nfs4_client *clp;
693698d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
693798d5c7c5SJeff Layton 						nfsd_net_id);
693898d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
693998d5c7c5SJeff Layton 
694098d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
694198d5c7c5SJeff Layton 		return count;
694298d5c7c5SJeff Layton 
694398d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
694498d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
694598d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
694698d5c7c5SJeff Layton 		if (max != 0 && count >= max)
694798d5c7c5SJeff Layton 			break;
694898d5c7c5SJeff Layton 	}
694998d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
695098d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
695198d5c7c5SJeff Layton 	return count;
695298d5c7c5SJeff Layton }
695398d5c7c5SJeff Layton 
695498d5c7c5SJeff Layton static void
695598d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist)
695698d5c7c5SJeff Layton {
695798d5c7c5SJeff Layton 	struct nfs4_client *clp;
695898d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
695998d5c7c5SJeff Layton 
696098d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
696198d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
696298d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
696398d5c7c5SJeff Layton 		/*
696498d5c7c5SJeff Layton 		 * We skipped all entries that had a zero dl_time before,
696598d5c7c5SJeff Layton 		 * so we can now reset the dl_time back to 0. If a delegation
696698d5c7c5SJeff Layton 		 * break comes in now, then it won't make any difference since
696798d5c7c5SJeff Layton 		 * we're recalling it either way.
696898d5c7c5SJeff Layton 		 */
696998d5c7c5SJeff Layton 		spin_lock(&state_lock);
697098d5c7c5SJeff Layton 		dp->dl_time = 0;
697198d5c7c5SJeff Layton 		spin_unlock(&state_lock);
697298d5c7c5SJeff Layton 		nfsd_break_one_deleg(dp);
697398d5c7c5SJeff Layton 		put_client(clp);
697498d5c7c5SJeff Layton 	}
697598d5c7c5SJeff Layton }
697698d5c7c5SJeff Layton 
697798d5c7c5SJeff Layton u64
6978285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr,
697998d5c7c5SJeff Layton 				      size_t addr_size)
698098d5c7c5SJeff Layton {
698198d5c7c5SJeff Layton 	u64 count = 0;
698298d5c7c5SJeff Layton 	struct nfs4_client *clp;
698398d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
698498d5c7c5SJeff Layton 						nfsd_net_id);
698598d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
698698d5c7c5SJeff Layton 
698798d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
698898d5c7c5SJeff Layton 		return count;
698998d5c7c5SJeff Layton 
699098d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
699198d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
699298d5c7c5SJeff Layton 	if (clp)
699398d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
699498d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
699598d5c7c5SJeff Layton 
699698d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
699798d5c7c5SJeff Layton 	return count;
699898d5c7c5SJeff Layton }
699998d5c7c5SJeff Layton 
700098d5c7c5SJeff Layton u64
7001285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max)
700298d5c7c5SJeff Layton {
700398d5c7c5SJeff Layton 	u64 count = 0;
700498d5c7c5SJeff Layton 	struct nfs4_client *clp, *next;
700598d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
700698d5c7c5SJeff Layton 						nfsd_net_id);
700798d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
700898d5c7c5SJeff Layton 
700998d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
701098d5c7c5SJeff Layton 		return count;
701198d5c7c5SJeff Layton 
701298d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
701398d5c7c5SJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
701498d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
701598d5c7c5SJeff Layton 		if (max != 0 && ++count >= max)
701698d5c7c5SJeff Layton 			break;
701798d5c7c5SJeff Layton 	}
701898d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
701998d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
702098d5c7c5SJeff Layton 	return count;
702198d5c7c5SJeff Layton }
702265178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */
702365178db4SBryan Schumaker 
7024c2f1a551SMeelap Shah /*
7025c2f1a551SMeelap Shah  * Since the lifetime of a delegation isn't limited to that of an open, a
7026c2f1a551SMeelap Shah  * client may quite reasonably hang on to a delegation as long as it has
7027c2f1a551SMeelap Shah  * the inode cached.  This becomes an obvious problem the first time a
7028c2f1a551SMeelap Shah  * client's inode cache approaches the size of the server's total memory.
7029c2f1a551SMeelap Shah  *
7030c2f1a551SMeelap Shah  * For now we avoid this problem by imposing a hard limit on the number
7031c2f1a551SMeelap Shah  * of delegations, which varies according to the server's memory size.
7032c2f1a551SMeelap Shah  */
7033c2f1a551SMeelap Shah static void
7034c2f1a551SMeelap Shah set_max_delegations(void)
7035c2f1a551SMeelap Shah {
7036c2f1a551SMeelap Shah 	/*
7037c2f1a551SMeelap Shah 	 * Allow at most 4 delegations per megabyte of RAM.  Quick
7038c2f1a551SMeelap Shah 	 * estimates suggest that in the worst case (where every delegation
7039c2f1a551SMeelap Shah 	 * is for a different inode), a delegation could take about 1.5K,
7040c2f1a551SMeelap Shah 	 * giving a worst case usage of about 6% of memory.
7041c2f1a551SMeelap Shah 	 */
7042c2f1a551SMeelap Shah 	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
7043c2f1a551SMeelap Shah }
7044c2f1a551SMeelap Shah 
7045d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net)
70468daae4dcSStanislav Kinsbursky {
70478daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
70488daae4dcSStanislav Kinsbursky 	int i;
70498daae4dcSStanislav Kinsbursky 
70508daae4dcSStanislav Kinsbursky 	nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
70518daae4dcSStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
70528daae4dcSStanislav Kinsbursky 	if (!nn->conf_id_hashtbl)
7053382a62e7SStanislav Kinsbursky 		goto err;
70540a7ec377SStanislav Kinsbursky 	nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) *
70550a7ec377SStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
70560a7ec377SStanislav Kinsbursky 	if (!nn->unconf_id_hashtbl)
70570a7ec377SStanislav Kinsbursky 		goto err_unconf_id;
70581872de0eSStanislav Kinsbursky 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
70591872de0eSStanislav Kinsbursky 			SESSION_HASH_SIZE, GFP_KERNEL);
70601872de0eSStanislav Kinsbursky 	if (!nn->sessionid_hashtbl)
70611872de0eSStanislav Kinsbursky 		goto err_sessionid;
70628daae4dcSStanislav Kinsbursky 
7063382a62e7SStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
70648daae4dcSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
70650a7ec377SStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
7066382a62e7SStanislav Kinsbursky 	}
70671872de0eSStanislav Kinsbursky 	for (i = 0; i < SESSION_HASH_SIZE; i++)
70681872de0eSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
7069382a62e7SStanislav Kinsbursky 	nn->conf_name_tree = RB_ROOT;
7070a99454aaSStanislav Kinsbursky 	nn->unconf_name_tree = RB_ROOT;
70715ed58bb2SStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->client_lru);
707273758fedSStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->close_lru);
7073e8c69d17SJ. Bruce Fields 	INIT_LIST_HEAD(&nn->del_recall_lru);
7074c9a49628SStanislav Kinsbursky 	spin_lock_init(&nn->client_lock);
70758daae4dcSStanislav Kinsbursky 
70760cc11a61SJeff Layton 	spin_lock_init(&nn->blocked_locks_lock);
70770cc11a61SJeff Layton 	INIT_LIST_HEAD(&nn->blocked_locks_lru);
70780cc11a61SJeff Layton 
707909121281SStanislav Kinsbursky 	INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
7080d85ed443SStanislav Kinsbursky 	get_net(net);
708109121281SStanislav Kinsbursky 
70828daae4dcSStanislav Kinsbursky 	return 0;
7083382a62e7SStanislav Kinsbursky 
70841872de0eSStanislav Kinsbursky err_sessionid:
70859b531137SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
70860a7ec377SStanislav Kinsbursky err_unconf_id:
70870a7ec377SStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
7088382a62e7SStanislav Kinsbursky err:
7089382a62e7SStanislav Kinsbursky 	return -ENOMEM;
70908daae4dcSStanislav Kinsbursky }
70918daae4dcSStanislav Kinsbursky 
70928daae4dcSStanislav Kinsbursky static void
70934dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net)
70948daae4dcSStanislav Kinsbursky {
70958daae4dcSStanislav Kinsbursky 	int i;
70968daae4dcSStanislav Kinsbursky 	struct nfs4_client *clp = NULL;
70978daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
70988daae4dcSStanislav Kinsbursky 
70998daae4dcSStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
71008daae4dcSStanislav Kinsbursky 		while (!list_empty(&nn->conf_id_hashtbl[i])) {
71018daae4dcSStanislav Kinsbursky 			clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
71028daae4dcSStanislav Kinsbursky 			destroy_client(clp);
71038daae4dcSStanislav Kinsbursky 		}
71048daae4dcSStanislav Kinsbursky 	}
7105a99454aaSStanislav Kinsbursky 
71062b905635SKinglong Mee 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
71072b905635SKinglong Mee 		while (!list_empty(&nn->unconf_id_hashtbl[i])) {
71082b905635SKinglong Mee 			clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
7109a99454aaSStanislav Kinsbursky 			destroy_client(clp);
7110a99454aaSStanislav Kinsbursky 		}
71112b905635SKinglong Mee 	}
7112a99454aaSStanislav Kinsbursky 
71131872de0eSStanislav Kinsbursky 	kfree(nn->sessionid_hashtbl);
71140a7ec377SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
71158daae4dcSStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
71164dce0ac9SStanislav Kinsbursky 	put_net(net);
71178daae4dcSStanislav Kinsbursky }
71188daae4dcSStanislav Kinsbursky 
7119f252bc68SStanislav Kinsbursky int
7120d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net)
7121ac4d8ff2SNeilBrown {
71225e1533c7SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
7123b5a1a81eSJ. Bruce Fields 	int ret;
7124b5a1a81eSJ. Bruce Fields 
7125d85ed443SStanislav Kinsbursky 	ret = nfs4_state_create_net(net);
71268daae4dcSStanislav Kinsbursky 	if (ret)
71278daae4dcSStanislav Kinsbursky 		return ret;
71282c142baaSStanislav Kinsbursky 	nn->boot_time = get_seconds();
7129a51c84edSStanislav Kinsbursky 	nn->grace_ended = false;
7130c87fb4a3SJ. Bruce Fields 	nn->nfsd4_manager.block_opens = true;
7131d4318acdSJeff Layton 	locks_start_grace(net, &nn->nfsd4_manager);
7132d4318acdSJeff Layton 	nfsd4_client_tracking_init(net);
71337e981a8aSVasily Averin 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n",
71347e981a8aSVasily Averin 	       nn->nfsd4_grace, net->ns.inum);
71355284b44eSStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
7136d85ed443SStanislav Kinsbursky 	return 0;
7137a6d6b781SJeff Layton }
7138d85ed443SStanislav Kinsbursky 
7139d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */
7140d85ed443SStanislav Kinsbursky 
7141d85ed443SStanislav Kinsbursky int
7142d85ed443SStanislav Kinsbursky nfs4_state_start(void)
7143d85ed443SStanislav Kinsbursky {
7144d85ed443SStanislav Kinsbursky 	int ret;
7145d85ed443SStanislav Kinsbursky 
7146d85ed443SStanislav Kinsbursky 	ret = set_callback_cred();
7147d85ed443SStanislav Kinsbursky 	if (ret)
7148f7d1ddbeSKinglong Mee 		return ret;
7149f7d1ddbeSKinglong Mee 
715051a54568SJeff Layton 	laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
7151a6d6b781SJeff Layton 	if (laundry_wq == NULL) {
7152a6d6b781SJeff Layton 		ret = -ENOMEM;
7153f7d1ddbeSKinglong Mee 		goto out_cleanup_cred;
7154a6d6b781SJeff Layton 	}
7155b5a1a81eSJ. Bruce Fields 	ret = nfsd4_create_callback_queue();
7156b5a1a81eSJ. Bruce Fields 	if (ret)
7157b5a1a81eSJ. Bruce Fields 		goto out_free_laundry;
715809121281SStanislav Kinsbursky 
7159c2f1a551SMeelap Shah 	set_max_delegations();
7160b5a1a81eSJ. Bruce Fields 	return 0;
7161d85ed443SStanislav Kinsbursky 
7162b5a1a81eSJ. Bruce Fields out_free_laundry:
7163b5a1a81eSJ. Bruce Fields 	destroy_workqueue(laundry_wq);
7164f7d1ddbeSKinglong Mee out_cleanup_cred:
7165f7d1ddbeSKinglong Mee 	cleanup_callback_cred();
7166b5a1a81eSJ. Bruce Fields 	return ret;
71671da177e4SLinus Torvalds }
71681da177e4SLinus Torvalds 
7169f252bc68SStanislav Kinsbursky void
71704dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net)
71711da177e4SLinus Torvalds {
71721da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
71731da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
71744dce0ac9SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
71757919d0a2SJeff Layton 	struct nfsd4_blocked_lock *nbl;
71761da177e4SLinus Torvalds 
71774dce0ac9SStanislav Kinsbursky 	cancel_delayed_work_sync(&nn->laundromat_work);
71784dce0ac9SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
7179ac55fdc4SJeff Layton 
71801da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
7181cdc97505SBenny Halevy 	spin_lock(&state_lock);
7182e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
71831da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
71843fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
718542690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
71861da177e4SLinus Torvalds 	}
7187cdc97505SBenny Halevy 	spin_unlock(&state_lock);
71881da177e4SLinus Torvalds 	list_for_each_safe(pos, next, &reaplist) {
71891da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
719042690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
71918287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
7192afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
71936011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
71941da177e4SLinus Torvalds 	}
71951da177e4SLinus Torvalds 
71967919d0a2SJeff Layton 	BUG_ON(!list_empty(&reaplist));
71970cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
71987919d0a2SJeff Layton 	while (!list_empty(&nn->blocked_locks_lru)) {
71997919d0a2SJeff Layton 		nbl = list_first_entry(&nn->blocked_locks_lru,
72007919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
72017919d0a2SJeff Layton 		list_move(&nbl->nbl_lru, &reaplist);
72027919d0a2SJeff Layton 		list_del_init(&nbl->nbl_list);
72037919d0a2SJeff Layton 	}
72040cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
72057919d0a2SJeff Layton 
72067919d0a2SJeff Layton 	while (!list_empty(&reaplist)) {
72077919d0a2SJeff Layton 		nbl = list_first_entry(&nn->blocked_locks_lru,
72087919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
72097919d0a2SJeff Layton 		list_del_init(&nbl->nbl_lru);
72107919d0a2SJeff Layton 		posix_unblock_lock(&nbl->nbl_lock);
72117919d0a2SJeff Layton 		free_blocked_lock(nbl);
72127919d0a2SJeff Layton 	}
72137919d0a2SJeff Layton 
72143320fef1SStanislav Kinsbursky 	nfsd4_client_tracking_exit(net);
72154dce0ac9SStanislav Kinsbursky 	nfs4_state_destroy_net(net);
72161da177e4SLinus Torvalds }
72171da177e4SLinus Torvalds 
72181da177e4SLinus Torvalds void
72191da177e4SLinus Torvalds nfs4_state_shutdown(void)
72201da177e4SLinus Torvalds {
72215e8d5c29SNeilBrown 	destroy_workqueue(laundry_wq);
7222c3935e30SJ. Bruce Fields 	nfsd4_destroy_callback_queue();
7223f7d1ddbeSKinglong Mee 	cleanup_callback_cred();
72241da177e4SLinus Torvalds }
72258b70484cSTigran Mkrtchyan 
72268b70484cSTigran Mkrtchyan static void
72278b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
72288b70484cSTigran Mkrtchyan {
722937c593c5STigran Mkrtchyan 	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
723037c593c5STigran Mkrtchyan 		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
72318b70484cSTigran Mkrtchyan }
72328b70484cSTigran Mkrtchyan 
72338b70484cSTigran Mkrtchyan static void
72348b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
72358b70484cSTigran Mkrtchyan {
723637c593c5STigran Mkrtchyan 	if (cstate->minorversion) {
723737c593c5STigran Mkrtchyan 		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
723837c593c5STigran Mkrtchyan 		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
723937c593c5STigran Mkrtchyan 	}
724037c593c5STigran Mkrtchyan }
724137c593c5STigran Mkrtchyan 
724237c593c5STigran Mkrtchyan void
724337c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate)
724437c593c5STigran Mkrtchyan {
724537c593c5STigran Mkrtchyan 	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
72468b70484cSTigran Mkrtchyan }
72478b70484cSTigran Mkrtchyan 
724862cd4a59STigran Mkrtchyan /*
724962cd4a59STigran Mkrtchyan  * functions to set current state id
725062cd4a59STigran Mkrtchyan  */
72518b70484cSTigran Mkrtchyan void
7252b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate,
7253b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
72549428fe1aSTigran Mkrtchyan {
7255b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->open_downgrade.od_stateid);
72569428fe1aSTigran Mkrtchyan }
72579428fe1aSTigran Mkrtchyan 
72589428fe1aSTigran Mkrtchyan void
7259b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate,
7260b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
72618b70484cSTigran Mkrtchyan {
7262b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->open.op_stateid);
72638b70484cSTigran Mkrtchyan }
72648b70484cSTigran Mkrtchyan 
72658b70484cSTigran Mkrtchyan void
7266b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate,
7267b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
726862cd4a59STigran Mkrtchyan {
7269b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->close.cl_stateid);
727062cd4a59STigran Mkrtchyan }
727162cd4a59STigran Mkrtchyan 
727262cd4a59STigran Mkrtchyan void
7273b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate,
7274b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
727562cd4a59STigran Mkrtchyan {
7276b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->lock.lk_resp_stateid);
727762cd4a59STigran Mkrtchyan }
727862cd4a59STigran Mkrtchyan 
727962cd4a59STigran Mkrtchyan /*
728062cd4a59STigran Mkrtchyan  * functions to consume current state id
728162cd4a59STigran Mkrtchyan  */
72821e97b519STigran Mkrtchyan 
72831e97b519STigran Mkrtchyan void
728457832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate,
728557832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
72869428fe1aSTigran Mkrtchyan {
728757832e7bSChristoph Hellwig 	get_stateid(cstate, &u->open_downgrade.od_stateid);
72889428fe1aSTigran Mkrtchyan }
72899428fe1aSTigran Mkrtchyan 
72909428fe1aSTigran Mkrtchyan void
729157832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate,
729257832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
72939428fe1aSTigran Mkrtchyan {
729457832e7bSChristoph Hellwig 	get_stateid(cstate, &u->delegreturn.dr_stateid);
72959428fe1aSTigran Mkrtchyan }
72969428fe1aSTigran Mkrtchyan 
72979428fe1aSTigran Mkrtchyan void
729857832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate,
729957832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73001e97b519STigran Mkrtchyan {
730157832e7bSChristoph Hellwig 	get_stateid(cstate, &u->free_stateid.fr_stateid);
73021e97b519STigran Mkrtchyan }
73031e97b519STigran Mkrtchyan 
73041e97b519STigran Mkrtchyan void
730557832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate,
730657832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73071e97b519STigran Mkrtchyan {
730857832e7bSChristoph Hellwig 	get_stateid(cstate, &u->setattr.sa_stateid);
73091e97b519STigran Mkrtchyan }
73101e97b519STigran Mkrtchyan 
731162cd4a59STigran Mkrtchyan void
731257832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate,
731357832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73148b70484cSTigran Mkrtchyan {
731557832e7bSChristoph Hellwig 	get_stateid(cstate, &u->close.cl_stateid);
73168b70484cSTigran Mkrtchyan }
73178b70484cSTigran Mkrtchyan 
73188b70484cSTigran Mkrtchyan void
731957832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate,
732057832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73218b70484cSTigran Mkrtchyan {
732257832e7bSChristoph Hellwig 	get_stateid(cstate, &u->locku.lu_stateid);
73238b70484cSTigran Mkrtchyan }
732430813e27STigran Mkrtchyan 
732530813e27STigran Mkrtchyan void
732657832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate,
732757832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
732830813e27STigran Mkrtchyan {
732957832e7bSChristoph Hellwig 	get_stateid(cstate, &u->read.rd_stateid);
733030813e27STigran Mkrtchyan }
733130813e27STigran Mkrtchyan 
733230813e27STigran Mkrtchyan void
733357832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
733457832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
733530813e27STigran Mkrtchyan {
733657832e7bSChristoph Hellwig 	get_stateid(cstate, &u->write.wr_stateid);
733730813e27STigran Mkrtchyan }
7338