xref: /openbmc/linux/fs/nfsd/nfs4state.c (revision 25020720)
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 };
66fb500a7cSTrond Myklebust static const stateid_t close_stateid = {
67fb500a7cSTrond Myklebust 	.si_generation = 0xffffffffU,
68fb500a7cSTrond Myklebust };
69f32f3c2dSJ. Bruce Fields 
70ec6b5d7bSAndy Adamson static u64 current_sessionid = 1;
71fd39ca9aSNeilBrown 
72f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
73f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
7419ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
75ae254dacSAndrew Elble #define CLOSE_STATEID(stateid)  (!memcmp((stateid), &close_stateid, sizeof(stateid_t)))
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds /* forward declarations */
78f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
796011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
801da177e4SLinus Torvalds 
818b671b80SJ. Bruce Fields /* Locking: */
828b671b80SJ. Bruce Fields 
838b671b80SJ. Bruce Fields /*
848b671b80SJ. Bruce Fields  * Currently used for the del_recall_lru and file hash table.  In an
858b671b80SJ. Bruce Fields  * effort to decrease the scope of the client_mutex, this spinlock may
868b671b80SJ. Bruce Fields  * eventually cover more:
878b671b80SJ. Bruce Fields  */
88cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock);
898b671b80SJ. Bruce Fields 
904f34bd05SAndrew Elble enum nfsd4_st_mutex_lock_subclass {
914f34bd05SAndrew Elble 	OPEN_STATEID_MUTEX = 0,
924f34bd05SAndrew Elble 	LOCK_STATEID_MUTEX = 1,
934f34bd05SAndrew Elble };
944f34bd05SAndrew Elble 
95b401be22SJeff Layton /*
96b401be22SJeff Layton  * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for
97b401be22SJeff Layton  * the refcount on the open stateid to drop.
98b401be22SJeff Layton  */
99b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq);
100b401be22SJeff Layton 
101abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab;
102abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab;
103abf1135bSChristoph Hellwig static struct kmem_cache *file_slab;
104abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab;
105abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab;
1068287f009SSachin Bhamare static struct kmem_cache *odstate_slab;
107e60d4398SNeilBrown 
10866b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *);
109508dc6e1SBenny Halevy 
110c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
11176d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;
1120162ac2bSChristoph Hellwig 
11366b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses)
114508dc6e1SBenny Halevy {
11566b2b9b2SJ. Bruce Fields 	return ses->se_flags & NFS4_SESSION_DEAD;
11666b2b9b2SJ. Bruce Fields }
11766b2b9b2SJ. Bruce Fields 
118f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
119f0f51f5cSJ. Bruce Fields {
120f0f51f5cSJ. Bruce Fields 	if (atomic_read(&ses->se_ref) > ref_held_by_me)
12166b2b9b2SJ. Bruce Fields 		return nfserr_jukebox;
12266b2b9b2SJ. Bruce Fields 	ses->se_flags |= NFS4_SESSION_DEAD;
12366b2b9b2SJ. Bruce Fields 	return nfs_ok;
12466b2b9b2SJ. Bruce Fields }
12566b2b9b2SJ. Bruce Fields 
126221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp)
127221a6876SJ. Bruce Fields {
128221a6876SJ. Bruce Fields 	return clp->cl_time == 0;
129221a6876SJ. Bruce Fields }
130221a6876SJ. Bruce Fields 
131221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp)
132221a6876SJ. Bruce Fields {
1330a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1340a880a28STrond Myklebust 
1350a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1360a880a28STrond Myklebust 
137221a6876SJ. Bruce Fields 	if (is_client_expired(clp))
138221a6876SJ. Bruce Fields 		return nfserr_expired;
139221a6876SJ. Bruce Fields 	atomic_inc(&clp->cl_refcount);
140221a6876SJ. Bruce Fields 	return nfs_ok;
141221a6876SJ. Bruce Fields }
142221a6876SJ. Bruce Fields 
143221a6876SJ. Bruce Fields /* must be called under the client_lock */
144221a6876SJ. Bruce Fields static inline void
145221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp)
146221a6876SJ. Bruce Fields {
147221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
148221a6876SJ. Bruce Fields 
149221a6876SJ. Bruce Fields 	if (is_client_expired(clp)) {
150221a6876SJ. Bruce Fields 		WARN_ON(1);
151221a6876SJ. Bruce Fields 		printk("%s: client (clientid %08x/%08x) already expired\n",
152221a6876SJ. Bruce Fields 			__func__,
153221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
154221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
155221a6876SJ. Bruce Fields 		return;
156221a6876SJ. Bruce Fields 	}
157221a6876SJ. Bruce Fields 
158221a6876SJ. Bruce Fields 	dprintk("renewing client (clientid %08x/%08x)\n",
159221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
160221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
161221a6876SJ. Bruce Fields 	list_move_tail(&clp->cl_lru, &nn->client_lru);
162221a6876SJ. Bruce Fields 	clp->cl_time = get_seconds();
163221a6876SJ. Bruce Fields }
164221a6876SJ. Bruce Fields 
165ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp)
166221a6876SJ. Bruce Fields {
1670a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1680a880a28STrond Myklebust 
1690a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1700a880a28STrond Myklebust 
171221a6876SJ. Bruce Fields 	if (!atomic_dec_and_test(&clp->cl_refcount))
172221a6876SJ. Bruce Fields 		return;
173221a6876SJ. Bruce Fields 	if (!is_client_expired(clp))
174221a6876SJ. Bruce Fields 		renew_client_locked(clp);
175221a6876SJ. Bruce Fields }
176221a6876SJ. Bruce Fields 
1774b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp)
1784b24ca7dSJeff Layton {
1794b24ca7dSJeff Layton 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1804b24ca7dSJeff Layton 
181d6c249b4SJeff Layton 	if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
182d6c249b4SJeff Layton 		return;
183d6c249b4SJeff Layton 	if (!is_client_expired(clp))
184d6c249b4SJeff Layton 		renew_client_locked(clp);
1854b24ca7dSJeff Layton 	spin_unlock(&nn->client_lock);
1864b24ca7dSJeff Layton }
1874b24ca7dSJeff Layton 
188d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
189d4e19e70STrond Myklebust {
190d4e19e70STrond Myklebust 	__be32 status;
191d4e19e70STrond Myklebust 
192d4e19e70STrond Myklebust 	if (is_session_dead(ses))
193d4e19e70STrond Myklebust 		return nfserr_badsession;
194d4e19e70STrond Myklebust 	status = get_client_locked(ses->se_client);
195d4e19e70STrond Myklebust 	if (status)
196d4e19e70STrond Myklebust 		return status;
197d4e19e70STrond Myklebust 	atomic_inc(&ses->se_ref);
198d4e19e70STrond Myklebust 	return nfs_ok;
199d4e19e70STrond Myklebust }
200d4e19e70STrond Myklebust 
201d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses)
202d4e19e70STrond Myklebust {
203d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
2040a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2050a880a28STrond Myklebust 
2060a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
207d4e19e70STrond Myklebust 
208d4e19e70STrond Myklebust 	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
209d4e19e70STrond Myklebust 		free_session(ses);
210d4e19e70STrond Myklebust 	put_client_renew_locked(clp);
211d4e19e70STrond Myklebust }
212d4e19e70STrond Myklebust 
213d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses)
214d4e19e70STrond Myklebust {
215d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
216d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
217d4e19e70STrond Myklebust 
218d4e19e70STrond Myklebust 	spin_lock(&nn->client_lock);
219d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
220d4e19e70STrond Myklebust 	spin_unlock(&nn->client_lock);
221d4e19e70STrond Myklebust }
222d4e19e70STrond Myklebust 
22376d348faSJeff Layton static struct nfsd4_blocked_lock *
22476d348faSJeff Layton find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
22576d348faSJeff Layton 			struct nfsd_net *nn)
22676d348faSJeff Layton {
22776d348faSJeff Layton 	struct nfsd4_blocked_lock *cur, *found = NULL;
22876d348faSJeff Layton 
2290cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
23076d348faSJeff Layton 	list_for_each_entry(cur, &lo->lo_blocked, nbl_list) {
23176d348faSJeff Layton 		if (fh_match(fh, &cur->nbl_fh)) {
23276d348faSJeff Layton 			list_del_init(&cur->nbl_list);
2337919d0a2SJeff Layton 			list_del_init(&cur->nbl_lru);
23476d348faSJeff Layton 			found = cur;
23576d348faSJeff Layton 			break;
23676d348faSJeff Layton 		}
23776d348faSJeff Layton 	}
2380cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
23976d348faSJeff Layton 	if (found)
24076d348faSJeff Layton 		posix_unblock_lock(&found->nbl_lock);
24176d348faSJeff Layton 	return found;
24276d348faSJeff Layton }
24376d348faSJeff Layton 
24476d348faSJeff Layton static struct nfsd4_blocked_lock *
24576d348faSJeff Layton find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
24676d348faSJeff Layton 			struct nfsd_net *nn)
24776d348faSJeff Layton {
24876d348faSJeff Layton 	struct nfsd4_blocked_lock *nbl;
24976d348faSJeff Layton 
25076d348faSJeff Layton 	nbl = find_blocked_lock(lo, fh, nn);
25176d348faSJeff Layton 	if (!nbl) {
25276d348faSJeff Layton 		nbl= kmalloc(sizeof(*nbl), GFP_KERNEL);
25376d348faSJeff Layton 		if (nbl) {
25476d348faSJeff Layton 			fh_copy_shallow(&nbl->nbl_fh, fh);
25576d348faSJeff Layton 			locks_init_lock(&nbl->nbl_lock);
25676d348faSJeff Layton 			nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client,
25776d348faSJeff Layton 					&nfsd4_cb_notify_lock_ops,
25876d348faSJeff Layton 					NFSPROC4_CLNT_CB_NOTIFY_LOCK);
25976d348faSJeff Layton 		}
26076d348faSJeff Layton 	}
26176d348faSJeff Layton 	return nbl;
26276d348faSJeff Layton }
26376d348faSJeff Layton 
26476d348faSJeff Layton static void
26576d348faSJeff Layton free_blocked_lock(struct nfsd4_blocked_lock *nbl)
26676d348faSJeff Layton {
26776d348faSJeff Layton 	locks_release_private(&nbl->nbl_lock);
26876d348faSJeff Layton 	kfree(nbl);
26976d348faSJeff Layton }
27076d348faSJeff Layton 
27176d348faSJeff Layton static int
27276d348faSJeff Layton nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task)
27376d348faSJeff Layton {
27476d348faSJeff Layton 	/*
27576d348faSJeff Layton 	 * Since this is just an optimization, we don't try very hard if it
27676d348faSJeff Layton 	 * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and
27776d348faSJeff Layton 	 * just quit trying on anything else.
27876d348faSJeff Layton 	 */
27976d348faSJeff Layton 	switch (task->tk_status) {
28076d348faSJeff Layton 	case -NFS4ERR_DELAY:
28176d348faSJeff Layton 		rpc_delay(task, 1 * HZ);
28276d348faSJeff Layton 		return 0;
28376d348faSJeff Layton 	default:
28476d348faSJeff Layton 		return 1;
28576d348faSJeff Layton 	}
28676d348faSJeff Layton }
28776d348faSJeff Layton 
28876d348faSJeff Layton static void
28976d348faSJeff Layton nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb)
29076d348faSJeff Layton {
29176d348faSJeff Layton 	struct nfsd4_blocked_lock	*nbl = container_of(cb,
29276d348faSJeff Layton 						struct nfsd4_blocked_lock, nbl_cb);
29376d348faSJeff Layton 
29476d348faSJeff Layton 	free_blocked_lock(nbl);
29576d348faSJeff Layton }
29676d348faSJeff Layton 
29776d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = {
29876d348faSJeff Layton 	.done		= nfsd4_cb_notify_lock_done,
29976d348faSJeff Layton 	.release	= nfsd4_cb_notify_lock_release,
30076d348faSJeff Layton };
30176d348faSJeff Layton 
302b5971afaSKinglong Mee static inline struct nfs4_stateowner *
303b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop)
304b5971afaSKinglong Mee {
305b5971afaSKinglong Mee 	atomic_inc(&sop->so_count);
306b5971afaSKinglong Mee 	return sop;
307b5971afaSKinglong Mee }
308b5971afaSKinglong Mee 
3097ffb5880STrond Myklebust static int
310d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
3117ffb5880STrond Myklebust {
3127ffb5880STrond Myklebust 	return (sop->so_owner.len == owner->len) &&
313d4f0489fSTrond Myklebust 		0 == memcmp(sop->so_owner.data, owner->data, owner->len);
3147ffb5880STrond Myklebust }
3157ffb5880STrond Myklebust 
3167ffb5880STrond Myklebust static struct nfs4_openowner *
3177ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
318d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
3197ffb5880STrond Myklebust {
3207ffb5880STrond Myklebust 	struct nfs4_stateowner *so;
3217ffb5880STrond Myklebust 
322d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
3237ffb5880STrond Myklebust 
324d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval],
325d4f0489fSTrond Myklebust 			    so_strhash) {
3267ffb5880STrond Myklebust 		if (!so->so_is_open_owner)
3277ffb5880STrond Myklebust 			continue;
328b5971afaSKinglong Mee 		if (same_owner_str(so, &open->op_owner))
329b5971afaSKinglong Mee 			return openowner(nfs4_get_stateowner(so));
3307ffb5880STrond Myklebust 	}
3317ffb5880STrond Myklebust 	return NULL;
3327ffb5880STrond Myklebust }
3337ffb5880STrond Myklebust 
3347ffb5880STrond Myklebust static struct nfs4_openowner *
3357ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
336d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
3377ffb5880STrond Myklebust {
3387ffb5880STrond Myklebust 	struct nfs4_openowner *oo;
3397ffb5880STrond Myklebust 
340d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
341d4f0489fSTrond Myklebust 	oo = find_openstateowner_str_locked(hashval, open, clp);
342d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
3437ffb5880STrond Myklebust 	return oo;
3447ffb5880STrond Myklebust }
3457ffb5880STrond Myklebust 
3461da177e4SLinus Torvalds static inline u32
3471da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes)
3481da177e4SLinus Torvalds {
3491da177e4SLinus Torvalds 	unsigned char *cptr = (unsigned char *) ptr;
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	u32 x = 0;
3521da177e4SLinus Torvalds 	while (nbytes--) {
3531da177e4SLinus Torvalds 		x *= 37;
3541da177e4SLinus Torvalds 		x += *cptr++;
3551da177e4SLinus Torvalds 	}
3561da177e4SLinus Torvalds 	return x;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds 
3595b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu)
36032513b40SJ. Bruce Fields {
3615b095e99SJeff Layton 	struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu);
3625b095e99SJeff Layton 
3635b095e99SJeff Layton 	kmem_cache_free(file_slab, fp);
36432513b40SJ. Bruce Fields }
36532513b40SJ. Bruce Fields 
366e6ba76e1SChristoph Hellwig void
36713cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi)
36813cd2184SNeilBrown {
36902e1215fSJeff Layton 	might_lock(&state_lock);
37002e1215fSJeff Layton 
371818a34ebSElena Reshetova 	if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) {
3725b095e99SJeff Layton 		hlist_del_rcu(&fi->fi_hash);
373cdc97505SBenny Halevy 		spin_unlock(&state_lock);
3748287f009SSachin Bhamare 		WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
3755b095e99SJeff Layton 		WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
3765b095e99SJeff Layton 		call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
3778b671b80SJ. Bruce Fields 	}
37813cd2184SNeilBrown }
37913cd2184SNeilBrown 
380de18643dSTrond Myklebust static struct file *
381de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag)
382de18643dSTrond Myklebust {
383de18643dSTrond Myklebust 	if (f->fi_fds[oflag])
384de18643dSTrond Myklebust 		return get_file(f->fi_fds[oflag]);
385de18643dSTrond Myklebust 	return NULL;
386de18643dSTrond Myklebust }
387de18643dSTrond Myklebust 
388de18643dSTrond Myklebust static struct file *
389de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f)
390de18643dSTrond Myklebust {
391de18643dSTrond Myklebust 	struct file *ret;
392de18643dSTrond Myklebust 
393de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
394de18643dSTrond Myklebust 
395de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_WRONLY);
396de18643dSTrond Myklebust 	if (!ret)
397de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
398de18643dSTrond Myklebust 	return ret;
399de18643dSTrond Myklebust }
400de18643dSTrond Myklebust 
401de18643dSTrond Myklebust static struct file *
402de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f)
403de18643dSTrond Myklebust {
404de18643dSTrond Myklebust 	struct file *ret;
405de18643dSTrond Myklebust 
406de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
407de18643dSTrond Myklebust 	ret = find_writeable_file_locked(f);
408de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
409de18643dSTrond Myklebust 
410de18643dSTrond Myklebust 	return ret;
411de18643dSTrond Myklebust }
412de18643dSTrond Myklebust 
413de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f)
414de18643dSTrond Myklebust {
415de18643dSTrond Myklebust 	struct file *ret;
416de18643dSTrond Myklebust 
417de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
418de18643dSTrond Myklebust 
419de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDONLY);
420de18643dSTrond Myklebust 	if (!ret)
421de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
422de18643dSTrond Myklebust 	return ret;
423de18643dSTrond Myklebust }
424de18643dSTrond Myklebust 
425de18643dSTrond Myklebust static struct file *
426de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f)
427de18643dSTrond Myklebust {
428de18643dSTrond Myklebust 	struct file *ret;
429de18643dSTrond Myklebust 
430de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
431de18643dSTrond Myklebust 	ret = find_readable_file_locked(f);
432de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
433de18643dSTrond Myklebust 
434de18643dSTrond Myklebust 	return ret;
435de18643dSTrond Myklebust }
436de18643dSTrond Myklebust 
4374d227fcaSChristoph Hellwig struct file *
438de18643dSTrond Myklebust find_any_file(struct nfs4_file *f)
439de18643dSTrond Myklebust {
440de18643dSTrond Myklebust 	struct file *ret;
441de18643dSTrond Myklebust 
442de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
443de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDWR);
444de18643dSTrond Myklebust 	if (!ret) {
445de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_WRONLY);
446de18643dSTrond Myklebust 		if (!ret)
447de18643dSTrond Myklebust 			ret = __nfs4_get_fd(f, O_RDONLY);
448de18643dSTrond Myklebust 	}
449de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
450de18643dSTrond Myklebust 	return ret;
451de18643dSTrond Myklebust }
452de18643dSTrond Myklebust 
45302a3508dSTrond Myklebust static atomic_long_t num_delegations;
454697ce9beSZhang Yanfei unsigned long max_delegations;
455ef0f3390SNeilBrown 
456ef0f3390SNeilBrown /*
457ef0f3390SNeilBrown  * Open owner state (share locks)
458ef0f3390SNeilBrown  */
459ef0f3390SNeilBrown 
46016bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */
46116bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS              8
46216bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
46316bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
464ef0f3390SNeilBrown 
465d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername)
466ddc04c41SJ. Bruce Fields {
467ddc04c41SJ. Bruce Fields 	unsigned int ret;
468ddc04c41SJ. Bruce Fields 
469ddc04c41SJ. Bruce Fields 	ret = opaque_hashval(ownername->data, ownername->len);
47016bfdaafSJ. Bruce Fields 	return ret & OWNER_HASH_MASK;
471ddc04c41SJ. Bruce Fields }
472ef0f3390SNeilBrown 
473ef0f3390SNeilBrown /* hash table for nfs4_file */
474ef0f3390SNeilBrown #define FILE_HASH_BITS                   8
475ef0f3390SNeilBrown #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
47635079582SShan Wei 
477ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh)
478ddc04c41SJ. Bruce Fields {
479ca943217STrond Myklebust 	return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0);
480ca943217STrond Myklebust }
481ca943217STrond Myklebust 
482ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh)
483ca943217STrond Myklebust {
484ca943217STrond Myklebust 	return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1);
485ca943217STrond Myklebust }
486ca943217STrond Myklebust 
48789876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
488ef0f3390SNeilBrown 
48912659651SJeff Layton static void
49012659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
4913477565eSJ. Bruce Fields {
4927214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4937214e860SJeff Layton 
49412659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
49512659651SJeff Layton 		atomic_inc(&fp->fi_access[O_WRONLY]);
49612659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
49712659651SJeff Layton 		atomic_inc(&fp->fi_access[O_RDONLY]);
4983477565eSJ. Bruce Fields }
4993477565eSJ. Bruce Fields 
50012659651SJeff Layton static __be32
50112659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access)
502998db52cSJ. Bruce Fields {
5037214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
5047214e860SJeff Layton 
50512659651SJeff Layton 	/* Does this access mode make sense? */
50612659651SJeff Layton 	if (access & ~NFS4_SHARE_ACCESS_BOTH)
50712659651SJeff Layton 		return nfserr_inval;
50812659651SJeff Layton 
509baeb4ff0SJeff Layton 	/* Does it conflict with a deny mode already set? */
510baeb4ff0SJeff Layton 	if ((access & fp->fi_share_deny) != 0)
511baeb4ff0SJeff Layton 		return nfserr_share_denied;
512baeb4ff0SJeff Layton 
51312659651SJeff Layton 	__nfs4_file_get_access(fp, access);
51412659651SJeff Layton 	return nfs_ok;
515998db52cSJ. Bruce Fields }
516998db52cSJ. Bruce Fields 
517baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny)
518baeb4ff0SJeff Layton {
519baeb4ff0SJeff Layton 	/* Common case is that there is no deny mode. */
520baeb4ff0SJeff Layton 	if (deny) {
521baeb4ff0SJeff Layton 		/* Does this deny mode make sense? */
522baeb4ff0SJeff Layton 		if (deny & ~NFS4_SHARE_DENY_BOTH)
523baeb4ff0SJeff Layton 			return nfserr_inval;
524baeb4ff0SJeff Layton 
525baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_READ) &&
526baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_RDONLY]))
527baeb4ff0SJeff Layton 			return nfserr_share_denied;
528baeb4ff0SJeff Layton 
529baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_WRITE) &&
530baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_WRONLY]))
531baeb4ff0SJeff Layton 			return nfserr_share_denied;
532baeb4ff0SJeff Layton 	}
533baeb4ff0SJeff Layton 	return nfs_ok;
534baeb4ff0SJeff Layton }
535baeb4ff0SJeff Layton 
536998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
537f9d7562fSJ. Bruce Fields {
538de18643dSTrond Myklebust 	might_lock(&fp->fi_lock);
539de18643dSTrond Myklebust 
540de18643dSTrond Myklebust 	if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) {
541de18643dSTrond Myklebust 		struct file *f1 = NULL;
542de18643dSTrond Myklebust 		struct file *f2 = NULL;
543de18643dSTrond Myklebust 
5446d338b51SJeff Layton 		swap(f1, fp->fi_fds[oflag]);
5450c7c3e67SJ. Bruce Fields 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
5466d338b51SJeff Layton 			swap(f2, fp->fi_fds[O_RDWR]);
547de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
548de18643dSTrond Myklebust 		if (f1)
549de18643dSTrond Myklebust 			fput(f1);
550de18643dSTrond Myklebust 		if (f2)
551de18643dSTrond Myklebust 			fput(f2);
552f9d7562fSJ. Bruce Fields 	}
553f9d7562fSJ. Bruce Fields }
554f9d7562fSJ. Bruce Fields 
55512659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
556998db52cSJ. Bruce Fields {
55712659651SJeff Layton 	WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH);
55812659651SJeff Layton 
55912659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
560998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, O_WRONLY);
56112659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
56212659651SJeff Layton 		__nfs4_file_put_access(fp, O_RDONLY);
563998db52cSJ. Bruce Fields }
564998db52cSJ. Bruce Fields 
5658287f009SSachin Bhamare /*
5668287f009SSachin Bhamare  * Allocate a new open/delegation state counter. This is needed for
5678287f009SSachin Bhamare  * pNFS for proper return on close semantics.
5688287f009SSachin Bhamare  *
5698287f009SSachin Bhamare  * Note that we only allocate it for pNFS-enabled exports, otherwise
5708287f009SSachin Bhamare  * all pointers to struct nfs4_clnt_odstate are always NULL.
5718287f009SSachin Bhamare  */
5728287f009SSachin Bhamare static struct nfs4_clnt_odstate *
5738287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp)
5748287f009SSachin Bhamare {
5758287f009SSachin Bhamare 	struct nfs4_clnt_odstate *co;
5768287f009SSachin Bhamare 
5778287f009SSachin Bhamare 	co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL);
5788287f009SSachin Bhamare 	if (co) {
5798287f009SSachin Bhamare 		co->co_client = clp;
580cff7cb2eSElena Reshetova 		refcount_set(&co->co_odcount, 1);
5818287f009SSachin Bhamare 	}
5828287f009SSachin Bhamare 	return co;
5838287f009SSachin Bhamare }
5848287f009SSachin Bhamare 
5858287f009SSachin Bhamare static void
5868287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co)
5878287f009SSachin Bhamare {
5888287f009SSachin Bhamare 	struct nfs4_file *fp = co->co_file;
5898287f009SSachin Bhamare 
5908287f009SSachin Bhamare 	lockdep_assert_held(&fp->fi_lock);
5918287f009SSachin Bhamare 	list_add(&co->co_perfile, &fp->fi_clnt_odstate);
5928287f009SSachin Bhamare }
5938287f009SSachin Bhamare 
5948287f009SSachin Bhamare static inline void
5958287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co)
5968287f009SSachin Bhamare {
5978287f009SSachin Bhamare 	if (co)
598cff7cb2eSElena Reshetova 		refcount_inc(&co->co_odcount);
5998287f009SSachin Bhamare }
6008287f009SSachin Bhamare 
6018287f009SSachin Bhamare static void
6028287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co)
6038287f009SSachin Bhamare {
6048287f009SSachin Bhamare 	struct nfs4_file *fp;
6058287f009SSachin Bhamare 
6068287f009SSachin Bhamare 	if (!co)
6078287f009SSachin Bhamare 		return;
6088287f009SSachin Bhamare 
6098287f009SSachin Bhamare 	fp = co->co_file;
610cff7cb2eSElena Reshetova 	if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
6118287f009SSachin Bhamare 		list_del(&co->co_perfile);
6128287f009SSachin Bhamare 		spin_unlock(&fp->fi_lock);
6138287f009SSachin Bhamare 
6148287f009SSachin Bhamare 		nfsd4_return_all_file_layouts(co->co_client, fp);
6158287f009SSachin Bhamare 		kmem_cache_free(odstate_slab, co);
6168287f009SSachin Bhamare 	}
6178287f009SSachin Bhamare }
6188287f009SSachin Bhamare 
6198287f009SSachin Bhamare static struct nfs4_clnt_odstate *
6208287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new)
6218287f009SSachin Bhamare {
6228287f009SSachin Bhamare 	struct nfs4_clnt_odstate *co;
6238287f009SSachin Bhamare 	struct nfs4_client *cl;
6248287f009SSachin Bhamare 
6258287f009SSachin Bhamare 	if (!new)
6268287f009SSachin Bhamare 		return NULL;
6278287f009SSachin Bhamare 
6288287f009SSachin Bhamare 	cl = new->co_client;
6298287f009SSachin Bhamare 
6308287f009SSachin Bhamare 	spin_lock(&fp->fi_lock);
6318287f009SSachin Bhamare 	list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) {
6328287f009SSachin Bhamare 		if (co->co_client == cl) {
6338287f009SSachin Bhamare 			get_clnt_odstate(co);
6348287f009SSachin Bhamare 			goto out;
6358287f009SSachin Bhamare 		}
6368287f009SSachin Bhamare 	}
6378287f009SSachin Bhamare 	co = new;
6388287f009SSachin Bhamare 	co->co_file = fp;
6398287f009SSachin Bhamare 	hash_clnt_odstate_locked(new);
6408287f009SSachin Bhamare out:
6418287f009SSachin Bhamare 	spin_unlock(&fp->fi_lock);
6428287f009SSachin Bhamare 	return co;
6438287f009SSachin Bhamare }
6448287f009SSachin Bhamare 
645d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
646d19fb70dSKinglong Mee 				  void (*sc_free)(struct nfs4_stid *))
647996e0938SJ. Bruce Fields {
6483abdb607SJ. Bruce Fields 	struct nfs4_stid *stid;
6493abdb607SJ. Bruce Fields 	int new_id;
6503abdb607SJ. Bruce Fields 
651f8338834STrond Myklebust 	stid = kmem_cache_zalloc(slab, GFP_KERNEL);
6523abdb607SJ. Bruce Fields 	if (!stid)
6533abdb607SJ. Bruce Fields 		return NULL;
654996e0938SJ. Bruce Fields 
6554770d722SJeff Layton 	idr_preload(GFP_KERNEL);
6564770d722SJeff Layton 	spin_lock(&cl->cl_lock);
6574770d722SJeff Layton 	new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT);
6584770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
6594770d722SJeff Layton 	idr_preload_end();
660ebd6c707STejun Heo 	if (new_id < 0)
6613abdb607SJ. Bruce Fields 		goto out_free;
662d19fb70dSKinglong Mee 
663d19fb70dSKinglong Mee 	stid->sc_free = sc_free;
6643abdb607SJ. Bruce Fields 	stid->sc_client = cl;
6653abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_id = new_id;
6663abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
6673abdb607SJ. Bruce Fields 	/* Will be incremented before return to client: */
668a15dfcd5SElena Reshetova 	refcount_set(&stid->sc_count, 1);
6699767feb2SJeff Layton 	spin_lock_init(&stid->sc_lock);
6703abdb607SJ. Bruce Fields 
671996e0938SJ. Bruce Fields 	/*
6723abdb607SJ. Bruce Fields 	 * It shouldn't be a problem to reuse an opaque stateid value.
6733abdb607SJ. Bruce Fields 	 * I don't think it is for 4.1.  But with 4.0 I worry that, for
6743abdb607SJ. Bruce Fields 	 * example, a stray write retransmission could be accepted by
6753abdb607SJ. Bruce Fields 	 * the server when it should have been rejected.  Therefore,
6763abdb607SJ. Bruce Fields 	 * adopt a trick from the sctp code to attempt to maximize the
6773abdb607SJ. Bruce Fields 	 * amount of time until an id is reused, by ensuring they always
6783abdb607SJ. Bruce Fields 	 * "increase" (mod INT_MAX):
679996e0938SJ. Bruce Fields 	 */
6803abdb607SJ. Bruce Fields 	return stid;
6813abdb607SJ. Bruce Fields out_free:
6822c44a234SWei Yongjun 	kmem_cache_free(slab, stid);
6833abdb607SJ. Bruce Fields 	return NULL;
6842a74aba7SJ. Bruce Fields }
6852a74aba7SJ. Bruce Fields 
686b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
6874cdc951bSJ. Bruce Fields {
6886011695dSTrond Myklebust 	struct nfs4_stid *stid;
6896011695dSTrond Myklebust 
690d19fb70dSKinglong Mee 	stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
6916011695dSTrond Myklebust 	if (!stid)
6926011695dSTrond Myklebust 		return NULL;
6936011695dSTrond Myklebust 
694d19fb70dSKinglong Mee 	return openlockstateid(stid);
6956011695dSTrond Myklebust }
6966011695dSTrond Myklebust 
6976011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid)
6986011695dSTrond Myklebust {
6996011695dSTrond Myklebust 	kmem_cache_free(deleg_slab, stid);
7006011695dSTrond Myklebust 	atomic_long_dec(&num_delegations);
7014cdc951bSJ. Bruce Fields }
7024cdc951bSJ. Bruce Fields 
7036282cd56SNeilBrown /*
7046282cd56SNeilBrown  * When we recall a delegation, we should be careful not to hand it
7056282cd56SNeilBrown  * out again straight away.
7066282cd56SNeilBrown  * To ensure this we keep a pair of bloom filters ('new' and 'old')
7076282cd56SNeilBrown  * in which the filehandles of recalled delegations are "stored".
7086282cd56SNeilBrown  * If a filehandle appear in either filter, a delegation is blocked.
7096282cd56SNeilBrown  * When a delegation is recalled, the filehandle is stored in the "new"
7106282cd56SNeilBrown  * filter.
7116282cd56SNeilBrown  * Every 30 seconds we swap the filters and clear the "new" one,
7126282cd56SNeilBrown  * unless both are empty of course.
7136282cd56SNeilBrown  *
7146282cd56SNeilBrown  * Each filter is 256 bits.  We hash the filehandle to 32bit and use the
7156282cd56SNeilBrown  * low 3 bytes as hash-table indices.
7166282cd56SNeilBrown  *
717f54fe962SJeff Layton  * 'blocked_delegations_lock', which is always taken in block_delegations(),
7186282cd56SNeilBrown  * is used to manage concurrent access.  Testing does not need the lock
7196282cd56SNeilBrown  * except when swapping the two filters.
7206282cd56SNeilBrown  */
721f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock);
7226282cd56SNeilBrown static struct bloom_pair {
7236282cd56SNeilBrown 	int	entries, old_entries;
7246282cd56SNeilBrown 	time_t	swap_time;
7256282cd56SNeilBrown 	int	new; /* index into 'set' */
7266282cd56SNeilBrown 	DECLARE_BITMAP(set[2], 256);
7276282cd56SNeilBrown } blocked_delegations;
7286282cd56SNeilBrown 
7296282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh)
7306282cd56SNeilBrown {
7316282cd56SNeilBrown 	u32 hash;
7326282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
7336282cd56SNeilBrown 
7346282cd56SNeilBrown 	if (bd->entries == 0)
7356282cd56SNeilBrown 		return 0;
7366282cd56SNeilBrown 	if (seconds_since_boot() - bd->swap_time > 30) {
737f54fe962SJeff Layton 		spin_lock(&blocked_delegations_lock);
7386282cd56SNeilBrown 		if (seconds_since_boot() - bd->swap_time > 30) {
7396282cd56SNeilBrown 			bd->entries -= bd->old_entries;
7406282cd56SNeilBrown 			bd->old_entries = bd->entries;
7416282cd56SNeilBrown 			memset(bd->set[bd->new], 0,
7426282cd56SNeilBrown 			       sizeof(bd->set[0]));
7436282cd56SNeilBrown 			bd->new = 1-bd->new;
7446282cd56SNeilBrown 			bd->swap_time = seconds_since_boot();
7456282cd56SNeilBrown 		}
746f54fe962SJeff Layton 		spin_unlock(&blocked_delegations_lock);
7476282cd56SNeilBrown 	}
74887545899SDaniel Borkmann 	hash = jhash(&fh->fh_base, fh->fh_size, 0);
7496282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[0]) &&
7506282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[0]) &&
7516282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[0]))
7526282cd56SNeilBrown 		return 1;
7536282cd56SNeilBrown 
7546282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[1]) &&
7556282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[1]) &&
7566282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[1]))
7576282cd56SNeilBrown 		return 1;
7586282cd56SNeilBrown 
7596282cd56SNeilBrown 	return 0;
7606282cd56SNeilBrown }
7616282cd56SNeilBrown 
7626282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh)
7636282cd56SNeilBrown {
7646282cd56SNeilBrown 	u32 hash;
7656282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
7666282cd56SNeilBrown 
76787545899SDaniel Borkmann 	hash = jhash(&fh->fh_base, fh->fh_size, 0);
7686282cd56SNeilBrown 
769f54fe962SJeff Layton 	spin_lock(&blocked_delegations_lock);
7706282cd56SNeilBrown 	__set_bit(hash&255, bd->set[bd->new]);
7716282cd56SNeilBrown 	__set_bit((hash>>8)&255, bd->set[bd->new]);
7726282cd56SNeilBrown 	__set_bit((hash>>16)&255, bd->set[bd->new]);
7736282cd56SNeilBrown 	if (bd->entries == 0)
7746282cd56SNeilBrown 		bd->swap_time = seconds_since_boot();
7756282cd56SNeilBrown 	bd->entries += 1;
776f54fe962SJeff Layton 	spin_unlock(&blocked_delegations_lock);
7776282cd56SNeilBrown }
7786282cd56SNeilBrown 
7791da177e4SLinus Torvalds static struct nfs4_delegation *
7808287f009SSachin Bhamare alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
7818287f009SSachin Bhamare 		 struct nfs4_clnt_odstate *odstate)
7821da177e4SLinus Torvalds {
7831da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
78402a3508dSTrond Myklebust 	long n;
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 	dprintk("NFSD alloc_init_deleg\n");
78702a3508dSTrond Myklebust 	n = atomic_long_inc_return(&num_delegations);
78802a3508dSTrond Myklebust 	if (n < 0 || n > max_delegations)
78902a3508dSTrond Myklebust 		goto out_dec;
7906282cd56SNeilBrown 	if (delegation_blocked(&current_fh->fh_handle))
79102a3508dSTrond Myklebust 		goto out_dec;
792d19fb70dSKinglong Mee 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
7935b2d21c1SNeilBrown 	if (dp == NULL)
79402a3508dSTrond Myklebust 		goto out_dec;
7956011695dSTrond Myklebust 
7962a74aba7SJ. Bruce Fields 	/*
7972a74aba7SJ. Bruce Fields 	 * delegation seqid's are never incremented.  The 4.1 special
7986136d2b4SJ. Bruce Fields 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
7996136d2b4SJ. Bruce Fields 	 * 0 anyway just for consistency and use 1:
8002a74aba7SJ. Bruce Fields 	 */
8012a74aba7SJ. Bruce Fields 	dp->dl_stid.sc_stateid.si_generation = 1;
802ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perfile);
803ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perclnt);
8041da177e4SLinus Torvalds 	INIT_LIST_HEAD(&dp->dl_recall_lru);
8058287f009SSachin Bhamare 	dp->dl_clnt_odstate = odstate;
8068287f009SSachin Bhamare 	get_clnt_odstate(odstate);
80799c41515SJ. Bruce Fields 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
808f0b5de1bSChristoph Hellwig 	dp->dl_retries = 1;
809f0b5de1bSChristoph Hellwig 	nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client,
8100162ac2bSChristoph Hellwig 		      &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL);
8111da177e4SLinus Torvalds 	return dp;
81202a3508dSTrond Myklebust out_dec:
81302a3508dSTrond Myklebust 	atomic_long_dec(&num_delegations);
81402a3508dSTrond Myklebust 	return NULL;
8151da177e4SLinus Torvalds }
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds void
8186011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s)
8191da177e4SLinus Torvalds {
82011b9164aSTrond Myklebust 	struct nfs4_file *fp = s->sc_file;
8216011695dSTrond Myklebust 	struct nfs4_client *clp = s->sc_client;
8226011695dSTrond Myklebust 
8234770d722SJeff Layton 	might_lock(&clp->cl_lock);
8244770d722SJeff Layton 
825a15dfcd5SElena Reshetova 	if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
826b401be22SJeff Layton 		wake_up_all(&close_wq);
8276011695dSTrond Myklebust 		return;
828b401be22SJeff Layton 	}
8296011695dSTrond Myklebust 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
8304770d722SJeff Layton 	spin_unlock(&clp->cl_lock);
8316011695dSTrond Myklebust 	s->sc_free(s);
83211b9164aSTrond Myklebust 	if (fp)
83311b9164aSTrond Myklebust 		put_nfs4_file(fp);
8341da177e4SLinus Torvalds }
8351da177e4SLinus Torvalds 
8369767feb2SJeff Layton void
8379767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid)
8389767feb2SJeff Layton {
8399767feb2SJeff Layton 	stateid_t *src = &stid->sc_stateid;
8409767feb2SJeff Layton 
8419767feb2SJeff Layton 	spin_lock(&stid->sc_lock);
8429767feb2SJeff Layton 	if (unlikely(++src->si_generation == 0))
8439767feb2SJeff Layton 		src->si_generation = 1;
8449767feb2SJeff Layton 	memcpy(dst, src, sizeof(*dst));
8459767feb2SJeff Layton 	spin_unlock(&stid->sc_lock);
8469767feb2SJeff Layton }
8479767feb2SJeff Layton 
848acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp)
8491da177e4SLinus Torvalds {
8506bcc034eSJeff Layton 	struct file *filp = NULL;
851417c6629SJeff Layton 
8526bcc034eSJeff Layton 	spin_lock(&fp->fi_lock);
85367db1034SJeff Layton 	if (fp->fi_deleg_file && --fp->fi_delegees == 0)
8546bcc034eSJeff Layton 		swap(filp, fp->fi_deleg_file);
8556bcc034eSJeff Layton 	spin_unlock(&fp->fi_lock);
8566bcc034eSJeff Layton 
8576bcc034eSJeff Layton 	if (filp) {
8582ab99ee1SChristoph Hellwig 		vfs_setlease(filp, F_UNLCK, NULL, (void **)&fp);
8596bcc034eSJeff Layton 		fput(filp);
860acfdf5c3SJ. Bruce Fields 	}
8611da177e4SLinus Torvalds }
8621da177e4SLinus Torvalds 
863cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s)
8646136d2b4SJ. Bruce Fields {
8653abdb607SJ. Bruce Fields 	s->sc_type = 0;
8666136d2b4SJ. Bruce Fields }
8676136d2b4SJ. Bruce Fields 
86834ed9872SAndrew Elble /**
86934ed9872SAndrew Elble  * nfs4_get_existing_delegation - Discover if this delegation already exists
87034ed9872SAndrew Elble  * @clp:     a pointer to the nfs4_client we're granting a delegation to
87134ed9872SAndrew Elble  * @fp:      a pointer to the nfs4_file we're granting a delegation on
87234ed9872SAndrew Elble  *
87334ed9872SAndrew Elble  * Return:
87434ed9872SAndrew Elble  *      On success: NULL if an existing delegation was not found.
87534ed9872SAndrew Elble  *
87634ed9872SAndrew Elble  *      On error: -EAGAIN if one was previously granted to this nfs4_client
87734ed9872SAndrew Elble  *                 for this nfs4_file.
87834ed9872SAndrew Elble  *
87934ed9872SAndrew Elble  */
88034ed9872SAndrew Elble 
88134ed9872SAndrew Elble static int
88234ed9872SAndrew Elble nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
883931ee56cSBenny Halevy {
88434ed9872SAndrew Elble 	struct nfs4_delegation *searchdp = NULL;
88534ed9872SAndrew Elble 	struct nfs4_client *searchclp = NULL;
88634ed9872SAndrew Elble 
887cdc97505SBenny Halevy 	lockdep_assert_held(&state_lock);
888417c6629SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
889931ee56cSBenny Halevy 
89034ed9872SAndrew Elble 	list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) {
89134ed9872SAndrew Elble 		searchclp = searchdp->dl_stid.sc_client;
89234ed9872SAndrew Elble 		if (clp == searchclp) {
89334ed9872SAndrew Elble 			return -EAGAIN;
89434ed9872SAndrew Elble 		}
89534ed9872SAndrew Elble 	}
89634ed9872SAndrew Elble 	return 0;
89734ed9872SAndrew Elble }
89834ed9872SAndrew Elble 
89934ed9872SAndrew Elble /**
90034ed9872SAndrew Elble  * hash_delegation_locked - Add a delegation to the appropriate lists
90134ed9872SAndrew Elble  * @dp:     a pointer to the nfs4_delegation we are adding.
90234ed9872SAndrew Elble  * @fp:     a pointer to the nfs4_file we're granting a delegation on
90334ed9872SAndrew Elble  *
90434ed9872SAndrew Elble  * Return:
90534ed9872SAndrew Elble  *      On success: NULL if the delegation was successfully hashed.
90634ed9872SAndrew Elble  *
90734ed9872SAndrew Elble  *      On error: -EAGAIN if one was previously granted to this
90834ed9872SAndrew Elble  *                 nfs4_client for this nfs4_file. Delegation is not hashed.
90934ed9872SAndrew Elble  *
91034ed9872SAndrew Elble  */
91134ed9872SAndrew Elble 
91234ed9872SAndrew Elble static int
91334ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
91434ed9872SAndrew Elble {
91534ed9872SAndrew Elble 	int status;
91634ed9872SAndrew Elble 	struct nfs4_client *clp = dp->dl_stid.sc_client;
91734ed9872SAndrew Elble 
91834ed9872SAndrew Elble 	lockdep_assert_held(&state_lock);
91934ed9872SAndrew Elble 	lockdep_assert_held(&fp->fi_lock);
92034ed9872SAndrew Elble 
92134ed9872SAndrew Elble 	status = nfs4_get_existing_delegation(clp, fp);
92234ed9872SAndrew Elble 	if (status)
92334ed9872SAndrew Elble 		return status;
92434ed9872SAndrew Elble 	++fp->fi_delegees;
925a15dfcd5SElena Reshetova 	refcount_inc(&dp->dl_stid.sc_count);
9263fb87d13SBenny Halevy 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
927931ee56cSBenny Halevy 	list_add(&dp->dl_perfile, &fp->fi_delegations);
92834ed9872SAndrew Elble 	list_add(&dp->dl_perclnt, &clp->cl_delegations);
92934ed9872SAndrew Elble 	return 0;
930931ee56cSBenny Halevy }
931931ee56cSBenny Halevy 
9323fcbbd24SJeff Layton static bool
93342690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp)
9341da177e4SLinus Torvalds {
93511b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
93602e1215fSJeff Layton 
93742690676SJeff Layton 	lockdep_assert_held(&state_lock);
93842690676SJeff Layton 
9393fcbbd24SJeff Layton 	if (list_empty(&dp->dl_perfile))
9403fcbbd24SJeff Layton 		return false;
9413fcbbd24SJeff Layton 
942b0fc29d6STrond Myklebust 	dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
943d55a166cSJeff Layton 	/* Ensure that deleg break won't try to requeue it */
944d55a166cSJeff Layton 	++dp->dl_time;
945417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
946931ee56cSBenny Halevy 	list_del_init(&dp->dl_perclnt);
9471da177e4SLinus Torvalds 	list_del_init(&dp->dl_recall_lru);
94802e1215fSJeff Layton 	list_del_init(&dp->dl_perfile);
94902e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
9503fcbbd24SJeff Layton 	return true;
951cbf7a75bSJ. Bruce Fields }
9523bd64a5bSJ. Bruce Fields 
9533bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp)
9543bd64a5bSJ. Bruce Fields {
9553fcbbd24SJeff Layton 	bool unhashed;
9563fcbbd24SJeff Layton 
95742690676SJeff Layton 	spin_lock(&state_lock);
9583fcbbd24SJeff Layton 	unhashed = unhash_delegation_locked(dp);
95942690676SJeff Layton 	spin_unlock(&state_lock);
9603fcbbd24SJeff Layton 	if (unhashed) {
9618287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
962afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
9636011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
9643bd64a5bSJ. Bruce Fields 	}
9653fcbbd24SJeff Layton }
9663bd64a5bSJ. Bruce Fields 
9673bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp)
9683bd64a5bSJ. Bruce Fields {
9693bd64a5bSJ. Bruce Fields 	struct nfs4_client *clp = dp->dl_stid.sc_client;
9703bd64a5bSJ. Bruce Fields 
9712d4a532dSJeff Layton 	WARN_ON(!list_empty(&dp->dl_recall_lru));
9722d4a532dSJeff Layton 
9738287f009SSachin Bhamare 	put_clnt_odstate(dp->dl_clnt_odstate);
974afbda402SJeff Layton 	nfs4_put_deleg_lease(dp->dl_stid.sc_file);
975afbda402SJeff Layton 
9763bd64a5bSJ. Bruce Fields 	if (clp->cl_minorversion == 0)
9776011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
9783bd64a5bSJ. Bruce Fields 	else {
9793bd64a5bSJ. Bruce Fields 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
9802d4a532dSJeff Layton 		spin_lock(&clp->cl_lock);
9812d4a532dSJeff Layton 		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
9822d4a532dSJeff Layton 		spin_unlock(&clp->cl_lock);
9833bd64a5bSJ. Bruce Fields 	}
9843bd64a5bSJ. Bruce Fields }
9853bd64a5bSJ. Bruce Fields 
9861da177e4SLinus Torvalds /*
9871da177e4SLinus Torvalds  * SETCLIENTID state
9881da177e4SLinus Torvalds  */
9891da177e4SLinus Torvalds 
990ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id)
991ddc04c41SJ. Bruce Fields {
992ddc04c41SJ. Bruce Fields 	return id & CLIENT_HASH_MASK;
993ddc04c41SJ. Bruce Fields }
994ddc04c41SJ. Bruce Fields 
995ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name)
996ddc04c41SJ. Bruce Fields {
997ddc04c41SJ. Bruce Fields 	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
998ddc04c41SJ. Bruce Fields }
999ddc04c41SJ. Bruce Fields 
10001da177e4SLinus Torvalds /*
1001f9d7562fSJ. Bruce Fields  * We store the NONE, READ, WRITE, and BOTH bits separately in the
1002f9d7562fSJ. Bruce Fields  * st_{access,deny}_bmap field of the stateid, in order to track not
1003f9d7562fSJ. Bruce Fields  * only what share bits are currently in force, but also what
1004f9d7562fSJ. Bruce Fields  * combinations of share bits previous opens have used.  This allows us
1005f9d7562fSJ. Bruce Fields  * to enforce the recommendation of rfc 3530 14.2.19 that the server
1006f9d7562fSJ. Bruce Fields  * return an error if the client attempt to downgrade to a combination
1007f9d7562fSJ. Bruce Fields  * of share bits not explicable by closing some of its previous opens.
1008f9d7562fSJ. Bruce Fields  *
1009f9d7562fSJ. Bruce Fields  * XXX: This enforcement is actually incomplete, since we don't keep
1010f9d7562fSJ. Bruce Fields  * track of access/deny bit combinations; so, e.g., we allow:
1011f9d7562fSJ. Bruce Fields  *
1012f9d7562fSJ. Bruce Fields  *	OPEN allow read, deny write
1013f9d7562fSJ. Bruce Fields  *	OPEN allow both, deny none
1014f9d7562fSJ. Bruce Fields  *	DOWNGRADE allow read, deny none
1015f9d7562fSJ. Bruce Fields  *
1016f9d7562fSJ. Bruce Fields  * which we should reject.
1017f9d7562fSJ. Bruce Fields  */
10185ae037e5SJeff Layton static unsigned int
10195ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) {
1020f9d7562fSJ. Bruce Fields 	int i;
10215ae037e5SJeff Layton 	unsigned int access = 0;
1022f9d7562fSJ. Bruce Fields 
1023f9d7562fSJ. Bruce Fields 	for (i = 1; i < 4; i++) {
1024f9d7562fSJ. Bruce Fields 		if (test_bit(i, &bmap))
10255ae037e5SJeff Layton 			access |= i;
1026f9d7562fSJ. Bruce Fields 	}
10275ae037e5SJeff Layton 	return access;
1028f9d7562fSJ. Bruce Fields }
1029f9d7562fSJ. Bruce Fields 
103082c5ff1bSJeff Layton /* set share access for a given stateid */
103182c5ff1bSJeff Layton static inline void
103282c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp)
103382c5ff1bSJeff Layton {
1034c11c591fSJeff Layton 	unsigned char mask = 1 << access;
1035c11c591fSJeff Layton 
1036c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
1037c11c591fSJeff Layton 	stp->st_access_bmap |= mask;
103882c5ff1bSJeff Layton }
103982c5ff1bSJeff Layton 
104082c5ff1bSJeff Layton /* clear share access for a given stateid */
104182c5ff1bSJeff Layton static inline void
104282c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp)
104382c5ff1bSJeff Layton {
1044c11c591fSJeff Layton 	unsigned char mask = 1 << access;
1045c11c591fSJeff Layton 
1046c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
1047c11c591fSJeff Layton 	stp->st_access_bmap &= ~mask;
104882c5ff1bSJeff Layton }
104982c5ff1bSJeff Layton 
105082c5ff1bSJeff Layton /* test whether a given stateid has access */
105182c5ff1bSJeff Layton static inline bool
105282c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp)
105382c5ff1bSJeff Layton {
1054c11c591fSJeff Layton 	unsigned char mask = 1 << access;
1055c11c591fSJeff Layton 
1056c11c591fSJeff Layton 	return (bool)(stp->st_access_bmap & mask);
105782c5ff1bSJeff Layton }
105882c5ff1bSJeff Layton 
1059ce0fc43cSJeff Layton /* set share deny for a given stateid */
1060ce0fc43cSJeff Layton static inline void
1061c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp)
1062ce0fc43cSJeff Layton {
1063c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
1064c11c591fSJeff Layton 
1065c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
1066c11c591fSJeff Layton 	stp->st_deny_bmap |= mask;
1067ce0fc43cSJeff Layton }
1068ce0fc43cSJeff Layton 
1069ce0fc43cSJeff Layton /* clear share deny for a given stateid */
1070ce0fc43cSJeff Layton static inline void
1071c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp)
1072ce0fc43cSJeff Layton {
1073c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
1074c11c591fSJeff Layton 
1075c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
1076c11c591fSJeff Layton 	stp->st_deny_bmap &= ~mask;
1077ce0fc43cSJeff Layton }
1078ce0fc43cSJeff Layton 
1079ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */
1080ce0fc43cSJeff Layton static inline bool
1081c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp)
1082ce0fc43cSJeff Layton {
1083c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
1084c11c591fSJeff Layton 
1085c11c591fSJeff Layton 	return (bool)(stp->st_deny_bmap & mask);
1086f9d7562fSJ. Bruce Fields }
1087f9d7562fSJ. Bruce Fields 
1088f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access)
1089f9d7562fSJ. Bruce Fields {
10908f34a430SJ. Bruce Fields 	switch (access & NFS4_SHARE_ACCESS_BOTH) {
1091f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
1092f9d7562fSJ. Bruce Fields 		return O_RDONLY;
1093f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
1094f9d7562fSJ. Bruce Fields 		return O_WRONLY;
1095f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
1096f9d7562fSJ. Bruce Fields 		return O_RDWR;
1097f9d7562fSJ. Bruce Fields 	}
1098063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(1);
1099063b0fb9SJ. Bruce Fields 	return O_RDONLY;
1100f9d7562fSJ. Bruce Fields }
1101f9d7562fSJ. Bruce Fields 
1102baeb4ff0SJeff Layton /*
1103baeb4ff0SJeff Layton  * A stateid that had a deny mode associated with it is being released
1104baeb4ff0SJeff Layton  * or downgraded. Recalculate the deny mode on the file.
1105baeb4ff0SJeff Layton  */
1106baeb4ff0SJeff Layton static void
1107baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp)
1108baeb4ff0SJeff Layton {
1109baeb4ff0SJeff Layton 	struct nfs4_ol_stateid *stp;
1110baeb4ff0SJeff Layton 
1111baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
1112baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
1113baeb4ff0SJeff Layton 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile)
1114baeb4ff0SJeff Layton 		fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap);
1115baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
1116baeb4ff0SJeff Layton }
1117baeb4ff0SJeff Layton 
1118baeb4ff0SJeff Layton static void
1119baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp)
1120baeb4ff0SJeff Layton {
1121baeb4ff0SJeff Layton 	int i;
1122baeb4ff0SJeff Layton 	bool change = false;
1123baeb4ff0SJeff Layton 
1124baeb4ff0SJeff Layton 	for (i = 1; i < 4; i++) {
1125baeb4ff0SJeff Layton 		if ((i & deny) != i) {
1126baeb4ff0SJeff Layton 			change = true;
1127baeb4ff0SJeff Layton 			clear_deny(i, stp);
1128baeb4ff0SJeff Layton 		}
1129baeb4ff0SJeff Layton 	}
1130baeb4ff0SJeff Layton 
1131baeb4ff0SJeff Layton 	/* Recalculate per-file deny mode if there was a change */
1132baeb4ff0SJeff Layton 	if (change)
113311b9164aSTrond Myklebust 		recalculate_deny_mode(stp->st_stid.sc_file);
1134baeb4ff0SJeff Layton }
1135baeb4ff0SJeff Layton 
113682c5ff1bSJeff Layton /* release all access and file references for a given stateid */
113782c5ff1bSJeff Layton static void
113882c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp)
113982c5ff1bSJeff Layton {
114082c5ff1bSJeff Layton 	int i;
114111b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
1142baeb4ff0SJeff Layton 
1143baeb4ff0SJeff Layton 	if (fp && stp->st_deny_bmap != 0)
1144baeb4ff0SJeff Layton 		recalculate_deny_mode(fp);
114582c5ff1bSJeff Layton 
114682c5ff1bSJeff Layton 	for (i = 1; i < 4; i++) {
114782c5ff1bSJeff Layton 		if (test_access(i, stp))
114811b9164aSTrond Myklebust 			nfs4_file_put_access(stp->st_stid.sc_file, i);
114982c5ff1bSJeff Layton 		clear_access(i, stp);
115082c5ff1bSJeff Layton 	}
115182c5ff1bSJeff Layton }
115282c5ff1bSJeff Layton 
1153d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop)
1154d50ffdedSKinglong Mee {
1155d50ffdedSKinglong Mee 	kfree(sop->so_owner.data);
1156d50ffdedSKinglong Mee 	sop->so_ops->so_free(sop);
1157d50ffdedSKinglong Mee }
1158d50ffdedSKinglong Mee 
11596b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
11606b180f0bSJeff Layton {
1161a819ecc1SJeff Layton 	struct nfs4_client *clp = sop->so_client;
1162a819ecc1SJeff Layton 
1163a819ecc1SJeff Layton 	might_lock(&clp->cl_lock);
1164a819ecc1SJeff Layton 
1165a819ecc1SJeff Layton 	if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock))
11666b180f0bSJeff Layton 		return;
11678f4b54c5SJeff Layton 	sop->so_ops->so_unhash(sop);
1168a819ecc1SJeff Layton 	spin_unlock(&clp->cl_lock);
1169d50ffdedSKinglong Mee 	nfs4_free_stateowner(sop);
11706b180f0bSJeff Layton }
11716b180f0bSJeff Layton 
1172e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp)
1173529d7b2aSJ. Bruce Fields {
117411b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
11751d31a253STrond Myklebust 
11761c755dc1SJeff Layton 	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
11771c755dc1SJeff Layton 
1178e8568739SJeff Layton 	if (list_empty(&stp->st_perfile))
1179e8568739SJeff Layton 		return false;
1180e8568739SJeff Layton 
11811d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
1182e8568739SJeff Layton 	list_del_init(&stp->st_perfile);
11831d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
1184529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perstateowner);
1185e8568739SJeff Layton 	return true;
1186529d7b2aSJ. Bruce Fields }
1187529d7b2aSJ. Bruce Fields 
11886011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
1189529d7b2aSJ. Bruce Fields {
11906011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
11914665e2baSJ. Bruce Fields 
11928287f009SSachin Bhamare 	put_clnt_odstate(stp->st_clnt_odstate);
11936011695dSTrond Myklebust 	release_all_access(stp);
1194d3134b10SJeff Layton 	if (stp->st_stateowner)
1195d3134b10SJeff Layton 		nfs4_put_stateowner(stp->st_stateowner);
11966011695dSTrond Myklebust 	kmem_cache_free(stateid_slab, stid);
1197529d7b2aSJ. Bruce Fields }
1198529d7b2aSJ. Bruce Fields 
1199b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid)
1200529d7b2aSJ. Bruce Fields {
1201b49e084dSJeff Layton 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
1202b49e084dSJeff Layton 	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
1203529d7b2aSJ. Bruce Fields 	struct file *file;
1204529d7b2aSJ. Bruce Fields 
1205b49e084dSJeff Layton 	file = find_any_file(stp->st_stid.sc_file);
1206b49e084dSJeff Layton 	if (file)
1207b49e084dSJeff Layton 		filp_close(file, (fl_owner_t)lo);
1208b49e084dSJeff Layton 	nfs4_free_ol_stateid(stid);
1209b49e084dSJeff Layton }
1210b49e084dSJeff Layton 
12112c41beb0SJeff Layton /*
12122c41beb0SJeff Layton  * Put the persistent reference to an already unhashed generic stateid, while
12132c41beb0SJeff Layton  * holding the cl_lock. If it's the last reference, then put it onto the
12142c41beb0SJeff Layton  * reaplist for later destruction.
12152c41beb0SJeff Layton  */
12162c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
12172c41beb0SJeff Layton 				       struct list_head *reaplist)
12182c41beb0SJeff Layton {
12192c41beb0SJeff Layton 	struct nfs4_stid *s = &stp->st_stid;
12202c41beb0SJeff Layton 	struct nfs4_client *clp = s->sc_client;
12212c41beb0SJeff Layton 
12222c41beb0SJeff Layton 	lockdep_assert_held(&clp->cl_lock);
12232c41beb0SJeff Layton 
12242c41beb0SJeff Layton 	WARN_ON_ONCE(!list_empty(&stp->st_locks));
12252c41beb0SJeff Layton 
1226a15dfcd5SElena Reshetova 	if (!refcount_dec_and_test(&s->sc_count)) {
12272c41beb0SJeff Layton 		wake_up_all(&close_wq);
12282c41beb0SJeff Layton 		return;
12292c41beb0SJeff Layton 	}
12302c41beb0SJeff Layton 
12312c41beb0SJeff Layton 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
12322c41beb0SJeff Layton 	list_add(&stp->st_locks, reaplist);
12332c41beb0SJeff Layton }
12342c41beb0SJeff Layton 
1235e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
12363c1c995cSJeff Layton {
1237f46c445bSChuck Lever 	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
12383c1c995cSJeff Layton 
12393c1c995cSJeff Layton 	list_del_init(&stp->st_locks);
1240cd61c522SChristoph Hellwig 	nfs4_unhash_stid(&stp->st_stid);
1241e8568739SJeff Layton 	return unhash_ol_stateid(stp);
12423c1c995cSJeff Layton }
12433c1c995cSJeff Layton 
12445adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp)
1245b49e084dSJeff Layton {
1246f46c445bSChuck Lever 	struct nfs4_client *clp = stp->st_stid.sc_client;
1247e8568739SJeff Layton 	bool unhashed;
12481c755dc1SJeff Layton 
1249f46c445bSChuck Lever 	spin_lock(&clp->cl_lock);
1250e8568739SJeff Layton 	unhashed = unhash_lock_stateid(stp);
1251f46c445bSChuck Lever 	spin_unlock(&clp->cl_lock);
1252e8568739SJeff Layton 	if (unhashed)
12536011695dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
1254529d7b2aSJ. Bruce Fields }
1255529d7b2aSJ. Bruce Fields 
1256c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
1257529d7b2aSJ. Bruce Fields {
1258d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
1259c58c6610STrond Myklebust 
1260d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
1261c58c6610STrond Myklebust 
12628f4b54c5SJeff Layton 	list_del_init(&lo->lo_owner.so_strhash);
12638f4b54c5SJeff Layton }
12648f4b54c5SJeff Layton 
12652c41beb0SJeff Layton /*
12662c41beb0SJeff Layton  * Free a list of generic stateids that were collected earlier after being
12672c41beb0SJeff Layton  * fully unhashed.
12682c41beb0SJeff Layton  */
12692c41beb0SJeff Layton static void
12702c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist)
12712c41beb0SJeff Layton {
12722c41beb0SJeff Layton 	struct nfs4_ol_stateid *stp;
1273fb94d766SKinglong Mee 	struct nfs4_file *fp;
12742c41beb0SJeff Layton 
12752c41beb0SJeff Layton 	might_sleep();
12762c41beb0SJeff Layton 
12772c41beb0SJeff Layton 	while (!list_empty(reaplist)) {
12782c41beb0SJeff Layton 		stp = list_first_entry(reaplist, struct nfs4_ol_stateid,
12792c41beb0SJeff Layton 				       st_locks);
12802c41beb0SJeff Layton 		list_del(&stp->st_locks);
1281fb94d766SKinglong Mee 		fp = stp->st_stid.sc_file;
12822c41beb0SJeff Layton 		stp->st_stid.sc_free(&stp->st_stid);
1283fb94d766SKinglong Mee 		if (fp)
1284fb94d766SKinglong Mee 			put_nfs4_file(fp);
12852c41beb0SJeff Layton 	}
12862c41beb0SJeff Layton }
12872c41beb0SJeff Layton 
1288d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
1289d83017f9SJeff Layton 				       struct list_head *reaplist)
12903c87b9b7STrond Myklebust {
12913c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *stp;
12923c87b9b7STrond Myklebust 
1293e8568739SJeff Layton 	lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock);
1294e8568739SJeff Layton 
12953c87b9b7STrond Myklebust 	while (!list_empty(&open_stp->st_locks)) {
12963c87b9b7STrond Myklebust 		stp = list_entry(open_stp->st_locks.next,
12973c87b9b7STrond Myklebust 				struct nfs4_ol_stateid, st_locks);
1298e8568739SJeff Layton 		WARN_ON(!unhash_lock_stateid(stp));
1299d83017f9SJeff Layton 		put_ol_stateid_locked(stp, reaplist);
1300529d7b2aSJ. Bruce Fields 	}
1301529d7b2aSJ. Bruce Fields }
1302529d7b2aSJ. Bruce Fields 
1303e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp,
1304d83017f9SJeff Layton 				struct list_head *reaplist)
13052283963fSJ. Bruce Fields {
1306e8568739SJeff Layton 	bool unhashed;
1307e8568739SJeff Layton 
13082c41beb0SJeff Layton 	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
13092c41beb0SJeff Layton 
1310e8568739SJeff Layton 	unhashed = unhash_ol_stateid(stp);
1311d83017f9SJeff Layton 	release_open_stateid_locks(stp, reaplist);
1312e8568739SJeff Layton 	return unhashed;
131338c387b5SJ. Bruce Fields }
131438c387b5SJ. Bruce Fields 
131538c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp)
131638c387b5SJ. Bruce Fields {
13172c41beb0SJeff Layton 	LIST_HEAD(reaplist);
13182c41beb0SJeff Layton 
13192c41beb0SJeff Layton 	spin_lock(&stp->st_stid.sc_client->cl_lock);
1320e8568739SJeff Layton 	if (unhash_open_stateid(stp, &reaplist))
13212c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
13222c41beb0SJeff Layton 	spin_unlock(&stp->st_stid.sc_client->cl_lock);
13232c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
13242283963fSJ. Bruce Fields }
13252283963fSJ. Bruce Fields 
13267ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo)
1327f1d110caSJ. Bruce Fields {
1328d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
13297ffb5880STrond Myklebust 
1330d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
13317ffb5880STrond Myklebust 
13328f4b54c5SJeff Layton 	list_del_init(&oo->oo_owner.so_strhash);
13338f4b54c5SJeff Layton 	list_del_init(&oo->oo_perclient);
1334f1d110caSJ. Bruce Fields }
1335f1d110caSJ. Bruce Fields 
1336f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo)
1337f7a4d872SJ. Bruce Fields {
1338217526e7SJeff Layton 	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1339217526e7SJeff Layton 					  nfsd_net_id);
1340217526e7SJeff Layton 	struct nfs4_ol_stateid *s;
1341f7a4d872SJ. Bruce Fields 
1342217526e7SJeff Layton 	spin_lock(&nn->client_lock);
1343217526e7SJeff Layton 	s = oo->oo_last_closed_stid;
1344f7a4d872SJ. Bruce Fields 	if (s) {
1345d3134b10SJeff Layton 		list_del_init(&oo->oo_close_lru);
1346f7a4d872SJ. Bruce Fields 		oo->oo_last_closed_stid = NULL;
1347f7a4d872SJ. Bruce Fields 	}
1348217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
1349217526e7SJeff Layton 	if (s)
1350217526e7SJeff Layton 		nfs4_put_stid(&s->st_stid);
1351f7a4d872SJ. Bruce Fields }
1352f7a4d872SJ. Bruce Fields 
13532c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo)
13548f4b54c5SJeff Layton {
13558f4b54c5SJeff Layton 	struct nfs4_ol_stateid *stp;
1356d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
13572c41beb0SJeff Layton 	struct list_head reaplist;
13587ffb5880STrond Myklebust 
13592c41beb0SJeff Layton 	INIT_LIST_HEAD(&reaplist);
13607ffb5880STrond Myklebust 
1361d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
13627ffb5880STrond Myklebust 	unhash_openowner_locked(oo);
13632c41beb0SJeff Layton 	while (!list_empty(&oo->oo_owner.so_stateids)) {
13642c41beb0SJeff Layton 		stp = list_first_entry(&oo->oo_owner.so_stateids,
13652c41beb0SJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
1366e8568739SJeff Layton 		if (unhash_open_stateid(stp, &reaplist))
13672c41beb0SJeff Layton 			put_ol_stateid_locked(stp, &reaplist);
13682c41beb0SJeff Layton 	}
1369d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
13702c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
1371f7a4d872SJ. Bruce Fields 	release_last_closed_stateid(oo);
13726b180f0bSJeff Layton 	nfs4_put_stateowner(&oo->oo_owner);
1373f1d110caSJ. Bruce Fields }
1374f1d110caSJ. Bruce Fields 
13755282fd72SMarc Eshel static inline int
13765282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid)
13775282fd72SMarc Eshel {
13785282fd72SMarc Eshel 	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
13795282fd72SMarc Eshel 
13805282fd72SMarc Eshel 	return sid->sequence % SESSION_HASH_SIZE;
13815282fd72SMarc Eshel }
13825282fd72SMarc Eshel 
1383135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG
13845282fd72SMarc Eshel static inline void
13855282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
13865282fd72SMarc Eshel {
13875282fd72SMarc Eshel 	u32 *ptr = (u32 *)(&sessionid->data[0]);
13885282fd72SMarc Eshel 	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
13895282fd72SMarc Eshel }
13908f199b82STrond Myklebust #else
13918f199b82STrond Myklebust static inline void
13928f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
13938f199b82STrond Myklebust {
13948f199b82STrond Myklebust }
13958f199b82STrond Myklebust #endif
13968f199b82STrond Myklebust 
13979411b1d4SJ. Bruce Fields /*
13989411b1d4SJ. Bruce Fields  * Bump the seqid on cstate->replay_owner, and clear replay_owner if it
13999411b1d4SJ. Bruce Fields  * won't be used for replay.
14009411b1d4SJ. Bruce Fields  */
14019411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
14029411b1d4SJ. Bruce Fields {
14039411b1d4SJ. Bruce Fields 	struct nfs4_stateowner *so = cstate->replay_owner;
14049411b1d4SJ. Bruce Fields 
14059411b1d4SJ. Bruce Fields 	if (nfserr == nfserr_replay_me)
14069411b1d4SJ. Bruce Fields 		return;
14079411b1d4SJ. Bruce Fields 
14089411b1d4SJ. Bruce Fields 	if (!seqid_mutating_err(ntohl(nfserr))) {
140958fb12e6SJeff Layton 		nfsd4_cstate_clear_replay(cstate);
14109411b1d4SJ. Bruce Fields 		return;
14119411b1d4SJ. Bruce Fields 	}
14129411b1d4SJ. Bruce Fields 	if (!so)
14139411b1d4SJ. Bruce Fields 		return;
14149411b1d4SJ. Bruce Fields 	if (so->so_is_open_owner)
14159411b1d4SJ. Bruce Fields 		release_last_closed_stateid(openowner(so));
14169411b1d4SJ. Bruce Fields 	so->so_seqid++;
14179411b1d4SJ. Bruce Fields 	return;
14189411b1d4SJ. Bruce Fields }
14195282fd72SMarc Eshel 
1420ec6b5d7bSAndy Adamson static void
1421ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses)
1422ec6b5d7bSAndy Adamson {
1423ec6b5d7bSAndy Adamson 	struct nfs4_client *clp = ses->se_client;
1424ec6b5d7bSAndy Adamson 	struct nfsd4_sessionid *sid;
1425ec6b5d7bSAndy Adamson 
1426ec6b5d7bSAndy Adamson 	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
1427ec6b5d7bSAndy Adamson 	sid->clientid = clp->cl_clientid;
1428ec6b5d7bSAndy Adamson 	sid->sequence = current_sessionid++;
1429ec6b5d7bSAndy Adamson 	sid->reserved = 0;
1430ec6b5d7bSAndy Adamson }
1431ec6b5d7bSAndy Adamson 
1432ec6b5d7bSAndy Adamson /*
1433a649637cSAndy Adamson  * The protocol defines ca_maxresponssize_cached to include the size of
1434a649637cSAndy Adamson  * the rpc header, but all we need to cache is the data starting after
1435a649637cSAndy Adamson  * the end of the initial SEQUENCE operation--the rest we regenerate
1436a649637cSAndy Adamson  * each time.  Therefore we can advertise a ca_maxresponssize_cached
1437a649637cSAndy Adamson  * value that is the number of bytes in our cache plus a few additional
1438a649637cSAndy Adamson  * bytes.  In order to stay on the safe side, and not promise more than
1439a649637cSAndy Adamson  * we can cache, those additional bytes must be the minimum possible: 24
1440a649637cSAndy Adamson  * bytes of rpc header (xid through accept state, with AUTH_NULL
1441a649637cSAndy Adamson  * verifier), 12 for the compound header (with zero-length tag), and 44
1442a649637cSAndy Adamson  * for the SEQUENCE op response:
1443ec6b5d7bSAndy Adamson  */
1444a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
1445a649637cSAndy Adamson 
1446557ce264SAndy Adamson static void
1447557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses)
1448557ce264SAndy Adamson {
1449557ce264SAndy Adamson 	int i;
1450557ce264SAndy Adamson 
145153da6a53SJ. Bruce Fields 	for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
145253da6a53SJ. Bruce Fields 		free_svc_cred(&ses->se_slots[i]->sl_cred);
1453557ce264SAndy Adamson 		kfree(ses->se_slots[i]);
1454557ce264SAndy Adamson 	}
145553da6a53SJ. Bruce Fields }
1456557ce264SAndy Adamson 
1457efe0cb6dSJ. Bruce Fields /*
1458efe0cb6dSJ. Bruce Fields  * We don't actually need to cache the rpc and session headers, so we
1459efe0cb6dSJ. Bruce Fields  * can allocate a little less for each slot:
1460efe0cb6dSJ. Bruce Fields  */
146155c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca)
1462efe0cb6dSJ. Bruce Fields {
146355c760cfSJ. Bruce Fields 	u32 size;
1464efe0cb6dSJ. Bruce Fields 
146555c760cfSJ. Bruce Fields 	if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ)
146655c760cfSJ. Bruce Fields 		size = 0;
146755c760cfSJ. Bruce Fields 	else
146855c760cfSJ. Bruce Fields 		size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
146955c760cfSJ. Bruce Fields 	return size + sizeof(struct nfsd4_slot);
1470557ce264SAndy Adamson }
1471557ce264SAndy Adamson 
14725b6feee9SJ. Bruce Fields /*
14735b6feee9SJ. Bruce Fields  * XXX: If we run out of reserved DRC memory we could (up to a point)
14745b6feee9SJ. Bruce Fields  * re-negotiate active sessions and reduce their slot usage to make
147542b2aa86SJustin P. Mattock  * room for new connections. For now we just fail the create session.
14765b6feee9SJ. Bruce Fields  */
147755c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
14785b6feee9SJ. Bruce Fields {
147955c760cfSJ. Bruce Fields 	u32 slotsize = slot_bytes(ca);
148055c760cfSJ. Bruce Fields 	u32 num = ca->maxreqs;
14815b6feee9SJ. Bruce Fields 	int avail;
14825b6feee9SJ. Bruce Fields 
14835b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
1484697ce9beSZhang Yanfei 	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
14855b6feee9SJ. Bruce Fields 		    nfsd_drc_max_mem - nfsd_drc_mem_used);
1486de766e57SJ. Bruce Fields 	/*
1487de766e57SJ. Bruce Fields 	 * Never use more than a third of the remaining memory,
1488de766e57SJ. Bruce Fields 	 * unless it's the only way to give this client a slot:
1489de766e57SJ. Bruce Fields 	 */
1490de766e57SJ. Bruce Fields 	avail = clamp_t(int, avail, slotsize, avail/3);
14915b6feee9SJ. Bruce Fields 	num = min_t(int, num, avail / slotsize);
14925b6feee9SJ. Bruce Fields 	nfsd_drc_mem_used += num * slotsize;
14935b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
14945b6feee9SJ. Bruce Fields 
14955b6feee9SJ. Bruce Fields 	return num;
14965b6feee9SJ. Bruce Fields }
14975b6feee9SJ. Bruce Fields 
149855c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
14995b6feee9SJ. Bruce Fields {
150055c760cfSJ. Bruce Fields 	int slotsize = slot_bytes(ca);
150155c760cfSJ. Bruce Fields 
15025b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
150355c760cfSJ. Bruce Fields 	nfsd_drc_mem_used -= slotsize * ca->maxreqs;
15045b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
15055b6feee9SJ. Bruce Fields }
15065b6feee9SJ. Bruce Fields 
150760810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
150860810e54SKinglong Mee 					   struct nfsd4_channel_attrs *battrs)
15095b6feee9SJ. Bruce Fields {
151060810e54SKinglong Mee 	int numslots = fattrs->maxreqs;
151160810e54SKinglong Mee 	int slotsize = slot_bytes(fattrs);
15125b6feee9SJ. Bruce Fields 	struct nfsd4_session *new;
15135b6feee9SJ. Bruce Fields 	int mem, i;
1514ec6b5d7bSAndy Adamson 
1515c23753daSJ. Bruce Fields 	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
1516ec6b5d7bSAndy Adamson 			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
15175b6feee9SJ. Bruce Fields 	mem = numslots * sizeof(struct nfsd4_slot *);
1518ec6b5d7bSAndy Adamson 
15195b6feee9SJ. Bruce Fields 	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
15206c18ba9fSAlexandros Batsakis 	if (!new)
15215b6feee9SJ. Bruce Fields 		return NULL;
1522ec6b5d7bSAndy Adamson 	/* allocate each struct nfsd4_slot and data cache in one piece */
15235b6feee9SJ. Bruce Fields 	for (i = 0; i < numslots; i++) {
152455c760cfSJ. Bruce Fields 		new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL);
15255b6feee9SJ. Bruce Fields 		if (!new->se_slots[i])
1526ec6b5d7bSAndy Adamson 			goto out_free;
1527ec6b5d7bSAndy Adamson 	}
152860810e54SKinglong Mee 
152960810e54SKinglong Mee 	memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
153060810e54SKinglong Mee 	memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
153160810e54SKinglong Mee 
15325b6feee9SJ. Bruce Fields 	return new;
15335b6feee9SJ. Bruce Fields out_free:
15345b6feee9SJ. Bruce Fields 	while (i--)
15355b6feee9SJ. Bruce Fields 		kfree(new->se_slots[i]);
15365b6feee9SJ. Bruce Fields 	kfree(new);
15375b6feee9SJ. Bruce Fields 	return NULL;
15385b6feee9SJ. Bruce Fields }
15395b6feee9SJ. Bruce Fields 
154019cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c)
154119cf5c02SJ. Bruce Fields {
154219cf5c02SJ. Bruce Fields 	svc_xprt_put(c->cn_xprt);
154319cf5c02SJ. Bruce Fields 	kfree(c);
154419cf5c02SJ. Bruce Fields }
154519cf5c02SJ. Bruce Fields 
154619cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u)
154719cf5c02SJ. Bruce Fields {
154819cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
154919cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = c->cn_session->se_client;
155019cf5c02SJ. Bruce Fields 
155119cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
155219cf5c02SJ. Bruce Fields 	if (!list_empty(&c->cn_persession)) {
155319cf5c02SJ. Bruce Fields 		list_del(&c->cn_persession);
155419cf5c02SJ. Bruce Fields 		free_conn(c);
155519cf5c02SJ. Bruce Fields 	}
1556eea49806SJ. Bruce Fields 	nfsd4_probe_callback(clp);
15572e4b7239SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
155819cf5c02SJ. Bruce Fields }
155919cf5c02SJ. Bruce Fields 
1560d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
1561c7662518SJ. Bruce Fields {
1562c7662518SJ. Bruce Fields 	struct nfsd4_conn *conn;
1563c7662518SJ. Bruce Fields 
1564c7662518SJ. Bruce Fields 	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
1565c7662518SJ. Bruce Fields 	if (!conn)
1566db90681dSJ. Bruce Fields 		return NULL;
1567c7662518SJ. Bruce Fields 	svc_xprt_get(rqstp->rq_xprt);
1568c7662518SJ. Bruce Fields 	conn->cn_xprt = rqstp->rq_xprt;
1569d29c374cSJ. Bruce Fields 	conn->cn_flags = flags;
1570db90681dSJ. Bruce Fields 	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
1571db90681dSJ. Bruce Fields 	return conn;
1572db90681dSJ. Bruce Fields }
1573db90681dSJ. Bruce Fields 
1574328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1575328ead28SJ. Bruce Fields {
1576328ead28SJ. Bruce Fields 	conn->cn_session = ses;
1577328ead28SJ. Bruce Fields 	list_add(&conn->cn_persession, &ses->se_conns);
1578328ead28SJ. Bruce Fields }
1579328ead28SJ. Bruce Fields 
1580db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1581db90681dSJ. Bruce Fields {
1582db90681dSJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
1583c7662518SJ. Bruce Fields 
1584c7662518SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1585328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(conn, ses);
1586c7662518SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1587db90681dSJ. Bruce Fields }
1588c7662518SJ. Bruce Fields 
158921b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn)
1590db90681dSJ. Bruce Fields {
159119cf5c02SJ. Bruce Fields 	conn->cn_xpt_user.callback = nfsd4_conn_lost;
159221b75b01SJ. Bruce Fields 	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
1593db90681dSJ. Bruce Fields }
1594db90681dSJ. Bruce Fields 
1595e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
1596db90681dSJ. Bruce Fields {
159721b75b01SJ. Bruce Fields 	int ret;
1598db90681dSJ. Bruce Fields 
1599db90681dSJ. Bruce Fields 	nfsd4_hash_conn(conn, ses);
160021b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(conn);
160121b75b01SJ. Bruce Fields 	if (ret)
160221b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
160321b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&conn->cn_xpt_user);
160457a37144SJ. Bruce Fields 	/* We may have gained or lost a callback channel: */
160557a37144SJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
1606c7662518SJ. Bruce Fields }
1607c7662518SJ. Bruce Fields 
1608e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
16091d1bc8f2SJ. Bruce Fields {
16101d1bc8f2SJ. Bruce Fields 	u32 dir = NFS4_CDFC4_FORE;
16111d1bc8f2SJ. Bruce Fields 
1612e1ff371fSJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN)
16131d1bc8f2SJ. Bruce Fields 		dir |= NFS4_CDFC4_BACK;
1614e1ff371fSJ. Bruce Fields 	return alloc_conn(rqstp, dir);
16151d1bc8f2SJ. Bruce Fields }
16161d1bc8f2SJ. Bruce Fields 
16171d1bc8f2SJ. Bruce Fields /* must be called under client_lock */
161819cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s)
1619c7662518SJ. Bruce Fields {
162019cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = s->se_client;
162119cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c;
162219cf5c02SJ. Bruce Fields 
162319cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
162419cf5c02SJ. Bruce Fields 	while (!list_empty(&s->se_conns)) {
162519cf5c02SJ. Bruce Fields 		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
162619cf5c02SJ. Bruce Fields 		list_del_init(&c->cn_persession);
162719cf5c02SJ. Bruce Fields 		spin_unlock(&clp->cl_lock);
162819cf5c02SJ. Bruce Fields 
162919cf5c02SJ. Bruce Fields 		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
163019cf5c02SJ. Bruce Fields 		free_conn(c);
163119cf5c02SJ. Bruce Fields 
163219cf5c02SJ. Bruce Fields 		spin_lock(&clp->cl_lock);
163319cf5c02SJ. Bruce Fields 	}
163419cf5c02SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1635c7662518SJ. Bruce Fields }
1636c7662518SJ. Bruce Fields 
16371377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses)
16381377b69eSJ. Bruce Fields {
16391377b69eSJ. Bruce Fields 	free_session_slots(ses);
16401377b69eSJ. Bruce Fields 	kfree(ses);
16411377b69eSJ. Bruce Fields }
16421377b69eSJ. Bruce Fields 
164366b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses)
1644508dc6e1SBenny Halevy {
1645c7662518SJ. Bruce Fields 	nfsd4_del_conns(ses);
164655c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&ses->se_fchannel);
1647c7662518SJ. Bruce Fields 	__free_session(ses);
1648a827bcb2SJ. Bruce Fields }
1649ec6b5d7bSAndy Adamson 
1650135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
1651a827bcb2SJ. Bruce Fields {
1652a827bcb2SJ. Bruce Fields 	int idx;
16531872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1654a827bcb2SJ. Bruce Fields 
1655ec6b5d7bSAndy Adamson 	new->se_client = clp;
1656ec6b5d7bSAndy Adamson 	gen_sessionid(new);
1657ec6b5d7bSAndy Adamson 
1658c7662518SJ. Bruce Fields 	INIT_LIST_HEAD(&new->se_conns);
1659c7662518SJ. Bruce Fields 
1660ac7c46f2SJ. Bruce Fields 	new->se_cb_seq_nr = 1;
1661ec6b5d7bSAndy Adamson 	new->se_flags = cses->flags;
16628b5ce5cdSJ. Bruce Fields 	new->se_cb_prog = cses->callback_prog;
1663c6bb3ca2SJ. Bruce Fields 	new->se_cb_sec = cses->cb_sec;
166466b2b9b2SJ. Bruce Fields 	atomic_set(&new->se_ref, 0);
16655b6feee9SJ. Bruce Fields 	idx = hash_sessionid(&new->se_sessionid);
16661872de0eSStanislav Kinsbursky 	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
16674c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1668ec6b5d7bSAndy Adamson 	list_add(&new->se_perclnt, &clp->cl_sessions);
16694c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
167060810e54SKinglong Mee 
1671b0d2e42cSChuck Lever 	{
1672edd76786SJ. Bruce Fields 		struct sockaddr *sa = svc_addr(rqstp);
1673dcbeaa68SJ. Bruce Fields 		/*
1674dcbeaa68SJ. Bruce Fields 		 * This is a little silly; with sessions there's no real
1675dcbeaa68SJ. Bruce Fields 		 * use for the callback address.  Use the peer address
1676dcbeaa68SJ. Bruce Fields 		 * as a reasonable default for now, but consider fixing
1677dcbeaa68SJ. Bruce Fields 		 * the rpc client not to require an address in the
1678dcbeaa68SJ. Bruce Fields 		 * future:
1679dcbeaa68SJ. Bruce Fields 		 */
1680edd76786SJ. Bruce Fields 		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
1681edd76786SJ. Bruce Fields 		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
1682edd76786SJ. Bruce Fields 	}
1683ec6b5d7bSAndy Adamson }
1684ec6b5d7bSAndy Adamson 
16859089f1b4SBenny Halevy /* caller must hold client_lock */
16865282fd72SMarc Eshel static struct nfsd4_session *
1687d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
16885282fd72SMarc Eshel {
16895282fd72SMarc Eshel 	struct nfsd4_session *elem;
16905282fd72SMarc Eshel 	int idx;
16911872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
16925282fd72SMarc Eshel 
16930a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
16940a880a28STrond Myklebust 
16955282fd72SMarc Eshel 	dump_sessionid(__func__, sessionid);
16965282fd72SMarc Eshel 	idx = hash_sessionid(sessionid);
16975282fd72SMarc Eshel 	/* Search in the appropriate list */
16981872de0eSStanislav Kinsbursky 	list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) {
16995282fd72SMarc Eshel 		if (!memcmp(elem->se_sessionid.data, sessionid->data,
17005282fd72SMarc Eshel 			    NFS4_MAX_SESSIONID_LEN)) {
17015282fd72SMarc Eshel 			return elem;
17025282fd72SMarc Eshel 		}
17035282fd72SMarc Eshel 	}
17045282fd72SMarc Eshel 
17055282fd72SMarc Eshel 	dprintk("%s: session not found\n", __func__);
17065282fd72SMarc Eshel 	return NULL;
17075282fd72SMarc Eshel }
17085282fd72SMarc Eshel 
1709d4e19e70STrond Myklebust static struct nfsd4_session *
1710d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net,
1711d4e19e70STrond Myklebust 		__be32 *ret)
1712d4e19e70STrond Myklebust {
1713d4e19e70STrond Myklebust 	struct nfsd4_session *session;
1714d4e19e70STrond Myklebust 	__be32 status = nfserr_badsession;
1715d4e19e70STrond Myklebust 
1716d4e19e70STrond Myklebust 	session = __find_in_sessionid_hashtbl(sessionid, net);
1717d4e19e70STrond Myklebust 	if (!session)
1718d4e19e70STrond Myklebust 		goto out;
1719d4e19e70STrond Myklebust 	status = nfsd4_get_session_locked(session);
1720d4e19e70STrond Myklebust 	if (status)
1721d4e19e70STrond Myklebust 		session = NULL;
1722d4e19e70STrond Myklebust out:
1723d4e19e70STrond Myklebust 	*ret = status;
1724d4e19e70STrond Myklebust 	return session;
1725d4e19e70STrond Myklebust }
1726d4e19e70STrond Myklebust 
17279089f1b4SBenny Halevy /* caller must hold client_lock */
17287116ed6bSAndy Adamson static void
17295282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses)
17307116ed6bSAndy Adamson {
17310a880a28STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
17320a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
17330a880a28STrond Myklebust 
17340a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
17350a880a28STrond Myklebust 
17367116ed6bSAndy Adamson 	list_del(&ses->se_hash);
17374c649378SJ. Bruce Fields 	spin_lock(&ses->se_client->cl_lock);
17387116ed6bSAndy Adamson 	list_del(&ses->se_perclnt);
17394c649378SJ. Bruce Fields 	spin_unlock(&ses->se_client->cl_lock);
17405282fd72SMarc Eshel }
17415282fd72SMarc Eshel 
17421da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
17431da177e4SLinus Torvalds static int
17442c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
17451da177e4SLinus Torvalds {
1746bbc7f33aSJ. Bruce Fields 	/*
1747bbc7f33aSJ. Bruce Fields 	 * We're assuming the clid was not given out from a boot
1748bbc7f33aSJ. Bruce Fields 	 * precisely 2^32 (about 136 years) before this one.  That seems
1749bbc7f33aSJ. Bruce Fields 	 * a safe assumption:
1750bbc7f33aSJ. Bruce Fields 	 */
1751bbc7f33aSJ. Bruce Fields 	if (clid->cl_boot == (u32)nn->boot_time)
17521da177e4SLinus Torvalds 		return 0;
175360adfc50SAndy Adamson 	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
17542c142baaSStanislav Kinsbursky 		clid->cl_boot, clid->cl_id, nn->boot_time);
17551da177e4SLinus Torvalds 	return 1;
17561da177e4SLinus Torvalds }
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds /*
17591da177e4SLinus Torvalds  * XXX Should we use a slab cache ?
17601da177e4SLinus Torvalds  * This type of memory management is somewhat inefficient, but we use it
17611da177e4SLinus Torvalds  * anyway since SETCLIENTID is not a common operation.
17621da177e4SLinus Torvalds  */
176335bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name)
17641da177e4SLinus Torvalds {
17651da177e4SLinus Torvalds 	struct nfs4_client *clp;
1766d4f0489fSTrond Myklebust 	int i;
17671da177e4SLinus Torvalds 
176835bba9a3SJ. Bruce Fields 	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
176935bba9a3SJ. Bruce Fields 	if (clp == NULL)
177035bba9a3SJ. Bruce Fields 		return NULL;
177167114fe6SThomas Meyer 	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
1772d4f0489fSTrond Myklebust 	if (clp->cl_name.data == NULL)
1773d4f0489fSTrond Myklebust 		goto err_no_name;
1774d4f0489fSTrond Myklebust 	clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
1775d4f0489fSTrond Myklebust 			OWNER_HASH_SIZE, GFP_KERNEL);
1776d4f0489fSTrond Myklebust 	if (!clp->cl_ownerstr_hashtbl)
1777d4f0489fSTrond Myklebust 		goto err_no_hashtbl;
1778d4f0489fSTrond Myklebust 	for (i = 0; i < OWNER_HASH_SIZE; i++)
1779d4f0489fSTrond Myklebust 		INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]);
17801da177e4SLinus Torvalds 	clp->cl_name.len = name.len;
17815694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_sessions);
17825694c93eSTrond Myklebust 	idr_init(&clp->cl_stateids);
17835694c93eSTrond Myklebust 	atomic_set(&clp->cl_refcount, 0);
17845694c93eSTrond Myklebust 	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
17855694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_idhash);
17865694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_openowners);
17875694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_delegations);
17885694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_lru);
17895694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_revoked);
17909cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
17919cf514ccSChristoph Hellwig 	INIT_LIST_HEAD(&clp->cl_lo_states);
17929cf514ccSChristoph Hellwig #endif
17935694c93eSTrond Myklebust 	spin_lock_init(&clp->cl_lock);
17945694c93eSTrond Myklebust 	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
17951da177e4SLinus Torvalds 	return clp;
1796d4f0489fSTrond Myklebust err_no_hashtbl:
1797d4f0489fSTrond Myklebust 	kfree(clp->cl_name.data);
1798d4f0489fSTrond Myklebust err_no_name:
1799d4f0489fSTrond Myklebust 	kfree(clp);
1800d4f0489fSTrond Myklebust 	return NULL;
18011da177e4SLinus Torvalds }
18021da177e4SLinus Torvalds 
18034dd86e15STrond Myklebust static void
18041da177e4SLinus Torvalds free_client(struct nfs4_client *clp)
18051da177e4SLinus Torvalds {
1806792c95ddSJ. Bruce Fields 	while (!list_empty(&clp->cl_sessions)) {
1807792c95ddSJ. Bruce Fields 		struct nfsd4_session *ses;
1808792c95ddSJ. Bruce Fields 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
1809792c95ddSJ. Bruce Fields 				se_perclnt);
1810792c95ddSJ. Bruce Fields 		list_del(&ses->se_perclnt);
181166b2b9b2SJ. Bruce Fields 		WARN_ON_ONCE(atomic_read(&ses->se_ref));
181266b2b9b2SJ. Bruce Fields 		free_session(ses);
1813792c95ddSJ. Bruce Fields 	}
18144cb57e30STrond Myklebust 	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
181503a4e1f6SJ. Bruce Fields 	free_svc_cred(&clp->cl_cred);
1816d4f0489fSTrond Myklebust 	kfree(clp->cl_ownerstr_hashtbl);
18171da177e4SLinus Torvalds 	kfree(clp->cl_name.data);
18182d32b29aSmajianpeng 	idr_destroy(&clp->cl_stateids);
18191da177e4SLinus Torvalds 	kfree(clp);
18201da177e4SLinus Torvalds }
18211da177e4SLinus Torvalds 
182284d38ac9SBenny Halevy /* must be called under the client_lock */
18234beb345bSTrond Myklebust static void
182484d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp)
182584d38ac9SBenny Halevy {
18264beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1827792c95ddSJ. Bruce Fields 	struct nfsd4_session *ses;
1828792c95ddSJ. Bruce Fields 
18290a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
18300a880a28STrond Myklebust 
18314beb345bSTrond Myklebust 	/* Mark the client as expired! */
18324beb345bSTrond Myklebust 	clp->cl_time = 0;
18334beb345bSTrond Myklebust 	/* Make it invisible */
18344beb345bSTrond Myklebust 	if (!list_empty(&clp->cl_idhash)) {
18354beb345bSTrond Myklebust 		list_del_init(&clp->cl_idhash);
18364beb345bSTrond Myklebust 		if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
18374beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
18384beb345bSTrond Myklebust 		else
18394beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
18404beb345bSTrond Myklebust 	}
18414beb345bSTrond Myklebust 	list_del_init(&clp->cl_lru);
18424c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1843792c95ddSJ. Bruce Fields 	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
1844792c95ddSJ. Bruce Fields 		list_del_init(&ses->se_hash);
18454c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
184684d38ac9SBenny Halevy }
184784d38ac9SBenny Halevy 
18481da177e4SLinus Torvalds static void
18494beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp)
18504beb345bSTrond Myklebust {
18514beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
18524beb345bSTrond Myklebust 
18534beb345bSTrond Myklebust 	spin_lock(&nn->client_lock);
18544beb345bSTrond Myklebust 	unhash_client_locked(clp);
18554beb345bSTrond Myklebust 	spin_unlock(&nn->client_lock);
18564beb345bSTrond Myklebust }
18574beb345bSTrond Myklebust 
185897403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp)
185997403d95SJeff Layton {
186097403d95SJeff Layton 	if (atomic_read(&clp->cl_refcount))
186197403d95SJeff Layton 		return nfserr_jukebox;
186297403d95SJeff Layton 	unhash_client_locked(clp);
186397403d95SJeff Layton 	return nfs_ok;
186497403d95SJeff Layton }
186597403d95SJeff Layton 
18664beb345bSTrond Myklebust static void
18674beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp)
18681da177e4SLinus Torvalds {
1869fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
18701da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
18711da177e4SLinus Torvalds 	struct list_head reaplist;
18721da177e4SLinus Torvalds 
18731da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
1874cdc97505SBenny Halevy 	spin_lock(&state_lock);
1875ea1da636SNeilBrown 	while (!list_empty(&clp->cl_delegations)) {
1876ea1da636SNeilBrown 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
18773fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
187842690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
18791da177e4SLinus Torvalds 	}
1880cdc97505SBenny Halevy 	spin_unlock(&state_lock);
18811da177e4SLinus Torvalds 	while (!list_empty(&reaplist)) {
18821da177e4SLinus Torvalds 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
188342690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
18848287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
1885afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
18866011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
18871da177e4SLinus Torvalds 	}
18882d4a532dSJeff Layton 	while (!list_empty(&clp->cl_revoked)) {
1889c876486bSAndrew Elble 		dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru);
18902d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
18916011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
1892956c4feeSBenny Halevy 	}
1893ea1da636SNeilBrown 	while (!list_empty(&clp->cl_openowners)) {
1894fe0750e5SJ. Bruce Fields 		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
1895b5971afaSKinglong Mee 		nfs4_get_stateowner(&oo->oo_owner);
1896fe0750e5SJ. Bruce Fields 		release_openowner(oo);
18971da177e4SLinus Torvalds 	}
18989cf514ccSChristoph Hellwig 	nfsd4_return_all_client_layouts(clp);
18996ff8da08SJ. Bruce Fields 	nfsd4_shutdown_callback(clp);
19002bf23875SJ. Bruce Fields 	if (clp->cl_cb_conn.cb_xprt)
19012bf23875SJ. Bruce Fields 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1902b12a05cbSJ. Bruce Fields 	free_client(clp);
19031da177e4SLinus Torvalds }
19041da177e4SLinus Torvalds 
19054beb345bSTrond Myklebust static void
19064beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp)
19074beb345bSTrond Myklebust {
19084beb345bSTrond Myklebust 	unhash_client(clp);
19094beb345bSTrond Myklebust 	__destroy_client(clp);
19104beb345bSTrond Myklebust }
19114beb345bSTrond Myklebust 
19120d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp)
19130d22f68fSJ. Bruce Fields {
19144beb345bSTrond Myklebust 	unhash_client(clp);
19150d22f68fSJ. Bruce Fields 	nfsd4_client_record_remove(clp);
19164beb345bSTrond Myklebust 	__destroy_client(clp);
19170d22f68fSJ. Bruce Fields }
19180d22f68fSJ. Bruce Fields 
191935bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
192035bba9a3SJ. Bruce Fields {
192135bba9a3SJ. Bruce Fields 	memcpy(target->cl_verifier.data, source->data,
192235bba9a3SJ. Bruce Fields 			sizeof(target->cl_verifier.data));
19231da177e4SLinus Torvalds }
19241da177e4SLinus Torvalds 
192535bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
192635bba9a3SJ. Bruce Fields {
19271da177e4SLinus Torvalds 	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
19281da177e4SLinus Torvalds 	target->cl_clientid.cl_id = source->cl_clientid.cl_id;
19291da177e4SLinus Torvalds }
19301da177e4SLinus Torvalds 
193150043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source)
193250043859SJ. Bruce Fields {
19332f10fdcbSNeilBrown 	target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL);
19342f10fdcbSNeilBrown 	target->cr_raw_principal = kstrdup(source->cr_raw_principal,
19352f10fdcbSNeilBrown 								GFP_KERNEL);
19362f10fdcbSNeilBrown 	if ((source->cr_principal && ! target->cr_principal) ||
19372f10fdcbSNeilBrown 	    (source->cr_raw_principal && ! target->cr_raw_principal))
19382f10fdcbSNeilBrown 		return -ENOMEM;
193950043859SJ. Bruce Fields 
1940d5497fc6SJ. Bruce Fields 	target->cr_flavor = source->cr_flavor;
19411da177e4SLinus Torvalds 	target->cr_uid = source->cr_uid;
19421da177e4SLinus Torvalds 	target->cr_gid = source->cr_gid;
19431da177e4SLinus Torvalds 	target->cr_group_info = source->cr_group_info;
19441da177e4SLinus Torvalds 	get_group_info(target->cr_group_info);
19450dc1531aSJ. Bruce Fields 	target->cr_gss_mech = source->cr_gss_mech;
19460dc1531aSJ. Bruce Fields 	if (source->cr_gss_mech)
19470dc1531aSJ. Bruce Fields 		gss_mech_get(source->cr_gss_mech);
194803a4e1f6SJ. Bruce Fields 	return 0;
19491da177e4SLinus Torvalds }
19501da177e4SLinus Torvalds 
1951ef17af2aSRasmus Villemoes static int
1952ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
1953ac55fdc4SJeff Layton {
1954ef17af2aSRasmus Villemoes 	if (o1->len < o2->len)
1955ef17af2aSRasmus Villemoes 		return -1;
1956ef17af2aSRasmus Villemoes 	if (o1->len > o2->len)
1957ef17af2aSRasmus Villemoes 		return 1;
1958ef17af2aSRasmus Villemoes 	return memcmp(o1->data, o2->data, o1->len);
1959ac55fdc4SJeff Layton }
1960ac55fdc4SJeff Layton 
196135bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2)
1962599e0a22SJ. Bruce Fields {
1963a55370a3SNeilBrown 	return 0 == memcmp(n1, n2, HEXDIR_LEN);
19641da177e4SLinus Torvalds }
19651da177e4SLinus Torvalds 
19661da177e4SLinus Torvalds static int
1967599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
1968599e0a22SJ. Bruce Fields {
1969599e0a22SJ. Bruce Fields 	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
19701da177e4SLinus Torvalds }
19711da177e4SLinus Torvalds 
19721da177e4SLinus Torvalds static int
1973599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2)
1974599e0a22SJ. Bruce Fields {
1975599e0a22SJ. Bruce Fields 	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
19761da177e4SLinus Torvalds }
19771da177e4SLinus Torvalds 
19788fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2)
19798fbba96eSJ. Bruce Fields {
19808fbba96eSJ. Bruce Fields 	int i;
19818fbba96eSJ. Bruce Fields 
19828fbba96eSJ. Bruce Fields 	if (g1->ngroups != g2->ngroups)
19838fbba96eSJ. Bruce Fields 		return false;
19848fbba96eSJ. Bruce Fields 	for (i=0; i<g1->ngroups; i++)
198581243eacSAlexey Dobriyan 		if (!gid_eq(g1->gid[i], g2->gid[i]))
19868fbba96eSJ. Bruce Fields 			return false;
19878fbba96eSJ. Bruce Fields 	return true;
19888fbba96eSJ. Bruce Fields }
19898fbba96eSJ. Bruce Fields 
199068eb3508SJ. Bruce Fields /*
199168eb3508SJ. Bruce Fields  * RFC 3530 language requires clid_inuse be returned when the
199268eb3508SJ. Bruce Fields  * "principal" associated with a requests differs from that previously
199368eb3508SJ. Bruce Fields  * used.  We use uid, gid's, and gss principal string as our best
199468eb3508SJ. Bruce Fields  * approximation.  We also don't want to allow non-gss use of a client
199568eb3508SJ. Bruce Fields  * established using gss: in theory cr_principal should catch that
199668eb3508SJ. Bruce Fields  * change, but in practice cr_principal can be null even in the gss case
199768eb3508SJ. Bruce Fields  * since gssd doesn't always pass down a principal string.
199868eb3508SJ. Bruce Fields  */
199968eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr)
200068eb3508SJ. Bruce Fields {
200168eb3508SJ. Bruce Fields 	/* Is cr_flavor one of the gss "pseudoflavors"?: */
200268eb3508SJ. Bruce Fields 	return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
200368eb3508SJ. Bruce Fields }
200468eb3508SJ. Bruce Fields 
200568eb3508SJ. Bruce Fields 
20065559b50aSVivek Trivedi static bool
2007599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
2008599e0a22SJ. Bruce Fields {
200968eb3508SJ. Bruce Fields 	if ((is_gss_cred(cr1) != is_gss_cred(cr2))
20106fab8779SEric W. Biederman 		|| (!uid_eq(cr1->cr_uid, cr2->cr_uid))
20116fab8779SEric W. Biederman 		|| (!gid_eq(cr1->cr_gid, cr2->cr_gid))
20128fbba96eSJ. Bruce Fields 		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
20138fbba96eSJ. Bruce Fields 		return false;
20148fbba96eSJ. Bruce Fields 	if (cr1->cr_principal == cr2->cr_principal)
20158fbba96eSJ. Bruce Fields 		return true;
20168fbba96eSJ. Bruce Fields 	if (!cr1->cr_principal || !cr2->cr_principal)
20178fbba96eSJ. Bruce Fields 		return false;
20185559b50aSVivek Trivedi 	return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
20191da177e4SLinus Torvalds }
20201da177e4SLinus Torvalds 
202157266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
202257266a6eSJ. Bruce Fields {
202357266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
202457266a6eSJ. Bruce Fields 	u32 service;
202557266a6eSJ. Bruce Fields 
2026c4720591SJ. Bruce Fields 	if (!cr->cr_gss_mech)
2027c4720591SJ. Bruce Fields 		return false;
202857266a6eSJ. Bruce Fields 	service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
202957266a6eSJ. Bruce Fields 	return service == RPC_GSS_SVC_INTEGRITY ||
203057266a6eSJ. Bruce Fields 	       service == RPC_GSS_SVC_PRIVACY;
203157266a6eSJ. Bruce Fields }
203257266a6eSJ. Bruce Fields 
2033dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
203457266a6eSJ. Bruce Fields {
203557266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
203657266a6eSJ. Bruce Fields 
203757266a6eSJ. Bruce Fields 	if (!cl->cl_mach_cred)
203857266a6eSJ. Bruce Fields 		return true;
203957266a6eSJ. Bruce Fields 	if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
204057266a6eSJ. Bruce Fields 		return false;
204157266a6eSJ. Bruce Fields 	if (!svc_rqst_integrity_protected(rqstp))
204257266a6eSJ. Bruce Fields 		return false;
2043414ca017SJ. Bruce Fields 	if (cl->cl_cred.cr_raw_principal)
2044414ca017SJ. Bruce Fields 		return 0 == strcmp(cl->cl_cred.cr_raw_principal,
2045414ca017SJ. Bruce Fields 						cr->cr_raw_principal);
204657266a6eSJ. Bruce Fields 	if (!cr->cr_principal)
204757266a6eSJ. Bruce Fields 		return false;
204857266a6eSJ. Bruce Fields 	return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
204957266a6eSJ. Bruce Fields }
205057266a6eSJ. Bruce Fields 
2051294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
2052deda2faaSJ. Bruce Fields {
2053ab4684d1SChuck Lever 	__be32 verf[2];
20541da177e4SLinus Torvalds 
2055f419992cSJeff Layton 	/*
2056f419992cSJeff Layton 	 * This is opaque to client, so no need to byte-swap. Use
2057f419992cSJeff Layton 	 * __force to keep sparse happy
2058f419992cSJeff Layton 	 */
2059f419992cSJeff Layton 	verf[0] = (__force __be32)get_seconds();
206019311aa8SKinglong Mee 	verf[1] = (__force __be32)nn->clverifier_counter++;
2061ab4684d1SChuck Lever 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
20621da177e4SLinus Torvalds }
20631da177e4SLinus Torvalds 
2064294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
2065294ac32eSJeff Layton {
2066294ac32eSJeff Layton 	clp->cl_clientid.cl_boot = nn->boot_time;
2067294ac32eSJeff Layton 	clp->cl_clientid.cl_id = nn->clientid_counter++;
2068294ac32eSJeff Layton 	gen_confirm(clp, nn);
2069294ac32eSJeff Layton }
2070294ac32eSJeff Layton 
20714770d722SJeff Layton static struct nfs4_stid *
20724770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
20734581d140SJ. Bruce Fields {
20743abdb607SJ. Bruce Fields 	struct nfs4_stid *ret;
20753abdb607SJ. Bruce Fields 
20763abdb607SJ. Bruce Fields 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
20773abdb607SJ. Bruce Fields 	if (!ret || !ret->sc_type)
20783abdb607SJ. Bruce Fields 		return NULL;
20793abdb607SJ. Bruce Fields 	return ret;
20804581d140SJ. Bruce Fields }
20814d71ab87SJ. Bruce Fields 
20824770d722SJeff Layton static struct nfs4_stid *
20834770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
2084f459e453SJ. Bruce Fields {
2085f459e453SJ. Bruce Fields 	struct nfs4_stid *s;
2086f459e453SJ. Bruce Fields 
20874770d722SJeff Layton 	spin_lock(&cl->cl_lock);
20884770d722SJeff Layton 	s = find_stateid_locked(cl, t);
20892d3f9668STrond Myklebust 	if (s != NULL) {
20902d3f9668STrond Myklebust 		if (typemask & s->sc_type)
2091a15dfcd5SElena Reshetova 			refcount_inc(&s->sc_count);
20922d3f9668STrond Myklebust 		else
20934770d722SJeff Layton 			s = NULL;
20942d3f9668STrond Myklebust 	}
20954770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
20964d71ab87SJ. Bruce Fields 	return s;
20974581d140SJ. Bruce Fields }
20984581d140SJ. Bruce Fields 
20992216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name,
2100b09333c4SRicardo Labiaga 		struct svc_rqst *rqstp, nfs4_verifier *verf)
2101b09333c4SRicardo Labiaga {
2102b09333c4SRicardo Labiaga 	struct nfs4_client *clp;
2103b09333c4SRicardo Labiaga 	struct sockaddr *sa = svc_addr(rqstp);
210403a4e1f6SJ. Bruce Fields 	int ret;
2105c212cecfSStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
2106b09333c4SRicardo Labiaga 
2107b09333c4SRicardo Labiaga 	clp = alloc_client(name);
2108b09333c4SRicardo Labiaga 	if (clp == NULL)
2109b09333c4SRicardo Labiaga 		return NULL;
2110b09333c4SRicardo Labiaga 
211103a4e1f6SJ. Bruce Fields 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
211203a4e1f6SJ. Bruce Fields 	if (ret) {
2113b09333c4SRicardo Labiaga 		free_client(clp);
2114b09333c4SRicardo Labiaga 		return NULL;
2115b09333c4SRicardo Labiaga 	}
21160162ac2bSChristoph Hellwig 	nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL);
211707cd4909SBenny Halevy 	clp->cl_time = get_seconds();
2118b09333c4SRicardo Labiaga 	clear_bit(0, &clp->cl_cb_slot_busy);
2119b09333c4SRicardo Labiaga 	copy_verf(clp, verf);
2120b09333c4SRicardo Labiaga 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
2121edd76786SJ. Bruce Fields 	clp->cl_cb_session = NULL;
2122c212cecfSStanislav Kinsbursky 	clp->net = net;
2123b09333c4SRicardo Labiaga 	return clp;
2124b09333c4SRicardo Labiaga }
2125b09333c4SRicardo Labiaga 
2126fd39ca9aSNeilBrown static void
2127ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
2128ac55fdc4SJeff Layton {
2129ac55fdc4SJeff Layton 	struct rb_node **new = &(root->rb_node), *parent = NULL;
2130ac55fdc4SJeff Layton 	struct nfs4_client *clp;
2131ac55fdc4SJeff Layton 
2132ac55fdc4SJeff Layton 	while (*new) {
2133ac55fdc4SJeff Layton 		clp = rb_entry(*new, struct nfs4_client, cl_namenode);
2134ac55fdc4SJeff Layton 		parent = *new;
2135ac55fdc4SJeff Layton 
2136ac55fdc4SJeff Layton 		if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
2137ac55fdc4SJeff Layton 			new = &((*new)->rb_left);
2138ac55fdc4SJeff Layton 		else
2139ac55fdc4SJeff Layton 			new = &((*new)->rb_right);
2140ac55fdc4SJeff Layton 	}
2141ac55fdc4SJeff Layton 
2142ac55fdc4SJeff Layton 	rb_link_node(&new_clp->cl_namenode, parent, new);
2143ac55fdc4SJeff Layton 	rb_insert_color(&new_clp->cl_namenode, root);
2144ac55fdc4SJeff Layton }
2145ac55fdc4SJeff Layton 
2146ac55fdc4SJeff Layton static struct nfs4_client *
2147ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
2148ac55fdc4SJeff Layton {
2149ef17af2aSRasmus Villemoes 	int cmp;
2150ac55fdc4SJeff Layton 	struct rb_node *node = root->rb_node;
2151ac55fdc4SJeff Layton 	struct nfs4_client *clp;
2152ac55fdc4SJeff Layton 
2153ac55fdc4SJeff Layton 	while (node) {
2154ac55fdc4SJeff Layton 		clp = rb_entry(node, struct nfs4_client, cl_namenode);
2155ac55fdc4SJeff Layton 		cmp = compare_blob(&clp->cl_name, name);
2156ac55fdc4SJeff Layton 		if (cmp > 0)
2157ac55fdc4SJeff Layton 			node = node->rb_left;
2158ac55fdc4SJeff Layton 		else if (cmp < 0)
2159ac55fdc4SJeff Layton 			node = node->rb_right;
2160ac55fdc4SJeff Layton 		else
2161ac55fdc4SJeff Layton 			return clp;
2162ac55fdc4SJeff Layton 	}
2163ac55fdc4SJeff Layton 	return NULL;
2164ac55fdc4SJeff Layton }
2165ac55fdc4SJeff Layton 
2166ac55fdc4SJeff Layton static void
2167ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp)
21681da177e4SLinus Torvalds {
21691da177e4SLinus Torvalds 	unsigned int idhashval;
21700a7ec377SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
21711da177e4SLinus Torvalds 
21720a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
21730a880a28STrond Myklebust 
2174ac55fdc4SJeff Layton 	clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
2175a99454aaSStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
21761da177e4SLinus Torvalds 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
21770a7ec377SStanislav Kinsbursky 	list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
21783dbacee6STrond Myklebust 	renew_client_locked(clp);
21791da177e4SLinus Torvalds }
21801da177e4SLinus Torvalds 
2181fd39ca9aSNeilBrown static void
21821da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp)
21831da177e4SLinus Torvalds {
21841da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
21858daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
21861da177e4SLinus Torvalds 
21870a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
21880a880a28STrond Myklebust 
21891da177e4SLinus Torvalds 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
21908daae4dcSStanislav Kinsbursky 	list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
2191a99454aaSStanislav Kinsbursky 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
2192382a62e7SStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->conf_name_tree);
2193ac55fdc4SJeff Layton 	set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
21943dbacee6STrond Myklebust 	renew_client_locked(clp);
21951da177e4SLinus Torvalds }
21961da177e4SLinus Torvalds 
21971da177e4SLinus Torvalds static struct nfs4_client *
2198bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
21991da177e4SLinus Torvalds {
22001da177e4SLinus Torvalds 	struct nfs4_client *clp;
22011da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clid->cl_id);
22021da177e4SLinus Torvalds 
2203bfa85e83SJ. Bruce Fields 	list_for_each_entry(clp, &tbl[idhashval], cl_idhash) {
2204a50d2ad1SJ. Bruce Fields 		if (same_clid(&clp->cl_clientid, clid)) {
2205d15c077eSJ. Bruce Fields 			if ((bool)clp->cl_minorversion != sessions)
2206d15c077eSJ. Bruce Fields 				return NULL;
22073dbacee6STrond Myklebust 			renew_client_locked(clp);
22081da177e4SLinus Torvalds 			return clp;
22091da177e4SLinus Torvalds 		}
2210a50d2ad1SJ. Bruce Fields 	}
22111da177e4SLinus Torvalds 	return NULL;
22121da177e4SLinus Torvalds }
22131da177e4SLinus Torvalds 
22141da177e4SLinus Torvalds static struct nfs4_client *
2215bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
2216bfa85e83SJ. Bruce Fields {
2217bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->conf_id_hashtbl;
2218bfa85e83SJ. Bruce Fields 
22190a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2220bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
2221bfa85e83SJ. Bruce Fields }
2222bfa85e83SJ. Bruce Fields 
2223bfa85e83SJ. Bruce Fields static struct nfs4_client *
22240a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
22251da177e4SLinus Torvalds {
2226bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->unconf_id_hashtbl;
22271da177e4SLinus Torvalds 
22280a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2229bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
22301da177e4SLinus Torvalds }
22311da177e4SLinus Torvalds 
22326e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp)
2233a1bcecd2SAndy Adamson {
22346e5f15c9SJ. Bruce Fields 	return clp->cl_exchange_flags != 0;
2235a1bcecd2SAndy Adamson }
2236a1bcecd2SAndy Adamson 
223728ce6054SNeilBrown static struct nfs4_client *
2238382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
223928ce6054SNeilBrown {
22400a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2241382a62e7SStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->conf_name_tree);
224228ce6054SNeilBrown }
224328ce6054SNeilBrown 
224428ce6054SNeilBrown static struct nfs4_client *
2245a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
224628ce6054SNeilBrown {
22470a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2248a99454aaSStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->unconf_name_tree);
224928ce6054SNeilBrown }
225028ce6054SNeilBrown 
2251fd39ca9aSNeilBrown static void
22526f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
22531da177e4SLinus Torvalds {
225407263f1eSJ. Bruce Fields 	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
22556f3d772fSTakuma Umeya 	struct sockaddr	*sa = svc_addr(rqstp);
22566f3d772fSTakuma Umeya 	u32 scopeid = rpc_get_scope_id(sa);
22577077ecbaSJeff Layton 	unsigned short expected_family;
22581da177e4SLinus Torvalds 
22597077ecbaSJeff Layton 	/* Currently, we only support tcp and tcp6 for the callback channel */
22607077ecbaSJeff Layton 	if (se->se_callback_netid_len == 3 &&
22617077ecbaSJeff Layton 	    !memcmp(se->se_callback_netid_val, "tcp", 3))
22627077ecbaSJeff Layton 		expected_family = AF_INET;
22637077ecbaSJeff Layton 	else if (se->se_callback_netid_len == 4 &&
22647077ecbaSJeff Layton 		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
22657077ecbaSJeff Layton 		expected_family = AF_INET6;
22667077ecbaSJeff Layton 	else
22671da177e4SLinus Torvalds 		goto out_err;
22681da177e4SLinus Torvalds 
2269c212cecfSStanislav Kinsbursky 	conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val,
2270aa9a4ec7SJeff Layton 					    se->se_callback_addr_len,
227107263f1eSJ. Bruce Fields 					    (struct sockaddr *)&conn->cb_addr,
227207263f1eSJ. Bruce Fields 					    sizeof(conn->cb_addr));
2273aa9a4ec7SJeff Layton 
227407263f1eSJ. Bruce Fields 	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
22751da177e4SLinus Torvalds 		goto out_err;
2276aa9a4ec7SJeff Layton 
227707263f1eSJ. Bruce Fields 	if (conn->cb_addr.ss_family == AF_INET6)
227807263f1eSJ. Bruce Fields 		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
2279fbf4665fSJeff Layton 
228007263f1eSJ. Bruce Fields 	conn->cb_prog = se->se_callback_prog;
228107263f1eSJ. Bruce Fields 	conn->cb_ident = se->se_callback_ident;
2282849a1cf1SMi Jinlong 	memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
22831da177e4SLinus Torvalds 	return;
22841da177e4SLinus Torvalds out_err:
228507263f1eSJ. Bruce Fields 	conn->cb_addr.ss_family = AF_UNSPEC;
228607263f1eSJ. Bruce Fields 	conn->cb_addrlen = 0;
22874ab495bfSRasmus Villemoes 	dprintk("NFSD: this client (clientid %08x/%08x) "
22881da177e4SLinus Torvalds 		"will not receive delegations\n",
22891da177e4SLinus Torvalds 		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
22901da177e4SLinus Torvalds 
22911da177e4SLinus Torvalds 	return;
22921da177e4SLinus Torvalds }
22931da177e4SLinus Torvalds 
2294074fe897SAndy Adamson /*
2295067e1aceSJ. Bruce Fields  * Cache a reply. nfsd4_check_resp_size() has bounded the cache size.
2296074fe897SAndy Adamson  */
2297b607664eSTrond Myklebust static void
2298074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
2299074fe897SAndy Adamson {
2300f5236013SJ. Bruce Fields 	struct xdr_buf *buf = resp->xdr.buf;
2301557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2302557ce264SAndy Adamson 	unsigned int base;
2303074fe897SAndy Adamson 
2304557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2305074fe897SAndy Adamson 
2306085def3aSJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
2307557ce264SAndy Adamson 	slot->sl_opcnt = resp->opcnt;
2308557ce264SAndy Adamson 	slot->sl_status = resp->cstate.status;
230953da6a53SJ. Bruce Fields 	free_svc_cred(&slot->sl_cred);
231053da6a53SJ. Bruce Fields 	copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred);
2311bf864a31SAndy Adamson 
2312085def3aSJ. Bruce Fields 	if (!nfsd4_cache_this(resp)) {
2313085def3aSJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHED;
2314bf864a31SAndy Adamson 		return;
2315bf864a31SAndy Adamson 	}
2316085def3aSJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_CACHED;
2317085def3aSJ. Bruce Fields 
2318f5236013SJ. Bruce Fields 	base = resp->cstate.data_offset;
2319f5236013SJ. Bruce Fields 	slot->sl_datalen = buf->len - base;
2320f5236013SJ. Bruce Fields 	if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
2321d3f03403SDan Carpenter 		WARN(1, "%s: sessions DRC could not cache compound\n",
2322d3f03403SDan Carpenter 		     __func__);
2323557ce264SAndy Adamson 	return;
2324074fe897SAndy Adamson }
2325074fe897SAndy Adamson 
2326074fe897SAndy Adamson /*
2327abfabf8cSAndy Adamson  * Encode the replay sequence operation from the slot values.
2328abfabf8cSAndy Adamson  * If cachethis is FALSE encode the uncached rep error on the next
2329abfabf8cSAndy Adamson  * operation which sets resp->p and increments resp->opcnt for
2330abfabf8cSAndy Adamson  * nfs4svc_encode_compoundres.
2331abfabf8cSAndy Adamson  *
2332074fe897SAndy Adamson  */
2333abfabf8cSAndy Adamson static __be32
2334abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
2335abfabf8cSAndy Adamson 			  struct nfsd4_compoundres *resp)
2336074fe897SAndy Adamson {
2337abfabf8cSAndy Adamson 	struct nfsd4_op *op;
2338abfabf8cSAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2339074fe897SAndy Adamson 
2340abfabf8cSAndy Adamson 	/* Encode the replayed sequence operation */
2341abfabf8cSAndy Adamson 	op = &args->ops[resp->opcnt - 1];
2342abfabf8cSAndy Adamson 	nfsd4_encode_operation(resp, op);
2343abfabf8cSAndy Adamson 
2344085def3aSJ. Bruce Fields 	if (slot->sl_flags & NFSD4_SLOT_CACHED)
2345085def3aSJ. Bruce Fields 		return op->status;
2346085def3aSJ. Bruce Fields 	if (args->opcnt == 1) {
2347085def3aSJ. Bruce Fields 		/*
2348085def3aSJ. Bruce Fields 		 * The original operation wasn't a solo sequence--we
2349085def3aSJ. Bruce Fields 		 * always cache those--so this retry must not match the
2350085def3aSJ. Bruce Fields 		 * original:
2351085def3aSJ. Bruce Fields 		 */
2352085def3aSJ. Bruce Fields 		op->status = nfserr_seq_false_retry;
2353085def3aSJ. Bruce Fields 	} else {
2354abfabf8cSAndy Adamson 		op = &args->ops[resp->opcnt++];
2355abfabf8cSAndy Adamson 		op->status = nfserr_retry_uncached_rep;
2356abfabf8cSAndy Adamson 		nfsd4_encode_operation(resp, op);
2357074fe897SAndy Adamson 	}
2358abfabf8cSAndy Adamson 	return op->status;
2359074fe897SAndy Adamson }
2360074fe897SAndy Adamson 
2361074fe897SAndy Adamson /*
2362557ce264SAndy Adamson  * The sequence operation is not cached because we can use the slot and
2363557ce264SAndy Adamson  * session values.
2364074fe897SAndy Adamson  */
23653ca2eb98SJ. Bruce Fields static __be32
2366bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
2367bf864a31SAndy Adamson 			 struct nfsd4_sequence *seq)
2368074fe897SAndy Adamson {
2369557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2370f5236013SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2371f5236013SJ. Bruce Fields 	__be32 *p;
2372074fe897SAndy Adamson 	__be32 status;
2373074fe897SAndy Adamson 
2374557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2375074fe897SAndy Adamson 
2376abfabf8cSAndy Adamson 	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
23770da7b19cSJ. Bruce Fields 	if (status)
2378abfabf8cSAndy Adamson 		return status;
2379074fe897SAndy Adamson 
2380f5236013SJ. Bruce Fields 	p = xdr_reserve_space(xdr, slot->sl_datalen);
2381f5236013SJ. Bruce Fields 	if (!p) {
2382f5236013SJ. Bruce Fields 		WARN_ON_ONCE(1);
2383f5236013SJ. Bruce Fields 		return nfserr_serverfault;
2384f5236013SJ. Bruce Fields 	}
2385f5236013SJ. Bruce Fields 	xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen);
2386f5236013SJ. Bruce Fields 	xdr_commit_encode(xdr);
2387074fe897SAndy Adamson 
2388557ce264SAndy Adamson 	resp->opcnt = slot->sl_opcnt;
2389f5236013SJ. Bruce Fields 	return slot->sl_status;
2390074fe897SAndy Adamson }
2391074fe897SAndy Adamson 
23920733d213SAndy Adamson /*
23930733d213SAndy Adamson  * Set the exchange_id flags returned by the server.
23940733d213SAndy Adamson  */
23950733d213SAndy Adamson static void
23960733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
23970733d213SAndy Adamson {
23989cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
23999cf514ccSChristoph Hellwig 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS;
24009cf514ccSChristoph Hellwig #else
24010733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
24029cf514ccSChristoph Hellwig #endif
24030733d213SAndy Adamson 
24040733d213SAndy Adamson 	/* Referrals are supported, Migration is not. */
24050733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
24060733d213SAndy Adamson 
24070733d213SAndy Adamson 	/* set the wire flags to return to client. */
24080733d213SAndy Adamson 	clid->flags = new->cl_exchange_flags;
24090733d213SAndy Adamson }
24100733d213SAndy Adamson 
24114eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp)
24124eaea134SJ. Bruce Fields {
24134eaea134SJ. Bruce Fields 	struct nfs4_openowner *oo;
24144eaea134SJ. Bruce Fields 
24154eaea134SJ. Bruce Fields 	list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) {
24164eaea134SJ. Bruce Fields 		if (!list_empty(&oo->oo_owner.so_stateids))
24174eaea134SJ. Bruce Fields 			return true;
24184eaea134SJ. Bruce Fields 	}
24194eaea134SJ. Bruce Fields 	return false;
24204eaea134SJ. Bruce Fields }
24214eaea134SJ. Bruce Fields 
2422631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp)
2423631fc9eaSJ. Bruce Fields {
24244eaea134SJ. Bruce Fields 	return client_has_openowners(clp)
242547e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS
242647e970beSKinglong Mee 		|| !list_empty(&clp->cl_lo_states)
242747e970beSKinglong Mee #endif
24286eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_delegations)
24296eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_sessions);
2430631fc9eaSJ. Bruce Fields }
2431631fc9eaSJ. Bruce Fields 
2432b37ad28bSAl Viro __be32
2433eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2434eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
2435069b6ad4SAndy Adamson {
2436eb69853dSChristoph Hellwig 	struct nfsd4_exchange_id *exid = &u->exchange_id;
24373dbacee6STrond Myklebust 	struct nfs4_client *conf, *new;
24383dbacee6STrond Myklebust 	struct nfs4_client *unconf = NULL;
243957b7b43bSJ. Bruce Fields 	__be32 status;
2440363168b4SJeff Layton 	char			addr_str[INET6_ADDRSTRLEN];
24410733d213SAndy Adamson 	nfs4_verifier		verf = exid->verifier;
2442363168b4SJeff Layton 	struct sockaddr		*sa = svc_addr(rqstp);
244383e08fd4SJ. Bruce Fields 	bool	update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A;
2444c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
24450733d213SAndy Adamson 
2446363168b4SJeff Layton 	rpc_ntop(sa, addr_str, sizeof(addr_str));
24470733d213SAndy Adamson 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
2448363168b4SJeff Layton 		"ip_addr=%s flags %x, spa_how %d\n",
24490733d213SAndy Adamson 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
2450363168b4SJeff Layton 		addr_str, exid->flags, exid->spa_how);
24510733d213SAndy Adamson 
2452a084daf5SJ. Bruce Fields 	if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
24530733d213SAndy Adamson 		return nfserr_inval;
24540733d213SAndy Adamson 
245550c7b948SJ. Bruce Fields 	new = create_client(exid->clname, rqstp, &verf);
245650c7b948SJ. Bruce Fields 	if (new == NULL)
245750c7b948SJ. Bruce Fields 		return nfserr_jukebox;
245850c7b948SJ. Bruce Fields 
24590733d213SAndy Adamson 	switch (exid->spa_how) {
246057266a6eSJ. Bruce Fields 	case SP4_MACH_CRED:
2461ed941643SAndrew Elble 		exid->spo_must_enforce[0] = 0;
2462ed941643SAndrew Elble 		exid->spo_must_enforce[1] = (
2463ed941643SAndrew Elble 			1 << (OP_BIND_CONN_TO_SESSION - 32) |
2464ed941643SAndrew Elble 			1 << (OP_EXCHANGE_ID - 32) |
2465ed941643SAndrew Elble 			1 << (OP_CREATE_SESSION - 32) |
2466ed941643SAndrew Elble 			1 << (OP_DESTROY_SESSION - 32) |
2467ed941643SAndrew Elble 			1 << (OP_DESTROY_CLIENTID - 32));
2468ed941643SAndrew Elble 
2469ed941643SAndrew Elble 		exid->spo_must_allow[0] &= (1 << (OP_CLOSE) |
2470ed941643SAndrew Elble 					1 << (OP_OPEN_DOWNGRADE) |
2471ed941643SAndrew Elble 					1 << (OP_LOCKU) |
2472ed941643SAndrew Elble 					1 << (OP_DELEGRETURN));
2473ed941643SAndrew Elble 
2474ed941643SAndrew Elble 		exid->spo_must_allow[1] &= (
2475ed941643SAndrew Elble 					1 << (OP_TEST_STATEID - 32) |
2476ed941643SAndrew Elble 					1 << (OP_FREE_STATEID - 32));
247750c7b948SJ. Bruce Fields 		if (!svc_rqst_integrity_protected(rqstp)) {
247850c7b948SJ. Bruce Fields 			status = nfserr_inval;
247950c7b948SJ. Bruce Fields 			goto out_nolock;
248050c7b948SJ. Bruce Fields 		}
2481920dd9bbSJ. Bruce Fields 		/*
2482920dd9bbSJ. Bruce Fields 		 * Sometimes userspace doesn't give us a principal.
2483920dd9bbSJ. Bruce Fields 		 * Which is a bug, really.  Anyway, we can't enforce
2484920dd9bbSJ. Bruce Fields 		 * MACH_CRED in that case, better to give up now:
2485920dd9bbSJ. Bruce Fields 		 */
2486414ca017SJ. Bruce Fields 		if (!new->cl_cred.cr_principal &&
2487414ca017SJ. Bruce Fields 					!new->cl_cred.cr_raw_principal) {
2488920dd9bbSJ. Bruce Fields 			status = nfserr_serverfault;
2489920dd9bbSJ. Bruce Fields 			goto out_nolock;
2490920dd9bbSJ. Bruce Fields 		}
249150c7b948SJ. Bruce Fields 		new->cl_mach_cred = true;
24920733d213SAndy Adamson 	case SP4_NONE:
24930733d213SAndy Adamson 		break;
2494063b0fb9SJ. Bruce Fields 	default:				/* checked by xdr code */
2495063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
24960733d213SAndy Adamson 	case SP4_SSV:
24978edf4b02SKinglong Mee 		status = nfserr_encr_alg_unsupp;
24988edf4b02SKinglong Mee 		goto out_nolock;
24990733d213SAndy Adamson 	}
25000733d213SAndy Adamson 
25012dbb269dSJ. Bruce Fields 	/* Cases below refer to rfc 5661 section 18.35.4: */
25023dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
2503382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&exid->clname, nn);
25040733d213SAndy Adamson 	if (conf) {
250583e08fd4SJ. Bruce Fields 		bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
250683e08fd4SJ. Bruce Fields 		bool verfs_match = same_verf(&verf, &conf->cl_verifier);
250783e08fd4SJ. Bruce Fields 
2508136e658dSJ. Bruce Fields 		if (update) {
2509136e658dSJ. Bruce Fields 			if (!clp_used_exchangeid(conf)) { /* buggy client */
25102dbb269dSJ. Bruce Fields 				status = nfserr_inval;
2511e203d506SJ. Bruce Fields 				goto out;
2512e203d506SJ. Bruce Fields 			}
2513dedeb13fSAndrew Elble 			if (!nfsd4_mach_creds_match(conf, rqstp)) {
251457266a6eSJ. Bruce Fields 				status = nfserr_wrong_cred;
251557266a6eSJ. Bruce Fields 				goto out;
251657266a6eSJ. Bruce Fields 			}
25172dbb269dSJ. Bruce Fields 			if (!creds_match) { /* case 9 */
25180733d213SAndy Adamson 				status = nfserr_perm;
25190733d213SAndy Adamson 				goto out;
25200733d213SAndy Adamson 			}
25212dbb269dSJ. Bruce Fields 			if (!verfs_match) { /* case 8 */
25220733d213SAndy Adamson 				status = nfserr_not_same;
25230733d213SAndy Adamson 				goto out;
25240733d213SAndy Adamson 			}
2525136e658dSJ. Bruce Fields 			/* case 6 */
25260733d213SAndy Adamson 			exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
25270733d213SAndy Adamson 			goto out_copy;
25286ddbbbfeSMike Sager 		}
2529136e658dSJ. Bruce Fields 		if (!creds_match) { /* case 3 */
2530631fc9eaSJ. Bruce Fields 			if (client_has_state(conf)) {
2531136e658dSJ. Bruce Fields 				status = nfserr_clid_inuse;
2532136e658dSJ. Bruce Fields 				goto out;
2533136e658dSJ. Bruce Fields 			}
2534b9831b59SJ. Bruce Fields 			goto out_new;
2535631fc9eaSJ. Bruce Fields 		}
2536136e658dSJ. Bruce Fields 		if (verfs_match) { /* case 2 */
25370f1ba0efSJ. Bruce Fields 			conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
2538136e658dSJ. Bruce Fields 			goto out_copy;
2539136e658dSJ. Bruce Fields 		}
25402dbb269dSJ. Bruce Fields 		/* case 5, client reboot */
25413dbacee6STrond Myklebust 		conf = NULL;
25420733d213SAndy Adamson 		goto out_new;
25430733d213SAndy Adamson 	}
25446ddbbbfeSMike Sager 
25452dbb269dSJ. Bruce Fields 	if (update) { /* case 7 */
25460733d213SAndy Adamson 		status = nfserr_noent;
25470733d213SAndy Adamson 		goto out;
25480733d213SAndy Adamson 	}
25490733d213SAndy Adamson 
2550a99454aaSStanislav Kinsbursky 	unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
25512dbb269dSJ. Bruce Fields 	if (unconf) /* case 4, possible retry or client restart */
25523dbacee6STrond Myklebust 		unhash_client_locked(unconf);
25530733d213SAndy Adamson 
25542dbb269dSJ. Bruce Fields 	/* case 1 (normal case) */
25550733d213SAndy Adamson out_new:
2556fd699b8aSJeff Layton 	if (conf) {
2557fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
2558fd699b8aSJeff Layton 		if (status)
2559fd699b8aSJeff Layton 			goto out;
2560fd699b8aSJeff Layton 	}
25614f540e29SJ. Bruce Fields 	new->cl_minorversion = cstate->minorversion;
2562ed941643SAndrew Elble 	new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0];
2563ed941643SAndrew Elble 	new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1];
25640733d213SAndy Adamson 
2565c212cecfSStanislav Kinsbursky 	gen_clid(new, nn);
2566ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
25673dbacee6STrond Myklebust 	swap(new, conf);
25680733d213SAndy Adamson out_copy:
25695cc40fd7STrond Myklebust 	exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
25705cc40fd7STrond Myklebust 	exid->clientid.cl_id = conf->cl_clientid.cl_id;
25710733d213SAndy Adamson 
25725cc40fd7STrond Myklebust 	exid->seqid = conf->cl_cs_slot.sl_seqid + 1;
25735cc40fd7STrond Myklebust 	nfsd4_set_ex_flags(conf, exid);
25740733d213SAndy Adamson 
25750733d213SAndy Adamson 	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
25765cc40fd7STrond Myklebust 		conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags);
25770733d213SAndy Adamson 	status = nfs_ok;
25780733d213SAndy Adamson 
25790733d213SAndy Adamson out:
25803dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
258150c7b948SJ. Bruce Fields out_nolock:
25825cc40fd7STrond Myklebust 	if (new)
25833dbacee6STrond Myklebust 		expire_client(new);
25843dbacee6STrond Myklebust 	if (unconf)
25853dbacee6STrond Myklebust 		expire_client(unconf);
25860733d213SAndy Adamson 	return status;
2587069b6ad4SAndy Adamson }
2588069b6ad4SAndy Adamson 
258957b7b43bSJ. Bruce Fields static __be32
259088e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
2591b85d4c01SBenny Halevy {
259288e588d5SAndy Adamson 	dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
259388e588d5SAndy Adamson 		slot_seqid);
2594b85d4c01SBenny Halevy 
2595b85d4c01SBenny Halevy 	/* The slot is in use, and no response has been sent. */
259688e588d5SAndy Adamson 	if (slot_inuse) {
259788e588d5SAndy Adamson 		if (seqid == slot_seqid)
2598b85d4c01SBenny Halevy 			return nfserr_jukebox;
2599b85d4c01SBenny Halevy 		else
2600b85d4c01SBenny Halevy 			return nfserr_seq_misordered;
2601b85d4c01SBenny Halevy 	}
2602f6d82485SJ. Bruce Fields 	/* Note unsigned 32-bit arithmetic handles wraparound: */
260388e588d5SAndy Adamson 	if (likely(seqid == slot_seqid + 1))
2604b85d4c01SBenny Halevy 		return nfs_ok;
260588e588d5SAndy Adamson 	if (seqid == slot_seqid)
2606b85d4c01SBenny Halevy 		return nfserr_replay_cache;
2607b85d4c01SBenny Halevy 	return nfserr_seq_misordered;
2608b85d4c01SBenny Halevy }
2609b85d4c01SBenny Halevy 
261049557cc7SAndy Adamson /*
261149557cc7SAndy Adamson  * Cache the create session result into the create session single DRC
261249557cc7SAndy Adamson  * slot cache by saving the xdr structure. sl_seqid has been set.
261349557cc7SAndy Adamson  * Do this for solo or embedded create session operations.
261449557cc7SAndy Adamson  */
261549557cc7SAndy Adamson static void
261649557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
261757b7b43bSJ. Bruce Fields 			   struct nfsd4_clid_slot *slot, __be32 nfserr)
261849557cc7SAndy Adamson {
261949557cc7SAndy Adamson 	slot->sl_status = nfserr;
262049557cc7SAndy Adamson 	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
262149557cc7SAndy Adamson }
262249557cc7SAndy Adamson 
262349557cc7SAndy Adamson static __be32
262449557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
262549557cc7SAndy Adamson 			    struct nfsd4_clid_slot *slot)
262649557cc7SAndy Adamson {
262749557cc7SAndy Adamson 	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
262849557cc7SAndy Adamson 	return slot->sl_status;
262949557cc7SAndy Adamson }
263049557cc7SAndy Adamson 
26311b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
26321b74c25bSMi Jinlong 			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
26331b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
26341b74c25bSMi Jinlong 			3 +	/* version, opcount, opcode */ \
26351b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
26361b74c25bSMi Jinlong 				/* seqid, slotID, slotID, cache */ \
26371b74c25bSMi Jinlong 			4 ) * sizeof(__be32))
26381b74c25bSMi Jinlong 
26391b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
26401b74c25bSMi Jinlong 			2 +	/* verifier: AUTH_NULL, length 0 */\
26411b74c25bSMi Jinlong 			1 +	/* status */ \
26421b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
26431b74c25bSMi Jinlong 			3 +	/* opcount, opcode, opstatus*/ \
26441b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
26451b74c25bSMi Jinlong 				/* seqid, slotID, slotID, slotID, status */ \
26461b74c25bSMi Jinlong 			5 ) * sizeof(__be32))
26471b74c25bSMi Jinlong 
264855c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn)
26491b74c25bSMi Jinlong {
265055c760cfSJ. Bruce Fields 	u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
265155c760cfSJ. Bruce Fields 
2652373cd409SJ. Bruce Fields 	if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
2653373cd409SJ. Bruce Fields 		return nfserr_toosmall;
2654373cd409SJ. Bruce Fields 	if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
2655373cd409SJ. Bruce Fields 		return nfserr_toosmall;
265655c760cfSJ. Bruce Fields 	ca->headerpadsz = 0;
265755c760cfSJ. Bruce Fields 	ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
265855c760cfSJ. Bruce Fields 	ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
265955c760cfSJ. Bruce Fields 	ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
266055c760cfSJ. Bruce Fields 	ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
266155c760cfSJ. Bruce Fields 			NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
266255c760cfSJ. Bruce Fields 	ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
266355c760cfSJ. Bruce Fields 	/*
266455c760cfSJ. Bruce Fields 	 * Note decreasing slot size below client's request may make it
266555c760cfSJ. Bruce Fields 	 * difficult for client to function correctly, whereas
266655c760cfSJ. Bruce Fields 	 * decreasing the number of slots will (just?) affect
266755c760cfSJ. Bruce Fields 	 * performance.  When short on memory we therefore prefer to
266855c760cfSJ. Bruce Fields 	 * decrease number of slots instead of their size.  Clients that
266955c760cfSJ. Bruce Fields 	 * request larger slots than they need will get poor results:
267055c760cfSJ. Bruce Fields 	 */
267155c760cfSJ. Bruce Fields 	ca->maxreqs = nfsd4_get_drc_mem(ca);
267255c760cfSJ. Bruce Fields 	if (!ca->maxreqs)
267355c760cfSJ. Bruce Fields 		return nfserr_jukebox;
267455c760cfSJ. Bruce Fields 
2675373cd409SJ. Bruce Fields 	return nfs_ok;
26761b74c25bSMi Jinlong }
26771b74c25bSMi Jinlong 
26784500632fSChuck Lever /*
26794500632fSChuck Lever  * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now.
26804500632fSChuck Lever  * These are based on similar macros in linux/sunrpc/msg_prot.h .
26814500632fSChuck Lever  */
26824500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \
26834500632fSChuck Lever 	(RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK))
26844500632fSChuck Lever 
26854500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \
26864500632fSChuck Lever 	(RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK))
26874500632fSChuck Lever 
26888a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ	((NFS4_enc_cb_recall_sz + \
26894500632fSChuck Lever 				 RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32))
26908a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ	((NFS4_dec_cb_recall_sz + \
26914500632fSChuck Lever 				 RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \
26924500632fSChuck Lever 				 sizeof(__be32))
26938a891633SKinglong Mee 
269406b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
269506b332a5SJ. Bruce Fields {
269606b332a5SJ. Bruce Fields 	ca->headerpadsz = 0;
269706b332a5SJ. Bruce Fields 
26988a891633SKinglong Mee 	if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ)
269906b332a5SJ. Bruce Fields 		return nfserr_toosmall;
27008a891633SKinglong Mee 	if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ)
270106b332a5SJ. Bruce Fields 		return nfserr_toosmall;
270206b332a5SJ. Bruce Fields 	ca->maxresp_cached = 0;
270306b332a5SJ. Bruce Fields 	if (ca->maxops < 2)
270406b332a5SJ. Bruce Fields 		return nfserr_toosmall;
270506b332a5SJ. Bruce Fields 
270606b332a5SJ. Bruce Fields 	return nfs_ok;
2707069b6ad4SAndy Adamson }
2708069b6ad4SAndy Adamson 
2709b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
2710b78724b7SJ. Bruce Fields {
2711b78724b7SJ. Bruce Fields 	switch (cbs->flavor) {
2712b78724b7SJ. Bruce Fields 	case RPC_AUTH_NULL:
2713b78724b7SJ. Bruce Fields 	case RPC_AUTH_UNIX:
2714b78724b7SJ. Bruce Fields 		return nfs_ok;
2715b78724b7SJ. Bruce Fields 	default:
2716b78724b7SJ. Bruce Fields 		/*
2717b78724b7SJ. Bruce Fields 		 * GSS case: the spec doesn't allow us to return this
2718b78724b7SJ. Bruce Fields 		 * error.  But it also doesn't allow us not to support
2719b78724b7SJ. Bruce Fields 		 * GSS.
2720b78724b7SJ. Bruce Fields 		 * I'd rather this fail hard than return some error the
2721b78724b7SJ. Bruce Fields 		 * client might think it can already handle:
2722b78724b7SJ. Bruce Fields 		 */
2723b78724b7SJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
2724b78724b7SJ. Bruce Fields 	}
2725b78724b7SJ. Bruce Fields }
2726b78724b7SJ. Bruce Fields 
2727069b6ad4SAndy Adamson __be32
2728069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp,
2729eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
2730069b6ad4SAndy Adamson {
2731eb69853dSChristoph Hellwig 	struct nfsd4_create_session *cr_ses = &u->create_session;
2732363168b4SJeff Layton 	struct sockaddr *sa = svc_addr(rqstp);
2733ec6b5d7bSAndy Adamson 	struct nfs4_client *conf, *unconf;
2734d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
2735ac7c46f2SJ. Bruce Fields 	struct nfsd4_session *new;
273681f0b2a4SJ. Bruce Fields 	struct nfsd4_conn *conn;
273749557cc7SAndy Adamson 	struct nfsd4_clid_slot *cs_slot = NULL;
273857b7b43bSJ. Bruce Fields 	__be32 status = 0;
27398daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2740ec6b5d7bSAndy Adamson 
2741a62573dcSMi Jinlong 	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
2742a62573dcSMi Jinlong 		return nfserr_inval;
2743b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
2744b78724b7SJ. Bruce Fields 	if (status)
2745b78724b7SJ. Bruce Fields 		return status;
274655c760cfSJ. Bruce Fields 	status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
2747373cd409SJ. Bruce Fields 	if (status)
2748373cd409SJ. Bruce Fields 		return status;
274906b332a5SJ. Bruce Fields 	status = check_backchannel_attrs(&cr_ses->back_channel);
275006b332a5SJ. Bruce Fields 	if (status)
2751f403e450SKinglong Mee 		goto out_release_drc_mem;
275281f0b2a4SJ. Bruce Fields 	status = nfserr_jukebox;
275360810e54SKinglong Mee 	new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
275455c760cfSJ. Bruce Fields 	if (!new)
275555c760cfSJ. Bruce Fields 		goto out_release_drc_mem;
275681f0b2a4SJ. Bruce Fields 	conn = alloc_conn_from_crses(rqstp, cr_ses);
275781f0b2a4SJ. Bruce Fields 	if (!conn)
275881f0b2a4SJ. Bruce Fields 		goto out_free_session;
2759a62573dcSMi Jinlong 
2760d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
27610a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
27628daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
276378389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2764ec6b5d7bSAndy Adamson 
2765ec6b5d7bSAndy Adamson 	if (conf) {
276657266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
2767dedeb13fSAndrew Elble 		if (!nfsd4_mach_creds_match(conf, rqstp))
276857266a6eSJ. Bruce Fields 			goto out_free_conn;
276949557cc7SAndy Adamson 		cs_slot = &conf->cl_cs_slot;
277049557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
2771f5e22bb6SKinglong Mee 		if (status) {
2772f5e22bb6SKinglong Mee 			if (status == nfserr_replay_cache)
277349557cc7SAndy Adamson 				status = nfsd4_replay_create_session(cr_ses, cs_slot);
277481f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2775ec6b5d7bSAndy Adamson 		}
2776ec6b5d7bSAndy Adamson 	} else if (unconf) {
2777ec6b5d7bSAndy Adamson 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
2778363168b4SJeff Layton 		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
2779ec6b5d7bSAndy Adamson 			status = nfserr_clid_inuse;
278081f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2781ec6b5d7bSAndy Adamson 		}
278257266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
2783dedeb13fSAndrew Elble 		if (!nfsd4_mach_creds_match(unconf, rqstp))
278457266a6eSJ. Bruce Fields 			goto out_free_conn;
278549557cc7SAndy Adamson 		cs_slot = &unconf->cl_cs_slot;
278649557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
278738eb76a5SAndy Adamson 		if (status) {
278838eb76a5SAndy Adamson 			/* an unconfirmed replay returns misordered */
2789ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
279081f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2791ec6b5d7bSAndy Adamson 		}
2792382a62e7SStanislav Kinsbursky 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
2793221a6876SJ. Bruce Fields 		if (old) {
2794d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
27957abea1e8SJeff Layton 			if (status) {
27967abea1e8SJeff Layton 				old = NULL;
2797221a6876SJ. Bruce Fields 				goto out_free_conn;
2798221a6876SJ. Bruce Fields 			}
27997abea1e8SJeff Layton 		}
28008f9d3d3bSJ. Bruce Fields 		move_to_confirmed(unconf);
2801ec6b5d7bSAndy Adamson 		conf = unconf;
2802ec6b5d7bSAndy Adamson 	} else {
2803ec6b5d7bSAndy Adamson 		status = nfserr_stale_clientid;
280481f0b2a4SJ. Bruce Fields 		goto out_free_conn;
2805ec6b5d7bSAndy Adamson 	}
280681f0b2a4SJ. Bruce Fields 	status = nfs_ok;
28074ce85c8cSChuck Lever 	/* Persistent sessions are not supported */
2808408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_PERSIST;
28094ce85c8cSChuck Lever 	/* Upshifting from TCP to RDMA is not supported */
2810408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_RDMA;
2811408b79bcSJ. Bruce Fields 
281281f0b2a4SJ. Bruce Fields 	init_session(rqstp, new, conf, cr_ses);
2813d20c11d8SJeff Layton 	nfsd4_get_session_locked(new);
281481f0b2a4SJ. Bruce Fields 
2815ac7c46f2SJ. Bruce Fields 	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
2816ec6b5d7bSAndy Adamson 	       NFS4_MAX_SESSIONID_LEN);
281786c3e16cSJ. Bruce Fields 	cs_slot->sl_seqid++;
281849557cc7SAndy Adamson 	cr_ses->seqid = cs_slot->sl_seqid;
2819ec6b5d7bSAndy Adamson 
2820d20c11d8SJeff Layton 	/* cache solo and embedded create sessions under the client_lock */
282149557cc7SAndy Adamson 	nfsd4_cache_create_session(cr_ses, cs_slot, status);
2822d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
2823d20c11d8SJeff Layton 	/* init connection and backchannel */
2824d20c11d8SJeff Layton 	nfsd4_init_conn(rqstp, conn, new);
2825d20c11d8SJeff Layton 	nfsd4_put_session(new);
2826d20c11d8SJeff Layton 	if (old)
2827d20c11d8SJeff Layton 		expire_client(old);
2828ec6b5d7bSAndy Adamson 	return status;
282981f0b2a4SJ. Bruce Fields out_free_conn:
2830d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
283181f0b2a4SJ. Bruce Fields 	free_conn(conn);
2832d20c11d8SJeff Layton 	if (old)
2833d20c11d8SJeff Layton 		expire_client(old);
283481f0b2a4SJ. Bruce Fields out_free_session:
283581f0b2a4SJ. Bruce Fields 	__free_session(new);
283655c760cfSJ. Bruce Fields out_release_drc_mem:
283755c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&cr_ses->fore_channel);
28381ca50792SJ. Bruce Fields 	return status;
2839069b6ad4SAndy Adamson }
2840069b6ad4SAndy Adamson 
28411d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir)
28421d1bc8f2SJ. Bruce Fields {
28431d1bc8f2SJ. Bruce Fields 	switch (*dir) {
28441d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE:
28451d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK:
28461d1bc8f2SJ. Bruce Fields 		return nfs_ok;
28471d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE_OR_BOTH:
28481d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK_OR_BOTH:
28491d1bc8f2SJ. Bruce Fields 		*dir = NFS4_CDFC4_BOTH;
28501d1bc8f2SJ. Bruce Fields 		return nfs_ok;
28511d1bc8f2SJ. Bruce Fields 	};
28521d1bc8f2SJ. Bruce Fields 	return nfserr_inval;
28531d1bc8f2SJ. Bruce Fields }
28541d1bc8f2SJ. Bruce Fields 
2855eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp,
2856eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate,
2857eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
2858cb73a9f4SJ. Bruce Fields {
2859eb69853dSChristoph Hellwig 	struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl;
2860cb73a9f4SJ. Bruce Fields 	struct nfsd4_session *session = cstate->session;
2861c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2862b78724b7SJ. Bruce Fields 	__be32 status;
2863cb73a9f4SJ. Bruce Fields 
2864b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
2865b78724b7SJ. Bruce Fields 	if (status)
2866b78724b7SJ. Bruce Fields 		return status;
2867c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2868cb73a9f4SJ. Bruce Fields 	session->se_cb_prog = bc->bc_cb_program;
2869cb73a9f4SJ. Bruce Fields 	session->se_cb_sec = bc->bc_cb_sec;
2870c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2871cb73a9f4SJ. Bruce Fields 
2872cb73a9f4SJ. Bruce Fields 	nfsd4_probe_callback(session->se_client);
2873cb73a9f4SJ. Bruce Fields 
2874cb73a9f4SJ. Bruce Fields 	return nfs_ok;
2875cb73a9f4SJ. Bruce Fields }
2876cb73a9f4SJ. Bruce Fields 
28771d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
28781d1bc8f2SJ. Bruce Fields 		     struct nfsd4_compound_state *cstate,
2879eb69853dSChristoph Hellwig 		     union nfsd4_op_u *u)
28801d1bc8f2SJ. Bruce Fields {
2881eb69853dSChristoph Hellwig 	struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
28821d1bc8f2SJ. Bruce Fields 	__be32 status;
28833ba63671SJ. Bruce Fields 	struct nfsd4_conn *conn;
28844f6e6c17SJ. Bruce Fields 	struct nfsd4_session *session;
2885d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2886d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
28871d1bc8f2SJ. Bruce Fields 
28881d1bc8f2SJ. Bruce Fields 	if (!nfsd4_last_compound_op(rqstp))
28891d1bc8f2SJ. Bruce Fields 		return nfserr_not_only_op;
2890c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2891d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status);
2892c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
28934f6e6c17SJ. Bruce Fields 	if (!session)
2894d4e19e70STrond Myklebust 		goto out_no_session;
289557266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
2896dedeb13fSAndrew Elble 	if (!nfsd4_mach_creds_match(session->se_client, rqstp))
289757266a6eSJ. Bruce Fields 		goto out;
28981d1bc8f2SJ. Bruce Fields 	status = nfsd4_map_bcts_dir(&bcts->dir);
28993ba63671SJ. Bruce Fields 	if (status)
29004f6e6c17SJ. Bruce Fields 		goto out;
29013ba63671SJ. Bruce Fields 	conn = alloc_conn(rqstp, bcts->dir);
29024f6e6c17SJ. Bruce Fields 	status = nfserr_jukebox;
29033ba63671SJ. Bruce Fields 	if (!conn)
29044f6e6c17SJ. Bruce Fields 		goto out;
29054f6e6c17SJ. Bruce Fields 	nfsd4_init_conn(rqstp, conn, session);
29064f6e6c17SJ. Bruce Fields 	status = nfs_ok;
29074f6e6c17SJ. Bruce Fields out:
2908d4e19e70STrond Myklebust 	nfsd4_put_session(session);
2909d4e19e70STrond Myklebust out_no_session:
29104f6e6c17SJ. Bruce Fields 	return status;
29111d1bc8f2SJ. Bruce Fields }
29121d1bc8f2SJ. Bruce Fields 
29135d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
29145d4cec2fSJ. Bruce Fields {
29155d4cec2fSJ. Bruce Fields 	if (!session)
29165d4cec2fSJ. Bruce Fields 		return 0;
29175d4cec2fSJ. Bruce Fields 	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
29185d4cec2fSJ. Bruce Fields }
29195d4cec2fSJ. Bruce Fields 
2920069b6ad4SAndy Adamson __be32
2921eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate,
2922eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
2923069b6ad4SAndy Adamson {
2924eb69853dSChristoph Hellwig 	struct nfsd4_destroy_session *sessionid = &u->destroy_session;
2925e10e0cfcSBenny Halevy 	struct nfsd4_session *ses;
2926abcdff09SJ. Bruce Fields 	__be32 status;
2927f0f51f5cSJ. Bruce Fields 	int ref_held_by_me = 0;
2928d4e19e70STrond Myklebust 	struct net *net = SVC_NET(r);
2929d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2930e10e0cfcSBenny Halevy 
2931abcdff09SJ. Bruce Fields 	status = nfserr_not_only_op;
29325d4cec2fSJ. Bruce Fields 	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
293357716355SJ. Bruce Fields 		if (!nfsd4_last_compound_op(r))
2934abcdff09SJ. Bruce Fields 			goto out;
2935f0f51f5cSJ. Bruce Fields 		ref_held_by_me++;
293657716355SJ. Bruce Fields 	}
2937e10e0cfcSBenny Halevy 	dump_sessionid(__func__, &sessionid->sessionid);
2938c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2939d4e19e70STrond Myklebust 	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status);
2940abcdff09SJ. Bruce Fields 	if (!ses)
2941abcdff09SJ. Bruce Fields 		goto out_client_lock;
294257266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
2943dedeb13fSAndrew Elble 	if (!nfsd4_mach_creds_match(ses->se_client, r))
2944d4e19e70STrond Myklebust 		goto out_put_session;
2945f0f51f5cSJ. Bruce Fields 	status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
294666b2b9b2SJ. Bruce Fields 	if (status)
2947f0f51f5cSJ. Bruce Fields 		goto out_put_session;
2948e10e0cfcSBenny Halevy 	unhash_session(ses);
2949c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2950e10e0cfcSBenny Halevy 
295184f5f7ccSJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
295219cf5c02SJ. Bruce Fields 
2953c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2954e10e0cfcSBenny Halevy 	status = nfs_ok;
2955f0f51f5cSJ. Bruce Fields out_put_session:
2956d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
2957abcdff09SJ. Bruce Fields out_client_lock:
2958abcdff09SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
2959e10e0cfcSBenny Halevy out:
2960e10e0cfcSBenny Halevy 	return status;
2961069b6ad4SAndy Adamson }
2962069b6ad4SAndy Adamson 
2963a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
2964328ead28SJ. Bruce Fields {
2965328ead28SJ. Bruce Fields 	struct nfsd4_conn *c;
2966328ead28SJ. Bruce Fields 
2967328ead28SJ. Bruce Fields 	list_for_each_entry(c, &s->se_conns, cn_persession) {
2968a663bdd8SJ. Bruce Fields 		if (c->cn_xprt == xpt) {
2969328ead28SJ. Bruce Fields 			return c;
2970328ead28SJ. Bruce Fields 		}
2971328ead28SJ. Bruce Fields 	}
2972328ead28SJ. Bruce Fields 	return NULL;
2973328ead28SJ. Bruce Fields }
2974328ead28SJ. Bruce Fields 
297557266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
2976328ead28SJ. Bruce Fields {
2977328ead28SJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
2978a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *c;
297957266a6eSJ. Bruce Fields 	__be32 status = nfs_ok;
298021b75b01SJ. Bruce Fields 	int ret;
2981328ead28SJ. Bruce Fields 
2982328ead28SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
2983a663bdd8SJ. Bruce Fields 	c = __nfsd4_find_conn(new->cn_xprt, ses);
298457266a6eSJ. Bruce Fields 	if (c)
298557266a6eSJ. Bruce Fields 		goto out_free;
298657266a6eSJ. Bruce Fields 	status = nfserr_conn_not_bound_to_session;
298757266a6eSJ. Bruce Fields 	if (clp->cl_mach_cred)
298857266a6eSJ. Bruce Fields 		goto out_free;
2989328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(new, ses);
2990328ead28SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
299121b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(new);
299221b75b01SJ. Bruce Fields 	if (ret)
299321b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
299421b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&new->cn_xpt_user);
299557266a6eSJ. Bruce Fields 	return nfs_ok;
299657266a6eSJ. Bruce Fields out_free:
299757266a6eSJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
299857266a6eSJ. Bruce Fields 	free_conn(new);
299957266a6eSJ. Bruce Fields 	return status;
3000328ead28SJ. Bruce Fields }
3001328ead28SJ. Bruce Fields 
3002868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
3003868b89c3SMi Jinlong {
3004868b89c3SMi Jinlong 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
3005868b89c3SMi Jinlong 
3006868b89c3SMi Jinlong 	return args->opcnt > session->se_fchannel.maxops;
3007868b89c3SMi Jinlong }
3008868b89c3SMi Jinlong 
3009ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
3010ae82a8d0SMi Jinlong 				  struct nfsd4_session *session)
3011ae82a8d0SMi Jinlong {
3012ae82a8d0SMi Jinlong 	struct xdr_buf *xb = &rqstp->rq_arg;
3013ae82a8d0SMi Jinlong 
3014ae82a8d0SMi Jinlong 	return xb->len > session->se_fchannel.maxreq_sz;
3015ae82a8d0SMi Jinlong }
3016ae82a8d0SMi Jinlong 
301753da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp,
301853da6a53SJ. Bruce Fields 		 struct nfsd4_sequence *seq, struct nfsd4_slot *slot)
301953da6a53SJ. Bruce Fields {
302053da6a53SJ. Bruce Fields 	struct nfsd4_compoundargs *argp = rqstp->rq_argp;
302153da6a53SJ. Bruce Fields 
302253da6a53SJ. Bruce Fields 	if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) !=
302353da6a53SJ. Bruce Fields 	    (bool)seq->cachethis)
302453da6a53SJ. Bruce Fields 		return false;
302553da6a53SJ. Bruce Fields 	/*
302653da6a53SJ. Bruce Fields 	 * If there's an error than the reply can have fewer ops than
302753da6a53SJ. Bruce Fields 	 * the call.  But if we cached a reply with *more* ops than the
302853da6a53SJ. Bruce Fields 	 * call you're sending us now, then this new call is clearly not
302953da6a53SJ. Bruce Fields 	 * really a replay of the old one:
303053da6a53SJ. Bruce Fields 	 */
303153da6a53SJ. Bruce Fields 	if (slot->sl_opcnt < argp->opcnt)
303253da6a53SJ. Bruce Fields 		return false;
303353da6a53SJ. Bruce Fields 	/* This is the only check explicitly called by spec: */
303453da6a53SJ. Bruce Fields 	if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
303553da6a53SJ. Bruce Fields 		return false;
303653da6a53SJ. Bruce Fields 	/*
303753da6a53SJ. Bruce Fields 	 * There may be more comparisons we could actually do, but the
303853da6a53SJ. Bruce Fields 	 * spec doesn't require us to catch every case where the calls
303953da6a53SJ. Bruce Fields 	 * don't match (that would require caching the call as well as
304053da6a53SJ. Bruce Fields 	 * the reply), so we don't bother.
304153da6a53SJ. Bruce Fields 	 */
304253da6a53SJ. Bruce Fields 	return true;
304353da6a53SJ. Bruce Fields }
304453da6a53SJ. Bruce Fields 
3045069b6ad4SAndy Adamson __be32
3046eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3047eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
3048069b6ad4SAndy Adamson {
3049eb69853dSChristoph Hellwig 	struct nfsd4_sequence *seq = &u->sequence;
3050f9bb94c4SAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
305147ee5298SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
3052b85d4c01SBenny Halevy 	struct nfsd4_session *session;
3053221a6876SJ. Bruce Fields 	struct nfs4_client *clp;
3054b85d4c01SBenny Halevy 	struct nfsd4_slot *slot;
3055a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *conn;
305657b7b43bSJ. Bruce Fields 	__be32 status;
305747ee5298SJ. Bruce Fields 	int buflen;
3058d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
3059d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
3060b85d4c01SBenny Halevy 
3061f9bb94c4SAndy Adamson 	if (resp->opcnt != 1)
3062f9bb94c4SAndy Adamson 		return nfserr_sequence_pos;
3063f9bb94c4SAndy Adamson 
3064a663bdd8SJ. Bruce Fields 	/*
3065a663bdd8SJ. Bruce Fields 	 * Will be either used or freed by nfsd4_sequence_check_conn
3066a663bdd8SJ. Bruce Fields 	 * below.
3067a663bdd8SJ. Bruce Fields 	 */
3068a663bdd8SJ. Bruce Fields 	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
3069a663bdd8SJ. Bruce Fields 	if (!conn)
3070a663bdd8SJ. Bruce Fields 		return nfserr_jukebox;
3071a663bdd8SJ. Bruce Fields 
3072c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
3073d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status);
3074b85d4c01SBenny Halevy 	if (!session)
3075221a6876SJ. Bruce Fields 		goto out_no_session;
3076221a6876SJ. Bruce Fields 	clp = session->se_client;
3077b85d4c01SBenny Halevy 
3078868b89c3SMi Jinlong 	status = nfserr_too_many_ops;
3079868b89c3SMi Jinlong 	if (nfsd4_session_too_many_ops(rqstp, session))
308066b2b9b2SJ. Bruce Fields 		goto out_put_session;
3081868b89c3SMi Jinlong 
3082ae82a8d0SMi Jinlong 	status = nfserr_req_too_big;
3083ae82a8d0SMi Jinlong 	if (nfsd4_request_too_big(rqstp, session))
308466b2b9b2SJ. Bruce Fields 		goto out_put_session;
3085ae82a8d0SMi Jinlong 
3086b85d4c01SBenny Halevy 	status = nfserr_badslot;
30876c18ba9fSAlexandros Batsakis 	if (seq->slotid >= session->se_fchannel.maxreqs)
308866b2b9b2SJ. Bruce Fields 		goto out_put_session;
3089b85d4c01SBenny Halevy 
3090557ce264SAndy Adamson 	slot = session->se_slots[seq->slotid];
3091b85d4c01SBenny Halevy 	dprintk("%s: slotid %d\n", __func__, seq->slotid);
3092b85d4c01SBenny Halevy 
3093a8dfdaebSAndy Adamson 	/* We do not negotiate the number of slots yet, so set the
3094a8dfdaebSAndy Adamson 	 * maxslots to the session maxreqs which is used to encode
3095a8dfdaebSAndy Adamson 	 * sr_highest_slotid and the sr_target_slot id to maxslots */
3096a8dfdaebSAndy Adamson 	seq->maxslots = session->se_fchannel.maxreqs;
3097a8dfdaebSAndy Adamson 
309873e79482SJ. Bruce Fields 	status = check_slot_seqid(seq->seqid, slot->sl_seqid,
309973e79482SJ. Bruce Fields 					slot->sl_flags & NFSD4_SLOT_INUSE);
3100b85d4c01SBenny Halevy 	if (status == nfserr_replay_cache) {
3101bf5c43c8SJ. Bruce Fields 		status = nfserr_seq_misordered;
3102bf5c43c8SJ. Bruce Fields 		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
310366b2b9b2SJ. Bruce Fields 			goto out_put_session;
310453da6a53SJ. Bruce Fields 		status = nfserr_seq_false_retry;
310553da6a53SJ. Bruce Fields 		if (!replay_matches_cache(rqstp, seq, slot))
310653da6a53SJ. Bruce Fields 			goto out_put_session;
3107b85d4c01SBenny Halevy 		cstate->slot = slot;
3108b85d4c01SBenny Halevy 		cstate->session = session;
31094b24ca7dSJeff Layton 		cstate->clp = clp;
3110da3846a2SAndy Adamson 		/* Return the cached reply status and set cstate->status
3111557ce264SAndy Adamson 		 * for nfsd4_proc_compound processing */
3112bf864a31SAndy Adamson 		status = nfsd4_replay_cache_entry(resp, seq);
3113da3846a2SAndy Adamson 		cstate->status = nfserr_replay_cache;
3114aaf84eb9SBenny Halevy 		goto out;
3115b85d4c01SBenny Halevy 	}
3116b85d4c01SBenny Halevy 	if (status)
311766b2b9b2SJ. Bruce Fields 		goto out_put_session;
3118b85d4c01SBenny Halevy 
311957266a6eSJ. Bruce Fields 	status = nfsd4_sequence_check_conn(conn, session);
3120a663bdd8SJ. Bruce Fields 	conn = NULL;
312157266a6eSJ. Bruce Fields 	if (status)
312257266a6eSJ. Bruce Fields 		goto out_put_session;
3123328ead28SJ. Bruce Fields 
312447ee5298SJ. Bruce Fields 	buflen = (seq->cachethis) ?
312547ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_cached :
312647ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_sz;
312747ee5298SJ. Bruce Fields 	status = (seq->cachethis) ? nfserr_rep_too_big_to_cache :
312847ee5298SJ. Bruce Fields 				    nfserr_rep_too_big;
3129a5cddc88SJ. Bruce Fields 	if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack))
313047ee5298SJ. Bruce Fields 		goto out_put_session;
313132aaa62eSJ. Bruce Fields 	svc_reserve(rqstp, buflen);
313247ee5298SJ. Bruce Fields 
313347ee5298SJ. Bruce Fields 	status = nfs_ok;
3134b85d4c01SBenny Halevy 	/* Success! bump slot seqid */
3135b85d4c01SBenny Halevy 	slot->sl_seqid = seq->seqid;
3136bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INUSE;
313773e79482SJ. Bruce Fields 	if (seq->cachethis)
313873e79482SJ. Bruce Fields 		slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
3139bf5c43c8SJ. Bruce Fields 	else
3140bf5c43c8SJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
3141b85d4c01SBenny Halevy 
3142b85d4c01SBenny Halevy 	cstate->slot = slot;
3143b85d4c01SBenny Halevy 	cstate->session = session;
31444b24ca7dSJeff Layton 	cstate->clp = clp;
3145b85d4c01SBenny Halevy 
3146b85d4c01SBenny Halevy out:
31475423732aSBenny Halevy 	switch (clp->cl_cb_state) {
31485423732aSBenny Halevy 	case NFSD4_CB_DOWN:
3149fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
31505423732aSBenny Halevy 		break;
31515423732aSBenny Halevy 	case NFSD4_CB_FAULT:
3152fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
31535423732aSBenny Halevy 		break;
3154fc0c3dd1SBenny Halevy 	default:
3155fc0c3dd1SBenny Halevy 		seq->status_flags = 0;
31565423732aSBenny Halevy 	}
31573bd64a5bSJ. Bruce Fields 	if (!list_empty(&clp->cl_revoked))
31583bd64a5bSJ. Bruce Fields 		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
3159221a6876SJ. Bruce Fields out_no_session:
31603f42d2c4SKinglong Mee 	if (conn)
31613f42d2c4SKinglong Mee 		free_conn(conn);
3162c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
3163b85d4c01SBenny Halevy 	return status;
316466b2b9b2SJ. Bruce Fields out_put_session:
3165d4e19e70STrond Myklebust 	nfsd4_put_session_locked(session);
3166221a6876SJ. Bruce Fields 	goto out_no_session;
3167069b6ad4SAndy Adamson }
3168069b6ad4SAndy Adamson 
3169b607664eSTrond Myklebust void
3170b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp)
3171b607664eSTrond Myklebust {
3172b607664eSTrond Myklebust 	struct nfsd4_compound_state *cs = &resp->cstate;
3173b607664eSTrond Myklebust 
3174b607664eSTrond Myklebust 	if (nfsd4_has_session(cs)) {
3175b607664eSTrond Myklebust 		if (cs->status != nfserr_replay_cache) {
3176b607664eSTrond Myklebust 			nfsd4_store_cache_entry(resp);
3177b607664eSTrond Myklebust 			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
3178b607664eSTrond Myklebust 		}
3179d4e19e70STrond Myklebust 		/* Drop session reference that was taken in nfsd4_sequence() */
3180b607664eSTrond Myklebust 		nfsd4_put_session(cs->session);
31814b24ca7dSJeff Layton 	} else if (cs->clp)
31824b24ca7dSJeff Layton 		put_client_renew(cs->clp);
3183b607664eSTrond Myklebust }
3184b607664eSTrond Myklebust 
3185345c2842SMi Jinlong __be32
3186eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp,
3187eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate,
3188eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
3189345c2842SMi Jinlong {
3190eb69853dSChristoph Hellwig 	struct nfsd4_destroy_clientid *dc = &u->destroy_clientid;
31916b10ad19STrond Myklebust 	struct nfs4_client *conf, *unconf;
31926b10ad19STrond Myklebust 	struct nfs4_client *clp = NULL;
319357b7b43bSJ. Bruce Fields 	__be32 status = 0;
31948daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
3195345c2842SMi Jinlong 
31966b10ad19STrond Myklebust 	spin_lock(&nn->client_lock);
31970a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
31988daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&dc->clientid, true, nn);
319978389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
3200345c2842SMi Jinlong 
3201345c2842SMi Jinlong 	if (conf) {
3202c0293b01SJ. Bruce Fields 		if (client_has_state(conf)) {
3203345c2842SMi Jinlong 			status = nfserr_clientid_busy;
3204345c2842SMi Jinlong 			goto out;
3205345c2842SMi Jinlong 		}
3206fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
3207fd699b8aSJeff Layton 		if (status)
3208fd699b8aSJeff Layton 			goto out;
32096b10ad19STrond Myklebust 		clp = conf;
3210345c2842SMi Jinlong 	} else if (unconf)
3211345c2842SMi Jinlong 		clp = unconf;
3212345c2842SMi Jinlong 	else {
3213345c2842SMi Jinlong 		status = nfserr_stale_clientid;
3214345c2842SMi Jinlong 		goto out;
3215345c2842SMi Jinlong 	}
3216dedeb13fSAndrew Elble 	if (!nfsd4_mach_creds_match(clp, rqstp)) {
32176b10ad19STrond Myklebust 		clp = NULL;
321857266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
321957266a6eSJ. Bruce Fields 		goto out;
322057266a6eSJ. Bruce Fields 	}
32216b10ad19STrond Myklebust 	unhash_client_locked(clp);
3222345c2842SMi Jinlong out:
32236b10ad19STrond Myklebust 	spin_unlock(&nn->client_lock);
32246b10ad19STrond Myklebust 	if (clp)
32256b10ad19STrond Myklebust 		expire_client(clp);
3226345c2842SMi Jinlong 	return status;
3227345c2842SMi Jinlong }
3228345c2842SMi Jinlong 
3229069b6ad4SAndy Adamson __be32
3230eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp,
3231eb69853dSChristoph Hellwig 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
32324dc6ec00SJ. Bruce Fields {
3233eb69853dSChristoph Hellwig 	struct nfsd4_reclaim_complete *rc = &u->reclaim_complete;
323457b7b43bSJ. Bruce Fields 	__be32 status = 0;
3235bcecf1ccSMi Jinlong 
32364dc6ec00SJ. Bruce Fields 	if (rc->rca_one_fs) {
32374dc6ec00SJ. Bruce Fields 		if (!cstate->current_fh.fh_dentry)
32384dc6ec00SJ. Bruce Fields 			return nfserr_nofilehandle;
32394dc6ec00SJ. Bruce Fields 		/*
32404dc6ec00SJ. Bruce Fields 		 * We don't take advantage of the rca_one_fs case.
32414dc6ec00SJ. Bruce Fields 		 * That's OK, it's optional, we can safely ignore it.
32424dc6ec00SJ. Bruce Fields 		 */
32434dc6ec00SJ. Bruce Fields 		return nfs_ok;
32444dc6ec00SJ. Bruce Fields 	}
3245bcecf1ccSMi Jinlong 
3246bcecf1ccSMi Jinlong 	status = nfserr_complete_already;
3247a52d726bSJeff Layton 	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
3248a52d726bSJeff Layton 			     &cstate->session->se_client->cl_flags))
3249bcecf1ccSMi Jinlong 		goto out;
3250bcecf1ccSMi Jinlong 
3251bcecf1ccSMi Jinlong 	status = nfserr_stale_clientid;
3252bcecf1ccSMi Jinlong 	if (is_client_expired(cstate->session->se_client))
32534dc6ec00SJ. Bruce Fields 		/*
32544dc6ec00SJ. Bruce Fields 		 * The following error isn't really legal.
32554dc6ec00SJ. Bruce Fields 		 * But we only get here if the client just explicitly
32564dc6ec00SJ. Bruce Fields 		 * destroyed the client.  Surely it no longer cares what
32574dc6ec00SJ. Bruce Fields 		 * error it gets back on an operation for the dead
32584dc6ec00SJ. Bruce Fields 		 * client.
32594dc6ec00SJ. Bruce Fields 		 */
3260bcecf1ccSMi Jinlong 		goto out;
3261bcecf1ccSMi Jinlong 
3262bcecf1ccSMi Jinlong 	status = nfs_ok;
32632a4317c5SJeff Layton 	nfsd4_client_record_create(cstate->session->se_client);
3264bcecf1ccSMi Jinlong out:
3265bcecf1ccSMi Jinlong 	return status;
32664dc6ec00SJ. Bruce Fields }
32674dc6ec00SJ. Bruce Fields 
32684dc6ec00SJ. Bruce Fields __be32
3269b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3270eb69853dSChristoph Hellwig 		  union nfsd4_op_u *u)
32711da177e4SLinus Torvalds {
3272eb69853dSChristoph Hellwig 	struct nfsd4_setclientid *setclid = &u->setclientid;
3273a084daf5SJ. Bruce Fields 	struct xdr_netobj 	clname = setclid->se_name;
32741da177e4SLinus Torvalds 	nfs4_verifier		clverifier = setclid->se_verf;
32753dbacee6STrond Myklebust 	struct nfs4_client	*conf, *new;
32763dbacee6STrond Myklebust 	struct nfs4_client	*unconf = NULL;
3277b37ad28bSAl Viro 	__be32 			status;
3278c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
3279a55370a3SNeilBrown 
32805cc40fd7STrond Myklebust 	new = create_client(clname, rqstp, &clverifier);
32815cc40fd7STrond Myklebust 	if (new == NULL)
32825cc40fd7STrond Myklebust 		return nfserr_jukebox;
328363db4632SJ. Bruce Fields 	/* Cases below refer to rfc 3530 section 14.2.33: */
32843dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
3285382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&clname, nn);
32862b634821SJ. Bruce Fields 	if (conf && client_has_state(conf)) {
328763db4632SJ. Bruce Fields 		/* case 0: */
32881da177e4SLinus Torvalds 		status = nfserr_clid_inuse;
3289e203d506SJ. Bruce Fields 		if (clp_used_exchangeid(conf))
3290e203d506SJ. Bruce Fields 			goto out;
3291026722c2SJ. Bruce Fields 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
3292363168b4SJeff Layton 			char addr_str[INET6_ADDRSTRLEN];
3293363168b4SJeff Layton 			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
3294363168b4SJeff Layton 				 sizeof(addr_str));
3295026722c2SJ. Bruce Fields 			dprintk("NFSD: setclientid: string in use by client "
3296363168b4SJeff Layton 				"at %s\n", addr_str);
32971da177e4SLinus Torvalds 			goto out;
32981da177e4SLinus Torvalds 		}
32991da177e4SLinus Torvalds 	}
3300a99454aaSStanislav Kinsbursky 	unconf = find_unconfirmed_client_by_name(&clname, nn);
33011da177e4SLinus Torvalds 	if (unconf)
33023dbacee6STrond Myklebust 		unhash_client_locked(unconf);
330341eb1670SKinglong Mee 	if (conf && same_verf(&conf->cl_verifier, &clverifier)) {
330463db4632SJ. Bruce Fields 		/* case 1: probable callback update */
33051da177e4SLinus Torvalds 		copy_clid(new, conf);
330641eb1670SKinglong Mee 		gen_confirm(new, nn);
330741eb1670SKinglong Mee 	} else /* case 4 (new client) or cases 2, 3 (client reboot): */
3308c212cecfSStanislav Kinsbursky 		gen_clid(new, nn);
33098323c3b2SJ. Bruce Fields 	new->cl_minorversion = 0;
33106f3d772fSTakuma Umeya 	gen_callback(new, setclid, rqstp);
3311ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
33121da177e4SLinus Torvalds 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
33131da177e4SLinus Torvalds 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
33141da177e4SLinus Torvalds 	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
33155cc40fd7STrond Myklebust 	new = NULL;
33161da177e4SLinus Torvalds 	status = nfs_ok;
33171da177e4SLinus Torvalds out:
33183dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
33195cc40fd7STrond Myklebust 	if (new)
33205cc40fd7STrond Myklebust 		free_client(new);
33213dbacee6STrond Myklebust 	if (unconf)
33223dbacee6STrond Myklebust 		expire_client(unconf);
33231da177e4SLinus Torvalds 	return status;
33241da177e4SLinus Torvalds }
33251da177e4SLinus Torvalds 
33261da177e4SLinus Torvalds 
3327b37ad28bSAl Viro __be32
3328b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
3329b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
3330eb69853dSChristoph Hellwig 			union nfsd4_op_u *u)
33311da177e4SLinus Torvalds {
3332eb69853dSChristoph Hellwig 	struct nfsd4_setclientid_confirm *setclientid_confirm =
3333eb69853dSChristoph Hellwig 			&u->setclientid_confirm;
333421ab45a4SNeilBrown 	struct nfs4_client *conf, *unconf;
3335d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
33361da177e4SLinus Torvalds 	nfs4_verifier confirm = setclientid_confirm->sc_confirm;
33371da177e4SLinus Torvalds 	clientid_t * clid = &setclientid_confirm->sc_clientid;
3338b37ad28bSAl Viro 	__be32 status;
33397f2210faSStanislav Kinsbursky 	struct nfsd_net	*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
33401da177e4SLinus Torvalds 
33412c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(clid, nn))
33421da177e4SLinus Torvalds 		return nfserr_stale_clientid;
334321ab45a4SNeilBrown 
3344d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
33458daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(clid, false, nn);
33460a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(clid, false, nn);
3347a186e767SJ. Bruce Fields 	/*
33488695b90aSJ. Bruce Fields 	 * We try hard to give out unique clientid's, so if we get an
33498695b90aSJ. Bruce Fields 	 * attempt to confirm the same clientid with a different cred,
3350f984a7ceSJ. Bruce Fields 	 * the client may be buggy; this should never happen.
3351f984a7ceSJ. Bruce Fields 	 *
3352f984a7ceSJ. Bruce Fields 	 * Nevertheless, RFC 7530 recommends INUSE for this case:
3353a186e767SJ. Bruce Fields 	 */
3354f984a7ceSJ. Bruce Fields 	status = nfserr_clid_inuse;
33558695b90aSJ. Bruce Fields 	if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred))
33568695b90aSJ. Bruce Fields 		goto out;
33578695b90aSJ. Bruce Fields 	if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred))
33588695b90aSJ. Bruce Fields 		goto out;
335963db4632SJ. Bruce Fields 	/* cases below refer to rfc 3530 section 14.2.34: */
336090d700b7SJ. Bruce Fields 	if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) {
33617d22fc11SJ. Bruce Fields 		if (conf && same_verf(&confirm, &conf->cl_confirm)) {
33627d22fc11SJ. Bruce Fields 			/* case 2: probable retransmit */
336390d700b7SJ. Bruce Fields 			status = nfs_ok;
33647d22fc11SJ. Bruce Fields 		} else /* case 4: client hasn't noticed we rebooted yet? */
336590d700b7SJ. Bruce Fields 			status = nfserr_stale_clientid;
336690d700b7SJ. Bruce Fields 		goto out;
336790d700b7SJ. Bruce Fields 	}
336890d700b7SJ. Bruce Fields 	status = nfs_ok;
336990d700b7SJ. Bruce Fields 	if (conf) { /* case 1: callback update */
3370d20c11d8SJeff Layton 		old = unconf;
3371d20c11d8SJeff Layton 		unhash_client_locked(old);
33725a3c9d71SJ. Bruce Fields 		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
337390d700b7SJ. Bruce Fields 	} else { /* case 3: normal case; new or rebooted client */
3374d20c11d8SJeff Layton 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
3375d20c11d8SJeff Layton 		if (old) {
33762b634821SJ. Bruce Fields 			status = nfserr_clid_inuse;
33772b634821SJ. Bruce Fields 			if (client_has_state(old)
33782b634821SJ. Bruce Fields 					&& !same_creds(&unconf->cl_cred,
33792b634821SJ. Bruce Fields 							&old->cl_cred))
33802b634821SJ. Bruce Fields 				goto out;
3381d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
33827abea1e8SJeff Layton 			if (status) {
33837abea1e8SJeff Layton 				old = NULL;
3384221a6876SJ. Bruce Fields 				goto out;
3385221a6876SJ. Bruce Fields 			}
33867abea1e8SJeff Layton 		}
33871da177e4SLinus Torvalds 		move_to_confirmed(unconf);
3388d20c11d8SJeff Layton 		conf = unconf;
338908e8987cSNeilBrown 	}
3390d20c11d8SJeff Layton 	get_client_locked(conf);
3391d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3392d20c11d8SJeff Layton 	nfsd4_probe_callback(conf);
3393d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
3394d20c11d8SJeff Layton 	put_client_renew_locked(conf);
33951da177e4SLinus Torvalds out:
3396d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3397d20c11d8SJeff Layton 	if (old)
3398d20c11d8SJeff Layton 		expire_client(old);
33991da177e4SLinus Torvalds 	return status;
34001da177e4SLinus Torvalds }
34011da177e4SLinus Torvalds 
340232513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void)
34031da177e4SLinus Torvalds {
340432513b40SJ. Bruce Fields 	return kmem_cache_alloc(file_slab, GFP_KERNEL);
340532513b40SJ. Bruce Fields }
340632513b40SJ. Bruce Fields 
340732513b40SJ. Bruce Fields /* OPEN Share state helper functions */
34085b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
34095b095e99SJeff Layton 				struct nfs4_file *fp)
341032513b40SJ. Bruce Fields {
3411950e0118STrond Myklebust 	lockdep_assert_held(&state_lock);
3412950e0118STrond Myklebust 
3413818a34ebSElena Reshetova 	refcount_set(&fp->fi_ref, 1);
34141d31a253STrond Myklebust 	spin_lock_init(&fp->fi_lock);
34158beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_stateids);
34168beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_delegations);
34178287f009SSachin Bhamare 	INIT_LIST_HEAD(&fp->fi_clnt_odstate);
3418e2cf80d7STrond Myklebust 	fh_copy_shallow(&fp->fi_fhandle, fh);
34190c637be8SJeff Layton 	fp->fi_deleg_file = NULL;
342047f9940cSMeelap Shah 	fp->fi_had_conflict = false;
3421baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
3422f9d7562fSJ. Bruce Fields 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
3423f9d7562fSJ. Bruce Fields 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
34249cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS
34259cf514ccSChristoph Hellwig 	INIT_LIST_HEAD(&fp->fi_lo_states);
3426c5c707f9SChristoph Hellwig 	atomic_set(&fp->fi_lo_recalls, 0);
34279cf514ccSChristoph Hellwig #endif
34285b095e99SJeff Layton 	hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]);
34291da177e4SLinus Torvalds }
34301da177e4SLinus Torvalds 
3431e8ff2a84SJ. Bruce Fields void
3432e60d4398SNeilBrown nfsd4_free_slabs(void)
3433e60d4398SNeilBrown {
34348287f009SSachin Bhamare 	kmem_cache_destroy(odstate_slab);
3435abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3436abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3437abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3438abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3439abf1135bSChristoph Hellwig 	kmem_cache_destroy(deleg_slab);
3440e60d4398SNeilBrown }
34411da177e4SLinus Torvalds 
344272083396SBryan Schumaker int
34431da177e4SLinus Torvalds nfsd4_init_slabs(void)
34441da177e4SLinus Torvalds {
3445fe0750e5SJ. Bruce Fields 	openowner_slab = kmem_cache_create("nfsd4_openowners",
3446fe0750e5SJ. Bruce Fields 			sizeof(struct nfs4_openowner), 0, 0, NULL);
3447fe0750e5SJ. Bruce Fields 	if (openowner_slab == NULL)
3448abf1135bSChristoph Hellwig 		goto out;
3449fe0750e5SJ. Bruce Fields 	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
34503c40794bSYanchuan Nian 			sizeof(struct nfs4_lockowner), 0, 0, NULL);
3451fe0750e5SJ. Bruce Fields 	if (lockowner_slab == NULL)
3452abf1135bSChristoph Hellwig 		goto out_free_openowner_slab;
3453e60d4398SNeilBrown 	file_slab = kmem_cache_create("nfsd4_files",
345420c2df83SPaul Mundt 			sizeof(struct nfs4_file), 0, 0, NULL);
3455e60d4398SNeilBrown 	if (file_slab == NULL)
3456abf1135bSChristoph Hellwig 		goto out_free_lockowner_slab;
34575ac049acSNeilBrown 	stateid_slab = kmem_cache_create("nfsd4_stateids",
3458dcef0413SJ. Bruce Fields 			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
34595ac049acSNeilBrown 	if (stateid_slab == NULL)
3460abf1135bSChristoph Hellwig 		goto out_free_file_slab;
34615b2d21c1SNeilBrown 	deleg_slab = kmem_cache_create("nfsd4_delegations",
346220c2df83SPaul Mundt 			sizeof(struct nfs4_delegation), 0, 0, NULL);
34635b2d21c1SNeilBrown 	if (deleg_slab == NULL)
3464abf1135bSChristoph Hellwig 		goto out_free_stateid_slab;
34658287f009SSachin Bhamare 	odstate_slab = kmem_cache_create("nfsd4_odstate",
34668287f009SSachin Bhamare 			sizeof(struct nfs4_clnt_odstate), 0, 0, NULL);
34678287f009SSachin Bhamare 	if (odstate_slab == NULL)
34688287f009SSachin Bhamare 		goto out_free_deleg_slab;
3469e60d4398SNeilBrown 	return 0;
3470abf1135bSChristoph Hellwig 
34718287f009SSachin Bhamare out_free_deleg_slab:
34728287f009SSachin Bhamare 	kmem_cache_destroy(deleg_slab);
3473abf1135bSChristoph Hellwig out_free_stateid_slab:
3474abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3475abf1135bSChristoph Hellwig out_free_file_slab:
3476abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3477abf1135bSChristoph Hellwig out_free_lockowner_slab:
3478abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3479abf1135bSChristoph Hellwig out_free_openowner_slab:
3480abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3481abf1135bSChristoph Hellwig out:
34821da177e4SLinus Torvalds 	dprintk("nfsd4: out of memory while initializing nfsv4\n");
34831da177e4SLinus Torvalds 	return -ENOMEM;
34841da177e4SLinus Torvalds }
34851da177e4SLinus Torvalds 
3486ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp)
3487ff194bd9SJ. Bruce Fields {
3488ff194bd9SJ. Bruce Fields 	rp->rp_status = nfserr_serverfault;
3489ff194bd9SJ. Bruce Fields 	rp->rp_buflen = 0;
3490ff194bd9SJ. Bruce Fields 	rp->rp_buf = rp->rp_ibuf;
349158fb12e6SJeff Layton 	mutex_init(&rp->rp_mutex);
349258fb12e6SJeff Layton }
349358fb12e6SJeff Layton 
349458fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
349558fb12e6SJeff Layton 		struct nfs4_stateowner *so)
349658fb12e6SJeff Layton {
349758fb12e6SJeff Layton 	if (!nfsd4_has_session(cstate)) {
349858fb12e6SJeff Layton 		mutex_lock(&so->so_replay.rp_mutex);
3499b5971afaSKinglong Mee 		cstate->replay_owner = nfs4_get_stateowner(so);
350058fb12e6SJeff Layton 	}
350158fb12e6SJeff Layton }
350258fb12e6SJeff Layton 
350358fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate)
350458fb12e6SJeff Layton {
350558fb12e6SJeff Layton 	struct nfs4_stateowner *so = cstate->replay_owner;
350658fb12e6SJeff Layton 
350758fb12e6SJeff Layton 	if (so != NULL) {
350858fb12e6SJeff Layton 		cstate->replay_owner = NULL;
350958fb12e6SJeff Layton 		mutex_unlock(&so->so_replay.rp_mutex);
351058fb12e6SJeff Layton 		nfs4_put_stateowner(so);
351158fb12e6SJeff Layton 	}
3512ff194bd9SJ. Bruce Fields }
3513ff194bd9SJ. Bruce Fields 
3514fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
35151da177e4SLinus Torvalds {
35161da177e4SLinus Torvalds 	struct nfs4_stateowner *sop;
35171da177e4SLinus Torvalds 
3518fe0750e5SJ. Bruce Fields 	sop = kmem_cache_alloc(slab, GFP_KERNEL);
3519ff194bd9SJ. Bruce Fields 	if (!sop)
3520ff194bd9SJ. Bruce Fields 		return NULL;
3521ff194bd9SJ. Bruce Fields 
3522ff194bd9SJ. Bruce Fields 	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
3523ff194bd9SJ. Bruce Fields 	if (!sop->so_owner.data) {
3524fe0750e5SJ. Bruce Fields 		kmem_cache_free(slab, sop);
3525ff194bd9SJ. Bruce Fields 		return NULL;
3526ff194bd9SJ. Bruce Fields 	}
35271da177e4SLinus Torvalds 	sop->so_owner.len = owner->len;
3528ff194bd9SJ. Bruce Fields 
3529ff194bd9SJ. Bruce Fields 	INIT_LIST_HEAD(&sop->so_stateids);
3530ff194bd9SJ. Bruce Fields 	sop->so_client = clp;
3531ff194bd9SJ. Bruce Fields 	init_nfs4_replay(&sop->so_replay);
35326b180f0bSJeff Layton 	atomic_set(&sop->so_count, 1);
35331da177e4SLinus Torvalds 	return sop;
35341da177e4SLinus Torvalds }
3535ff194bd9SJ. Bruce Fields 
3536fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
3537ff194bd9SJ. Bruce Fields {
3538d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
35399b531137SStanislav Kinsbursky 
3540d4f0489fSTrond Myklebust 	list_add(&oo->oo_owner.so_strhash,
3541d4f0489fSTrond Myklebust 		 &clp->cl_ownerstr_hashtbl[strhashval]);
3542fe0750e5SJ. Bruce Fields 	list_add(&oo->oo_perclient, &clp->cl_openowners);
35431da177e4SLinus Torvalds }
35441da177e4SLinus Torvalds 
35458f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
35468f4b54c5SJeff Layton {
3547d4f0489fSTrond Myklebust 	unhash_openowner_locked(openowner(so));
35488f4b54c5SJeff Layton }
35498f4b54c5SJeff Layton 
35506b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so)
35516b180f0bSJeff Layton {
35526b180f0bSJeff Layton 	struct nfs4_openowner *oo = openowner(so);
35536b180f0bSJeff Layton 
35546b180f0bSJeff Layton 	kmem_cache_free(openowner_slab, oo);
35556b180f0bSJeff Layton }
35566b180f0bSJeff Layton 
35576b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = {
35588f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_openowner,
35596b180f0bSJeff Layton 	.so_free =	nfs4_free_openowner,
35606b180f0bSJeff Layton };
35616b180f0bSJeff Layton 
35627fc0564eSAndrew Elble static struct nfs4_ol_stateid *
35637fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
35647fc0564eSAndrew Elble {
35657fc0564eSAndrew Elble 	struct nfs4_ol_stateid *local, *ret = NULL;
35667fc0564eSAndrew Elble 	struct nfs4_openowner *oo = open->op_openowner;
35677fc0564eSAndrew Elble 
35687fc0564eSAndrew Elble 	lockdep_assert_held(&fp->fi_lock);
35697fc0564eSAndrew Elble 
35707fc0564eSAndrew Elble 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
35717fc0564eSAndrew Elble 		/* ignore lock owners */
35727fc0564eSAndrew Elble 		if (local->st_stateowner->so_is_open_owner == 0)
35737fc0564eSAndrew Elble 			continue;
357415ca08d3STrond Myklebust 		if (local->st_stateowner != &oo->oo_owner)
357515ca08d3STrond Myklebust 			continue;
357615ca08d3STrond Myklebust 		if (local->st_stid.sc_type == NFS4_OPEN_STID) {
35777fc0564eSAndrew Elble 			ret = local;
3578a15dfcd5SElena Reshetova 			refcount_inc(&ret->st_stid.sc_count);
35797fc0564eSAndrew Elble 			break;
35807fc0564eSAndrew Elble 		}
35817fc0564eSAndrew Elble 	}
35827fc0564eSAndrew Elble 	return ret;
35837fc0564eSAndrew Elble }
35847fc0564eSAndrew Elble 
358515ca08d3STrond Myklebust static __be32
358615ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s)
358715ca08d3STrond Myklebust {
358815ca08d3STrond Myklebust 	__be32 ret = nfs_ok;
358915ca08d3STrond Myklebust 
359015ca08d3STrond Myklebust 	switch (s->sc_type) {
359115ca08d3STrond Myklebust 	default:
359215ca08d3STrond Myklebust 		break;
35934f176417STrond Myklebust 	case 0:
359415ca08d3STrond Myklebust 	case NFS4_CLOSED_STID:
359515ca08d3STrond Myklebust 	case NFS4_CLOSED_DELEG_STID:
359615ca08d3STrond Myklebust 		ret = nfserr_bad_stateid;
359715ca08d3STrond Myklebust 		break;
359815ca08d3STrond Myklebust 	case NFS4_REVOKED_DELEG_STID:
359915ca08d3STrond Myklebust 		ret = nfserr_deleg_revoked;
360015ca08d3STrond Myklebust 	}
360115ca08d3STrond Myklebust 	return ret;
360215ca08d3STrond Myklebust }
360315ca08d3STrond Myklebust 
360415ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */
360515ca08d3STrond Myklebust static __be32
360615ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp)
360715ca08d3STrond Myklebust {
360815ca08d3STrond Myklebust 	__be32 ret;
360915ca08d3STrond Myklebust 
36104f34bd05SAndrew Elble 	mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX);
361115ca08d3STrond Myklebust 	ret = nfsd4_verify_open_stid(&stp->st_stid);
361215ca08d3STrond Myklebust 	if (ret != nfs_ok)
361315ca08d3STrond Myklebust 		mutex_unlock(&stp->st_mutex);
361415ca08d3STrond Myklebust 	return ret;
361515ca08d3STrond Myklebust }
361615ca08d3STrond Myklebust 
361715ca08d3STrond Myklebust static struct nfs4_ol_stateid *
361815ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
361915ca08d3STrond Myklebust {
362015ca08d3STrond Myklebust 	struct nfs4_ol_stateid *stp;
362115ca08d3STrond Myklebust 	for (;;) {
362215ca08d3STrond Myklebust 		spin_lock(&fp->fi_lock);
362315ca08d3STrond Myklebust 		stp = nfsd4_find_existing_open(fp, open);
362415ca08d3STrond Myklebust 		spin_unlock(&fp->fi_lock);
362515ca08d3STrond Myklebust 		if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok)
362615ca08d3STrond Myklebust 			break;
362715ca08d3STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
362815ca08d3STrond Myklebust 	}
362915ca08d3STrond Myklebust 	return stp;
363015ca08d3STrond Myklebust }
363115ca08d3STrond Myklebust 
3632fe0750e5SJ. Bruce Fields static struct nfs4_openowner *
363313d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3634db24b3b4SJeff Layton 			   struct nfsd4_compound_state *cstate)
3635db24b3b4SJeff Layton {
363613d6f66bSTrond Myklebust 	struct nfs4_client *clp = cstate->clp;
36377ffb5880STrond Myklebust 	struct nfs4_openowner *oo, *ret;
36381da177e4SLinus Torvalds 
3639fe0750e5SJ. Bruce Fields 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
3640fe0750e5SJ. Bruce Fields 	if (!oo)
36411da177e4SLinus Torvalds 		return NULL;
36426b180f0bSJeff Layton 	oo->oo_owner.so_ops = &openowner_ops;
3643fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_is_open_owner = 1;
3644fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_seqid = open->op_seqid;
3645d3134b10SJeff Layton 	oo->oo_flags = 0;
3646db24b3b4SJeff Layton 	if (nfsd4_has_session(cstate))
3647db24b3b4SJeff Layton 		oo->oo_flags |= NFS4_OO_CONFIRMED;
3648fe0750e5SJ. Bruce Fields 	oo->oo_time = 0;
364938c387b5SJ. Bruce Fields 	oo->oo_last_closed_stid = NULL;
3650fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&oo->oo_close_lru);
3651d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
3652d4f0489fSTrond Myklebust 	ret = find_openstateowner_str_locked(strhashval, open, clp);
36537ffb5880STrond Myklebust 	if (ret == NULL) {
3654fe0750e5SJ. Bruce Fields 		hash_openowner(oo, clp, strhashval);
36557ffb5880STrond Myklebust 		ret = oo;
36567ffb5880STrond Myklebust 	} else
3657d50ffdedSKinglong Mee 		nfs4_free_stateowner(&oo->oo_owner);
3658d50ffdedSKinglong Mee 
3659d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
3660c5952338SJeff Layton 	return ret;
36611da177e4SLinus Torvalds }
36621da177e4SLinus Torvalds 
36637fc0564eSAndrew Elble static struct nfs4_ol_stateid *
36648c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open)
36657fc0564eSAndrew Elble {
36661da177e4SLinus Torvalds 
36677fc0564eSAndrew Elble 	struct nfs4_openowner *oo = open->op_openowner;
36687fc0564eSAndrew Elble 	struct nfs4_ol_stateid *retstp = NULL;
36698c7245abSOleg Drokin 	struct nfs4_ol_stateid *stp;
36707fc0564eSAndrew Elble 
36718c7245abSOleg Drokin 	stp = open->op_stp;
36725cc1fb2aSOleg Drokin 	/* We are moving these outside of the spinlocks to avoid the warnings */
36735cc1fb2aSOleg Drokin 	mutex_init(&stp->st_mutex);
36744f34bd05SAndrew Elble 	mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX);
36755cc1fb2aSOleg Drokin 
367615ca08d3STrond Myklebust retry:
36777fc0564eSAndrew Elble 	spin_lock(&oo->oo_owner.so_client->cl_lock);
36787fc0564eSAndrew Elble 	spin_lock(&fp->fi_lock);
36797fc0564eSAndrew Elble 
36807fc0564eSAndrew Elble 	retstp = nfsd4_find_existing_open(fp, open);
36817fc0564eSAndrew Elble 	if (retstp)
36827fc0564eSAndrew Elble 		goto out_unlock;
36838c7245abSOleg Drokin 
36848c7245abSOleg Drokin 	open->op_stp = NULL;
3685a15dfcd5SElena Reshetova 	refcount_inc(&stp->st_stid.sc_count);
36863abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_OPEN_STID;
36873c87b9b7STrond Myklebust 	INIT_LIST_HEAD(&stp->st_locks);
3688b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
368913cd2184SNeilBrown 	get_nfs4_file(fp);
369011b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
36911da177e4SLinus Torvalds 	stp->st_access_bmap = 0;
36921da177e4SLinus Torvalds 	stp->st_deny_bmap = 0;
36934c4cd222SNeilBrown 	stp->st_openstp = NULL;
36941c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
36951d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
36967fc0564eSAndrew Elble 
36977fc0564eSAndrew Elble out_unlock:
36981d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
36991c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
37005cc1fb2aSOleg Drokin 	if (retstp) {
370115ca08d3STrond Myklebust 		/* Handle races with CLOSE */
370215ca08d3STrond Myklebust 		if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
370315ca08d3STrond Myklebust 			nfs4_put_stid(&retstp->st_stid);
370415ca08d3STrond Myklebust 			goto retry;
370515ca08d3STrond Myklebust 		}
37068c7245abSOleg Drokin 		/* To keep mutex tracking happy */
37075cc1fb2aSOleg Drokin 		mutex_unlock(&stp->st_mutex);
37088c7245abSOleg Drokin 		stp = retstp;
37095cc1fb2aSOleg Drokin 	}
37108c7245abSOleg Drokin 	return stp;
37111da177e4SLinus Torvalds }
37121da177e4SLinus Torvalds 
3713d3134b10SJeff Layton /*
3714d3134b10SJeff Layton  * In the 4.0 case we need to keep the owners around a little while to handle
3715d3134b10SJeff Layton  * CLOSE replay. We still do need to release any file access that is held by
3716d3134b10SJeff Layton  * them before returning however.
3717d3134b10SJeff Layton  */
37181da177e4SLinus Torvalds static void
3719d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
37201da177e4SLinus Torvalds {
3721217526e7SJeff Layton 	struct nfs4_ol_stateid *last;
3722d3134b10SJeff Layton 	struct nfs4_openowner *oo = openowner(s->st_stateowner);
3723d3134b10SJeff Layton 	struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net,
3724d3134b10SJeff Layton 						nfsd_net_id);
372573758fedSStanislav Kinsbursky 
3726fe0750e5SJ. Bruce Fields 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
37271da177e4SLinus Torvalds 
3728b401be22SJeff Layton 	/*
3729b401be22SJeff Layton 	 * We know that we hold one reference via nfsd4_close, and another
3730b401be22SJeff Layton 	 * "persistent" reference for the client. If the refcount is higher
3731b401be22SJeff Layton 	 * than 2, then there are still calls in progress that are using this
3732b401be22SJeff Layton 	 * stateid. We can't put the sc_file reference until they are finished.
3733b401be22SJeff Layton 	 * Wait for the refcount to drop to 2. Since it has been unhashed,
3734b401be22SJeff Layton 	 * there should be no danger of the refcount going back up again at
3735b401be22SJeff Layton 	 * this point.
3736b401be22SJeff Layton 	 */
3737a15dfcd5SElena Reshetova 	wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2);
3738b401be22SJeff Layton 
3739d3134b10SJeff Layton 	release_all_access(s);
3740d3134b10SJeff Layton 	if (s->st_stid.sc_file) {
3741d3134b10SJeff Layton 		put_nfs4_file(s->st_stid.sc_file);
3742d3134b10SJeff Layton 		s->st_stid.sc_file = NULL;
3743d3134b10SJeff Layton 	}
3744217526e7SJeff Layton 
3745217526e7SJeff Layton 	spin_lock(&nn->client_lock);
3746217526e7SJeff Layton 	last = oo->oo_last_closed_stid;
3747d3134b10SJeff Layton 	oo->oo_last_closed_stid = s;
374873758fedSStanislav Kinsbursky 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
3749fe0750e5SJ. Bruce Fields 	oo->oo_time = get_seconds();
3750217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
3751217526e7SJeff Layton 	if (last)
3752217526e7SJeff Layton 		nfs4_put_stid(&last->st_stid);
37531da177e4SLinus Torvalds }
37541da177e4SLinus Torvalds 
37551da177e4SLinus Torvalds /* search file_hashtbl[] for file */
37561da177e4SLinus Torvalds static struct nfs4_file *
37575b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval)
37581da177e4SLinus Torvalds {
37591da177e4SLinus Torvalds 	struct nfs4_file *fp;
37601da177e4SLinus Torvalds 
37615b095e99SJeff Layton 	hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) {
37624d94c2efSChristoph Hellwig 		if (fh_match(&fp->fi_fhandle, fh)) {
3763818a34ebSElena Reshetova 			if (refcount_inc_not_zero(&fp->fi_ref))
37641da177e4SLinus Torvalds 				return fp;
37651da177e4SLinus Torvalds 		}
376613cd2184SNeilBrown 	}
37671da177e4SLinus Torvalds 	return NULL;
37681da177e4SLinus Torvalds }
37691da177e4SLinus Torvalds 
3770e6ba76e1SChristoph Hellwig struct nfs4_file *
3771ca943217STrond Myklebust find_file(struct knfsd_fh *fh)
3772950e0118STrond Myklebust {
3773950e0118STrond Myklebust 	struct nfs4_file *fp;
37745b095e99SJeff Layton 	unsigned int hashval = file_hashval(fh);
3775950e0118STrond Myklebust 
37765b095e99SJeff Layton 	rcu_read_lock();
37775b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
37785b095e99SJeff Layton 	rcu_read_unlock();
3779950e0118STrond Myklebust 	return fp;
3780950e0118STrond Myklebust }
3781950e0118STrond Myklebust 
3782950e0118STrond Myklebust static struct nfs4_file *
3783f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh)
3784950e0118STrond Myklebust {
3785950e0118STrond Myklebust 	struct nfs4_file *fp;
37865b095e99SJeff Layton 	unsigned int hashval = file_hashval(fh);
37875b095e99SJeff Layton 
37885b095e99SJeff Layton 	rcu_read_lock();
37895b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
37905b095e99SJeff Layton 	rcu_read_unlock();
37915b095e99SJeff Layton 	if (fp)
37925b095e99SJeff Layton 		return fp;
3793950e0118STrond Myklebust 
3794950e0118STrond Myklebust 	spin_lock(&state_lock);
37955b095e99SJeff Layton 	fp = find_file_locked(fh, hashval);
37965b095e99SJeff Layton 	if (likely(fp == NULL)) {
37975b095e99SJeff Layton 		nfsd4_init_file(fh, hashval, new);
3798950e0118STrond Myklebust 		fp = new;
3799950e0118STrond Myklebust 	}
3800950e0118STrond Myklebust 	spin_unlock(&state_lock);
3801950e0118STrond Myklebust 
3802950e0118STrond Myklebust 	return fp;
3803950e0118STrond Myklebust }
3804950e0118STrond Myklebust 
38054f83aa30SJ. Bruce Fields /*
38061da177e4SLinus Torvalds  * Called to check deny when READ with all zero stateid or
38071da177e4SLinus Torvalds  * WRITE with all zero or all one stateid
38081da177e4SLinus Torvalds  */
3809b37ad28bSAl Viro static __be32
38101da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
38111da177e4SLinus Torvalds {
38121da177e4SLinus Torvalds 	struct nfs4_file *fp;
3813baeb4ff0SJeff Layton 	__be32 ret = nfs_ok;
38141da177e4SLinus Torvalds 
3815ca943217STrond Myklebust 	fp = find_file(&current_fh->fh_handle);
381613cd2184SNeilBrown 	if (!fp)
3817baeb4ff0SJeff Layton 		return ret;
3818baeb4ff0SJeff Layton 	/* Check for conflicting share reservations */
38191d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
3820baeb4ff0SJeff Layton 	if (fp->fi_share_deny & deny_type)
3821baeb4ff0SJeff Layton 		ret = nfserr_locked;
38221d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
382313cd2184SNeilBrown 	put_nfs4_file(fp);
382413cd2184SNeilBrown 	return ret;
38251da177e4SLinus Torvalds }
38261da177e4SLinus Torvalds 
38270162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb)
38281da177e4SLinus Torvalds {
38290162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
383011b9164aSTrond Myklebust 	struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net,
383111b9164aSTrond Myklebust 					  nfsd_net_id);
3832e8c69d17SJ. Bruce Fields 
383311b9164aSTrond Myklebust 	block_delegations(&dp->dl_stid.sc_file->fi_fhandle);
3834f54fe962SJeff Layton 
383502e1215fSJeff Layton 	/*
383602e1215fSJeff Layton 	 * We can't do this in nfsd_break_deleg_cb because it is
3837f54fe962SJeff Layton 	 * already holding inode->i_lock.
3838f54fe962SJeff Layton 	 *
3839dff1399fSJeff Layton 	 * If the dl_time != 0, then we know that it has already been
3840dff1399fSJeff Layton 	 * queued for a lease break. Don't queue it again.
3841dff1399fSJeff Layton 	 */
3842f54fe962SJeff Layton 	spin_lock(&state_lock);
3843dff1399fSJeff Layton 	if (dp->dl_time == 0) {
38441da177e4SLinus Torvalds 		dp->dl_time = get_seconds();
384502e1215fSJeff Layton 		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
384602e1215fSJeff Layton 	}
384702e1215fSJeff Layton 	spin_unlock(&state_lock);
3848dff1399fSJeff Layton }
38491da177e4SLinus Torvalds 
38500162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
38510162ac2bSChristoph Hellwig 		struct rpc_task *task)
38520162ac2bSChristoph Hellwig {
38530162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
38540162ac2bSChristoph Hellwig 
3855a457974fSAndrew Elble 	if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID)
3856a457974fSAndrew Elble 	        return 1;
3857a457974fSAndrew Elble 
38580162ac2bSChristoph Hellwig 	switch (task->tk_status) {
38590162ac2bSChristoph Hellwig 	case 0:
38600162ac2bSChristoph Hellwig 		return 1;
38610162ac2bSChristoph Hellwig 	case -EBADHANDLE:
38620162ac2bSChristoph Hellwig 	case -NFS4ERR_BAD_STATEID:
38630162ac2bSChristoph Hellwig 		/*
38640162ac2bSChristoph Hellwig 		 * Race: client probably got cb_recall before open reply
38650162ac2bSChristoph Hellwig 		 * granting delegation.
38660162ac2bSChristoph Hellwig 		 */
38670162ac2bSChristoph Hellwig 		if (dp->dl_retries--) {
38680162ac2bSChristoph Hellwig 			rpc_delay(task, 2 * HZ);
38690162ac2bSChristoph Hellwig 			return 0;
38700162ac2bSChristoph Hellwig 		}
38710162ac2bSChristoph Hellwig 		/*FALLTHRU*/
38720162ac2bSChristoph Hellwig 	default:
38730162ac2bSChristoph Hellwig 		return -1;
38740162ac2bSChristoph Hellwig 	}
38750162ac2bSChristoph Hellwig }
38760162ac2bSChristoph Hellwig 
38770162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb)
38780162ac2bSChristoph Hellwig {
38790162ac2bSChristoph Hellwig 	struct nfs4_delegation *dp = cb_to_delegation(cb);
38800162ac2bSChristoph Hellwig 
38810162ac2bSChristoph Hellwig 	nfs4_put_stid(&dp->dl_stid);
38820162ac2bSChristoph Hellwig }
38830162ac2bSChristoph Hellwig 
3884c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
38850162ac2bSChristoph Hellwig 	.prepare	= nfsd4_cb_recall_prepare,
38860162ac2bSChristoph Hellwig 	.done		= nfsd4_cb_recall_done,
38870162ac2bSChristoph Hellwig 	.release	= nfsd4_cb_recall_release,
38880162ac2bSChristoph Hellwig };
38890162ac2bSChristoph Hellwig 
389002e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
389102e1215fSJeff Layton {
389202e1215fSJeff Layton 	/*
389302e1215fSJeff Layton 	 * We're assuming the state code never drops its reference
389402e1215fSJeff Layton 	 * without first removing the lease.  Since we're in this lease
389502e1215fSJeff Layton 	 * callback (and since the lease code is serialized by the kernel
389602e1215fSJeff Layton 	 * lock) we know the server hasn't removed the lease yet, we know
389702e1215fSJeff Layton 	 * it's safe to take a reference.
389802e1215fSJeff Layton 	 */
3899a15dfcd5SElena Reshetova 	refcount_inc(&dp->dl_stid.sc_count);
3900f0b5de1bSChristoph Hellwig 	nfsd4_run_cb(&dp->dl_recall);
39016b57d9c8SJ. Bruce Fields }
39026b57d9c8SJ. Bruce Fields 
39031c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */
39044d01b7f5SJeff Layton static bool
39054d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl)
39066b57d9c8SJ. Bruce Fields {
39074d01b7f5SJeff Layton 	bool ret = false;
3908acfdf5c3SJ. Bruce Fields 	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
3909acfdf5c3SJ. Bruce Fields 	struct nfs4_delegation *dp;
39106b57d9c8SJ. Bruce Fields 
39117fa10cd1SJ. Bruce Fields 	if (!fp) {
39127fa10cd1SJ. Bruce Fields 		WARN(1, "(%p)->fl_owner NULL\n", fl);
39134d01b7f5SJeff Layton 		return ret;
39147fa10cd1SJ. Bruce Fields 	}
39157fa10cd1SJ. Bruce Fields 	if (fp->fi_had_conflict) {
39167fa10cd1SJ. Bruce Fields 		WARN(1, "duplicate break on %p\n", fp);
39174d01b7f5SJeff Layton 		return ret;
39187fa10cd1SJ. Bruce Fields 	}
39190272e1fdSJ. Bruce Fields 	/*
39200272e1fdSJ. Bruce Fields 	 * We don't want the locks code to timeout the lease for us;
3921acfdf5c3SJ. Bruce Fields 	 * we'll remove it ourself if a delegation isn't returned
39226b57d9c8SJ. Bruce Fields 	 * in time:
39230272e1fdSJ. Bruce Fields 	 */
39240272e1fdSJ. Bruce Fields 	fl->fl_break_time = 0;
39251da177e4SLinus Torvalds 
392602e1215fSJeff Layton 	spin_lock(&fp->fi_lock);
3927417c6629SJeff Layton 	fp->fi_had_conflict = true;
3928417c6629SJeff Layton 	/*
39294d01b7f5SJeff Layton 	 * If there are no delegations on the list, then return true
39304d01b7f5SJeff Layton 	 * so that the lease code will go ahead and delete it.
3931417c6629SJeff Layton 	 */
3932417c6629SJeff Layton 	if (list_empty(&fp->fi_delegations))
39334d01b7f5SJeff Layton 		ret = true;
3934417c6629SJeff Layton 	else
3935acfdf5c3SJ. Bruce Fields 		list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
39365d926e8cSJ. Bruce Fields 			nfsd_break_one_deleg(dp);
393702e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
39384d01b7f5SJeff Layton 	return ret;
39391da177e4SLinus Torvalds }
39401da177e4SLinus Torvalds 
3941c45198edSJeff Layton static int
39427448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
39437448cc37SJeff Layton 		     struct list_head *dispose)
39441da177e4SLinus Torvalds {
39451da177e4SLinus Torvalds 	if (arg & F_UNLCK)
3946c45198edSJeff Layton 		return lease_modify(onlist, arg, dispose);
39471da177e4SLinus Torvalds 	else
39481da177e4SLinus Torvalds 		return -EAGAIN;
39491da177e4SLinus Torvalds }
39501da177e4SLinus Torvalds 
39517b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = {
39528fb47a4fSJ. Bruce Fields 	.lm_break = nfsd_break_deleg_cb,
39538fb47a4fSJ. Bruce Fields 	.lm_change = nfsd_change_deleg_cb,
39541da177e4SLinus Torvalds };
39551da177e4SLinus Torvalds 
39567a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
39577a8711c9SJ. Bruce Fields {
39587a8711c9SJ. Bruce Fields 	if (nfsd4_has_session(cstate))
39597a8711c9SJ. Bruce Fields 		return nfs_ok;
39607a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid - 1)
39617a8711c9SJ. Bruce Fields 		return nfserr_replay_me;
39627a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid)
39637a8711c9SJ. Bruce Fields 		return nfs_ok;
39647a8711c9SJ. Bruce Fields 	return nfserr_bad_seqid;
39657a8711c9SJ. Bruce Fields }
39661da177e4SLinus Torvalds 
39674b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid,
39684b24ca7dSJeff Layton 		struct nfsd4_compound_state *cstate,
39694b24ca7dSJeff Layton 		struct nfsd_net *nn)
39704b24ca7dSJeff Layton {
39714b24ca7dSJeff Layton 	struct nfs4_client *found;
39724b24ca7dSJeff Layton 
39734b24ca7dSJeff Layton 	if (cstate->clp) {
39744b24ca7dSJeff Layton 		found = cstate->clp;
39754b24ca7dSJeff Layton 		if (!same_clid(&found->cl_clientid, clid))
39764b24ca7dSJeff Layton 			return nfserr_stale_clientid;
39774b24ca7dSJeff Layton 		return nfs_ok;
39784b24ca7dSJeff Layton 	}
39794b24ca7dSJeff Layton 
39804b24ca7dSJeff Layton 	if (STALE_CLIENTID(clid, nn))
39814b24ca7dSJeff Layton 		return nfserr_stale_clientid;
39824b24ca7dSJeff Layton 
39834b24ca7dSJeff Layton 	/*
39844b24ca7dSJeff Layton 	 * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
39854b24ca7dSJeff Layton 	 * cached already then we know this is for is for v4.0 and "sessions"
39864b24ca7dSJeff Layton 	 * will be false.
39874b24ca7dSJeff Layton 	 */
39884b24ca7dSJeff Layton 	WARN_ON_ONCE(cstate->session);
39893e339f96STrond Myklebust 	spin_lock(&nn->client_lock);
39904b24ca7dSJeff Layton 	found = find_confirmed_client(clid, false, nn);
39913e339f96STrond Myklebust 	if (!found) {
39923e339f96STrond Myklebust 		spin_unlock(&nn->client_lock);
39934b24ca7dSJeff Layton 		return nfserr_expired;
39943e339f96STrond Myklebust 	}
39953e339f96STrond Myklebust 	atomic_inc(&found->cl_refcount);
39963e339f96STrond Myklebust 	spin_unlock(&nn->client_lock);
39974b24ca7dSJeff Layton 
39984b24ca7dSJeff Layton 	/* Cache the nfs4_client in cstate! */
39994b24ca7dSJeff Layton 	cstate->clp = found;
40004b24ca7dSJeff Layton 	return nfs_ok;
40014b24ca7dSJeff Layton }
40024b24ca7dSJeff Layton 
4003b37ad28bSAl Viro __be32
40046668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate,
40053320fef1SStanislav Kinsbursky 		    struct nfsd4_open *open, struct nfsd_net *nn)
40061da177e4SLinus Torvalds {
40071da177e4SLinus Torvalds 	clientid_t *clientid = &open->op_clientid;
40081da177e4SLinus Torvalds 	struct nfs4_client *clp = NULL;
40091da177e4SLinus Torvalds 	unsigned int strhashval;
4010fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = NULL;
40114cdc951bSJ. Bruce Fields 	__be32 status;
40121da177e4SLinus Torvalds 
40132c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(&open->op_clientid, nn))
40141da177e4SLinus Torvalds 		return nfserr_stale_clientid;
401532513b40SJ. Bruce Fields 	/*
401632513b40SJ. Bruce Fields 	 * In case we need it later, after we've already created the
401732513b40SJ. Bruce Fields 	 * file and don't want to risk a further failure:
401832513b40SJ. Bruce Fields 	 */
401932513b40SJ. Bruce Fields 	open->op_file = nfsd4_alloc_file();
402032513b40SJ. Bruce Fields 	if (open->op_file == NULL)
402132513b40SJ. Bruce Fields 		return nfserr_jukebox;
40221da177e4SLinus Torvalds 
402313d6f66bSTrond Myklebust 	status = lookup_clientid(clientid, cstate, nn);
402413d6f66bSTrond Myklebust 	if (status)
402513d6f66bSTrond Myklebust 		return status;
402613d6f66bSTrond Myklebust 	clp = cstate->clp;
40272d91e895STrond Myklebust 
4028d4f0489fSTrond Myklebust 	strhashval = ownerstr_hashval(&open->op_owner);
4029d4f0489fSTrond Myklebust 	oo = find_openstateowner_str(strhashval, open, clp);
40302d91e895STrond Myklebust 	open->op_openowner = oo;
40312d91e895STrond Myklebust 	if (!oo) {
4032bcf130f9SJ. Bruce Fields 		goto new_owner;
40330f442aa2SJ. Bruce Fields 	}
4034dad1c067SJ. Bruce Fields 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
40350f442aa2SJ. Bruce Fields 		/* Replace unconfirmed owners without checking for replay. */
4036fe0750e5SJ. Bruce Fields 		release_openowner(oo);
4037fe0750e5SJ. Bruce Fields 		open->op_openowner = NULL;
4038bcf130f9SJ. Bruce Fields 		goto new_owner;
40390f442aa2SJ. Bruce Fields 	}
40404cdc951bSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
40414cdc951bSJ. Bruce Fields 	if (status)
40424cdc951bSJ. Bruce Fields 		return status;
40434cdc951bSJ. Bruce Fields 	goto alloc_stateid;
4044bcf130f9SJ. Bruce Fields new_owner:
404513d6f66bSTrond Myklebust 	oo = alloc_init_open_stateowner(strhashval, open, cstate);
4046fe0750e5SJ. Bruce Fields 	if (oo == NULL)
40473e772463SJ. Bruce Fields 		return nfserr_jukebox;
4048fe0750e5SJ. Bruce Fields 	open->op_openowner = oo;
40494cdc951bSJ. Bruce Fields alloc_stateid:
4050b49e084dSJeff Layton 	open->op_stp = nfs4_alloc_open_stateid(clp);
40514cdc951bSJ. Bruce Fields 	if (!open->op_stp)
40524cdc951bSJ. Bruce Fields 		return nfserr_jukebox;
40538287f009SSachin Bhamare 
40548287f009SSachin Bhamare 	if (nfsd4_has_session(cstate) &&
40558287f009SSachin Bhamare 	    (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) {
40568287f009SSachin Bhamare 		open->op_odstate = alloc_clnt_odstate(clp);
40578287f009SSachin Bhamare 		if (!open->op_odstate)
40588287f009SSachin Bhamare 			return nfserr_jukebox;
40598287f009SSachin Bhamare 	}
40608287f009SSachin Bhamare 
40610f442aa2SJ. Bruce Fields 	return nfs_ok;
40621da177e4SLinus Torvalds }
40631da177e4SLinus Torvalds 
4064b37ad28bSAl Viro static inline __be32
40654a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
40664a6e43e6SNeilBrown {
40674a6e43e6SNeilBrown 	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
40684a6e43e6SNeilBrown 		return nfserr_openmode;
40694a6e43e6SNeilBrown 	else
40704a6e43e6SNeilBrown 		return nfs_ok;
40714a6e43e6SNeilBrown }
40724a6e43e6SNeilBrown 
4073c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access)
407424a0111eSJ. Bruce Fields {
407524a0111eSJ. Bruce Fields 	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
407624a0111eSJ. Bruce Fields }
407724a0111eSJ. Bruce Fields 
407838c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
4079f459e453SJ. Bruce Fields {
4080f459e453SJ. Bruce Fields 	struct nfs4_stid *ret;
4081f459e453SJ. Bruce Fields 
408295da1b3aSAndrew Elble 	ret = find_stateid_by_type(cl, s,
408395da1b3aSAndrew Elble 				NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID);
4084f459e453SJ. Bruce Fields 	if (!ret)
4085f459e453SJ. Bruce Fields 		return NULL;
4086f459e453SJ. Bruce Fields 	return delegstateid(ret);
4087f459e453SJ. Bruce Fields }
4088f459e453SJ. Bruce Fields 
40898b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
40908b289b2cSJ. Bruce Fields {
40918b289b2cSJ. Bruce Fields 	return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
40928b289b2cSJ. Bruce Fields 	       open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
40938b289b2cSJ. Bruce Fields }
40948b289b2cSJ. Bruce Fields 
4095b37ad28bSAl Viro static __be32
409641d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
4097567d9829SNeilBrown 		struct nfs4_delegation **dp)
4098567d9829SNeilBrown {
4099567d9829SNeilBrown 	int flags;
4100b37ad28bSAl Viro 	__be32 status = nfserr_bad_stateid;
4101dcd94cc2STrond Myklebust 	struct nfs4_delegation *deleg;
4102567d9829SNeilBrown 
4103dcd94cc2STrond Myklebust 	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
4104dcd94cc2STrond Myklebust 	if (deleg == NULL)
4105c44c5eebSNeilBrown 		goto out;
410695da1b3aSAndrew Elble 	if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
410795da1b3aSAndrew Elble 		nfs4_put_stid(&deleg->dl_stid);
410895da1b3aSAndrew Elble 		if (cl->cl_minorversion)
410995da1b3aSAndrew Elble 			status = nfserr_deleg_revoked;
411095da1b3aSAndrew Elble 		goto out;
411195da1b3aSAndrew Elble 	}
411224a0111eSJ. Bruce Fields 	flags = share_access_to_flags(open->op_share_access);
4113dcd94cc2STrond Myklebust 	status = nfs4_check_delegmode(deleg, flags);
4114dcd94cc2STrond Myklebust 	if (status) {
4115dcd94cc2STrond Myklebust 		nfs4_put_stid(&deleg->dl_stid);
4116dcd94cc2STrond Myklebust 		goto out;
4117dcd94cc2STrond Myklebust 	}
4118dcd94cc2STrond Myklebust 	*dp = deleg;
4119c44c5eebSNeilBrown out:
41208b289b2cSJ. Bruce Fields 	if (!nfsd4_is_deleg_cur(open))
4121c44c5eebSNeilBrown 		return nfs_ok;
4122c44c5eebSNeilBrown 	if (status)
4123c44c5eebSNeilBrown 		return status;
4124dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
4125c44c5eebSNeilBrown 	return nfs_ok;
4126567d9829SNeilBrown }
4127567d9829SNeilBrown 
412821fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access)
412921fb4016SJ. Bruce Fields {
413021fb4016SJ. Bruce Fields 	int flags = 0;
413121fb4016SJ. Bruce Fields 
413221fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
413321fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_READ;
413421fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
413521fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_WRITE;
413621fb4016SJ. Bruce Fields 	return flags;
413721fb4016SJ. Bruce Fields }
413821fb4016SJ. Bruce Fields 
4139b37ad28bSAl Viro static inline __be32
41401da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
41411da177e4SLinus Torvalds 		struct nfsd4_open *open)
41421da177e4SLinus Torvalds {
41431da177e4SLinus Torvalds 	struct iattr iattr = {
41441da177e4SLinus Torvalds 		.ia_valid = ATTR_SIZE,
41451da177e4SLinus Torvalds 		.ia_size = 0,
41461da177e4SLinus Torvalds 	};
41471da177e4SLinus Torvalds 	if (!open->op_truncate)
41481da177e4SLinus Torvalds 		return 0;
41491da177e4SLinus Torvalds 	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
41509246585aSAl Viro 		return nfserr_inval;
41511da177e4SLinus Torvalds 	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
41521da177e4SLinus Torvalds }
41531da177e4SLinus Torvalds 
41547e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
41556eb3a1d0SJeff Layton 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
41566eb3a1d0SJeff Layton 		struct nfsd4_open *open)
41577e6a72e5SChristoph Hellwig {
4158de18643dSTrond Myklebust 	struct file *filp = NULL;
41597e6a72e5SChristoph Hellwig 	__be32 status;
41607e6a72e5SChristoph Hellwig 	int oflag = nfs4_access_to_omode(open->op_share_access);
41617e6a72e5SChristoph Hellwig 	int access = nfs4_access_to_access(open->op_share_access);
4162baeb4ff0SJeff Layton 	unsigned char old_access_bmap, old_deny_bmap;
41637e6a72e5SChristoph Hellwig 
4164de18643dSTrond Myklebust 	spin_lock(&fp->fi_lock);
4165baeb4ff0SJeff Layton 
4166baeb4ff0SJeff Layton 	/*
4167baeb4ff0SJeff Layton 	 * Are we trying to set a deny mode that would conflict with
4168baeb4ff0SJeff Layton 	 * current access?
4169baeb4ff0SJeff Layton 	 */
4170baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
4171baeb4ff0SJeff Layton 	if (status != nfs_ok) {
4172baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
4173baeb4ff0SJeff Layton 		goto out;
4174baeb4ff0SJeff Layton 	}
4175baeb4ff0SJeff Layton 
4176baeb4ff0SJeff Layton 	/* set access to the file */
4177baeb4ff0SJeff Layton 	status = nfs4_file_get_access(fp, open->op_share_access);
4178baeb4ff0SJeff Layton 	if (status != nfs_ok) {
4179baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
4180baeb4ff0SJeff Layton 		goto out;
4181baeb4ff0SJeff Layton 	}
4182baeb4ff0SJeff Layton 
4183baeb4ff0SJeff Layton 	/* Set access bits in stateid */
4184baeb4ff0SJeff Layton 	old_access_bmap = stp->st_access_bmap;
4185baeb4ff0SJeff Layton 	set_access(open->op_share_access, stp);
4186baeb4ff0SJeff Layton 
4187baeb4ff0SJeff Layton 	/* Set new deny mask */
4188baeb4ff0SJeff Layton 	old_deny_bmap = stp->st_deny_bmap;
4189baeb4ff0SJeff Layton 	set_deny(open->op_share_deny, stp);
4190baeb4ff0SJeff Layton 	fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH);
4191baeb4ff0SJeff Layton 
41927e6a72e5SChristoph Hellwig 	if (!fp->fi_fds[oflag]) {
4193de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
4194de18643dSTrond Myklebust 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
41957e6a72e5SChristoph Hellwig 		if (status)
4196baeb4ff0SJeff Layton 			goto out_put_access;
4197de18643dSTrond Myklebust 		spin_lock(&fp->fi_lock);
4198de18643dSTrond Myklebust 		if (!fp->fi_fds[oflag]) {
4199de18643dSTrond Myklebust 			fp->fi_fds[oflag] = filp;
4200de18643dSTrond Myklebust 			filp = NULL;
4201de18643dSTrond Myklebust 		}
42027e6a72e5SChristoph Hellwig 	}
4203de18643dSTrond Myklebust 	spin_unlock(&fp->fi_lock);
4204de18643dSTrond Myklebust 	if (filp)
4205de18643dSTrond Myklebust 		fput(filp);
42067e6a72e5SChristoph Hellwig 
42077e6a72e5SChristoph Hellwig 	status = nfsd4_truncate(rqstp, cur_fh, open);
42087e6a72e5SChristoph Hellwig 	if (status)
42097e6a72e5SChristoph Hellwig 		goto out_put_access;
42107e6a72e5SChristoph Hellwig out:
42117e6a72e5SChristoph Hellwig 	return status;
4212baeb4ff0SJeff Layton out_put_access:
4213baeb4ff0SJeff Layton 	stp->st_access_bmap = old_access_bmap;
4214baeb4ff0SJeff Layton 	nfs4_file_put_access(fp, open->op_share_access);
4215baeb4ff0SJeff Layton 	reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp);
4216baeb4ff0SJeff Layton 	goto out;
42177e6a72e5SChristoph Hellwig }
42187e6a72e5SChristoph Hellwig 
4219b37ad28bSAl Viro static __be32
4220dcef0413SJ. 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)
42211da177e4SLinus Torvalds {
4222b37ad28bSAl Viro 	__be32 status;
42236ac75368SArnd Bergmann 	unsigned char old_deny_bmap = stp->st_deny_bmap;
42241da177e4SLinus Torvalds 
42256eb3a1d0SJeff Layton 	if (!test_access(open->op_share_access, stp))
4226baeb4ff0SJeff Layton 		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
42277e6a72e5SChristoph Hellwig 
4228baeb4ff0SJeff Layton 	/* test and set deny mode */
4229baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
4230baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
4231baeb4ff0SJeff Layton 	if (status == nfs_ok) {
4232baeb4ff0SJeff Layton 		set_deny(open->op_share_deny, stp);
4233baeb4ff0SJeff Layton 		fp->fi_share_deny |=
4234baeb4ff0SJeff Layton 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
42351da177e4SLinus Torvalds 	}
4236baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
42371da177e4SLinus Torvalds 
4238baeb4ff0SJeff Layton 	if (status != nfs_ok)
4239baeb4ff0SJeff Layton 		return status;
4240baeb4ff0SJeff Layton 
4241baeb4ff0SJeff Layton 	status = nfsd4_truncate(rqstp, cur_fh, open);
4242baeb4ff0SJeff Layton 	if (status != nfs_ok)
4243baeb4ff0SJeff Layton 		reset_union_bmap_deny(old_deny_bmap, stp);
4244baeb4ff0SJeff Layton 	return status;
4245baeb4ff0SJeff Layton }
42461da177e4SLinus Torvalds 
424714a24e99SJ. Bruce Fields /* Should we give out recallable state?: */
424814a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
424914a24e99SJ. Bruce Fields {
425014a24e99SJ. Bruce Fields 	if (clp->cl_cb_state == NFSD4_CB_UP)
425114a24e99SJ. Bruce Fields 		return true;
425214a24e99SJ. Bruce Fields 	/*
425314a24e99SJ. Bruce Fields 	 * In the sessions case, since we don't have to establish a
425414a24e99SJ. Bruce Fields 	 * separate connection for callbacks, we assume it's OK
425514a24e99SJ. Bruce Fields 	 * until we hear otherwise:
425614a24e99SJ. Bruce Fields 	 */
425714a24e99SJ. Bruce Fields 	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
425814a24e99SJ. Bruce Fields }
425914a24e99SJ. Bruce Fields 
4260d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
426122d38c4cSJ. Bruce Fields {
426222d38c4cSJ. Bruce Fields 	struct file_lock *fl;
426322d38c4cSJ. Bruce Fields 
426422d38c4cSJ. Bruce Fields 	fl = locks_alloc_lock();
426522d38c4cSJ. Bruce Fields 	if (!fl)
426622d38c4cSJ. Bruce Fields 		return NULL;
426722d38c4cSJ. Bruce Fields 	fl->fl_lmops = &nfsd_lease_mng_ops;
4268617588d5SJ. Bruce Fields 	fl->fl_flags = FL_DELEG;
426922d38c4cSJ. Bruce Fields 	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
427022d38c4cSJ. Bruce Fields 	fl->fl_end = OFFSET_MAX;
4271d564fbecSJeff Layton 	fl->fl_owner = (fl_owner_t)fp;
427222d38c4cSJ. Bruce Fields 	fl->fl_pid = current->tgid;
427322d38c4cSJ. Bruce Fields 	return fl;
427422d38c4cSJ. Bruce Fields }
427522d38c4cSJ. Bruce Fields 
427634ed9872SAndrew Elble /**
427734ed9872SAndrew Elble  * nfs4_setlease - Obtain a delegation by requesting lease from vfs layer
427834ed9872SAndrew Elble  * @dp:   a pointer to the nfs4_delegation we're adding.
427934ed9872SAndrew Elble  *
428034ed9872SAndrew Elble  * Return:
428134ed9872SAndrew Elble  *      On success: Return code will be 0 on success.
428234ed9872SAndrew Elble  *
428334ed9872SAndrew Elble  *      On error: -EAGAIN if there was an existing delegation.
428434ed9872SAndrew Elble  *                 nonzero if there is an error in other cases.
428534ed9872SAndrew Elble  *
428634ed9872SAndrew Elble  */
428734ed9872SAndrew Elble 
428899c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp)
4289edab9782SJ. Bruce Fields {
429011b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
4291efde6b4dSKinglong Mee 	struct file_lock *fl;
4292417c6629SJeff Layton 	struct file *filp;
4293417c6629SJeff Layton 	int status = 0;
4294edab9782SJ. Bruce Fields 
4295d564fbecSJeff Layton 	fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ);
4296edab9782SJ. Bruce Fields 	if (!fl)
4297edab9782SJ. Bruce Fields 		return -ENOMEM;
4298417c6629SJeff Layton 	filp = find_readable_file(fp);
4299417c6629SJeff Layton 	if (!filp) {
4300417c6629SJeff Layton 		/* We should always have a readable file here */
4301417c6629SJeff Layton 		WARN_ON_ONCE(1);
4302af9dbaf4SKinglong Mee 		locks_free_lock(fl);
4303417c6629SJeff Layton 		return -EBADF;
4304417c6629SJeff Layton 	}
4305417c6629SJeff Layton 	fl->fl_file = filp;
4306e6f5c789SJeff Layton 	status = vfs_setlease(filp, fl->fl_type, &fl, NULL);
43071c7dd2ffSJeff Layton 	if (fl)
4308417c6629SJeff Layton 		locks_free_lock(fl);
43091c7dd2ffSJeff Layton 	if (status)
4310417c6629SJeff Layton 		goto out_fput;
4311cdc97505SBenny Halevy 	spin_lock(&state_lock);
4312417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
4313417c6629SJeff Layton 	/* Did the lease get broken before we took the lock? */
4314417c6629SJeff Layton 	status = -EAGAIN;
4315417c6629SJeff Layton 	if (fp->fi_had_conflict)
4316417c6629SJeff Layton 		goto out_unlock;
4317417c6629SJeff Layton 	/* Race breaker */
43180c637be8SJeff Layton 	if (fp->fi_deleg_file) {
431934ed9872SAndrew Elble 		status = hash_delegation_locked(dp, fp);
4320417c6629SJeff Layton 		goto out_unlock;
4321417c6629SJeff Layton 	}
4322417c6629SJeff Layton 	fp->fi_deleg_file = filp;
432334ed9872SAndrew Elble 	fp->fi_delegees = 0;
432434ed9872SAndrew Elble 	status = hash_delegation_locked(dp, fp);
4325417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4326cdc97505SBenny Halevy 	spin_unlock(&state_lock);
432734ed9872SAndrew Elble 	if (status) {
432834ed9872SAndrew Elble 		/* Should never happen, this is a new fi_deleg_file  */
432934ed9872SAndrew Elble 		WARN_ON_ONCE(1);
433034ed9872SAndrew Elble 		goto out_fput;
433134ed9872SAndrew Elble 	}
4332acfdf5c3SJ. Bruce Fields 	return 0;
4333417c6629SJeff Layton out_unlock:
4334417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4335417c6629SJeff Layton 	spin_unlock(&state_lock);
4336417c6629SJeff Layton out_fput:
4337417c6629SJeff Layton 	fput(filp);
4338e873088fSJ. Bruce Fields 	return status;
4339acfdf5c3SJ. Bruce Fields }
4340acfdf5c3SJ. Bruce Fields 
43410b26693cSJeff Layton static struct nfs4_delegation *
43420b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
43438287f009SSachin Bhamare 		    struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
4344acfdf5c3SJ. Bruce Fields {
43450b26693cSJeff Layton 	int status;
43460b26693cSJeff Layton 	struct nfs4_delegation *dp;
4347417c6629SJeff Layton 
4348bf7bd3e9SJ. Bruce Fields 	if (fp->fi_had_conflict)
43490b26693cSJeff Layton 		return ERR_PTR(-EAGAIN);
43500b26693cSJeff Layton 
435134ed9872SAndrew Elble 	spin_lock(&state_lock);
435234ed9872SAndrew Elble 	spin_lock(&fp->fi_lock);
435334ed9872SAndrew Elble 	status = nfs4_get_existing_delegation(clp, fp);
435434ed9872SAndrew Elble 	spin_unlock(&fp->fi_lock);
435534ed9872SAndrew Elble 	spin_unlock(&state_lock);
435634ed9872SAndrew Elble 
435734ed9872SAndrew Elble 	if (status)
435834ed9872SAndrew Elble 		return ERR_PTR(status);
435934ed9872SAndrew Elble 
43608287f009SSachin Bhamare 	dp = alloc_init_deleg(clp, fh, odstate);
43610b26693cSJeff Layton 	if (!dp)
43620b26693cSJeff Layton 		return ERR_PTR(-ENOMEM);
43630b26693cSJeff Layton 
4364bf7bd3e9SJ. Bruce Fields 	get_nfs4_file(fp);
4365cdc97505SBenny Halevy 	spin_lock(&state_lock);
4366417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
436711b9164aSTrond Myklebust 	dp->dl_stid.sc_file = fp;
43680c637be8SJeff Layton 	if (!fp->fi_deleg_file) {
4369417c6629SJeff Layton 		spin_unlock(&fp->fi_lock);
4370417c6629SJeff Layton 		spin_unlock(&state_lock);
43710b26693cSJeff Layton 		status = nfs4_setlease(dp);
43720b26693cSJeff Layton 		goto out;
4373417c6629SJeff Layton 	}
4374acfdf5c3SJ. Bruce Fields 	if (fp->fi_had_conflict) {
4375417c6629SJeff Layton 		status = -EAGAIN;
4376417c6629SJeff Layton 		goto out_unlock;
4377acfdf5c3SJ. Bruce Fields 	}
437834ed9872SAndrew Elble 	status = hash_delegation_locked(dp, fp);
4379417c6629SJeff Layton out_unlock:
4380417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
4381cdc97505SBenny Halevy 	spin_unlock(&state_lock);
43820b26693cSJeff Layton out:
43830b26693cSJeff Layton 	if (status) {
43848287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
43856011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
43860b26693cSJeff Layton 		return ERR_PTR(status);
43870b26693cSJeff Layton 	}
43880b26693cSJeff Layton 	return dp;
4389edab9782SJ. Bruce Fields }
4390edab9782SJ. Bruce Fields 
43914aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
43924aa8913cSBenny Halevy {
43934aa8913cSBenny Halevy 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
43944aa8913cSBenny Halevy 	if (status == -EAGAIN)
43954aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_CONTENTION;
43964aa8913cSBenny Halevy 	else {
43974aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_RESOURCE;
43984aa8913cSBenny Halevy 		switch (open->op_deleg_want) {
43994aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_READ_DELEG:
44004aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_WRITE_DELEG:
44014aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_ANY_DELEG:
44024aa8913cSBenny Halevy 			break;
44034aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_CANCEL:
44044aa8913cSBenny Halevy 			open->op_why_no_deleg = WND4_CANCELLED;
44054aa8913cSBenny Halevy 			break;
44064aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_NO_DELEG:
4407063b0fb9SJ. Bruce Fields 			WARN_ON_ONCE(1);
44084aa8913cSBenny Halevy 		}
44094aa8913cSBenny Halevy 	}
44104aa8913cSBenny Halevy }
44114aa8913cSBenny Halevy 
44121da177e4SLinus Torvalds /*
44131da177e4SLinus Torvalds  * Attempt to hand out a delegation.
441499c41515SJ. Bruce Fields  *
441599c41515SJ. Bruce Fields  * Note we don't support write delegations, and won't until the vfs has
441699c41515SJ. Bruce Fields  * proper support for them.
44171da177e4SLinus Torvalds  */
44181da177e4SLinus Torvalds static void
44194cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
44204cf59221SJeff Layton 			struct nfs4_ol_stateid *stp)
44211da177e4SLinus Torvalds {
44221da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
44234cf59221SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_stateowner);
44244cf59221SJeff Layton 	struct nfs4_client *clp = stp->st_stid.sc_client;
442514a24e99SJ. Bruce Fields 	int cb_up;
442699c41515SJ. Bruce Fields 	int status = 0;
44271da177e4SLinus Torvalds 
4428fe0750e5SJ. Bruce Fields 	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
44297b190fecSNeilBrown 	open->op_recall = 0;
44307b190fecSNeilBrown 	switch (open->op_claim_type) {
44317b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_PREVIOUS:
44322bf23875SJ. Bruce Fields 			if (!cb_up)
44337b190fecSNeilBrown 				open->op_recall = 1;
443499c41515SJ. Bruce Fields 			if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
443599c41515SJ. Bruce Fields 				goto out_no_deleg;
44367b190fecSNeilBrown 			break;
44377b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_NULL:
4438ed47b062SMing Chen 		case NFS4_OPEN_CLAIM_FH:
443999c41515SJ. Bruce Fields 			/*
444099c41515SJ. Bruce Fields 			 * Let's not give out any delegations till everyone's
4441c87fb4a3SJ. Bruce Fields 			 * had the chance to reclaim theirs, *and* until
4442c87fb4a3SJ. Bruce Fields 			 * NLM locks have all been reclaimed:
444399c41515SJ. Bruce Fields 			 */
44444cf59221SJeff Layton 			if (locks_in_grace(clp->net))
444599c41515SJ. Bruce Fields 				goto out_no_deleg;
4446dad1c067SJ. Bruce Fields 			if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
444799c41515SJ. Bruce Fields 				goto out_no_deleg;
44489a0590aeSSteve Dickson 			/*
44499a0590aeSSteve Dickson 			 * Also, if the file was opened for write or
44509a0590aeSSteve Dickson 			 * create, there's a good chance the client's
44519a0590aeSSteve Dickson 			 * about to write to it, resulting in an
44529a0590aeSSteve Dickson 			 * immediate recall (since we don't support
44539a0590aeSSteve Dickson 			 * write delegations):
44549a0590aeSSteve Dickson 			 */
44551da177e4SLinus Torvalds 			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
445699c41515SJ. Bruce Fields 				goto out_no_deleg;
445799c41515SJ. Bruce Fields 			if (open->op_create == NFS4_OPEN_CREATE)
445899c41515SJ. Bruce Fields 				goto out_no_deleg;
44597b190fecSNeilBrown 			break;
44607b190fecSNeilBrown 		default:
446199c41515SJ. Bruce Fields 			goto out_no_deleg;
44627b190fecSNeilBrown 	}
44638287f009SSachin Bhamare 	dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
44640b26693cSJeff Layton 	if (IS_ERR(dp))
4465dd239cc0SJ. Bruce Fields 		goto out_no_deleg;
44661da177e4SLinus Torvalds 
4467d5477a8dSJ. Bruce Fields 	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
44681da177e4SLinus Torvalds 
44698c10cbdbSBenny Halevy 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
4470d5477a8dSJ. Bruce Fields 		STATEID_VAL(&dp->dl_stid.sc_stateid));
447199c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
447267cb1279STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
4473dd239cc0SJ. Bruce Fields 	return;
4474dd239cc0SJ. Bruce Fields out_no_deleg:
447599c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
44767b190fecSNeilBrown 	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
4477d08d32e6SJ. Bruce Fields 	    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
44781da177e4SLinus Torvalds 		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
4479d08d32e6SJ. Bruce Fields 		open->op_recall = 1;
4480d08d32e6SJ. Bruce Fields 	}
4481dd239cc0SJ. Bruce Fields 
4482dd239cc0SJ. Bruce Fields 	/* 4.1 client asking for a delegation? */
4483dd239cc0SJ. Bruce Fields 	if (open->op_deleg_want)
4484dd239cc0SJ. Bruce Fields 		nfsd4_open_deleg_none_ext(open, status);
4485dd239cc0SJ. Bruce Fields 	return;
44861da177e4SLinus Torvalds }
44871da177e4SLinus Torvalds 
4488e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
4489e27f49c3SBenny Halevy 					struct nfs4_delegation *dp)
4490e27f49c3SBenny Halevy {
4491e27f49c3SBenny Halevy 	if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
4492e27f49c3SBenny Halevy 	    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
4493e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4494e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
4495e27f49c3SBenny Halevy 	} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
4496e27f49c3SBenny Halevy 		   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
4497e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4498e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
4499e27f49c3SBenny Halevy 	}
4500e27f49c3SBenny Halevy 	/* Otherwise the client must be confused wanting a delegation
4501e27f49c3SBenny Halevy 	 * it already has, therefore we don't return
4502e27f49c3SBenny Halevy 	 * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
4503e27f49c3SBenny Halevy 	 */
4504e27f49c3SBenny Halevy }
4505e27f49c3SBenny Halevy 
4506b37ad28bSAl Viro __be32
45071da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
45081da177e4SLinus Torvalds {
45096668958fSAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
451038c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
45111da177e4SLinus Torvalds 	struct nfs4_file *fp = NULL;
4512dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
4513567d9829SNeilBrown 	struct nfs4_delegation *dp = NULL;
4514b37ad28bSAl Viro 	__be32 status;
4515d8a1a000STrond Myklebust 	bool new_stp = false;
45161da177e4SLinus Torvalds 
45171da177e4SLinus Torvalds 	/*
45181da177e4SLinus Torvalds 	 * Lookup file; if found, lookup stateid and check open request,
45191da177e4SLinus Torvalds 	 * and check for delegations in the process of being recalled.
45201da177e4SLinus Torvalds 	 * If not found, create the nfs4_file struct
45211da177e4SLinus Torvalds 	 */
4522f9c00c3aSJeff Layton 	fp = find_or_add_file(open->op_file, &current_fh->fh_handle);
4523950e0118STrond Myklebust 	if (fp != open->op_file) {
452441d22663SJ. Bruce Fields 		status = nfs4_check_deleg(cl, open, &dp);
4525c44c5eebSNeilBrown 		if (status)
4526c44c5eebSNeilBrown 			goto out;
452715ca08d3STrond Myklebust 		stp = nfsd4_find_and_lock_existing_open(fp, open);
45281da177e4SLinus Torvalds 	} else {
4529950e0118STrond Myklebust 		open->op_file = NULL;
4530c44c5eebSNeilBrown 		status = nfserr_bad_stateid;
45318b289b2cSJ. Bruce Fields 		if (nfsd4_is_deleg_cur(open))
4532c44c5eebSNeilBrown 			goto out;
45331da177e4SLinus Torvalds 	}
45341da177e4SLinus Torvalds 
4535d8a1a000STrond Myklebust 	if (!stp) {
4536d8a1a000STrond Myklebust 		stp = init_open_stateid(fp, open);
4537d8a1a000STrond Myklebust 		if (!open->op_stp)
4538d8a1a000STrond Myklebust 			new_stp = true;
4539d8a1a000STrond Myklebust 	}
4540d8a1a000STrond Myklebust 
45411da177e4SLinus Torvalds 	/*
45421da177e4SLinus Torvalds 	 * OPEN the file, or upgrade an existing OPEN.
45431da177e4SLinus Torvalds 	 * If truncate fails, the OPEN fails.
4544d8a1a000STrond Myklebust 	 *
4545d8a1a000STrond Myklebust 	 * stp is already locked.
45461da177e4SLinus Torvalds 	 */
4547d8a1a000STrond Myklebust 	if (!new_stp) {
45481da177e4SLinus Torvalds 		/* Stateid was found, this is an OPEN upgrade */
4549f9d7562fSJ. Bruce Fields 		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
455035a92fe8SJeff Layton 		if (status) {
4551feb9dad5SOleg Drokin 			mutex_unlock(&stp->st_mutex);
45521da177e4SLinus Torvalds 			goto out;
455335a92fe8SJeff Layton 		}
45541da177e4SLinus Torvalds 	} else {
45556eb3a1d0SJeff Layton 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
45566eb3a1d0SJeff Layton 		if (status) {
4557d8a1a000STrond Myklebust 			stp->st_stid.sc_type = NFS4_CLOSED_STID;
45586eb3a1d0SJeff Layton 			release_open_stateid(stp);
4559d8a1a000STrond Myklebust 			mutex_unlock(&stp->st_mutex);
45606eb3a1d0SJeff Layton 			goto out;
45616eb3a1d0SJeff Layton 		}
45628287f009SSachin Bhamare 
45638287f009SSachin Bhamare 		stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp,
45648287f009SSachin Bhamare 							open->op_odstate);
45658287f009SSachin Bhamare 		if (stp->st_clnt_odstate == open->op_odstate)
45668287f009SSachin Bhamare 			open->op_odstate = NULL;
45671da177e4SLinus Torvalds 	}
4568d8a1a000STrond Myklebust 
45699767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
4570feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
45711da177e4SLinus Torvalds 
4572d24433cdSBenny Halevy 	if (nfsd4_has_session(&resp->cstate)) {
4573d24433cdSBenny Halevy 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
4574d24433cdSBenny Halevy 			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4575d24433cdSBenny Halevy 			open->op_why_no_deleg = WND4_NOT_WANTED;
4576d24433cdSBenny Halevy 			goto nodeleg;
4577d24433cdSBenny Halevy 		}
4578d24433cdSBenny Halevy 	}
4579d24433cdSBenny Halevy 
45801da177e4SLinus Torvalds 	/*
45811da177e4SLinus Torvalds 	* Attempt to hand out a delegation. No error return, because the
45821da177e4SLinus Torvalds 	* OPEN succeeds even if we fail.
45831da177e4SLinus Torvalds 	*/
45844cf59221SJeff Layton 	nfs4_open_delegation(current_fh, open, stp);
4585d24433cdSBenny Halevy nodeleg:
45861da177e4SLinus Torvalds 	status = nfs_ok;
45871da177e4SLinus Torvalds 
45888c10cbdbSBenny Halevy 	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
4589dcef0413SJ. Bruce Fields 		STATEID_VAL(&stp->st_stid.sc_stateid));
45901da177e4SLinus Torvalds out:
4591d24433cdSBenny Halevy 	/* 4.1 client trying to upgrade/downgrade delegation? */
4592d24433cdSBenny Halevy 	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
4593e27f49c3SBenny Halevy 	    open->op_deleg_want)
4594e27f49c3SBenny Halevy 		nfsd4_deleg_xgrade_none_ext(open, dp);
4595d24433cdSBenny Halevy 
459613cd2184SNeilBrown 	if (fp)
459713cd2184SNeilBrown 		put_nfs4_file(fp);
459837515177SNeilBrown 	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
459987186022SKinglong Mee 		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
46001da177e4SLinus Torvalds 	/*
46011da177e4SLinus Torvalds 	* To finish the open response, we just need to set the rflags.
46021da177e4SLinus Torvalds 	*/
46031da177e4SLinus Torvalds 	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
460419e4c347SJeff Layton 	if (nfsd4_has_session(&resp->cstate))
460519e4c347SJeff Layton 		open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK;
460619e4c347SJeff Layton 	else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED))
46071da177e4SLinus Torvalds 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
460819e4c347SJeff Layton 
4609dcd94cc2STrond Myklebust 	if (dp)
4610dcd94cc2STrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
4611d6f2bc5dSTrond Myklebust 	if (stp)
4612d6f2bc5dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
46131da177e4SLinus Torvalds 
46141da177e4SLinus Torvalds 	return status;
46151da177e4SLinus Torvalds }
46161da177e4SLinus Torvalds 
461758fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
461842297899SJeff Layton 			      struct nfsd4_open *open)
4619d29b20cdSJ. Bruce Fields {
4620d29b20cdSJ. Bruce Fields 	if (open->op_openowner) {
4621d3134b10SJeff Layton 		struct nfs4_stateowner *so = &open->op_openowner->oo_owner;
4622d29b20cdSJ. Bruce Fields 
4623d3134b10SJeff Layton 		nfsd4_cstate_assign_replay(cstate, so);
4624d3134b10SJeff Layton 		nfs4_put_stateowner(so);
4625d29b20cdSJ. Bruce Fields 	}
462632513b40SJ. Bruce Fields 	if (open->op_file)
46275b095e99SJeff Layton 		kmem_cache_free(file_slab, open->op_file);
46284cdc951bSJ. Bruce Fields 	if (open->op_stp)
46296011695dSTrond Myklebust 		nfs4_put_stid(&open->op_stp->st_stid);
46308287f009SSachin Bhamare 	if (open->op_odstate)
46318287f009SSachin Bhamare 		kmem_cache_free(odstate_slab, open->op_odstate);
4632d29b20cdSJ. Bruce Fields }
4633d29b20cdSJ. Bruce Fields 
4634b37ad28bSAl Viro __be32
4635b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4636eb69853dSChristoph Hellwig 	    union nfsd4_op_u *u)
46371da177e4SLinus Torvalds {
4638eb69853dSChristoph Hellwig 	clientid_t *clid = &u->renew;
46391da177e4SLinus Torvalds 	struct nfs4_client *clp;
4640b37ad28bSAl Viro 	__be32 status;
46417f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
46421da177e4SLinus Torvalds 
46431da177e4SLinus Torvalds 	dprintk("process_renew(%08x/%08x): starting\n",
46441da177e4SLinus Torvalds 			clid->cl_boot, clid->cl_id);
46454b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
46469b2ef62bSJ. Bruce Fields 	if (status)
46471da177e4SLinus Torvalds 		goto out;
46484b24ca7dSJeff Layton 	clp = cstate->clp;
46491da177e4SLinus Torvalds 	status = nfserr_cb_path_down;
4650ea1da636SNeilBrown 	if (!list_empty(&clp->cl_delegations)
465177a3569dSJ. Bruce Fields 			&& clp->cl_cb_state != NFSD4_CB_UP)
46521da177e4SLinus Torvalds 		goto out;
46531da177e4SLinus Torvalds 	status = nfs_ok;
46541da177e4SLinus Torvalds out:
46551da177e4SLinus Torvalds 	return status;
46561da177e4SLinus Torvalds }
46571da177e4SLinus Torvalds 
46587f5ef2e9SJeff Layton void
465912760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn)
4660a76b4319SNeilBrown {
466133dcc481SJeff Layton 	/* do nothing if grace period already ended */
4662a51c84edSStanislav Kinsbursky 	if (nn->grace_ended)
466333dcc481SJeff Layton 		return;
466433dcc481SJeff Layton 
4665a76b4319SNeilBrown 	dprintk("NFSD: end of grace period\n");
4666a51c84edSStanislav Kinsbursky 	nn->grace_ended = true;
466770b28235SJ. Bruce Fields 	/*
466870b28235SJ. Bruce Fields 	 * If the server goes down again right now, an NFSv4
466970b28235SJ. Bruce Fields 	 * client will still be allowed to reclaim after it comes back up,
467070b28235SJ. Bruce Fields 	 * even if it hasn't yet had a chance to reclaim state this time.
467170b28235SJ. Bruce Fields 	 *
467270b28235SJ. Bruce Fields 	 */
4673919b8049SJeff Layton 	nfsd4_record_grace_done(nn);
467470b28235SJ. Bruce Fields 	/*
467570b28235SJ. Bruce Fields 	 * At this point, NFSv4 clients can still reclaim.  But if the
467670b28235SJ. Bruce Fields 	 * server crashes, any that have not yet reclaimed will be out
467770b28235SJ. Bruce Fields 	 * of luck on the next boot.
467870b28235SJ. Bruce Fields 	 *
467970b28235SJ. Bruce Fields 	 * (NFSv4.1+ clients are considered to have reclaimed once they
468070b28235SJ. Bruce Fields 	 * call RECLAIM_COMPLETE.  NFSv4.0 clients are considered to
468170b28235SJ. Bruce Fields 	 * have reclaimed after their first OPEN.)
468270b28235SJ. Bruce Fields 	 */
46835e1533c7SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
468470b28235SJ. Bruce Fields 	/*
468570b28235SJ. Bruce Fields 	 * At this point, and once lockd and/or any other containers
468670b28235SJ. Bruce Fields 	 * exit their grace period, further reclaims will fail and
468770b28235SJ. Bruce Fields 	 * regular locking can resume.
468870b28235SJ. Bruce Fields 	 */
4689a76b4319SNeilBrown }
4690a76b4319SNeilBrown 
4691fd39ca9aSNeilBrown static time_t
469209121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn)
46931da177e4SLinus Torvalds {
46941da177e4SLinus Torvalds 	struct nfs4_client *clp;
4695fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
46961da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
4697217526e7SJeff Layton 	struct nfs4_ol_stateid *stp;
46987919d0a2SJeff Layton 	struct nfsd4_blocked_lock *nbl;
46991da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
47003d733711SStanislav Kinsbursky 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
4701a832e7aeSJeff Layton 	time_t t, new_timeo = nn->nfsd4_lease;
47021da177e4SLinus Torvalds 
47031da177e4SLinus Torvalds 	dprintk("NFSD: laundromat service - starting\n");
470412760c66SStanislav Kinsbursky 	nfsd4_end_grace(nn);
470536acb66bSBenny Halevy 	INIT_LIST_HEAD(&reaplist);
4706c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
47075ed58bb2SStanislav Kinsbursky 	list_for_each_safe(pos, next, &nn->client_lru) {
47081da177e4SLinus Torvalds 		clp = list_entry(pos, struct nfs4_client, cl_lru);
47091da177e4SLinus Torvalds 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
47101da177e4SLinus Torvalds 			t = clp->cl_time - cutoff;
4711a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
47121da177e4SLinus Torvalds 			break;
47131da177e4SLinus Torvalds 		}
4714221a6876SJ. Bruce Fields 		if (mark_client_expired_locked(clp)) {
4715d7682988SBenny Halevy 			dprintk("NFSD: client in use (clientid %08x)\n",
4716d7682988SBenny Halevy 				clp->cl_clientid.cl_id);
4717d7682988SBenny Halevy 			continue;
4718d7682988SBenny Halevy 		}
47194864af97STrond Myklebust 		list_add(&clp->cl_lru, &reaplist);
472036acb66bSBenny Halevy 	}
4721c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
472236acb66bSBenny Halevy 	list_for_each_safe(pos, next, &reaplist) {
472336acb66bSBenny Halevy 		clp = list_entry(pos, struct nfs4_client, cl_lru);
47241da177e4SLinus Torvalds 		dprintk("NFSD: purging unused client (clientid %08x)\n",
47251da177e4SLinus Torvalds 			clp->cl_clientid.cl_id);
47264864af97STrond Myklebust 		list_del_init(&clp->cl_lru);
47271da177e4SLinus Torvalds 		expire_client(clp);
47281da177e4SLinus Torvalds 	}
4729cdc97505SBenny Halevy 	spin_lock(&state_lock);
4730e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
47311da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
47321da177e4SLinus Torvalds 		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
4733a832e7aeSJeff Layton 			t = dp->dl_time - cutoff;
4734a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
47351da177e4SLinus Torvalds 			break;
47361da177e4SLinus Torvalds 		}
47373fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
473842690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
47391da177e4SLinus Torvalds 	}
4740cdc97505SBenny Halevy 	spin_unlock(&state_lock);
47412d4a532dSJeff Layton 	while (!list_empty(&reaplist)) {
47422d4a532dSJeff Layton 		dp = list_first_entry(&reaplist, struct nfs4_delegation,
47432d4a532dSJeff Layton 					dl_recall_lru);
47442d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
47453bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
47461da177e4SLinus Torvalds 	}
4747217526e7SJeff Layton 
4748217526e7SJeff Layton 	spin_lock(&nn->client_lock);
4749217526e7SJeff Layton 	while (!list_empty(&nn->close_lru)) {
4750217526e7SJeff Layton 		oo = list_first_entry(&nn->close_lru, struct nfs4_openowner,
4751217526e7SJeff Layton 					oo_close_lru);
4752217526e7SJeff Layton 		if (time_after((unsigned long)oo->oo_time,
4753217526e7SJeff Layton 			       (unsigned long)cutoff)) {
4754a832e7aeSJeff Layton 			t = oo->oo_time - cutoff;
4755a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
47561da177e4SLinus Torvalds 			break;
47571da177e4SLinus Torvalds 		}
4758217526e7SJeff Layton 		list_del_init(&oo->oo_close_lru);
4759217526e7SJeff Layton 		stp = oo->oo_last_closed_stid;
4760217526e7SJeff Layton 		oo->oo_last_closed_stid = NULL;
4761217526e7SJeff Layton 		spin_unlock(&nn->client_lock);
4762217526e7SJeff Layton 		nfs4_put_stid(&stp->st_stid);
4763217526e7SJeff Layton 		spin_lock(&nn->client_lock);
47641da177e4SLinus Torvalds 	}
4765217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
4766217526e7SJeff Layton 
47677919d0a2SJeff Layton 	/*
47687919d0a2SJeff Layton 	 * It's possible for a client to try and acquire an already held lock
47697919d0a2SJeff Layton 	 * that is being held for a long time, and then lose interest in it.
47707919d0a2SJeff Layton 	 * So, we clean out any un-revisited request after a lease period
47717919d0a2SJeff Layton 	 * under the assumption that the client is no longer interested.
47727919d0a2SJeff Layton 	 *
47737919d0a2SJeff Layton 	 * RFC5661, sec. 9.6 states that the client must not rely on getting
47747919d0a2SJeff Layton 	 * notifications and must continue to poll for locks, even when the
47757919d0a2SJeff Layton 	 * server supports them. Thus this shouldn't lead to clients blocking
47767919d0a2SJeff Layton 	 * indefinitely once the lock does become free.
47777919d0a2SJeff Layton 	 */
47787919d0a2SJeff Layton 	BUG_ON(!list_empty(&reaplist));
47790cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
47807919d0a2SJeff Layton 	while (!list_empty(&nn->blocked_locks_lru)) {
47817919d0a2SJeff Layton 		nbl = list_first_entry(&nn->blocked_locks_lru,
47827919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
47837919d0a2SJeff Layton 		if (time_after((unsigned long)nbl->nbl_time,
47847919d0a2SJeff Layton 			       (unsigned long)cutoff)) {
47857919d0a2SJeff Layton 			t = nbl->nbl_time - cutoff;
47867919d0a2SJeff Layton 			new_timeo = min(new_timeo, t);
47877919d0a2SJeff Layton 			break;
47887919d0a2SJeff Layton 		}
47897919d0a2SJeff Layton 		list_move(&nbl->nbl_lru, &reaplist);
47907919d0a2SJeff Layton 		list_del_init(&nbl->nbl_list);
47917919d0a2SJeff Layton 	}
47920cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
47937919d0a2SJeff Layton 
47947919d0a2SJeff Layton 	while (!list_empty(&reaplist)) {
479564ebe124SNaofumi Honda 		nbl = list_first_entry(&reaplist,
47967919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
47977919d0a2SJeff Layton 		list_del_init(&nbl->nbl_lru);
47987919d0a2SJeff Layton 		posix_unblock_lock(&nbl->nbl_lock);
47997919d0a2SJeff Layton 		free_blocked_lock(nbl);
48007919d0a2SJeff Layton 	}
48017919d0a2SJeff Layton 
4802a832e7aeSJeff Layton 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
4803a832e7aeSJeff Layton 	return new_timeo;
48041da177e4SLinus Torvalds }
48051da177e4SLinus Torvalds 
4806a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq;
4807a254b246SHarvey Harrison static void laundromat_main(struct work_struct *);
4808a254b246SHarvey Harrison 
4809a254b246SHarvey Harrison static void
481009121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry)
48111da177e4SLinus Torvalds {
48121da177e4SLinus Torvalds 	time_t t;
48132e55f3abSGeliang Tang 	struct delayed_work *dwork = to_delayed_work(laundry);
481409121281SStanislav Kinsbursky 	struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
481509121281SStanislav Kinsbursky 					   laundromat_work);
48161da177e4SLinus Torvalds 
481709121281SStanislav Kinsbursky 	t = nfs4_laundromat(nn);
48181da177e4SLinus Torvalds 	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
481909121281SStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
48201da177e4SLinus Torvalds }
48211da177e4SLinus Torvalds 
48228fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
4823f8816512SNeilBrown {
48248fcd461dSJeff Layton 	if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
4825f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
4826f7a4d872SJ. Bruce Fields 	return nfs_ok;
48271da177e4SLinus Torvalds }
48281da177e4SLinus Torvalds 
48291da177e4SLinus Torvalds static inline int
483082c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp)
48311da177e4SLinus Torvalds {
483282c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_READ, stp) ||
483382c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp) ||
483482c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_WRITE, stp);
48351da177e4SLinus Torvalds }
48361da177e4SLinus Torvalds 
48371da177e4SLinus Torvalds static inline int
483882c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp)
48391da177e4SLinus Torvalds {
484082c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_WRITE, stp) ||
484182c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp);
48421da177e4SLinus Torvalds }
48431da177e4SLinus Torvalds 
48441da177e4SLinus Torvalds static
4845dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
48461da177e4SLinus Torvalds {
4847b37ad28bSAl Viro         __be32 status = nfserr_openmode;
48481da177e4SLinus Torvalds 
484902921914SJ. Bruce Fields 	/* For lock stateid's, we test the parent open, not the lock: */
485002921914SJ. Bruce Fields 	if (stp->st_openstp)
485102921914SJ. Bruce Fields 		stp = stp->st_openstp;
485282c5ff1bSJeff Layton 	if ((flags & WR_STATE) && !access_permit_write(stp))
48531da177e4SLinus Torvalds                 goto out;
485482c5ff1bSJeff Layton 	if ((flags & RD_STATE) && !access_permit_read(stp))
48551da177e4SLinus Torvalds                 goto out;
48561da177e4SLinus Torvalds 	status = nfs_ok;
48571da177e4SLinus Torvalds out:
48581da177e4SLinus Torvalds 	return status;
48591da177e4SLinus Torvalds }
48601da177e4SLinus Torvalds 
4861b37ad28bSAl Viro static inline __be32
48625ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags)
48631da177e4SLinus Torvalds {
4864203a8c8eSJ. Bruce Fields 	if (ONE_STATEID(stateid) && (flags & RD_STATE))
48651da177e4SLinus Torvalds 		return nfs_ok;
4866c87fb4a3SJ. Bruce Fields 	else if (opens_in_grace(net)) {
486725985edcSLucas De Marchi 		/* Answer in remaining cases depends on existence of
48681da177e4SLinus Torvalds 		 * conflicting state; so we must wait out the grace period. */
48691da177e4SLinus Torvalds 		return nfserr_grace;
48701da177e4SLinus Torvalds 	} else if (flags & WR_STATE)
48711da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
48721da177e4SLinus Torvalds 				NFS4_SHARE_DENY_WRITE);
48731da177e4SLinus Torvalds 	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
48741da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
48751da177e4SLinus Torvalds 				NFS4_SHARE_DENY_READ);
48761da177e4SLinus Torvalds }
48771da177e4SLinus Torvalds 
48781da177e4SLinus Torvalds /*
48791da177e4SLinus Torvalds  * Allow READ/WRITE during grace period on recovered state only for files
48801da177e4SLinus Torvalds  * that are not able to provide mandatory locking.
48811da177e4SLinus Torvalds  */
48821da177e4SLinus Torvalds static inline int
48835ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode)
48841da177e4SLinus Torvalds {
4885c87fb4a3SJ. Bruce Fields 	return opens_in_grace(net) && mandatory_lock(inode);
48861da177e4SLinus Torvalds }
48871da177e4SLinus Torvalds 
488857b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
48890836f587SJ. Bruce Fields {
48906668958fSAndy Adamson 	/*
48916668958fSAndy Adamson 	 * When sessions are used the stateid generation number is ignored
48926668958fSAndy Adamson 	 * when it is zero.
48936668958fSAndy Adamson 	 */
489428dde241SJ. Bruce Fields 	if (has_session && in->si_generation == 0)
489581b82965SJ. Bruce Fields 		return nfs_ok;
489681b82965SJ. Bruce Fields 
489781b82965SJ. Bruce Fields 	if (in->si_generation == ref->si_generation)
489881b82965SJ. Bruce Fields 		return nfs_ok;
48996668958fSAndy Adamson 
49000836f587SJ. Bruce Fields 	/* If the client sends us a stateid from the future, it's buggy: */
490114b7f4a1SJeff Layton 	if (nfsd4_stateid_generation_after(in, ref))
49020836f587SJ. Bruce Fields 		return nfserr_bad_stateid;
49030836f587SJ. Bruce Fields 	/*
490481b82965SJ. Bruce Fields 	 * However, we could see a stateid from the past, even from a
490581b82965SJ. Bruce Fields 	 * non-buggy client.  For example, if the client sends a lock
490681b82965SJ. Bruce Fields 	 * while some IO is outstanding, the lock may bump si_generation
490781b82965SJ. Bruce Fields 	 * while the IO is still in flight.  The client could avoid that
490881b82965SJ. Bruce Fields 	 * situation by waiting for responses on all the IO requests,
490981b82965SJ. Bruce Fields 	 * but better performance may result in retrying IO that
491081b82965SJ. Bruce Fields 	 * receives an old_stateid error if requests are rarely
491181b82965SJ. Bruce Fields 	 * reordered in flight:
49120836f587SJ. Bruce Fields 	 */
49130836f587SJ. Bruce Fields 	return nfserr_old_stateid;
49140836f587SJ. Bruce Fields }
49150836f587SJ. Bruce Fields 
491603da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session)
491703da3169STrond Myklebust {
491803da3169STrond Myklebust 	__be32 ret;
491903da3169STrond Myklebust 
492003da3169STrond Myklebust 	spin_lock(&s->sc_lock);
492103da3169STrond Myklebust 	ret = nfsd4_verify_open_stid(s);
492203da3169STrond Myklebust 	if (ret == nfs_ok)
492303da3169STrond Myklebust 		ret = check_stateid_generation(in, &s->sc_stateid, has_session);
492403da3169STrond Myklebust 	spin_unlock(&s->sc_lock);
492503da3169STrond Myklebust 	return ret;
492603da3169STrond Myklebust }
492703da3169STrond Myklebust 
4928ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols)
4929ebe9cb3bSChristoph Hellwig {
4930ebe9cb3bSChristoph Hellwig 	if (ols->st_stateowner->so_is_open_owner &&
4931ebe9cb3bSChristoph Hellwig 	    !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
4932ebe9cb3bSChristoph Hellwig 		return nfserr_bad_stateid;
4933ebe9cb3bSChristoph Hellwig 	return nfs_ok;
4934ebe9cb3bSChristoph Hellwig }
4935ebe9cb3bSChristoph Hellwig 
49367df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
493717456804SBryan Schumaker {
493897b7e3b6SJ. Bruce Fields 	struct nfs4_stid *s;
49391af71cc8SJeff Layton 	__be32 status = nfserr_bad_stateid;
494017456804SBryan Schumaker 
4941ae254dacSAndrew Elble 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
4942ae254dacSAndrew Elble 		CLOSE_STATEID(stateid))
49431af71cc8SJeff Layton 		return status;
49447df302f7SChuck Lever 	/* Client debugging aid. */
49457df302f7SChuck Lever 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
49467df302f7SChuck Lever 		char addr_str[INET6_ADDRSTRLEN];
49477df302f7SChuck Lever 		rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
49487df302f7SChuck Lever 				 sizeof(addr_str));
49497df302f7SChuck Lever 		pr_warn_ratelimited("NFSD: client %s testing state ID "
49507df302f7SChuck Lever 					"with incorrect client ID\n", addr_str);
49511af71cc8SJeff Layton 		return status;
49527df302f7SChuck Lever 	}
49531af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
49541af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
495597b7e3b6SJ. Bruce Fields 	if (!s)
49561af71cc8SJeff Layton 		goto out_unlock;
495703da3169STrond Myklebust 	status = nfsd4_stid_check_stateid_generation(stateid, s, 1);
495817456804SBryan Schumaker 	if (status)
49591af71cc8SJeff Layton 		goto out_unlock;
496023340032SJ. Bruce Fields 	switch (s->sc_type) {
496123340032SJ. Bruce Fields 	case NFS4_DELEG_STID:
49621af71cc8SJeff Layton 		status = nfs_ok;
49631af71cc8SJeff Layton 		break;
49643bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
49651af71cc8SJeff Layton 		status = nfserr_deleg_revoked;
49661af71cc8SJeff Layton 		break;
496723340032SJ. Bruce Fields 	case NFS4_OPEN_STID:
496823340032SJ. Bruce Fields 	case NFS4_LOCK_STID:
4969ebe9cb3bSChristoph Hellwig 		status = nfsd4_check_openowner_confirmed(openlockstateid(s));
49701af71cc8SJeff Layton 		break;
497123340032SJ. Bruce Fields 	default:
497223340032SJ. Bruce Fields 		printk("unknown stateid type %x\n", s->sc_type);
4973b0fc29d6STrond Myklebust 		/* Fallthrough */
497423340032SJ. Bruce Fields 	case NFS4_CLOSED_STID:
4975b0fc29d6STrond Myklebust 	case NFS4_CLOSED_DELEG_STID:
49761af71cc8SJeff Layton 		status = nfserr_bad_stateid;
497723340032SJ. Bruce Fields 	}
49781af71cc8SJeff Layton out_unlock:
49791af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
49801af71cc8SJeff Layton 	return status;
498117456804SBryan Schumaker }
498217456804SBryan Schumaker 
4983cd61c522SChristoph Hellwig __be32
49842dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
49852dd6e458STrond Myklebust 		     stateid_t *stateid, unsigned char typemask,
49862dd6e458STrond Myklebust 		     struct nfs4_stid **s, struct nfsd_net *nn)
498738c2f4b1SJ. Bruce Fields {
49880eb6f20aSJ. Bruce Fields 	__be32 status;
498995da1b3aSAndrew Elble 	bool return_revoked = false;
499095da1b3aSAndrew Elble 
499195da1b3aSAndrew Elble 	/*
499295da1b3aSAndrew Elble 	 *  only return revoked delegations if explicitly asked.
499395da1b3aSAndrew Elble 	 *  otherwise we report revoked or bad_stateid status.
499495da1b3aSAndrew Elble 	 */
499595da1b3aSAndrew Elble 	if (typemask & NFS4_REVOKED_DELEG_STID)
499695da1b3aSAndrew Elble 		return_revoked = true;
499795da1b3aSAndrew Elble 	else if (typemask & NFS4_DELEG_STID)
499895da1b3aSAndrew Elble 		typemask |= NFS4_REVOKED_DELEG_STID;
499938c2f4b1SJ. Bruce Fields 
5000ae254dacSAndrew Elble 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
5001ae254dacSAndrew Elble 		CLOSE_STATEID(stateid))
500238c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
50034b24ca7dSJeff Layton 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
5004a8a7c677STrond Myklebust 	if (status == nfserr_stale_clientid) {
50054b24ca7dSJeff Layton 		if (cstate->session)
5006a8a7c677STrond Myklebust 			return nfserr_bad_stateid;
500738c2f4b1SJ. Bruce Fields 		return nfserr_stale_stateid;
5008a8a7c677STrond Myklebust 	}
50090eb6f20aSJ. Bruce Fields 	if (status)
50100eb6f20aSJ. Bruce Fields 		return status;
50114b24ca7dSJeff Layton 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
501238c2f4b1SJ. Bruce Fields 	if (!*s)
501338c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
501495da1b3aSAndrew Elble 	if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) {
501595da1b3aSAndrew Elble 		nfs4_put_stid(*s);
501695da1b3aSAndrew Elble 		if (cstate->minorversion)
501795da1b3aSAndrew Elble 			return nfserr_deleg_revoked;
501895da1b3aSAndrew Elble 		return nfserr_bad_stateid;
501995da1b3aSAndrew Elble 	}
502038c2f4b1SJ. Bruce Fields 	return nfs_ok;
502138c2f4b1SJ. Bruce Fields }
502238c2f4b1SJ. Bruce Fields 
5023a0649b2dSChristoph Hellwig static struct file *
5024a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags)
5025a0649b2dSChristoph Hellwig {
5026af90f707SChristoph Hellwig 	if (!s)
5027af90f707SChristoph Hellwig 		return NULL;
5028af90f707SChristoph Hellwig 
5029a0649b2dSChristoph Hellwig 	switch (s->sc_type) {
5030a0649b2dSChristoph Hellwig 	case NFS4_DELEG_STID:
5031a0649b2dSChristoph Hellwig 		if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file))
5032a0649b2dSChristoph Hellwig 			return NULL;
5033a0649b2dSChristoph Hellwig 		return get_file(s->sc_file->fi_deleg_file);
5034a0649b2dSChristoph Hellwig 	case NFS4_OPEN_STID:
5035a0649b2dSChristoph Hellwig 	case NFS4_LOCK_STID:
5036a0649b2dSChristoph Hellwig 		if (flags & RD_STATE)
5037a0649b2dSChristoph Hellwig 			return find_readable_file(s->sc_file);
5038a0649b2dSChristoph Hellwig 		else
5039a0649b2dSChristoph Hellwig 			return find_writeable_file(s->sc_file);
5040a0649b2dSChristoph Hellwig 		break;
5041a0649b2dSChristoph Hellwig 	}
5042a0649b2dSChristoph Hellwig 
5043a0649b2dSChristoph Hellwig 	return NULL;
5044a0649b2dSChristoph Hellwig }
5045a0649b2dSChristoph Hellwig 
5046a0649b2dSChristoph Hellwig static __be32
5047a0649b2dSChristoph Hellwig nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags)
5048a0649b2dSChristoph Hellwig {
5049a0649b2dSChristoph Hellwig 	__be32 status;
5050a0649b2dSChristoph Hellwig 
5051a0649b2dSChristoph Hellwig 	status = nfsd4_check_openowner_confirmed(ols);
5052a0649b2dSChristoph Hellwig 	if (status)
5053a0649b2dSChristoph Hellwig 		return status;
5054a0649b2dSChristoph Hellwig 	return nfs4_check_openmode(ols, flags);
5055a0649b2dSChristoph Hellwig }
5056a0649b2dSChristoph Hellwig 
5057af90f707SChristoph Hellwig static __be32
5058af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s,
5059af90f707SChristoph Hellwig 		struct file **filpp, bool *tmp_file, int flags)
5060af90f707SChristoph Hellwig {
5061af90f707SChristoph Hellwig 	int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE;
5062af90f707SChristoph Hellwig 	struct file *file;
5063af90f707SChristoph Hellwig 	__be32 status;
5064af90f707SChristoph Hellwig 
5065af90f707SChristoph Hellwig 	file = nfs4_find_file(s, flags);
5066af90f707SChristoph Hellwig 	if (file) {
5067af90f707SChristoph Hellwig 		status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
5068af90f707SChristoph Hellwig 				acc | NFSD_MAY_OWNER_OVERRIDE);
5069af90f707SChristoph Hellwig 		if (status) {
5070af90f707SChristoph Hellwig 			fput(file);
5071af90f707SChristoph Hellwig 			return status;
5072af90f707SChristoph Hellwig 		}
5073af90f707SChristoph Hellwig 
5074af90f707SChristoph Hellwig 		*filpp = file;
5075af90f707SChristoph Hellwig 	} else {
5076af90f707SChristoph Hellwig 		status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp);
5077af90f707SChristoph Hellwig 		if (status)
5078af90f707SChristoph Hellwig 			return status;
5079af90f707SChristoph Hellwig 
5080af90f707SChristoph Hellwig 		if (tmp_file)
5081af90f707SChristoph Hellwig 			*tmp_file = true;
5082af90f707SChristoph Hellwig 	}
5083af90f707SChristoph Hellwig 
5084af90f707SChristoph Hellwig 	return 0;
5085af90f707SChristoph Hellwig }
5086af90f707SChristoph Hellwig 
50871da177e4SLinus Torvalds /*
50881da177e4SLinus Torvalds  * Checks for stateid operations
50891da177e4SLinus Torvalds  */
5090b37ad28bSAl Viro __be32
5091af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
5092aa0d6aedSAnna Schumaker 		struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
5093aa0d6aedSAnna Schumaker 		stateid_t *stateid, int flags, struct file **filpp, bool *tmp_file)
50941da177e4SLinus Torvalds {
5095a0649b2dSChristoph Hellwig 	struct inode *ino = d_inode(fhp->fh_dentry);
5096af90f707SChristoph Hellwig 	struct net *net = SVC_NET(rqstp);
50973320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
5098af90f707SChristoph Hellwig 	struct nfs4_stid *s = NULL;
5099b37ad28bSAl Viro 	__be32 status;
51001da177e4SLinus Torvalds 
51011da177e4SLinus Torvalds 	if (filpp)
51021da177e4SLinus Torvalds 		*filpp = NULL;
5103af90f707SChristoph Hellwig 	if (tmp_file)
5104af90f707SChristoph Hellwig 		*tmp_file = false;
51051da177e4SLinus Torvalds 
51065ccb0066SStanislav Kinsbursky 	if (grace_disallows_io(net, ino))
51071da177e4SLinus Torvalds 		return nfserr_grace;
51081da177e4SLinus Torvalds 
5109af90f707SChristoph Hellwig 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
5110af90f707SChristoph Hellwig 		status = check_special_stateids(net, fhp, stateid, flags);
5111af90f707SChristoph Hellwig 		goto done;
5112af90f707SChristoph Hellwig 	}
51131da177e4SLinus Torvalds 
51142dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid,
5115db24b3b4SJeff Layton 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
51162dd6e458STrond Myklebust 				&s, nn);
511738c2f4b1SJ. Bruce Fields 	if (status)
5118c2d1d6a8STrond Myklebust 		return status;
511903da3169STrond Myklebust 	status = nfsd4_stid_check_stateid_generation(stateid, s,
5120a0649b2dSChristoph Hellwig 			nfsd4_has_session(cstate));
51210c2a498fSJ. Bruce Fields 	if (status)
51220c2a498fSJ. Bruce Fields 		goto out;
5123a0649b2dSChristoph Hellwig 
5124f7a4d872SJ. Bruce Fields 	switch (s->sc_type) {
5125f7a4d872SJ. Bruce Fields 	case NFS4_DELEG_STID:
5126a0649b2dSChristoph Hellwig 		status = nfs4_check_delegmode(delegstateid(s), flags);
5127f7a4d872SJ. Bruce Fields 		break;
5128f7a4d872SJ. Bruce Fields 	case NFS4_OPEN_STID:
5129f7a4d872SJ. Bruce Fields 	case NFS4_LOCK_STID:
5130a0649b2dSChristoph Hellwig 		status = nfs4_check_olstateid(fhp, openlockstateid(s), flags);
5131f7a4d872SJ. Bruce Fields 		break;
5132f7a4d872SJ. Bruce Fields 	default:
513314bcab1aSTrond Myklebust 		status = nfserr_bad_stateid;
5134a0649b2dSChristoph Hellwig 		break;
51351da177e4SLinus Torvalds 	}
51368fcd461dSJeff Layton 	if (status)
51378fcd461dSJeff Layton 		goto out;
51388fcd461dSJeff Layton 	status = nfs4_check_fh(fhp, s);
5139a0649b2dSChristoph Hellwig 
5140af90f707SChristoph Hellwig done:
5141af90f707SChristoph Hellwig 	if (!status && filpp)
5142af90f707SChristoph Hellwig 		status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags);
51431da177e4SLinus Torvalds out:
5144af90f707SChristoph Hellwig 	if (s)
5145fd911011STrond Myklebust 		nfs4_put_stid(s);
51461da177e4SLinus Torvalds 	return status;
51471da177e4SLinus Torvalds }
51481da177e4SLinus Torvalds 
5149e1ca12dfSBryan Schumaker /*
515017456804SBryan Schumaker  * Test if the stateid is valid
515117456804SBryan Schumaker  */
515217456804SBryan Schumaker __be32
515317456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5154eb69853dSChristoph Hellwig 		   union nfsd4_op_u *u)
515517456804SBryan Schumaker {
5156eb69853dSChristoph Hellwig 	struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
515703cfb420SBryan Schumaker 	struct nfsd4_test_stateid_id *stateid;
515803cfb420SBryan Schumaker 	struct nfs4_client *cl = cstate->session->se_client;
515903cfb420SBryan Schumaker 
516003cfb420SBryan Schumaker 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
51617df302f7SChuck Lever 		stateid->ts_id_status =
51627df302f7SChuck Lever 			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
516303cfb420SBryan Schumaker 
516417456804SBryan Schumaker 	return nfs_ok;
516517456804SBryan Schumaker }
516617456804SBryan Schumaker 
516742691398SChuck Lever static __be32
516842691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
516942691398SChuck Lever {
517042691398SChuck Lever 	struct nfs4_ol_stateid *stp = openlockstateid(s);
517142691398SChuck Lever 	__be32 ret;
517242691398SChuck Lever 
5173659aefb6STrond Myklebust 	ret = nfsd4_lock_ol_stateid(stp);
5174659aefb6STrond Myklebust 	if (ret)
5175659aefb6STrond Myklebust 		goto out_put_stid;
517642691398SChuck Lever 
517742691398SChuck Lever 	ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
517842691398SChuck Lever 	if (ret)
517942691398SChuck Lever 		goto out;
518042691398SChuck Lever 
518142691398SChuck Lever 	ret = nfserr_locks_held;
518242691398SChuck Lever 	if (check_for_locks(stp->st_stid.sc_file,
518342691398SChuck Lever 			    lockowner(stp->st_stateowner)))
518442691398SChuck Lever 		goto out;
518542691398SChuck Lever 
518642691398SChuck Lever 	release_lock_stateid(stp);
518742691398SChuck Lever 	ret = nfs_ok;
518842691398SChuck Lever 
518942691398SChuck Lever out:
519042691398SChuck Lever 	mutex_unlock(&stp->st_mutex);
5191659aefb6STrond Myklebust out_put_stid:
519242691398SChuck Lever 	nfs4_put_stid(s);
519342691398SChuck Lever 	return ret;
519442691398SChuck Lever }
519542691398SChuck Lever 
5196e1ca12dfSBryan Schumaker __be32
5197e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5198eb69853dSChristoph Hellwig 		   union nfsd4_op_u *u)
5199e1ca12dfSBryan Schumaker {
5200eb69853dSChristoph Hellwig 	struct nfsd4_free_stateid *free_stateid = &u->free_stateid;
5201e1ca12dfSBryan Schumaker 	stateid_t *stateid = &free_stateid->fr_stateid;
52022da1cec7SJ. Bruce Fields 	struct nfs4_stid *s;
52033bd64a5bSJ. Bruce Fields 	struct nfs4_delegation *dp;
520438c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = cstate->session->se_client;
52052da1cec7SJ. Bruce Fields 	__be32 ret = nfserr_bad_stateid;
5206e1ca12dfSBryan Schumaker 
52071af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
52081af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
52092da1cec7SJ. Bruce Fields 	if (!s)
52101af71cc8SJeff Layton 		goto out_unlock;
521103da3169STrond Myklebust 	spin_lock(&s->sc_lock);
52122da1cec7SJ. Bruce Fields 	switch (s->sc_type) {
52132da1cec7SJ. Bruce Fields 	case NFS4_DELEG_STID:
5214e1ca12dfSBryan Schumaker 		ret = nfserr_locks_held;
52151af71cc8SJeff Layton 		break;
52162da1cec7SJ. Bruce Fields 	case NFS4_OPEN_STID:
52171af71cc8SJeff Layton 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
52181af71cc8SJeff Layton 		if (ret)
52191af71cc8SJeff Layton 			break;
52201af71cc8SJeff Layton 		ret = nfserr_locks_held;
52211af71cc8SJeff Layton 		break;
52222da1cec7SJ. Bruce Fields 	case NFS4_LOCK_STID:
522303da3169STrond Myklebust 		spin_unlock(&s->sc_lock);
5224a15dfcd5SElena Reshetova 		refcount_inc(&s->sc_count);
52251af71cc8SJeff Layton 		spin_unlock(&cl->cl_lock);
522642691398SChuck Lever 		ret = nfsd4_free_lock_stateid(stateid, s);
52271af71cc8SJeff Layton 		goto out;
52283bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
522903da3169STrond Myklebust 		spin_unlock(&s->sc_lock);
52303bd64a5bSJ. Bruce Fields 		dp = delegstateid(s);
52312d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
52322d4a532dSJeff Layton 		spin_unlock(&cl->cl_lock);
52336011695dSTrond Myklebust 		nfs4_put_stid(s);
52343bd64a5bSJ. Bruce Fields 		ret = nfs_ok;
52351af71cc8SJeff Layton 		goto out;
52361af71cc8SJeff Layton 	/* Default falls through and returns nfserr_bad_stateid */
5237e1ca12dfSBryan Schumaker 	}
523803da3169STrond Myklebust 	spin_unlock(&s->sc_lock);
52391af71cc8SJeff Layton out_unlock:
52401af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
5241e1ca12dfSBryan Schumaker out:
5242e1ca12dfSBryan Schumaker 	return ret;
5243e1ca12dfSBryan Schumaker }
5244e1ca12dfSBryan Schumaker 
52454c4cd222SNeilBrown static inline int
52464c4cd222SNeilBrown setlkflg (int type)
52474c4cd222SNeilBrown {
52484c4cd222SNeilBrown 	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
52494c4cd222SNeilBrown 		RD_STATE : WR_STATE;
52504c4cd222SNeilBrown }
52511da177e4SLinus Torvalds 
5252dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
5253c0a5d93eSJ. Bruce Fields {
5254c0a5d93eSJ. Bruce Fields 	struct svc_fh *current_fh = &cstate->current_fh;
5255c0a5d93eSJ. Bruce Fields 	struct nfs4_stateowner *sop = stp->st_stateowner;
5256c0a5d93eSJ. Bruce Fields 	__be32 status;
5257c0a5d93eSJ. Bruce Fields 
5258c0a5d93eSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, sop, seqid);
5259c0a5d93eSJ. Bruce Fields 	if (status)
5260c0a5d93eSJ. Bruce Fields 		return status;
52619271d7e5STrond Myklebust 	status = nfsd4_lock_ol_stateid(stp);
52629271d7e5STrond Myklebust 	if (status != nfs_ok)
52639271d7e5STrond Myklebust 		return status;
5264f7a4d872SJ. Bruce Fields 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
526535a92fe8SJeff Layton 	if (status == nfs_ok)
526635a92fe8SJeff Layton 		status = nfs4_check_fh(current_fh, &stp->st_stid);
526735a92fe8SJeff Layton 	if (status != nfs_ok)
5268feb9dad5SOleg Drokin 		mutex_unlock(&stp->st_mutex);
5269f7a4d872SJ. Bruce Fields 	return status;
5270c0a5d93eSJ. Bruce Fields }
5271c0a5d93eSJ. Bruce Fields 
52721da177e4SLinus Torvalds /*
52731da177e4SLinus Torvalds  * Checks for sequence id mutating operations.
52741da177e4SLinus Torvalds  */
5275b37ad28bSAl Viro static __be32
5276dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
52772288d0e3SJ. Bruce Fields 			 stateid_t *stateid, char typemask,
52783320fef1SStanislav Kinsbursky 			 struct nfs4_ol_stateid **stpp,
52793320fef1SStanislav Kinsbursky 			 struct nfsd_net *nn)
52801da177e4SLinus Torvalds {
52810836f587SJ. Bruce Fields 	__be32 status;
528238c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
5283e17f99b7STrond Myklebust 	struct nfs4_ol_stateid *stp = NULL;
52841da177e4SLinus Torvalds 
52858c10cbdbSBenny Halevy 	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
52868c10cbdbSBenny Halevy 		seqid, STATEID_VAL(stateid));
52871da177e4SLinus Torvalds 
52881da177e4SLinus Torvalds 	*stpp = NULL;
52892dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn);
5290c0a5d93eSJ. Bruce Fields 	if (status)
5291c0a5d93eSJ. Bruce Fields 		return status;
5292e17f99b7STrond Myklebust 	stp = openlockstateid(s);
529358fb12e6SJeff Layton 	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
52941da177e4SLinus Torvalds 
5295e17f99b7STrond Myklebust 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
5296fd911011STrond Myklebust 	if (!status)
5297e17f99b7STrond Myklebust 		*stpp = stp;
5298fd911011STrond Myklebust 	else
5299fd911011STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
5300e17f99b7STrond Myklebust 	return status;
53011da177e4SLinus Torvalds }
53021da177e4SLinus Torvalds 
53033320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
53043320fef1SStanislav Kinsbursky 						 stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn)
5305c0a5d93eSJ. Bruce Fields {
5306c0a5d93eSJ. Bruce Fields 	__be32 status;
5307c0a5d93eSJ. Bruce Fields 	struct nfs4_openowner *oo;
53084cbfc9f7STrond Myklebust 	struct nfs4_ol_stateid *stp;
53091da177e4SLinus Torvalds 
5310c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
53114cbfc9f7STrond Myklebust 						NFS4_OPEN_STID, &stp, nn);
53120836f587SJ. Bruce Fields 	if (status)
53130836f587SJ. Bruce Fields 		return status;
53144cbfc9f7STrond Myklebust 	oo = openowner(stp->st_stateowner);
53154cbfc9f7STrond Myklebust 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
5316feb9dad5SOleg Drokin 		mutex_unlock(&stp->st_mutex);
53174cbfc9f7STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
5318c0a5d93eSJ. Bruce Fields 		return nfserr_bad_stateid;
53194cbfc9f7STrond Myklebust 	}
53204cbfc9f7STrond Myklebust 	*stpp = stp;
53213a4f98bbSNeilBrown 	return nfs_ok;
53221da177e4SLinus Torvalds }
53231da177e4SLinus Torvalds 
5324b37ad28bSAl Viro __be32
5325ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5326eb69853dSChristoph Hellwig 		   union nfsd4_op_u *u)
53271da177e4SLinus Torvalds {
5328eb69853dSChristoph Hellwig 	struct nfsd4_open_confirm *oc = &u->open_confirm;
5329b37ad28bSAl Viro 	__be32 status;
5330fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
5331dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
53323320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
53331da177e4SLinus Torvalds 
5334a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_confirm on file %pd\n",
5335a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
53361da177e4SLinus Torvalds 
5337ca364317SJ.Bruce Fields 	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
5338a8cddc5dSJ. Bruce Fields 	if (status)
5339a8cddc5dSJ. Bruce Fields 		return status;
53401da177e4SLinus Torvalds 
53419072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate,
5342ca364317SJ.Bruce Fields 					oc->oc_seqid, &oc->oc_req_stateid,
53433320fef1SStanislav Kinsbursky 					NFS4_OPEN_STID, &stp, nn);
53449072d5c6SJ. Bruce Fields 	if (status)
53451da177e4SLinus Torvalds 		goto out;
5346fe0750e5SJ. Bruce Fields 	oo = openowner(stp->st_stateowner);
534768b66e82SJ. Bruce Fields 	status = nfserr_bad_stateid;
534835a92fe8SJeff Layton 	if (oo->oo_flags & NFS4_OO_CONFIRMED) {
5349feb9dad5SOleg Drokin 		mutex_unlock(&stp->st_mutex);
53502585fc79STrond Myklebust 		goto put_stateid;
535135a92fe8SJeff Layton 	}
5352dad1c067SJ. Bruce Fields 	oo->oo_flags |= NFS4_OO_CONFIRMED;
53539767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid);
5354feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
53558c10cbdbSBenny Halevy 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
5356dcef0413SJ. Bruce Fields 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
5357c7b9a459SNeilBrown 
53582a4317c5SJeff Layton 	nfsd4_client_record_create(oo->oo_owner.so_client);
535968b66e82SJ. Bruce Fields 	status = nfs_ok;
53602585fc79STrond Myklebust put_stateid:
53612585fc79STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
53621da177e4SLinus Torvalds out:
53639411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
53641da177e4SLinus Torvalds 	return status;
53651da177e4SLinus Torvalds }
53661da177e4SLinus Torvalds 
53676409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
53681da177e4SLinus Torvalds {
536982c5ff1bSJeff Layton 	if (!test_access(access, stp))
53706409a5a6SJ. Bruce Fields 		return;
537111b9164aSTrond Myklebust 	nfs4_file_put_access(stp->st_stid.sc_file, access);
537282c5ff1bSJeff Layton 	clear_access(access, stp);
5373f197c271SJ. Bruce Fields }
53746409a5a6SJ. Bruce Fields 
53756409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
53766409a5a6SJ. Bruce Fields {
53776409a5a6SJ. Bruce Fields 	switch (to_access) {
53786409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
53796409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
53806409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
53816409a5a6SJ. Bruce Fields 		break;
53826409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
53836409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
53846409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
53856409a5a6SJ. Bruce Fields 		break;
53866409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
53876409a5a6SJ. Bruce Fields 		break;
53886409a5a6SJ. Bruce Fields 	default:
5389063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
53901da177e4SLinus Torvalds 	}
53911da177e4SLinus Torvalds }
53921da177e4SLinus Torvalds 
5393b37ad28bSAl Viro __be32
5394ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp,
5395eb69853dSChristoph Hellwig 		     struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
53961da177e4SLinus Torvalds {
5397eb69853dSChristoph Hellwig 	struct nfsd4_open_downgrade *od = &u->open_downgrade;
5398b37ad28bSAl Viro 	__be32 status;
5399dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
54003320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
54011da177e4SLinus Torvalds 
5402a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_downgrade on file %pd\n",
5403a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
54041da177e4SLinus Torvalds 
5405c30e92dfSJ. Bruce Fields 	/* We don't yet support WANT bits: */
54062c8bd7e0SBenny Halevy 	if (od->od_deleg_want)
54072c8bd7e0SBenny Halevy 		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
54082c8bd7e0SBenny Halevy 			od->od_deleg_want);
54091da177e4SLinus Torvalds 
5410c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
54113320fef1SStanislav Kinsbursky 					&od->od_stateid, &stp, nn);
54129072d5c6SJ. Bruce Fields 	if (status)
54131da177e4SLinus Torvalds 		goto out;
54141da177e4SLinus Torvalds 	status = nfserr_inval;
541582c5ff1bSJeff Layton 	if (!test_access(od->od_share_access, stp)) {
5416c11c591fSJeff Layton 		dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n",
54171da177e4SLinus Torvalds 			stp->st_access_bmap, od->od_share_access);
54180667b1e9STrond Myklebust 		goto put_stateid;
54191da177e4SLinus Torvalds 	}
5420ce0fc43cSJeff Layton 	if (!test_deny(od->od_share_deny, stp)) {
5421c11c591fSJeff Layton 		dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n",
54221da177e4SLinus Torvalds 			stp->st_deny_bmap, od->od_share_deny);
54230667b1e9STrond Myklebust 		goto put_stateid;
54241da177e4SLinus Torvalds 	}
54256409a5a6SJ. Bruce Fields 	nfs4_stateid_downgrade(stp, od->od_share_access);
5426ce0fc43cSJeff Layton 	reset_union_bmap_deny(od->od_share_deny, stp);
54279767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid);
54281da177e4SLinus Torvalds 	status = nfs_ok;
54290667b1e9STrond Myklebust put_stateid:
5430feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
54310667b1e9STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
54321da177e4SLinus Torvalds out:
54339411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
54341da177e4SLinus Torvalds 	return status;
54351da177e4SLinus Torvalds }
54361da177e4SLinus Torvalds 
5437f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
5438f7a4d872SJ. Bruce Fields {
5439acf9295bSTrond Myklebust 	struct nfs4_client *clp = s->st_stid.sc_client;
5440e8568739SJeff Layton 	bool unhashed;
5441d83017f9SJeff Layton 	LIST_HEAD(reaplist);
5442acf9295bSTrond Myklebust 
54432c41beb0SJeff Layton 	spin_lock(&clp->cl_lock);
5444e8568739SJeff Layton 	unhashed = unhash_open_stateid(s, &reaplist);
5445acf9295bSTrond Myklebust 
5446d83017f9SJeff Layton 	if (clp->cl_minorversion) {
5447e8568739SJeff Layton 		if (unhashed)
5448d83017f9SJeff Layton 			put_ol_stateid_locked(s, &reaplist);
5449d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
5450d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
5451d83017f9SJeff Layton 	} else {
5452d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
5453d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
5454e8568739SJeff Layton 		if (unhashed)
5455d3134b10SJeff Layton 			move_to_close_lru(s, clp->net);
545638c387b5SJ. Bruce Fields 	}
5457d83017f9SJeff Layton }
545838c387b5SJ. Bruce Fields 
54591da177e4SLinus Torvalds /*
54601da177e4SLinus Torvalds  * nfs4_unlock_state() called after encode
54611da177e4SLinus Torvalds  */
5462b37ad28bSAl Viro __be32
5463ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5464eb69853dSChristoph Hellwig 		union nfsd4_op_u *u)
54651da177e4SLinus Torvalds {
5466eb69853dSChristoph Hellwig 	struct nfsd4_close *close = &u->close;
5467b37ad28bSAl Viro 	__be32 status;
5468dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
54693320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
54703320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
54711da177e4SLinus Torvalds 
5472a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_close on file %pd\n",
5473a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
54741da177e4SLinus Torvalds 
5475f7a4d872SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
5476f7a4d872SJ. Bruce Fields 					&close->cl_stateid,
5477f7a4d872SJ. Bruce Fields 					NFS4_OPEN_STID|NFS4_CLOSED_STID,
54783320fef1SStanislav Kinsbursky 					&stp, nn);
54799411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
54809072d5c6SJ. Bruce Fields 	if (status)
54811da177e4SLinus Torvalds 		goto out;
548215ca08d3STrond Myklebust 
548315ca08d3STrond Myklebust 	stp->st_stid.sc_type = NFS4_CLOSED_STID;
54849767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
54851da177e4SLinus Torvalds 
5486f7a4d872SJ. Bruce Fields 	nfsd4_close_open_stateid(stp);
548715ca08d3STrond Myklebust 	mutex_unlock(&stp->st_mutex);
54888a0b589dSTrond Myklebust 
5489fb500a7cSTrond Myklebust 	/* See RFC5661 sectionm 18.2.4 */
5490fb500a7cSTrond Myklebust 	if (stp->st_stid.sc_client->cl_minorversion)
5491fb500a7cSTrond Myklebust 		memcpy(&close->cl_stateid, &close_stateid,
5492fb500a7cSTrond Myklebust 				sizeof(close->cl_stateid));
5493fb500a7cSTrond Myklebust 
54948a0b589dSTrond Myklebust 	/* put reference from nfs4_preprocess_seqid_op */
54958a0b589dSTrond Myklebust 	nfs4_put_stid(&stp->st_stid);
54961da177e4SLinus Torvalds out:
54971da177e4SLinus Torvalds 	return status;
54981da177e4SLinus Torvalds }
54991da177e4SLinus Torvalds 
5500b37ad28bSAl Viro __be32
5501ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5502eb69853dSChristoph Hellwig 		  union nfsd4_op_u *u)
55031da177e4SLinus Torvalds {
5504eb69853dSChristoph Hellwig 	struct nfsd4_delegreturn *dr = &u->delegreturn;
5505203a8c8eSJ. Bruce Fields 	struct nfs4_delegation *dp;
5506203a8c8eSJ. Bruce Fields 	stateid_t *stateid = &dr->dr_stateid;
550738c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
5508b37ad28bSAl Viro 	__be32 status;
55093320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
55101da177e4SLinus Torvalds 
5511ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
5512203a8c8eSJ. Bruce Fields 		return status;
55131da177e4SLinus Torvalds 
55142dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
551538c2f4b1SJ. Bruce Fields 	if (status)
5516203a8c8eSJ. Bruce Fields 		goto out;
551738c2f4b1SJ. Bruce Fields 	dp = delegstateid(s);
551803da3169STrond Myklebust 	status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate));
5519203a8c8eSJ. Bruce Fields 	if (status)
5520fd911011STrond Myklebust 		goto put_stateid;
5521203a8c8eSJ. Bruce Fields 
55223bd64a5bSJ. Bruce Fields 	destroy_delegation(dp);
5523fd911011STrond Myklebust put_stateid:
5524fd911011STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
55251da177e4SLinus Torvalds out:
55261da177e4SLinus Torvalds 	return status;
55271da177e4SLinus Torvalds }
55281da177e4SLinus Torvalds 
552987df4de8SBenny Halevy static inline u64
553087df4de8SBenny Halevy end_offset(u64 start, u64 len)
553187df4de8SBenny Halevy {
553287df4de8SBenny Halevy 	u64 end;
553387df4de8SBenny Halevy 
553487df4de8SBenny Halevy 	end = start + len;
553587df4de8SBenny Halevy 	return end >= start ? end: NFS4_MAX_UINT64;
553687df4de8SBenny Halevy }
553787df4de8SBenny Halevy 
553887df4de8SBenny Halevy /* last octet in a range */
553987df4de8SBenny Halevy static inline u64
554087df4de8SBenny Halevy last_byte_offset(u64 start, u64 len)
554187df4de8SBenny Halevy {
554287df4de8SBenny Halevy 	u64 end;
554387df4de8SBenny Halevy 
5544063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(!len);
554587df4de8SBenny Halevy 	end = start + len;
554687df4de8SBenny Halevy 	return end > start ? end - 1: NFS4_MAX_UINT64;
554787df4de8SBenny Halevy }
554887df4de8SBenny Halevy 
55491da177e4SLinus Torvalds /*
55501da177e4SLinus Torvalds  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
55511da177e4SLinus Torvalds  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
55521da177e4SLinus Torvalds  * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
55531da177e4SLinus Torvalds  * locking, this prevents us from being completely protocol-compliant.  The
55541da177e4SLinus Torvalds  * real solution to this problem is to start using unsigned file offsets in
55551da177e4SLinus Torvalds  * the VFS, but this is a very deep change!
55561da177e4SLinus Torvalds  */
55571da177e4SLinus Torvalds static inline void
55581da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock)
55591da177e4SLinus Torvalds {
55601da177e4SLinus Torvalds 	if (lock->fl_start < 0)
55611da177e4SLinus Torvalds 		lock->fl_start = OFFSET_MAX;
55621da177e4SLinus Torvalds 	if (lock->fl_end < 0)
55631da177e4SLinus Torvalds 		lock->fl_end = OFFSET_MAX;
55641da177e4SLinus Torvalds }
55651da177e4SLinus Torvalds 
5566cae80b30SJeff Layton static fl_owner_t
5567cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner)
5568aef9583bSKinglong Mee {
5569cae80b30SJeff Layton 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
5570cae80b30SJeff Layton 
5571cae80b30SJeff Layton 	nfs4_get_stateowner(&lo->lo_owner);
5572cae80b30SJeff Layton 	return owner;
5573aef9583bSKinglong Mee }
5574aef9583bSKinglong Mee 
5575cae80b30SJeff Layton static void
5576cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner)
5577aef9583bSKinglong Mee {
5578cae80b30SJeff Layton 	struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
5579aef9583bSKinglong Mee 
5580cae80b30SJeff Layton 	if (lo)
5581aef9583bSKinglong Mee 		nfs4_put_stateowner(&lo->lo_owner);
5582aef9583bSKinglong Mee }
5583aef9583bSKinglong Mee 
558476d348faSJeff Layton static void
558576d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl)
558676d348faSJeff Layton {
558776d348faSJeff Layton 	struct nfs4_lockowner		*lo = (struct nfs4_lockowner *)fl->fl_owner;
558876d348faSJeff Layton 	struct net			*net = lo->lo_owner.so_client->net;
558976d348faSJeff Layton 	struct nfsd_net			*nn = net_generic(net, nfsd_net_id);
559076d348faSJeff Layton 	struct nfsd4_blocked_lock	*nbl = container_of(fl,
559176d348faSJeff Layton 						struct nfsd4_blocked_lock, nbl_lock);
559276d348faSJeff Layton 	bool queue = false;
559376d348faSJeff Layton 
55947919d0a2SJeff Layton 	/* An empty list means that something else is going to be using it */
55950cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
559676d348faSJeff Layton 	if (!list_empty(&nbl->nbl_list)) {
559776d348faSJeff Layton 		list_del_init(&nbl->nbl_list);
55987919d0a2SJeff Layton 		list_del_init(&nbl->nbl_lru);
559976d348faSJeff Layton 		queue = true;
560076d348faSJeff Layton 	}
56010cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
560276d348faSJeff Layton 
560376d348faSJeff Layton 	if (queue)
560476d348faSJeff Layton 		nfsd4_run_cb(&nbl->nbl_cb);
560576d348faSJeff Layton }
560676d348faSJeff Layton 
56077b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops  = {
560876d348faSJeff Layton 	.lm_notify = nfsd4_lm_notify,
5609aef9583bSKinglong Mee 	.lm_get_owner = nfsd4_fl_get_owner,
5610aef9583bSKinglong Mee 	.lm_put_owner = nfsd4_fl_put_owner,
5611d5b9026aSNeilBrown };
56121da177e4SLinus Torvalds 
56131da177e4SLinus Torvalds static inline void
56141da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
56151da177e4SLinus Torvalds {
5616fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
56171da177e4SLinus Torvalds 
5618d5b9026aSNeilBrown 	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
5619fe0750e5SJ. Bruce Fields 		lo = (struct nfs4_lockowner *) fl->fl_owner;
5620fe0750e5SJ. Bruce Fields 		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
5621fe0750e5SJ. Bruce Fields 					lo->lo_owner.so_owner.len, GFP_KERNEL);
56227c13f344SJ. Bruce Fields 		if (!deny->ld_owner.data)
56237c13f344SJ. Bruce Fields 			/* We just don't care that much */
56247c13f344SJ. Bruce Fields 			goto nevermind;
5625fe0750e5SJ. Bruce Fields 		deny->ld_owner.len = lo->lo_owner.so_owner.len;
5626fe0750e5SJ. Bruce Fields 		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
5627d5b9026aSNeilBrown 	} else {
56287c13f344SJ. Bruce Fields nevermind:
56297c13f344SJ. Bruce Fields 		deny->ld_owner.len = 0;
56307c13f344SJ. Bruce Fields 		deny->ld_owner.data = NULL;
5631d5b9026aSNeilBrown 		deny->ld_clientid.cl_boot = 0;
5632d5b9026aSNeilBrown 		deny->ld_clientid.cl_id = 0;
56331da177e4SLinus Torvalds 	}
56341da177e4SLinus Torvalds 	deny->ld_start = fl->fl_start;
563587df4de8SBenny Halevy 	deny->ld_length = NFS4_MAX_UINT64;
563687df4de8SBenny Halevy 	if (fl->fl_end != NFS4_MAX_UINT64)
56371da177e4SLinus Torvalds 		deny->ld_length = fl->fl_end - fl->fl_start + 1;
56381da177e4SLinus Torvalds 	deny->ld_type = NFS4_READ_LT;
56391da177e4SLinus Torvalds 	if (fl->fl_type != F_RDLCK)
56401da177e4SLinus Torvalds 		deny->ld_type = NFS4_WRITE_LT;
56411da177e4SLinus Torvalds }
56421da177e4SLinus Torvalds 
5643fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
5644c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner)
56451da177e4SLinus Torvalds {
5646d4f0489fSTrond Myklebust 	unsigned int strhashval = ownerstr_hashval(owner);
5647b3c32bcdSTrond Myklebust 	struct nfs4_stateowner *so;
56481da177e4SLinus Torvalds 
56490a880a28STrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
56500a880a28STrond Myklebust 
5651d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval],
5652d4f0489fSTrond Myklebust 			    so_strhash) {
5653b3c32bcdSTrond Myklebust 		if (so->so_is_open_owner)
5654b3c32bcdSTrond Myklebust 			continue;
5655b5971afaSKinglong Mee 		if (same_owner_str(so, owner))
5656b5971afaSKinglong Mee 			return lockowner(nfs4_get_stateowner(so));
56571da177e4SLinus Torvalds 	}
56581da177e4SLinus Torvalds 	return NULL;
56591da177e4SLinus Torvalds }
56601da177e4SLinus Torvalds 
5661c58c6610STrond Myklebust static struct nfs4_lockowner *
5662c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner)
5663c58c6610STrond Myklebust {
5664c58c6610STrond Myklebust 	struct nfs4_lockowner *lo;
5665c58c6610STrond Myklebust 
5666d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5667c8623999SKinglong Mee 	lo = find_lockowner_str_locked(clp, owner);
5668d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5669c58c6610STrond Myklebust 	return lo;
5670c58c6610STrond Myklebust }
5671c58c6610STrond Myklebust 
56728f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
56738f4b54c5SJeff Layton {
5674c58c6610STrond Myklebust 	unhash_lockowner_locked(lockowner(sop));
56758f4b54c5SJeff Layton }
56768f4b54c5SJeff Layton 
56776b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
56786b180f0bSJeff Layton {
56796b180f0bSJeff Layton 	struct nfs4_lockowner *lo = lockowner(sop);
56806b180f0bSJeff Layton 
56816b180f0bSJeff Layton 	kmem_cache_free(lockowner_slab, lo);
56826b180f0bSJeff Layton }
56836b180f0bSJeff Layton 
56846b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = {
56858f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_lockowner,
56866b180f0bSJeff Layton 	.so_free =	nfs4_free_lockowner,
56876b180f0bSJeff Layton };
56886b180f0bSJeff Layton 
56891da177e4SLinus Torvalds /*
56901da177e4SLinus Torvalds  * Alloc a lock owner structure.
56911da177e4SLinus Torvalds  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
569225985edcSLucas De Marchi  * occurred.
56931da177e4SLinus Torvalds  *
569416bfdaafSJ. Bruce Fields  * strhashval = ownerstr_hashval
56951da177e4SLinus Torvalds  */
5696fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
5697c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
5698c58c6610STrond Myklebust 			   struct nfs4_ol_stateid *open_stp,
5699c58c6610STrond Myklebust 			   struct nfsd4_lock *lock)
5700c58c6610STrond Myklebust {
5701c58c6610STrond Myklebust 	struct nfs4_lockowner *lo, *ret;
57021da177e4SLinus Torvalds 
5703fe0750e5SJ. Bruce Fields 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
5704fe0750e5SJ. Bruce Fields 	if (!lo)
57051da177e4SLinus Torvalds 		return NULL;
570676d348faSJeff Layton 	INIT_LIST_HEAD(&lo->lo_blocked);
5707fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
5708fe0750e5SJ. Bruce Fields 	lo->lo_owner.so_is_open_owner = 0;
57095db1c03fSJeff Layton 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
57106b180f0bSJeff Layton 	lo->lo_owner.so_ops = &lockowner_ops;
5711d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5712c8623999SKinglong Mee 	ret = find_lockowner_str_locked(clp, &lock->lk_new_owner);
5713c58c6610STrond Myklebust 	if (ret == NULL) {
5714c58c6610STrond Myklebust 		list_add(&lo->lo_owner.so_strhash,
5715d4f0489fSTrond Myklebust 			 &clp->cl_ownerstr_hashtbl[strhashval]);
5716c58c6610STrond Myklebust 		ret = lo;
5717c58c6610STrond Myklebust 	} else
5718d50ffdedSKinglong Mee 		nfs4_free_stateowner(&lo->lo_owner);
5719d50ffdedSKinglong Mee 
5720d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5721340f0ba1SJ. Bruce Fields 	return ret;
57221da177e4SLinus Torvalds }
57231da177e4SLinus Torvalds 
5724fd1fd685STrond Myklebust static struct nfs4_ol_stateid *
5725fd1fd685STrond Myklebust find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
5726fd1fd685STrond Myklebust {
5727fd1fd685STrond Myklebust 	struct nfs4_ol_stateid *lst;
5728fd1fd685STrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
5729fd1fd685STrond Myklebust 
5730fd1fd685STrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
5731fd1fd685STrond Myklebust 
5732fd1fd685STrond Myklebust 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
5733fd1fd685STrond Myklebust 		if (lst->st_stid.sc_type != NFS4_LOCK_STID)
5734fd1fd685STrond Myklebust 			continue;
5735fd1fd685STrond Myklebust 		if (lst->st_stid.sc_file == fp) {
5736fd1fd685STrond Myklebust 			refcount_inc(&lst->st_stid.sc_count);
5737fd1fd685STrond Myklebust 			return lst;
5738fd1fd685STrond Myklebust 		}
5739fd1fd685STrond Myklebust 	}
5740fd1fd685STrond Myklebust 	return NULL;
5741fd1fd685STrond Myklebust }
5742fd1fd685STrond Myklebust 
5743beeca19cSTrond Myklebust static struct nfs4_ol_stateid *
5744356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5745356a95ecSJeff Layton 		  struct nfs4_file *fp, struct inode *inode,
5746f9c00c3aSJeff Layton 		  struct nfs4_ol_stateid *open_stp)
57471da177e4SLinus Torvalds {
5748d3b313a4SJ. Bruce Fields 	struct nfs4_client *clp = lo->lo_owner.so_client;
5749beeca19cSTrond Myklebust 	struct nfs4_ol_stateid *retstp;
57501da177e4SLinus Torvalds 
5751beeca19cSTrond Myklebust 	mutex_init(&stp->st_mutex);
57524f34bd05SAndrew Elble 	mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX);
5753beeca19cSTrond Myklebust retry:
5754beeca19cSTrond Myklebust 	spin_lock(&clp->cl_lock);
5755beeca19cSTrond Myklebust 	spin_lock(&fp->fi_lock);
5756beeca19cSTrond Myklebust 	retstp = find_lock_stateid(lo, fp);
5757beeca19cSTrond Myklebust 	if (retstp)
5758beeca19cSTrond Myklebust 		goto out_unlock;
5759356a95ecSJeff Layton 
5760a15dfcd5SElena Reshetova 	refcount_inc(&stp->st_stid.sc_count);
57613abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_LOCK_STID;
5762b5971afaSKinglong Mee 	stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
576313cd2184SNeilBrown 	get_nfs4_file(fp);
576411b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
57650997b173SJ. Bruce Fields 	stp->st_access_bmap = 0;
57661da177e4SLinus Torvalds 	stp->st_deny_bmap = open_stp->st_deny_bmap;
57674c4cd222SNeilBrown 	stp->st_openstp = open_stp;
57683c87b9b7STrond Myklebust 	list_add(&stp->st_locks, &open_stp->st_locks);
57691c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
57701d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
5771beeca19cSTrond Myklebust out_unlock:
57721d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
5773beeca19cSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5774beeca19cSTrond Myklebust 	if (retstp) {
5775beeca19cSTrond Myklebust 		if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
5776beeca19cSTrond Myklebust 			nfs4_put_stid(&retstp->st_stid);
5777beeca19cSTrond Myklebust 			goto retry;
5778beeca19cSTrond Myklebust 		}
5779beeca19cSTrond Myklebust 		/* To keep mutex tracking happy */
5780beeca19cSTrond Myklebust 		mutex_unlock(&stp->st_mutex);
5781beeca19cSTrond Myklebust 		stp = retstp;
5782beeca19cSTrond Myklebust 	}
5783beeca19cSTrond Myklebust 	return stp;
57841da177e4SLinus Torvalds }
57851da177e4SLinus Torvalds 
5786c53530daSJeff Layton static struct nfs4_ol_stateid *
5787356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
5788356a95ecSJeff Layton 			    struct inode *inode, struct nfs4_ol_stateid *ost,
5789356a95ecSJeff Layton 			    bool *new)
5790356a95ecSJeff Layton {
5791356a95ecSJeff Layton 	struct nfs4_stid *ns = NULL;
5792356a95ecSJeff Layton 	struct nfs4_ol_stateid *lst;
5793356a95ecSJeff Layton 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
5794356a95ecSJeff Layton 	struct nfs4_client *clp = oo->oo_owner.so_client;
5795356a95ecSJeff Layton 
5796beeca19cSTrond Myklebust 	*new = false;
5797356a95ecSJeff Layton 	spin_lock(&clp->cl_lock);
5798356a95ecSJeff Layton 	lst = find_lock_stateid(lo, fi);
5799356a95ecSJeff Layton 	spin_unlock(&clp->cl_lock);
5800beeca19cSTrond Myklebust 	if (lst != NULL) {
5801beeca19cSTrond Myklebust 		if (nfsd4_lock_ol_stateid(lst) == nfs_ok)
5802beeca19cSTrond Myklebust 			goto out;
5803beeca19cSTrond Myklebust 		nfs4_put_stid(&lst->st_stid);
5804beeca19cSTrond Myklebust 	}
5805d19fb70dSKinglong Mee 	ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
5806356a95ecSJeff Layton 	if (ns == NULL)
5807356a95ecSJeff Layton 		return NULL;
5808356a95ecSJeff Layton 
5809beeca19cSTrond Myklebust 	lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost);
5810beeca19cSTrond Myklebust 	if (lst == openlockstateid(ns))
5811356a95ecSJeff Layton 		*new = true;
5812beeca19cSTrond Myklebust 	else
5813356a95ecSJeff Layton 		nfs4_put_stid(ns);
5814beeca19cSTrond Myklebust out:
5815356a95ecSJeff Layton 	return lst;
5816356a95ecSJeff Layton }
5817c53530daSJeff Layton 
5818fd39ca9aSNeilBrown static int
58191da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length)
58201da177e4SLinus Torvalds {
582187df4de8SBenny Halevy 	return ((length == 0) || ((length != NFS4_MAX_UINT64) &&
5822e7969315SKinglong Mee 		(length > ~offset)));
58231da177e4SLinus Torvalds }
58241da177e4SLinus Torvalds 
5825dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
58260997b173SJ. Bruce Fields {
582711b9164aSTrond Myklebust 	struct nfs4_file *fp = lock_stp->st_stid.sc_file;
58280997b173SJ. Bruce Fields 
58297214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
58307214e860SJeff Layton 
583182c5ff1bSJeff Layton 	if (test_access(access, lock_stp))
58320997b173SJ. Bruce Fields 		return;
583312659651SJeff Layton 	__nfs4_file_get_access(fp, access);
583482c5ff1bSJeff Layton 	set_access(access, lock_stp);
58350997b173SJ. Bruce Fields }
58360997b173SJ. Bruce Fields 
5837356a95ecSJeff Layton static __be32
5838356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5839356a95ecSJeff Layton 			    struct nfs4_ol_stateid *ost,
5840356a95ecSJeff Layton 			    struct nfsd4_lock *lock,
5841dd257933SJeff Layton 			    struct nfs4_ol_stateid **plst, bool *new)
584264a284d0SJ. Bruce Fields {
58435db1c03fSJeff Layton 	__be32 status;
584411b9164aSTrond Myklebust 	struct nfs4_file *fi = ost->st_stid.sc_file;
584564a284d0SJ. Bruce Fields 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
584664a284d0SJ. Bruce Fields 	struct nfs4_client *cl = oo->oo_owner.so_client;
58472b0143b5SDavid Howells 	struct inode *inode = d_inode(cstate->current_fh.fh_dentry);
584864a284d0SJ. Bruce Fields 	struct nfs4_lockowner *lo;
5849dd257933SJeff Layton 	struct nfs4_ol_stateid *lst;
585064a284d0SJ. Bruce Fields 	unsigned int strhashval;
585164a284d0SJ. Bruce Fields 
5852c8623999SKinglong Mee 	lo = find_lockowner_str(cl, &lock->lk_new_owner);
5853c53530daSJeff Layton 	if (!lo) {
585476f6c9e1SKinglong Mee 		strhashval = ownerstr_hashval(&lock->lk_new_owner);
585564a284d0SJ. Bruce Fields 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
585664a284d0SJ. Bruce Fields 		if (lo == NULL)
585764a284d0SJ. Bruce Fields 			return nfserr_jukebox;
5858c53530daSJeff Layton 	} else {
5859c53530daSJeff Layton 		/* with an existing lockowner, seqids must be the same */
58605db1c03fSJeff Layton 		status = nfserr_bad_seqid;
5861c53530daSJeff Layton 		if (!cstate->minorversion &&
5862c53530daSJeff Layton 		    lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
58635db1c03fSJeff Layton 			goto out;
5864c53530daSJeff Layton 	}
5865c53530daSJeff Layton 
5866dd257933SJeff Layton 	lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
5867dd257933SJeff Layton 	if (lst == NULL) {
58685db1c03fSJeff Layton 		status = nfserr_jukebox;
58695db1c03fSJeff Layton 		goto out;
587064a284d0SJ. Bruce Fields 	}
5871dd257933SJeff Layton 
58725db1c03fSJeff Layton 	status = nfs_ok;
5873dd257933SJeff Layton 	*plst = lst;
58745db1c03fSJeff Layton out:
58755db1c03fSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
58765db1c03fSJeff Layton 	return status;
587764a284d0SJ. Bruce Fields }
587864a284d0SJ. Bruce Fields 
58791da177e4SLinus Torvalds /*
58801da177e4SLinus Torvalds  *  LOCK operation
58811da177e4SLinus Torvalds  */
5882b37ad28bSAl Viro __be32
5883ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5884eb69853dSChristoph Hellwig 	   union nfsd4_op_u *u)
58851da177e4SLinus Torvalds {
5886eb69853dSChristoph Hellwig 	struct nfsd4_lock *lock = &u->lock;
5887fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *open_sop = NULL;
5888fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lock_sop = NULL;
58893d0fabd5STrond Myklebust 	struct nfs4_ol_stateid *lock_stp = NULL;
58900667b1e9STrond Myklebust 	struct nfs4_ol_stateid *open_stp = NULL;
58917214e860SJeff Layton 	struct nfs4_file *fp;
58927d947842SJ. Bruce Fields 	struct file *filp = NULL;
589376d348faSJeff Layton 	struct nfsd4_blocked_lock *nbl = NULL;
589421179d81SJeff Layton 	struct file_lock *file_lock = NULL;
589521179d81SJeff Layton 	struct file_lock *conflock = NULL;
5896b37ad28bSAl Viro 	__be32 status = 0;
5897b34f27aaSJ. Bruce Fields 	int lkflg;
5898b8dd7b9aSAl Viro 	int err;
58995db1c03fSJeff Layton 	bool new = false;
590076d348faSJeff Layton 	unsigned char fl_type;
590176d348faSJeff Layton 	unsigned int fl_flags = FL_POSIX;
59023320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
59033320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
59041da177e4SLinus Torvalds 
59051da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
59061da177e4SLinus Torvalds 		(long long) lock->lk_offset,
59071da177e4SLinus Torvalds 		(long long) lock->lk_length);
59081da177e4SLinus Torvalds 
59091da177e4SLinus Torvalds 	if (check_lock_length(lock->lk_offset, lock->lk_length))
59101da177e4SLinus Torvalds 		 return nfserr_inval;
59111da177e4SLinus Torvalds 
5912ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh,
59138837abcaSMiklos Szeredi 				S_IFREG, NFSD_MAY_LOCK))) {
5914a6f6ef2fSAndy Adamson 		dprintk("NFSD: nfsd4_lock: permission denied!\n");
5915a6f6ef2fSAndy Adamson 		return status;
5916a6f6ef2fSAndy Adamson 	}
5917a6f6ef2fSAndy Adamson 
59181da177e4SLinus Torvalds 	if (lock->lk_is_new) {
5919684e5638SJ. Bruce Fields 		if (nfsd4_has_session(cstate))
5920684e5638SJ. Bruce Fields 			/* See rfc 5661 18.10.3: given clientid is ignored: */
592176f6c9e1SKinglong Mee 			memcpy(&lock->lk_new_clientid,
5922684e5638SJ. Bruce Fields 				&cstate->session->se_client->cl_clientid,
5923684e5638SJ. Bruce Fields 				sizeof(clientid_t));
5924684e5638SJ. Bruce Fields 
59251da177e4SLinus Torvalds 		status = nfserr_stale_clientid;
59262c142baaSStanislav Kinsbursky 		if (STALE_CLIENTID(&lock->lk_new_clientid, nn))
59271da177e4SLinus Torvalds 			goto out;
59281da177e4SLinus Torvalds 
59291da177e4SLinus Torvalds 		/* validate and update open stateid and open seqid */
5930c0a5d93eSJ. Bruce Fields 		status = nfs4_preprocess_confirmed_seqid_op(cstate,
59311da177e4SLinus Torvalds 				        lock->lk_new_open_seqid,
59321da177e4SLinus Torvalds 		                        &lock->lk_new_open_stateid,
59333320fef1SStanislav Kinsbursky 					&open_stp, nn);
593437515177SNeilBrown 		if (status)
59351da177e4SLinus Torvalds 			goto out;
5936feb9dad5SOleg Drokin 		mutex_unlock(&open_stp->st_mutex);
5937fe0750e5SJ. Bruce Fields 		open_sop = openowner(open_stp->st_stateowner);
5938b34f27aaSJ. Bruce Fields 		status = nfserr_bad_stateid;
5939684e5638SJ. Bruce Fields 		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
594076f6c9e1SKinglong Mee 						&lock->lk_new_clientid))
5941b34f27aaSJ. Bruce Fields 			goto out;
594264a284d0SJ. Bruce Fields 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
59435db1c03fSJeff Layton 							&lock_stp, &new);
59443d0fabd5STrond Myklebust 	} else {
5945dd453dfdSBenny Halevy 		status = nfs4_preprocess_seqid_op(cstate,
59461da177e4SLinus Torvalds 				       lock->lk_old_lock_seqid,
59471da177e4SLinus Torvalds 				       &lock->lk_old_lock_stateid,
59483320fef1SStanislav Kinsbursky 				       NFS4_LOCK_STID, &lock_stp, nn);
59493d0fabd5STrond Myklebust 	}
59501da177e4SLinus Torvalds 	if (status)
59511da177e4SLinus Torvalds 		goto out;
5952fe0750e5SJ. Bruce Fields 	lock_sop = lockowner(lock_stp->st_stateowner);
59531da177e4SLinus Torvalds 
5954b34f27aaSJ. Bruce Fields 	lkflg = setlkflg(lock->lk_type);
5955b34f27aaSJ. Bruce Fields 	status = nfs4_check_openmode(lock_stp, lkflg);
5956b34f27aaSJ. Bruce Fields 	if (status)
5957b34f27aaSJ. Bruce Fields 		goto out;
5958b34f27aaSJ. Bruce Fields 
59590dd395dcSNeilBrown 	status = nfserr_grace;
59603320fef1SStanislav Kinsbursky 	if (locks_in_grace(net) && !lock->lk_reclaim)
59610dd395dcSNeilBrown 		goto out;
59620dd395dcSNeilBrown 	status = nfserr_no_grace;
59633320fef1SStanislav Kinsbursky 	if (!locks_in_grace(net) && lock->lk_reclaim)
59640dd395dcSNeilBrown 		goto out;
59650dd395dcSNeilBrown 
596611b9164aSTrond Myklebust 	fp = lock_stp->st_stid.sc_file;
59671da177e4SLinus Torvalds 	switch (lock->lk_type) {
59681da177e4SLinus Torvalds 		case NFS4_READW_LT:
596976d348faSJeff Layton 			if (nfsd4_has_session(cstate))
597076d348faSJeff Layton 				fl_flags |= FL_SLEEP;
597176d348faSJeff Layton 			/* Fallthrough */
597276d348faSJeff Layton 		case NFS4_READ_LT:
59737214e860SJeff Layton 			spin_lock(&fp->fi_lock);
59747214e860SJeff Layton 			filp = find_readable_file_locked(fp);
59750997b173SJ. Bruce Fields 			if (filp)
59760997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
59777214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
597876d348faSJeff Layton 			fl_type = F_RDLCK;
59791da177e4SLinus Torvalds 			break;
59801da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
598176d348faSJeff Layton 			if (nfsd4_has_session(cstate))
598276d348faSJeff Layton 				fl_flags |= FL_SLEEP;
598376d348faSJeff Layton 			/* Fallthrough */
598476d348faSJeff Layton 		case NFS4_WRITE_LT:
59857214e860SJeff Layton 			spin_lock(&fp->fi_lock);
59867214e860SJeff Layton 			filp = find_writeable_file_locked(fp);
59870997b173SJ. Bruce Fields 			if (filp)
59880997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
59897214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
599076d348faSJeff Layton 			fl_type = F_WRLCK;
59911da177e4SLinus Torvalds 			break;
59921da177e4SLinus Torvalds 		default:
59931da177e4SLinus Torvalds 			status = nfserr_inval;
59941da177e4SLinus Torvalds 		goto out;
59951da177e4SLinus Torvalds 	}
599676d348faSJeff Layton 
5997f9d7562fSJ. Bruce Fields 	if (!filp) {
5998f9d7562fSJ. Bruce Fields 		status = nfserr_openmode;
5999f9d7562fSJ. Bruce Fields 		goto out;
6000f9d7562fSJ. Bruce Fields 	}
6001aef9583bSKinglong Mee 
600276d348faSJeff Layton 	nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn);
600376d348faSJeff Layton 	if (!nbl) {
600476d348faSJeff Layton 		dprintk("NFSD: %s: unable to allocate block!\n", __func__);
600576d348faSJeff Layton 		status = nfserr_jukebox;
600676d348faSJeff Layton 		goto out;
600776d348faSJeff Layton 	}
600876d348faSJeff Layton 
600976d348faSJeff Layton 	file_lock = &nbl->nbl_lock;
601076d348faSJeff Layton 	file_lock->fl_type = fl_type;
6011aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
601221179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
601321179d81SJeff Layton 	file_lock->fl_file = filp;
601476d348faSJeff Layton 	file_lock->fl_flags = fl_flags;
601521179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
601621179d81SJeff Layton 	file_lock->fl_start = lock->lk_offset;
601721179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
601821179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
60191da177e4SLinus Torvalds 
602021179d81SJeff Layton 	conflock = locks_alloc_lock();
602121179d81SJeff Layton 	if (!conflock) {
602221179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
602321179d81SJeff Layton 		status = nfserr_jukebox;
602421179d81SJeff Layton 		goto out;
602521179d81SJeff Layton 	}
60261da177e4SLinus Torvalds 
602776d348faSJeff Layton 	if (fl_flags & FL_SLEEP) {
60287919d0a2SJeff Layton 		nbl->nbl_time = jiffies;
60290cc11a61SJeff Layton 		spin_lock(&nn->blocked_locks_lock);
603076d348faSJeff Layton 		list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked);
60317919d0a2SJeff Layton 		list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru);
60320cc11a61SJeff Layton 		spin_unlock(&nn->blocked_locks_lock);
603376d348faSJeff Layton 	}
603476d348faSJeff Layton 
603521179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
603676d348faSJeff Layton 	switch (err) {
60371da177e4SLinus Torvalds 	case 0: /* success! */
60389767feb2SJeff Layton 		nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid);
6039b8dd7b9aSAl Viro 		status = 0;
6040eb76b3fdSAndy Adamson 		break;
604176d348faSJeff Layton 	case FILE_LOCK_DEFERRED:
604276d348faSJeff Layton 		nbl = NULL;
604376d348faSJeff Layton 		/* Fallthrough */
604476d348faSJeff Layton 	case -EAGAIN:		/* conflock holds conflicting lock */
6045eb76b3fdSAndy Adamson 		status = nfserr_denied;
6046eb76b3fdSAndy Adamson 		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
604721179d81SJeff Layton 		nfs4_set_lock_denied(conflock, &lock->lk_denied);
6048eb76b3fdSAndy Adamson 		break;
604976d348faSJeff Layton 	case -EDEADLK:
60501da177e4SLinus Torvalds 		status = nfserr_deadlock;
6051eb76b3fdSAndy Adamson 		break;
60521da177e4SLinus Torvalds 	default:
6053fd85b817SMarc Eshel 		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
60543e772463SJ. Bruce Fields 		status = nfserrno(err);
6055eb76b3fdSAndy Adamson 		break;
60561da177e4SLinus Torvalds 	}
60571da177e4SLinus Torvalds out:
605876d348faSJeff Layton 	if (nbl) {
605976d348faSJeff Layton 		/* dequeue it if we queued it before */
606076d348faSJeff Layton 		if (fl_flags & FL_SLEEP) {
60610cc11a61SJeff Layton 			spin_lock(&nn->blocked_locks_lock);
606276d348faSJeff Layton 			list_del_init(&nbl->nbl_list);
60637919d0a2SJeff Layton 			list_del_init(&nbl->nbl_lru);
60640cc11a61SJeff Layton 			spin_unlock(&nn->blocked_locks_lock);
606576d348faSJeff Layton 		}
606676d348faSJeff Layton 		free_blocked_lock(nbl);
606776d348faSJeff Layton 	}
6068de18643dSTrond Myklebust 	if (filp)
6069de18643dSTrond Myklebust 		fput(filp);
60705db1c03fSJeff Layton 	if (lock_stp) {
60715db1c03fSJeff Layton 		/* Bump seqid manually if the 4.0 replay owner is openowner */
60725db1c03fSJeff Layton 		if (cstate->replay_owner &&
60735db1c03fSJeff Layton 		    cstate->replay_owner != &lock_sop->lo_owner &&
60745db1c03fSJeff Layton 		    seqid_mutating_err(ntohl(status)))
60755db1c03fSJeff Layton 			lock_sop->lo_owner.so_seqid++;
60765db1c03fSJeff Layton 
60775db1c03fSJeff Layton 		/*
60785db1c03fSJeff Layton 		 * If this is a new, never-before-used stateid, and we are
60795db1c03fSJeff Layton 		 * returning an error, then just go ahead and release it.
60805db1c03fSJeff Layton 		 */
608125020720SJ. Bruce Fields 		if (status && new)
60825db1c03fSJeff Layton 			release_lock_stateid(lock_stp);
6083beeca19cSTrond Myklebust 
6084beeca19cSTrond Myklebust 		mutex_unlock(&lock_stp->st_mutex);
60855db1c03fSJeff Layton 
60863d0fabd5STrond Myklebust 		nfs4_put_stid(&lock_stp->st_stid);
60875db1c03fSJeff Layton 	}
60880667b1e9STrond Myklebust 	if (open_stp)
60890667b1e9STrond Myklebust 		nfs4_put_stid(&open_stp->st_stid);
60909411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
609121179d81SJeff Layton 	if (conflock)
609221179d81SJeff Layton 		locks_free_lock(conflock);
60931da177e4SLinus Torvalds 	return status;
60941da177e4SLinus Torvalds }
60951da177e4SLinus Torvalds 
60961da177e4SLinus Torvalds /*
609755ef1274SJ. Bruce Fields  * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
609855ef1274SJ. Bruce Fields  * so we do a temporary open here just to get an open file to pass to
609955ef1274SJ. Bruce Fields  * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
610055ef1274SJ. Bruce Fields  * inode operation.)
610155ef1274SJ. Bruce Fields  */
610204da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
610355ef1274SJ. Bruce Fields {
610455ef1274SJ. Bruce Fields 	struct file *file;
610504da6e9dSAl Viro 	__be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
610604da6e9dSAl Viro 	if (!err) {
610704da6e9dSAl Viro 		err = nfserrno(vfs_test_lock(file, lock));
6108fd891454SChristoph Hellwig 		fput(file);
610904da6e9dSAl Viro 	}
611055ef1274SJ. Bruce Fields 	return err;
611155ef1274SJ. Bruce Fields }
611255ef1274SJ. Bruce Fields 
611355ef1274SJ. Bruce Fields /*
61141da177e4SLinus Torvalds  * LOCKT operation
61151da177e4SLinus Torvalds  */
6116b37ad28bSAl Viro __be32
6117ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
6118eb69853dSChristoph Hellwig 	    union nfsd4_op_u *u)
61191da177e4SLinus Torvalds {
6120eb69853dSChristoph Hellwig 	struct nfsd4_lockt *lockt = &u->lockt;
612121179d81SJeff Layton 	struct file_lock *file_lock = NULL;
61225db1c03fSJeff Layton 	struct nfs4_lockowner *lo = NULL;
6123b37ad28bSAl Viro 	__be32 status;
61247f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
61251da177e4SLinus Torvalds 
61265ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp)))
61271da177e4SLinus Torvalds 		return nfserr_grace;
61281da177e4SLinus Torvalds 
61291da177e4SLinus Torvalds 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
61301da177e4SLinus Torvalds 		 return nfserr_inval;
61311da177e4SLinus Torvalds 
61329b2ef62bSJ. Bruce Fields 	if (!nfsd4_has_session(cstate)) {
61334b24ca7dSJeff Layton 		status = lookup_clientid(&lockt->lt_clientid, cstate, nn);
61349b2ef62bSJ. Bruce Fields 		if (status)
61351da177e4SLinus Torvalds 			goto out;
61369b2ef62bSJ. Bruce Fields 	}
61371da177e4SLinus Torvalds 
613875c096f7SJ. Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
61391da177e4SLinus Torvalds 		goto out;
61401da177e4SLinus Torvalds 
614121179d81SJeff Layton 	file_lock = locks_alloc_lock();
614221179d81SJeff Layton 	if (!file_lock) {
614321179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
614421179d81SJeff Layton 		status = nfserr_jukebox;
614521179d81SJeff Layton 		goto out;
614621179d81SJeff Layton 	}
61476cd90662SKinglong Mee 
61481da177e4SLinus Torvalds 	switch (lockt->lt_type) {
61491da177e4SLinus Torvalds 		case NFS4_READ_LT:
61501da177e4SLinus Torvalds 		case NFS4_READW_LT:
615121179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
61521da177e4SLinus Torvalds 		break;
61531da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
61541da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
615521179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
61561da177e4SLinus Torvalds 		break;
61571da177e4SLinus Torvalds 		default:
61582fdada03SJ. Bruce Fields 			dprintk("NFSD: nfs4_lockt: bad lock type!\n");
61591da177e4SLinus Torvalds 			status = nfserr_inval;
61601da177e4SLinus Torvalds 		goto out;
61611da177e4SLinus Torvalds 	}
61621da177e4SLinus Torvalds 
6163c8623999SKinglong Mee 	lo = find_lockowner_str(cstate->clp, &lockt->lt_owner);
6164fe0750e5SJ. Bruce Fields 	if (lo)
616521179d81SJeff Layton 		file_lock->fl_owner = (fl_owner_t)lo;
616621179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
616721179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
61681da177e4SLinus Torvalds 
616921179d81SJeff Layton 	file_lock->fl_start = lockt->lt_offset;
617021179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
61711da177e4SLinus Torvalds 
617221179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
61731da177e4SLinus Torvalds 
617421179d81SJeff Layton 	status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
617504da6e9dSAl Viro 	if (status)
6176fd85b817SMarc Eshel 		goto out;
617704da6e9dSAl Viro 
617821179d81SJeff Layton 	if (file_lock->fl_type != F_UNLCK) {
61791da177e4SLinus Torvalds 		status = nfserr_denied;
618021179d81SJeff Layton 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
61811da177e4SLinus Torvalds 	}
61821da177e4SLinus Torvalds out:
61835db1c03fSJeff Layton 	if (lo)
61845db1c03fSJeff Layton 		nfs4_put_stateowner(&lo->lo_owner);
618521179d81SJeff Layton 	if (file_lock)
618621179d81SJeff Layton 		locks_free_lock(file_lock);
61871da177e4SLinus Torvalds 	return status;
61881da177e4SLinus Torvalds }
61891da177e4SLinus Torvalds 
6190b37ad28bSAl Viro __be32
6191ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
6192eb69853dSChristoph Hellwig 	    union nfsd4_op_u *u)
61931da177e4SLinus Torvalds {
6194eb69853dSChristoph Hellwig 	struct nfsd4_locku *locku = &u->locku;
6195dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
61961da177e4SLinus Torvalds 	struct file *filp = NULL;
619721179d81SJeff Layton 	struct file_lock *file_lock = NULL;
6198b37ad28bSAl Viro 	__be32 status;
6199b8dd7b9aSAl Viro 	int err;
62003320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
62011da177e4SLinus Torvalds 
62021da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
62031da177e4SLinus Torvalds 		(long long) locku->lu_offset,
62041da177e4SLinus Torvalds 		(long long) locku->lu_length);
62051da177e4SLinus Torvalds 
62061da177e4SLinus Torvalds 	if (check_lock_length(locku->lu_offset, locku->lu_length))
62071da177e4SLinus Torvalds 		 return nfserr_inval;
62081da177e4SLinus Torvalds 
62099072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
62103320fef1SStanislav Kinsbursky 					&locku->lu_stateid, NFS4_LOCK_STID,
62113320fef1SStanislav Kinsbursky 					&stp, nn);
62129072d5c6SJ. Bruce Fields 	if (status)
62131da177e4SLinus Torvalds 		goto out;
621411b9164aSTrond Myklebust 	filp = find_any_file(stp->st_stid.sc_file);
6215f9d7562fSJ. Bruce Fields 	if (!filp) {
6216f9d7562fSJ. Bruce Fields 		status = nfserr_lock_range;
6217858cc573STrond Myklebust 		goto put_stateid;
6218f9d7562fSJ. Bruce Fields 	}
621921179d81SJeff Layton 	file_lock = locks_alloc_lock();
622021179d81SJeff Layton 	if (!file_lock) {
622121179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
622221179d81SJeff Layton 		status = nfserr_jukebox;
6223de18643dSTrond Myklebust 		goto fput;
622421179d81SJeff Layton 	}
62256cd90662SKinglong Mee 
622621179d81SJeff Layton 	file_lock->fl_type = F_UNLCK;
6227aef9583bSKinglong Mee 	file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
622821179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
622921179d81SJeff Layton 	file_lock->fl_file = filp;
623021179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
623121179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
623221179d81SJeff Layton 	file_lock->fl_start = locku->lu_offset;
62331da177e4SLinus Torvalds 
623421179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(locku->lu_offset,
623521179d81SJeff Layton 						locku->lu_length);
623621179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
62371da177e4SLinus Torvalds 
623821179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
6239b8dd7b9aSAl Viro 	if (err) {
6240fd85b817SMarc Eshel 		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
62411da177e4SLinus Torvalds 		goto out_nfserr;
62421da177e4SLinus Torvalds 	}
62439767feb2SJeff Layton 	nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid);
6244de18643dSTrond Myklebust fput:
6245de18643dSTrond Myklebust 	fput(filp);
6246858cc573STrond Myklebust put_stateid:
6247feb9dad5SOleg Drokin 	mutex_unlock(&stp->st_mutex);
6248858cc573STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
62491da177e4SLinus Torvalds out:
62509411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
625121179d81SJeff Layton 	if (file_lock)
625221179d81SJeff Layton 		locks_free_lock(file_lock);
62531da177e4SLinus Torvalds 	return status;
62541da177e4SLinus Torvalds 
62551da177e4SLinus Torvalds out_nfserr:
6256b8dd7b9aSAl Viro 	status = nfserrno(err);
6257de18643dSTrond Myklebust 	goto fput;
62581da177e4SLinus Torvalds }
62591da177e4SLinus Torvalds 
62601da177e4SLinus Torvalds /*
62611da177e4SLinus Torvalds  * returns
6262f9c00c3aSJeff Layton  * 	true:  locks held by lockowner
6263f9c00c3aSJeff Layton  * 	false: no locks held by lockowner
62641da177e4SLinus Torvalds  */
6265f9c00c3aSJeff Layton static bool
6266f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
62671da177e4SLinus Torvalds {
6268bd61e0a9SJeff Layton 	struct file_lock *fl;
6269f9c00c3aSJeff Layton 	int status = false;
6270f9c00c3aSJeff Layton 	struct file *filp = find_any_file(fp);
6271f9c00c3aSJeff Layton 	struct inode *inode;
6272bd61e0a9SJeff Layton 	struct file_lock_context *flctx;
6273f9c00c3aSJeff Layton 
6274f9c00c3aSJeff Layton 	if (!filp) {
6275f9c00c3aSJeff Layton 		/* Any valid lock stateid should have some sort of access */
6276f9c00c3aSJeff Layton 		WARN_ON_ONCE(1);
6277f9c00c3aSJeff Layton 		return status;
6278f9c00c3aSJeff Layton 	}
6279f9c00c3aSJeff Layton 
6280f9c00c3aSJeff Layton 	inode = file_inode(filp);
6281bd61e0a9SJeff Layton 	flctx = inode->i_flctx;
62821da177e4SLinus Torvalds 
6283bd61e0a9SJeff Layton 	if (flctx && !list_empty_careful(&flctx->flc_posix)) {
62846109c850SJeff Layton 		spin_lock(&flctx->flc_lock);
6285bd61e0a9SJeff Layton 		list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
6286bd61e0a9SJeff Layton 			if (fl->fl_owner == (fl_owner_t)lowner) {
6287f9c00c3aSJeff Layton 				status = true;
6288f9c00c3aSJeff Layton 				break;
62891da177e4SLinus Torvalds 			}
6290796dadfdSJ. Bruce Fields 		}
62916109c850SJeff Layton 		spin_unlock(&flctx->flc_lock);
6292bd61e0a9SJeff Layton 	}
6293f9c00c3aSJeff Layton 	fput(filp);
62941da177e4SLinus Torvalds 	return status;
62951da177e4SLinus Torvalds }
62961da177e4SLinus Torvalds 
6297b37ad28bSAl Viro __be32
6298b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp,
6299b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
6300eb69853dSChristoph Hellwig 			union nfsd4_op_u *u)
63011da177e4SLinus Torvalds {
6302eb69853dSChristoph Hellwig 	struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
63031da177e4SLinus Torvalds 	clientid_t *clid = &rlockowner->rl_clientid;
6304882e9d25SJeff Layton 	struct nfs4_stateowner *sop;
6305882e9d25SJeff Layton 	struct nfs4_lockowner *lo = NULL;
6306dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
63071da177e4SLinus Torvalds 	struct xdr_netobj *owner = &rlockowner->rl_owner;
6308d4f0489fSTrond Myklebust 	unsigned int hashval = ownerstr_hashval(owner);
6309b37ad28bSAl Viro 	__be32 status;
63107f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
6311c58c6610STrond Myklebust 	struct nfs4_client *clp;
631288584818SChuck Lever 	LIST_HEAD (reaplist);
63131da177e4SLinus Torvalds 
63141da177e4SLinus Torvalds 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
63151da177e4SLinus Torvalds 		clid->cl_boot, clid->cl_id);
63161da177e4SLinus Torvalds 
63174b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
63189b2ef62bSJ. Bruce Fields 	if (status)
631951f5e783STrond Myklebust 		return status;
63209b2ef62bSJ. Bruce Fields 
6321d4f0489fSTrond Myklebust 	clp = cstate->clp;
6322fd44907cSJeff Layton 	/* Find the matching lock stateowner */
6323d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
6324882e9d25SJeff Layton 	list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval],
6325d4f0489fSTrond Myklebust 			    so_strhash) {
6326882e9d25SJeff Layton 
6327882e9d25SJeff Layton 		if (sop->so_is_open_owner || !same_owner_str(sop, owner))
632816bfdaafSJ. Bruce Fields 			continue;
6329882e9d25SJeff Layton 
6330882e9d25SJeff Layton 		/* see if there are still any locks associated with it */
6331882e9d25SJeff Layton 		lo = lockowner(sop);
6332882e9d25SJeff Layton 		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
6333882e9d25SJeff Layton 			if (check_for_locks(stp->st_stid.sc_file, lo)) {
6334882e9d25SJeff Layton 				status = nfserr_locks_held;
6335882e9d25SJeff Layton 				spin_unlock(&clp->cl_lock);
633651f5e783STrond Myklebust 				return status;
6337882e9d25SJeff Layton 			}
6338882e9d25SJeff Layton 		}
6339882e9d25SJeff Layton 
6340b5971afaSKinglong Mee 		nfs4_get_stateowner(sop);
6341fd44907cSJeff Layton 		break;
6342fd44907cSJeff Layton 	}
634388584818SChuck Lever 	if (!lo) {
6344d4f0489fSTrond Myklebust 		spin_unlock(&clp->cl_lock);
634588584818SChuck Lever 		return status;
634688584818SChuck Lever 	}
634788584818SChuck Lever 
634888584818SChuck Lever 	unhash_lockowner_locked(lo);
634988584818SChuck Lever 	while (!list_empty(&lo->lo_owner.so_stateids)) {
635088584818SChuck Lever 		stp = list_first_entry(&lo->lo_owner.so_stateids,
635188584818SChuck Lever 				       struct nfs4_ol_stateid,
635288584818SChuck Lever 				       st_perstateowner);
635388584818SChuck Lever 		WARN_ON(!unhash_lock_stateid(stp));
635488584818SChuck Lever 		put_ol_stateid_locked(stp, &reaplist);
635588584818SChuck Lever 	}
635688584818SChuck Lever 	spin_unlock(&clp->cl_lock);
635788584818SChuck Lever 	free_ol_stateid_reaplist(&reaplist);
635888584818SChuck Lever 	nfs4_put_stateowner(&lo->lo_owner);
635988584818SChuck Lever 
63601da177e4SLinus Torvalds 	return status;
63611da177e4SLinus Torvalds }
63621da177e4SLinus Torvalds 
63631da177e4SLinus Torvalds static inline struct nfs4_client_reclaim *
6364a55370a3SNeilBrown alloc_reclaim(void)
63651da177e4SLinus Torvalds {
6366a55370a3SNeilBrown 	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
63671da177e4SLinus Torvalds }
63681da177e4SLinus Torvalds 
63690ce0c2b5SJeff Layton bool
637052e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
6371c7b9a459SNeilBrown {
63720ce0c2b5SJeff Layton 	struct nfs4_client_reclaim *crp;
6373c7b9a459SNeilBrown 
637452e19c09SStanislav Kinsbursky 	crp = nfsd4_find_reclaim_client(name, nn);
63750ce0c2b5SJeff Layton 	return (crp && crp->cr_clp);
6376c7b9a459SNeilBrown }
6377c7b9a459SNeilBrown 
63781da177e4SLinus Torvalds /*
63791da177e4SLinus Torvalds  * failure => all reset bets are off, nfserr_no_grace...
63801da177e4SLinus Torvalds  */
6381772a9bbbSJeff Layton struct nfs4_client_reclaim *
638252e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
63831da177e4SLinus Torvalds {
63841da177e4SLinus Torvalds 	unsigned int strhashval;
6385772a9bbbSJeff Layton 	struct nfs4_client_reclaim *crp;
63861da177e4SLinus Torvalds 
6387a55370a3SNeilBrown 	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
6388a55370a3SNeilBrown 	crp = alloc_reclaim();
6389772a9bbbSJeff Layton 	if (crp) {
6390a55370a3SNeilBrown 		strhashval = clientstr_hashval(name);
63911da177e4SLinus Torvalds 		INIT_LIST_HEAD(&crp->cr_strhash);
639252e19c09SStanislav Kinsbursky 		list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
6393a55370a3SNeilBrown 		memcpy(crp->cr_recdir, name, HEXDIR_LEN);
63940ce0c2b5SJeff Layton 		crp->cr_clp = NULL;
639552e19c09SStanislav Kinsbursky 		nn->reclaim_str_hashtbl_size++;
6396772a9bbbSJeff Layton 	}
6397772a9bbbSJeff Layton 	return crp;
63981da177e4SLinus Torvalds }
63991da177e4SLinus Torvalds 
64002a4317c5SJeff Layton void
640152e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
6402ce30e539SJeff Layton {
6403ce30e539SJeff Layton 	list_del(&crp->cr_strhash);
6404ce30e539SJeff Layton 	kfree(crp);
640552e19c09SStanislav Kinsbursky 	nn->reclaim_str_hashtbl_size--;
6406ce30e539SJeff Layton }
6407ce30e539SJeff Layton 
6408ce30e539SJeff Layton void
640952e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn)
64101da177e4SLinus Torvalds {
64111da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
64121da177e4SLinus Torvalds 	int i;
64131da177e4SLinus Torvalds 
64141da177e4SLinus Torvalds 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
641552e19c09SStanislav Kinsbursky 		while (!list_empty(&nn->reclaim_str_hashtbl[i])) {
641652e19c09SStanislav Kinsbursky 			crp = list_entry(nn->reclaim_str_hashtbl[i].next,
64171da177e4SLinus Torvalds 			                struct nfs4_client_reclaim, cr_strhash);
641852e19c09SStanislav Kinsbursky 			nfs4_remove_reclaim_record(crp, nn);
64191da177e4SLinus Torvalds 		}
64201da177e4SLinus Torvalds 	}
6421063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(nn->reclaim_str_hashtbl_size);
64221da177e4SLinus Torvalds }
64231da177e4SLinus Torvalds 
64241da177e4SLinus Torvalds /*
64251da177e4SLinus Torvalds  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
64262a4317c5SJeff Layton struct nfs4_client_reclaim *
642752e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
64281da177e4SLinus Torvalds {
64291da177e4SLinus Torvalds 	unsigned int strhashval;
64301da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
64311da177e4SLinus Torvalds 
6432278c931cSJeff Layton 	dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
64331da177e4SLinus Torvalds 
6434278c931cSJeff Layton 	strhashval = clientstr_hashval(recdir);
643552e19c09SStanislav Kinsbursky 	list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
6436278c931cSJeff Layton 		if (same_name(crp->cr_recdir, recdir)) {
64371da177e4SLinus Torvalds 			return crp;
64381da177e4SLinus Torvalds 		}
64391da177e4SLinus Torvalds 	}
64401da177e4SLinus Torvalds 	return NULL;
64411da177e4SLinus Torvalds }
64421da177e4SLinus Torvalds 
64431da177e4SLinus Torvalds /*
64441da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list.
64451da177e4SLinus Torvalds */
6446b37ad28bSAl Viro __be32
64470fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid,
64480fe492dbSTrond Myklebust 		struct nfsd4_compound_state *cstate,
64490fe492dbSTrond Myklebust 		struct nfsd_net *nn)
64501da177e4SLinus Torvalds {
64510fe492dbSTrond Myklebust 	__be32 status;
6452a52d726bSJeff Layton 
6453a52d726bSJeff Layton 	/* find clientid in conf_id_hashtbl */
64540fe492dbSTrond Myklebust 	status = lookup_clientid(clid, cstate, nn);
64550fe492dbSTrond Myklebust 	if (status)
6456a52d726bSJeff Layton 		return nfserr_reclaim_bad;
6457a52d726bSJeff Layton 
64583b3e7b72SJeff Layton 	if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags))
64593b3e7b72SJeff Layton 		return nfserr_no_grace;
64603b3e7b72SJeff Layton 
64610fe492dbSTrond Myklebust 	if (nfsd4_client_record_check(cstate->clp))
64620fe492dbSTrond Myklebust 		return nfserr_reclaim_bad;
64630fe492dbSTrond Myklebust 
64640fe492dbSTrond Myklebust 	return nfs_ok;
64651da177e4SLinus Torvalds }
64661da177e4SLinus Torvalds 
646765178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION
6468016200c3SJeff Layton static inline void
6469016200c3SJeff Layton put_client(struct nfs4_client *clp)
6470016200c3SJeff Layton {
6471016200c3SJeff Layton 	atomic_dec(&clp->cl_refcount);
6472016200c3SJeff Layton }
6473016200c3SJeff Layton 
6474285abdeeSJeff Layton static struct nfs4_client *
6475285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
6476285abdeeSJeff Layton {
6477285abdeeSJeff Layton 	struct nfs4_client *clp;
6478285abdeeSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6479285abdeeSJeff Layton 					  nfsd_net_id);
6480285abdeeSJeff Layton 
6481285abdeeSJeff Layton 	if (!nfsd_netns_ready(nn))
6482285abdeeSJeff Layton 		return NULL;
6483285abdeeSJeff Layton 
6484285abdeeSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
6485285abdeeSJeff Layton 		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
6486285abdeeSJeff Layton 			return clp;
6487285abdeeSJeff Layton 	}
6488285abdeeSJeff Layton 	return NULL;
6489285abdeeSJeff Layton }
6490285abdeeSJeff Layton 
64917ec0e36fSJeff Layton u64
6492285abdeeSJeff Layton nfsd_inject_print_clients(void)
64937ec0e36fSJeff Layton {
64947ec0e36fSJeff Layton 	struct nfs4_client *clp;
64957ec0e36fSJeff Layton 	u64 count = 0;
64967ec0e36fSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
64977ec0e36fSJeff Layton 					  nfsd_net_id);
64987ec0e36fSJeff Layton 	char buf[INET6_ADDRSTRLEN];
64997ec0e36fSJeff Layton 
65007ec0e36fSJeff Layton 	if (!nfsd_netns_ready(nn))
65017ec0e36fSJeff Layton 		return 0;
65027ec0e36fSJeff Layton 
65037ec0e36fSJeff Layton 	spin_lock(&nn->client_lock);
65047ec0e36fSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
65057ec0e36fSJeff Layton 		rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
65067ec0e36fSJeff Layton 		pr_info("NFS Client: %s\n", buf);
65077ec0e36fSJeff Layton 		++count;
65087ec0e36fSJeff Layton 	}
65097ec0e36fSJeff Layton 	spin_unlock(&nn->client_lock);
65107ec0e36fSJeff Layton 
65117ec0e36fSJeff Layton 	return count;
65127ec0e36fSJeff Layton }
651365178db4SBryan Schumaker 
6514a0926d15SJeff Layton u64
6515285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size)
6516a0926d15SJeff Layton {
6517a0926d15SJeff Layton 	u64 count = 0;
6518a0926d15SJeff Layton 	struct nfs4_client *clp;
6519a0926d15SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6520a0926d15SJeff Layton 					  nfsd_net_id);
6521a0926d15SJeff Layton 
6522a0926d15SJeff Layton 	if (!nfsd_netns_ready(nn))
6523a0926d15SJeff Layton 		return count;
6524a0926d15SJeff Layton 
6525a0926d15SJeff Layton 	spin_lock(&nn->client_lock);
6526a0926d15SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
6527a0926d15SJeff Layton 	if (clp) {
6528a0926d15SJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok)
6529a0926d15SJeff Layton 			++count;
6530a0926d15SJeff Layton 		else
6531a0926d15SJeff Layton 			clp = NULL;
6532a0926d15SJeff Layton 	}
6533a0926d15SJeff Layton 	spin_unlock(&nn->client_lock);
6534a0926d15SJeff Layton 
6535a0926d15SJeff Layton 	if (clp)
6536a0926d15SJeff Layton 		expire_client(clp);
6537a0926d15SJeff Layton 
6538a0926d15SJeff Layton 	return count;
6539a0926d15SJeff Layton }
6540a0926d15SJeff Layton 
654169fc9edfSJeff Layton u64
6542285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max)
654369fc9edfSJeff Layton {
654469fc9edfSJeff Layton 	u64 count = 0;
654569fc9edfSJeff Layton 	struct nfs4_client *clp, *next;
654669fc9edfSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
654769fc9edfSJeff Layton 						nfsd_net_id);
654869fc9edfSJeff Layton 	LIST_HEAD(reaplist);
654969fc9edfSJeff Layton 
655069fc9edfSJeff Layton 	if (!nfsd_netns_ready(nn))
655169fc9edfSJeff Layton 		return count;
655269fc9edfSJeff Layton 
655369fc9edfSJeff Layton 	spin_lock(&nn->client_lock);
655469fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
655569fc9edfSJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok) {
655669fc9edfSJeff Layton 			list_add(&clp->cl_lru, &reaplist);
655769fc9edfSJeff Layton 			if (max != 0 && ++count >= max)
655869fc9edfSJeff Layton 				break;
655969fc9edfSJeff Layton 		}
656069fc9edfSJeff Layton 	}
656169fc9edfSJeff Layton 	spin_unlock(&nn->client_lock);
656269fc9edfSJeff Layton 
656369fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
656469fc9edfSJeff Layton 		expire_client(clp);
656569fc9edfSJeff Layton 
656669fc9edfSJeff Layton 	return count;
656769fc9edfSJeff Layton }
656869fc9edfSJeff Layton 
6569184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
6570184c1847SBryan Schumaker 			     const char *type)
6571184c1847SBryan Schumaker {
6572184c1847SBryan Schumaker 	char buf[INET6_ADDRSTRLEN];
65730a5c33e2SBryan Schumaker 	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
6574184c1847SBryan Schumaker 	printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
6575184c1847SBryan Schumaker }
6576184c1847SBryan Schumaker 
6577016200c3SJeff Layton static void
6578016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
6579016200c3SJeff Layton 			     struct list_head *collect)
6580016200c3SJeff Layton {
6581016200c3SJeff Layton 	struct nfs4_client *clp = lst->st_stid.sc_client;
6582016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6583016200c3SJeff Layton 					  nfsd_net_id);
6584016200c3SJeff Layton 
6585016200c3SJeff Layton 	if (!collect)
6586016200c3SJeff Layton 		return;
6587016200c3SJeff Layton 
6588016200c3SJeff Layton 	lockdep_assert_held(&nn->client_lock);
6589016200c3SJeff Layton 	atomic_inc(&clp->cl_refcount);
6590016200c3SJeff Layton 	list_add(&lst->st_locks, collect);
6591016200c3SJeff Layton }
6592016200c3SJeff Layton 
65933c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
65943738d50eSJeff Layton 				    struct list_head *collect,
6595e8568739SJeff Layton 				    bool (*func)(struct nfs4_ol_stateid *))
6596fc29171fSBryan Schumaker {
6597fc29171fSBryan Schumaker 	struct nfs4_openowner *oop;
6598fc29171fSBryan Schumaker 	struct nfs4_ol_stateid *stp, *st_next;
65993c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *lst, *lst_next;
6600fc29171fSBryan Schumaker 	u64 count = 0;
6601fc29171fSBryan Schumaker 
6602016200c3SJeff Layton 	spin_lock(&clp->cl_lock);
6603fc29171fSBryan Schumaker 	list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
66043c87b9b7STrond Myklebust 		list_for_each_entry_safe(stp, st_next,
66053c87b9b7STrond Myklebust 				&oop->oo_owner.so_stateids, st_perstateowner) {
66063c87b9b7STrond Myklebust 			list_for_each_entry_safe(lst, lst_next,
66073c87b9b7STrond Myklebust 					&stp->st_locks, st_locks) {
66083738d50eSJeff Layton 				if (func) {
6609e8568739SJeff Layton 					if (func(lst))
6610016200c3SJeff Layton 						nfsd_inject_add_lock_to_list(lst,
66113738d50eSJeff Layton 									collect);
66123738d50eSJeff Layton 				}
6613016200c3SJeff Layton 				++count;
6614016200c3SJeff Layton 				/*
6615016200c3SJeff Layton 				 * Despite the fact that these functions deal
6616016200c3SJeff Layton 				 * with 64-bit integers for "count", we must
6617016200c3SJeff Layton 				 * ensure that it doesn't blow up the
6618016200c3SJeff Layton 				 * clp->cl_refcount. Throw a warning if we
6619016200c3SJeff Layton 				 * start to approach INT_MAX here.
6620016200c3SJeff Layton 				 */
6621016200c3SJeff Layton 				WARN_ON_ONCE(count == (INT_MAX / 2));
6622016200c3SJeff Layton 				if (count == max)
6623016200c3SJeff Layton 					goto out;
6624fc29171fSBryan Schumaker 			}
6625fc29171fSBryan Schumaker 		}
6626fc29171fSBryan Schumaker 	}
6627016200c3SJeff Layton out:
6628016200c3SJeff Layton 	spin_unlock(&clp->cl_lock);
6629fc29171fSBryan Schumaker 
6630fc29171fSBryan Schumaker 	return count;
6631fc29171fSBryan Schumaker }
6632fc29171fSBryan Schumaker 
6633016200c3SJeff Layton static u64
6634016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
6635016200c3SJeff Layton 			  u64 max)
6636fc29171fSBryan Schumaker {
6637016200c3SJeff Layton 	return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
6638fc29171fSBryan Schumaker }
6639fc29171fSBryan Schumaker 
6640016200c3SJeff Layton static u64
6641016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp)
6642184c1847SBryan Schumaker {
6643016200c3SJeff Layton 	u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
6644184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "locked files");
6645184c1847SBryan Schumaker 	return count;
6646184c1847SBryan Schumaker }
6647184c1847SBryan Schumaker 
6648016200c3SJeff Layton u64
6649285abdeeSJeff Layton nfsd_inject_print_locks(void)
6650016200c3SJeff Layton {
6651016200c3SJeff Layton 	struct nfs4_client *clp;
6652016200c3SJeff Layton 	u64 count = 0;
6653016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6654016200c3SJeff Layton 						nfsd_net_id);
6655016200c3SJeff Layton 
6656016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6657016200c3SJeff Layton 		return 0;
6658016200c3SJeff Layton 
6659016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6660016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
6661016200c3SJeff Layton 		count += nfsd_print_client_locks(clp);
6662016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6663016200c3SJeff Layton 
6664016200c3SJeff Layton 	return count;
6665016200c3SJeff Layton }
6666016200c3SJeff Layton 
6667016200c3SJeff Layton static void
6668016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist)
6669016200c3SJeff Layton {
6670016200c3SJeff Layton 	struct nfs4_client *clp;
6671016200c3SJeff Layton 	struct nfs4_ol_stateid *stp, *next;
6672016200c3SJeff Layton 
6673016200c3SJeff Layton 	list_for_each_entry_safe(stp, next, reaplist, st_locks) {
6674016200c3SJeff Layton 		list_del_init(&stp->st_locks);
6675016200c3SJeff Layton 		clp = stp->st_stid.sc_client;
6676016200c3SJeff Layton 		nfs4_put_stid(&stp->st_stid);
6677016200c3SJeff Layton 		put_client(clp);
6678016200c3SJeff Layton 	}
6679016200c3SJeff Layton }
6680016200c3SJeff Layton 
6681016200c3SJeff Layton u64
6682285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size)
6683016200c3SJeff Layton {
6684016200c3SJeff Layton 	unsigned int count = 0;
6685016200c3SJeff Layton 	struct nfs4_client *clp;
6686016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6687016200c3SJeff Layton 						nfsd_net_id);
6688016200c3SJeff Layton 	LIST_HEAD(reaplist);
6689016200c3SJeff Layton 
6690016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6691016200c3SJeff Layton 		return count;
6692016200c3SJeff Layton 
6693016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6694016200c3SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
6695016200c3SJeff Layton 	if (clp)
6696016200c3SJeff Layton 		count = nfsd_collect_client_locks(clp, &reaplist, 0);
6697016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6698016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
6699016200c3SJeff Layton 	return count;
6700016200c3SJeff Layton }
6701016200c3SJeff Layton 
6702016200c3SJeff Layton u64
6703285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max)
6704016200c3SJeff Layton {
6705016200c3SJeff Layton 	u64 count = 0;
6706016200c3SJeff Layton 	struct nfs4_client *clp;
6707016200c3SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6708016200c3SJeff Layton 						nfsd_net_id);
6709016200c3SJeff Layton 	LIST_HEAD(reaplist);
6710016200c3SJeff Layton 
6711016200c3SJeff Layton 	if (!nfsd_netns_ready(nn))
6712016200c3SJeff Layton 		return count;
6713016200c3SJeff Layton 
6714016200c3SJeff Layton 	spin_lock(&nn->client_lock);
6715016200c3SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
6716016200c3SJeff Layton 		count += nfsd_collect_client_locks(clp, &reaplist, max - count);
6717016200c3SJeff Layton 		if (max != 0 && count >= max)
6718016200c3SJeff Layton 			break;
6719016200c3SJeff Layton 	}
6720016200c3SJeff Layton 	spin_unlock(&nn->client_lock);
6721016200c3SJeff Layton 	nfsd_reap_locks(&reaplist);
6722016200c3SJeff Layton 	return count;
6723016200c3SJeff Layton }
6724016200c3SJeff Layton 
672582e05efaSJeff Layton static u64
672682e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
672782e05efaSJeff Layton 			      struct list_head *collect,
672882e05efaSJeff Layton 			      void (*func)(struct nfs4_openowner *))
67294dbdbda8SBryan Schumaker {
67304dbdbda8SBryan Schumaker 	struct nfs4_openowner *oop, *next;
673182e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
673282e05efaSJeff Layton 						nfsd_net_id);
67334dbdbda8SBryan Schumaker 	u64 count = 0;
67344dbdbda8SBryan Schumaker 
673582e05efaSJeff Layton 	lockdep_assert_held(&nn->client_lock);
673682e05efaSJeff Layton 
673782e05efaSJeff Layton 	spin_lock(&clp->cl_lock);
67384dbdbda8SBryan Schumaker 	list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
673982e05efaSJeff Layton 		if (func) {
67404dbdbda8SBryan Schumaker 			func(oop);
674182e05efaSJeff Layton 			if (collect) {
674282e05efaSJeff Layton 				atomic_inc(&clp->cl_refcount);
674382e05efaSJeff Layton 				list_add(&oop->oo_perclient, collect);
674482e05efaSJeff Layton 			}
674582e05efaSJeff Layton 		}
674682e05efaSJeff Layton 		++count;
674782e05efaSJeff Layton 		/*
674882e05efaSJeff Layton 		 * Despite the fact that these functions deal with
674982e05efaSJeff Layton 		 * 64-bit integers for "count", we must ensure that
675082e05efaSJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
675182e05efaSJeff Layton 		 * warning if we start to approach INT_MAX here.
675282e05efaSJeff Layton 		 */
675382e05efaSJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
675482e05efaSJeff Layton 		if (count == max)
67554dbdbda8SBryan Schumaker 			break;
67564dbdbda8SBryan Schumaker 	}
675782e05efaSJeff Layton 	spin_unlock(&clp->cl_lock);
67584dbdbda8SBryan Schumaker 
67594dbdbda8SBryan Schumaker 	return count;
67604dbdbda8SBryan Schumaker }
67614dbdbda8SBryan Schumaker 
676282e05efaSJeff Layton static u64
676382e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp)
67644dbdbda8SBryan Schumaker {
676582e05efaSJeff Layton 	u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
676682e05efaSJeff Layton 
676782e05efaSJeff Layton 	nfsd_print_count(clp, count, "openowners");
676882e05efaSJeff Layton 	return count;
67694dbdbda8SBryan Schumaker }
67704dbdbda8SBryan Schumaker 
677182e05efaSJeff Layton static u64
677282e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp,
677382e05efaSJeff Layton 			       struct list_head *collect, u64 max)
6774184c1847SBryan Schumaker {
677582e05efaSJeff Layton 	return nfsd_foreach_client_openowner(clp, max, collect,
677682e05efaSJeff Layton 						unhash_openowner_locked);
677782e05efaSJeff Layton }
677882e05efaSJeff Layton 
677982e05efaSJeff Layton u64
6780285abdeeSJeff Layton nfsd_inject_print_openowners(void)
678182e05efaSJeff Layton {
678282e05efaSJeff Layton 	struct nfs4_client *clp;
678382e05efaSJeff Layton 	u64 count = 0;
678482e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
678582e05efaSJeff Layton 						nfsd_net_id);
678682e05efaSJeff Layton 
678782e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
678882e05efaSJeff Layton 		return 0;
678982e05efaSJeff Layton 
679082e05efaSJeff Layton 	spin_lock(&nn->client_lock);
679182e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
679282e05efaSJeff Layton 		count += nfsd_print_client_openowners(clp);
679382e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
679482e05efaSJeff Layton 
679582e05efaSJeff Layton 	return count;
679682e05efaSJeff Layton }
679782e05efaSJeff Layton 
679882e05efaSJeff Layton static void
679982e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist)
680082e05efaSJeff Layton {
680182e05efaSJeff Layton 	struct nfs4_client *clp;
680282e05efaSJeff Layton 	struct nfs4_openowner *oop, *next;
680382e05efaSJeff Layton 
680482e05efaSJeff Layton 	list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
680582e05efaSJeff Layton 		list_del_init(&oop->oo_perclient);
680682e05efaSJeff Layton 		clp = oop->oo_owner.so_client;
680782e05efaSJeff Layton 		release_openowner(oop);
680882e05efaSJeff Layton 		put_client(clp);
680982e05efaSJeff Layton 	}
681082e05efaSJeff Layton }
681182e05efaSJeff Layton 
681282e05efaSJeff Layton u64
6813285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr,
6814285abdeeSJeff Layton 				     size_t addr_size)
681582e05efaSJeff Layton {
681682e05efaSJeff Layton 	unsigned int count = 0;
681782e05efaSJeff Layton 	struct nfs4_client *clp;
681882e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
681982e05efaSJeff Layton 						nfsd_net_id);
682082e05efaSJeff Layton 	LIST_HEAD(reaplist);
682182e05efaSJeff Layton 
682282e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
682382e05efaSJeff Layton 		return count;
682482e05efaSJeff Layton 
682582e05efaSJeff Layton 	spin_lock(&nn->client_lock);
682682e05efaSJeff Layton 	clp = nfsd_find_client(addr, addr_size);
682782e05efaSJeff Layton 	if (clp)
682882e05efaSJeff Layton 		count = nfsd_collect_client_openowners(clp, &reaplist, 0);
682982e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
683082e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
683182e05efaSJeff Layton 	return count;
683282e05efaSJeff Layton }
683382e05efaSJeff Layton 
683482e05efaSJeff Layton u64
6835285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max)
683682e05efaSJeff Layton {
683782e05efaSJeff Layton 	u64 count = 0;
683882e05efaSJeff Layton 	struct nfs4_client *clp;
683982e05efaSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
684082e05efaSJeff Layton 						nfsd_net_id);
684182e05efaSJeff Layton 	LIST_HEAD(reaplist);
684282e05efaSJeff Layton 
684382e05efaSJeff Layton 	if (!nfsd_netns_ready(nn))
684482e05efaSJeff Layton 		return count;
684582e05efaSJeff Layton 
684682e05efaSJeff Layton 	spin_lock(&nn->client_lock);
684782e05efaSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
684882e05efaSJeff Layton 		count += nfsd_collect_client_openowners(clp, &reaplist,
684982e05efaSJeff Layton 							max - count);
685082e05efaSJeff Layton 		if (max != 0 && count >= max)
685182e05efaSJeff Layton 			break;
685282e05efaSJeff Layton 	}
685382e05efaSJeff Layton 	spin_unlock(&nn->client_lock);
685482e05efaSJeff Layton 	nfsd_reap_openowners(&reaplist);
6855184c1847SBryan Schumaker 	return count;
6856184c1847SBryan Schumaker }
6857184c1847SBryan Schumaker 
6858269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
6859269de30fSBryan Schumaker 				     struct list_head *victims)
6860269de30fSBryan Schumaker {
6861269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
686298d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
686398d5c7c5SJeff Layton 						nfsd_net_id);
6864269de30fSBryan Schumaker 	u64 count = 0;
6865269de30fSBryan Schumaker 
686698d5c7c5SJeff Layton 	lockdep_assert_held(&nn->client_lock);
686798d5c7c5SJeff Layton 
686898d5c7c5SJeff Layton 	spin_lock(&state_lock);
6869269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
6870dff1399fSJeff Layton 		if (victims) {
6871dff1399fSJeff Layton 			/*
6872dff1399fSJeff Layton 			 * It's not safe to mess with delegations that have a
6873dff1399fSJeff Layton 			 * non-zero dl_time. They might have already been broken
6874dff1399fSJeff Layton 			 * and could be processed by the laundromat outside of
6875dff1399fSJeff Layton 			 * the state_lock. Just leave them be.
6876dff1399fSJeff Layton 			 */
6877dff1399fSJeff Layton 			if (dp->dl_time != 0)
6878dff1399fSJeff Layton 				continue;
6879dff1399fSJeff Layton 
688098d5c7c5SJeff Layton 			atomic_inc(&clp->cl_refcount);
68813fcbbd24SJeff Layton 			WARN_ON(!unhash_delegation_locked(dp));
688242690676SJeff Layton 			list_add(&dp->dl_recall_lru, victims);
6883dff1399fSJeff Layton 		}
688498d5c7c5SJeff Layton 		++count;
688598d5c7c5SJeff Layton 		/*
688698d5c7c5SJeff Layton 		 * Despite the fact that these functions deal with
688798d5c7c5SJeff Layton 		 * 64-bit integers for "count", we must ensure that
688898d5c7c5SJeff Layton 		 * it doesn't blow up the clp->cl_refcount. Throw a
688998d5c7c5SJeff Layton 		 * warning if we start to approach INT_MAX here.
689098d5c7c5SJeff Layton 		 */
689198d5c7c5SJeff Layton 		WARN_ON_ONCE(count == (INT_MAX / 2));
689298d5c7c5SJeff Layton 		if (count == max)
6893269de30fSBryan Schumaker 			break;
6894269de30fSBryan Schumaker 	}
689598d5c7c5SJeff Layton 	spin_unlock(&state_lock);
6896269de30fSBryan Schumaker 	return count;
6897269de30fSBryan Schumaker }
6898269de30fSBryan Schumaker 
689998d5c7c5SJeff Layton static u64
690098d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp)
6901269de30fSBryan Schumaker {
690298d5c7c5SJeff Layton 	u64 count = nfsd_find_all_delegations(clp, 0, NULL);
6903184c1847SBryan Schumaker 
6904184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "delegations");
6905184c1847SBryan Schumaker 	return count;
6906184c1847SBryan Schumaker }
6907184c1847SBryan Schumaker 
690898d5c7c5SJeff Layton u64
6909285abdeeSJeff Layton nfsd_inject_print_delegations(void)
691098d5c7c5SJeff Layton {
691198d5c7c5SJeff Layton 	struct nfs4_client *clp;
691298d5c7c5SJeff Layton 	u64 count = 0;
691398d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
691498d5c7c5SJeff Layton 						nfsd_net_id);
691598d5c7c5SJeff Layton 
691698d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
691798d5c7c5SJeff Layton 		return 0;
691898d5c7c5SJeff Layton 
691998d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
692098d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru)
692198d5c7c5SJeff Layton 		count += nfsd_print_client_delegations(clp);
692298d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
692398d5c7c5SJeff Layton 
692498d5c7c5SJeff Layton 	return count;
692598d5c7c5SJeff Layton }
692698d5c7c5SJeff Layton 
692798d5c7c5SJeff Layton static void
692898d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist)
692998d5c7c5SJeff Layton {
693098d5c7c5SJeff Layton 	struct nfs4_client *clp;
693198d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
693298d5c7c5SJeff Layton 
693398d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
693498d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
693598d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
693698d5c7c5SJeff Layton 		revoke_delegation(dp);
693798d5c7c5SJeff Layton 		put_client(clp);
693898d5c7c5SJeff Layton 	}
693998d5c7c5SJeff Layton }
694098d5c7c5SJeff Layton 
694198d5c7c5SJeff Layton u64
6942285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr,
6943285abdeeSJeff Layton 				      size_t addr_size)
694498d5c7c5SJeff Layton {
694598d5c7c5SJeff Layton 	u64 count = 0;
694698d5c7c5SJeff Layton 	struct nfs4_client *clp;
694798d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
694898d5c7c5SJeff Layton 						nfsd_net_id);
694998d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
695098d5c7c5SJeff Layton 
695198d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
695298d5c7c5SJeff Layton 		return count;
695398d5c7c5SJeff Layton 
695498d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
695598d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
695698d5c7c5SJeff Layton 	if (clp)
695798d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
695898d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
695998d5c7c5SJeff Layton 
696098d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
696198d5c7c5SJeff Layton 	return count;
696298d5c7c5SJeff Layton }
696398d5c7c5SJeff Layton 
696498d5c7c5SJeff Layton u64
6965285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max)
696698d5c7c5SJeff Layton {
696798d5c7c5SJeff Layton 	u64 count = 0;
696898d5c7c5SJeff Layton 	struct nfs4_client *clp;
696998d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
697098d5c7c5SJeff Layton 						nfsd_net_id);
697198d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
697298d5c7c5SJeff Layton 
697398d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
697498d5c7c5SJeff Layton 		return count;
697598d5c7c5SJeff Layton 
697698d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
697798d5c7c5SJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
697898d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
697998d5c7c5SJeff Layton 		if (max != 0 && count >= max)
698098d5c7c5SJeff Layton 			break;
698198d5c7c5SJeff Layton 	}
698298d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
698398d5c7c5SJeff Layton 	nfsd_forget_delegations(&reaplist);
698498d5c7c5SJeff Layton 	return count;
698598d5c7c5SJeff Layton }
698698d5c7c5SJeff Layton 
698798d5c7c5SJeff Layton static void
698898d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist)
698998d5c7c5SJeff Layton {
699098d5c7c5SJeff Layton 	struct nfs4_client *clp;
699198d5c7c5SJeff Layton 	struct nfs4_delegation *dp, *next;
699298d5c7c5SJeff Layton 
699398d5c7c5SJeff Layton 	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
699498d5c7c5SJeff Layton 		list_del_init(&dp->dl_recall_lru);
699598d5c7c5SJeff Layton 		clp = dp->dl_stid.sc_client;
699698d5c7c5SJeff Layton 		/*
699798d5c7c5SJeff Layton 		 * We skipped all entries that had a zero dl_time before,
699898d5c7c5SJeff Layton 		 * so we can now reset the dl_time back to 0. If a delegation
699998d5c7c5SJeff Layton 		 * break comes in now, then it won't make any difference since
700098d5c7c5SJeff Layton 		 * we're recalling it either way.
700198d5c7c5SJeff Layton 		 */
700298d5c7c5SJeff Layton 		spin_lock(&state_lock);
700398d5c7c5SJeff Layton 		dp->dl_time = 0;
700498d5c7c5SJeff Layton 		spin_unlock(&state_lock);
700598d5c7c5SJeff Layton 		nfsd_break_one_deleg(dp);
700698d5c7c5SJeff Layton 		put_client(clp);
700798d5c7c5SJeff Layton 	}
700898d5c7c5SJeff Layton }
700998d5c7c5SJeff Layton 
701098d5c7c5SJeff Layton u64
7011285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr,
701298d5c7c5SJeff Layton 				      size_t addr_size)
701398d5c7c5SJeff Layton {
701498d5c7c5SJeff Layton 	u64 count = 0;
701598d5c7c5SJeff Layton 	struct nfs4_client *clp;
701698d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
701798d5c7c5SJeff Layton 						nfsd_net_id);
701898d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
701998d5c7c5SJeff Layton 
702098d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
702198d5c7c5SJeff Layton 		return count;
702298d5c7c5SJeff Layton 
702398d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
702498d5c7c5SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
702598d5c7c5SJeff Layton 	if (clp)
702698d5c7c5SJeff Layton 		count = nfsd_find_all_delegations(clp, 0, &reaplist);
702798d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
702898d5c7c5SJeff Layton 
702998d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
703098d5c7c5SJeff Layton 	return count;
703198d5c7c5SJeff Layton }
703298d5c7c5SJeff Layton 
703398d5c7c5SJeff Layton u64
7034285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max)
703598d5c7c5SJeff Layton {
703698d5c7c5SJeff Layton 	u64 count = 0;
703798d5c7c5SJeff Layton 	struct nfs4_client *clp, *next;
703898d5c7c5SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
703998d5c7c5SJeff Layton 						nfsd_net_id);
704098d5c7c5SJeff Layton 	LIST_HEAD(reaplist);
704198d5c7c5SJeff Layton 
704298d5c7c5SJeff Layton 	if (!nfsd_netns_ready(nn))
704398d5c7c5SJeff Layton 		return count;
704498d5c7c5SJeff Layton 
704598d5c7c5SJeff Layton 	spin_lock(&nn->client_lock);
704698d5c7c5SJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
704798d5c7c5SJeff Layton 		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
704898d5c7c5SJeff Layton 		if (max != 0 && ++count >= max)
704998d5c7c5SJeff Layton 			break;
705098d5c7c5SJeff Layton 	}
705198d5c7c5SJeff Layton 	spin_unlock(&nn->client_lock);
705298d5c7c5SJeff Layton 	nfsd_recall_delegations(&reaplist);
705398d5c7c5SJeff Layton 	return count;
705498d5c7c5SJeff Layton }
705565178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */
705665178db4SBryan Schumaker 
7057c2f1a551SMeelap Shah /*
7058c2f1a551SMeelap Shah  * Since the lifetime of a delegation isn't limited to that of an open, a
7059c2f1a551SMeelap Shah  * client may quite reasonably hang on to a delegation as long as it has
7060c2f1a551SMeelap Shah  * the inode cached.  This becomes an obvious problem the first time a
7061c2f1a551SMeelap Shah  * client's inode cache approaches the size of the server's total memory.
7062c2f1a551SMeelap Shah  *
7063c2f1a551SMeelap Shah  * For now we avoid this problem by imposing a hard limit on the number
7064c2f1a551SMeelap Shah  * of delegations, which varies according to the server's memory size.
7065c2f1a551SMeelap Shah  */
7066c2f1a551SMeelap Shah static void
7067c2f1a551SMeelap Shah set_max_delegations(void)
7068c2f1a551SMeelap Shah {
7069c2f1a551SMeelap Shah 	/*
7070c2f1a551SMeelap Shah 	 * Allow at most 4 delegations per megabyte of RAM.  Quick
7071c2f1a551SMeelap Shah 	 * estimates suggest that in the worst case (where every delegation
7072c2f1a551SMeelap Shah 	 * is for a different inode), a delegation could take about 1.5K,
7073c2f1a551SMeelap Shah 	 * giving a worst case usage of about 6% of memory.
7074c2f1a551SMeelap Shah 	 */
7075c2f1a551SMeelap Shah 	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
7076c2f1a551SMeelap Shah }
7077c2f1a551SMeelap Shah 
7078d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net)
70798daae4dcSStanislav Kinsbursky {
70808daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
70818daae4dcSStanislav Kinsbursky 	int i;
70828daae4dcSStanislav Kinsbursky 
70838daae4dcSStanislav Kinsbursky 	nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
70848daae4dcSStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
70858daae4dcSStanislav Kinsbursky 	if (!nn->conf_id_hashtbl)
7086382a62e7SStanislav Kinsbursky 		goto err;
70870a7ec377SStanislav Kinsbursky 	nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) *
70880a7ec377SStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
70890a7ec377SStanislav Kinsbursky 	if (!nn->unconf_id_hashtbl)
70900a7ec377SStanislav Kinsbursky 		goto err_unconf_id;
70911872de0eSStanislav Kinsbursky 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
70921872de0eSStanislav Kinsbursky 			SESSION_HASH_SIZE, GFP_KERNEL);
70931872de0eSStanislav Kinsbursky 	if (!nn->sessionid_hashtbl)
70941872de0eSStanislav Kinsbursky 		goto err_sessionid;
70958daae4dcSStanislav Kinsbursky 
7096382a62e7SStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
70978daae4dcSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
70980a7ec377SStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
7099382a62e7SStanislav Kinsbursky 	}
71001872de0eSStanislav Kinsbursky 	for (i = 0; i < SESSION_HASH_SIZE; i++)
71011872de0eSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
7102382a62e7SStanislav Kinsbursky 	nn->conf_name_tree = RB_ROOT;
7103a99454aaSStanislav Kinsbursky 	nn->unconf_name_tree = RB_ROOT;
710481833de1SVasily Averin 	nn->boot_time = get_seconds();
710581833de1SVasily Averin 	nn->grace_ended = false;
710681833de1SVasily Averin 	nn->nfsd4_manager.block_opens = true;
710781833de1SVasily Averin 	INIT_LIST_HEAD(&nn->nfsd4_manager.list);
71085ed58bb2SStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->client_lru);
710973758fedSStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->close_lru);
7110e8c69d17SJ. Bruce Fields 	INIT_LIST_HEAD(&nn->del_recall_lru);
7111c9a49628SStanislav Kinsbursky 	spin_lock_init(&nn->client_lock);
71128daae4dcSStanislav Kinsbursky 
71130cc11a61SJeff Layton 	spin_lock_init(&nn->blocked_locks_lock);
71140cc11a61SJeff Layton 	INIT_LIST_HEAD(&nn->blocked_locks_lru);
71150cc11a61SJeff Layton 
711609121281SStanislav Kinsbursky 	INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
7117d85ed443SStanislav Kinsbursky 	get_net(net);
711809121281SStanislav Kinsbursky 
71198daae4dcSStanislav Kinsbursky 	return 0;
7120382a62e7SStanislav Kinsbursky 
71211872de0eSStanislav Kinsbursky err_sessionid:
71229b531137SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
71230a7ec377SStanislav Kinsbursky err_unconf_id:
71240a7ec377SStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
7125382a62e7SStanislav Kinsbursky err:
7126382a62e7SStanislav Kinsbursky 	return -ENOMEM;
71278daae4dcSStanislav Kinsbursky }
71288daae4dcSStanislav Kinsbursky 
71298daae4dcSStanislav Kinsbursky static void
71304dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net)
71318daae4dcSStanislav Kinsbursky {
71328daae4dcSStanislav Kinsbursky 	int i;
71338daae4dcSStanislav Kinsbursky 	struct nfs4_client *clp = NULL;
71348daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
71358daae4dcSStanislav Kinsbursky 
71368daae4dcSStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
71378daae4dcSStanislav Kinsbursky 		while (!list_empty(&nn->conf_id_hashtbl[i])) {
71388daae4dcSStanislav Kinsbursky 			clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
71398daae4dcSStanislav Kinsbursky 			destroy_client(clp);
71408daae4dcSStanislav Kinsbursky 		}
71418daae4dcSStanislav Kinsbursky 	}
7142a99454aaSStanislav Kinsbursky 
71432b905635SKinglong Mee 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
71442b905635SKinglong Mee 		while (!list_empty(&nn->unconf_id_hashtbl[i])) {
71452b905635SKinglong Mee 			clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
7146a99454aaSStanislav Kinsbursky 			destroy_client(clp);
7147a99454aaSStanislav Kinsbursky 		}
71482b905635SKinglong Mee 	}
7149a99454aaSStanislav Kinsbursky 
71501872de0eSStanislav Kinsbursky 	kfree(nn->sessionid_hashtbl);
71510a7ec377SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
71528daae4dcSStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
71534dce0ac9SStanislav Kinsbursky 	put_net(net);
71548daae4dcSStanislav Kinsbursky }
71558daae4dcSStanislav Kinsbursky 
7156f252bc68SStanislav Kinsbursky int
7157d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net)
7158ac4d8ff2SNeilBrown {
71595e1533c7SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
7160b5a1a81eSJ. Bruce Fields 	int ret;
7161b5a1a81eSJ. Bruce Fields 
7162d85ed443SStanislav Kinsbursky 	ret = nfs4_state_create_net(net);
71638daae4dcSStanislav Kinsbursky 	if (ret)
71648daae4dcSStanislav Kinsbursky 		return ret;
7165d4318acdSJeff Layton 	locks_start_grace(net, &nn->nfsd4_manager);
7166d4318acdSJeff Layton 	nfsd4_client_tracking_init(net);
71677e981a8aSVasily Averin 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n",
71687e981a8aSVasily Averin 	       nn->nfsd4_grace, net->ns.inum);
71695284b44eSStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
7170d85ed443SStanislav Kinsbursky 	return 0;
7171a6d6b781SJeff Layton }
7172d85ed443SStanislav Kinsbursky 
7173d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */
7174d85ed443SStanislav Kinsbursky 
7175d85ed443SStanislav Kinsbursky int
7176d85ed443SStanislav Kinsbursky nfs4_state_start(void)
7177d85ed443SStanislav Kinsbursky {
7178d85ed443SStanislav Kinsbursky 	int ret;
7179d85ed443SStanislav Kinsbursky 
7180d85ed443SStanislav Kinsbursky 	ret = set_callback_cred();
7181d85ed443SStanislav Kinsbursky 	if (ret)
7182f7d1ddbeSKinglong Mee 		return ret;
7183f7d1ddbeSKinglong Mee 
718451a54568SJeff Layton 	laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
7185a6d6b781SJeff Layton 	if (laundry_wq == NULL) {
7186a6d6b781SJeff Layton 		ret = -ENOMEM;
7187f7d1ddbeSKinglong Mee 		goto out_cleanup_cred;
7188a6d6b781SJeff Layton 	}
7189b5a1a81eSJ. Bruce Fields 	ret = nfsd4_create_callback_queue();
7190b5a1a81eSJ. Bruce Fields 	if (ret)
7191b5a1a81eSJ. Bruce Fields 		goto out_free_laundry;
719209121281SStanislav Kinsbursky 
7193c2f1a551SMeelap Shah 	set_max_delegations();
7194b5a1a81eSJ. Bruce Fields 	return 0;
7195d85ed443SStanislav Kinsbursky 
7196b5a1a81eSJ. Bruce Fields out_free_laundry:
7197b5a1a81eSJ. Bruce Fields 	destroy_workqueue(laundry_wq);
7198f7d1ddbeSKinglong Mee out_cleanup_cred:
7199f7d1ddbeSKinglong Mee 	cleanup_callback_cred();
7200b5a1a81eSJ. Bruce Fields 	return ret;
72011da177e4SLinus Torvalds }
72021da177e4SLinus Torvalds 
7203f252bc68SStanislav Kinsbursky void
72044dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net)
72051da177e4SLinus Torvalds {
72061da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
72071da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
72084dce0ac9SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
72097919d0a2SJeff Layton 	struct nfsd4_blocked_lock *nbl;
72101da177e4SLinus Torvalds 
72114dce0ac9SStanislav Kinsbursky 	cancel_delayed_work_sync(&nn->laundromat_work);
72124dce0ac9SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
7213ac55fdc4SJeff Layton 
72141da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
7215cdc97505SBenny Halevy 	spin_lock(&state_lock);
7216e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
72171da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
72183fcbbd24SJeff Layton 		WARN_ON(!unhash_delegation_locked(dp));
721942690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
72201da177e4SLinus Torvalds 	}
7221cdc97505SBenny Halevy 	spin_unlock(&state_lock);
72221da177e4SLinus Torvalds 	list_for_each_safe(pos, next, &reaplist) {
72231da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
722442690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
72258287f009SSachin Bhamare 		put_clnt_odstate(dp->dl_clnt_odstate);
7226afbda402SJeff Layton 		nfs4_put_deleg_lease(dp->dl_stid.sc_file);
72276011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
72281da177e4SLinus Torvalds 	}
72291da177e4SLinus Torvalds 
72307919d0a2SJeff Layton 	BUG_ON(!list_empty(&reaplist));
72310cc11a61SJeff Layton 	spin_lock(&nn->blocked_locks_lock);
72327919d0a2SJeff Layton 	while (!list_empty(&nn->blocked_locks_lru)) {
72337919d0a2SJeff Layton 		nbl = list_first_entry(&nn->blocked_locks_lru,
72347919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
72357919d0a2SJeff Layton 		list_move(&nbl->nbl_lru, &reaplist);
72367919d0a2SJeff Layton 		list_del_init(&nbl->nbl_list);
72377919d0a2SJeff Layton 	}
72380cc11a61SJeff Layton 	spin_unlock(&nn->blocked_locks_lock);
72397919d0a2SJeff Layton 
72407919d0a2SJeff Layton 	while (!list_empty(&reaplist)) {
724164ebe124SNaofumi Honda 		nbl = list_first_entry(&reaplist,
72427919d0a2SJeff Layton 					struct nfsd4_blocked_lock, nbl_lru);
72437919d0a2SJeff Layton 		list_del_init(&nbl->nbl_lru);
72447919d0a2SJeff Layton 		posix_unblock_lock(&nbl->nbl_lock);
72457919d0a2SJeff Layton 		free_blocked_lock(nbl);
72467919d0a2SJeff Layton 	}
72477919d0a2SJeff Layton 
72483320fef1SStanislav Kinsbursky 	nfsd4_client_tracking_exit(net);
72494dce0ac9SStanislav Kinsbursky 	nfs4_state_destroy_net(net);
72501da177e4SLinus Torvalds }
72511da177e4SLinus Torvalds 
72521da177e4SLinus Torvalds void
72531da177e4SLinus Torvalds nfs4_state_shutdown(void)
72541da177e4SLinus Torvalds {
72555e8d5c29SNeilBrown 	destroy_workqueue(laundry_wq);
7256c3935e30SJ. Bruce Fields 	nfsd4_destroy_callback_queue();
7257f7d1ddbeSKinglong Mee 	cleanup_callback_cred();
72581da177e4SLinus Torvalds }
72598b70484cSTigran Mkrtchyan 
72608b70484cSTigran Mkrtchyan static void
72618b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
72628b70484cSTigran Mkrtchyan {
726337c593c5STigran Mkrtchyan 	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
726437c593c5STigran Mkrtchyan 		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
72658b70484cSTigran Mkrtchyan }
72668b70484cSTigran Mkrtchyan 
72678b70484cSTigran Mkrtchyan static void
72688b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
72698b70484cSTigran Mkrtchyan {
727037c593c5STigran Mkrtchyan 	if (cstate->minorversion) {
727137c593c5STigran Mkrtchyan 		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
727237c593c5STigran Mkrtchyan 		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
727337c593c5STigran Mkrtchyan 	}
727437c593c5STigran Mkrtchyan }
727537c593c5STigran Mkrtchyan 
727637c593c5STigran Mkrtchyan void
727737c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate)
727837c593c5STigran Mkrtchyan {
727937c593c5STigran Mkrtchyan 	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
72808b70484cSTigran Mkrtchyan }
72818b70484cSTigran Mkrtchyan 
728262cd4a59STigran Mkrtchyan /*
728362cd4a59STigran Mkrtchyan  * functions to set current state id
728462cd4a59STigran Mkrtchyan  */
72858b70484cSTigran Mkrtchyan void
7286b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate,
7287b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
72889428fe1aSTigran Mkrtchyan {
7289b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->open_downgrade.od_stateid);
72909428fe1aSTigran Mkrtchyan }
72919428fe1aSTigran Mkrtchyan 
72929428fe1aSTigran Mkrtchyan void
7293b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate,
7294b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
72958b70484cSTigran Mkrtchyan {
7296b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->open.op_stateid);
72978b70484cSTigran Mkrtchyan }
72988b70484cSTigran Mkrtchyan 
72998b70484cSTigran Mkrtchyan void
7300b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate,
7301b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
730262cd4a59STigran Mkrtchyan {
7303b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->close.cl_stateid);
730462cd4a59STigran Mkrtchyan }
730562cd4a59STigran Mkrtchyan 
730662cd4a59STigran Mkrtchyan void
7307b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate,
7308b60e9859SChristoph Hellwig 		union nfsd4_op_u *u)
730962cd4a59STigran Mkrtchyan {
7310b60e9859SChristoph Hellwig 	put_stateid(cstate, &u->lock.lk_resp_stateid);
731162cd4a59STigran Mkrtchyan }
731262cd4a59STigran Mkrtchyan 
731362cd4a59STigran Mkrtchyan /*
731462cd4a59STigran Mkrtchyan  * functions to consume current state id
731562cd4a59STigran Mkrtchyan  */
73161e97b519STigran Mkrtchyan 
73171e97b519STigran Mkrtchyan void
731857832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate,
731957832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73209428fe1aSTigran Mkrtchyan {
732157832e7bSChristoph Hellwig 	get_stateid(cstate, &u->open_downgrade.od_stateid);
73229428fe1aSTigran Mkrtchyan }
73239428fe1aSTigran Mkrtchyan 
73249428fe1aSTigran Mkrtchyan void
732557832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate,
732657832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73279428fe1aSTigran Mkrtchyan {
732857832e7bSChristoph Hellwig 	get_stateid(cstate, &u->delegreturn.dr_stateid);
73299428fe1aSTigran Mkrtchyan }
73309428fe1aSTigran Mkrtchyan 
73319428fe1aSTigran Mkrtchyan void
733257832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate,
733357832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73341e97b519STigran Mkrtchyan {
733557832e7bSChristoph Hellwig 	get_stateid(cstate, &u->free_stateid.fr_stateid);
73361e97b519STigran Mkrtchyan }
73371e97b519STigran Mkrtchyan 
73381e97b519STigran Mkrtchyan void
733957832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate,
734057832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73411e97b519STigran Mkrtchyan {
734257832e7bSChristoph Hellwig 	get_stateid(cstate, &u->setattr.sa_stateid);
73431e97b519STigran Mkrtchyan }
73441e97b519STigran Mkrtchyan 
734562cd4a59STigran Mkrtchyan void
734657832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate,
734757832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73488b70484cSTigran Mkrtchyan {
734957832e7bSChristoph Hellwig 	get_stateid(cstate, &u->close.cl_stateid);
73508b70484cSTigran Mkrtchyan }
73518b70484cSTigran Mkrtchyan 
73528b70484cSTigran Mkrtchyan void
735357832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate,
735457832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
73558b70484cSTigran Mkrtchyan {
735657832e7bSChristoph Hellwig 	get_stateid(cstate, &u->locku.lu_stateid);
73578b70484cSTigran Mkrtchyan }
735830813e27STigran Mkrtchyan 
735930813e27STigran Mkrtchyan void
736057832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate,
736157832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
736230813e27STigran Mkrtchyan {
736357832e7bSChristoph Hellwig 	get_stateid(cstate, &u->read.rd_stateid);
736430813e27STigran Mkrtchyan }
736530813e27STigran Mkrtchyan 
736630813e27STigran Mkrtchyan void
736757832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
736857832e7bSChristoph Hellwig 		union nfsd4_op_u *u)
736930813e27STigran Mkrtchyan {
737057832e7bSChristoph Hellwig 	get_stateid(cstate, &u->write.wr_stateid);
737130813e27STigran Mkrtchyan }
7372