xref: /openbmc/linux/fs/nfsd/nfs4state.c (revision a6a9f18f)
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>
449a74af21SBoaz Harrosh #include "xdr4.h"
4506b332a5SJ. Bruce Fields #include "xdr4cb.h"
460a3adadeSJ. Bruce Fields #include "vfs.h"
47bfa4b365SJ. Bruce Fields #include "current_stateid.h"
481da177e4SLinus Torvalds 
495e1533c7SStanislav Kinsbursky #include "netns.h"
505e1533c7SStanislav Kinsbursky 
511da177e4SLinus Torvalds #define NFSDDBG_FACILITY                NFSDDBG_PROC
521da177e4SLinus Torvalds 
53f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0}
54f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = {
55f32f3c2dSJ. Bruce Fields 	.si_generation = ~0,
56f32f3c2dSJ. Bruce Fields 	.si_opaque = all_ones,
57f32f3c2dSJ. Bruce Fields };
58f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = {
59f32f3c2dSJ. Bruce Fields 	/* all fields zero */
60f32f3c2dSJ. Bruce Fields };
6119ff0f28STigran Mkrtchyan static const stateid_t currentstateid = {
6219ff0f28STigran Mkrtchyan 	.si_generation = 1,
6319ff0f28STigran Mkrtchyan };
64f32f3c2dSJ. Bruce Fields 
65ec6b5d7bSAndy Adamson static u64 current_sessionid = 1;
66fd39ca9aSNeilBrown 
67f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
68f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
6919ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /* forward declarations */
72fe0750e5SJ. Bruce Fields static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
731da177e4SLinus Torvalds 
748b671b80SJ. Bruce Fields /* Locking: */
758b671b80SJ. Bruce Fields 
768b671b80SJ. Bruce Fields /* Currently used for almost all code touching nfsv4 state: */
77353ab6e9SIngo Molnar static DEFINE_MUTEX(client_mutex);
781da177e4SLinus Torvalds 
798b671b80SJ. Bruce Fields /*
808b671b80SJ. Bruce Fields  * Currently used for the del_recall_lru and file hash table.  In an
818b671b80SJ. Bruce Fields  * effort to decrease the scope of the client_mutex, this spinlock may
828b671b80SJ. Bruce Fields  * eventually cover more:
838b671b80SJ. Bruce Fields  */
848b671b80SJ. Bruce Fields static DEFINE_SPINLOCK(recall_lock);
858b671b80SJ. Bruce Fields 
86fe0750e5SJ. Bruce Fields static struct kmem_cache *openowner_slab = NULL;
87fe0750e5SJ. Bruce Fields static struct kmem_cache *lockowner_slab = NULL;
88e18b890bSChristoph Lameter static struct kmem_cache *file_slab = NULL;
89e18b890bSChristoph Lameter static struct kmem_cache *stateid_slab = NULL;
90e18b890bSChristoph Lameter static struct kmem_cache *deleg_slab = NULL;
91e60d4398SNeilBrown 
921da177e4SLinus Torvalds void
931da177e4SLinus Torvalds nfs4_lock_state(void)
941da177e4SLinus Torvalds {
95353ab6e9SIngo Molnar 	mutex_lock(&client_mutex);
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
9866b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *);
99508dc6e1SBenny Halevy 
10066b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses)
101508dc6e1SBenny Halevy {
10266b2b9b2SJ. Bruce Fields 	return ses->se_flags & NFS4_SESSION_DEAD;
10366b2b9b2SJ. Bruce Fields }
10466b2b9b2SJ. Bruce Fields 
105f0f51f5cSJ. Bruce Fields void nfsd4_put_session(struct nfsd4_session *ses)
10666b2b9b2SJ. Bruce Fields {
107f0f51f5cSJ. Bruce Fields 	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
108f0f51f5cSJ. Bruce Fields 		free_session(ses);
109f0f51f5cSJ. Bruce Fields }
110f0f51f5cSJ. Bruce Fields 
111f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
112f0f51f5cSJ. Bruce Fields {
113f0f51f5cSJ. Bruce Fields 	if (atomic_read(&ses->se_ref) > ref_held_by_me)
11466b2b9b2SJ. Bruce Fields 		return nfserr_jukebox;
11566b2b9b2SJ. Bruce Fields 	ses->se_flags |= NFS4_SESSION_DEAD;
11666b2b9b2SJ. Bruce Fields 	return nfs_ok;
11766b2b9b2SJ. Bruce Fields }
11866b2b9b2SJ. Bruce Fields 
11966b2b9b2SJ. Bruce Fields static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
12066b2b9b2SJ. Bruce Fields {
12166b2b9b2SJ. Bruce Fields 	if (is_session_dead(ses))
12266b2b9b2SJ. Bruce Fields 		return nfserr_badsession;
12366b2b9b2SJ. Bruce Fields 	atomic_inc(&ses->se_ref);
12466b2b9b2SJ. Bruce Fields 	return nfs_ok;
125508dc6e1SBenny Halevy }
126508dc6e1SBenny Halevy 
1271da177e4SLinus Torvalds void
1281da177e4SLinus Torvalds nfs4_unlock_state(void)
1291da177e4SLinus Torvalds {
130353ab6e9SIngo Molnar 	mutex_unlock(&client_mutex);
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
133221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp)
134221a6876SJ. Bruce Fields {
135221a6876SJ. Bruce Fields 	return clp->cl_time == 0;
136221a6876SJ. Bruce Fields }
137221a6876SJ. Bruce Fields 
138221a6876SJ. Bruce Fields static __be32 mark_client_expired_locked(struct nfs4_client *clp)
139221a6876SJ. Bruce Fields {
140221a6876SJ. Bruce Fields 	if (atomic_read(&clp->cl_refcount))
141221a6876SJ. Bruce Fields 		return nfserr_jukebox;
142221a6876SJ. Bruce Fields 	clp->cl_time = 0;
143221a6876SJ. Bruce Fields 	return nfs_ok;
144221a6876SJ. Bruce Fields }
145221a6876SJ. Bruce Fields 
146221a6876SJ. Bruce Fields static __be32 mark_client_expired(struct nfs4_client *clp)
147221a6876SJ. Bruce Fields {
148221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
149221a6876SJ. Bruce Fields 	__be32 ret;
150221a6876SJ. Bruce Fields 
151221a6876SJ. Bruce Fields 	spin_lock(&nn->client_lock);
152221a6876SJ. Bruce Fields 	ret = mark_client_expired_locked(clp);
153221a6876SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
154221a6876SJ. Bruce Fields 	return ret;
155221a6876SJ. Bruce Fields }
156221a6876SJ. Bruce Fields 
157221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp)
158221a6876SJ. Bruce Fields {
159221a6876SJ. Bruce Fields 	if (is_client_expired(clp))
160221a6876SJ. Bruce Fields 		return nfserr_expired;
161221a6876SJ. Bruce Fields 	atomic_inc(&clp->cl_refcount);
162221a6876SJ. Bruce Fields 	return nfs_ok;
163221a6876SJ. Bruce Fields }
164221a6876SJ. Bruce Fields 
165221a6876SJ. Bruce Fields /* must be called under the client_lock */
166221a6876SJ. Bruce Fields static inline void
167221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp)
168221a6876SJ. Bruce Fields {
169221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
170221a6876SJ. Bruce Fields 
171221a6876SJ. Bruce Fields 	if (is_client_expired(clp)) {
172221a6876SJ. Bruce Fields 		WARN_ON(1);
173221a6876SJ. Bruce Fields 		printk("%s: client (clientid %08x/%08x) already expired\n",
174221a6876SJ. Bruce Fields 			__func__,
175221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
176221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
177221a6876SJ. Bruce Fields 		return;
178221a6876SJ. Bruce Fields 	}
179221a6876SJ. Bruce Fields 
180221a6876SJ. Bruce Fields 	dprintk("renewing client (clientid %08x/%08x)\n",
181221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
182221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
183221a6876SJ. Bruce Fields 	list_move_tail(&clp->cl_lru, &nn->client_lru);
184221a6876SJ. Bruce Fields 	clp->cl_time = get_seconds();
185221a6876SJ. Bruce Fields }
186221a6876SJ. Bruce Fields 
187221a6876SJ. Bruce Fields static inline void
188221a6876SJ. Bruce Fields renew_client(struct nfs4_client *clp)
189221a6876SJ. Bruce Fields {
190221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
191221a6876SJ. Bruce Fields 
192221a6876SJ. Bruce Fields 	spin_lock(&nn->client_lock);
193221a6876SJ. Bruce Fields 	renew_client_locked(clp);
194221a6876SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
195221a6876SJ. Bruce Fields }
196221a6876SJ. Bruce Fields 
197ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp)
198221a6876SJ. Bruce Fields {
199221a6876SJ. Bruce Fields 	if (!atomic_dec_and_test(&clp->cl_refcount))
200221a6876SJ. Bruce Fields 		return;
201221a6876SJ. Bruce Fields 	if (!is_client_expired(clp))
202221a6876SJ. Bruce Fields 		renew_client_locked(clp);
203221a6876SJ. Bruce Fields }
204221a6876SJ. Bruce Fields 
205221a6876SJ. Bruce Fields void put_client_renew(struct nfs4_client *clp)
206221a6876SJ. Bruce Fields {
207221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
208221a6876SJ. Bruce Fields 
209221a6876SJ. Bruce Fields 	if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
210221a6876SJ. Bruce Fields 		return;
211221a6876SJ. Bruce Fields 	if (!is_client_expired(clp))
212221a6876SJ. Bruce Fields 		renew_client_locked(clp);
213221a6876SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
214221a6876SJ. Bruce Fields }
215221a6876SJ. Bruce Fields 
216221a6876SJ. Bruce Fields 
2171da177e4SLinus Torvalds static inline u32
2181da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes)
2191da177e4SLinus Torvalds {
2201da177e4SLinus Torvalds 	unsigned char *cptr = (unsigned char *) ptr;
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	u32 x = 0;
2231da177e4SLinus Torvalds 	while (nbytes--) {
2241da177e4SLinus Torvalds 		x *= 37;
2251da177e4SLinus Torvalds 		x += *cptr++;
2261da177e4SLinus Torvalds 	}
2271da177e4SLinus Torvalds 	return x;
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds 
23032513b40SJ. Bruce Fields static void nfsd4_free_file(struct nfs4_file *f)
23132513b40SJ. Bruce Fields {
23232513b40SJ. Bruce Fields 	kmem_cache_free(file_slab, f);
23332513b40SJ. Bruce Fields }
23432513b40SJ. Bruce Fields 
23513cd2184SNeilBrown static inline void
23613cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi)
23713cd2184SNeilBrown {
2388b671b80SJ. Bruce Fields 	if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) {
23989876f8cSJeff Layton 		hlist_del(&fi->fi_hash);
2408b671b80SJ. Bruce Fields 		spin_unlock(&recall_lock);
2418b671b80SJ. Bruce Fields 		iput(fi->fi_inode);
24232513b40SJ. Bruce Fields 		nfsd4_free_file(fi);
2438b671b80SJ. Bruce Fields 	}
24413cd2184SNeilBrown }
24513cd2184SNeilBrown 
24613cd2184SNeilBrown static inline void
24713cd2184SNeilBrown get_nfs4_file(struct nfs4_file *fi)
24813cd2184SNeilBrown {
2498b671b80SJ. Bruce Fields 	atomic_inc(&fi->fi_ref);
25013cd2184SNeilBrown }
25113cd2184SNeilBrown 
252ef0f3390SNeilBrown static int num_delegations;
253697ce9beSZhang Yanfei unsigned long max_delegations;
254ef0f3390SNeilBrown 
255ef0f3390SNeilBrown /*
256ef0f3390SNeilBrown  * Open owner state (share locks)
257ef0f3390SNeilBrown  */
258ef0f3390SNeilBrown 
25916bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */
26016bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS              8
26116bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
26216bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
263ef0f3390SNeilBrown 
26416bfdaafSJ. Bruce Fields static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
265ddc04c41SJ. Bruce Fields {
266ddc04c41SJ. Bruce Fields 	unsigned int ret;
267ddc04c41SJ. Bruce Fields 
268ddc04c41SJ. Bruce Fields 	ret = opaque_hashval(ownername->data, ownername->len);
269ddc04c41SJ. Bruce Fields 	ret += clientid;
27016bfdaafSJ. Bruce Fields 	return ret & OWNER_HASH_MASK;
271ddc04c41SJ. Bruce Fields }
272ef0f3390SNeilBrown 
273ef0f3390SNeilBrown /* hash table for nfs4_file */
274ef0f3390SNeilBrown #define FILE_HASH_BITS                   8
275ef0f3390SNeilBrown #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
27635079582SShan Wei 
277ddc04c41SJ. Bruce Fields static unsigned int file_hashval(struct inode *ino)
278ddc04c41SJ. Bruce Fields {
279ddc04c41SJ. Bruce Fields 	/* XXX: why are we hashing on inode pointer, anyway? */
280ddc04c41SJ. Bruce Fields 	return hash_ptr(ino, FILE_HASH_BITS);
281ddc04c41SJ. Bruce Fields }
282ddc04c41SJ. Bruce Fields 
28389876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
284ef0f3390SNeilBrown 
2853477565eSJ. Bruce Fields static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
2863477565eSJ. Bruce Fields {
2873477565eSJ. Bruce Fields 	WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
2883477565eSJ. Bruce Fields 	atomic_inc(&fp->fi_access[oflag]);
2893477565eSJ. Bruce Fields }
2903477565eSJ. Bruce Fields 
291998db52cSJ. Bruce Fields static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
292998db52cSJ. Bruce Fields {
293998db52cSJ. Bruce Fields 	if (oflag == O_RDWR) {
2943477565eSJ. Bruce Fields 		__nfs4_file_get_access(fp, O_RDONLY);
2953477565eSJ. Bruce Fields 		__nfs4_file_get_access(fp, O_WRONLY);
296998db52cSJ. Bruce Fields 	} else
2973477565eSJ. Bruce Fields 		__nfs4_file_get_access(fp, oflag);
298998db52cSJ. Bruce Fields }
299998db52cSJ. Bruce Fields 
300998db52cSJ. Bruce Fields static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
301f9d7562fSJ. Bruce Fields {
302f9d7562fSJ. Bruce Fields 	if (fp->fi_fds[oflag]) {
303f9d7562fSJ. Bruce Fields 		fput(fp->fi_fds[oflag]);
304f9d7562fSJ. Bruce Fields 		fp->fi_fds[oflag] = NULL;
305f9d7562fSJ. Bruce Fields 	}
306f9d7562fSJ. Bruce Fields }
307f9d7562fSJ. Bruce Fields 
308998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
309f9d7562fSJ. Bruce Fields {
310f9d7562fSJ. Bruce Fields 	if (atomic_dec_and_test(&fp->fi_access[oflag])) {
311f9d7562fSJ. Bruce Fields 		nfs4_file_put_fd(fp, oflag);
3120c7c3e67SJ. Bruce Fields 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
3133d02fa29SJ. Bruce Fields 			nfs4_file_put_fd(fp, O_RDWR);
314f9d7562fSJ. Bruce Fields 	}
315f9d7562fSJ. Bruce Fields }
316f9d7562fSJ. Bruce Fields 
317998db52cSJ. Bruce Fields static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
318998db52cSJ. Bruce Fields {
319998db52cSJ. Bruce Fields 	if (oflag == O_RDWR) {
320998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, O_RDONLY);
321998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, O_WRONLY);
322998db52cSJ. Bruce Fields 	} else
323998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, oflag);
324998db52cSJ. Bruce Fields }
325998db52cSJ. Bruce Fields 
3263abdb607SJ. Bruce Fields static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct
3273abdb607SJ. Bruce Fields kmem_cache *slab)
328996e0938SJ. Bruce Fields {
329996e0938SJ. Bruce Fields 	struct idr *stateids = &cl->cl_stateids;
3303abdb607SJ. Bruce Fields 	struct nfs4_stid *stid;
3313abdb607SJ. Bruce Fields 	int new_id;
3323abdb607SJ. Bruce Fields 
3333abdb607SJ. Bruce Fields 	stid = kmem_cache_alloc(slab, GFP_KERNEL);
3343abdb607SJ. Bruce Fields 	if (!stid)
3353abdb607SJ. Bruce Fields 		return NULL;
336996e0938SJ. Bruce Fields 
337398c33aaSJeff Layton 	new_id = idr_alloc_cyclic(stateids, stid, 0, 0, GFP_KERNEL);
338ebd6c707STejun Heo 	if (new_id < 0)
3393abdb607SJ. Bruce Fields 		goto out_free;
3403abdb607SJ. Bruce Fields 	stid->sc_client = cl;
3413abdb607SJ. Bruce Fields 	stid->sc_type = 0;
3423abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_id = new_id;
3433abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
3443abdb607SJ. Bruce Fields 	/* Will be incremented before return to client: */
3453abdb607SJ. Bruce Fields 	stid->sc_stateid.si_generation = 0;
3463abdb607SJ. Bruce Fields 
347996e0938SJ. Bruce Fields 	/*
3483abdb607SJ. Bruce Fields 	 * It shouldn't be a problem to reuse an opaque stateid value.
3493abdb607SJ. Bruce Fields 	 * I don't think it is for 4.1.  But with 4.0 I worry that, for
3503abdb607SJ. Bruce Fields 	 * example, a stray write retransmission could be accepted by
3513abdb607SJ. Bruce Fields 	 * the server when it should have been rejected.  Therefore,
3523abdb607SJ. Bruce Fields 	 * adopt a trick from the sctp code to attempt to maximize the
3533abdb607SJ. Bruce Fields 	 * amount of time until an id is reused, by ensuring they always
3543abdb607SJ. Bruce Fields 	 * "increase" (mod INT_MAX):
355996e0938SJ. Bruce Fields 	 */
3563abdb607SJ. Bruce Fields 	return stid;
3573abdb607SJ. Bruce Fields out_free:
3582c44a234SWei Yongjun 	kmem_cache_free(slab, stid);
3593abdb607SJ. Bruce Fields 	return NULL;
3602a74aba7SJ. Bruce Fields }
3612a74aba7SJ. Bruce Fields 
3624cdc951bSJ. Bruce Fields static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
3634cdc951bSJ. Bruce Fields {
3644cdc951bSJ. Bruce Fields 	return openlockstateid(nfs4_alloc_stid(clp, stateid_slab));
3654cdc951bSJ. Bruce Fields }
3664cdc951bSJ. Bruce Fields 
3671da177e4SLinus Torvalds static struct nfs4_delegation *
36899c41515SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
3691da177e4SLinus Torvalds {
3701da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	dprintk("NFSD alloc_init_deleg\n");
373c2f1a551SMeelap Shah 	if (num_delegations > max_delegations)
374ef0f3390SNeilBrown 		return NULL;
375996e0938SJ. Bruce Fields 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
3765b2d21c1SNeilBrown 	if (dp == NULL)
3771da177e4SLinus Torvalds 		return dp;
3783abdb607SJ. Bruce Fields 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
3792a74aba7SJ. Bruce Fields 	/*
3802a74aba7SJ. Bruce Fields 	 * delegation seqid's are never incremented.  The 4.1 special
3816136d2b4SJ. Bruce Fields 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
3826136d2b4SJ. Bruce Fields 	 * 0 anyway just for consistency and use 1:
3832a74aba7SJ. Bruce Fields 	 */
3842a74aba7SJ. Bruce Fields 	dp->dl_stid.sc_stateid.si_generation = 1;
385ef0f3390SNeilBrown 	num_delegations++;
386ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perfile);
387ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perclnt);
3881da177e4SLinus Torvalds 	INIT_LIST_HEAD(&dp->dl_recall_lru);
389bf7bd3e9SJ. Bruce Fields 	dp->dl_file = NULL;
39099c41515SJ. Bruce Fields 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
3916c02eaa1SJ. Bruce Fields 	fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
3921da177e4SLinus Torvalds 	dp->dl_time = 0;
3931da177e4SLinus Torvalds 	atomic_set(&dp->dl_count, 1);
39457725155SJ. Bruce Fields 	nfsd4_init_callback(&dp->dl_recall);
3951da177e4SLinus Torvalds 	return dp;
3961da177e4SLinus Torvalds }
3971da177e4SLinus Torvalds 
39868a33961SJ. Bruce Fields static void remove_stid(struct nfs4_stid *s)
3993abdb607SJ. Bruce Fields {
4003abdb607SJ. Bruce Fields 	struct idr *stateids = &s->sc_client->cl_stateids;
4013abdb607SJ. Bruce Fields 
4023abdb607SJ. Bruce Fields 	idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
4033abdb607SJ. Bruce Fields }
4043abdb607SJ. Bruce Fields 
4051da177e4SLinus Torvalds void
4061da177e4SLinus Torvalds nfs4_put_delegation(struct nfs4_delegation *dp)
4071da177e4SLinus Torvalds {
4081da177e4SLinus Torvalds 	if (atomic_dec_and_test(&dp->dl_count)) {
40968a33961SJ. Bruce Fields 		kmem_cache_free(deleg_slab, dp);
410ef0f3390SNeilBrown 		num_delegations--;
4111da177e4SLinus Torvalds 	}
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
414acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp)
4151da177e4SLinus Torvalds {
416acfdf5c3SJ. Bruce Fields 	if (atomic_dec_and_test(&fp->fi_delegees)) {
417acfdf5c3SJ. Bruce Fields 		vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
418acfdf5c3SJ. Bruce Fields 		fp->fi_lease = NULL;
4194ee63624SJ. Bruce Fields 		fput(fp->fi_deleg_file);
420acfdf5c3SJ. Bruce Fields 		fp->fi_deleg_file = NULL;
421acfdf5c3SJ. Bruce Fields 	}
4221da177e4SLinus Torvalds }
4231da177e4SLinus Torvalds 
4246136d2b4SJ. Bruce Fields static void unhash_stid(struct nfs4_stid *s)
4256136d2b4SJ. Bruce Fields {
4263abdb607SJ. Bruce Fields 	s->sc_type = 0;
4276136d2b4SJ. Bruce Fields }
4286136d2b4SJ. Bruce Fields 
4291da177e4SLinus Torvalds /* Called under the state lock. */
4301da177e4SLinus Torvalds static void
4311da177e4SLinus Torvalds unhash_delegation(struct nfs4_delegation *dp)
4321da177e4SLinus Torvalds {
433ea1da636SNeilBrown 	list_del_init(&dp->dl_perclnt);
4341da177e4SLinus Torvalds 	spin_lock(&recall_lock);
4355d926e8cSJ. Bruce Fields 	list_del_init(&dp->dl_perfile);
4361da177e4SLinus Torvalds 	list_del_init(&dp->dl_recall_lru);
4371da177e4SLinus Torvalds 	spin_unlock(&recall_lock);
438acfdf5c3SJ. Bruce Fields 	nfs4_put_deleg_lease(dp->dl_file);
43968a33961SJ. Bruce Fields 	put_nfs4_file(dp->dl_file);
44068a33961SJ. Bruce Fields 	dp->dl_file = NULL;
4413bd64a5bSJ. Bruce Fields }
4423bd64a5bSJ. Bruce Fields 
4433bd64a5bSJ. Bruce Fields 
4443bd64a5bSJ. Bruce Fields 
4453bd64a5bSJ. Bruce Fields static void destroy_revoked_delegation(struct nfs4_delegation *dp)
4463bd64a5bSJ. Bruce Fields {
4473bd64a5bSJ. Bruce Fields 	list_del_init(&dp->dl_recall_lru);
44868a33961SJ. Bruce Fields 	remove_stid(&dp->dl_stid);
4491da177e4SLinus Torvalds 	nfs4_put_delegation(dp);
4501da177e4SLinus Torvalds }
4511da177e4SLinus Torvalds 
4523bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp)
4533bd64a5bSJ. Bruce Fields {
4543bd64a5bSJ. Bruce Fields 	unhash_delegation(dp);
4553bd64a5bSJ. Bruce Fields 	remove_stid(&dp->dl_stid);
4563bd64a5bSJ. Bruce Fields 	nfs4_put_delegation(dp);
4573bd64a5bSJ. Bruce Fields }
4583bd64a5bSJ. Bruce Fields 
4593bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp)
4603bd64a5bSJ. Bruce Fields {
4613bd64a5bSJ. Bruce Fields 	struct nfs4_client *clp = dp->dl_stid.sc_client;
4623bd64a5bSJ. Bruce Fields 
4633bd64a5bSJ. Bruce Fields 	if (clp->cl_minorversion == 0)
4643bd64a5bSJ. Bruce Fields 		destroy_delegation(dp);
4653bd64a5bSJ. Bruce Fields 	else {
4663bd64a5bSJ. Bruce Fields 		unhash_delegation(dp);
4673bd64a5bSJ. Bruce Fields 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
4683bd64a5bSJ. Bruce Fields 		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
4693bd64a5bSJ. Bruce Fields 	}
4703bd64a5bSJ. Bruce Fields }
4713bd64a5bSJ. Bruce Fields 
4721da177e4SLinus Torvalds /*
4731da177e4SLinus Torvalds  * SETCLIENTID state
4741da177e4SLinus Torvalds  */
4751da177e4SLinus Torvalds 
476ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id)
477ddc04c41SJ. Bruce Fields {
478ddc04c41SJ. Bruce Fields 	return id & CLIENT_HASH_MASK;
479ddc04c41SJ. Bruce Fields }
480ddc04c41SJ. Bruce Fields 
481ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name)
482ddc04c41SJ. Bruce Fields {
483ddc04c41SJ. Bruce Fields 	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
484ddc04c41SJ. Bruce Fields }
485ddc04c41SJ. Bruce Fields 
4861da177e4SLinus Torvalds /*
487f9d7562fSJ. Bruce Fields  * We store the NONE, READ, WRITE, and BOTH bits separately in the
488f9d7562fSJ. Bruce Fields  * st_{access,deny}_bmap field of the stateid, in order to track not
489f9d7562fSJ. Bruce Fields  * only what share bits are currently in force, but also what
490f9d7562fSJ. Bruce Fields  * combinations of share bits previous opens have used.  This allows us
491f9d7562fSJ. Bruce Fields  * to enforce the recommendation of rfc 3530 14.2.19 that the server
492f9d7562fSJ. Bruce Fields  * return an error if the client attempt to downgrade to a combination
493f9d7562fSJ. Bruce Fields  * of share bits not explicable by closing some of its previous opens.
494f9d7562fSJ. Bruce Fields  *
495f9d7562fSJ. Bruce Fields  * XXX: This enforcement is actually incomplete, since we don't keep
496f9d7562fSJ. Bruce Fields  * track of access/deny bit combinations; so, e.g., we allow:
497f9d7562fSJ. Bruce Fields  *
498f9d7562fSJ. Bruce Fields  *	OPEN allow read, deny write
499f9d7562fSJ. Bruce Fields  *	OPEN allow both, deny none
500f9d7562fSJ. Bruce Fields  *	DOWNGRADE allow read, deny none
501f9d7562fSJ. Bruce Fields  *
502f9d7562fSJ. Bruce Fields  * which we should reject.
503f9d7562fSJ. Bruce Fields  */
5045ae037e5SJeff Layton static unsigned int
5055ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) {
506f9d7562fSJ. Bruce Fields 	int i;
5075ae037e5SJeff Layton 	unsigned int access = 0;
508f9d7562fSJ. Bruce Fields 
509f9d7562fSJ. Bruce Fields 	for (i = 1; i < 4; i++) {
510f9d7562fSJ. Bruce Fields 		if (test_bit(i, &bmap))
5115ae037e5SJeff Layton 			access |= i;
512f9d7562fSJ. Bruce Fields 	}
5135ae037e5SJeff Layton 	return access;
514f9d7562fSJ. Bruce Fields }
515f9d7562fSJ. Bruce Fields 
5163a328614SJeff Layton static bool
517dcef0413SJ. Bruce Fields test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
518f9d7562fSJ. Bruce Fields 	unsigned int access, deny;
519f9d7562fSJ. Bruce Fields 
5205ae037e5SJeff Layton 	access = bmap_to_share_mode(stp->st_access_bmap);
5215ae037e5SJeff Layton 	deny = bmap_to_share_mode(stp->st_deny_bmap);
522f9d7562fSJ. Bruce Fields 	if ((access & open->op_share_deny) || (deny & open->op_share_access))
5233a328614SJeff Layton 		return false;
5243a328614SJeff Layton 	return true;
525f9d7562fSJ. Bruce Fields }
526f9d7562fSJ. Bruce Fields 
52782c5ff1bSJeff Layton /* set share access for a given stateid */
52882c5ff1bSJeff Layton static inline void
52982c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp)
53082c5ff1bSJeff Layton {
53182c5ff1bSJeff Layton 	__set_bit(access, &stp->st_access_bmap);
53282c5ff1bSJeff Layton }
53382c5ff1bSJeff Layton 
53482c5ff1bSJeff Layton /* clear share access for a given stateid */
53582c5ff1bSJeff Layton static inline void
53682c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp)
53782c5ff1bSJeff Layton {
53882c5ff1bSJeff Layton 	__clear_bit(access, &stp->st_access_bmap);
53982c5ff1bSJeff Layton }
54082c5ff1bSJeff Layton 
54182c5ff1bSJeff Layton /* test whether a given stateid has access */
54282c5ff1bSJeff Layton static inline bool
54382c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp)
54482c5ff1bSJeff Layton {
54582c5ff1bSJeff Layton 	return test_bit(access, &stp->st_access_bmap);
54682c5ff1bSJeff Layton }
54782c5ff1bSJeff Layton 
548ce0fc43cSJeff Layton /* set share deny for a given stateid */
549ce0fc43cSJeff Layton static inline void
550ce0fc43cSJeff Layton set_deny(u32 access, struct nfs4_ol_stateid *stp)
551ce0fc43cSJeff Layton {
552ce0fc43cSJeff Layton 	__set_bit(access, &stp->st_deny_bmap);
553ce0fc43cSJeff Layton }
554ce0fc43cSJeff Layton 
555ce0fc43cSJeff Layton /* clear share deny for a given stateid */
556ce0fc43cSJeff Layton static inline void
557ce0fc43cSJeff Layton clear_deny(u32 access, struct nfs4_ol_stateid *stp)
558ce0fc43cSJeff Layton {
559ce0fc43cSJeff Layton 	__clear_bit(access, &stp->st_deny_bmap);
560ce0fc43cSJeff Layton }
561ce0fc43cSJeff Layton 
562ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */
563ce0fc43cSJeff Layton static inline bool
564ce0fc43cSJeff Layton test_deny(u32 access, struct nfs4_ol_stateid *stp)
565ce0fc43cSJeff Layton {
566ce0fc43cSJeff Layton 	return test_bit(access, &stp->st_deny_bmap);
567f9d7562fSJ. Bruce Fields }
568f9d7562fSJ. Bruce Fields 
569f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access)
570f9d7562fSJ. Bruce Fields {
5718f34a430SJ. Bruce Fields 	switch (access & NFS4_SHARE_ACCESS_BOTH) {
572f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
573f9d7562fSJ. Bruce Fields 		return O_RDONLY;
574f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
575f9d7562fSJ. Bruce Fields 		return O_WRONLY;
576f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
577f9d7562fSJ. Bruce Fields 		return O_RDWR;
578f9d7562fSJ. Bruce Fields 	}
579063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(1);
580063b0fb9SJ. Bruce Fields 	return O_RDONLY;
581f9d7562fSJ. Bruce Fields }
582f9d7562fSJ. Bruce Fields 
58382c5ff1bSJeff Layton /* release all access and file references for a given stateid */
58482c5ff1bSJeff Layton static void
58582c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp)
58682c5ff1bSJeff Layton {
58782c5ff1bSJeff Layton 	int i;
58882c5ff1bSJeff Layton 
58982c5ff1bSJeff Layton 	for (i = 1; i < 4; i++) {
59082c5ff1bSJeff Layton 		if (test_access(i, stp))
59182c5ff1bSJeff Layton 			nfs4_file_put_access(stp->st_file,
59282c5ff1bSJeff Layton 					     nfs4_access_to_omode(i));
59382c5ff1bSJeff Layton 		clear_access(i, stp);
59482c5ff1bSJeff Layton 	}
59582c5ff1bSJeff Layton }
59682c5ff1bSJeff Layton 
597dcef0413SJ. Bruce Fields static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
598529d7b2aSJ. Bruce Fields {
599529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perfile);
600529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perstateowner);
601529d7b2aSJ. Bruce Fields }
602529d7b2aSJ. Bruce Fields 
603dcef0413SJ. Bruce Fields static void close_generic_stateid(struct nfs4_ol_stateid *stp)
604529d7b2aSJ. Bruce Fields {
60582c5ff1bSJeff Layton 	release_all_access(stp);
606a96e5b90SOGAWA Hirofumi 	put_nfs4_file(stp->st_file);
6074665e2baSJ. Bruce Fields 	stp->st_file = NULL;
6084665e2baSJ. Bruce Fields }
6094665e2baSJ. Bruce Fields 
610dcef0413SJ. Bruce Fields static void free_generic_stateid(struct nfs4_ol_stateid *stp)
6114665e2baSJ. Bruce Fields {
61268a33961SJ. Bruce Fields 	remove_stid(&stp->st_stid);
61368a33961SJ. Bruce Fields 	kmem_cache_free(stateid_slab, stp);
614529d7b2aSJ. Bruce Fields }
615529d7b2aSJ. Bruce Fields 
616dcef0413SJ. Bruce Fields static void release_lock_stateid(struct nfs4_ol_stateid *stp)
617529d7b2aSJ. Bruce Fields {
618529d7b2aSJ. Bruce Fields 	struct file *file;
619529d7b2aSJ. Bruce Fields 
620529d7b2aSJ. Bruce Fields 	unhash_generic_stateid(stp);
6216136d2b4SJ. Bruce Fields 	unhash_stid(&stp->st_stid);
622529d7b2aSJ. Bruce Fields 	file = find_any_file(stp->st_file);
623529d7b2aSJ. Bruce Fields 	if (file)
624fe0750e5SJ. Bruce Fields 		locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
62538c387b5SJ. Bruce Fields 	close_generic_stateid(stp);
626529d7b2aSJ. Bruce Fields 	free_generic_stateid(stp);
627529d7b2aSJ. Bruce Fields }
628529d7b2aSJ. Bruce Fields 
629fe0750e5SJ. Bruce Fields static void unhash_lockowner(struct nfs4_lockowner *lo)
630529d7b2aSJ. Bruce Fields {
631dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
632529d7b2aSJ. Bruce Fields 
633fe0750e5SJ. Bruce Fields 	list_del(&lo->lo_owner.so_strhash);
634fe0750e5SJ. Bruce Fields 	list_del(&lo->lo_perstateid);
635009673b4SJ. Bruce Fields 	list_del(&lo->lo_owner_ino_hash);
636fe0750e5SJ. Bruce Fields 	while (!list_empty(&lo->lo_owner.so_stateids)) {
637fe0750e5SJ. Bruce Fields 		stp = list_first_entry(&lo->lo_owner.so_stateids,
638dcef0413SJ. Bruce Fields 				struct nfs4_ol_stateid, st_perstateowner);
639529d7b2aSJ. Bruce Fields 		release_lock_stateid(stp);
640529d7b2aSJ. Bruce Fields 	}
641529d7b2aSJ. Bruce Fields }
642529d7b2aSJ. Bruce Fields 
643fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo)
644529d7b2aSJ. Bruce Fields {
645fe0750e5SJ. Bruce Fields 	unhash_lockowner(lo);
646fe0750e5SJ. Bruce Fields 	nfs4_free_lockowner(lo);
647529d7b2aSJ. Bruce Fields }
648529d7b2aSJ. Bruce Fields 
649529d7b2aSJ. Bruce Fields static void
650dcef0413SJ. Bruce Fields release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
651529d7b2aSJ. Bruce Fields {
652fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
653529d7b2aSJ. Bruce Fields 
654529d7b2aSJ. Bruce Fields 	while (!list_empty(&open_stp->st_lockowners)) {
655fe0750e5SJ. Bruce Fields 		lo = list_entry(open_stp->st_lockowners.next,
656fe0750e5SJ. Bruce Fields 				struct nfs4_lockowner, lo_perstateid);
657fe0750e5SJ. Bruce Fields 		release_lockowner(lo);
658529d7b2aSJ. Bruce Fields 	}
659529d7b2aSJ. Bruce Fields }
660529d7b2aSJ. Bruce Fields 
66138c387b5SJ. Bruce Fields static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
6622283963fSJ. Bruce Fields {
6632283963fSJ. Bruce Fields 	unhash_generic_stateid(stp);
6642283963fSJ. Bruce Fields 	release_stateid_lockowners(stp);
66538c387b5SJ. Bruce Fields 	close_generic_stateid(stp);
66638c387b5SJ. Bruce Fields }
66738c387b5SJ. Bruce Fields 
66838c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp)
66938c387b5SJ. Bruce Fields {
67038c387b5SJ. Bruce Fields 	unhash_open_stateid(stp);
6716136d2b4SJ. Bruce Fields 	unhash_stid(&stp->st_stid);
6722283963fSJ. Bruce Fields 	free_generic_stateid(stp);
6732283963fSJ. Bruce Fields }
6742283963fSJ. Bruce Fields 
675fe0750e5SJ. Bruce Fields static void unhash_openowner(struct nfs4_openowner *oo)
676f1d110caSJ. Bruce Fields {
677dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
678f1d110caSJ. Bruce Fields 
679fe0750e5SJ. Bruce Fields 	list_del(&oo->oo_owner.so_strhash);
680fe0750e5SJ. Bruce Fields 	list_del(&oo->oo_perclient);
681fe0750e5SJ. Bruce Fields 	while (!list_empty(&oo->oo_owner.so_stateids)) {
682fe0750e5SJ. Bruce Fields 		stp = list_first_entry(&oo->oo_owner.so_stateids,
683dcef0413SJ. Bruce Fields 				struct nfs4_ol_stateid, st_perstateowner);
684f1d110caSJ. Bruce Fields 		release_open_stateid(stp);
685f1d110caSJ. Bruce Fields 	}
686f1d110caSJ. Bruce Fields }
687f1d110caSJ. Bruce Fields 
688f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo)
689f7a4d872SJ. Bruce Fields {
690f7a4d872SJ. Bruce Fields 	struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
691f7a4d872SJ. Bruce Fields 
692f7a4d872SJ. Bruce Fields 	if (s) {
6936136d2b4SJ. Bruce Fields 		unhash_stid(&s->st_stid);
694f7a4d872SJ. Bruce Fields 		free_generic_stateid(s);
695f7a4d872SJ. Bruce Fields 		oo->oo_last_closed_stid = NULL;
696f7a4d872SJ. Bruce Fields 	}
697f7a4d872SJ. Bruce Fields }
698f7a4d872SJ. Bruce Fields 
699fe0750e5SJ. Bruce Fields static void release_openowner(struct nfs4_openowner *oo)
700f1d110caSJ. Bruce Fields {
701fe0750e5SJ. Bruce Fields 	unhash_openowner(oo);
702fe0750e5SJ. Bruce Fields 	list_del(&oo->oo_close_lru);
703f7a4d872SJ. Bruce Fields 	release_last_closed_stateid(oo);
704fe0750e5SJ. Bruce Fields 	nfs4_free_openowner(oo);
705f1d110caSJ. Bruce Fields }
706f1d110caSJ. Bruce Fields 
7075282fd72SMarc Eshel static inline int
7085282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid)
7095282fd72SMarc Eshel {
7105282fd72SMarc Eshel 	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
7115282fd72SMarc Eshel 
7125282fd72SMarc Eshel 	return sid->sequence % SESSION_HASH_SIZE;
7135282fd72SMarc Eshel }
7145282fd72SMarc Eshel 
7158f199b82STrond Myklebust #ifdef NFSD_DEBUG
7165282fd72SMarc Eshel static inline void
7175282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
7185282fd72SMarc Eshel {
7195282fd72SMarc Eshel 	u32 *ptr = (u32 *)(&sessionid->data[0]);
7205282fd72SMarc Eshel 	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
7215282fd72SMarc Eshel }
7228f199b82STrond Myklebust #else
7238f199b82STrond Myklebust static inline void
7248f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
7258f199b82STrond Myklebust {
7268f199b82STrond Myklebust }
7278f199b82STrond Myklebust #endif
7288f199b82STrond Myklebust 
7299411b1d4SJ. Bruce Fields /*
7309411b1d4SJ. Bruce Fields  * Bump the seqid on cstate->replay_owner, and clear replay_owner if it
7319411b1d4SJ. Bruce Fields  * won't be used for replay.
7329411b1d4SJ. Bruce Fields  */
7339411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
7349411b1d4SJ. Bruce Fields {
7359411b1d4SJ. Bruce Fields 	struct nfs4_stateowner *so = cstate->replay_owner;
7369411b1d4SJ. Bruce Fields 
7379411b1d4SJ. Bruce Fields 	if (nfserr == nfserr_replay_me)
7389411b1d4SJ. Bruce Fields 		return;
7399411b1d4SJ. Bruce Fields 
7409411b1d4SJ. Bruce Fields 	if (!seqid_mutating_err(ntohl(nfserr))) {
7419411b1d4SJ. Bruce Fields 		cstate->replay_owner = NULL;
7429411b1d4SJ. Bruce Fields 		return;
7439411b1d4SJ. Bruce Fields 	}
7449411b1d4SJ. Bruce Fields 	if (!so)
7459411b1d4SJ. Bruce Fields 		return;
7469411b1d4SJ. Bruce Fields 	if (so->so_is_open_owner)
7479411b1d4SJ. Bruce Fields 		release_last_closed_stateid(openowner(so));
7489411b1d4SJ. Bruce Fields 	so->so_seqid++;
7499411b1d4SJ. Bruce Fields 	return;
7509411b1d4SJ. Bruce Fields }
7515282fd72SMarc Eshel 
752ec6b5d7bSAndy Adamson static void
753ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses)
754ec6b5d7bSAndy Adamson {
755ec6b5d7bSAndy Adamson 	struct nfs4_client *clp = ses->se_client;
756ec6b5d7bSAndy Adamson 	struct nfsd4_sessionid *sid;
757ec6b5d7bSAndy Adamson 
758ec6b5d7bSAndy Adamson 	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
759ec6b5d7bSAndy Adamson 	sid->clientid = clp->cl_clientid;
760ec6b5d7bSAndy Adamson 	sid->sequence = current_sessionid++;
761ec6b5d7bSAndy Adamson 	sid->reserved = 0;
762ec6b5d7bSAndy Adamson }
763ec6b5d7bSAndy Adamson 
764ec6b5d7bSAndy Adamson /*
765a649637cSAndy Adamson  * The protocol defines ca_maxresponssize_cached to include the size of
766a649637cSAndy Adamson  * the rpc header, but all we need to cache is the data starting after
767a649637cSAndy Adamson  * the end of the initial SEQUENCE operation--the rest we regenerate
768a649637cSAndy Adamson  * each time.  Therefore we can advertise a ca_maxresponssize_cached
769a649637cSAndy Adamson  * value that is the number of bytes in our cache plus a few additional
770a649637cSAndy Adamson  * bytes.  In order to stay on the safe side, and not promise more than
771a649637cSAndy Adamson  * we can cache, those additional bytes must be the minimum possible: 24
772a649637cSAndy Adamson  * bytes of rpc header (xid through accept state, with AUTH_NULL
773a649637cSAndy Adamson  * verifier), 12 for the compound header (with zero-length tag), and 44
774a649637cSAndy Adamson  * for the SEQUENCE op response:
775ec6b5d7bSAndy Adamson  */
776a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
777a649637cSAndy Adamson 
778557ce264SAndy Adamson static void
779557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses)
780557ce264SAndy Adamson {
781557ce264SAndy Adamson 	int i;
782557ce264SAndy Adamson 
783557ce264SAndy Adamson 	for (i = 0; i < ses->se_fchannel.maxreqs; i++)
784557ce264SAndy Adamson 		kfree(ses->se_slots[i]);
785557ce264SAndy Adamson }
786557ce264SAndy Adamson 
787efe0cb6dSJ. Bruce Fields /*
788efe0cb6dSJ. Bruce Fields  * We don't actually need to cache the rpc and session headers, so we
789efe0cb6dSJ. Bruce Fields  * can allocate a little less for each slot:
790efe0cb6dSJ. Bruce Fields  */
79155c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca)
792efe0cb6dSJ. Bruce Fields {
79355c760cfSJ. Bruce Fields 	u32 size;
794efe0cb6dSJ. Bruce Fields 
79555c760cfSJ. Bruce Fields 	if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ)
79655c760cfSJ. Bruce Fields 		size = 0;
79755c760cfSJ. Bruce Fields 	else
79855c760cfSJ. Bruce Fields 		size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
79955c760cfSJ. Bruce Fields 	return size + sizeof(struct nfsd4_slot);
800557ce264SAndy Adamson }
801557ce264SAndy Adamson 
8025b6feee9SJ. Bruce Fields /*
8035b6feee9SJ. Bruce Fields  * XXX: If we run out of reserved DRC memory we could (up to a point)
8045b6feee9SJ. Bruce Fields  * re-negotiate active sessions and reduce their slot usage to make
80542b2aa86SJustin P. Mattock  * room for new connections. For now we just fail the create session.
8065b6feee9SJ. Bruce Fields  */
80755c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
8085b6feee9SJ. Bruce Fields {
80955c760cfSJ. Bruce Fields 	u32 slotsize = slot_bytes(ca);
81055c760cfSJ. Bruce Fields 	u32 num = ca->maxreqs;
8115b6feee9SJ. Bruce Fields 	int avail;
8125b6feee9SJ. Bruce Fields 
8135b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
814697ce9beSZhang Yanfei 	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
8155b6feee9SJ. Bruce Fields 		    nfsd_drc_max_mem - nfsd_drc_mem_used);
8165b6feee9SJ. Bruce Fields 	num = min_t(int, num, avail / slotsize);
8175b6feee9SJ. Bruce Fields 	nfsd_drc_mem_used += num * slotsize;
8185b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
8195b6feee9SJ. Bruce Fields 
8205b6feee9SJ. Bruce Fields 	return num;
8215b6feee9SJ. Bruce Fields }
8225b6feee9SJ. Bruce Fields 
82355c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
8245b6feee9SJ. Bruce Fields {
82555c760cfSJ. Bruce Fields 	int slotsize = slot_bytes(ca);
82655c760cfSJ. Bruce Fields 
8275b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
82855c760cfSJ. Bruce Fields 	nfsd_drc_mem_used -= slotsize * ca->maxreqs;
8295b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
8305b6feee9SJ. Bruce Fields }
8315b6feee9SJ. Bruce Fields 
83255c760cfSJ. Bruce Fields static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
8335b6feee9SJ. Bruce Fields {
83455c760cfSJ. Bruce Fields 	int numslots = attrs->maxreqs;
83555c760cfSJ. Bruce Fields 	int slotsize = slot_bytes(attrs);
8365b6feee9SJ. Bruce Fields 	struct nfsd4_session *new;
8375b6feee9SJ. Bruce Fields 	int mem, i;
838ec6b5d7bSAndy Adamson 
839c23753daSJ. Bruce Fields 	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
840ec6b5d7bSAndy Adamson 			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
8415b6feee9SJ. Bruce Fields 	mem = numslots * sizeof(struct nfsd4_slot *);
842ec6b5d7bSAndy Adamson 
8435b6feee9SJ. Bruce Fields 	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
8446c18ba9fSAlexandros Batsakis 	if (!new)
8455b6feee9SJ. Bruce Fields 		return NULL;
846ec6b5d7bSAndy Adamson 	/* allocate each struct nfsd4_slot and data cache in one piece */
8475b6feee9SJ. Bruce Fields 	for (i = 0; i < numslots; i++) {
84855c760cfSJ. Bruce Fields 		new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL);
8495b6feee9SJ. Bruce Fields 		if (!new->se_slots[i])
850ec6b5d7bSAndy Adamson 			goto out_free;
851ec6b5d7bSAndy Adamson 	}
8525b6feee9SJ. Bruce Fields 	return new;
8535b6feee9SJ. Bruce Fields out_free:
8545b6feee9SJ. Bruce Fields 	while (i--)
8555b6feee9SJ. Bruce Fields 		kfree(new->se_slots[i]);
8565b6feee9SJ. Bruce Fields 	kfree(new);
8575b6feee9SJ. Bruce Fields 	return NULL;
8585b6feee9SJ. Bruce Fields }
8595b6feee9SJ. Bruce Fields 
86019cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c)
86119cf5c02SJ. Bruce Fields {
86219cf5c02SJ. Bruce Fields 	svc_xprt_put(c->cn_xprt);
86319cf5c02SJ. Bruce Fields 	kfree(c);
86419cf5c02SJ. Bruce Fields }
86519cf5c02SJ. Bruce Fields 
86619cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u)
86719cf5c02SJ. Bruce Fields {
86819cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
86919cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = c->cn_session->se_client;
87019cf5c02SJ. Bruce Fields 
87119cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
87219cf5c02SJ. Bruce Fields 	if (!list_empty(&c->cn_persession)) {
87319cf5c02SJ. Bruce Fields 		list_del(&c->cn_persession);
87419cf5c02SJ. Bruce Fields 		free_conn(c);
87519cf5c02SJ. Bruce Fields 	}
876eea49806SJ. Bruce Fields 	nfsd4_probe_callback(clp);
8772e4b7239SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
87819cf5c02SJ. Bruce Fields }
87919cf5c02SJ. Bruce Fields 
880d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
881c7662518SJ. Bruce Fields {
882c7662518SJ. Bruce Fields 	struct nfsd4_conn *conn;
883c7662518SJ. Bruce Fields 
884c7662518SJ. Bruce Fields 	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
885c7662518SJ. Bruce Fields 	if (!conn)
886db90681dSJ. Bruce Fields 		return NULL;
887c7662518SJ. Bruce Fields 	svc_xprt_get(rqstp->rq_xprt);
888c7662518SJ. Bruce Fields 	conn->cn_xprt = rqstp->rq_xprt;
889d29c374cSJ. Bruce Fields 	conn->cn_flags = flags;
890db90681dSJ. Bruce Fields 	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
891db90681dSJ. Bruce Fields 	return conn;
892db90681dSJ. Bruce Fields }
893db90681dSJ. Bruce Fields 
894328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
895328ead28SJ. Bruce Fields {
896328ead28SJ. Bruce Fields 	conn->cn_session = ses;
897328ead28SJ. Bruce Fields 	list_add(&conn->cn_persession, &ses->se_conns);
898328ead28SJ. Bruce Fields }
899328ead28SJ. Bruce Fields 
900db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
901db90681dSJ. Bruce Fields {
902db90681dSJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
903c7662518SJ. Bruce Fields 
904c7662518SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
905328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(conn, ses);
906c7662518SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
907db90681dSJ. Bruce Fields }
908c7662518SJ. Bruce Fields 
90921b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn)
910db90681dSJ. Bruce Fields {
91119cf5c02SJ. Bruce Fields 	conn->cn_xpt_user.callback = nfsd4_conn_lost;
91221b75b01SJ. Bruce Fields 	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
913db90681dSJ. Bruce Fields }
914db90681dSJ. Bruce Fields 
915e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
916db90681dSJ. Bruce Fields {
91721b75b01SJ. Bruce Fields 	int ret;
918db90681dSJ. Bruce Fields 
919db90681dSJ. Bruce Fields 	nfsd4_hash_conn(conn, ses);
92021b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(conn);
92121b75b01SJ. Bruce Fields 	if (ret)
92221b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
92321b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&conn->cn_xpt_user);
9246a3b1563SJ. Bruce Fields 	if (conn->cn_flags & NFS4_CDFC4_BACK) {
92524119673SWeston Andros Adamson 		/* callback channel may be back up */
92624119673SWeston Andros Adamson 		nfsd4_probe_callback(ses->se_client);
92724119673SWeston Andros Adamson 	}
928c7662518SJ. Bruce Fields }
929c7662518SJ. Bruce Fields 
930e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
9311d1bc8f2SJ. Bruce Fields {
9321d1bc8f2SJ. Bruce Fields 	u32 dir = NFS4_CDFC4_FORE;
9331d1bc8f2SJ. Bruce Fields 
934e1ff371fSJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN)
9351d1bc8f2SJ. Bruce Fields 		dir |= NFS4_CDFC4_BACK;
936e1ff371fSJ. Bruce Fields 	return alloc_conn(rqstp, dir);
9371d1bc8f2SJ. Bruce Fields }
9381d1bc8f2SJ. Bruce Fields 
9391d1bc8f2SJ. Bruce Fields /* must be called under client_lock */
94019cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s)
941c7662518SJ. Bruce Fields {
94219cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = s->se_client;
94319cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c;
94419cf5c02SJ. Bruce Fields 
94519cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
94619cf5c02SJ. Bruce Fields 	while (!list_empty(&s->se_conns)) {
94719cf5c02SJ. Bruce Fields 		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
94819cf5c02SJ. Bruce Fields 		list_del_init(&c->cn_persession);
94919cf5c02SJ. Bruce Fields 		spin_unlock(&clp->cl_lock);
95019cf5c02SJ. Bruce Fields 
95119cf5c02SJ. Bruce Fields 		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
95219cf5c02SJ. Bruce Fields 		free_conn(c);
95319cf5c02SJ. Bruce Fields 
95419cf5c02SJ. Bruce Fields 		spin_lock(&clp->cl_lock);
95519cf5c02SJ. Bruce Fields 	}
95619cf5c02SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
957c7662518SJ. Bruce Fields }
958c7662518SJ. Bruce Fields 
9591377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses)
9601377b69eSJ. Bruce Fields {
9611377b69eSJ. Bruce Fields 	free_session_slots(ses);
9621377b69eSJ. Bruce Fields 	kfree(ses);
9631377b69eSJ. Bruce Fields }
9641377b69eSJ. Bruce Fields 
96566b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses)
966508dc6e1SBenny Halevy {
967c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id);
968c9a49628SStanislav Kinsbursky 
969c7662518SJ. Bruce Fields 	lockdep_assert_held(&nn->client_lock);
970c7662518SJ. Bruce Fields 	nfsd4_del_conns(ses);
97155c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&ses->se_fchannel);
972c7662518SJ. Bruce Fields 	__free_session(ses);
973a827bcb2SJ. Bruce Fields }
974ec6b5d7bSAndy Adamson 
975135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
976a827bcb2SJ. Bruce Fields {
977a827bcb2SJ. Bruce Fields 	int idx;
9781872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
979a827bcb2SJ. Bruce Fields 
980ec6b5d7bSAndy Adamson 	new->se_client = clp;
981ec6b5d7bSAndy Adamson 	gen_sessionid(new);
982ec6b5d7bSAndy Adamson 
983c7662518SJ. Bruce Fields 	INIT_LIST_HEAD(&new->se_conns);
984c7662518SJ. Bruce Fields 
985ac7c46f2SJ. Bruce Fields 	new->se_cb_seq_nr = 1;
986ec6b5d7bSAndy Adamson 	new->se_flags = cses->flags;
9878b5ce5cdSJ. Bruce Fields 	new->se_cb_prog = cses->callback_prog;
988c6bb3ca2SJ. Bruce Fields 	new->se_cb_sec = cses->cb_sec;
98966b2b9b2SJ. Bruce Fields 	atomic_set(&new->se_ref, 0);
9905b6feee9SJ. Bruce Fields 	idx = hash_sessionid(&new->se_sessionid);
991c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
9921872de0eSStanislav Kinsbursky 	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
9934c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
994ec6b5d7bSAndy Adamson 	list_add(&new->se_perclnt, &clp->cl_sessions);
9954c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
996c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
99755c760cfSJ. Bruce Fields 	memcpy(&new->se_fchannel, &cses->fore_channel,
99855c760cfSJ. Bruce Fields 			sizeof(struct nfsd4_channel_attrs));
999dcbeaa68SJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN) {
1000edd76786SJ. Bruce Fields 		struct sockaddr *sa = svc_addr(rqstp);
1001dcbeaa68SJ. Bruce Fields 		/*
1002dcbeaa68SJ. Bruce Fields 		 * This is a little silly; with sessions there's no real
1003dcbeaa68SJ. Bruce Fields 		 * use for the callback address.  Use the peer address
1004dcbeaa68SJ. Bruce Fields 		 * as a reasonable default for now, but consider fixing
1005dcbeaa68SJ. Bruce Fields 		 * the rpc client not to require an address in the
1006dcbeaa68SJ. Bruce Fields 		 * future:
1007dcbeaa68SJ. Bruce Fields 		 */
1008edd76786SJ. Bruce Fields 		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
1009edd76786SJ. Bruce Fields 		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
1010edd76786SJ. Bruce Fields 	}
1011ec6b5d7bSAndy Adamson }
1012ec6b5d7bSAndy Adamson 
10139089f1b4SBenny Halevy /* caller must hold client_lock */
10145282fd72SMarc Eshel static struct nfsd4_session *
10151872de0eSStanislav Kinsbursky find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
10165282fd72SMarc Eshel {
10175282fd72SMarc Eshel 	struct nfsd4_session *elem;
10185282fd72SMarc Eshel 	int idx;
10191872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
10205282fd72SMarc Eshel 
10215282fd72SMarc Eshel 	dump_sessionid(__func__, sessionid);
10225282fd72SMarc Eshel 	idx = hash_sessionid(sessionid);
10235282fd72SMarc Eshel 	/* Search in the appropriate list */
10241872de0eSStanislav Kinsbursky 	list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) {
10255282fd72SMarc Eshel 		if (!memcmp(elem->se_sessionid.data, sessionid->data,
10265282fd72SMarc Eshel 			    NFS4_MAX_SESSIONID_LEN)) {
10275282fd72SMarc Eshel 			return elem;
10285282fd72SMarc Eshel 		}
10295282fd72SMarc Eshel 	}
10305282fd72SMarc Eshel 
10315282fd72SMarc Eshel 	dprintk("%s: session not found\n", __func__);
10325282fd72SMarc Eshel 	return NULL;
10335282fd72SMarc Eshel }
10345282fd72SMarc Eshel 
10359089f1b4SBenny Halevy /* caller must hold client_lock */
10367116ed6bSAndy Adamson static void
10375282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses)
10387116ed6bSAndy Adamson {
10397116ed6bSAndy Adamson 	list_del(&ses->se_hash);
10404c649378SJ. Bruce Fields 	spin_lock(&ses->se_client->cl_lock);
10417116ed6bSAndy Adamson 	list_del(&ses->se_perclnt);
10424c649378SJ. Bruce Fields 	spin_unlock(&ses->se_client->cl_lock);
10435282fd72SMarc Eshel }
10445282fd72SMarc Eshel 
10451da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
10461da177e4SLinus Torvalds static int
10472c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
10481da177e4SLinus Torvalds {
10492c142baaSStanislav Kinsbursky 	if (clid->cl_boot == nn->boot_time)
10501da177e4SLinus Torvalds 		return 0;
105160adfc50SAndy Adamson 	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
10522c142baaSStanislav Kinsbursky 		clid->cl_boot, clid->cl_id, nn->boot_time);
10531da177e4SLinus Torvalds 	return 1;
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds /*
10571da177e4SLinus Torvalds  * XXX Should we use a slab cache ?
10581da177e4SLinus Torvalds  * This type of memory management is somewhat inefficient, but we use it
10591da177e4SLinus Torvalds  * anyway since SETCLIENTID is not a common operation.
10601da177e4SLinus Torvalds  */
106135bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name)
10621da177e4SLinus Torvalds {
10631da177e4SLinus Torvalds 	struct nfs4_client *clp;
10641da177e4SLinus Torvalds 
106535bba9a3SJ. Bruce Fields 	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
106635bba9a3SJ. Bruce Fields 	if (clp == NULL)
106735bba9a3SJ. Bruce Fields 		return NULL;
106867114fe6SThomas Meyer 	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
106935bba9a3SJ. Bruce Fields 	if (clp->cl_name.data == NULL) {
107035bba9a3SJ. Bruce Fields 		kfree(clp);
107135bba9a3SJ. Bruce Fields 		return NULL;
107235bba9a3SJ. Bruce Fields 	}
10731da177e4SLinus Torvalds 	clp->cl_name.len = name.len;
10741da177e4SLinus Torvalds 	return clp;
10751da177e4SLinus Torvalds }
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds static inline void
10781da177e4SLinus Torvalds free_client(struct nfs4_client *clp)
10791da177e4SLinus Torvalds {
1080bca0ec65SStanislav Kinsbursky 	struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id);
1081c9a49628SStanislav Kinsbursky 
1082c9a49628SStanislav Kinsbursky 	lockdep_assert_held(&nn->client_lock);
1083792c95ddSJ. Bruce Fields 	while (!list_empty(&clp->cl_sessions)) {
1084792c95ddSJ. Bruce Fields 		struct nfsd4_session *ses;
1085792c95ddSJ. Bruce Fields 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
1086792c95ddSJ. Bruce Fields 				se_perclnt);
1087792c95ddSJ. Bruce Fields 		list_del(&ses->se_perclnt);
108866b2b9b2SJ. Bruce Fields 		WARN_ON_ONCE(atomic_read(&ses->se_ref));
108966b2b9b2SJ. Bruce Fields 		free_session(ses);
1090792c95ddSJ. Bruce Fields 	}
109103a4e1f6SJ. Bruce Fields 	free_svc_cred(&clp->cl_cred);
10921da177e4SLinus Torvalds 	kfree(clp->cl_name.data);
10932d32b29aSmajianpeng 	idr_destroy(&clp->cl_stateids);
10941da177e4SLinus Torvalds 	kfree(clp);
10951da177e4SLinus Torvalds }
10961da177e4SLinus Torvalds 
109784d38ac9SBenny Halevy /* must be called under the client_lock */
109884d38ac9SBenny Halevy static inline void
109984d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp)
110084d38ac9SBenny Halevy {
1101792c95ddSJ. Bruce Fields 	struct nfsd4_session *ses;
1102792c95ddSJ. Bruce Fields 
110384d38ac9SBenny Halevy 	list_del(&clp->cl_lru);
11044c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1105792c95ddSJ. Bruce Fields 	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
1106792c95ddSJ. Bruce Fields 		list_del_init(&ses->se_hash);
11074c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
110884d38ac9SBenny Halevy }
110984d38ac9SBenny Halevy 
11101da177e4SLinus Torvalds static void
11110d22f68fSJ. Bruce Fields destroy_client(struct nfs4_client *clp)
11121da177e4SLinus Torvalds {
1113fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
11141da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
11151da177e4SLinus Torvalds 	struct list_head reaplist;
1116382a62e7SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
11191da177e4SLinus Torvalds 	spin_lock(&recall_lock);
1120ea1da636SNeilBrown 	while (!list_empty(&clp->cl_delegations)) {
1121ea1da636SNeilBrown 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
1122ea1da636SNeilBrown 		list_del_init(&dp->dl_perclnt);
11231da177e4SLinus Torvalds 		list_move(&dp->dl_recall_lru, &reaplist);
11241da177e4SLinus Torvalds 	}
11251da177e4SLinus Torvalds 	spin_unlock(&recall_lock);
11261da177e4SLinus Torvalds 	while (!list_empty(&reaplist)) {
11271da177e4SLinus Torvalds 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
11283bd64a5bSJ. Bruce Fields 		destroy_delegation(dp);
11291da177e4SLinus Torvalds 	}
1130ea1da636SNeilBrown 	while (!list_empty(&clp->cl_openowners)) {
1131fe0750e5SJ. Bruce Fields 		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
1132fe0750e5SJ. Bruce Fields 		release_openowner(oo);
11331da177e4SLinus Torvalds 	}
11346ff8da08SJ. Bruce Fields 	nfsd4_shutdown_callback(clp);
11352bf23875SJ. Bruce Fields 	if (clp->cl_cb_conn.cb_xprt)
11362bf23875SJ. Bruce Fields 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
113784d38ac9SBenny Halevy 	list_del(&clp->cl_idhash);
1138ac55fdc4SJeff Layton 	if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
1139382a62e7SStanislav Kinsbursky 		rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
1140ac55fdc4SJeff Layton 	else
1141a99454aaSStanislav Kinsbursky 		rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
1142c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
114384d38ac9SBenny Halevy 	unhash_client_locked(clp);
1144221a6876SJ. Bruce Fields 	WARN_ON_ONCE(atomic_read(&clp->cl_refcount));
1145b12a05cbSJ. Bruce Fields 	free_client(clp);
1146c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
11471da177e4SLinus Torvalds }
11481da177e4SLinus Torvalds 
11490d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp)
11500d22f68fSJ. Bruce Fields {
11510d22f68fSJ. Bruce Fields 	nfsd4_client_record_remove(clp);
11520d22f68fSJ. Bruce Fields 	destroy_client(clp);
11530d22f68fSJ. Bruce Fields }
11540d22f68fSJ. Bruce Fields 
115535bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
115635bba9a3SJ. Bruce Fields {
115735bba9a3SJ. Bruce Fields 	memcpy(target->cl_verifier.data, source->data,
115835bba9a3SJ. Bruce Fields 			sizeof(target->cl_verifier.data));
11591da177e4SLinus Torvalds }
11601da177e4SLinus Torvalds 
116135bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
116235bba9a3SJ. Bruce Fields {
11631da177e4SLinus Torvalds 	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
11641da177e4SLinus Torvalds 	target->cl_clientid.cl_id = source->cl_clientid.cl_id;
11651da177e4SLinus Torvalds }
11661da177e4SLinus Torvalds 
116703a4e1f6SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source)
116835bba9a3SJ. Bruce Fields {
116903a4e1f6SJ. Bruce Fields 	if (source->cr_principal) {
117003a4e1f6SJ. Bruce Fields 		target->cr_principal =
117103a4e1f6SJ. Bruce Fields 				kstrdup(source->cr_principal, GFP_KERNEL);
117203a4e1f6SJ. Bruce Fields 		if (target->cr_principal == NULL)
117303a4e1f6SJ. Bruce Fields 			return -ENOMEM;
117403a4e1f6SJ. Bruce Fields 	} else
117503a4e1f6SJ. Bruce Fields 		target->cr_principal = NULL;
1176d5497fc6SJ. Bruce Fields 	target->cr_flavor = source->cr_flavor;
11771da177e4SLinus Torvalds 	target->cr_uid = source->cr_uid;
11781da177e4SLinus Torvalds 	target->cr_gid = source->cr_gid;
11791da177e4SLinus Torvalds 	target->cr_group_info = source->cr_group_info;
11801da177e4SLinus Torvalds 	get_group_info(target->cr_group_info);
11810dc1531aSJ. Bruce Fields 	target->cr_gss_mech = source->cr_gss_mech;
11820dc1531aSJ. Bruce Fields 	if (source->cr_gss_mech)
11830dc1531aSJ. Bruce Fields 		gss_mech_get(source->cr_gss_mech);
118403a4e1f6SJ. Bruce Fields 	return 0;
11851da177e4SLinus Torvalds }
11861da177e4SLinus Torvalds 
1187ac55fdc4SJeff Layton static long long
1188ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
1189ac55fdc4SJeff Layton {
1190ac55fdc4SJeff Layton 	long long res;
1191ac55fdc4SJeff Layton 
1192ac55fdc4SJeff Layton 	res = o1->len - o2->len;
1193ac55fdc4SJeff Layton 	if (res)
1194ac55fdc4SJeff Layton 		return res;
1195ac55fdc4SJeff Layton 	return (long long)memcmp(o1->data, o2->data, o1->len);
1196ac55fdc4SJeff Layton }
1197ac55fdc4SJeff Layton 
119835bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2)
1199599e0a22SJ. Bruce Fields {
1200a55370a3SNeilBrown 	return 0 == memcmp(n1, n2, HEXDIR_LEN);
12011da177e4SLinus Torvalds }
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds static int
1204599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
1205599e0a22SJ. Bruce Fields {
1206599e0a22SJ. Bruce Fields 	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
12071da177e4SLinus Torvalds }
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds static int
1210599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2)
1211599e0a22SJ. Bruce Fields {
1212599e0a22SJ. Bruce Fields 	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
12131da177e4SLinus Torvalds }
12141da177e4SLinus Torvalds 
12158fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2)
12168fbba96eSJ. Bruce Fields {
12178fbba96eSJ. Bruce Fields 	int i;
12188fbba96eSJ. Bruce Fields 
12198fbba96eSJ. Bruce Fields 	if (g1->ngroups != g2->ngroups)
12208fbba96eSJ. Bruce Fields 		return false;
12218fbba96eSJ. Bruce Fields 	for (i=0; i<g1->ngroups; i++)
12226fab8779SEric W. Biederman 		if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i)))
12238fbba96eSJ. Bruce Fields 			return false;
12248fbba96eSJ. Bruce Fields 	return true;
12258fbba96eSJ. Bruce Fields }
12268fbba96eSJ. Bruce Fields 
122768eb3508SJ. Bruce Fields /*
122868eb3508SJ. Bruce Fields  * RFC 3530 language requires clid_inuse be returned when the
122968eb3508SJ. Bruce Fields  * "principal" associated with a requests differs from that previously
123068eb3508SJ. Bruce Fields  * used.  We use uid, gid's, and gss principal string as our best
123168eb3508SJ. Bruce Fields  * approximation.  We also don't want to allow non-gss use of a client
123268eb3508SJ. Bruce Fields  * established using gss: in theory cr_principal should catch that
123368eb3508SJ. Bruce Fields  * change, but in practice cr_principal can be null even in the gss case
123468eb3508SJ. Bruce Fields  * since gssd doesn't always pass down a principal string.
123568eb3508SJ. Bruce Fields  */
123668eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr)
123768eb3508SJ. Bruce Fields {
123868eb3508SJ. Bruce Fields 	/* Is cr_flavor one of the gss "pseudoflavors"?: */
123968eb3508SJ. Bruce Fields 	return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
124068eb3508SJ. Bruce Fields }
124168eb3508SJ. Bruce Fields 
124268eb3508SJ. Bruce Fields 
12435559b50aSVivek Trivedi static bool
1244599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
1245599e0a22SJ. Bruce Fields {
124668eb3508SJ. Bruce Fields 	if ((is_gss_cred(cr1) != is_gss_cred(cr2))
12476fab8779SEric W. Biederman 		|| (!uid_eq(cr1->cr_uid, cr2->cr_uid))
12486fab8779SEric W. Biederman 		|| (!gid_eq(cr1->cr_gid, cr2->cr_gid))
12498fbba96eSJ. Bruce Fields 		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
12508fbba96eSJ. Bruce Fields 		return false;
12518fbba96eSJ. Bruce Fields 	if (cr1->cr_principal == cr2->cr_principal)
12528fbba96eSJ. Bruce Fields 		return true;
12538fbba96eSJ. Bruce Fields 	if (!cr1->cr_principal || !cr2->cr_principal)
12548fbba96eSJ. Bruce Fields 		return false;
12555559b50aSVivek Trivedi 	return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
12561da177e4SLinus Torvalds }
12571da177e4SLinus Torvalds 
125857266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
125957266a6eSJ. Bruce Fields {
126057266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
126157266a6eSJ. Bruce Fields 	u32 service;
126257266a6eSJ. Bruce Fields 
1263c4720591SJ. Bruce Fields 	if (!cr->cr_gss_mech)
1264c4720591SJ. Bruce Fields 		return false;
126557266a6eSJ. Bruce Fields 	service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
126657266a6eSJ. Bruce Fields 	return service == RPC_GSS_SVC_INTEGRITY ||
126757266a6eSJ. Bruce Fields 	       service == RPC_GSS_SVC_PRIVACY;
126857266a6eSJ. Bruce Fields }
126957266a6eSJ. Bruce Fields 
127057266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
127157266a6eSJ. Bruce Fields {
127257266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
127357266a6eSJ. Bruce Fields 
127457266a6eSJ. Bruce Fields 	if (!cl->cl_mach_cred)
127557266a6eSJ. Bruce Fields 		return true;
127657266a6eSJ. Bruce Fields 	if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
127757266a6eSJ. Bruce Fields 		return false;
127857266a6eSJ. Bruce Fields 	if (!svc_rqst_integrity_protected(rqstp))
127957266a6eSJ. Bruce Fields 		return false;
128057266a6eSJ. Bruce Fields 	if (!cr->cr_principal)
128157266a6eSJ. Bruce Fields 		return false;
128257266a6eSJ. Bruce Fields 	return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
128357266a6eSJ. Bruce Fields }
128457266a6eSJ. Bruce Fields 
1285c212cecfSStanislav Kinsbursky static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
12865ec7b46cSJ. Bruce Fields {
12875ec7b46cSJ. Bruce Fields 	static u32 current_clientid = 1;
12885ec7b46cSJ. Bruce Fields 
12892c142baaSStanislav Kinsbursky 	clp->cl_clientid.cl_boot = nn->boot_time;
12901da177e4SLinus Torvalds 	clp->cl_clientid.cl_id = current_clientid++;
12911da177e4SLinus Torvalds }
12921da177e4SLinus Torvalds 
1293deda2faaSJ. Bruce Fields static void gen_confirm(struct nfs4_client *clp)
1294deda2faaSJ. Bruce Fields {
1295ab4684d1SChuck Lever 	__be32 verf[2];
1296deda2faaSJ. Bruce Fields 	static u32 i;
12971da177e4SLinus Torvalds 
1298ab4684d1SChuck Lever 	verf[0] = (__be32)get_seconds();
1299ab4684d1SChuck Lever 	verf[1] = (__be32)i++;
1300ab4684d1SChuck Lever 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
13011da177e4SLinus Torvalds }
13021da177e4SLinus Torvalds 
130338c2f4b1SJ. Bruce Fields static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
13044581d140SJ. Bruce Fields {
13053abdb607SJ. Bruce Fields 	struct nfs4_stid *ret;
13063abdb607SJ. Bruce Fields 
13073abdb607SJ. Bruce Fields 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
13083abdb607SJ. Bruce Fields 	if (!ret || !ret->sc_type)
13093abdb607SJ. Bruce Fields 		return NULL;
13103abdb607SJ. Bruce Fields 	return ret;
13114581d140SJ. Bruce Fields }
13124d71ab87SJ. Bruce Fields 
131338c2f4b1SJ. Bruce Fields static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
1314f459e453SJ. Bruce Fields {
1315f459e453SJ. Bruce Fields 	struct nfs4_stid *s;
1316f459e453SJ. Bruce Fields 
131738c2f4b1SJ. Bruce Fields 	s = find_stateid(cl, t);
1318f459e453SJ. Bruce Fields 	if (!s)
1319f459e453SJ. Bruce Fields 		return NULL;
1320f459e453SJ. Bruce Fields 	if (typemask & s->sc_type)
13214d71ab87SJ. Bruce Fields 		return s;
13224581d140SJ. Bruce Fields 	return NULL;
13234581d140SJ. Bruce Fields }
13244581d140SJ. Bruce Fields 
13252216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name,
1326b09333c4SRicardo Labiaga 		struct svc_rqst *rqstp, nfs4_verifier *verf)
1327b09333c4SRicardo Labiaga {
1328b09333c4SRicardo Labiaga 	struct nfs4_client *clp;
1329b09333c4SRicardo Labiaga 	struct sockaddr *sa = svc_addr(rqstp);
133003a4e1f6SJ. Bruce Fields 	int ret;
1331c212cecfSStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
1332c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1333b09333c4SRicardo Labiaga 
1334b09333c4SRicardo Labiaga 	clp = alloc_client(name);
1335b09333c4SRicardo Labiaga 	if (clp == NULL)
1336b09333c4SRicardo Labiaga 		return NULL;
1337b09333c4SRicardo Labiaga 
1338792c95ddSJ. Bruce Fields 	INIT_LIST_HEAD(&clp->cl_sessions);
133903a4e1f6SJ. Bruce Fields 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
134003a4e1f6SJ. Bruce Fields 	if (ret) {
1341c9a49628SStanislav Kinsbursky 		spin_lock(&nn->client_lock);
1342b09333c4SRicardo Labiaga 		free_client(clp);
1343c9a49628SStanislav Kinsbursky 		spin_unlock(&nn->client_lock);
1344b09333c4SRicardo Labiaga 		return NULL;
1345b09333c4SRicardo Labiaga 	}
134638c2f4b1SJ. Bruce Fields 	idr_init(&clp->cl_stateids);
134746583e25SBenny Halevy 	atomic_set(&clp->cl_refcount, 0);
134877a3569dSJ. Bruce Fields 	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
1349b09333c4SRicardo Labiaga 	INIT_LIST_HEAD(&clp->cl_idhash);
1350b09333c4SRicardo Labiaga 	INIT_LIST_HEAD(&clp->cl_openowners);
1351b09333c4SRicardo Labiaga 	INIT_LIST_HEAD(&clp->cl_delegations);
1352b09333c4SRicardo Labiaga 	INIT_LIST_HEAD(&clp->cl_lru);
13535ce8ba25SJ. Bruce Fields 	INIT_LIST_HEAD(&clp->cl_callbacks);
13543bd64a5bSJ. Bruce Fields 	INIT_LIST_HEAD(&clp->cl_revoked);
13556ff8da08SJ. Bruce Fields 	spin_lock_init(&clp->cl_lock);
135657725155SJ. Bruce Fields 	nfsd4_init_callback(&clp->cl_cb_null);
135707cd4909SBenny Halevy 	clp->cl_time = get_seconds();
1358b09333c4SRicardo Labiaga 	clear_bit(0, &clp->cl_cb_slot_busy);
1359b09333c4SRicardo Labiaga 	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
1360b09333c4SRicardo Labiaga 	copy_verf(clp, verf);
1361b09333c4SRicardo Labiaga 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
1362b09333c4SRicardo Labiaga 	gen_confirm(clp);
1363edd76786SJ. Bruce Fields 	clp->cl_cb_session = NULL;
1364c212cecfSStanislav Kinsbursky 	clp->net = net;
1365b09333c4SRicardo Labiaga 	return clp;
1366b09333c4SRicardo Labiaga }
1367b09333c4SRicardo Labiaga 
1368fd39ca9aSNeilBrown static void
1369ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
1370ac55fdc4SJeff Layton {
1371ac55fdc4SJeff Layton 	struct rb_node **new = &(root->rb_node), *parent = NULL;
1372ac55fdc4SJeff Layton 	struct nfs4_client *clp;
1373ac55fdc4SJeff Layton 
1374ac55fdc4SJeff Layton 	while (*new) {
1375ac55fdc4SJeff Layton 		clp = rb_entry(*new, struct nfs4_client, cl_namenode);
1376ac55fdc4SJeff Layton 		parent = *new;
1377ac55fdc4SJeff Layton 
1378ac55fdc4SJeff Layton 		if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
1379ac55fdc4SJeff Layton 			new = &((*new)->rb_left);
1380ac55fdc4SJeff Layton 		else
1381ac55fdc4SJeff Layton 			new = &((*new)->rb_right);
1382ac55fdc4SJeff Layton 	}
1383ac55fdc4SJeff Layton 
1384ac55fdc4SJeff Layton 	rb_link_node(&new_clp->cl_namenode, parent, new);
1385ac55fdc4SJeff Layton 	rb_insert_color(&new_clp->cl_namenode, root);
1386ac55fdc4SJeff Layton }
1387ac55fdc4SJeff Layton 
1388ac55fdc4SJeff Layton static struct nfs4_client *
1389ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
1390ac55fdc4SJeff Layton {
1391ac55fdc4SJeff Layton 	long long cmp;
1392ac55fdc4SJeff Layton 	struct rb_node *node = root->rb_node;
1393ac55fdc4SJeff Layton 	struct nfs4_client *clp;
1394ac55fdc4SJeff Layton 
1395ac55fdc4SJeff Layton 	while (node) {
1396ac55fdc4SJeff Layton 		clp = rb_entry(node, struct nfs4_client, cl_namenode);
1397ac55fdc4SJeff Layton 		cmp = compare_blob(&clp->cl_name, name);
1398ac55fdc4SJeff Layton 		if (cmp > 0)
1399ac55fdc4SJeff Layton 			node = node->rb_left;
1400ac55fdc4SJeff Layton 		else if (cmp < 0)
1401ac55fdc4SJeff Layton 			node = node->rb_right;
1402ac55fdc4SJeff Layton 		else
1403ac55fdc4SJeff Layton 			return clp;
1404ac55fdc4SJeff Layton 	}
1405ac55fdc4SJeff Layton 	return NULL;
1406ac55fdc4SJeff Layton }
1407ac55fdc4SJeff Layton 
1408ac55fdc4SJeff Layton static void
1409ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp)
14101da177e4SLinus Torvalds {
14111da177e4SLinus Torvalds 	unsigned int idhashval;
14120a7ec377SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
14131da177e4SLinus Torvalds 
1414ac55fdc4SJeff Layton 	clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
1415a99454aaSStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
14161da177e4SLinus Torvalds 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
14170a7ec377SStanislav Kinsbursky 	list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
141836acb66bSBenny Halevy 	renew_client(clp);
14191da177e4SLinus Torvalds }
14201da177e4SLinus Torvalds 
1421fd39ca9aSNeilBrown static void
14221da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp)
14231da177e4SLinus Torvalds {
14241da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
14258daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
14288daae4dcSStanislav Kinsbursky 	list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
1429a99454aaSStanislav Kinsbursky 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
1430382a62e7SStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->conf_name_tree);
1431ac55fdc4SJeff Layton 	set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
14321da177e4SLinus Torvalds 	renew_client(clp);
14331da177e4SLinus Torvalds }
14341da177e4SLinus Torvalds 
14351da177e4SLinus Torvalds static struct nfs4_client *
1436bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
14371da177e4SLinus Torvalds {
14381da177e4SLinus Torvalds 	struct nfs4_client *clp;
14391da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clid->cl_id);
14401da177e4SLinus Torvalds 
1441bfa85e83SJ. Bruce Fields 	list_for_each_entry(clp, &tbl[idhashval], cl_idhash) {
1442a50d2ad1SJ. Bruce Fields 		if (same_clid(&clp->cl_clientid, clid)) {
1443d15c077eSJ. Bruce Fields 			if ((bool)clp->cl_minorversion != sessions)
1444d15c077eSJ. Bruce Fields 				return NULL;
1445a50d2ad1SJ. Bruce Fields 			renew_client(clp);
14461da177e4SLinus Torvalds 			return clp;
14471da177e4SLinus Torvalds 		}
1448a50d2ad1SJ. Bruce Fields 	}
14491da177e4SLinus Torvalds 	return NULL;
14501da177e4SLinus Torvalds }
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds static struct nfs4_client *
1453bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
1454bfa85e83SJ. Bruce Fields {
1455bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->conf_id_hashtbl;
1456bfa85e83SJ. Bruce Fields 
1457bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
1458bfa85e83SJ. Bruce Fields }
1459bfa85e83SJ. Bruce Fields 
1460bfa85e83SJ. Bruce Fields static struct nfs4_client *
14610a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
14621da177e4SLinus Torvalds {
1463bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->unconf_id_hashtbl;
14641da177e4SLinus Torvalds 
1465bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
14661da177e4SLinus Torvalds }
14671da177e4SLinus Torvalds 
14686e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp)
1469a1bcecd2SAndy Adamson {
14706e5f15c9SJ. Bruce Fields 	return clp->cl_exchange_flags != 0;
1471a1bcecd2SAndy Adamson }
1472a1bcecd2SAndy Adamson 
147328ce6054SNeilBrown static struct nfs4_client *
1474382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
147528ce6054SNeilBrown {
1476382a62e7SStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->conf_name_tree);
147728ce6054SNeilBrown }
147828ce6054SNeilBrown 
147928ce6054SNeilBrown static struct nfs4_client *
1480a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
148128ce6054SNeilBrown {
1482a99454aaSStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->unconf_name_tree);
148328ce6054SNeilBrown }
148428ce6054SNeilBrown 
1485fd39ca9aSNeilBrown static void
14866f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
14871da177e4SLinus Torvalds {
148807263f1eSJ. Bruce Fields 	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
14896f3d772fSTakuma Umeya 	struct sockaddr	*sa = svc_addr(rqstp);
14906f3d772fSTakuma Umeya 	u32 scopeid = rpc_get_scope_id(sa);
14917077ecbaSJeff Layton 	unsigned short expected_family;
14921da177e4SLinus Torvalds 
14937077ecbaSJeff Layton 	/* Currently, we only support tcp and tcp6 for the callback channel */
14947077ecbaSJeff Layton 	if (se->se_callback_netid_len == 3 &&
14957077ecbaSJeff Layton 	    !memcmp(se->se_callback_netid_val, "tcp", 3))
14967077ecbaSJeff Layton 		expected_family = AF_INET;
14977077ecbaSJeff Layton 	else if (se->se_callback_netid_len == 4 &&
14987077ecbaSJeff Layton 		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
14997077ecbaSJeff Layton 		expected_family = AF_INET6;
15007077ecbaSJeff Layton 	else
15011da177e4SLinus Torvalds 		goto out_err;
15021da177e4SLinus Torvalds 
1503c212cecfSStanislav Kinsbursky 	conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val,
1504aa9a4ec7SJeff Layton 					    se->se_callback_addr_len,
150507263f1eSJ. Bruce Fields 					    (struct sockaddr *)&conn->cb_addr,
150607263f1eSJ. Bruce Fields 					    sizeof(conn->cb_addr));
1507aa9a4ec7SJeff Layton 
150807263f1eSJ. Bruce Fields 	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
15091da177e4SLinus Torvalds 		goto out_err;
1510aa9a4ec7SJeff Layton 
151107263f1eSJ. Bruce Fields 	if (conn->cb_addr.ss_family == AF_INET6)
151207263f1eSJ. Bruce Fields 		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
1513fbf4665fSJeff Layton 
151407263f1eSJ. Bruce Fields 	conn->cb_prog = se->se_callback_prog;
151507263f1eSJ. Bruce Fields 	conn->cb_ident = se->se_callback_ident;
1516849a1cf1SMi Jinlong 	memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
15171da177e4SLinus Torvalds 	return;
15181da177e4SLinus Torvalds out_err:
151907263f1eSJ. Bruce Fields 	conn->cb_addr.ss_family = AF_UNSPEC;
152007263f1eSJ. Bruce Fields 	conn->cb_addrlen = 0;
1521849823c5SNeil Brown 	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
15221da177e4SLinus Torvalds 		"will not receive delegations\n",
15231da177e4SLinus Torvalds 		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
15241da177e4SLinus Torvalds 
15251da177e4SLinus Torvalds 	return;
15261da177e4SLinus Torvalds }
15271da177e4SLinus Torvalds 
1528074fe897SAndy Adamson /*
1529557ce264SAndy Adamson  * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size.
1530074fe897SAndy Adamson  */
1531074fe897SAndy Adamson void
1532074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
1533074fe897SAndy Adamson {
1534557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
1535557ce264SAndy Adamson 	unsigned int base;
1536074fe897SAndy Adamson 
1537557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
1538074fe897SAndy Adamson 
1539557ce264SAndy Adamson 	slot->sl_opcnt = resp->opcnt;
1540557ce264SAndy Adamson 	slot->sl_status = resp->cstate.status;
1541bf864a31SAndy Adamson 
1542bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
1543bf864a31SAndy Adamson 	if (nfsd4_not_cached(resp)) {
1544557ce264SAndy Adamson 		slot->sl_datalen = 0;
1545bf864a31SAndy Adamson 		return;
1546bf864a31SAndy Adamson 	}
1547557ce264SAndy Adamson 	slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap;
1548557ce264SAndy Adamson 	base = (char *)resp->cstate.datap -
1549557ce264SAndy Adamson 					(char *)resp->xbuf->head[0].iov_base;
1550557ce264SAndy Adamson 	if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data,
1551557ce264SAndy Adamson 				    slot->sl_datalen))
1552557ce264SAndy Adamson 		WARN("%s: sessions DRC could not cache compound\n", __func__);
1553557ce264SAndy Adamson 	return;
1554074fe897SAndy Adamson }
1555074fe897SAndy Adamson 
1556074fe897SAndy Adamson /*
1557abfabf8cSAndy Adamson  * Encode the replay sequence operation from the slot values.
1558abfabf8cSAndy Adamson  * If cachethis is FALSE encode the uncached rep error on the next
1559abfabf8cSAndy Adamson  * operation which sets resp->p and increments resp->opcnt for
1560abfabf8cSAndy Adamson  * nfs4svc_encode_compoundres.
1561abfabf8cSAndy Adamson  *
1562074fe897SAndy Adamson  */
1563abfabf8cSAndy Adamson static __be32
1564abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
1565abfabf8cSAndy Adamson 			  struct nfsd4_compoundres *resp)
1566074fe897SAndy Adamson {
1567abfabf8cSAndy Adamson 	struct nfsd4_op *op;
1568abfabf8cSAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
1569074fe897SAndy Adamson 
1570abfabf8cSAndy Adamson 	/* Encode the replayed sequence operation */
1571abfabf8cSAndy Adamson 	op = &args->ops[resp->opcnt - 1];
1572abfabf8cSAndy Adamson 	nfsd4_encode_operation(resp, op);
1573abfabf8cSAndy Adamson 
1574abfabf8cSAndy Adamson 	/* Return nfserr_retry_uncached_rep in next operation. */
157573e79482SJ. Bruce Fields 	if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
1576abfabf8cSAndy Adamson 		op = &args->ops[resp->opcnt++];
1577abfabf8cSAndy Adamson 		op->status = nfserr_retry_uncached_rep;
1578abfabf8cSAndy Adamson 		nfsd4_encode_operation(resp, op);
1579074fe897SAndy Adamson 	}
1580abfabf8cSAndy Adamson 	return op->status;
1581074fe897SAndy Adamson }
1582074fe897SAndy Adamson 
1583074fe897SAndy Adamson /*
1584557ce264SAndy Adamson  * The sequence operation is not cached because we can use the slot and
1585557ce264SAndy Adamson  * session values.
1586074fe897SAndy Adamson  */
1587074fe897SAndy Adamson __be32
1588bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
1589bf864a31SAndy Adamson 			 struct nfsd4_sequence *seq)
1590074fe897SAndy Adamson {
1591557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
1592074fe897SAndy Adamson 	__be32 status;
1593074fe897SAndy Adamson 
1594557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
1595074fe897SAndy Adamson 
1596abfabf8cSAndy Adamson 	/* Either returns 0 or nfserr_retry_uncached */
1597abfabf8cSAndy Adamson 	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
1598abfabf8cSAndy Adamson 	if (status == nfserr_retry_uncached_rep)
1599abfabf8cSAndy Adamson 		return status;
1600074fe897SAndy Adamson 
1601557ce264SAndy Adamson 	/* The sequence operation has been encoded, cstate->datap set. */
1602557ce264SAndy Adamson 	memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen);
1603074fe897SAndy Adamson 
1604557ce264SAndy Adamson 	resp->opcnt = slot->sl_opcnt;
1605557ce264SAndy Adamson 	resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen);
1606557ce264SAndy Adamson 	status = slot->sl_status;
1607074fe897SAndy Adamson 
1608074fe897SAndy Adamson 	return status;
1609074fe897SAndy Adamson }
1610074fe897SAndy Adamson 
16110733d213SAndy Adamson /*
16120733d213SAndy Adamson  * Set the exchange_id flags returned by the server.
16130733d213SAndy Adamson  */
16140733d213SAndy Adamson static void
16150733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
16160733d213SAndy Adamson {
16170733d213SAndy Adamson 	/* pNFS is not supported */
16180733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
16190733d213SAndy Adamson 
16200733d213SAndy Adamson 	/* Referrals are supported, Migration is not. */
16210733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
16220733d213SAndy Adamson 
16230733d213SAndy Adamson 	/* set the wire flags to return to client. */
16240733d213SAndy Adamson 	clid->flags = new->cl_exchange_flags;
16250733d213SAndy Adamson }
16260733d213SAndy Adamson 
1627631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp)
1628631fc9eaSJ. Bruce Fields {
1629631fc9eaSJ. Bruce Fields 	/*
1630631fc9eaSJ. Bruce Fields 	 * Note clp->cl_openowners check isn't quite right: there's no
1631631fc9eaSJ. Bruce Fields 	 * need to count owners without stateid's.
1632631fc9eaSJ. Bruce Fields 	 *
1633631fc9eaSJ. Bruce Fields 	 * Also note we should probably be using this in 4.0 case too.
1634631fc9eaSJ. Bruce Fields 	 */
16356eccece9SJ. Bruce Fields 	return !list_empty(&clp->cl_openowners)
16366eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_delegations)
16376eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_sessions);
1638631fc9eaSJ. Bruce Fields }
1639631fc9eaSJ. Bruce Fields 
1640b37ad28bSAl Viro __be32
1641069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp,
1642069b6ad4SAndy Adamson 		  struct nfsd4_compound_state *cstate,
1643069b6ad4SAndy Adamson 		  struct nfsd4_exchange_id *exid)
1644069b6ad4SAndy Adamson {
16450733d213SAndy Adamson 	struct nfs4_client *unconf, *conf, *new;
164657b7b43bSJ. Bruce Fields 	__be32 status;
1647363168b4SJeff Layton 	char			addr_str[INET6_ADDRSTRLEN];
16480733d213SAndy Adamson 	nfs4_verifier		verf = exid->verifier;
1649363168b4SJeff Layton 	struct sockaddr		*sa = svc_addr(rqstp);
165083e08fd4SJ. Bruce Fields 	bool	update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A;
1651c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
16520733d213SAndy Adamson 
1653363168b4SJeff Layton 	rpc_ntop(sa, addr_str, sizeof(addr_str));
16540733d213SAndy Adamson 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
1655363168b4SJeff Layton 		"ip_addr=%s flags %x, spa_how %d\n",
16560733d213SAndy Adamson 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
1657363168b4SJeff Layton 		addr_str, exid->flags, exid->spa_how);
16580733d213SAndy Adamson 
1659a084daf5SJ. Bruce Fields 	if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
16600733d213SAndy Adamson 		return nfserr_inval;
16610733d213SAndy Adamson 
16620733d213SAndy Adamson 	switch (exid->spa_how) {
166357266a6eSJ. Bruce Fields 	case SP4_MACH_CRED:
166457266a6eSJ. Bruce Fields 		if (!svc_rqst_integrity_protected(rqstp))
166557266a6eSJ. Bruce Fields 			return nfserr_inval;
16660733d213SAndy Adamson 	case SP4_NONE:
16670733d213SAndy Adamson 		break;
1668063b0fb9SJ. Bruce Fields 	default:				/* checked by xdr code */
1669063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
16700733d213SAndy Adamson 	case SP4_SSV:
1671dd30333cSJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
16720733d213SAndy Adamson 	}
16730733d213SAndy Adamson 
16742dbb269dSJ. Bruce Fields 	/* Cases below refer to rfc 5661 section 18.35.4: */
16750733d213SAndy Adamson 	nfs4_lock_state();
1676382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&exid->clname, nn);
16770733d213SAndy Adamson 	if (conf) {
167883e08fd4SJ. Bruce Fields 		bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
167983e08fd4SJ. Bruce Fields 		bool verfs_match = same_verf(&verf, &conf->cl_verifier);
168083e08fd4SJ. Bruce Fields 
1681136e658dSJ. Bruce Fields 		if (update) {
1682136e658dSJ. Bruce Fields 			if (!clp_used_exchangeid(conf)) { /* buggy client */
16832dbb269dSJ. Bruce Fields 				status = nfserr_inval;
1684e203d506SJ. Bruce Fields 				goto out;
1685e203d506SJ. Bruce Fields 			}
168657266a6eSJ. Bruce Fields 			if (!mach_creds_match(conf, rqstp)) {
168757266a6eSJ. Bruce Fields 				status = nfserr_wrong_cred;
168857266a6eSJ. Bruce Fields 				goto out;
168957266a6eSJ. Bruce Fields 			}
16902dbb269dSJ. Bruce Fields 			if (!creds_match) { /* case 9 */
16910733d213SAndy Adamson 				status = nfserr_perm;
16920733d213SAndy Adamson 				goto out;
16930733d213SAndy Adamson 			}
16942dbb269dSJ. Bruce Fields 			if (!verfs_match) { /* case 8 */
16950733d213SAndy Adamson 				status = nfserr_not_same;
16960733d213SAndy Adamson 				goto out;
16970733d213SAndy Adamson 			}
1698136e658dSJ. Bruce Fields 			/* case 6 */
16990733d213SAndy Adamson 			exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
17000733d213SAndy Adamson 			new = conf;
17010733d213SAndy Adamson 			goto out_copy;
17026ddbbbfeSMike Sager 		}
1703136e658dSJ. Bruce Fields 		if (!creds_match) { /* case 3 */
1704631fc9eaSJ. Bruce Fields 			if (client_has_state(conf)) {
1705136e658dSJ. Bruce Fields 				status = nfserr_clid_inuse;
1706136e658dSJ. Bruce Fields 				goto out;
1707136e658dSJ. Bruce Fields 			}
1708b9831b59SJ. Bruce Fields 			expire_client(conf);
1709b9831b59SJ. Bruce Fields 			goto out_new;
1710631fc9eaSJ. Bruce Fields 		}
1711136e658dSJ. Bruce Fields 		if (verfs_match) { /* case 2 */
17120f1ba0efSJ. Bruce Fields 			conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
1713136e658dSJ. Bruce Fields 			new = conf;
1714136e658dSJ. Bruce Fields 			goto out_copy;
1715136e658dSJ. Bruce Fields 		}
17162dbb269dSJ. Bruce Fields 		/* case 5, client reboot */
17170733d213SAndy Adamson 		goto out_new;
17180733d213SAndy Adamson 	}
17196ddbbbfeSMike Sager 
17202dbb269dSJ. Bruce Fields 	if (update) { /* case 7 */
17210733d213SAndy Adamson 		status = nfserr_noent;
17220733d213SAndy Adamson 		goto out;
17230733d213SAndy Adamson 	}
17240733d213SAndy Adamson 
1725a99454aaSStanislav Kinsbursky 	unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
17262dbb269dSJ. Bruce Fields 	if (unconf) /* case 4, possible retry or client restart */
17270733d213SAndy Adamson 		expire_client(unconf);
17280733d213SAndy Adamson 
17292dbb269dSJ. Bruce Fields 	/* case 1 (normal case) */
17300733d213SAndy Adamson out_new:
17312216d449SJeff Layton 	new = create_client(exid->clname, rqstp, &verf);
17320733d213SAndy Adamson 	if (new == NULL) {
17334731030dSJ. Bruce Fields 		status = nfserr_jukebox;
17340733d213SAndy Adamson 		goto out;
17350733d213SAndy Adamson 	}
17364f540e29SJ. Bruce Fields 	new->cl_minorversion = cstate->minorversion;
173757266a6eSJ. Bruce Fields 	new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
17380733d213SAndy Adamson 
1739c212cecfSStanislav Kinsbursky 	gen_clid(new, nn);
1740ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
17410733d213SAndy Adamson out_copy:
17420733d213SAndy Adamson 	exid->clientid.cl_boot = new->cl_clientid.cl_boot;
17430733d213SAndy Adamson 	exid->clientid.cl_id = new->cl_clientid.cl_id;
17440733d213SAndy Adamson 
1745778df3f0SJ. Bruce Fields 	exid->seqid = new->cl_cs_slot.sl_seqid + 1;
17460733d213SAndy Adamson 	nfsd4_set_ex_flags(new, exid);
17470733d213SAndy Adamson 
17480733d213SAndy Adamson 	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
174949557cc7SAndy Adamson 		new->cl_cs_slot.sl_seqid, new->cl_exchange_flags);
17500733d213SAndy Adamson 	status = nfs_ok;
17510733d213SAndy Adamson 
17520733d213SAndy Adamson out:
17530733d213SAndy Adamson 	nfs4_unlock_state();
17540733d213SAndy Adamson 	return status;
1755069b6ad4SAndy Adamson }
1756069b6ad4SAndy Adamson 
175757b7b43bSJ. Bruce Fields static __be32
175888e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
1759b85d4c01SBenny Halevy {
176088e588d5SAndy Adamson 	dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
176188e588d5SAndy Adamson 		slot_seqid);
1762b85d4c01SBenny Halevy 
1763b85d4c01SBenny Halevy 	/* The slot is in use, and no response has been sent. */
176488e588d5SAndy Adamson 	if (slot_inuse) {
176588e588d5SAndy Adamson 		if (seqid == slot_seqid)
1766b85d4c01SBenny Halevy 			return nfserr_jukebox;
1767b85d4c01SBenny Halevy 		else
1768b85d4c01SBenny Halevy 			return nfserr_seq_misordered;
1769b85d4c01SBenny Halevy 	}
1770f6d82485SJ. Bruce Fields 	/* Note unsigned 32-bit arithmetic handles wraparound: */
177188e588d5SAndy Adamson 	if (likely(seqid == slot_seqid + 1))
1772b85d4c01SBenny Halevy 		return nfs_ok;
177388e588d5SAndy Adamson 	if (seqid == slot_seqid)
1774b85d4c01SBenny Halevy 		return nfserr_replay_cache;
1775b85d4c01SBenny Halevy 	return nfserr_seq_misordered;
1776b85d4c01SBenny Halevy }
1777b85d4c01SBenny Halevy 
177849557cc7SAndy Adamson /*
177949557cc7SAndy Adamson  * Cache the create session result into the create session single DRC
178049557cc7SAndy Adamson  * slot cache by saving the xdr structure. sl_seqid has been set.
178149557cc7SAndy Adamson  * Do this for solo or embedded create session operations.
178249557cc7SAndy Adamson  */
178349557cc7SAndy Adamson static void
178449557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
178557b7b43bSJ. Bruce Fields 			   struct nfsd4_clid_slot *slot, __be32 nfserr)
178649557cc7SAndy Adamson {
178749557cc7SAndy Adamson 	slot->sl_status = nfserr;
178849557cc7SAndy Adamson 	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
178949557cc7SAndy Adamson }
179049557cc7SAndy Adamson 
179149557cc7SAndy Adamson static __be32
179249557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
179349557cc7SAndy Adamson 			    struct nfsd4_clid_slot *slot)
179449557cc7SAndy Adamson {
179549557cc7SAndy Adamson 	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
179649557cc7SAndy Adamson 	return slot->sl_status;
179749557cc7SAndy Adamson }
179849557cc7SAndy Adamson 
17991b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
18001b74c25bSMi Jinlong 			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
18011b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
18021b74c25bSMi Jinlong 			3 +	/* version, opcount, opcode */ \
18031b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
18041b74c25bSMi Jinlong 				/* seqid, slotID, slotID, cache */ \
18051b74c25bSMi Jinlong 			4 ) * sizeof(__be32))
18061b74c25bSMi Jinlong 
18071b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
18081b74c25bSMi Jinlong 			2 +	/* verifier: AUTH_NULL, length 0 */\
18091b74c25bSMi Jinlong 			1 +	/* status */ \
18101b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
18111b74c25bSMi Jinlong 			3 +	/* opcount, opcode, opstatus*/ \
18121b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
18131b74c25bSMi Jinlong 				/* seqid, slotID, slotID, slotID, status */ \
18141b74c25bSMi Jinlong 			5 ) * sizeof(__be32))
18151b74c25bSMi Jinlong 
181655c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn)
18171b74c25bSMi Jinlong {
181855c760cfSJ. Bruce Fields 	u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
181955c760cfSJ. Bruce Fields 
1820373cd409SJ. Bruce Fields 	if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
1821373cd409SJ. Bruce Fields 		return nfserr_toosmall;
1822373cd409SJ. Bruce Fields 	if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
1823373cd409SJ. Bruce Fields 		return nfserr_toosmall;
182455c760cfSJ. Bruce Fields 	ca->headerpadsz = 0;
182555c760cfSJ. Bruce Fields 	ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
182655c760cfSJ. Bruce Fields 	ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
182755c760cfSJ. Bruce Fields 	ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
182855c760cfSJ. Bruce Fields 	ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
182955c760cfSJ. Bruce Fields 			NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
183055c760cfSJ. Bruce Fields 	ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
183155c760cfSJ. Bruce Fields 	/*
183255c760cfSJ. Bruce Fields 	 * Note decreasing slot size below client's request may make it
183355c760cfSJ. Bruce Fields 	 * difficult for client to function correctly, whereas
183455c760cfSJ. Bruce Fields 	 * decreasing the number of slots will (just?) affect
183555c760cfSJ. Bruce Fields 	 * performance.  When short on memory we therefore prefer to
183655c760cfSJ. Bruce Fields 	 * decrease number of slots instead of their size.  Clients that
183755c760cfSJ. Bruce Fields 	 * request larger slots than they need will get poor results:
183855c760cfSJ. Bruce Fields 	 */
183955c760cfSJ. Bruce Fields 	ca->maxreqs = nfsd4_get_drc_mem(ca);
184055c760cfSJ. Bruce Fields 	if (!ca->maxreqs)
184155c760cfSJ. Bruce Fields 		return nfserr_jukebox;
184255c760cfSJ. Bruce Fields 
1843373cd409SJ. Bruce Fields 	return nfs_ok;
18441b74c25bSMi Jinlong }
18451b74c25bSMi Jinlong 
184606b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
184706b332a5SJ. Bruce Fields {
184806b332a5SJ. Bruce Fields 	ca->headerpadsz = 0;
184906b332a5SJ. Bruce Fields 
185006b332a5SJ. Bruce Fields 	/*
185106b332a5SJ. Bruce Fields 	 * These RPC_MAX_HEADER macros are overkill, especially since we
185206b332a5SJ. Bruce Fields 	 * don't even do gss on the backchannel yet.  But this is still
185306b332a5SJ. Bruce Fields 	 * less than 1k.  Tighten up this estimate in the unlikely event
185406b332a5SJ. Bruce Fields 	 * it turns out to be a problem for some client:
185506b332a5SJ. Bruce Fields 	 */
185606b332a5SJ. Bruce Fields 	if (ca->maxreq_sz < NFS4_enc_cb_recall_sz + RPC_MAX_HEADER_WITH_AUTH)
185706b332a5SJ. Bruce Fields 		return nfserr_toosmall;
185806b332a5SJ. Bruce Fields 	if (ca->maxresp_sz < NFS4_dec_cb_recall_sz + RPC_MAX_REPHEADER_WITH_AUTH)
185906b332a5SJ. Bruce Fields 		return nfserr_toosmall;
186006b332a5SJ. Bruce Fields 	ca->maxresp_cached = 0;
186106b332a5SJ. Bruce Fields 	if (ca->maxops < 2)
186206b332a5SJ. Bruce Fields 		return nfserr_toosmall;
186306b332a5SJ. Bruce Fields 
186406b332a5SJ. Bruce Fields 	return nfs_ok;
1865069b6ad4SAndy Adamson }
1866069b6ad4SAndy Adamson 
1867b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
1868b78724b7SJ. Bruce Fields {
1869b78724b7SJ. Bruce Fields 	switch (cbs->flavor) {
1870b78724b7SJ. Bruce Fields 	case RPC_AUTH_NULL:
1871b78724b7SJ. Bruce Fields 	case RPC_AUTH_UNIX:
1872b78724b7SJ. Bruce Fields 		return nfs_ok;
1873b78724b7SJ. Bruce Fields 	default:
1874b78724b7SJ. Bruce Fields 		/*
1875b78724b7SJ. Bruce Fields 		 * GSS case: the spec doesn't allow us to return this
1876b78724b7SJ. Bruce Fields 		 * error.  But it also doesn't allow us not to support
1877b78724b7SJ. Bruce Fields 		 * GSS.
1878b78724b7SJ. Bruce Fields 		 * I'd rather this fail hard than return some error the
1879b78724b7SJ. Bruce Fields 		 * client might think it can already handle:
1880b78724b7SJ. Bruce Fields 		 */
1881b78724b7SJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
1882b78724b7SJ. Bruce Fields 	}
1883b78724b7SJ. Bruce Fields }
1884b78724b7SJ. Bruce Fields 
1885069b6ad4SAndy Adamson __be32
1886069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp,
1887069b6ad4SAndy Adamson 		     struct nfsd4_compound_state *cstate,
1888069b6ad4SAndy Adamson 		     struct nfsd4_create_session *cr_ses)
1889069b6ad4SAndy Adamson {
1890363168b4SJeff Layton 	struct sockaddr *sa = svc_addr(rqstp);
1891ec6b5d7bSAndy Adamson 	struct nfs4_client *conf, *unconf;
1892ac7c46f2SJ. Bruce Fields 	struct nfsd4_session *new;
189381f0b2a4SJ. Bruce Fields 	struct nfsd4_conn *conn;
189449557cc7SAndy Adamson 	struct nfsd4_clid_slot *cs_slot = NULL;
189557b7b43bSJ. Bruce Fields 	__be32 status = 0;
18968daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1897ec6b5d7bSAndy Adamson 
1898a62573dcSMi Jinlong 	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
1899a62573dcSMi Jinlong 		return nfserr_inval;
1900b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
1901b78724b7SJ. Bruce Fields 	if (status)
1902b78724b7SJ. Bruce Fields 		return status;
190355c760cfSJ. Bruce Fields 	status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
1904373cd409SJ. Bruce Fields 	if (status)
1905373cd409SJ. Bruce Fields 		return status;
190606b332a5SJ. Bruce Fields 	status = check_backchannel_attrs(&cr_ses->back_channel);
190706b332a5SJ. Bruce Fields 	if (status)
190806b332a5SJ. Bruce Fields 		return status;
190981f0b2a4SJ. Bruce Fields 	status = nfserr_jukebox;
191055c760cfSJ. Bruce Fields 	new = alloc_session(&cr_ses->fore_channel);
191155c760cfSJ. Bruce Fields 	if (!new)
191255c760cfSJ. Bruce Fields 		goto out_release_drc_mem;
191381f0b2a4SJ. Bruce Fields 	conn = alloc_conn_from_crses(rqstp, cr_ses);
191481f0b2a4SJ. Bruce Fields 	if (!conn)
191581f0b2a4SJ. Bruce Fields 		goto out_free_session;
1916a62573dcSMi Jinlong 
1917ec6b5d7bSAndy Adamson 	nfs4_lock_state();
19180a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
19198daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
192078389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
1921ec6b5d7bSAndy Adamson 
1922ec6b5d7bSAndy Adamson 	if (conf) {
192357266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
192457266a6eSJ. Bruce Fields 		if (!mach_creds_match(conf, rqstp))
192557266a6eSJ. Bruce Fields 			goto out_free_conn;
192649557cc7SAndy Adamson 		cs_slot = &conf->cl_cs_slot;
192749557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
192838eb76a5SAndy Adamson 		if (status == nfserr_replay_cache) {
192949557cc7SAndy Adamson 			status = nfsd4_replay_create_session(cr_ses, cs_slot);
193081f0b2a4SJ. Bruce Fields 			goto out_free_conn;
193149557cc7SAndy Adamson 		} else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
1932ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
193381f0b2a4SJ. Bruce Fields 			goto out_free_conn;
1934ec6b5d7bSAndy Adamson 		}
1935ec6b5d7bSAndy Adamson 	} else if (unconf) {
19368f9d3d3bSJ. Bruce Fields 		struct nfs4_client *old;
1937ec6b5d7bSAndy Adamson 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
1938363168b4SJeff Layton 		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
1939ec6b5d7bSAndy Adamson 			status = nfserr_clid_inuse;
194081f0b2a4SJ. Bruce Fields 			goto out_free_conn;
1941ec6b5d7bSAndy Adamson 		}
194257266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
194357266a6eSJ. Bruce Fields 		if (!mach_creds_match(unconf, rqstp))
194457266a6eSJ. Bruce Fields 			goto out_free_conn;
194549557cc7SAndy Adamson 		cs_slot = &unconf->cl_cs_slot;
194649557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
194738eb76a5SAndy Adamson 		if (status) {
194838eb76a5SAndy Adamson 			/* an unconfirmed replay returns misordered */
1949ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
195081f0b2a4SJ. Bruce Fields 			goto out_free_conn;
1951ec6b5d7bSAndy Adamson 		}
1952382a62e7SStanislav Kinsbursky 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
1953221a6876SJ. Bruce Fields 		if (old) {
1954221a6876SJ. Bruce Fields 			status = mark_client_expired(old);
1955221a6876SJ. Bruce Fields 			if (status)
1956221a6876SJ. Bruce Fields 				goto out_free_conn;
19578f9d3d3bSJ. Bruce Fields 			expire_client(old);
1958221a6876SJ. Bruce Fields 		}
19598f9d3d3bSJ. Bruce Fields 		move_to_confirmed(unconf);
1960ec6b5d7bSAndy Adamson 		conf = unconf;
1961ec6b5d7bSAndy Adamson 	} else {
1962ec6b5d7bSAndy Adamson 		status = nfserr_stale_clientid;
196381f0b2a4SJ. Bruce Fields 		goto out_free_conn;
1964ec6b5d7bSAndy Adamson 	}
196581f0b2a4SJ. Bruce Fields 	status = nfs_ok;
19668323c3b2SJ. Bruce Fields 	/*
1967408b79bcSJ. Bruce Fields 	 * We do not support RDMA or persistent sessions
1968408b79bcSJ. Bruce Fields 	 */
1969408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_PERSIST;
1970408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_RDMA;
1971408b79bcSJ. Bruce Fields 
197281f0b2a4SJ. Bruce Fields 	init_session(rqstp, new, conf, cr_ses);
197381f0b2a4SJ. Bruce Fields 	nfsd4_init_conn(rqstp, conn, new);
197481f0b2a4SJ. Bruce Fields 
1975ac7c46f2SJ. Bruce Fields 	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
1976ec6b5d7bSAndy Adamson 	       NFS4_MAX_SESSIONID_LEN);
197786c3e16cSJ. Bruce Fields 	cs_slot->sl_seqid++;
197849557cc7SAndy Adamson 	cr_ses->seqid = cs_slot->sl_seqid;
1979ec6b5d7bSAndy Adamson 
198049557cc7SAndy Adamson 	/* cache solo and embedded create sessions under the state lock */
198149557cc7SAndy Adamson 	nfsd4_cache_create_session(cr_ses, cs_slot, status);
1982ec6b5d7bSAndy Adamson 	nfs4_unlock_state();
1983ec6b5d7bSAndy Adamson 	return status;
198481f0b2a4SJ. Bruce Fields out_free_conn:
1985266533c6SYanchuan Nian 	nfs4_unlock_state();
198681f0b2a4SJ. Bruce Fields 	free_conn(conn);
198781f0b2a4SJ. Bruce Fields out_free_session:
198881f0b2a4SJ. Bruce Fields 	__free_session(new);
198955c760cfSJ. Bruce Fields out_release_drc_mem:
199055c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&cr_ses->fore_channel);
19911ca50792SJ. Bruce Fields 	return status;
1992069b6ad4SAndy Adamson }
1993069b6ad4SAndy Adamson 
19941d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir)
19951d1bc8f2SJ. Bruce Fields {
19961d1bc8f2SJ. Bruce Fields 	switch (*dir) {
19971d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE:
19981d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK:
19991d1bc8f2SJ. Bruce Fields 		return nfs_ok;
20001d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE_OR_BOTH:
20011d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK_OR_BOTH:
20021d1bc8f2SJ. Bruce Fields 		*dir = NFS4_CDFC4_BOTH;
20031d1bc8f2SJ. Bruce Fields 		return nfs_ok;
20041d1bc8f2SJ. Bruce Fields 	};
20051d1bc8f2SJ. Bruce Fields 	return nfserr_inval;
20061d1bc8f2SJ. Bruce Fields }
20071d1bc8f2SJ. Bruce Fields 
2008cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc)
2009cb73a9f4SJ. Bruce Fields {
2010cb73a9f4SJ. Bruce Fields 	struct nfsd4_session *session = cstate->session;
2011c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2012b78724b7SJ. Bruce Fields 	__be32 status;
2013cb73a9f4SJ. Bruce Fields 
2014b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
2015b78724b7SJ. Bruce Fields 	if (status)
2016b78724b7SJ. Bruce Fields 		return status;
2017c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2018cb73a9f4SJ. Bruce Fields 	session->se_cb_prog = bc->bc_cb_program;
2019cb73a9f4SJ. Bruce Fields 	session->se_cb_sec = bc->bc_cb_sec;
2020c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2021cb73a9f4SJ. Bruce Fields 
2022cb73a9f4SJ. Bruce Fields 	nfsd4_probe_callback(session->se_client);
2023cb73a9f4SJ. Bruce Fields 
2024cb73a9f4SJ. Bruce Fields 	return nfs_ok;
2025cb73a9f4SJ. Bruce Fields }
2026cb73a9f4SJ. Bruce Fields 
20271d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
20281d1bc8f2SJ. Bruce Fields 		     struct nfsd4_compound_state *cstate,
20291d1bc8f2SJ. Bruce Fields 		     struct nfsd4_bind_conn_to_session *bcts)
20301d1bc8f2SJ. Bruce Fields {
20311d1bc8f2SJ. Bruce Fields 	__be32 status;
20323ba63671SJ. Bruce Fields 	struct nfsd4_conn *conn;
20334f6e6c17SJ. Bruce Fields 	struct nfsd4_session *session;
2034c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
20351d1bc8f2SJ. Bruce Fields 
20361d1bc8f2SJ. Bruce Fields 	if (!nfsd4_last_compound_op(rqstp))
20371d1bc8f2SJ. Bruce Fields 		return nfserr_not_only_op;
20384f6e6c17SJ. Bruce Fields 	nfs4_lock_state();
2039c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
20404f6e6c17SJ. Bruce Fields 	session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp));
2041c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
20424f6e6c17SJ. Bruce Fields 	status = nfserr_badsession;
20434f6e6c17SJ. Bruce Fields 	if (!session)
20444f6e6c17SJ. Bruce Fields 		goto out;
204557266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
204657266a6eSJ. Bruce Fields 	if (!mach_creds_match(session->se_client, rqstp))
204757266a6eSJ. Bruce Fields 		goto out;
20481d1bc8f2SJ. Bruce Fields 	status = nfsd4_map_bcts_dir(&bcts->dir);
20493ba63671SJ. Bruce Fields 	if (status)
20504f6e6c17SJ. Bruce Fields 		goto out;
20513ba63671SJ. Bruce Fields 	conn = alloc_conn(rqstp, bcts->dir);
20524f6e6c17SJ. Bruce Fields 	status = nfserr_jukebox;
20533ba63671SJ. Bruce Fields 	if (!conn)
20544f6e6c17SJ. Bruce Fields 		goto out;
20554f6e6c17SJ. Bruce Fields 	nfsd4_init_conn(rqstp, conn, session);
20564f6e6c17SJ. Bruce Fields 	status = nfs_ok;
20574f6e6c17SJ. Bruce Fields out:
20584f6e6c17SJ. Bruce Fields 	nfs4_unlock_state();
20594f6e6c17SJ. Bruce Fields 	return status;
20601d1bc8f2SJ. Bruce Fields }
20611d1bc8f2SJ. Bruce Fields 
20625d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
20635d4cec2fSJ. Bruce Fields {
20645d4cec2fSJ. Bruce Fields 	if (!session)
20655d4cec2fSJ. Bruce Fields 		return 0;
20665d4cec2fSJ. Bruce Fields 	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
20675d4cec2fSJ. Bruce Fields }
20685d4cec2fSJ. Bruce Fields 
2069069b6ad4SAndy Adamson __be32
2070069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r,
2071069b6ad4SAndy Adamson 		      struct nfsd4_compound_state *cstate,
2072069b6ad4SAndy Adamson 		      struct nfsd4_destroy_session *sessionid)
2073069b6ad4SAndy Adamson {
2074e10e0cfcSBenny Halevy 	struct nfsd4_session *ses;
2075abcdff09SJ. Bruce Fields 	__be32 status;
2076f0f51f5cSJ. Bruce Fields 	int ref_held_by_me = 0;
2077c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
2078e10e0cfcSBenny Halevy 
2079abcdff09SJ. Bruce Fields 	nfs4_lock_state();
2080abcdff09SJ. Bruce Fields 	status = nfserr_not_only_op;
20815d4cec2fSJ. Bruce Fields 	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
208257716355SJ. Bruce Fields 		if (!nfsd4_last_compound_op(r))
2083abcdff09SJ. Bruce Fields 			goto out;
2084f0f51f5cSJ. Bruce Fields 		ref_held_by_me++;
208557716355SJ. Bruce Fields 	}
2086e10e0cfcSBenny Halevy 	dump_sessionid(__func__, &sessionid->sessionid);
2087c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
20881872de0eSStanislav Kinsbursky 	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r));
2089abcdff09SJ. Bruce Fields 	status = nfserr_badsession;
2090abcdff09SJ. Bruce Fields 	if (!ses)
2091abcdff09SJ. Bruce Fields 		goto out_client_lock;
209257266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
209357266a6eSJ. Bruce Fields 	if (!mach_creds_match(ses->se_client, r))
209466b2b9b2SJ. Bruce Fields 		goto out_client_lock;
2095f0f51f5cSJ. Bruce Fields 	nfsd4_get_session_locked(ses);
2096f0f51f5cSJ. Bruce Fields 	status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
2097e10e0cfcSBenny Halevy 	if (status)
2098f0f51f5cSJ. Bruce Fields 		goto out_put_session;
2099e10e0cfcSBenny Halevy 	unhash_session(ses);
2100c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2101e10e0cfcSBenny Halevy 
210284f5f7ccSJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
210319cf5c02SJ. Bruce Fields 
2104c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2105e10e0cfcSBenny Halevy 	status = nfs_ok;
2106f0f51f5cSJ. Bruce Fields out_put_session:
2107f0f51f5cSJ. Bruce Fields 	nfsd4_put_session(ses);
2108abcdff09SJ. Bruce Fields out_client_lock:
2109abcdff09SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
2110e10e0cfcSBenny Halevy out:
2111abcdff09SJ. Bruce Fields 	nfs4_unlock_state();
2112e10e0cfcSBenny Halevy 	return status;
2113069b6ad4SAndy Adamson }
2114069b6ad4SAndy Adamson 
2115a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
2116328ead28SJ. Bruce Fields {
2117328ead28SJ. Bruce Fields 	struct nfsd4_conn *c;
2118328ead28SJ. Bruce Fields 
2119328ead28SJ. Bruce Fields 	list_for_each_entry(c, &s->se_conns, cn_persession) {
2120a663bdd8SJ. Bruce Fields 		if (c->cn_xprt == xpt) {
2121328ead28SJ. Bruce Fields 			return c;
2122328ead28SJ. Bruce Fields 		}
2123328ead28SJ. Bruce Fields 	}
2124328ead28SJ. Bruce Fields 	return NULL;
2125328ead28SJ. Bruce Fields }
2126328ead28SJ. Bruce Fields 
212757266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
2128328ead28SJ. Bruce Fields {
2129328ead28SJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
2130a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *c;
213157266a6eSJ. Bruce Fields 	__be32 status = nfs_ok;
213221b75b01SJ. Bruce Fields 	int ret;
2133328ead28SJ. Bruce Fields 
2134328ead28SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
2135a663bdd8SJ. Bruce Fields 	c = __nfsd4_find_conn(new->cn_xprt, ses);
213657266a6eSJ. Bruce Fields 	if (c)
213757266a6eSJ. Bruce Fields 		goto out_free;
213857266a6eSJ. Bruce Fields 	status = nfserr_conn_not_bound_to_session;
213957266a6eSJ. Bruce Fields 	if (clp->cl_mach_cred)
214057266a6eSJ. Bruce Fields 		goto out_free;
2141328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(new, ses);
2142328ead28SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
214321b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(new);
214421b75b01SJ. Bruce Fields 	if (ret)
214521b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
214621b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&new->cn_xpt_user);
214757266a6eSJ. Bruce Fields 	return nfs_ok;
214857266a6eSJ. Bruce Fields out_free:
214957266a6eSJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
215057266a6eSJ. Bruce Fields 	free_conn(new);
215157266a6eSJ. Bruce Fields 	return status;
2152328ead28SJ. Bruce Fields }
2153328ead28SJ. Bruce Fields 
2154868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
2155868b89c3SMi Jinlong {
2156868b89c3SMi Jinlong 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
2157868b89c3SMi Jinlong 
2158868b89c3SMi Jinlong 	return args->opcnt > session->se_fchannel.maxops;
2159868b89c3SMi Jinlong }
2160868b89c3SMi Jinlong 
2161ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
2162ae82a8d0SMi Jinlong 				  struct nfsd4_session *session)
2163ae82a8d0SMi Jinlong {
2164ae82a8d0SMi Jinlong 	struct xdr_buf *xb = &rqstp->rq_arg;
2165ae82a8d0SMi Jinlong 
2166ae82a8d0SMi Jinlong 	return xb->len > session->se_fchannel.maxreq_sz;
2167ae82a8d0SMi Jinlong }
2168ae82a8d0SMi Jinlong 
2169069b6ad4SAndy Adamson __be32
2170b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp,
2171069b6ad4SAndy Adamson 	       struct nfsd4_compound_state *cstate,
2172069b6ad4SAndy Adamson 	       struct nfsd4_sequence *seq)
2173069b6ad4SAndy Adamson {
2174f9bb94c4SAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
2175b85d4c01SBenny Halevy 	struct nfsd4_session *session;
2176221a6876SJ. Bruce Fields 	struct nfs4_client *clp;
2177b85d4c01SBenny Halevy 	struct nfsd4_slot *slot;
2178a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *conn;
217957b7b43bSJ. Bruce Fields 	__be32 status;
2180c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2181b85d4c01SBenny Halevy 
2182f9bb94c4SAndy Adamson 	if (resp->opcnt != 1)
2183f9bb94c4SAndy Adamson 		return nfserr_sequence_pos;
2184f9bb94c4SAndy Adamson 
2185a663bdd8SJ. Bruce Fields 	/*
2186a663bdd8SJ. Bruce Fields 	 * Will be either used or freed by nfsd4_sequence_check_conn
2187a663bdd8SJ. Bruce Fields 	 * below.
2188a663bdd8SJ. Bruce Fields 	 */
2189a663bdd8SJ. Bruce Fields 	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
2190a663bdd8SJ. Bruce Fields 	if (!conn)
2191a663bdd8SJ. Bruce Fields 		return nfserr_jukebox;
2192a663bdd8SJ. Bruce Fields 
2193c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2194b85d4c01SBenny Halevy 	status = nfserr_badsession;
21951872de0eSStanislav Kinsbursky 	session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp));
2196b85d4c01SBenny Halevy 	if (!session)
2197221a6876SJ. Bruce Fields 		goto out_no_session;
2198221a6876SJ. Bruce Fields 	clp = session->se_client;
2199221a6876SJ. Bruce Fields 	status = get_client_locked(clp);
2200221a6876SJ. Bruce Fields 	if (status)
2201221a6876SJ. Bruce Fields 		goto out_no_session;
220266b2b9b2SJ. Bruce Fields 	status = nfsd4_get_session_locked(session);
220366b2b9b2SJ. Bruce Fields 	if (status)
220466b2b9b2SJ. Bruce Fields 		goto out_put_client;
2205b85d4c01SBenny Halevy 
2206868b89c3SMi Jinlong 	status = nfserr_too_many_ops;
2207868b89c3SMi Jinlong 	if (nfsd4_session_too_many_ops(rqstp, session))
220866b2b9b2SJ. Bruce Fields 		goto out_put_session;
2209868b89c3SMi Jinlong 
2210ae82a8d0SMi Jinlong 	status = nfserr_req_too_big;
2211ae82a8d0SMi Jinlong 	if (nfsd4_request_too_big(rqstp, session))
221266b2b9b2SJ. Bruce Fields 		goto out_put_session;
2213ae82a8d0SMi Jinlong 
2214b85d4c01SBenny Halevy 	status = nfserr_badslot;
22156c18ba9fSAlexandros Batsakis 	if (seq->slotid >= session->se_fchannel.maxreqs)
221666b2b9b2SJ. Bruce Fields 		goto out_put_session;
2217b85d4c01SBenny Halevy 
2218557ce264SAndy Adamson 	slot = session->se_slots[seq->slotid];
2219b85d4c01SBenny Halevy 	dprintk("%s: slotid %d\n", __func__, seq->slotid);
2220b85d4c01SBenny Halevy 
2221a8dfdaebSAndy Adamson 	/* We do not negotiate the number of slots yet, so set the
2222a8dfdaebSAndy Adamson 	 * maxslots to the session maxreqs which is used to encode
2223a8dfdaebSAndy Adamson 	 * sr_highest_slotid and the sr_target_slot id to maxslots */
2224a8dfdaebSAndy Adamson 	seq->maxslots = session->se_fchannel.maxreqs;
2225a8dfdaebSAndy Adamson 
222673e79482SJ. Bruce Fields 	status = check_slot_seqid(seq->seqid, slot->sl_seqid,
222773e79482SJ. Bruce Fields 					slot->sl_flags & NFSD4_SLOT_INUSE);
2228b85d4c01SBenny Halevy 	if (status == nfserr_replay_cache) {
2229bf5c43c8SJ. Bruce Fields 		status = nfserr_seq_misordered;
2230bf5c43c8SJ. Bruce Fields 		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
223166b2b9b2SJ. Bruce Fields 			goto out_put_session;
2232b85d4c01SBenny Halevy 		cstate->slot = slot;
2233b85d4c01SBenny Halevy 		cstate->session = session;
2234da3846a2SAndy Adamson 		/* Return the cached reply status and set cstate->status
2235557ce264SAndy Adamson 		 * for nfsd4_proc_compound processing */
2236bf864a31SAndy Adamson 		status = nfsd4_replay_cache_entry(resp, seq);
2237da3846a2SAndy Adamson 		cstate->status = nfserr_replay_cache;
2238aaf84eb9SBenny Halevy 		goto out;
2239b85d4c01SBenny Halevy 	}
2240b85d4c01SBenny Halevy 	if (status)
224166b2b9b2SJ. Bruce Fields 		goto out_put_session;
2242b85d4c01SBenny Halevy 
224357266a6eSJ. Bruce Fields 	status = nfsd4_sequence_check_conn(conn, session);
2244a663bdd8SJ. Bruce Fields 	conn = NULL;
224557266a6eSJ. Bruce Fields 	if (status)
224657266a6eSJ. Bruce Fields 		goto out_put_session;
2247328ead28SJ. Bruce Fields 
2248b85d4c01SBenny Halevy 	/* Success! bump slot seqid */
2249b85d4c01SBenny Halevy 	slot->sl_seqid = seq->seqid;
2250bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INUSE;
225173e79482SJ. Bruce Fields 	if (seq->cachethis)
225273e79482SJ. Bruce Fields 		slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
2253bf5c43c8SJ. Bruce Fields 	else
2254bf5c43c8SJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
2255b85d4c01SBenny Halevy 
2256b85d4c01SBenny Halevy 	cstate->slot = slot;
2257b85d4c01SBenny Halevy 	cstate->session = session;
2258b85d4c01SBenny Halevy 
2259b85d4c01SBenny Halevy out:
22605423732aSBenny Halevy 	switch (clp->cl_cb_state) {
22615423732aSBenny Halevy 	case NFSD4_CB_DOWN:
2262fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
22635423732aSBenny Halevy 		break;
22645423732aSBenny Halevy 	case NFSD4_CB_FAULT:
2265fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
22665423732aSBenny Halevy 		break;
2267fc0c3dd1SBenny Halevy 	default:
2268fc0c3dd1SBenny Halevy 		seq->status_flags = 0;
22695423732aSBenny Halevy 	}
22703bd64a5bSJ. Bruce Fields 	if (!list_empty(&clp->cl_revoked))
22713bd64a5bSJ. Bruce Fields 		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
2272221a6876SJ. Bruce Fields out_no_session:
2273a663bdd8SJ. Bruce Fields 	kfree(conn);
2274c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2275b85d4c01SBenny Halevy 	return status;
227666b2b9b2SJ. Bruce Fields out_put_session:
227766b2b9b2SJ. Bruce Fields 	nfsd4_put_session(session);
2278221a6876SJ. Bruce Fields out_put_client:
2279221a6876SJ. Bruce Fields 	put_client_renew_locked(clp);
2280221a6876SJ. Bruce Fields 	goto out_no_session;
2281069b6ad4SAndy Adamson }
2282069b6ad4SAndy Adamson 
2283345c2842SMi Jinlong __be32
2284345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
2285345c2842SMi Jinlong {
2286345c2842SMi Jinlong 	struct nfs4_client *conf, *unconf, *clp;
228757b7b43bSJ. Bruce Fields 	__be32 status = 0;
22888daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2289345c2842SMi Jinlong 
2290345c2842SMi Jinlong 	nfs4_lock_state();
22910a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
22928daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&dc->clientid, true, nn);
229378389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2294345c2842SMi Jinlong 
2295345c2842SMi Jinlong 	if (conf) {
2296345c2842SMi Jinlong 		clp = conf;
2297345c2842SMi Jinlong 
2298c0293b01SJ. Bruce Fields 		if (client_has_state(conf)) {
2299345c2842SMi Jinlong 			status = nfserr_clientid_busy;
2300345c2842SMi Jinlong 			goto out;
2301345c2842SMi Jinlong 		}
2302345c2842SMi Jinlong 	} else if (unconf)
2303345c2842SMi Jinlong 		clp = unconf;
2304345c2842SMi Jinlong 	else {
2305345c2842SMi Jinlong 		status = nfserr_stale_clientid;
2306345c2842SMi Jinlong 		goto out;
2307345c2842SMi Jinlong 	}
230857266a6eSJ. Bruce Fields 	if (!mach_creds_match(clp, rqstp)) {
230957266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
231057266a6eSJ. Bruce Fields 		goto out;
231157266a6eSJ. Bruce Fields 	}
2312345c2842SMi Jinlong 	expire_client(clp);
2313345c2842SMi Jinlong out:
2314345c2842SMi Jinlong 	nfs4_unlock_state();
2315345c2842SMi Jinlong 	return status;
2316345c2842SMi Jinlong }
2317345c2842SMi Jinlong 
2318069b6ad4SAndy Adamson __be32
23194dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
23204dc6ec00SJ. Bruce Fields {
232157b7b43bSJ. Bruce Fields 	__be32 status = 0;
2322bcecf1ccSMi Jinlong 
23234dc6ec00SJ. Bruce Fields 	if (rc->rca_one_fs) {
23244dc6ec00SJ. Bruce Fields 		if (!cstate->current_fh.fh_dentry)
23254dc6ec00SJ. Bruce Fields 			return nfserr_nofilehandle;
23264dc6ec00SJ. Bruce Fields 		/*
23274dc6ec00SJ. Bruce Fields 		 * We don't take advantage of the rca_one_fs case.
23284dc6ec00SJ. Bruce Fields 		 * That's OK, it's optional, we can safely ignore it.
23294dc6ec00SJ. Bruce Fields 		 */
23304dc6ec00SJ. Bruce Fields 		 return nfs_ok;
23314dc6ec00SJ. Bruce Fields 	}
2332bcecf1ccSMi Jinlong 
23334dc6ec00SJ. Bruce Fields 	nfs4_lock_state();
2334bcecf1ccSMi Jinlong 	status = nfserr_complete_already;
2335a52d726bSJeff Layton 	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
2336a52d726bSJeff Layton 			     &cstate->session->se_client->cl_flags))
2337bcecf1ccSMi Jinlong 		goto out;
2338bcecf1ccSMi Jinlong 
2339bcecf1ccSMi Jinlong 	status = nfserr_stale_clientid;
2340bcecf1ccSMi Jinlong 	if (is_client_expired(cstate->session->se_client))
23414dc6ec00SJ. Bruce Fields 		/*
23424dc6ec00SJ. Bruce Fields 		 * The following error isn't really legal.
23434dc6ec00SJ. Bruce Fields 		 * But we only get here if the client just explicitly
23444dc6ec00SJ. Bruce Fields 		 * destroyed the client.  Surely it no longer cares what
23454dc6ec00SJ. Bruce Fields 		 * error it gets back on an operation for the dead
23464dc6ec00SJ. Bruce Fields 		 * client.
23474dc6ec00SJ. Bruce Fields 		 */
2348bcecf1ccSMi Jinlong 		goto out;
2349bcecf1ccSMi Jinlong 
2350bcecf1ccSMi Jinlong 	status = nfs_ok;
23512a4317c5SJeff Layton 	nfsd4_client_record_create(cstate->session->se_client);
2352bcecf1ccSMi Jinlong out:
23534dc6ec00SJ. Bruce Fields 	nfs4_unlock_state();
2354bcecf1ccSMi Jinlong 	return status;
23554dc6ec00SJ. Bruce Fields }
23564dc6ec00SJ. Bruce Fields 
23574dc6ec00SJ. Bruce Fields __be32
2358b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2359b591480bSJ.Bruce Fields 		  struct nfsd4_setclientid *setclid)
23601da177e4SLinus Torvalds {
2361a084daf5SJ. Bruce Fields 	struct xdr_netobj 	clname = setclid->se_name;
23621da177e4SLinus Torvalds 	nfs4_verifier		clverifier = setclid->se_verf;
236328ce6054SNeilBrown 	struct nfs4_client	*conf, *unconf, *new;
2364b37ad28bSAl Viro 	__be32 			status;
2365c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2366a55370a3SNeilBrown 
236763db4632SJ. Bruce Fields 	/* Cases below refer to rfc 3530 section 14.2.33: */
23681da177e4SLinus Torvalds 	nfs4_lock_state();
2369382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&clname, nn);
237028ce6054SNeilBrown 	if (conf) {
237163db4632SJ. Bruce Fields 		/* case 0: */
23721da177e4SLinus Torvalds 		status = nfserr_clid_inuse;
2373e203d506SJ. Bruce Fields 		if (clp_used_exchangeid(conf))
2374e203d506SJ. Bruce Fields 			goto out;
2375026722c2SJ. Bruce Fields 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
2376363168b4SJeff Layton 			char addr_str[INET6_ADDRSTRLEN];
2377363168b4SJeff Layton 			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
2378363168b4SJeff Layton 				 sizeof(addr_str));
2379026722c2SJ. Bruce Fields 			dprintk("NFSD: setclientid: string in use by client "
2380363168b4SJeff Layton 				"at %s\n", addr_str);
23811da177e4SLinus Torvalds 			goto out;
23821da177e4SLinus Torvalds 		}
23831da177e4SLinus Torvalds 	}
2384a99454aaSStanislav Kinsbursky 	unconf = find_unconfirmed_client_by_name(&clname, nn);
23851da177e4SLinus Torvalds 	if (unconf)
23861da177e4SLinus Torvalds 		expire_client(unconf);
23878f930711SJ. Bruce Fields 	status = nfserr_jukebox;
23882216d449SJeff Layton 	new = create_client(clname, rqstp, &clverifier);
2389a55370a3SNeilBrown 	if (new == NULL)
23901da177e4SLinus Torvalds 		goto out;
239134b232bbSJ. Bruce Fields 	if (conf && same_verf(&conf->cl_verifier, &clverifier))
239263db4632SJ. Bruce Fields 		/* case 1: probable callback update */
23931da177e4SLinus Torvalds 		copy_clid(new, conf);
239434b232bbSJ. Bruce Fields 	else /* case 4 (new client) or cases 2, 3 (client reboot): */
2395c212cecfSStanislav Kinsbursky 		gen_clid(new, nn);
23968323c3b2SJ. Bruce Fields 	new->cl_minorversion = 0;
23976f3d772fSTakuma Umeya 	gen_callback(new, setclid, rqstp);
2398ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
23991da177e4SLinus Torvalds 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
24001da177e4SLinus Torvalds 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
24011da177e4SLinus Torvalds 	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
24021da177e4SLinus Torvalds 	status = nfs_ok;
24031da177e4SLinus Torvalds out:
24041da177e4SLinus Torvalds 	nfs4_unlock_state();
24051da177e4SLinus Torvalds 	return status;
24061da177e4SLinus Torvalds }
24071da177e4SLinus Torvalds 
24081da177e4SLinus Torvalds 
2409b37ad28bSAl Viro __be32
2410b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2411b591480bSJ.Bruce Fields 			 struct nfsd4_compound_state *cstate,
2412b591480bSJ.Bruce Fields 			 struct nfsd4_setclientid_confirm *setclientid_confirm)
24131da177e4SLinus Torvalds {
241421ab45a4SNeilBrown 	struct nfs4_client *conf, *unconf;
24151da177e4SLinus Torvalds 	nfs4_verifier confirm = setclientid_confirm->sc_confirm;
24161da177e4SLinus Torvalds 	clientid_t * clid = &setclientid_confirm->sc_clientid;
2417b37ad28bSAl Viro 	__be32 status;
24187f2210faSStanislav Kinsbursky 	struct nfsd_net	*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
24191da177e4SLinus Torvalds 
24202c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(clid, nn))
24211da177e4SLinus Torvalds 		return nfserr_stale_clientid;
24221da177e4SLinus Torvalds 	nfs4_lock_state();
242321ab45a4SNeilBrown 
24248daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(clid, false, nn);
24250a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(clid, false, nn);
2426a186e767SJ. Bruce Fields 	/*
24278695b90aSJ. Bruce Fields 	 * We try hard to give out unique clientid's, so if we get an
24288695b90aSJ. Bruce Fields 	 * attempt to confirm the same clientid with a different cred,
24298695b90aSJ. Bruce Fields 	 * there's a bug somewhere.  Let's charitably assume it's our
24308695b90aSJ. Bruce Fields 	 * bug.
2431a186e767SJ. Bruce Fields 	 */
24328695b90aSJ. Bruce Fields 	status = nfserr_serverfault;
24338695b90aSJ. Bruce Fields 	if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred))
24348695b90aSJ. Bruce Fields 		goto out;
24358695b90aSJ. Bruce Fields 	if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred))
24368695b90aSJ. Bruce Fields 		goto out;
243763db4632SJ. Bruce Fields 	/* cases below refer to rfc 3530 section 14.2.34: */
243890d700b7SJ. Bruce Fields 	if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) {
243990d700b7SJ. Bruce Fields 		if (conf && !unconf) /* case 2: probable retransmit */
244090d700b7SJ. Bruce Fields 			status = nfs_ok;
244190d700b7SJ. Bruce Fields 		else /* case 4: client hasn't noticed we rebooted yet? */
244290d700b7SJ. Bruce Fields 			status = nfserr_stale_clientid;
244390d700b7SJ. Bruce Fields 		goto out;
244490d700b7SJ. Bruce Fields 	}
244590d700b7SJ. Bruce Fields 	status = nfs_ok;
244690d700b7SJ. Bruce Fields 	if (conf) { /* case 1: callback update */
24475a3c9d71SJ. Bruce Fields 		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
24485a3c9d71SJ. Bruce Fields 		nfsd4_probe_callback(conf);
24491a69c179SNeilBrown 		expire_client(unconf);
245090d700b7SJ. Bruce Fields 	} else { /* case 3: normal case; new or rebooted client */
2451382a62e7SStanislav Kinsbursky 		conf = find_confirmed_client_by_name(&unconf->cl_name, nn);
2452221a6876SJ. Bruce Fields 		if (conf) {
2453221a6876SJ. Bruce Fields 			status = mark_client_expired(conf);
2454221a6876SJ. Bruce Fields 			if (status)
2455221a6876SJ. Bruce Fields 				goto out;
24561a69c179SNeilBrown 			expire_client(conf);
2457221a6876SJ. Bruce Fields 		}
24581da177e4SLinus Torvalds 		move_to_confirmed(unconf);
2459f3d03b92SJ. Bruce Fields 		nfsd4_probe_callback(unconf);
246008e8987cSNeilBrown 	}
24611da177e4SLinus Torvalds out:
24621da177e4SLinus Torvalds 	nfs4_unlock_state();
24631da177e4SLinus Torvalds 	return status;
24641da177e4SLinus Torvalds }
24651da177e4SLinus Torvalds 
246632513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void)
24671da177e4SLinus Torvalds {
246832513b40SJ. Bruce Fields 	return kmem_cache_alloc(file_slab, GFP_KERNEL);
246932513b40SJ. Bruce Fields }
247032513b40SJ. Bruce Fields 
247132513b40SJ. Bruce Fields /* OPEN Share state helper functions */
247232513b40SJ. Bruce Fields static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
247332513b40SJ. Bruce Fields {
24741da177e4SLinus Torvalds 	unsigned int hashval = file_hashval(ino);
24751da177e4SLinus Torvalds 
24768b671b80SJ. Bruce Fields 	atomic_set(&fp->fi_ref, 1);
24778beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_stateids);
24788beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_delegations);
24791da177e4SLinus Torvalds 	fp->fi_inode = igrab(ino);
248047f9940cSMeelap Shah 	fp->fi_had_conflict = false;
2481acfdf5c3SJ. Bruce Fields 	fp->fi_lease = NULL;
2482f9d7562fSJ. Bruce Fields 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
2483f9d7562fSJ. Bruce Fields 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
248447cee541SPavel Emelyanov 	spin_lock(&recall_lock);
248589876f8cSJeff Layton 	hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
248647cee541SPavel Emelyanov 	spin_unlock(&recall_lock);
24871da177e4SLinus Torvalds }
24881da177e4SLinus Torvalds 
24891da177e4SLinus Torvalds static void
2490e18b890bSChristoph Lameter nfsd4_free_slab(struct kmem_cache **slab)
2491e60d4398SNeilBrown {
2492e60d4398SNeilBrown 	if (*slab == NULL)
2493e60d4398SNeilBrown 		return;
24941a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(*slab);
2495e60d4398SNeilBrown 	*slab = NULL;
2496e60d4398SNeilBrown }
2497e60d4398SNeilBrown 
2498e8ff2a84SJ. Bruce Fields void
2499e60d4398SNeilBrown nfsd4_free_slabs(void)
2500e60d4398SNeilBrown {
2501fe0750e5SJ. Bruce Fields 	nfsd4_free_slab(&openowner_slab);
2502fe0750e5SJ. Bruce Fields 	nfsd4_free_slab(&lockowner_slab);
2503e60d4398SNeilBrown 	nfsd4_free_slab(&file_slab);
25045ac049acSNeilBrown 	nfsd4_free_slab(&stateid_slab);
25055b2d21c1SNeilBrown 	nfsd4_free_slab(&deleg_slab);
2506e60d4398SNeilBrown }
25071da177e4SLinus Torvalds 
250872083396SBryan Schumaker int
25091da177e4SLinus Torvalds nfsd4_init_slabs(void)
25101da177e4SLinus Torvalds {
2511fe0750e5SJ. Bruce Fields 	openowner_slab = kmem_cache_create("nfsd4_openowners",
2512fe0750e5SJ. Bruce Fields 			sizeof(struct nfs4_openowner), 0, 0, NULL);
2513fe0750e5SJ. Bruce Fields 	if (openowner_slab == NULL)
2514fe0750e5SJ. Bruce Fields 		goto out_nomem;
2515fe0750e5SJ. Bruce Fields 	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
25163c40794bSYanchuan Nian 			sizeof(struct nfs4_lockowner), 0, 0, NULL);
2517fe0750e5SJ. Bruce Fields 	if (lockowner_slab == NULL)
2518e60d4398SNeilBrown 		goto out_nomem;
2519e60d4398SNeilBrown 	file_slab = kmem_cache_create("nfsd4_files",
252020c2df83SPaul Mundt 			sizeof(struct nfs4_file), 0, 0, NULL);
2521e60d4398SNeilBrown 	if (file_slab == NULL)
2522e60d4398SNeilBrown 		goto out_nomem;
25235ac049acSNeilBrown 	stateid_slab = kmem_cache_create("nfsd4_stateids",
2524dcef0413SJ. Bruce Fields 			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
25255ac049acSNeilBrown 	if (stateid_slab == NULL)
25265ac049acSNeilBrown 		goto out_nomem;
25275b2d21c1SNeilBrown 	deleg_slab = kmem_cache_create("nfsd4_delegations",
252820c2df83SPaul Mundt 			sizeof(struct nfs4_delegation), 0, 0, NULL);
25295b2d21c1SNeilBrown 	if (deleg_slab == NULL)
25305b2d21c1SNeilBrown 		goto out_nomem;
2531e60d4398SNeilBrown 	return 0;
2532e60d4398SNeilBrown out_nomem:
2533e60d4398SNeilBrown 	nfsd4_free_slabs();
25341da177e4SLinus Torvalds 	dprintk("nfsd4: out of memory while initializing nfsv4\n");
25351da177e4SLinus Torvalds 	return -ENOMEM;
25361da177e4SLinus Torvalds }
25371da177e4SLinus Torvalds 
2538fe0750e5SJ. Bruce Fields void nfs4_free_openowner(struct nfs4_openowner *oo)
25391da177e4SLinus Torvalds {
2540fe0750e5SJ. Bruce Fields 	kfree(oo->oo_owner.so_owner.data);
2541fe0750e5SJ. Bruce Fields 	kmem_cache_free(openowner_slab, oo);
2542fe0750e5SJ. Bruce Fields }
2543fe0750e5SJ. Bruce Fields 
2544fe0750e5SJ. Bruce Fields void nfs4_free_lockowner(struct nfs4_lockowner *lo)
2545fe0750e5SJ. Bruce Fields {
2546fe0750e5SJ. Bruce Fields 	kfree(lo->lo_owner.so_owner.data);
2547fe0750e5SJ. Bruce Fields 	kmem_cache_free(lockowner_slab, lo);
25481da177e4SLinus Torvalds }
25491da177e4SLinus Torvalds 
2550ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp)
2551ff194bd9SJ. Bruce Fields {
2552ff194bd9SJ. Bruce Fields 	rp->rp_status = nfserr_serverfault;
2553ff194bd9SJ. Bruce Fields 	rp->rp_buflen = 0;
2554ff194bd9SJ. Bruce Fields 	rp->rp_buf = rp->rp_ibuf;
2555ff194bd9SJ. Bruce Fields }
2556ff194bd9SJ. Bruce Fields 
2557fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
25581da177e4SLinus Torvalds {
25591da177e4SLinus Torvalds 	struct nfs4_stateowner *sop;
25601da177e4SLinus Torvalds 
2561fe0750e5SJ. Bruce Fields 	sop = kmem_cache_alloc(slab, GFP_KERNEL);
2562ff194bd9SJ. Bruce Fields 	if (!sop)
2563ff194bd9SJ. Bruce Fields 		return NULL;
2564ff194bd9SJ. Bruce Fields 
2565ff194bd9SJ. Bruce Fields 	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
2566ff194bd9SJ. Bruce Fields 	if (!sop->so_owner.data) {
2567fe0750e5SJ. Bruce Fields 		kmem_cache_free(slab, sop);
2568ff194bd9SJ. Bruce Fields 		return NULL;
2569ff194bd9SJ. Bruce Fields 	}
25701da177e4SLinus Torvalds 	sop->so_owner.len = owner->len;
2571ff194bd9SJ. Bruce Fields 
2572ff194bd9SJ. Bruce Fields 	INIT_LIST_HEAD(&sop->so_stateids);
2573ff194bd9SJ. Bruce Fields 	sop->so_client = clp;
2574ff194bd9SJ. Bruce Fields 	init_nfs4_replay(&sop->so_replay);
25751da177e4SLinus Torvalds 	return sop;
25761da177e4SLinus Torvalds }
2577ff194bd9SJ. Bruce Fields 
2578fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
2579ff194bd9SJ. Bruce Fields {
25809b531137SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
25819b531137SStanislav Kinsbursky 
25829b531137SStanislav Kinsbursky 	list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
2583fe0750e5SJ. Bruce Fields 	list_add(&oo->oo_perclient, &clp->cl_openowners);
25841da177e4SLinus Torvalds }
25851da177e4SLinus Torvalds 
2586fe0750e5SJ. Bruce Fields static struct nfs4_openowner *
25871da177e4SLinus Torvalds alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
2588fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
25891da177e4SLinus Torvalds 
2590fe0750e5SJ. Bruce Fields 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
2591fe0750e5SJ. Bruce Fields 	if (!oo)
25921da177e4SLinus Torvalds 		return NULL;
2593fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_is_open_owner = 1;
2594fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_seqid = open->op_seqid;
2595d29b20cdSJ. Bruce Fields 	oo->oo_flags = NFS4_OO_NEW;
2596fe0750e5SJ. Bruce Fields 	oo->oo_time = 0;
259738c387b5SJ. Bruce Fields 	oo->oo_last_closed_stid = NULL;
2598fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&oo->oo_close_lru);
2599fe0750e5SJ. Bruce Fields 	hash_openowner(oo, clp, strhashval);
2600fe0750e5SJ. Bruce Fields 	return oo;
26011da177e4SLinus Torvalds }
26021da177e4SLinus Torvalds 
2603996e0938SJ. Bruce Fields static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
2604fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = open->op_openowner;
26051da177e4SLinus Torvalds 
26063abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_OPEN_STID;
2607ea1da636SNeilBrown 	INIT_LIST_HEAD(&stp->st_lockowners);
2608fe0750e5SJ. Bruce Fields 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
26098beefa24SNeilBrown 	list_add(&stp->st_perfile, &fp->fi_stateids);
2610fe0750e5SJ. Bruce Fields 	stp->st_stateowner = &oo->oo_owner;
261113cd2184SNeilBrown 	get_nfs4_file(fp);
26121da177e4SLinus Torvalds 	stp->st_file = fp;
26131da177e4SLinus Torvalds 	stp->st_access_bmap = 0;
26141da177e4SLinus Torvalds 	stp->st_deny_bmap = 0;
261582c5ff1bSJeff Layton 	set_access(open->op_share_access, stp);
2616ce0fc43cSJeff Layton 	set_deny(open->op_share_deny, stp);
26174c4cd222SNeilBrown 	stp->st_openstp = NULL;
26181da177e4SLinus Torvalds }
26191da177e4SLinus Torvalds 
26201da177e4SLinus Torvalds static void
262173758fedSStanislav Kinsbursky move_to_close_lru(struct nfs4_openowner *oo, struct net *net)
26221da177e4SLinus Torvalds {
262373758fedSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
262473758fedSStanislav Kinsbursky 
2625fe0750e5SJ. Bruce Fields 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
26261da177e4SLinus Torvalds 
262773758fedSStanislav Kinsbursky 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
2628fe0750e5SJ. Bruce Fields 	oo->oo_time = get_seconds();
26291da177e4SLinus Torvalds }
26301da177e4SLinus Torvalds 
26311da177e4SLinus Torvalds static int
2632599e0a22SJ. Bruce Fields same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
2633599e0a22SJ. Bruce Fields 							clientid_t *clid)
2634599e0a22SJ. Bruce Fields {
2635599e0a22SJ. Bruce Fields 	return (sop->so_owner.len == owner->len) &&
2636599e0a22SJ. Bruce Fields 		0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
2637599e0a22SJ. Bruce Fields 		(sop->so_client->cl_clientid.cl_id == clid->cl_id);
26381da177e4SLinus Torvalds }
26391da177e4SLinus Torvalds 
2640fe0750e5SJ. Bruce Fields static struct nfs4_openowner *
26419b531137SStanislav Kinsbursky find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
26429b531137SStanislav Kinsbursky 			bool sessions, struct nfsd_net *nn)
26431da177e4SLinus Torvalds {
2644a50d2ad1SJ. Bruce Fields 	struct nfs4_stateowner *so;
2645a50d2ad1SJ. Bruce Fields 	struct nfs4_openowner *oo;
2646d15c077eSJ. Bruce Fields 	struct nfs4_client *clp;
26471da177e4SLinus Torvalds 
26489b531137SStanislav Kinsbursky 	list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) {
264916bfdaafSJ. Bruce Fields 		if (!so->so_is_open_owner)
265016bfdaafSJ. Bruce Fields 			continue;
2651a50d2ad1SJ. Bruce Fields 		if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
2652a50d2ad1SJ. Bruce Fields 			oo = openowner(so);
2653d15c077eSJ. Bruce Fields 			clp = oo->oo_owner.so_client;
2654d15c077eSJ. Bruce Fields 			if ((bool)clp->cl_minorversion != sessions)
2655d15c077eSJ. Bruce Fields 				return NULL;
2656a50d2ad1SJ. Bruce Fields 			renew_client(oo->oo_owner.so_client);
2657a50d2ad1SJ. Bruce Fields 			return oo;
2658a50d2ad1SJ. Bruce Fields 		}
26591da177e4SLinus Torvalds 	}
26601da177e4SLinus Torvalds 	return NULL;
26611da177e4SLinus Torvalds }
26621da177e4SLinus Torvalds 
26631da177e4SLinus Torvalds /* search file_hashtbl[] for file */
26641da177e4SLinus Torvalds static struct nfs4_file *
26651da177e4SLinus Torvalds find_file(struct inode *ino)
26661da177e4SLinus Torvalds {
26671da177e4SLinus Torvalds 	unsigned int hashval = file_hashval(ino);
26681da177e4SLinus Torvalds 	struct nfs4_file *fp;
26691da177e4SLinus Torvalds 
26708b671b80SJ. Bruce Fields 	spin_lock(&recall_lock);
267189876f8cSJeff Layton 	hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
267213cd2184SNeilBrown 		if (fp->fi_inode == ino) {
267313cd2184SNeilBrown 			get_nfs4_file(fp);
26748b671b80SJ. Bruce Fields 			spin_unlock(&recall_lock);
26751da177e4SLinus Torvalds 			return fp;
26761da177e4SLinus Torvalds 		}
267713cd2184SNeilBrown 	}
26788b671b80SJ. Bruce Fields 	spin_unlock(&recall_lock);
26791da177e4SLinus Torvalds 	return NULL;
26801da177e4SLinus Torvalds }
26811da177e4SLinus Torvalds 
26824f83aa30SJ. Bruce Fields /*
26831da177e4SLinus Torvalds  * Called to check deny when READ with all zero stateid or
26841da177e4SLinus Torvalds  * WRITE with all zero or all one stateid
26851da177e4SLinus Torvalds  */
2686b37ad28bSAl Viro static __be32
26871da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
26881da177e4SLinus Torvalds {
26891da177e4SLinus Torvalds 	struct inode *ino = current_fh->fh_dentry->d_inode;
26901da177e4SLinus Torvalds 	struct nfs4_file *fp;
2691dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
2692b37ad28bSAl Viro 	__be32 ret;
26931da177e4SLinus Torvalds 
26941da177e4SLinus Torvalds 	fp = find_file(ino);
269513cd2184SNeilBrown 	if (!fp)
269613cd2184SNeilBrown 		return nfs_ok;
2697b700949bSNeilBrown 	ret = nfserr_locked;
26981da177e4SLinus Torvalds 	/* Search for conflicting share reservations */
26998beefa24SNeilBrown 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
2700ce0fc43cSJeff Layton 		if (test_deny(deny_type, stp) ||
2701ce0fc43cSJeff Layton 		    test_deny(NFS4_SHARE_DENY_BOTH, stp))
270213cd2184SNeilBrown 			goto out;
27031da177e4SLinus Torvalds 	}
270413cd2184SNeilBrown 	ret = nfs_ok;
270513cd2184SNeilBrown out:
270613cd2184SNeilBrown 	put_nfs4_file(fp);
270713cd2184SNeilBrown 	return ret;
27081da177e4SLinus Torvalds }
27091da177e4SLinus Torvalds 
27106b57d9c8SJ. Bruce Fields static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
27111da177e4SLinus Torvalds {
2712e8c69d17SJ. Bruce Fields 	struct nfs4_client *clp = dp->dl_stid.sc_client;
2713e8c69d17SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2714e8c69d17SJ. Bruce Fields 
27151da177e4SLinus Torvalds 	/* We're assuming the state code never drops its reference
27161da177e4SLinus Torvalds 	 * without first removing the lease.  Since we're in this lease
27171da177e4SLinus Torvalds 	 * callback (and since the lease code is serialized by the kernel
27181da177e4SLinus Torvalds 	 * lock) we know the server hasn't removed the lease yet, we know
27191da177e4SLinus Torvalds 	 * it's safe to take a reference: */
27201da177e4SLinus Torvalds 	atomic_inc(&dp->dl_count);
27211da177e4SLinus Torvalds 
2722e8c69d17SJ. Bruce Fields 	list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
27231da177e4SLinus Torvalds 
27241c8c601aSJeff Layton 	/* Only place dl_time is set; protected by i_lock: */
27251da177e4SLinus Torvalds 	dp->dl_time = get_seconds();
27261da177e4SLinus Torvalds 
27276b57d9c8SJ. Bruce Fields 	nfsd4_cb_recall(dp);
27286b57d9c8SJ. Bruce Fields }
27296b57d9c8SJ. Bruce Fields 
27301c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */
27316b57d9c8SJ. Bruce Fields static void nfsd_break_deleg_cb(struct file_lock *fl)
27326b57d9c8SJ. Bruce Fields {
2733acfdf5c3SJ. Bruce Fields 	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
2734acfdf5c3SJ. Bruce Fields 	struct nfs4_delegation *dp;
27356b57d9c8SJ. Bruce Fields 
27367fa10cd1SJ. Bruce Fields 	if (!fp) {
27377fa10cd1SJ. Bruce Fields 		WARN(1, "(%p)->fl_owner NULL\n", fl);
27387fa10cd1SJ. Bruce Fields 		return;
27397fa10cd1SJ. Bruce Fields 	}
27407fa10cd1SJ. Bruce Fields 	if (fp->fi_had_conflict) {
27417fa10cd1SJ. Bruce Fields 		WARN(1, "duplicate break on %p\n", fp);
27427fa10cd1SJ. Bruce Fields 		return;
27437fa10cd1SJ. Bruce Fields 	}
27440272e1fdSJ. Bruce Fields 	/*
27450272e1fdSJ. Bruce Fields 	 * We don't want the locks code to timeout the lease for us;
2746acfdf5c3SJ. Bruce Fields 	 * we'll remove it ourself if a delegation isn't returned
27476b57d9c8SJ. Bruce Fields 	 * in time:
27480272e1fdSJ. Bruce Fields 	 */
27490272e1fdSJ. Bruce Fields 	fl->fl_break_time = 0;
27501da177e4SLinus Torvalds 
27515d926e8cSJ. Bruce Fields 	spin_lock(&recall_lock);
2752acfdf5c3SJ. Bruce Fields 	fp->fi_had_conflict = true;
2753acfdf5c3SJ. Bruce Fields 	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
27545d926e8cSJ. Bruce Fields 		nfsd_break_one_deleg(dp);
27555d926e8cSJ. Bruce Fields 	spin_unlock(&recall_lock);
27561da177e4SLinus Torvalds }
27571da177e4SLinus Torvalds 
27581da177e4SLinus Torvalds static
27591da177e4SLinus Torvalds int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
27601da177e4SLinus Torvalds {
27611da177e4SLinus Torvalds 	if (arg & F_UNLCK)
27621da177e4SLinus Torvalds 		return lease_modify(onlist, arg);
27631da177e4SLinus Torvalds 	else
27641da177e4SLinus Torvalds 		return -EAGAIN;
27651da177e4SLinus Torvalds }
27661da177e4SLinus Torvalds 
27677b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = {
27688fb47a4fSJ. Bruce Fields 	.lm_break = nfsd_break_deleg_cb,
27698fb47a4fSJ. Bruce Fields 	.lm_change = nfsd_change_deleg_cb,
27701da177e4SLinus Torvalds };
27711da177e4SLinus Torvalds 
27727a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
27737a8711c9SJ. Bruce Fields {
27747a8711c9SJ. Bruce Fields 	if (nfsd4_has_session(cstate))
27757a8711c9SJ. Bruce Fields 		return nfs_ok;
27767a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid - 1)
27777a8711c9SJ. Bruce Fields 		return nfserr_replay_me;
27787a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid)
27797a8711c9SJ. Bruce Fields 		return nfs_ok;
27807a8711c9SJ. Bruce Fields 	return nfserr_bad_seqid;
27817a8711c9SJ. Bruce Fields }
27821da177e4SLinus Torvalds 
2783b37ad28bSAl Viro __be32
27846668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate,
27853320fef1SStanislav Kinsbursky 		    struct nfsd4_open *open, struct nfsd_net *nn)
27861da177e4SLinus Torvalds {
27871da177e4SLinus Torvalds 	clientid_t *clientid = &open->op_clientid;
27881da177e4SLinus Torvalds 	struct nfs4_client *clp = NULL;
27891da177e4SLinus Torvalds 	unsigned int strhashval;
2790fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = NULL;
27914cdc951bSJ. Bruce Fields 	__be32 status;
27921da177e4SLinus Torvalds 
27932c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(&open->op_clientid, nn))
27941da177e4SLinus Torvalds 		return nfserr_stale_clientid;
279532513b40SJ. Bruce Fields 	/*
279632513b40SJ. Bruce Fields 	 * In case we need it later, after we've already created the
279732513b40SJ. Bruce Fields 	 * file and don't want to risk a further failure:
279832513b40SJ. Bruce Fields 	 */
279932513b40SJ. Bruce Fields 	open->op_file = nfsd4_alloc_file();
280032513b40SJ. Bruce Fields 	if (open->op_file == NULL)
280132513b40SJ. Bruce Fields 		return nfserr_jukebox;
28021da177e4SLinus Torvalds 
280316bfdaafSJ. Bruce Fields 	strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
28049b531137SStanislav Kinsbursky 	oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn);
2805fe0750e5SJ. Bruce Fields 	open->op_openowner = oo;
2806fe0750e5SJ. Bruce Fields 	if (!oo) {
28078daae4dcSStanislav Kinsbursky 		clp = find_confirmed_client(clientid, cstate->minorversion,
28088daae4dcSStanislav Kinsbursky 					    nn);
28090f442aa2SJ. Bruce Fields 		if (clp == NULL)
28100f442aa2SJ. Bruce Fields 			return nfserr_expired;
2811bcf130f9SJ. Bruce Fields 		goto new_owner;
28120f442aa2SJ. Bruce Fields 	}
2813dad1c067SJ. Bruce Fields 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
28140f442aa2SJ. Bruce Fields 		/* Replace unconfirmed owners without checking for replay. */
2815fe0750e5SJ. Bruce Fields 		clp = oo->oo_owner.so_client;
2816fe0750e5SJ. Bruce Fields 		release_openowner(oo);
2817fe0750e5SJ. Bruce Fields 		open->op_openowner = NULL;
2818bcf130f9SJ. Bruce Fields 		goto new_owner;
28190f442aa2SJ. Bruce Fields 	}
28204cdc951bSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
28214cdc951bSJ. Bruce Fields 	if (status)
28224cdc951bSJ. Bruce Fields 		return status;
28234cdc951bSJ. Bruce Fields 	clp = oo->oo_owner.so_client;
28244cdc951bSJ. Bruce Fields 	goto alloc_stateid;
2825bcf130f9SJ. Bruce Fields new_owner:
2826fe0750e5SJ. Bruce Fields 	oo = alloc_init_open_stateowner(strhashval, clp, open);
2827fe0750e5SJ. Bruce Fields 	if (oo == NULL)
28283e772463SJ. Bruce Fields 		return nfserr_jukebox;
2829fe0750e5SJ. Bruce Fields 	open->op_openowner = oo;
28304cdc951bSJ. Bruce Fields alloc_stateid:
28314cdc951bSJ. Bruce Fields 	open->op_stp = nfs4_alloc_stateid(clp);
28324cdc951bSJ. Bruce Fields 	if (!open->op_stp)
28334cdc951bSJ. Bruce Fields 		return nfserr_jukebox;
28340f442aa2SJ. Bruce Fields 	return nfs_ok;
28351da177e4SLinus Torvalds }
28361da177e4SLinus Torvalds 
2837b37ad28bSAl Viro static inline __be32
28384a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
28394a6e43e6SNeilBrown {
28404a6e43e6SNeilBrown 	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
28414a6e43e6SNeilBrown 		return nfserr_openmode;
28424a6e43e6SNeilBrown 	else
28434a6e43e6SNeilBrown 		return nfs_ok;
28444a6e43e6SNeilBrown }
28454a6e43e6SNeilBrown 
2846c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access)
284724a0111eSJ. Bruce Fields {
284824a0111eSJ. Bruce Fields 	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
284924a0111eSJ. Bruce Fields }
285024a0111eSJ. Bruce Fields 
285138c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
2852f459e453SJ. Bruce Fields {
2853f459e453SJ. Bruce Fields 	struct nfs4_stid *ret;
2854f459e453SJ. Bruce Fields 
285538c2f4b1SJ. Bruce Fields 	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
2856f459e453SJ. Bruce Fields 	if (!ret)
2857f459e453SJ. Bruce Fields 		return NULL;
2858f459e453SJ. Bruce Fields 	return delegstateid(ret);
2859f459e453SJ. Bruce Fields }
2860f459e453SJ. Bruce Fields 
28618b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
28628b289b2cSJ. Bruce Fields {
28638b289b2cSJ. Bruce Fields 	return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
28648b289b2cSJ. Bruce Fields 	       open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
28658b289b2cSJ. Bruce Fields }
28668b289b2cSJ. Bruce Fields 
2867b37ad28bSAl Viro static __be32
286841d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
2869567d9829SNeilBrown 		struct nfs4_delegation **dp)
2870567d9829SNeilBrown {
2871567d9829SNeilBrown 	int flags;
2872b37ad28bSAl Viro 	__be32 status = nfserr_bad_stateid;
2873567d9829SNeilBrown 
287438c2f4b1SJ. Bruce Fields 	*dp = find_deleg_stateid(cl, &open->op_delegate_stateid);
2875567d9829SNeilBrown 	if (*dp == NULL)
2876c44c5eebSNeilBrown 		goto out;
287724a0111eSJ. Bruce Fields 	flags = share_access_to_flags(open->op_share_access);
2878567d9829SNeilBrown 	status = nfs4_check_delegmode(*dp, flags);
2879567d9829SNeilBrown 	if (status)
2880567d9829SNeilBrown 		*dp = NULL;
2881c44c5eebSNeilBrown out:
28828b289b2cSJ. Bruce Fields 	if (!nfsd4_is_deleg_cur(open))
2883c44c5eebSNeilBrown 		return nfs_ok;
2884c44c5eebSNeilBrown 	if (status)
2885c44c5eebSNeilBrown 		return status;
2886dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
2887c44c5eebSNeilBrown 	return nfs_ok;
2888567d9829SNeilBrown }
2889567d9829SNeilBrown 
2890b37ad28bSAl Viro static __be32
2891dcef0413SJ. Bruce Fields nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp)
28921da177e4SLinus Torvalds {
2893dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *local;
2894fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = open->op_openowner;
28951da177e4SLinus Torvalds 
28968beefa24SNeilBrown 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
28971da177e4SLinus Torvalds 		/* ignore lock owners */
28981da177e4SLinus Torvalds 		if (local->st_stateowner->so_is_open_owner == 0)
28991da177e4SLinus Torvalds 			continue;
29001da177e4SLinus Torvalds 		/* remember if we have seen this open owner */
2901fe0750e5SJ. Bruce Fields 		if (local->st_stateowner == &oo->oo_owner)
29021da177e4SLinus Torvalds 			*stpp = local;
29031da177e4SLinus Torvalds 		/* check for conflicting share reservations */
29041da177e4SLinus Torvalds 		if (!test_share(local, open))
290577eaae8dSJ. Bruce Fields 			return nfserr_share_denied;
29061da177e4SLinus Torvalds 	}
290777eaae8dSJ. Bruce Fields 	return nfs_ok;
29081da177e4SLinus Torvalds }
29091da177e4SLinus Torvalds 
291021fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access)
291121fb4016SJ. Bruce Fields {
291221fb4016SJ. Bruce Fields 	int flags = 0;
291321fb4016SJ. Bruce Fields 
291421fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
291521fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_READ;
291621fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
291721fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_WRITE;
291821fb4016SJ. Bruce Fields 	return flags;
291921fb4016SJ. Bruce Fields }
292021fb4016SJ. Bruce Fields 
29210c12eaffSCasey Bodley static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
29220c12eaffSCasey Bodley 		struct svc_fh *cur_fh, struct nfsd4_open *open)
2923f9d7562fSJ. Bruce Fields {
2924f9d7562fSJ. Bruce Fields 	__be32 status;
29250c12eaffSCasey Bodley 	int oflag = nfs4_access_to_omode(open->op_share_access);
29260c12eaffSCasey Bodley 	int access = nfs4_access_to_access(open->op_share_access);
29270c12eaffSCasey Bodley 
2928f9d7562fSJ. Bruce Fields 	if (!fp->fi_fds[oflag]) {
2929f9d7562fSJ. Bruce Fields 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
2930f9d7562fSJ. Bruce Fields 			&fp->fi_fds[oflag]);
2931f9d7562fSJ. Bruce Fields 		if (status)
2932f9d7562fSJ. Bruce Fields 			return status;
2933f9d7562fSJ. Bruce Fields 	}
2934f9d7562fSJ. Bruce Fields 	nfs4_file_get_access(fp, oflag);
2935f9d7562fSJ. Bruce Fields 
2936f9d7562fSJ. Bruce Fields 	return nfs_ok;
2937f9d7562fSJ. Bruce Fields }
2938f9d7562fSJ. Bruce Fields 
2939b37ad28bSAl Viro static inline __be32
29401da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
29411da177e4SLinus Torvalds 		struct nfsd4_open *open)
29421da177e4SLinus Torvalds {
29431da177e4SLinus Torvalds 	struct iattr iattr = {
29441da177e4SLinus Torvalds 		.ia_valid = ATTR_SIZE,
29451da177e4SLinus Torvalds 		.ia_size = 0,
29461da177e4SLinus Torvalds 	};
29471da177e4SLinus Torvalds 	if (!open->op_truncate)
29481da177e4SLinus Torvalds 		return 0;
29491da177e4SLinus Torvalds 	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
29509246585aSAl Viro 		return nfserr_inval;
29511da177e4SLinus Torvalds 	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
29521da177e4SLinus Torvalds }
29531da177e4SLinus Torvalds 
2954b37ad28bSAl Viro static __be32
2955dcef0413SJ. 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)
29561da177e4SLinus Torvalds {
2957b6d2f1caSJ. Bruce Fields 	u32 op_share_access = open->op_share_access;
29587d947842SJ. Bruce Fields 	bool new_access;
2959b37ad28bSAl Viro 	__be32 status;
29601da177e4SLinus Torvalds 
296182c5ff1bSJeff Layton 	new_access = !test_access(op_share_access, stp);
2962f9d7562fSJ. Bruce Fields 	if (new_access) {
29630c12eaffSCasey Bodley 		status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
2964f9d7562fSJ. Bruce Fields 		if (status)
2965f9d7562fSJ. Bruce Fields 			return status;
29666c26d08fSJ. Bruce Fields 	}
29671da177e4SLinus Torvalds 	status = nfsd4_truncate(rqstp, cur_fh, open);
29681da177e4SLinus Torvalds 	if (status) {
2969f9d7562fSJ. Bruce Fields 		if (new_access) {
2970f197c271SJ. Bruce Fields 			int oflag = nfs4_access_to_omode(op_share_access);
2971f9d7562fSJ. Bruce Fields 			nfs4_file_put_access(fp, oflag);
2972f9d7562fSJ. Bruce Fields 		}
29731da177e4SLinus Torvalds 		return status;
29741da177e4SLinus Torvalds 	}
29751da177e4SLinus Torvalds 	/* remember the open */
297682c5ff1bSJeff Layton 	set_access(op_share_access, stp);
2977ce0fc43cSJeff Layton 	set_deny(open->op_share_deny, stp);
29781da177e4SLinus Torvalds 
29791da177e4SLinus Torvalds 	return nfs_ok;
29801da177e4SLinus Torvalds }
29811da177e4SLinus Torvalds 
29821da177e4SLinus Torvalds 
29831da177e4SLinus Torvalds static void
29841255a8f3SJ. Bruce Fields nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session)
29851da177e4SLinus Torvalds {
2986dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
29871da177e4SLinus Torvalds }
29881da177e4SLinus Torvalds 
298914a24e99SJ. Bruce Fields /* Should we give out recallable state?: */
299014a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
299114a24e99SJ. Bruce Fields {
299214a24e99SJ. Bruce Fields 	if (clp->cl_cb_state == NFSD4_CB_UP)
299314a24e99SJ. Bruce Fields 		return true;
299414a24e99SJ. Bruce Fields 	/*
299514a24e99SJ. Bruce Fields 	 * In the sessions case, since we don't have to establish a
299614a24e99SJ. Bruce Fields 	 * separate connection for callbacks, we assume it's OK
299714a24e99SJ. Bruce Fields 	 * until we hear otherwise:
299814a24e99SJ. Bruce Fields 	 */
299914a24e99SJ. Bruce Fields 	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
300014a24e99SJ. Bruce Fields }
300114a24e99SJ. Bruce Fields 
300222d38c4cSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag)
300322d38c4cSJ. Bruce Fields {
300422d38c4cSJ. Bruce Fields 	struct file_lock *fl;
300522d38c4cSJ. Bruce Fields 
300622d38c4cSJ. Bruce Fields 	fl = locks_alloc_lock();
300722d38c4cSJ. Bruce Fields 	if (!fl)
300822d38c4cSJ. Bruce Fields 		return NULL;
300922d38c4cSJ. Bruce Fields 	locks_init_lock(fl);
301022d38c4cSJ. Bruce Fields 	fl->fl_lmops = &nfsd_lease_mng_ops;
301122d38c4cSJ. Bruce Fields 	fl->fl_flags = FL_LEASE;
301222d38c4cSJ. Bruce Fields 	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
301322d38c4cSJ. Bruce Fields 	fl->fl_end = OFFSET_MAX;
3014acfdf5c3SJ. Bruce Fields 	fl->fl_owner = (fl_owner_t)(dp->dl_file);
301522d38c4cSJ. Bruce Fields 	fl->fl_pid = current->tgid;
301622d38c4cSJ. Bruce Fields 	return fl;
301722d38c4cSJ. Bruce Fields }
301822d38c4cSJ. Bruce Fields 
301999c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp)
3020edab9782SJ. Bruce Fields {
3021acfdf5c3SJ. Bruce Fields 	struct nfs4_file *fp = dp->dl_file;
3022edab9782SJ. Bruce Fields 	struct file_lock *fl;
3023edab9782SJ. Bruce Fields 	int status;
3024edab9782SJ. Bruce Fields 
302599c41515SJ. Bruce Fields 	fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ);
3026edab9782SJ. Bruce Fields 	if (!fl)
3027edab9782SJ. Bruce Fields 		return -ENOMEM;
3028acfdf5c3SJ. Bruce Fields 	fl->fl_file = find_readable_file(fp);
30292a74aba7SJ. Bruce Fields 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
3030acfdf5c3SJ. Bruce Fields 	status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
3031edab9782SJ. Bruce Fields 	if (status) {
3032acfdf5c3SJ. Bruce Fields 		list_del_init(&dp->dl_perclnt);
3033edab9782SJ. Bruce Fields 		locks_free_lock(fl);
3034b1948a64SJ. Bruce Fields 		return status;
3035edab9782SJ. Bruce Fields 	}
3036acfdf5c3SJ. Bruce Fields 	fp->fi_lease = fl;
3037cb0942b8SAl Viro 	fp->fi_deleg_file = get_file(fl->fl_file);
3038acfdf5c3SJ. Bruce Fields 	atomic_set(&fp->fi_delegees, 1);
3039acfdf5c3SJ. Bruce Fields 	list_add(&dp->dl_perfile, &fp->fi_delegations);
3040acfdf5c3SJ. Bruce Fields 	return 0;
3041acfdf5c3SJ. Bruce Fields }
3042acfdf5c3SJ. Bruce Fields 
3043bf7bd3e9SJ. Bruce Fields static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
3044acfdf5c3SJ. Bruce Fields {
3045bf7bd3e9SJ. Bruce Fields 	int status;
3046acfdf5c3SJ. Bruce Fields 
3047bf7bd3e9SJ. Bruce Fields 	if (fp->fi_had_conflict)
3048bf7bd3e9SJ. Bruce Fields 		return -EAGAIN;
3049bf7bd3e9SJ. Bruce Fields 	get_nfs4_file(fp);
3050bf7bd3e9SJ. Bruce Fields 	dp->dl_file = fp;
3051bf7bd3e9SJ. Bruce Fields 	if (!fp->fi_lease) {
3052bf7bd3e9SJ. Bruce Fields 		status = nfs4_setlease(dp);
3053bf7bd3e9SJ. Bruce Fields 		if (status)
3054bf7bd3e9SJ. Bruce Fields 			goto out_free;
3055bf7bd3e9SJ. Bruce Fields 		return 0;
3056bf7bd3e9SJ. Bruce Fields 	}
3057acfdf5c3SJ. Bruce Fields 	spin_lock(&recall_lock);
3058acfdf5c3SJ. Bruce Fields 	if (fp->fi_had_conflict) {
3059acfdf5c3SJ. Bruce Fields 		spin_unlock(&recall_lock);
3060bf7bd3e9SJ. Bruce Fields 		status = -EAGAIN;
3061bf7bd3e9SJ. Bruce Fields 		goto out_free;
3062acfdf5c3SJ. Bruce Fields 	}
3063acfdf5c3SJ. Bruce Fields 	atomic_inc(&fp->fi_delegees);
3064acfdf5c3SJ. Bruce Fields 	list_add(&dp->dl_perfile, &fp->fi_delegations);
3065acfdf5c3SJ. Bruce Fields 	spin_unlock(&recall_lock);
30662a74aba7SJ. Bruce Fields 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
3067edab9782SJ. Bruce Fields 	return 0;
3068bf7bd3e9SJ. Bruce Fields out_free:
3069bf7bd3e9SJ. Bruce Fields 	put_nfs4_file(fp);
3070bf7bd3e9SJ. Bruce Fields 	dp->dl_file = fp;
3071bf7bd3e9SJ. Bruce Fields 	return status;
3072edab9782SJ. Bruce Fields }
3073edab9782SJ. Bruce Fields 
30744aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
30754aa8913cSBenny Halevy {
30764aa8913cSBenny Halevy 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
30774aa8913cSBenny Halevy 	if (status == -EAGAIN)
30784aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_CONTENTION;
30794aa8913cSBenny Halevy 	else {
30804aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_RESOURCE;
30814aa8913cSBenny Halevy 		switch (open->op_deleg_want) {
30824aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_READ_DELEG:
30834aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_WRITE_DELEG:
30844aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_ANY_DELEG:
30854aa8913cSBenny Halevy 			break;
30864aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_CANCEL:
30874aa8913cSBenny Halevy 			open->op_why_no_deleg = WND4_CANCELLED;
30884aa8913cSBenny Halevy 			break;
30894aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_NO_DELEG:
3090063b0fb9SJ. Bruce Fields 			WARN_ON_ONCE(1);
30914aa8913cSBenny Halevy 		}
30924aa8913cSBenny Halevy 	}
30934aa8913cSBenny Halevy }
30944aa8913cSBenny Halevy 
30951da177e4SLinus Torvalds /*
30961da177e4SLinus Torvalds  * Attempt to hand out a delegation.
309799c41515SJ. Bruce Fields  *
309899c41515SJ. Bruce Fields  * Note we don't support write delegations, and won't until the vfs has
309999c41515SJ. Bruce Fields  * proper support for them.
31001da177e4SLinus Torvalds  */
31011da177e4SLinus Torvalds static void
31025ccb0066SStanislav Kinsbursky nfs4_open_delegation(struct net *net, struct svc_fh *fh,
31035ccb0066SStanislav Kinsbursky 		     struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
31041da177e4SLinus Torvalds {
31051da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
3106fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
310714a24e99SJ. Bruce Fields 	int cb_up;
310899c41515SJ. Bruce Fields 	int status = 0;
31091da177e4SLinus Torvalds 
3110fe0750e5SJ. Bruce Fields 	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
31117b190fecSNeilBrown 	open->op_recall = 0;
31127b190fecSNeilBrown 	switch (open->op_claim_type) {
31137b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_PREVIOUS:
31142bf23875SJ. Bruce Fields 			if (!cb_up)
31157b190fecSNeilBrown 				open->op_recall = 1;
311699c41515SJ. Bruce Fields 			if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
311799c41515SJ. Bruce Fields 				goto out_no_deleg;
31187b190fecSNeilBrown 			break;
31197b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_NULL:
312099c41515SJ. Bruce Fields 			/*
312199c41515SJ. Bruce Fields 			 * Let's not give out any delegations till everyone's
312299c41515SJ. Bruce Fields 			 * had the chance to reclaim theirs....
312399c41515SJ. Bruce Fields 			 */
31245ccb0066SStanislav Kinsbursky 			if (locks_in_grace(net))
312599c41515SJ. Bruce Fields 				goto out_no_deleg;
3126dad1c067SJ. Bruce Fields 			if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
312799c41515SJ. Bruce Fields 				goto out_no_deleg;
31289a0590aeSSteve Dickson 			/*
31299a0590aeSSteve Dickson 			 * Also, if the file was opened for write or
31309a0590aeSSteve Dickson 			 * create, there's a good chance the client's
31319a0590aeSSteve Dickson 			 * about to write to it, resulting in an
31329a0590aeSSteve Dickson 			 * immediate recall (since we don't support
31339a0590aeSSteve Dickson 			 * write delegations):
31349a0590aeSSteve Dickson 			 */
31351da177e4SLinus Torvalds 			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
313699c41515SJ. Bruce Fields 				goto out_no_deleg;
313799c41515SJ. Bruce Fields 			if (open->op_create == NFS4_OPEN_CREATE)
313899c41515SJ. Bruce Fields 				goto out_no_deleg;
31397b190fecSNeilBrown 			break;
31407b190fecSNeilBrown 		default:
314199c41515SJ. Bruce Fields 			goto out_no_deleg;
31427b190fecSNeilBrown 	}
314399c41515SJ. Bruce Fields 	dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
3144dd239cc0SJ. Bruce Fields 	if (dp == NULL)
3145dd239cc0SJ. Bruce Fields 		goto out_no_deleg;
3146bf7bd3e9SJ. Bruce Fields 	status = nfs4_set_delegation(dp, stp->st_file);
3147edab9782SJ. Bruce Fields 	if (status)
3148dd239cc0SJ. Bruce Fields 		goto out_free;
31491da177e4SLinus Torvalds 
3150d5477a8dSJ. Bruce Fields 	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
31511da177e4SLinus Torvalds 
31528c10cbdbSBenny Halevy 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
3153d5477a8dSJ. Bruce Fields 		STATEID_VAL(&dp->dl_stid.sc_stateid));
315499c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
3155dd239cc0SJ. Bruce Fields 	return;
3156dd239cc0SJ. Bruce Fields out_free:
315724ffb938SJ. Bruce Fields 	unhash_stid(&dp->dl_stid);
3158acfdf5c3SJ. Bruce Fields 	nfs4_put_delegation(dp);
3159dd239cc0SJ. Bruce Fields out_no_deleg:
316099c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
31617b190fecSNeilBrown 	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
3162d08d32e6SJ. Bruce Fields 	    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
31631da177e4SLinus Torvalds 		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
3164d08d32e6SJ. Bruce Fields 		open->op_recall = 1;
3165d08d32e6SJ. Bruce Fields 	}
3166dd239cc0SJ. Bruce Fields 
3167dd239cc0SJ. Bruce Fields 	/* 4.1 client asking for a delegation? */
3168dd239cc0SJ. Bruce Fields 	if (open->op_deleg_want)
3169dd239cc0SJ. Bruce Fields 		nfsd4_open_deleg_none_ext(open, status);
3170dd239cc0SJ. Bruce Fields 	return;
31711da177e4SLinus Torvalds }
31721da177e4SLinus Torvalds 
3173e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
3174e27f49c3SBenny Halevy 					struct nfs4_delegation *dp)
3175e27f49c3SBenny Halevy {
3176e27f49c3SBenny Halevy 	if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
3177e27f49c3SBenny Halevy 	    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
3178e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
3179e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
3180e27f49c3SBenny Halevy 	} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
3181e27f49c3SBenny Halevy 		   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
3182e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
3183e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
3184e27f49c3SBenny Halevy 	}
3185e27f49c3SBenny Halevy 	/* Otherwise the client must be confused wanting a delegation
3186e27f49c3SBenny Halevy 	 * it already has, therefore we don't return
3187e27f49c3SBenny Halevy 	 * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
3188e27f49c3SBenny Halevy 	 */
3189e27f49c3SBenny Halevy }
3190e27f49c3SBenny Halevy 
31911da177e4SLinus Torvalds /*
31921da177e4SLinus Torvalds  * called with nfs4_lock_state() held.
31931da177e4SLinus Torvalds  */
3194b37ad28bSAl Viro __be32
31951da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
31961da177e4SLinus Torvalds {
31976668958fSAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
319838c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
31991da177e4SLinus Torvalds 	struct nfs4_file *fp = NULL;
32001da177e4SLinus Torvalds 	struct inode *ino = current_fh->fh_dentry->d_inode;
3201dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
3202567d9829SNeilBrown 	struct nfs4_delegation *dp = NULL;
3203b37ad28bSAl Viro 	__be32 status;
32041da177e4SLinus Torvalds 
32051da177e4SLinus Torvalds 	/*
32061da177e4SLinus Torvalds 	 * Lookup file; if found, lookup stateid and check open request,
32071da177e4SLinus Torvalds 	 * and check for delegations in the process of being recalled.
32081da177e4SLinus Torvalds 	 * If not found, create the nfs4_file struct
32091da177e4SLinus Torvalds 	 */
32101da177e4SLinus Torvalds 	fp = find_file(ino);
32111da177e4SLinus Torvalds 	if (fp) {
32121da177e4SLinus Torvalds 		if ((status = nfs4_check_open(fp, open, &stp)))
32131da177e4SLinus Torvalds 			goto out;
321441d22663SJ. Bruce Fields 		status = nfs4_check_deleg(cl, open, &dp);
3215c44c5eebSNeilBrown 		if (status)
3216c44c5eebSNeilBrown 			goto out;
32171da177e4SLinus Torvalds 	} else {
3218c44c5eebSNeilBrown 		status = nfserr_bad_stateid;
32198b289b2cSJ. Bruce Fields 		if (nfsd4_is_deleg_cur(open))
3220c44c5eebSNeilBrown 			goto out;
32213e772463SJ. Bruce Fields 		status = nfserr_jukebox;
322232513b40SJ. Bruce Fields 		fp = open->op_file;
322332513b40SJ. Bruce Fields 		open->op_file = NULL;
322432513b40SJ. Bruce Fields 		nfsd4_init_file(fp, ino);
32251da177e4SLinus Torvalds 	}
32261da177e4SLinus Torvalds 
32271da177e4SLinus Torvalds 	/*
32281da177e4SLinus Torvalds 	 * OPEN the file, or upgrade an existing OPEN.
32291da177e4SLinus Torvalds 	 * If truncate fails, the OPEN fails.
32301da177e4SLinus Torvalds 	 */
32311da177e4SLinus Torvalds 	if (stp) {
32321da177e4SLinus Torvalds 		/* Stateid was found, this is an OPEN upgrade */
3233f9d7562fSJ. Bruce Fields 		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
32341da177e4SLinus Torvalds 		if (status)
32351da177e4SLinus Torvalds 			goto out;
32361da177e4SLinus Torvalds 	} else {
32374cdc951bSJ. Bruce Fields 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, open);
3238567d9829SNeilBrown 		if (status)
32391da177e4SLinus Torvalds 			goto out;
32404af82504SJ. Bruce Fields 		status = nfsd4_truncate(rqstp, current_fh, open);
32414af82504SJ. Bruce Fields 		if (status)
32424af82504SJ. Bruce Fields 			goto out;
32434cdc951bSJ. Bruce Fields 		stp = open->op_stp;
32444cdc951bSJ. Bruce Fields 		open->op_stp = NULL;
3245996e0938SJ. Bruce Fields 		init_open_stateid(stp, fp, open);
32461da177e4SLinus Torvalds 	}
3247dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
3248dcef0413SJ. Bruce Fields 	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
32491da177e4SLinus Torvalds 
3250d24433cdSBenny Halevy 	if (nfsd4_has_session(&resp->cstate)) {
3251dad1c067SJ. Bruce Fields 		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
32526668958fSAndy Adamson 
3253d24433cdSBenny Halevy 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
3254d24433cdSBenny Halevy 			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
3255d24433cdSBenny Halevy 			open->op_why_no_deleg = WND4_NOT_WANTED;
3256d24433cdSBenny Halevy 			goto nodeleg;
3257d24433cdSBenny Halevy 		}
3258d24433cdSBenny Halevy 	}
3259d24433cdSBenny Halevy 
32601da177e4SLinus Torvalds 	/*
32611da177e4SLinus Torvalds 	* Attempt to hand out a delegation. No error return, because the
32621da177e4SLinus Torvalds 	* OPEN succeeds even if we fail.
32631da177e4SLinus Torvalds 	*/
32645ccb0066SStanislav Kinsbursky 	nfs4_open_delegation(SVC_NET(rqstp), current_fh, open, stp);
3265d24433cdSBenny Halevy nodeleg:
32661da177e4SLinus Torvalds 	status = nfs_ok;
32671da177e4SLinus Torvalds 
32688c10cbdbSBenny Halevy 	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
3269dcef0413SJ. Bruce Fields 		STATEID_VAL(&stp->st_stid.sc_stateid));
32701da177e4SLinus Torvalds out:
3271d24433cdSBenny Halevy 	/* 4.1 client trying to upgrade/downgrade delegation? */
3272d24433cdSBenny Halevy 	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
3273e27f49c3SBenny Halevy 	    open->op_deleg_want)
3274e27f49c3SBenny Halevy 		nfsd4_deleg_xgrade_none_ext(open, dp);
3275d24433cdSBenny Halevy 
327613cd2184SNeilBrown 	if (fp)
327713cd2184SNeilBrown 		put_nfs4_file(fp);
327837515177SNeilBrown 	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
32791255a8f3SJ. Bruce Fields 		nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate));
32801da177e4SLinus Torvalds 	/*
32811da177e4SLinus Torvalds 	* To finish the open response, we just need to set the rflags.
32821da177e4SLinus Torvalds 	*/
32831da177e4SLinus Torvalds 	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
3284dad1c067SJ. Bruce Fields 	if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
32856668958fSAndy Adamson 	    !nfsd4_has_session(&resp->cstate))
32861da177e4SLinus Torvalds 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
32871da177e4SLinus Torvalds 
32881da177e4SLinus Torvalds 	return status;
32891da177e4SLinus Torvalds }
32901da177e4SLinus Torvalds 
3291d29b20cdSJ. Bruce Fields void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
3292d29b20cdSJ. Bruce Fields {
3293d29b20cdSJ. Bruce Fields 	if (open->op_openowner) {
3294d29b20cdSJ. Bruce Fields 		struct nfs4_openowner *oo = open->op_openowner;
3295d29b20cdSJ. Bruce Fields 
3296d29b20cdSJ. Bruce Fields 		if (!list_empty(&oo->oo_owner.so_stateids))
3297d29b20cdSJ. Bruce Fields 			list_del_init(&oo->oo_close_lru);
3298d29b20cdSJ. Bruce Fields 		if (oo->oo_flags & NFS4_OO_NEW) {
3299d29b20cdSJ. Bruce Fields 			if (status) {
3300d29b20cdSJ. Bruce Fields 				release_openowner(oo);
3301d29b20cdSJ. Bruce Fields 				open->op_openowner = NULL;
3302d29b20cdSJ. Bruce Fields 			} else
3303d29b20cdSJ. Bruce Fields 				oo->oo_flags &= ~NFS4_OO_NEW;
3304d29b20cdSJ. Bruce Fields 		}
3305d29b20cdSJ. Bruce Fields 	}
330632513b40SJ. Bruce Fields 	if (open->op_file)
330732513b40SJ. Bruce Fields 		nfsd4_free_file(open->op_file);
33084cdc951bSJ. Bruce Fields 	if (open->op_stp)
3309ef79859eSJ. Bruce Fields 		free_generic_stateid(open->op_stp);
3310d29b20cdSJ. Bruce Fields }
3311d29b20cdSJ. Bruce Fields 
33129b2ef62bSJ. Bruce Fields static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp)
33139b2ef62bSJ. Bruce Fields {
33149b2ef62bSJ. Bruce Fields 	struct nfs4_client *found;
33159b2ef62bSJ. Bruce Fields 
33169b2ef62bSJ. Bruce Fields 	if (STALE_CLIENTID(clid, nn))
33179b2ef62bSJ. Bruce Fields 		return nfserr_stale_clientid;
33189b2ef62bSJ. Bruce Fields 	found = find_confirmed_client(clid, session, nn);
33199b2ef62bSJ. Bruce Fields 	if (clp)
33209b2ef62bSJ. Bruce Fields 		*clp = found;
33219b2ef62bSJ. Bruce Fields 	return found ? nfs_ok : nfserr_expired;
33229b2ef62bSJ. Bruce Fields }
33239b2ef62bSJ. Bruce Fields 
3324b37ad28bSAl Viro __be32
3325b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3326b591480bSJ.Bruce Fields 	    clientid_t *clid)
33271da177e4SLinus Torvalds {
33281da177e4SLinus Torvalds 	struct nfs4_client *clp;
3329b37ad28bSAl Viro 	__be32 status;
33307f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
33311da177e4SLinus Torvalds 
33321da177e4SLinus Torvalds 	nfs4_lock_state();
33331da177e4SLinus Torvalds 	dprintk("process_renew(%08x/%08x): starting\n",
33341da177e4SLinus Torvalds 			clid->cl_boot, clid->cl_id);
33359b2ef62bSJ. Bruce Fields 	status = lookup_clientid(clid, cstate->minorversion, nn, &clp);
33369b2ef62bSJ. Bruce Fields 	if (status)
33371da177e4SLinus Torvalds 		goto out;
33381da177e4SLinus Torvalds 	status = nfserr_cb_path_down;
3339ea1da636SNeilBrown 	if (!list_empty(&clp->cl_delegations)
334077a3569dSJ. Bruce Fields 			&& clp->cl_cb_state != NFSD4_CB_UP)
33411da177e4SLinus Torvalds 		goto out;
33421da177e4SLinus Torvalds 	status = nfs_ok;
33431da177e4SLinus Torvalds out:
33441da177e4SLinus Torvalds 	nfs4_unlock_state();
33451da177e4SLinus Torvalds 	return status;
33461da177e4SLinus Torvalds }
33471da177e4SLinus Torvalds 
3348a76b4319SNeilBrown static void
334912760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn)
3350a76b4319SNeilBrown {
335133dcc481SJeff Layton 	/* do nothing if grace period already ended */
3352a51c84edSStanislav Kinsbursky 	if (nn->grace_ended)
335333dcc481SJeff Layton 		return;
335433dcc481SJeff Layton 
3355a76b4319SNeilBrown 	dprintk("NFSD: end of grace period\n");
3356a51c84edSStanislav Kinsbursky 	nn->grace_ended = true;
335712760c66SStanislav Kinsbursky 	nfsd4_record_grace_done(nn, nn->boot_time);
33585e1533c7SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
3359e46b498cSJ. Bruce Fields 	/*
3360e46b498cSJ. Bruce Fields 	 * Now that every NFSv4 client has had the chance to recover and
3361e46b498cSJ. Bruce Fields 	 * to see the (possibly new, possibly shorter) lease time, we
3362e46b498cSJ. Bruce Fields 	 * can safely set the next grace time to the current lease time:
3363e46b498cSJ. Bruce Fields 	 */
33645284b44eSStanislav Kinsbursky 	nn->nfsd4_grace = nn->nfsd4_lease;
3365a76b4319SNeilBrown }
3366a76b4319SNeilBrown 
3367fd39ca9aSNeilBrown static time_t
336809121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn)
33691da177e4SLinus Torvalds {
33701da177e4SLinus Torvalds 	struct nfs4_client *clp;
3371fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
33721da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
33731da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
33743d733711SStanislav Kinsbursky 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
33753d733711SStanislav Kinsbursky 	time_t t, clientid_val = nn->nfsd4_lease;
33763d733711SStanislav Kinsbursky 	time_t u, test_val = nn->nfsd4_lease;
33771da177e4SLinus Torvalds 
33781da177e4SLinus Torvalds 	nfs4_lock_state();
33791da177e4SLinus Torvalds 
33801da177e4SLinus Torvalds 	dprintk("NFSD: laundromat service - starting\n");
338112760c66SStanislav Kinsbursky 	nfsd4_end_grace(nn);
338236acb66bSBenny Halevy 	INIT_LIST_HEAD(&reaplist);
3383c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
33845ed58bb2SStanislav Kinsbursky 	list_for_each_safe(pos, next, &nn->client_lru) {
33851da177e4SLinus Torvalds 		clp = list_entry(pos, struct nfs4_client, cl_lru);
33861da177e4SLinus Torvalds 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
33871da177e4SLinus Torvalds 			t = clp->cl_time - cutoff;
33881da177e4SLinus Torvalds 			if (clientid_val > t)
33891da177e4SLinus Torvalds 				clientid_val = t;
33901da177e4SLinus Torvalds 			break;
33911da177e4SLinus Torvalds 		}
3392221a6876SJ. Bruce Fields 		if (mark_client_expired_locked(clp)) {
3393d7682988SBenny Halevy 			dprintk("NFSD: client in use (clientid %08x)\n",
3394d7682988SBenny Halevy 				clp->cl_clientid.cl_id);
3395d7682988SBenny Halevy 			continue;
3396d7682988SBenny Halevy 		}
3397221a6876SJ. Bruce Fields 		list_move(&clp->cl_lru, &reaplist);
339836acb66bSBenny Halevy 	}
3399c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
340036acb66bSBenny Halevy 	list_for_each_safe(pos, next, &reaplist) {
340136acb66bSBenny Halevy 		clp = list_entry(pos, struct nfs4_client, cl_lru);
34021da177e4SLinus Torvalds 		dprintk("NFSD: purging unused client (clientid %08x)\n",
34031da177e4SLinus Torvalds 			clp->cl_clientid.cl_id);
34041da177e4SLinus Torvalds 		expire_client(clp);
34051da177e4SLinus Torvalds 	}
34061da177e4SLinus Torvalds 	spin_lock(&recall_lock);
3407e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
34081da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
34094e37a7c2SStanislav Kinsbursky 		if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn)
34104e37a7c2SStanislav Kinsbursky 			continue;
34111da177e4SLinus Torvalds 		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
34121da177e4SLinus Torvalds 			u = dp->dl_time - cutoff;
34131da177e4SLinus Torvalds 			if (test_val > u)
34141da177e4SLinus Torvalds 				test_val = u;
34151da177e4SLinus Torvalds 			break;
34161da177e4SLinus Torvalds 		}
34171da177e4SLinus Torvalds 		list_move(&dp->dl_recall_lru, &reaplist);
34181da177e4SLinus Torvalds 	}
34191da177e4SLinus Torvalds 	spin_unlock(&recall_lock);
34201da177e4SLinus Torvalds 	list_for_each_safe(pos, next, &reaplist) {
34211da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
34223bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
34231da177e4SLinus Torvalds 	}
34243d733711SStanislav Kinsbursky 	test_val = nn->nfsd4_lease;
342573758fedSStanislav Kinsbursky 	list_for_each_safe(pos, next, &nn->close_lru) {
3426fe0750e5SJ. Bruce Fields 		oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
3427fe0750e5SJ. Bruce Fields 		if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
3428fe0750e5SJ. Bruce Fields 			u = oo->oo_time - cutoff;
34291da177e4SLinus Torvalds 			if (test_val > u)
34301da177e4SLinus Torvalds 				test_val = u;
34311da177e4SLinus Torvalds 			break;
34321da177e4SLinus Torvalds 		}
3433fe0750e5SJ. Bruce Fields 		release_openowner(oo);
34341da177e4SLinus Torvalds 	}
34351da177e4SLinus Torvalds 	if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
34361da177e4SLinus Torvalds 		clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
34371da177e4SLinus Torvalds 	nfs4_unlock_state();
34381da177e4SLinus Torvalds 	return clientid_val;
34391da177e4SLinus Torvalds }
34401da177e4SLinus Torvalds 
3441a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq;
3442a254b246SHarvey Harrison static void laundromat_main(struct work_struct *);
3443a254b246SHarvey Harrison 
3444a254b246SHarvey Harrison static void
344509121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry)
34461da177e4SLinus Torvalds {
34471da177e4SLinus Torvalds 	time_t t;
344809121281SStanislav Kinsbursky 	struct delayed_work *dwork = container_of(laundry, struct delayed_work,
344909121281SStanislav Kinsbursky 						  work);
345009121281SStanislav Kinsbursky 	struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
345109121281SStanislav Kinsbursky 					   laundromat_work);
34521da177e4SLinus Torvalds 
345309121281SStanislav Kinsbursky 	t = nfs4_laundromat(nn);
34541da177e4SLinus Torvalds 	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
345509121281SStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
34561da177e4SLinus Torvalds }
34571da177e4SLinus Torvalds 
3458f7a4d872SJ. Bruce Fields static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
3459f8816512SNeilBrown {
3460f7a4d872SJ. Bruce Fields 	if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode)
3461f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
3462f7a4d872SJ. Bruce Fields 	return nfs_ok;
34631da177e4SLinus Torvalds }
34641da177e4SLinus Torvalds 
34651da177e4SLinus Torvalds static inline int
346682c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp)
34671da177e4SLinus Torvalds {
346882c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_READ, stp) ||
346982c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp) ||
347082c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_WRITE, stp);
34711da177e4SLinus Torvalds }
34721da177e4SLinus Torvalds 
34731da177e4SLinus Torvalds static inline int
347482c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp)
34751da177e4SLinus Torvalds {
347682c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_WRITE, stp) ||
347782c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp);
34781da177e4SLinus Torvalds }
34791da177e4SLinus Torvalds 
34801da177e4SLinus Torvalds static
3481dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
34821da177e4SLinus Torvalds {
3483b37ad28bSAl Viro         __be32 status = nfserr_openmode;
34841da177e4SLinus Torvalds 
348502921914SJ. Bruce Fields 	/* For lock stateid's, we test the parent open, not the lock: */
348602921914SJ. Bruce Fields 	if (stp->st_openstp)
348702921914SJ. Bruce Fields 		stp = stp->st_openstp;
348882c5ff1bSJeff Layton 	if ((flags & WR_STATE) && !access_permit_write(stp))
34891da177e4SLinus Torvalds                 goto out;
349082c5ff1bSJeff Layton 	if ((flags & RD_STATE) && !access_permit_read(stp))
34911da177e4SLinus Torvalds                 goto out;
34921da177e4SLinus Torvalds 	status = nfs_ok;
34931da177e4SLinus Torvalds out:
34941da177e4SLinus Torvalds 	return status;
34951da177e4SLinus Torvalds }
34961da177e4SLinus Torvalds 
3497b37ad28bSAl Viro static inline __be32
34985ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags)
34991da177e4SLinus Torvalds {
3500203a8c8eSJ. Bruce Fields 	if (ONE_STATEID(stateid) && (flags & RD_STATE))
35011da177e4SLinus Torvalds 		return nfs_ok;
35025ccb0066SStanislav Kinsbursky 	else if (locks_in_grace(net)) {
350325985edcSLucas De Marchi 		/* Answer in remaining cases depends on existence of
35041da177e4SLinus Torvalds 		 * conflicting state; so we must wait out the grace period. */
35051da177e4SLinus Torvalds 		return nfserr_grace;
35061da177e4SLinus Torvalds 	} else if (flags & WR_STATE)
35071da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
35081da177e4SLinus Torvalds 				NFS4_SHARE_DENY_WRITE);
35091da177e4SLinus Torvalds 	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
35101da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
35111da177e4SLinus Torvalds 				NFS4_SHARE_DENY_READ);
35121da177e4SLinus Torvalds }
35131da177e4SLinus Torvalds 
35141da177e4SLinus Torvalds /*
35151da177e4SLinus Torvalds  * Allow READ/WRITE during grace period on recovered state only for files
35161da177e4SLinus Torvalds  * that are not able to provide mandatory locking.
35171da177e4SLinus Torvalds  */
35181da177e4SLinus Torvalds static inline int
35195ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode)
35201da177e4SLinus Torvalds {
35215ccb0066SStanislav Kinsbursky 	return locks_in_grace(net) && mandatory_lock(inode);
35221da177e4SLinus Torvalds }
35231da177e4SLinus Torvalds 
352481b82965SJ. Bruce Fields /* Returns true iff a is later than b: */
352581b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b)
352681b82965SJ. Bruce Fields {
35271a9357f4SJim Rees 	return (s32)(a->si_generation - b->si_generation) > 0;
352881b82965SJ. Bruce Fields }
352981b82965SJ. Bruce Fields 
353057b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
35310836f587SJ. Bruce Fields {
35326668958fSAndy Adamson 	/*
35336668958fSAndy Adamson 	 * When sessions are used the stateid generation number is ignored
35346668958fSAndy Adamson 	 * when it is zero.
35356668958fSAndy Adamson 	 */
353628dde241SJ. Bruce Fields 	if (has_session && in->si_generation == 0)
353781b82965SJ. Bruce Fields 		return nfs_ok;
353881b82965SJ. Bruce Fields 
353981b82965SJ. Bruce Fields 	if (in->si_generation == ref->si_generation)
354081b82965SJ. Bruce Fields 		return nfs_ok;
35416668958fSAndy Adamson 
35420836f587SJ. Bruce Fields 	/* If the client sends us a stateid from the future, it's buggy: */
354381b82965SJ. Bruce Fields 	if (stateid_generation_after(in, ref))
35440836f587SJ. Bruce Fields 		return nfserr_bad_stateid;
35450836f587SJ. Bruce Fields 	/*
354681b82965SJ. Bruce Fields 	 * However, we could see a stateid from the past, even from a
354781b82965SJ. Bruce Fields 	 * non-buggy client.  For example, if the client sends a lock
354881b82965SJ. Bruce Fields 	 * while some IO is outstanding, the lock may bump si_generation
354981b82965SJ. Bruce Fields 	 * while the IO is still in flight.  The client could avoid that
355081b82965SJ. Bruce Fields 	 * situation by waiting for responses on all the IO requests,
355181b82965SJ. Bruce Fields 	 * but better performance may result in retrying IO that
355281b82965SJ. Bruce Fields 	 * receives an old_stateid error if requests are rarely
355381b82965SJ. Bruce Fields 	 * reordered in flight:
35540836f587SJ. Bruce Fields 	 */
35550836f587SJ. Bruce Fields 	return nfserr_old_stateid;
35560836f587SJ. Bruce Fields }
35570836f587SJ. Bruce Fields 
35587df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
355917456804SBryan Schumaker {
356097b7e3b6SJ. Bruce Fields 	struct nfs4_stid *s;
356197b7e3b6SJ. Bruce Fields 	struct nfs4_ol_stateid *ols;
356297b7e3b6SJ. Bruce Fields 	__be32 status;
356317456804SBryan Schumaker 
35647df302f7SChuck Lever 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
35657df302f7SChuck Lever 		return nfserr_bad_stateid;
35667df302f7SChuck Lever 	/* Client debugging aid. */
35677df302f7SChuck Lever 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
35687df302f7SChuck Lever 		char addr_str[INET6_ADDRSTRLEN];
35697df302f7SChuck Lever 		rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
35707df302f7SChuck Lever 				 sizeof(addr_str));
35717df302f7SChuck Lever 		pr_warn_ratelimited("NFSD: client %s testing state ID "
35727df302f7SChuck Lever 					"with incorrect client ID\n", addr_str);
35737df302f7SChuck Lever 		return nfserr_bad_stateid;
35747df302f7SChuck Lever 	}
357538c2f4b1SJ. Bruce Fields 	s = find_stateid(cl, stateid);
357697b7e3b6SJ. Bruce Fields 	if (!s)
35777df302f7SChuck Lever 		return nfserr_bad_stateid;
357836279ac1SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
357917456804SBryan Schumaker 	if (status)
358017456804SBryan Schumaker 		return status;
358123340032SJ. Bruce Fields 	switch (s->sc_type) {
358223340032SJ. Bruce Fields 	case NFS4_DELEG_STID:
358397b7e3b6SJ. Bruce Fields 		return nfs_ok;
35843bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
35853bd64a5bSJ. Bruce Fields 		return nfserr_deleg_revoked;
358623340032SJ. Bruce Fields 	case NFS4_OPEN_STID:
358723340032SJ. Bruce Fields 	case NFS4_LOCK_STID:
358897b7e3b6SJ. Bruce Fields 		ols = openlockstateid(s);
358997b7e3b6SJ. Bruce Fields 		if (ols->st_stateowner->so_is_open_owner
359023340032SJ. Bruce Fields 	    			&& !(openowner(ols->st_stateowner)->oo_flags
359123340032SJ. Bruce Fields 						& NFS4_OO_CONFIRMED))
359297b7e3b6SJ. Bruce Fields 			return nfserr_bad_stateid;
359397b7e3b6SJ. Bruce Fields 		return nfs_ok;
359423340032SJ. Bruce Fields 	default:
359523340032SJ. Bruce Fields 		printk("unknown stateid type %x\n", s->sc_type);
359623340032SJ. Bruce Fields 	case NFS4_CLOSED_STID:
359723340032SJ. Bruce Fields 		return nfserr_bad_stateid;
359823340032SJ. Bruce Fields 	}
359917456804SBryan Schumaker }
360017456804SBryan Schumaker 
36013320fef1SStanislav Kinsbursky static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
36023320fef1SStanislav Kinsbursky 				   struct nfs4_stid **s, bool sessions,
36033320fef1SStanislav Kinsbursky 				   struct nfsd_net *nn)
360438c2f4b1SJ. Bruce Fields {
360538c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl;
36060eb6f20aSJ. Bruce Fields 	__be32 status;
360738c2f4b1SJ. Bruce Fields 
360838c2f4b1SJ. Bruce Fields 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
360938c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
36100eb6f20aSJ. Bruce Fields 	status = lookup_clientid(&stateid->si_opaque.so_clid, sessions,
36110eb6f20aSJ. Bruce Fields 							nn, &cl);
36120eb6f20aSJ. Bruce Fields 	if (status == nfserr_stale_clientid)
361338c2f4b1SJ. Bruce Fields 		return nfserr_stale_stateid;
36140eb6f20aSJ. Bruce Fields 	if (status)
36150eb6f20aSJ. Bruce Fields 		return status;
361638c2f4b1SJ. Bruce Fields 	*s = find_stateid_by_type(cl, stateid, typemask);
361738c2f4b1SJ. Bruce Fields 	if (!*s)
361838c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
361938c2f4b1SJ. Bruce Fields 	return nfs_ok;
362038c2f4b1SJ. Bruce Fields }
362138c2f4b1SJ. Bruce Fields 
36221da177e4SLinus Torvalds /*
36231da177e4SLinus Torvalds * Checks for stateid operations
36241da177e4SLinus Torvalds */
3625b37ad28bSAl Viro __be32
36265ccb0066SStanislav Kinsbursky nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
3627dd453dfdSBenny Halevy 			   stateid_t *stateid, int flags, struct file **filpp)
36281da177e4SLinus Torvalds {
362969064a27SJ. Bruce Fields 	struct nfs4_stid *s;
3630dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
36311da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
3632dd453dfdSBenny Halevy 	struct svc_fh *current_fh = &cstate->current_fh;
36331da177e4SLinus Torvalds 	struct inode *ino = current_fh->fh_dentry->d_inode;
36343320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
3635b37ad28bSAl Viro 	__be32 status;
36361da177e4SLinus Torvalds 
36371da177e4SLinus Torvalds 	if (filpp)
36381da177e4SLinus Torvalds 		*filpp = NULL;
36391da177e4SLinus Torvalds 
36405ccb0066SStanislav Kinsbursky 	if (grace_disallows_io(net, ino))
36411da177e4SLinus Torvalds 		return nfserr_grace;
36421da177e4SLinus Torvalds 
36431da177e4SLinus Torvalds 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
36445ccb0066SStanislav Kinsbursky 		return check_special_stateids(net, current_fh, stateid, flags);
36451da177e4SLinus Torvalds 
36463320fef1SStanislav Kinsbursky 	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
36473320fef1SStanislav Kinsbursky 				      &s, cstate->minorversion, nn);
364838c2f4b1SJ. Bruce Fields 	if (status)
364938c2f4b1SJ. Bruce Fields 		return status;
365069064a27SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
36510c2a498fSJ. Bruce Fields 	if (status)
36520c2a498fSJ. Bruce Fields 		goto out;
3653f7a4d872SJ. Bruce Fields 	switch (s->sc_type) {
3654f7a4d872SJ. Bruce Fields 	case NFS4_DELEG_STID:
365569064a27SJ. Bruce Fields 		dp = delegstateid(s);
3656dc9bf700SJ. Bruce Fields 		status = nfs4_check_delegmode(dp, flags);
3657dc9bf700SJ. Bruce Fields 		if (status)
3658dc9bf700SJ. Bruce Fields 			goto out;
365943b0178eSDan Carpenter 		if (filpp) {
3660acfdf5c3SJ. Bruce Fields 			*filpp = dp->dl_file->fi_deleg_file;
3661063b0fb9SJ. Bruce Fields 			if (!*filpp) {
3662063b0fb9SJ. Bruce Fields 				WARN_ON_ONCE(1);
3663063b0fb9SJ. Bruce Fields 				status = nfserr_serverfault;
3664063b0fb9SJ. Bruce Fields 				goto out;
3665063b0fb9SJ. Bruce Fields 			}
366643b0178eSDan Carpenter 		}
3667f7a4d872SJ. Bruce Fields 		break;
3668f7a4d872SJ. Bruce Fields 	case NFS4_OPEN_STID:
3669f7a4d872SJ. Bruce Fields 	case NFS4_LOCK_STID:
367069064a27SJ. Bruce Fields 		stp = openlockstateid(s);
3671f7a4d872SJ. Bruce Fields 		status = nfs4_check_fh(current_fh, stp);
3672f7a4d872SJ. Bruce Fields 		if (status)
36731da177e4SLinus Torvalds 			goto out;
3674fe0750e5SJ. Bruce Fields 		if (stp->st_stateowner->so_is_open_owner
3675dad1c067SJ. Bruce Fields 		    && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
36761da177e4SLinus Torvalds 			goto out;
3677a4455be0SJ. Bruce Fields 		status = nfs4_check_openmode(stp, flags);
3678a4455be0SJ. Bruce Fields 		if (status)
36791da177e4SLinus Torvalds 			goto out;
3680f9d7562fSJ. Bruce Fields 		if (filpp) {
3681f9d7562fSJ. Bruce Fields 			if (flags & RD_STATE)
3682f9d7562fSJ. Bruce Fields 				*filpp = find_readable_file(stp->st_file);
3683f9d7562fSJ. Bruce Fields 			else
3684f9d7562fSJ. Bruce Fields 				*filpp = find_writeable_file(stp->st_file);
3685f9d7562fSJ. Bruce Fields 		}
3686f7a4d872SJ. Bruce Fields 		break;
3687f7a4d872SJ. Bruce Fields 	default:
3688f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
36891da177e4SLinus Torvalds 	}
36901da177e4SLinus Torvalds 	status = nfs_ok;
36911da177e4SLinus Torvalds out:
36921da177e4SLinus Torvalds 	return status;
36931da177e4SLinus Torvalds }
36941da177e4SLinus Torvalds 
3695e1ca12dfSBryan Schumaker static __be32
3696dcef0413SJ. Bruce Fields nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
3697e1ca12dfSBryan Schumaker {
3698fe0750e5SJ. Bruce Fields 	if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
3699e1ca12dfSBryan Schumaker 		return nfserr_locks_held;
3700e1ca12dfSBryan Schumaker 	release_lock_stateid(stp);
3701e1ca12dfSBryan Schumaker 	return nfs_ok;
3702e1ca12dfSBryan Schumaker }
3703e1ca12dfSBryan Schumaker 
3704e1ca12dfSBryan Schumaker /*
370517456804SBryan Schumaker  * Test if the stateid is valid
370617456804SBryan Schumaker  */
370717456804SBryan Schumaker __be32
370817456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
370917456804SBryan Schumaker 		   struct nfsd4_test_stateid *test_stateid)
371017456804SBryan Schumaker {
371103cfb420SBryan Schumaker 	struct nfsd4_test_stateid_id *stateid;
371203cfb420SBryan Schumaker 	struct nfs4_client *cl = cstate->session->se_client;
371303cfb420SBryan Schumaker 
371403cfb420SBryan Schumaker 	nfs4_lock_state();
371503cfb420SBryan Schumaker 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
37167df302f7SChuck Lever 		stateid->ts_id_status =
37177df302f7SChuck Lever 			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
371803cfb420SBryan Schumaker 	nfs4_unlock_state();
371903cfb420SBryan Schumaker 
372017456804SBryan Schumaker 	return nfs_ok;
372117456804SBryan Schumaker }
372217456804SBryan Schumaker 
3723e1ca12dfSBryan Schumaker __be32
3724e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3725e1ca12dfSBryan Schumaker 		   struct nfsd4_free_stateid *free_stateid)
3726e1ca12dfSBryan Schumaker {
3727e1ca12dfSBryan Schumaker 	stateid_t *stateid = &free_stateid->fr_stateid;
37282da1cec7SJ. Bruce Fields 	struct nfs4_stid *s;
37293bd64a5bSJ. Bruce Fields 	struct nfs4_delegation *dp;
373038c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = cstate->session->se_client;
37312da1cec7SJ. Bruce Fields 	__be32 ret = nfserr_bad_stateid;
3732e1ca12dfSBryan Schumaker 
3733e1ca12dfSBryan Schumaker 	nfs4_lock_state();
373438c2f4b1SJ. Bruce Fields 	s = find_stateid(cl, stateid);
37352da1cec7SJ. Bruce Fields 	if (!s)
3736e1ca12dfSBryan Schumaker 		goto out;
37372da1cec7SJ. Bruce Fields 	switch (s->sc_type) {
37382da1cec7SJ. Bruce Fields 	case NFS4_DELEG_STID:
3739e1ca12dfSBryan Schumaker 		ret = nfserr_locks_held;
3740e1ca12dfSBryan Schumaker 		goto out;
37412da1cec7SJ. Bruce Fields 	case NFS4_OPEN_STID:
37422da1cec7SJ. Bruce Fields 	case NFS4_LOCK_STID:
37432da1cec7SJ. Bruce Fields 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
37442da1cec7SJ. Bruce Fields 		if (ret)
3745e1ca12dfSBryan Schumaker 			goto out;
37462da1cec7SJ. Bruce Fields 		if (s->sc_type == NFS4_LOCK_STID)
37472da1cec7SJ. Bruce Fields 			ret = nfsd4_free_lock_stateid(openlockstateid(s));
37482da1cec7SJ. Bruce Fields 		else
37492da1cec7SJ. Bruce Fields 			ret = nfserr_locks_held;
3750f7a4d872SJ. Bruce Fields 		break;
37513bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
37523bd64a5bSJ. Bruce Fields 		dp = delegstateid(s);
37533bd64a5bSJ. Bruce Fields 		destroy_revoked_delegation(dp);
37543bd64a5bSJ. Bruce Fields 		ret = nfs_ok;
37553bd64a5bSJ. Bruce Fields 		break;
3756f7a4d872SJ. Bruce Fields 	default:
3757f7a4d872SJ. Bruce Fields 		ret = nfserr_bad_stateid;
3758e1ca12dfSBryan Schumaker 	}
3759e1ca12dfSBryan Schumaker out:
3760e1ca12dfSBryan Schumaker 	nfs4_unlock_state();
3761e1ca12dfSBryan Schumaker 	return ret;
3762e1ca12dfSBryan Schumaker }
3763e1ca12dfSBryan Schumaker 
37644c4cd222SNeilBrown static inline int
37654c4cd222SNeilBrown setlkflg (int type)
37664c4cd222SNeilBrown {
37674c4cd222SNeilBrown 	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
37684c4cd222SNeilBrown 		RD_STATE : WR_STATE;
37694c4cd222SNeilBrown }
37701da177e4SLinus Torvalds 
3771dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
3772c0a5d93eSJ. Bruce Fields {
3773c0a5d93eSJ. Bruce Fields 	struct svc_fh *current_fh = &cstate->current_fh;
3774c0a5d93eSJ. Bruce Fields 	struct nfs4_stateowner *sop = stp->st_stateowner;
3775c0a5d93eSJ. Bruce Fields 	__be32 status;
3776c0a5d93eSJ. Bruce Fields 
3777c0a5d93eSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, sop, seqid);
3778c0a5d93eSJ. Bruce Fields 	if (status)
3779c0a5d93eSJ. Bruce Fields 		return status;
37803bd64a5bSJ. Bruce Fields 	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
37813bd64a5bSJ. Bruce Fields 		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
3782f7a4d872SJ. Bruce Fields 		/*
3783f7a4d872SJ. Bruce Fields 		 * "Closed" stateid's exist *only* to return
37843bd64a5bSJ. Bruce Fields 		 * nfserr_replay_me from the previous step, and
37853bd64a5bSJ. Bruce Fields 		 * revoked delegations are kept only for free_stateid.
3786f7a4d872SJ. Bruce Fields 		 */
3787f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
3788f7a4d872SJ. Bruce Fields 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
3789f7a4d872SJ. Bruce Fields 	if (status)
3790f7a4d872SJ. Bruce Fields 		return status;
3791f7a4d872SJ. Bruce Fields 	return nfs4_check_fh(current_fh, stp);
3792c0a5d93eSJ. Bruce Fields }
3793c0a5d93eSJ. Bruce Fields 
37941da177e4SLinus Torvalds /*
37951da177e4SLinus Torvalds  * Checks for sequence id mutating operations.
37961da177e4SLinus Torvalds  */
3797b37ad28bSAl Viro static __be32
3798dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
37992288d0e3SJ. Bruce Fields 			 stateid_t *stateid, char typemask,
38003320fef1SStanislav Kinsbursky 			 struct nfs4_ol_stateid **stpp,
38013320fef1SStanislav Kinsbursky 			 struct nfsd_net *nn)
38021da177e4SLinus Torvalds {
38030836f587SJ. Bruce Fields 	__be32 status;
380438c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
38051da177e4SLinus Torvalds 
38068c10cbdbSBenny Halevy 	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
38078c10cbdbSBenny Halevy 		seqid, STATEID_VAL(stateid));
38081da177e4SLinus Torvalds 
38091da177e4SLinus Torvalds 	*stpp = NULL;
38103320fef1SStanislav Kinsbursky 	status = nfsd4_lookup_stateid(stateid, typemask, &s,
38113320fef1SStanislav Kinsbursky 				      cstate->minorversion, nn);
3812c0a5d93eSJ. Bruce Fields 	if (status)
3813c0a5d93eSJ. Bruce Fields 		return status;
381438c2f4b1SJ. Bruce Fields 	*stpp = openlockstateid(s);
38153d74e6a5SJ. Bruce Fields 	if (!nfsd4_has_session(cstate))
3816c0a5d93eSJ. Bruce Fields 		cstate->replay_owner = (*stpp)->st_stateowner;
38171da177e4SLinus Torvalds 
3818c0a5d93eSJ. Bruce Fields 	return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
38191da177e4SLinus Torvalds }
38201da177e4SLinus Torvalds 
38213320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
38223320fef1SStanislav Kinsbursky 						 stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn)
3823c0a5d93eSJ. Bruce Fields {
3824c0a5d93eSJ. Bruce Fields 	__be32 status;
3825c0a5d93eSJ. Bruce Fields 	struct nfs4_openowner *oo;
38261da177e4SLinus Torvalds 
3827c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
38283320fef1SStanislav Kinsbursky 						NFS4_OPEN_STID, stpp, nn);
38290836f587SJ. Bruce Fields 	if (status)
38300836f587SJ. Bruce Fields 		return status;
3831c0a5d93eSJ. Bruce Fields 	oo = openowner((*stpp)->st_stateowner);
3832dad1c067SJ. Bruce Fields 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED))
3833c0a5d93eSJ. Bruce Fields 		return nfserr_bad_stateid;
38343a4f98bbSNeilBrown 	return nfs_ok;
38351da177e4SLinus Torvalds }
38361da177e4SLinus Torvalds 
3837b37ad28bSAl Viro __be32
3838ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3839a4f1706aSJ.Bruce Fields 		   struct nfsd4_open_confirm *oc)
38401da177e4SLinus Torvalds {
3841b37ad28bSAl Viro 	__be32 status;
3842fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
3843dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
38443320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
38451da177e4SLinus Torvalds 
3846*a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_confirm on file %pd\n",
3847*a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
38481da177e4SLinus Torvalds 
3849ca364317SJ.Bruce Fields 	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
3850a8cddc5dSJ. Bruce Fields 	if (status)
3851a8cddc5dSJ. Bruce Fields 		return status;
38521da177e4SLinus Torvalds 
38531da177e4SLinus Torvalds 	nfs4_lock_state();
38541da177e4SLinus Torvalds 
38559072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate,
3856ca364317SJ.Bruce Fields 					oc->oc_seqid, &oc->oc_req_stateid,
38573320fef1SStanislav Kinsbursky 					NFS4_OPEN_STID, &stp, nn);
38589072d5c6SJ. Bruce Fields 	if (status)
38591da177e4SLinus Torvalds 		goto out;
3860fe0750e5SJ. Bruce Fields 	oo = openowner(stp->st_stateowner);
386168b66e82SJ. Bruce Fields 	status = nfserr_bad_stateid;
3862dad1c067SJ. Bruce Fields 	if (oo->oo_flags & NFS4_OO_CONFIRMED)
386368b66e82SJ. Bruce Fields 		goto out;
3864dad1c067SJ. Bruce Fields 	oo->oo_flags |= NFS4_OO_CONFIRMED;
3865dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
3866dcef0413SJ. Bruce Fields 	memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
38678c10cbdbSBenny Halevy 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
3868dcef0413SJ. Bruce Fields 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
3869c7b9a459SNeilBrown 
38702a4317c5SJeff Layton 	nfsd4_client_record_create(oo->oo_owner.so_client);
387168b66e82SJ. Bruce Fields 	status = nfs_ok;
38721da177e4SLinus Torvalds out:
38739411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
38745ec094c1SJ. Bruce Fields 	if (!cstate->replay_owner)
38751da177e4SLinus Torvalds 		nfs4_unlock_state();
38761da177e4SLinus Torvalds 	return status;
38771da177e4SLinus Torvalds }
38781da177e4SLinus Torvalds 
38796409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
38801da177e4SLinus Torvalds {
388182c5ff1bSJeff Layton 	if (!test_access(access, stp))
38826409a5a6SJ. Bruce Fields 		return;
38836409a5a6SJ. Bruce Fields 	nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access));
388482c5ff1bSJeff Layton 	clear_access(access, stp);
3885f197c271SJ. Bruce Fields }
38866409a5a6SJ. Bruce Fields 
38876409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
38886409a5a6SJ. Bruce Fields {
38896409a5a6SJ. Bruce Fields 	switch (to_access) {
38906409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
38916409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
38926409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
38936409a5a6SJ. Bruce Fields 		break;
38946409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
38956409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
38966409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
38976409a5a6SJ. Bruce Fields 		break;
38986409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
38996409a5a6SJ. Bruce Fields 		break;
39006409a5a6SJ. Bruce Fields 	default:
3901063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
39021da177e4SLinus Torvalds 	}
39031da177e4SLinus Torvalds }
39041da177e4SLinus Torvalds 
39051da177e4SLinus Torvalds static void
3906ce0fc43cSJeff Layton reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp)
39071da177e4SLinus Torvalds {
39081da177e4SLinus Torvalds 	int i;
39091da177e4SLinus Torvalds 	for (i = 0; i < 4; i++) {
39101da177e4SLinus Torvalds 		if ((i & deny) != i)
3911ce0fc43cSJeff Layton 			clear_deny(i, stp);
39121da177e4SLinus Torvalds 	}
39131da177e4SLinus Torvalds }
39141da177e4SLinus Torvalds 
3915b37ad28bSAl Viro __be32
3916ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp,
3917ca364317SJ.Bruce Fields 		     struct nfsd4_compound_state *cstate,
3918a4f1706aSJ.Bruce Fields 		     struct nfsd4_open_downgrade *od)
39191da177e4SLinus Torvalds {
3920b37ad28bSAl Viro 	__be32 status;
3921dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
39223320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
39231da177e4SLinus Torvalds 
3924*a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_downgrade on file %pd\n",
3925*a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
39261da177e4SLinus Torvalds 
3927c30e92dfSJ. Bruce Fields 	/* We don't yet support WANT bits: */
39282c8bd7e0SBenny Halevy 	if (od->od_deleg_want)
39292c8bd7e0SBenny Halevy 		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
39302c8bd7e0SBenny Halevy 			od->od_deleg_want);
39311da177e4SLinus Torvalds 
39321da177e4SLinus Torvalds 	nfs4_lock_state();
3933c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
39343320fef1SStanislav Kinsbursky 					&od->od_stateid, &stp, nn);
39359072d5c6SJ. Bruce Fields 	if (status)
39361da177e4SLinus Torvalds 		goto out;
39371da177e4SLinus Torvalds 	status = nfserr_inval;
393882c5ff1bSJeff Layton 	if (!test_access(od->od_share_access, stp)) {
39391da177e4SLinus Torvalds 		dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n",
39401da177e4SLinus Torvalds 			stp->st_access_bmap, od->od_share_access);
39411da177e4SLinus Torvalds 		goto out;
39421da177e4SLinus Torvalds 	}
3943ce0fc43cSJeff Layton 	if (!test_deny(od->od_share_deny, stp)) {
39441da177e4SLinus Torvalds 		dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n",
39451da177e4SLinus Torvalds 			stp->st_deny_bmap, od->od_share_deny);
39461da177e4SLinus Torvalds 		goto out;
39471da177e4SLinus Torvalds 	}
39486409a5a6SJ. Bruce Fields 	nfs4_stateid_downgrade(stp, od->od_share_access);
39491da177e4SLinus Torvalds 
3950ce0fc43cSJeff Layton 	reset_union_bmap_deny(od->od_share_deny, stp);
39511da177e4SLinus Torvalds 
3952dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
3953dcef0413SJ. Bruce Fields 	memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
39541da177e4SLinus Torvalds 	status = nfs_ok;
39551da177e4SLinus Torvalds out:
39569411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
39575ec094c1SJ. Bruce Fields 	if (!cstate->replay_owner)
39581da177e4SLinus Torvalds 		nfs4_unlock_state();
39591da177e4SLinus Torvalds 	return status;
39601da177e4SLinus Torvalds }
39611da177e4SLinus Torvalds 
3962f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
3963f7a4d872SJ. Bruce Fields {
3964f7a4d872SJ. Bruce Fields 	unhash_open_stateid(s);
3965f7a4d872SJ. Bruce Fields 	s->st_stid.sc_type = NFS4_CLOSED_STID;
396638c387b5SJ. Bruce Fields }
396738c387b5SJ. Bruce Fields 
39681da177e4SLinus Torvalds /*
39691da177e4SLinus Torvalds  * nfs4_unlock_state() called after encode
39701da177e4SLinus Torvalds  */
3971b37ad28bSAl Viro __be32
3972ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3973a4f1706aSJ.Bruce Fields 	    struct nfsd4_close *close)
39741da177e4SLinus Torvalds {
3975b37ad28bSAl Viro 	__be32 status;
3976fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
3977dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
39783320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
39793320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
39801da177e4SLinus Torvalds 
3981*a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_close on file %pd\n",
3982*a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
39831da177e4SLinus Torvalds 
39841da177e4SLinus Torvalds 	nfs4_lock_state();
3985f7a4d872SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
3986f7a4d872SJ. Bruce Fields 					&close->cl_stateid,
3987f7a4d872SJ. Bruce Fields 					NFS4_OPEN_STID|NFS4_CLOSED_STID,
39883320fef1SStanislav Kinsbursky 					&stp, nn);
39899411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
39909072d5c6SJ. Bruce Fields 	if (status)
39911da177e4SLinus Torvalds 		goto out;
3992fe0750e5SJ. Bruce Fields 	oo = openowner(stp->st_stateowner);
3993dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
3994dcef0413SJ. Bruce Fields 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
39951da177e4SLinus Torvalds 
3996f7a4d872SJ. Bruce Fields 	nfsd4_close_open_stateid(stp);
39979411b1d4SJ. Bruce Fields 
39989411b1d4SJ. Bruce Fields 	if (cstate->minorversion) {
39999411b1d4SJ. Bruce Fields 		unhash_stid(&stp->st_stid);
40009411b1d4SJ. Bruce Fields 		free_generic_stateid(stp);
40019411b1d4SJ. Bruce Fields 	} else
400238c387b5SJ. Bruce Fields 		oo->oo_last_closed_stid = stp;
400304ef5954SJ. Bruce Fields 
400474dbafafSJ. Bruce Fields 	if (list_empty(&oo->oo_owner.so_stateids)) {
40053d74e6a5SJ. Bruce Fields 		if (cstate->minorversion)
400674dbafafSJ. Bruce Fields 			release_openowner(oo);
40073d74e6a5SJ. Bruce Fields 		else {
400874dbafafSJ. Bruce Fields 			/*
400974dbafafSJ. Bruce Fields 			 * In the 4.0 case we need to keep the owners around a
401074dbafafSJ. Bruce Fields 			 * little while to handle CLOSE replay.
401104ef5954SJ. Bruce Fields 			 */
401273758fedSStanislav Kinsbursky 			move_to_close_lru(oo, SVC_NET(rqstp));
401374dbafafSJ. Bruce Fields 		}
401474dbafafSJ. Bruce Fields 	}
40151da177e4SLinus Torvalds out:
40165ec094c1SJ. Bruce Fields 	if (!cstate->replay_owner)
40171da177e4SLinus Torvalds 		nfs4_unlock_state();
40181da177e4SLinus Torvalds 	return status;
40191da177e4SLinus Torvalds }
40201da177e4SLinus Torvalds 
4021b37ad28bSAl Viro __be32
4022ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4023ca364317SJ.Bruce Fields 		  struct nfsd4_delegreturn *dr)
40241da177e4SLinus Torvalds {
4025203a8c8eSJ. Bruce Fields 	struct nfs4_delegation *dp;
4026203a8c8eSJ. Bruce Fields 	stateid_t *stateid = &dr->dr_stateid;
402738c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
4028b37ad28bSAl Viro 	__be32 status;
40293320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
40301da177e4SLinus Torvalds 
4031ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
4032203a8c8eSJ. Bruce Fields 		return status;
40331da177e4SLinus Torvalds 
40341da177e4SLinus Torvalds 	nfs4_lock_state();
40353320fef1SStanislav Kinsbursky 	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s,
40363320fef1SStanislav Kinsbursky 				      cstate->minorversion, nn);
403738c2f4b1SJ. Bruce Fields 	if (status)
4038203a8c8eSJ. Bruce Fields 		goto out;
403938c2f4b1SJ. Bruce Fields 	dp = delegstateid(s);
4040d5477a8dSJ. Bruce Fields 	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
4041203a8c8eSJ. Bruce Fields 	if (status)
4042203a8c8eSJ. Bruce Fields 		goto out;
4043203a8c8eSJ. Bruce Fields 
40443bd64a5bSJ. Bruce Fields 	destroy_delegation(dp);
40451da177e4SLinus Torvalds out:
4046203a8c8eSJ. Bruce Fields 	nfs4_unlock_state();
4047203a8c8eSJ. Bruce Fields 
40481da177e4SLinus Torvalds 	return status;
40491da177e4SLinus Torvalds }
40501da177e4SLinus Torvalds 
40511da177e4SLinus Torvalds 
40521da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
40531da177e4SLinus Torvalds 
4054009673b4SJ. Bruce Fields #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
40551da177e4SLinus Torvalds 
405687df4de8SBenny Halevy static inline u64
405787df4de8SBenny Halevy end_offset(u64 start, u64 len)
405887df4de8SBenny Halevy {
405987df4de8SBenny Halevy 	u64 end;
406087df4de8SBenny Halevy 
406187df4de8SBenny Halevy 	end = start + len;
406287df4de8SBenny Halevy 	return end >= start ? end: NFS4_MAX_UINT64;
406387df4de8SBenny Halevy }
406487df4de8SBenny Halevy 
406587df4de8SBenny Halevy /* last octet in a range */
406687df4de8SBenny Halevy static inline u64
406787df4de8SBenny Halevy last_byte_offset(u64 start, u64 len)
406887df4de8SBenny Halevy {
406987df4de8SBenny Halevy 	u64 end;
407087df4de8SBenny Halevy 
4071063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(!len);
407287df4de8SBenny Halevy 	end = start + len;
407387df4de8SBenny Halevy 	return end > start ? end - 1: NFS4_MAX_UINT64;
407487df4de8SBenny Halevy }
407587df4de8SBenny Halevy 
4076009673b4SJ. Bruce Fields static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
40771da177e4SLinus Torvalds {
40781da177e4SLinus Torvalds 	return (file_hashval(inode) + cl_id
40791da177e4SLinus Torvalds 			+ opaque_hashval(ownername->data, ownername->len))
4080009673b4SJ. Bruce Fields 		& LOCKOWNER_INO_HASH_MASK;
40811da177e4SLinus Torvalds }
40821da177e4SLinus Torvalds 
40831da177e4SLinus Torvalds /*
40841da177e4SLinus Torvalds  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
40851da177e4SLinus Torvalds  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
40861da177e4SLinus Torvalds  * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
40871da177e4SLinus Torvalds  * locking, this prevents us from being completely protocol-compliant.  The
40881da177e4SLinus Torvalds  * real solution to this problem is to start using unsigned file offsets in
40891da177e4SLinus Torvalds  * the VFS, but this is a very deep change!
40901da177e4SLinus Torvalds  */
40911da177e4SLinus Torvalds static inline void
40921da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock)
40931da177e4SLinus Torvalds {
40941da177e4SLinus Torvalds 	if (lock->fl_start < 0)
40951da177e4SLinus Torvalds 		lock->fl_start = OFFSET_MAX;
40961da177e4SLinus Torvalds 	if (lock->fl_end < 0)
40971da177e4SLinus Torvalds 		lock->fl_end = OFFSET_MAX;
40981da177e4SLinus Torvalds }
40991da177e4SLinus Torvalds 
4100d5b9026aSNeilBrown /* Hack!: For now, we're defining this just so we can use a pointer to it
4101d5b9026aSNeilBrown  * as a unique cookie to identify our (NFSv4's) posix locks. */
41027b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops  = {
4103d5b9026aSNeilBrown };
41041da177e4SLinus Torvalds 
41051da177e4SLinus Torvalds static inline void
41061da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
41071da177e4SLinus Torvalds {
4108fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
41091da177e4SLinus Torvalds 
4110d5b9026aSNeilBrown 	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
4111fe0750e5SJ. Bruce Fields 		lo = (struct nfs4_lockowner *) fl->fl_owner;
4112fe0750e5SJ. Bruce Fields 		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
4113fe0750e5SJ. Bruce Fields 					lo->lo_owner.so_owner.len, GFP_KERNEL);
41147c13f344SJ. Bruce Fields 		if (!deny->ld_owner.data)
41157c13f344SJ. Bruce Fields 			/* We just don't care that much */
41167c13f344SJ. Bruce Fields 			goto nevermind;
4117fe0750e5SJ. Bruce Fields 		deny->ld_owner.len = lo->lo_owner.so_owner.len;
4118fe0750e5SJ. Bruce Fields 		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
4119d5b9026aSNeilBrown 	} else {
41207c13f344SJ. Bruce Fields nevermind:
41217c13f344SJ. Bruce Fields 		deny->ld_owner.len = 0;
41227c13f344SJ. Bruce Fields 		deny->ld_owner.data = NULL;
4123d5b9026aSNeilBrown 		deny->ld_clientid.cl_boot = 0;
4124d5b9026aSNeilBrown 		deny->ld_clientid.cl_id = 0;
41251da177e4SLinus Torvalds 	}
41261da177e4SLinus Torvalds 	deny->ld_start = fl->fl_start;
412787df4de8SBenny Halevy 	deny->ld_length = NFS4_MAX_UINT64;
412887df4de8SBenny Halevy 	if (fl->fl_end != NFS4_MAX_UINT64)
41291da177e4SLinus Torvalds 		deny->ld_length = fl->fl_end - fl->fl_start + 1;
41301da177e4SLinus Torvalds 	deny->ld_type = NFS4_READ_LT;
41311da177e4SLinus Torvalds 	if (fl->fl_type != F_RDLCK)
41321da177e4SLinus Torvalds 		deny->ld_type = NFS4_WRITE_LT;
41331da177e4SLinus Torvalds }
41341da177e4SLinus Torvalds 
4135b93d87c1SJ. Bruce Fields static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner)
4136b93d87c1SJ. Bruce Fields {
4137b93d87c1SJ. Bruce Fields 	struct nfs4_ol_stateid *lst;
4138b93d87c1SJ. Bruce Fields 
4139b93d87c1SJ. Bruce Fields 	if (!same_owner_str(&lo->lo_owner, owner, clid))
4140b93d87c1SJ. Bruce Fields 		return false;
4141b93d87c1SJ. Bruce Fields 	lst = list_first_entry(&lo->lo_owner.so_stateids,
4142b93d87c1SJ. Bruce Fields 			       struct nfs4_ol_stateid, st_perstateowner);
4143b93d87c1SJ. Bruce Fields 	return lst->st_file->fi_inode == inode;
4144b93d87c1SJ. Bruce Fields }
4145b93d87c1SJ. Bruce Fields 
4146fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
4147fe0750e5SJ. Bruce Fields find_lockowner_str(struct inode *inode, clientid_t *clid,
414820e9e2bcSStanislav Kinsbursky 		   struct xdr_netobj *owner, struct nfsd_net *nn)
41491da177e4SLinus Torvalds {
4150009673b4SJ. Bruce Fields 	unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
4151b93d87c1SJ. Bruce Fields 	struct nfs4_lockowner *lo;
41521da177e4SLinus Torvalds 
415320e9e2bcSStanislav Kinsbursky 	list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
4154b93d87c1SJ. Bruce Fields 		if (same_lockowner_ino(lo, inode, clid, owner))
4155b93d87c1SJ. Bruce Fields 			return lo;
41561da177e4SLinus Torvalds 	}
41571da177e4SLinus Torvalds 	return NULL;
41581da177e4SLinus Torvalds }
41591da177e4SLinus Torvalds 
4160dcef0413SJ. Bruce Fields static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
4161ff194bd9SJ. Bruce Fields {
4162009673b4SJ. Bruce Fields 	struct inode *inode = open_stp->st_file->fi_inode;
4163009673b4SJ. Bruce Fields 	unsigned int inohash = lockowner_ino_hashval(inode,
4164009673b4SJ. Bruce Fields 			clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
41659b531137SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
4166009673b4SJ. Bruce Fields 
41679b531137SStanislav Kinsbursky 	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
416820e9e2bcSStanislav Kinsbursky 	list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]);
4169fe0750e5SJ. Bruce Fields 	list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
4170ff194bd9SJ. Bruce Fields }
4171ff194bd9SJ. Bruce Fields 
41721da177e4SLinus Torvalds /*
41731da177e4SLinus Torvalds  * Alloc a lock owner structure.
41741da177e4SLinus Torvalds  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
417525985edcSLucas De Marchi  * occurred.
41761da177e4SLinus Torvalds  *
417716bfdaafSJ. Bruce Fields  * strhashval = ownerstr_hashval
41781da177e4SLinus Torvalds  */
41791da177e4SLinus Torvalds 
4180fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
4181dcef0413SJ. Bruce Fields alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
4182fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
41831da177e4SLinus Torvalds 
4184fe0750e5SJ. Bruce Fields 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
4185fe0750e5SJ. Bruce Fields 	if (!lo)
41861da177e4SLinus Torvalds 		return NULL;
4187fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
4188fe0750e5SJ. Bruce Fields 	lo->lo_owner.so_is_open_owner = 0;
4189b59e3c0eSNeil Brown 	/* It is the openowner seqid that will be incremented in encode in the
4190b59e3c0eSNeil Brown 	 * case of new lockowners; so increment the lock seqid manually: */
4191fe0750e5SJ. Bruce Fields 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
4192fe0750e5SJ. Bruce Fields 	hash_lockowner(lo, strhashval, clp, open_stp);
4193fe0750e5SJ. Bruce Fields 	return lo;
41941da177e4SLinus Torvalds }
41951da177e4SLinus Torvalds 
4196dcef0413SJ. Bruce Fields static struct nfs4_ol_stateid *
4197dcef0413SJ. Bruce Fields alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
41981da177e4SLinus Torvalds {
4199dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
4200d3b313a4SJ. Bruce Fields 	struct nfs4_client *clp = lo->lo_owner.so_client;
42011da177e4SLinus Torvalds 
4202996e0938SJ. Bruce Fields 	stp = nfs4_alloc_stateid(clp);
42035ac049acSNeilBrown 	if (stp == NULL)
42046136d2b4SJ. Bruce Fields 		return NULL;
42053abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_LOCK_STID;
42068beefa24SNeilBrown 	list_add(&stp->st_perfile, &fp->fi_stateids);
4207fe0750e5SJ. Bruce Fields 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
4208fe0750e5SJ. Bruce Fields 	stp->st_stateowner = &lo->lo_owner;
420913cd2184SNeilBrown 	get_nfs4_file(fp);
42101da177e4SLinus Torvalds 	stp->st_file = fp;
42110997b173SJ. Bruce Fields 	stp->st_access_bmap = 0;
42121da177e4SLinus Torvalds 	stp->st_deny_bmap = open_stp->st_deny_bmap;
42134c4cd222SNeilBrown 	stp->st_openstp = open_stp;
42141da177e4SLinus Torvalds 	return stp;
42151da177e4SLinus Torvalds }
42161da177e4SLinus Torvalds 
4217fd39ca9aSNeilBrown static int
42181da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length)
42191da177e4SLinus Torvalds {
422087df4de8SBenny Halevy 	return ((length == 0)  || ((length != NFS4_MAX_UINT64) &&
42211da177e4SLinus Torvalds 	     LOFF_OVERFLOW(offset, length)));
42221da177e4SLinus Torvalds }
42231da177e4SLinus Torvalds 
4224dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
42250997b173SJ. Bruce Fields {
42260997b173SJ. Bruce Fields 	struct nfs4_file *fp = lock_stp->st_file;
42270997b173SJ. Bruce Fields 	int oflag = nfs4_access_to_omode(access);
42280997b173SJ. Bruce Fields 
422982c5ff1bSJeff Layton 	if (test_access(access, lock_stp))
42300997b173SJ. Bruce Fields 		return;
42310997b173SJ. Bruce Fields 	nfs4_file_get_access(fp, oflag);
423282c5ff1bSJeff Layton 	set_access(access, lock_stp);
42330997b173SJ. Bruce Fields }
42340997b173SJ. Bruce Fields 
42352355c596SJ. Bruce Fields static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new)
423664a284d0SJ. Bruce Fields {
423764a284d0SJ. Bruce Fields 	struct nfs4_file *fi = ost->st_file;
423864a284d0SJ. Bruce Fields 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
423964a284d0SJ. Bruce Fields 	struct nfs4_client *cl = oo->oo_owner.so_client;
424064a284d0SJ. Bruce Fields 	struct nfs4_lockowner *lo;
424164a284d0SJ. Bruce Fields 	unsigned int strhashval;
424220e9e2bcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id);
424364a284d0SJ. Bruce Fields 
424420e9e2bcSStanislav Kinsbursky 	lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid,
424520e9e2bcSStanislav Kinsbursky 				&lock->v.new.owner, nn);
424664a284d0SJ. Bruce Fields 	if (lo) {
424764a284d0SJ. Bruce Fields 		if (!cstate->minorversion)
424864a284d0SJ. Bruce Fields 			return nfserr_bad_seqid;
424964a284d0SJ. Bruce Fields 		/* XXX: a lockowner always has exactly one stateid: */
425064a284d0SJ. Bruce Fields 		*lst = list_first_entry(&lo->lo_owner.so_stateids,
425164a284d0SJ. Bruce Fields 				struct nfs4_ol_stateid, st_perstateowner);
425264a284d0SJ. Bruce Fields 		return nfs_ok;
425364a284d0SJ. Bruce Fields 	}
425416bfdaafSJ. Bruce Fields 	strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
425564a284d0SJ. Bruce Fields 			&lock->v.new.owner);
425664a284d0SJ. Bruce Fields 	lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
425764a284d0SJ. Bruce Fields 	if (lo == NULL)
425864a284d0SJ. Bruce Fields 		return nfserr_jukebox;
425964a284d0SJ. Bruce Fields 	*lst = alloc_init_lock_stateid(lo, fi, ost);
426064a284d0SJ. Bruce Fields 	if (*lst == NULL) {
426164a284d0SJ. Bruce Fields 		release_lockowner(lo);
426264a284d0SJ. Bruce Fields 		return nfserr_jukebox;
426364a284d0SJ. Bruce Fields 	}
426464a284d0SJ. Bruce Fields 	*new = true;
426564a284d0SJ. Bruce Fields 	return nfs_ok;
426664a284d0SJ. Bruce Fields }
426764a284d0SJ. Bruce Fields 
42681da177e4SLinus Torvalds /*
42691da177e4SLinus Torvalds  *  LOCK operation
42701da177e4SLinus Torvalds  */
4271b37ad28bSAl Viro __be32
4272ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4273a4f1706aSJ.Bruce Fields 	   struct nfsd4_lock *lock)
42741da177e4SLinus Torvalds {
4275fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *open_sop = NULL;
4276fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lock_sop = NULL;
4277dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *lock_stp;
42787d947842SJ. Bruce Fields 	struct file *filp = NULL;
427921179d81SJeff Layton 	struct file_lock *file_lock = NULL;
428021179d81SJeff Layton 	struct file_lock *conflock = NULL;
4281b37ad28bSAl Viro 	__be32 status = 0;
428264a284d0SJ. Bruce Fields 	bool new_state = false;
4283b34f27aaSJ. Bruce Fields 	int lkflg;
4284b8dd7b9aSAl Viro 	int err;
42853320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
42863320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
42871da177e4SLinus Torvalds 
42881da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
42891da177e4SLinus Torvalds 		(long long) lock->lk_offset,
42901da177e4SLinus Torvalds 		(long long) lock->lk_length);
42911da177e4SLinus Torvalds 
42921da177e4SLinus Torvalds 	if (check_lock_length(lock->lk_offset, lock->lk_length))
42931da177e4SLinus Torvalds 		 return nfserr_inval;
42941da177e4SLinus Torvalds 
4295ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh,
42968837abcaSMiklos Szeredi 				S_IFREG, NFSD_MAY_LOCK))) {
4297a6f6ef2fSAndy Adamson 		dprintk("NFSD: nfsd4_lock: permission denied!\n");
4298a6f6ef2fSAndy Adamson 		return status;
4299a6f6ef2fSAndy Adamson 	}
4300a6f6ef2fSAndy Adamson 
43011da177e4SLinus Torvalds 	nfs4_lock_state();
43021da177e4SLinus Torvalds 
43031da177e4SLinus Torvalds 	if (lock->lk_is_new) {
4304dcef0413SJ. Bruce Fields 		struct nfs4_ol_stateid *open_stp = NULL;
43051da177e4SLinus Torvalds 
4306684e5638SJ. Bruce Fields 		if (nfsd4_has_session(cstate))
4307684e5638SJ. Bruce Fields 			/* See rfc 5661 18.10.3: given clientid is ignored: */
4308684e5638SJ. Bruce Fields 			memcpy(&lock->v.new.clientid,
4309684e5638SJ. Bruce Fields 				&cstate->session->se_client->cl_clientid,
4310684e5638SJ. Bruce Fields 				sizeof(clientid_t));
4311684e5638SJ. Bruce Fields 
43121da177e4SLinus Torvalds 		status = nfserr_stale_clientid;
43132c142baaSStanislav Kinsbursky 		if (STALE_CLIENTID(&lock->lk_new_clientid, nn))
43141da177e4SLinus Torvalds 			goto out;
43151da177e4SLinus Torvalds 
43161da177e4SLinus Torvalds 		/* validate and update open stateid and open seqid */
4317c0a5d93eSJ. Bruce Fields 		status = nfs4_preprocess_confirmed_seqid_op(cstate,
43181da177e4SLinus Torvalds 				        lock->lk_new_open_seqid,
43191da177e4SLinus Torvalds 		                        &lock->lk_new_open_stateid,
43203320fef1SStanislav Kinsbursky 					&open_stp, nn);
432137515177SNeilBrown 		if (status)
43221da177e4SLinus Torvalds 			goto out;
4323fe0750e5SJ. Bruce Fields 		open_sop = openowner(open_stp->st_stateowner);
4324b34f27aaSJ. Bruce Fields 		status = nfserr_bad_stateid;
4325684e5638SJ. Bruce Fields 		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
4326b34f27aaSJ. Bruce Fields 						&lock->v.new.clientid))
4327b34f27aaSJ. Bruce Fields 			goto out;
432864a284d0SJ. Bruce Fields 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
432964a284d0SJ. Bruce Fields 							&lock_stp, &new_state);
4330e1aaa891SJ. Bruce Fields 	} else
4331dd453dfdSBenny Halevy 		status = nfs4_preprocess_seqid_op(cstate,
43321da177e4SLinus Torvalds 				       lock->lk_old_lock_seqid,
43331da177e4SLinus Torvalds 				       &lock->lk_old_lock_stateid,
43343320fef1SStanislav Kinsbursky 				       NFS4_LOCK_STID, &lock_stp, nn);
43351da177e4SLinus Torvalds 	if (status)
43361da177e4SLinus Torvalds 		goto out;
4337fe0750e5SJ. Bruce Fields 	lock_sop = lockowner(lock_stp->st_stateowner);
43381da177e4SLinus Torvalds 
4339b34f27aaSJ. Bruce Fields 	lkflg = setlkflg(lock->lk_type);
4340b34f27aaSJ. Bruce Fields 	status = nfs4_check_openmode(lock_stp, lkflg);
4341b34f27aaSJ. Bruce Fields 	if (status)
4342b34f27aaSJ. Bruce Fields 		goto out;
4343b34f27aaSJ. Bruce Fields 
43440dd395dcSNeilBrown 	status = nfserr_grace;
43453320fef1SStanislav Kinsbursky 	if (locks_in_grace(net) && !lock->lk_reclaim)
43460dd395dcSNeilBrown 		goto out;
43470dd395dcSNeilBrown 	status = nfserr_no_grace;
43483320fef1SStanislav Kinsbursky 	if (!locks_in_grace(net) && lock->lk_reclaim)
43490dd395dcSNeilBrown 		goto out;
43500dd395dcSNeilBrown 
435121179d81SJeff Layton 	file_lock = locks_alloc_lock();
435221179d81SJeff Layton 	if (!file_lock) {
435321179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
435421179d81SJeff Layton 		status = nfserr_jukebox;
435521179d81SJeff Layton 		goto out;
435621179d81SJeff Layton 	}
435721179d81SJeff Layton 
435821179d81SJeff Layton 	locks_init_lock(file_lock);
43591da177e4SLinus Torvalds 	switch (lock->lk_type) {
43601da177e4SLinus Torvalds 		case NFS4_READ_LT:
43611da177e4SLinus Torvalds 		case NFS4_READW_LT:
4362f9d7562fSJ. Bruce Fields 			filp = find_readable_file(lock_stp->st_file);
43630997b173SJ. Bruce Fields 			if (filp)
43640997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
436521179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
43661da177e4SLinus Torvalds 			break;
43671da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
43681da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
4369f9d7562fSJ. Bruce Fields 			filp = find_writeable_file(lock_stp->st_file);
43700997b173SJ. Bruce Fields 			if (filp)
43710997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
437221179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
43731da177e4SLinus Torvalds 			break;
43741da177e4SLinus Torvalds 		default:
43751da177e4SLinus Torvalds 			status = nfserr_inval;
43761da177e4SLinus Torvalds 		goto out;
43771da177e4SLinus Torvalds 	}
4378f9d7562fSJ. Bruce Fields 	if (!filp) {
4379f9d7562fSJ. Bruce Fields 		status = nfserr_openmode;
4380f9d7562fSJ. Bruce Fields 		goto out;
4381f9d7562fSJ. Bruce Fields 	}
438221179d81SJeff Layton 	file_lock->fl_owner = (fl_owner_t)lock_sop;
438321179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
438421179d81SJeff Layton 	file_lock->fl_file = filp;
438521179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
438621179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
438721179d81SJeff Layton 	file_lock->fl_start = lock->lk_offset;
438821179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
438921179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
43901da177e4SLinus Torvalds 
439121179d81SJeff Layton 	conflock = locks_alloc_lock();
439221179d81SJeff Layton 	if (!conflock) {
439321179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
439421179d81SJeff Layton 		status = nfserr_jukebox;
439521179d81SJeff Layton 		goto out;
439621179d81SJeff Layton 	}
43971da177e4SLinus Torvalds 
439821179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
4399b8dd7b9aSAl Viro 	switch (-err) {
44001da177e4SLinus Torvalds 	case 0: /* success! */
4401dcef0413SJ. Bruce Fields 		update_stateid(&lock_stp->st_stid.sc_stateid);
4402dcef0413SJ. Bruce Fields 		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
44031da177e4SLinus Torvalds 				sizeof(stateid_t));
4404b8dd7b9aSAl Viro 		status = 0;
4405eb76b3fdSAndy Adamson 		break;
4406eb76b3fdSAndy Adamson 	case (EAGAIN):		/* conflock holds conflicting lock */
4407eb76b3fdSAndy Adamson 		status = nfserr_denied;
4408eb76b3fdSAndy Adamson 		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
440921179d81SJeff Layton 		nfs4_set_lock_denied(conflock, &lock->lk_denied);
4410eb76b3fdSAndy Adamson 		break;
44111da177e4SLinus Torvalds 	case (EDEADLK):
44121da177e4SLinus Torvalds 		status = nfserr_deadlock;
4413eb76b3fdSAndy Adamson 		break;
44141da177e4SLinus Torvalds 	default:
4415fd85b817SMarc Eshel 		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
44163e772463SJ. Bruce Fields 		status = nfserrno(err);
4417eb76b3fdSAndy Adamson 		break;
44181da177e4SLinus Torvalds 	}
44191da177e4SLinus Torvalds out:
442064a284d0SJ. Bruce Fields 	if (status && new_state)
4421f044ff83SJ. Bruce Fields 		release_lockowner(lock_sop);
44229411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
44235ec094c1SJ. Bruce Fields 	if (!cstate->replay_owner)
44241da177e4SLinus Torvalds 		nfs4_unlock_state();
442521179d81SJeff Layton 	if (file_lock)
442621179d81SJeff Layton 		locks_free_lock(file_lock);
442721179d81SJeff Layton 	if (conflock)
442821179d81SJeff Layton 		locks_free_lock(conflock);
44291da177e4SLinus Torvalds 	return status;
44301da177e4SLinus Torvalds }
44311da177e4SLinus Torvalds 
44321da177e4SLinus Torvalds /*
443355ef1274SJ. Bruce Fields  * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
443455ef1274SJ. Bruce Fields  * so we do a temporary open here just to get an open file to pass to
443555ef1274SJ. Bruce Fields  * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
443655ef1274SJ. Bruce Fields  * inode operation.)
443755ef1274SJ. Bruce Fields  */
443804da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
443955ef1274SJ. Bruce Fields {
444055ef1274SJ. Bruce Fields 	struct file *file;
444104da6e9dSAl Viro 	__be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
444204da6e9dSAl Viro 	if (!err) {
444304da6e9dSAl Viro 		err = nfserrno(vfs_test_lock(file, lock));
444455ef1274SJ. Bruce Fields 		nfsd_close(file);
444504da6e9dSAl Viro 	}
444655ef1274SJ. Bruce Fields 	return err;
444755ef1274SJ. Bruce Fields }
444855ef1274SJ. Bruce Fields 
444955ef1274SJ. Bruce Fields /*
44501da177e4SLinus Torvalds  * LOCKT operation
44511da177e4SLinus Torvalds  */
4452b37ad28bSAl Viro __be32
4453ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4454ca364317SJ.Bruce Fields 	    struct nfsd4_lockt *lockt)
44551da177e4SLinus Torvalds {
44561da177e4SLinus Torvalds 	struct inode *inode;
445721179d81SJeff Layton 	struct file_lock *file_lock = NULL;
4458fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
4459b37ad28bSAl Viro 	__be32 status;
44607f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
44611da177e4SLinus Torvalds 
44625ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp)))
44631da177e4SLinus Torvalds 		return nfserr_grace;
44641da177e4SLinus Torvalds 
44651da177e4SLinus Torvalds 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
44661da177e4SLinus Torvalds 		 return nfserr_inval;
44671da177e4SLinus Torvalds 
44681da177e4SLinus Torvalds 	nfs4_lock_state();
44691da177e4SLinus Torvalds 
44709b2ef62bSJ. Bruce Fields 	if (!nfsd4_has_session(cstate)) {
44719b2ef62bSJ. Bruce Fields 		status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL);
44729b2ef62bSJ. Bruce Fields 		if (status)
44731da177e4SLinus Torvalds 			goto out;
44749b2ef62bSJ. Bruce Fields 	}
44751da177e4SLinus Torvalds 
447675c096f7SJ. Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
44771da177e4SLinus Torvalds 		goto out;
44781da177e4SLinus Torvalds 
4479ca364317SJ.Bruce Fields 	inode = cstate->current_fh.fh_dentry->d_inode;
448021179d81SJeff Layton 	file_lock = locks_alloc_lock();
448121179d81SJeff Layton 	if (!file_lock) {
448221179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
448321179d81SJeff Layton 		status = nfserr_jukebox;
448421179d81SJeff Layton 		goto out;
448521179d81SJeff Layton 	}
448621179d81SJeff Layton 	locks_init_lock(file_lock);
44871da177e4SLinus Torvalds 	switch (lockt->lt_type) {
44881da177e4SLinus Torvalds 		case NFS4_READ_LT:
44891da177e4SLinus Torvalds 		case NFS4_READW_LT:
449021179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
44911da177e4SLinus Torvalds 		break;
44921da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
44931da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
449421179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
44951da177e4SLinus Torvalds 		break;
44961da177e4SLinus Torvalds 		default:
44972fdada03SJ. Bruce Fields 			dprintk("NFSD: nfs4_lockt: bad lock type!\n");
44981da177e4SLinus Torvalds 			status = nfserr_inval;
44991da177e4SLinus Torvalds 		goto out;
45001da177e4SLinus Torvalds 	}
45011da177e4SLinus Torvalds 
450220e9e2bcSStanislav Kinsbursky 	lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn);
4503fe0750e5SJ. Bruce Fields 	if (lo)
450421179d81SJeff Layton 		file_lock->fl_owner = (fl_owner_t)lo;
450521179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
450621179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
45071da177e4SLinus Torvalds 
450821179d81SJeff Layton 	file_lock->fl_start = lockt->lt_offset;
450921179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
45101da177e4SLinus Torvalds 
451121179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
45121da177e4SLinus Torvalds 
451321179d81SJeff Layton 	status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
451404da6e9dSAl Viro 	if (status)
4515fd85b817SMarc Eshel 		goto out;
451604da6e9dSAl Viro 
451721179d81SJeff Layton 	if (file_lock->fl_type != F_UNLCK) {
45181da177e4SLinus Torvalds 		status = nfserr_denied;
451921179d81SJeff Layton 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
45201da177e4SLinus Torvalds 	}
45211da177e4SLinus Torvalds out:
45221da177e4SLinus Torvalds 	nfs4_unlock_state();
452321179d81SJeff Layton 	if (file_lock)
452421179d81SJeff Layton 		locks_free_lock(file_lock);
45251da177e4SLinus Torvalds 	return status;
45261da177e4SLinus Torvalds }
45271da177e4SLinus Torvalds 
4528b37ad28bSAl Viro __be32
4529ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4530a4f1706aSJ.Bruce Fields 	    struct nfsd4_locku *locku)
45311da177e4SLinus Torvalds {
4532dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
45331da177e4SLinus Torvalds 	struct file *filp = NULL;
453421179d81SJeff Layton 	struct file_lock *file_lock = NULL;
4535b37ad28bSAl Viro 	__be32 status;
4536b8dd7b9aSAl Viro 	int err;
45373320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
45381da177e4SLinus Torvalds 
45391da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
45401da177e4SLinus Torvalds 		(long long) locku->lu_offset,
45411da177e4SLinus Torvalds 		(long long) locku->lu_length);
45421da177e4SLinus Torvalds 
45431da177e4SLinus Torvalds 	if (check_lock_length(locku->lu_offset, locku->lu_length))
45441da177e4SLinus Torvalds 		 return nfserr_inval;
45451da177e4SLinus Torvalds 
45461da177e4SLinus Torvalds 	nfs4_lock_state();
45471da177e4SLinus Torvalds 
45489072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
45493320fef1SStanislav Kinsbursky 					&locku->lu_stateid, NFS4_LOCK_STID,
45503320fef1SStanislav Kinsbursky 					&stp, nn);
45519072d5c6SJ. Bruce Fields 	if (status)
45521da177e4SLinus Torvalds 		goto out;
4553f9d7562fSJ. Bruce Fields 	filp = find_any_file(stp->st_file);
4554f9d7562fSJ. Bruce Fields 	if (!filp) {
4555f9d7562fSJ. Bruce Fields 		status = nfserr_lock_range;
4556f9d7562fSJ. Bruce Fields 		goto out;
4557f9d7562fSJ. Bruce Fields 	}
455821179d81SJeff Layton 	file_lock = locks_alloc_lock();
455921179d81SJeff Layton 	if (!file_lock) {
456021179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
456121179d81SJeff Layton 		status = nfserr_jukebox;
456221179d81SJeff Layton 		goto out;
456321179d81SJeff Layton 	}
456421179d81SJeff Layton 	locks_init_lock(file_lock);
456521179d81SJeff Layton 	file_lock->fl_type = F_UNLCK;
45660a262ffbSJ. Bruce Fields 	file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
456721179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
456821179d81SJeff Layton 	file_lock->fl_file = filp;
456921179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
457021179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
457121179d81SJeff Layton 	file_lock->fl_start = locku->lu_offset;
45721da177e4SLinus Torvalds 
457321179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(locku->lu_offset,
457421179d81SJeff Layton 						locku->lu_length);
457521179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
45761da177e4SLinus Torvalds 
457721179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
4578b8dd7b9aSAl Viro 	if (err) {
4579fd85b817SMarc Eshel 		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
45801da177e4SLinus Torvalds 		goto out_nfserr;
45811da177e4SLinus Torvalds 	}
4582dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4583dcef0413SJ. Bruce Fields 	memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
45841da177e4SLinus Torvalds 
45851da177e4SLinus Torvalds out:
45869411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
458771c3bcd7SJ. Bruce Fields 	if (!cstate->replay_owner)
45881da177e4SLinus Torvalds 		nfs4_unlock_state();
458921179d81SJeff Layton 	if (file_lock)
459021179d81SJeff Layton 		locks_free_lock(file_lock);
45911da177e4SLinus Torvalds 	return status;
45921da177e4SLinus Torvalds 
45931da177e4SLinus Torvalds out_nfserr:
4594b8dd7b9aSAl Viro 	status = nfserrno(err);
45951da177e4SLinus Torvalds 	goto out;
45961da177e4SLinus Torvalds }
45971da177e4SLinus Torvalds 
45981da177e4SLinus Torvalds /*
45991da177e4SLinus Torvalds  * returns
46001da177e4SLinus Torvalds  * 	1: locks held by lockowner
46011da177e4SLinus Torvalds  * 	0: no locks held by lockowner
46021da177e4SLinus Torvalds  */
46031da177e4SLinus Torvalds static int
4604fe0750e5SJ. Bruce Fields check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
46051da177e4SLinus Torvalds {
46061da177e4SLinus Torvalds 	struct file_lock **flpp;
4607f9d7562fSJ. Bruce Fields 	struct inode *inode = filp->fi_inode;
46081da177e4SLinus Torvalds 	int status = 0;
46091da177e4SLinus Torvalds 
46101c8c601aSJeff Layton 	spin_lock(&inode->i_lock);
46111da177e4SLinus Torvalds 	for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
4612796dadfdSJ. Bruce Fields 		if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
46131da177e4SLinus Torvalds 			status = 1;
46141da177e4SLinus Torvalds 			goto out;
46151da177e4SLinus Torvalds 		}
4616796dadfdSJ. Bruce Fields 	}
46171da177e4SLinus Torvalds out:
46181c8c601aSJeff Layton 	spin_unlock(&inode->i_lock);
46191da177e4SLinus Torvalds 	return status;
46201da177e4SLinus Torvalds }
46211da177e4SLinus Torvalds 
4622b37ad28bSAl Viro __be32
4623b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp,
4624b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
4625b591480bSJ.Bruce Fields 			struct nfsd4_release_lockowner *rlockowner)
46261da177e4SLinus Torvalds {
46271da177e4SLinus Torvalds 	clientid_t *clid = &rlockowner->rl_clientid;
46283e9e3dbeSNeilBrown 	struct nfs4_stateowner *sop;
4629fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
4630dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
46311da177e4SLinus Torvalds 	struct xdr_netobj *owner = &rlockowner->rl_owner;
46323e9e3dbeSNeilBrown 	struct list_head matches;
463316bfdaafSJ. Bruce Fields 	unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
4634b37ad28bSAl Viro 	__be32 status;
46357f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
46361da177e4SLinus Torvalds 
46371da177e4SLinus Torvalds 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
46381da177e4SLinus Torvalds 		clid->cl_boot, clid->cl_id);
46391da177e4SLinus Torvalds 
46401da177e4SLinus Torvalds 	nfs4_lock_state();
46411da177e4SLinus Torvalds 
46429b2ef62bSJ. Bruce Fields 	status = lookup_clientid(clid, cstate->minorversion, nn, NULL);
46439b2ef62bSJ. Bruce Fields 	if (status)
46449b2ef62bSJ. Bruce Fields 		goto out;
46459b2ef62bSJ. Bruce Fields 
46461da177e4SLinus Torvalds 	status = nfserr_locks_held;
46473e9e3dbeSNeilBrown 	INIT_LIST_HEAD(&matches);
464806f1f864SJ. Bruce Fields 
46499b531137SStanislav Kinsbursky 	list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) {
465016bfdaafSJ. Bruce Fields 		if (sop->so_is_open_owner)
465116bfdaafSJ. Bruce Fields 			continue;
4652599e0a22SJ. Bruce Fields 		if (!same_owner_str(sop, owner, clid))
46533e9e3dbeSNeilBrown 			continue;
46543e9e3dbeSNeilBrown 		list_for_each_entry(stp, &sop->so_stateids,
4655ea1da636SNeilBrown 				st_perstateowner) {
4656fe0750e5SJ. Bruce Fields 			lo = lockowner(sop);
4657fe0750e5SJ. Bruce Fields 			if (check_for_locks(stp->st_file, lo))
46581da177e4SLinus Torvalds 				goto out;
4659fe0750e5SJ. Bruce Fields 			list_add(&lo->lo_list, &matches);
46601da177e4SLinus Torvalds 		}
46613e9e3dbeSNeilBrown 	}
46623e9e3dbeSNeilBrown 	/* Clients probably won't expect us to return with some (but not all)
46633e9e3dbeSNeilBrown 	 * of the lockowner state released; so don't release any until all
46643e9e3dbeSNeilBrown 	 * have been checked. */
46651da177e4SLinus Torvalds 	status = nfs_ok;
46660fa822e4SNeilBrown 	while (!list_empty(&matches)) {
4667fe0750e5SJ. Bruce Fields 		lo = list_entry(matches.next, struct nfs4_lockowner,
4668fe0750e5SJ. Bruce Fields 								lo_list);
46690fa822e4SNeilBrown 		/* unhash_stateowner deletes so_perclient only
46700fa822e4SNeilBrown 		 * for openowners. */
4671fe0750e5SJ. Bruce Fields 		list_del(&lo->lo_list);
4672fe0750e5SJ. Bruce Fields 		release_lockowner(lo);
46731da177e4SLinus Torvalds 	}
46741da177e4SLinus Torvalds out:
46751da177e4SLinus Torvalds 	nfs4_unlock_state();
46761da177e4SLinus Torvalds 	return status;
46771da177e4SLinus Torvalds }
46781da177e4SLinus Torvalds 
46791da177e4SLinus Torvalds static inline struct nfs4_client_reclaim *
4680a55370a3SNeilBrown alloc_reclaim(void)
46811da177e4SLinus Torvalds {
4682a55370a3SNeilBrown 	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
46831da177e4SLinus Torvalds }
46841da177e4SLinus Torvalds 
46850ce0c2b5SJeff Layton bool
468652e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
4687c7b9a459SNeilBrown {
46880ce0c2b5SJeff Layton 	struct nfs4_client_reclaim *crp;
4689c7b9a459SNeilBrown 
469052e19c09SStanislav Kinsbursky 	crp = nfsd4_find_reclaim_client(name, nn);
46910ce0c2b5SJeff Layton 	return (crp && crp->cr_clp);
4692c7b9a459SNeilBrown }
4693c7b9a459SNeilBrown 
46941da177e4SLinus Torvalds /*
46951da177e4SLinus Torvalds  * failure => all reset bets are off, nfserr_no_grace...
46961da177e4SLinus Torvalds  */
4697772a9bbbSJeff Layton struct nfs4_client_reclaim *
469852e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
46991da177e4SLinus Torvalds {
47001da177e4SLinus Torvalds 	unsigned int strhashval;
4701772a9bbbSJeff Layton 	struct nfs4_client_reclaim *crp;
47021da177e4SLinus Torvalds 
4703a55370a3SNeilBrown 	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
4704a55370a3SNeilBrown 	crp = alloc_reclaim();
4705772a9bbbSJeff Layton 	if (crp) {
4706a55370a3SNeilBrown 		strhashval = clientstr_hashval(name);
47071da177e4SLinus Torvalds 		INIT_LIST_HEAD(&crp->cr_strhash);
470852e19c09SStanislav Kinsbursky 		list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
4709a55370a3SNeilBrown 		memcpy(crp->cr_recdir, name, HEXDIR_LEN);
47100ce0c2b5SJeff Layton 		crp->cr_clp = NULL;
471152e19c09SStanislav Kinsbursky 		nn->reclaim_str_hashtbl_size++;
4712772a9bbbSJeff Layton 	}
4713772a9bbbSJeff Layton 	return crp;
47141da177e4SLinus Torvalds }
47151da177e4SLinus Torvalds 
47162a4317c5SJeff Layton void
471752e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
4718ce30e539SJeff Layton {
4719ce30e539SJeff Layton 	list_del(&crp->cr_strhash);
4720ce30e539SJeff Layton 	kfree(crp);
472152e19c09SStanislav Kinsbursky 	nn->reclaim_str_hashtbl_size--;
4722ce30e539SJeff Layton }
4723ce30e539SJeff Layton 
4724ce30e539SJeff Layton void
472552e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn)
47261da177e4SLinus Torvalds {
47271da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
47281da177e4SLinus Torvalds 	int i;
47291da177e4SLinus Torvalds 
47301da177e4SLinus Torvalds 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
473152e19c09SStanislav Kinsbursky 		while (!list_empty(&nn->reclaim_str_hashtbl[i])) {
473252e19c09SStanislav Kinsbursky 			crp = list_entry(nn->reclaim_str_hashtbl[i].next,
47331da177e4SLinus Torvalds 			                struct nfs4_client_reclaim, cr_strhash);
473452e19c09SStanislav Kinsbursky 			nfs4_remove_reclaim_record(crp, nn);
47351da177e4SLinus Torvalds 		}
47361da177e4SLinus Torvalds 	}
4737063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(nn->reclaim_str_hashtbl_size);
47381da177e4SLinus Torvalds }
47391da177e4SLinus Torvalds 
47401da177e4SLinus Torvalds /*
47411da177e4SLinus Torvalds  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
47422a4317c5SJeff Layton struct nfs4_client_reclaim *
474352e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
47441da177e4SLinus Torvalds {
47451da177e4SLinus Torvalds 	unsigned int strhashval;
47461da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
47471da177e4SLinus Torvalds 
4748278c931cSJeff Layton 	dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
47491da177e4SLinus Torvalds 
4750278c931cSJeff Layton 	strhashval = clientstr_hashval(recdir);
475152e19c09SStanislav Kinsbursky 	list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
4752278c931cSJeff Layton 		if (same_name(crp->cr_recdir, recdir)) {
47531da177e4SLinus Torvalds 			return crp;
47541da177e4SLinus Torvalds 		}
47551da177e4SLinus Torvalds 	}
47561da177e4SLinus Torvalds 	return NULL;
47571da177e4SLinus Torvalds }
47581da177e4SLinus Torvalds 
47591da177e4SLinus Torvalds /*
47601da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list.
47611da177e4SLinus Torvalds */
4762b37ad28bSAl Viro __be32
47633320fef1SStanislav Kinsbursky nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn)
47641da177e4SLinus Torvalds {
4765a52d726bSJeff Layton 	struct nfs4_client *clp;
4766a52d726bSJeff Layton 
4767a52d726bSJeff Layton 	/* find clientid in conf_id_hashtbl */
47688daae4dcSStanislav Kinsbursky 	clp = find_confirmed_client(clid, sessions, nn);
4769a52d726bSJeff Layton 	if (clp == NULL)
4770a52d726bSJeff Layton 		return nfserr_reclaim_bad;
4771a52d726bSJeff Layton 
4772a52d726bSJeff Layton 	return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
47731da177e4SLinus Torvalds }
47741da177e4SLinus Torvalds 
477565178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION
477665178db4SBryan Schumaker 
477744e34da6SBryan Schumaker u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
477844e34da6SBryan Schumaker {
4779221a6876SJ. Bruce Fields 	if (mark_client_expired(clp))
4780221a6876SJ. Bruce Fields 		return 0;
478144e34da6SBryan Schumaker 	expire_client(clp);
478244e34da6SBryan Schumaker 	return 1;
478344e34da6SBryan Schumaker }
478444e34da6SBryan Schumaker 
4785184c1847SBryan Schumaker u64 nfsd_print_client(struct nfs4_client *clp, u64 num)
4786184c1847SBryan Schumaker {
4787184c1847SBryan Schumaker 	char buf[INET6_ADDRSTRLEN];
47880a5c33e2SBryan Schumaker 	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
4789184c1847SBryan Schumaker 	printk(KERN_INFO "NFS Client: %s\n", buf);
4790184c1847SBryan Schumaker 	return 1;
4791184c1847SBryan Schumaker }
4792184c1847SBryan Schumaker 
4793184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
4794184c1847SBryan Schumaker 			     const char *type)
4795184c1847SBryan Schumaker {
4796184c1847SBryan Schumaker 	char buf[INET6_ADDRSTRLEN];
47970a5c33e2SBryan Schumaker 	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
4798184c1847SBryan Schumaker 	printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
4799184c1847SBryan Schumaker }
4800184c1847SBryan Schumaker 
4801fc29171fSBryan Schumaker static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *))
4802fc29171fSBryan Schumaker {
4803fc29171fSBryan Schumaker 	struct nfs4_openowner *oop;
4804fc29171fSBryan Schumaker 	struct nfs4_lockowner *lop, *lo_next;
4805fc29171fSBryan Schumaker 	struct nfs4_ol_stateid *stp, *st_next;
4806fc29171fSBryan Schumaker 	u64 count = 0;
4807fc29171fSBryan Schumaker 
4808fc29171fSBryan Schumaker 	list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
4809fc29171fSBryan Schumaker 		list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) {
4810fc29171fSBryan Schumaker 			list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) {
4811fc29171fSBryan Schumaker 				if (func)
4812fc29171fSBryan Schumaker 					func(lop);
4813fc29171fSBryan Schumaker 				if (++count == max)
4814fc29171fSBryan Schumaker 					return count;
4815fc29171fSBryan Schumaker 			}
4816fc29171fSBryan Schumaker 		}
4817fc29171fSBryan Schumaker 	}
4818fc29171fSBryan Schumaker 
4819fc29171fSBryan Schumaker 	return count;
4820fc29171fSBryan Schumaker }
4821fc29171fSBryan Schumaker 
4822fc29171fSBryan Schumaker u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max)
4823fc29171fSBryan Schumaker {
4824fc29171fSBryan Schumaker 	return nfsd_foreach_client_lock(clp, max, release_lockowner);
4825fc29171fSBryan Schumaker }
4826fc29171fSBryan Schumaker 
4827184c1847SBryan Schumaker u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max)
4828184c1847SBryan Schumaker {
4829184c1847SBryan Schumaker 	u64 count = nfsd_foreach_client_lock(clp, max, NULL);
4830184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "locked files");
4831184c1847SBryan Schumaker 	return count;
4832184c1847SBryan Schumaker }
4833184c1847SBryan Schumaker 
48344dbdbda8SBryan Schumaker static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *))
48354dbdbda8SBryan Schumaker {
48364dbdbda8SBryan Schumaker 	struct nfs4_openowner *oop, *next;
48374dbdbda8SBryan Schumaker 	u64 count = 0;
48384dbdbda8SBryan Schumaker 
48394dbdbda8SBryan Schumaker 	list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
48404dbdbda8SBryan Schumaker 		if (func)
48414dbdbda8SBryan Schumaker 			func(oop);
48424dbdbda8SBryan Schumaker 		if (++count == max)
48434dbdbda8SBryan Schumaker 			break;
48444dbdbda8SBryan Schumaker 	}
48454dbdbda8SBryan Schumaker 
48464dbdbda8SBryan Schumaker 	return count;
48474dbdbda8SBryan Schumaker }
48484dbdbda8SBryan Schumaker 
48494dbdbda8SBryan Schumaker u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max)
48504dbdbda8SBryan Schumaker {
48514dbdbda8SBryan Schumaker 	return nfsd_foreach_client_open(clp, max, release_openowner);
48524dbdbda8SBryan Schumaker }
48534dbdbda8SBryan Schumaker 
4854184c1847SBryan Schumaker u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max)
4855184c1847SBryan Schumaker {
4856184c1847SBryan Schumaker 	u64 count = nfsd_foreach_client_open(clp, max, NULL);
4857184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "open files");
4858184c1847SBryan Schumaker 	return count;
4859184c1847SBryan Schumaker }
4860184c1847SBryan Schumaker 
4861269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
4862269de30fSBryan Schumaker 				     struct list_head *victims)
4863269de30fSBryan Schumaker {
4864269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
4865269de30fSBryan Schumaker 	u64 count = 0;
4866269de30fSBryan Schumaker 
4867269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
4868269de30fSBryan Schumaker 		if (victims)
4869269de30fSBryan Schumaker 			list_move(&dp->dl_recall_lru, victims);
4870269de30fSBryan Schumaker 		if (++count == max)
4871269de30fSBryan Schumaker 			break;
4872269de30fSBryan Schumaker 	}
4873269de30fSBryan Schumaker 	return count;
4874269de30fSBryan Schumaker }
4875269de30fSBryan Schumaker 
4876269de30fSBryan Schumaker u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
4877269de30fSBryan Schumaker {
4878269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
4879269de30fSBryan Schumaker 	LIST_HEAD(victims);
4880269de30fSBryan Schumaker 	u64 count;
4881269de30fSBryan Schumaker 
4882269de30fSBryan Schumaker 	spin_lock(&recall_lock);
4883269de30fSBryan Schumaker 	count = nfsd_find_all_delegations(clp, max, &victims);
4884269de30fSBryan Schumaker 	spin_unlock(&recall_lock);
4885269de30fSBryan Schumaker 
4886269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
48873bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
4888269de30fSBryan Schumaker 
4889269de30fSBryan Schumaker 	return count;
4890269de30fSBryan Schumaker }
4891269de30fSBryan Schumaker 
4892269de30fSBryan Schumaker u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max)
4893269de30fSBryan Schumaker {
4894269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
4895269de30fSBryan Schumaker 	LIST_HEAD(victims);
4896269de30fSBryan Schumaker 	u64 count;
4897269de30fSBryan Schumaker 
4898269de30fSBryan Schumaker 	spin_lock(&recall_lock);
4899269de30fSBryan Schumaker 	count = nfsd_find_all_delegations(clp, max, &victims);
4900269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
4901269de30fSBryan Schumaker 		nfsd_break_one_deleg(dp);
4902269de30fSBryan Schumaker 	spin_unlock(&recall_lock);
4903269de30fSBryan Schumaker 
4904269de30fSBryan Schumaker 	return count;
4905269de30fSBryan Schumaker }
4906269de30fSBryan Schumaker 
4907184c1847SBryan Schumaker u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max)
4908184c1847SBryan Schumaker {
4909184c1847SBryan Schumaker 	u64 count = 0;
4910184c1847SBryan Schumaker 
4911184c1847SBryan Schumaker 	spin_lock(&recall_lock);
4912184c1847SBryan Schumaker 	count = nfsd_find_all_delegations(clp, max, NULL);
4913184c1847SBryan Schumaker 	spin_unlock(&recall_lock);
4914184c1847SBryan Schumaker 
4915184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "delegations");
4916184c1847SBryan Schumaker 	return count;
4917184c1847SBryan Schumaker }
4918184c1847SBryan Schumaker 
491944e34da6SBryan Schumaker u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64))
492065178db4SBryan Schumaker {
492165178db4SBryan Schumaker 	struct nfs4_client *clp, *next;
492244e34da6SBryan Schumaker 	u64 count = 0;
49233320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
492465178db4SBryan Schumaker 
492544e34da6SBryan Schumaker 	if (!nfsd_netns_ready(nn))
492644e34da6SBryan Schumaker 		return 0;
492744e34da6SBryan Schumaker 
49285ed58bb2SStanislav Kinsbursky 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
492944e34da6SBryan Schumaker 		count += func(clp, max - count);
493044e34da6SBryan Schumaker 		if ((max != 0) && (count >= max))
493165178db4SBryan Schumaker 			break;
493265178db4SBryan Schumaker 	}
493365178db4SBryan Schumaker 
493444e34da6SBryan Schumaker 	return count;
493544e34da6SBryan Schumaker }
493644e34da6SBryan Schumaker 
49376c1e82a4SBryan Schumaker struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
49386c1e82a4SBryan Schumaker {
49396c1e82a4SBryan Schumaker 	struct nfs4_client *clp;
49406c1e82a4SBryan Schumaker 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
49416c1e82a4SBryan Schumaker 
49426c1e82a4SBryan Schumaker 	if (!nfsd_netns_ready(nn))
49436c1e82a4SBryan Schumaker 		return NULL;
49446c1e82a4SBryan Schumaker 
49456c1e82a4SBryan Schumaker 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
49466c1e82a4SBryan Schumaker 		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
49476c1e82a4SBryan Schumaker 			return clp;
49486c1e82a4SBryan Schumaker 	}
49496c1e82a4SBryan Schumaker 	return NULL;
49506c1e82a4SBryan Schumaker }
49516c1e82a4SBryan Schumaker 
495265178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */
495365178db4SBryan Schumaker 
4954ac4d8ff2SNeilBrown /* initialization to perform at module load time: */
49551da177e4SLinus Torvalds 
495672083396SBryan Schumaker void
4957ac4d8ff2SNeilBrown nfs4_state_init(void)
49581da177e4SLinus Torvalds {
4959ac4d8ff2SNeilBrown }
4960ac4d8ff2SNeilBrown 
4961c2f1a551SMeelap Shah /*
4962c2f1a551SMeelap Shah  * Since the lifetime of a delegation isn't limited to that of an open, a
4963c2f1a551SMeelap Shah  * client may quite reasonably hang on to a delegation as long as it has
4964c2f1a551SMeelap Shah  * the inode cached.  This becomes an obvious problem the first time a
4965c2f1a551SMeelap Shah  * client's inode cache approaches the size of the server's total memory.
4966c2f1a551SMeelap Shah  *
4967c2f1a551SMeelap Shah  * For now we avoid this problem by imposing a hard limit on the number
4968c2f1a551SMeelap Shah  * of delegations, which varies according to the server's memory size.
4969c2f1a551SMeelap Shah  */
4970c2f1a551SMeelap Shah static void
4971c2f1a551SMeelap Shah set_max_delegations(void)
4972c2f1a551SMeelap Shah {
4973c2f1a551SMeelap Shah 	/*
4974c2f1a551SMeelap Shah 	 * Allow at most 4 delegations per megabyte of RAM.  Quick
4975c2f1a551SMeelap Shah 	 * estimates suggest that in the worst case (where every delegation
4976c2f1a551SMeelap Shah 	 * is for a different inode), a delegation could take about 1.5K,
4977c2f1a551SMeelap Shah 	 * giving a worst case usage of about 6% of memory.
4978c2f1a551SMeelap Shah 	 */
4979c2f1a551SMeelap Shah 	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
4980c2f1a551SMeelap Shah }
4981c2f1a551SMeelap Shah 
4982d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net)
49838daae4dcSStanislav Kinsbursky {
49848daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
49858daae4dcSStanislav Kinsbursky 	int i;
49868daae4dcSStanislav Kinsbursky 
49878daae4dcSStanislav Kinsbursky 	nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
49888daae4dcSStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
49898daae4dcSStanislav Kinsbursky 	if (!nn->conf_id_hashtbl)
4990382a62e7SStanislav Kinsbursky 		goto err;
49910a7ec377SStanislav Kinsbursky 	nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) *
49920a7ec377SStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
49930a7ec377SStanislav Kinsbursky 	if (!nn->unconf_id_hashtbl)
49940a7ec377SStanislav Kinsbursky 		goto err_unconf_id;
49959b531137SStanislav Kinsbursky 	nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
49969b531137SStanislav Kinsbursky 			OWNER_HASH_SIZE, GFP_KERNEL);
49979b531137SStanislav Kinsbursky 	if (!nn->ownerstr_hashtbl)
49989b531137SStanislav Kinsbursky 		goto err_ownerstr;
499920e9e2bcSStanislav Kinsbursky 	nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) *
500020e9e2bcSStanislav Kinsbursky 			LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL);
500120e9e2bcSStanislav Kinsbursky 	if (!nn->lockowner_ino_hashtbl)
500220e9e2bcSStanislav Kinsbursky 		goto err_lockowner_ino;
50031872de0eSStanislav Kinsbursky 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
50041872de0eSStanislav Kinsbursky 			SESSION_HASH_SIZE, GFP_KERNEL);
50051872de0eSStanislav Kinsbursky 	if (!nn->sessionid_hashtbl)
50061872de0eSStanislav Kinsbursky 		goto err_sessionid;
50078daae4dcSStanislav Kinsbursky 
5008382a62e7SStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
50098daae4dcSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
50100a7ec377SStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
5011382a62e7SStanislav Kinsbursky 	}
50129b531137SStanislav Kinsbursky 	for (i = 0; i < OWNER_HASH_SIZE; i++)
50139b531137SStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]);
501420e9e2bcSStanislav Kinsbursky 	for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
501520e9e2bcSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]);
50161872de0eSStanislav Kinsbursky 	for (i = 0; i < SESSION_HASH_SIZE; i++)
50171872de0eSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
5018382a62e7SStanislav Kinsbursky 	nn->conf_name_tree = RB_ROOT;
5019a99454aaSStanislav Kinsbursky 	nn->unconf_name_tree = RB_ROOT;
50205ed58bb2SStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->client_lru);
502173758fedSStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->close_lru);
5022e8c69d17SJ. Bruce Fields 	INIT_LIST_HEAD(&nn->del_recall_lru);
5023c9a49628SStanislav Kinsbursky 	spin_lock_init(&nn->client_lock);
50248daae4dcSStanislav Kinsbursky 
502509121281SStanislav Kinsbursky 	INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
5026d85ed443SStanislav Kinsbursky 	get_net(net);
502709121281SStanislav Kinsbursky 
50288daae4dcSStanislav Kinsbursky 	return 0;
5029382a62e7SStanislav Kinsbursky 
50301872de0eSStanislav Kinsbursky err_sessionid:
50311872de0eSStanislav Kinsbursky 	kfree(nn->lockowner_ino_hashtbl);
503220e9e2bcSStanislav Kinsbursky err_lockowner_ino:
503320e9e2bcSStanislav Kinsbursky 	kfree(nn->ownerstr_hashtbl);
50349b531137SStanislav Kinsbursky err_ownerstr:
50359b531137SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
50360a7ec377SStanislav Kinsbursky err_unconf_id:
50370a7ec377SStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
5038382a62e7SStanislav Kinsbursky err:
5039382a62e7SStanislav Kinsbursky 	return -ENOMEM;
50408daae4dcSStanislav Kinsbursky }
50418daae4dcSStanislav Kinsbursky 
50428daae4dcSStanislav Kinsbursky static void
50434dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net)
50448daae4dcSStanislav Kinsbursky {
50458daae4dcSStanislav Kinsbursky 	int i;
50468daae4dcSStanislav Kinsbursky 	struct nfs4_client *clp = NULL;
50478daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
5048a99454aaSStanislav Kinsbursky 	struct rb_node *node, *tmp;
50498daae4dcSStanislav Kinsbursky 
50508daae4dcSStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
50518daae4dcSStanislav Kinsbursky 		while (!list_empty(&nn->conf_id_hashtbl[i])) {
50528daae4dcSStanislav Kinsbursky 			clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
50538daae4dcSStanislav Kinsbursky 			destroy_client(clp);
50548daae4dcSStanislav Kinsbursky 		}
50558daae4dcSStanislav Kinsbursky 	}
5056a99454aaSStanislav Kinsbursky 
5057a99454aaSStanislav Kinsbursky 	node = rb_first(&nn->unconf_name_tree);
5058a99454aaSStanislav Kinsbursky 	while (node != NULL) {
5059a99454aaSStanislav Kinsbursky 		tmp = node;
5060a99454aaSStanislav Kinsbursky 		node = rb_next(tmp);
5061a99454aaSStanislav Kinsbursky 		clp = rb_entry(tmp, struct nfs4_client, cl_namenode);
5062a99454aaSStanislav Kinsbursky 		rb_erase(tmp, &nn->unconf_name_tree);
5063a99454aaSStanislav Kinsbursky 		destroy_client(clp);
5064a99454aaSStanislav Kinsbursky 	}
5065a99454aaSStanislav Kinsbursky 
50661872de0eSStanislav Kinsbursky 	kfree(nn->sessionid_hashtbl);
506720e9e2bcSStanislav Kinsbursky 	kfree(nn->lockowner_ino_hashtbl);
50689b531137SStanislav Kinsbursky 	kfree(nn->ownerstr_hashtbl);
50690a7ec377SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
50708daae4dcSStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
50714dce0ac9SStanislav Kinsbursky 	put_net(net);
50728daae4dcSStanislav Kinsbursky }
50738daae4dcSStanislav Kinsbursky 
5074f252bc68SStanislav Kinsbursky int
5075d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net)
5076ac4d8ff2SNeilBrown {
50775e1533c7SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
5078b5a1a81eSJ. Bruce Fields 	int ret;
5079b5a1a81eSJ. Bruce Fields 
5080d85ed443SStanislav Kinsbursky 	ret = nfs4_state_create_net(net);
50818daae4dcSStanislav Kinsbursky 	if (ret)
50828daae4dcSStanislav Kinsbursky 		return ret;
50835e1533c7SStanislav Kinsbursky 	nfsd4_client_tracking_init(net);
50842c142baaSStanislav Kinsbursky 	nn->boot_time = get_seconds();
50855ccb0066SStanislav Kinsbursky 	locks_start_grace(net, &nn->nfsd4_manager);
5086a51c84edSStanislav Kinsbursky 	nn->grace_ended = false;
5087d85ed443SStanislav Kinsbursky 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
50885284b44eSStanislav Kinsbursky 	       nn->nfsd4_grace, net);
50895284b44eSStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
5090d85ed443SStanislav Kinsbursky 	return 0;
5091a6d6b781SJeff Layton }
5092d85ed443SStanislav Kinsbursky 
5093d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */
5094d85ed443SStanislav Kinsbursky 
5095d85ed443SStanislav Kinsbursky int
5096d85ed443SStanislav Kinsbursky nfs4_state_start(void)
5097d85ed443SStanislav Kinsbursky {
5098d85ed443SStanislav Kinsbursky 	int ret;
5099d85ed443SStanislav Kinsbursky 
5100d85ed443SStanislav Kinsbursky 	ret = set_callback_cred();
5101d85ed443SStanislav Kinsbursky 	if (ret)
5102d85ed443SStanislav Kinsbursky 		return -ENOMEM;
510358da282bSNeilBrown 	laundry_wq = create_singlethread_workqueue("nfsd4");
5104a6d6b781SJeff Layton 	if (laundry_wq == NULL) {
5105a6d6b781SJeff Layton 		ret = -ENOMEM;
5106a6d6b781SJeff Layton 		goto out_recovery;
5107a6d6b781SJeff Layton 	}
5108b5a1a81eSJ. Bruce Fields 	ret = nfsd4_create_callback_queue();
5109b5a1a81eSJ. Bruce Fields 	if (ret)
5110b5a1a81eSJ. Bruce Fields 		goto out_free_laundry;
511109121281SStanislav Kinsbursky 
5112c2f1a551SMeelap Shah 	set_max_delegations();
5113d85ed443SStanislav Kinsbursky 
5114b5a1a81eSJ. Bruce Fields 	return 0;
5115d85ed443SStanislav Kinsbursky 
5116b5a1a81eSJ. Bruce Fields out_free_laundry:
5117b5a1a81eSJ. Bruce Fields 	destroy_workqueue(laundry_wq);
5118a6d6b781SJeff Layton out_recovery:
5119b5a1a81eSJ. Bruce Fields 	return ret;
51201da177e4SLinus Torvalds }
51211da177e4SLinus Torvalds 
5122ac55fdc4SJeff Layton /* should be called with the state lock held */
5123f252bc68SStanislav Kinsbursky void
51244dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net)
51251da177e4SLinus Torvalds {
51261da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
51271da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
51284dce0ac9SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
51291da177e4SLinus Torvalds 
51304dce0ac9SStanislav Kinsbursky 	cancel_delayed_work_sync(&nn->laundromat_work);
51314dce0ac9SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
5132ac55fdc4SJeff Layton 
51331da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
51341da177e4SLinus Torvalds 	spin_lock(&recall_lock);
5135e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
51361da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
51371da177e4SLinus Torvalds 		list_move(&dp->dl_recall_lru, &reaplist);
51381da177e4SLinus Torvalds 	}
51391da177e4SLinus Torvalds 	spin_unlock(&recall_lock);
51401da177e4SLinus Torvalds 	list_for_each_safe(pos, next, &reaplist) {
51411da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
51423bd64a5bSJ. Bruce Fields 		destroy_delegation(dp);
51431da177e4SLinus Torvalds 	}
51441da177e4SLinus Torvalds 
51453320fef1SStanislav Kinsbursky 	nfsd4_client_tracking_exit(net);
51464dce0ac9SStanislav Kinsbursky 	nfs4_state_destroy_net(net);
51471da177e4SLinus Torvalds }
51481da177e4SLinus Torvalds 
51491da177e4SLinus Torvalds void
51501da177e4SLinus Torvalds nfs4_state_shutdown(void)
51511da177e4SLinus Torvalds {
51525e8d5c29SNeilBrown 	destroy_workqueue(laundry_wq);
5153c3935e30SJ. Bruce Fields 	nfsd4_destroy_callback_queue();
51541da177e4SLinus Torvalds }
51558b70484cSTigran Mkrtchyan 
51568b70484cSTigran Mkrtchyan static void
51578b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
51588b70484cSTigran Mkrtchyan {
515937c593c5STigran Mkrtchyan 	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
516037c593c5STigran Mkrtchyan 		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
51618b70484cSTigran Mkrtchyan }
51628b70484cSTigran Mkrtchyan 
51638b70484cSTigran Mkrtchyan static void
51648b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
51658b70484cSTigran Mkrtchyan {
516637c593c5STigran Mkrtchyan 	if (cstate->minorversion) {
516737c593c5STigran Mkrtchyan 		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
516837c593c5STigran Mkrtchyan 		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
516937c593c5STigran Mkrtchyan 	}
517037c593c5STigran Mkrtchyan }
517137c593c5STigran Mkrtchyan 
517237c593c5STigran Mkrtchyan void
517337c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate)
517437c593c5STigran Mkrtchyan {
517537c593c5STigran Mkrtchyan 	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
51768b70484cSTigran Mkrtchyan }
51778b70484cSTigran Mkrtchyan 
517862cd4a59STigran Mkrtchyan /*
517962cd4a59STigran Mkrtchyan  * functions to set current state id
518062cd4a59STigran Mkrtchyan  */
51818b70484cSTigran Mkrtchyan void
51829428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
51839428fe1aSTigran Mkrtchyan {
51849428fe1aSTigran Mkrtchyan 	put_stateid(cstate, &odp->od_stateid);
51859428fe1aSTigran Mkrtchyan }
51869428fe1aSTigran Mkrtchyan 
51879428fe1aSTigran Mkrtchyan void
51888b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
51898b70484cSTigran Mkrtchyan {
51908b70484cSTigran Mkrtchyan 	put_stateid(cstate, &open->op_stateid);
51918b70484cSTigran Mkrtchyan }
51928b70484cSTigran Mkrtchyan 
51938b70484cSTigran Mkrtchyan void
519462cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
519562cd4a59STigran Mkrtchyan {
519662cd4a59STigran Mkrtchyan 	put_stateid(cstate, &close->cl_stateid);
519762cd4a59STigran Mkrtchyan }
519862cd4a59STigran Mkrtchyan 
519962cd4a59STigran Mkrtchyan void
520062cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
520162cd4a59STigran Mkrtchyan {
520262cd4a59STigran Mkrtchyan 	put_stateid(cstate, &lock->lk_resp_stateid);
520362cd4a59STigran Mkrtchyan }
520462cd4a59STigran Mkrtchyan 
520562cd4a59STigran Mkrtchyan /*
520662cd4a59STigran Mkrtchyan  * functions to consume current state id
520762cd4a59STigran Mkrtchyan  */
52081e97b519STigran Mkrtchyan 
52091e97b519STigran Mkrtchyan void
52109428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
52119428fe1aSTigran Mkrtchyan {
52129428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &odp->od_stateid);
52139428fe1aSTigran Mkrtchyan }
52149428fe1aSTigran Mkrtchyan 
52159428fe1aSTigran Mkrtchyan void
52169428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
52179428fe1aSTigran Mkrtchyan {
52189428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &drp->dr_stateid);
52199428fe1aSTigran Mkrtchyan }
52209428fe1aSTigran Mkrtchyan 
52219428fe1aSTigran Mkrtchyan void
52221e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
52231e97b519STigran Mkrtchyan {
52241e97b519STigran Mkrtchyan 	get_stateid(cstate, &fsp->fr_stateid);
52251e97b519STigran Mkrtchyan }
52261e97b519STigran Mkrtchyan 
52271e97b519STigran Mkrtchyan void
52281e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
52291e97b519STigran Mkrtchyan {
52301e97b519STigran Mkrtchyan 	get_stateid(cstate, &setattr->sa_stateid);
52311e97b519STigran Mkrtchyan }
52321e97b519STigran Mkrtchyan 
523362cd4a59STigran Mkrtchyan void
52348b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
52358b70484cSTigran Mkrtchyan {
52368b70484cSTigran Mkrtchyan 	get_stateid(cstate, &close->cl_stateid);
52378b70484cSTigran Mkrtchyan }
52388b70484cSTigran Mkrtchyan 
52398b70484cSTigran Mkrtchyan void
524062cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
52418b70484cSTigran Mkrtchyan {
524262cd4a59STigran Mkrtchyan 	get_stateid(cstate, &locku->lu_stateid);
52438b70484cSTigran Mkrtchyan }
524430813e27STigran Mkrtchyan 
524530813e27STigran Mkrtchyan void
524630813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
524730813e27STigran Mkrtchyan {
524830813e27STigran Mkrtchyan 	get_stateid(cstate, &read->rd_stateid);
524930813e27STigran Mkrtchyan }
525030813e27STigran Mkrtchyan 
525130813e27STigran Mkrtchyan void
525230813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
525330813e27STigran Mkrtchyan {
525430813e27STigran Mkrtchyan 	get_stateid(cstate, &write->wr_stateid);
525530813e27STigran Mkrtchyan }
5256