xref: /openbmc/linux/fs/nfsd/nfs4state.c (revision 3738d50e)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds *  Copyright (c) 2001 The Regents of the University of Michigan.
31da177e4SLinus Torvalds *  All rights reserved.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *  Kendrick Smith <kmsmith@umich.edu>
61da177e4SLinus Torvalds *  Andy Adamson <kandros@umich.edu>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds *  Redistribution and use in source and binary forms, with or without
91da177e4SLinus Torvalds *  modification, are permitted provided that the following conditions
101da177e4SLinus Torvalds *  are met:
111da177e4SLinus Torvalds *
121da177e4SLinus Torvalds *  1. Redistributions of source code must retain the above copyright
131da177e4SLinus Torvalds *     notice, this list of conditions and the following disclaimer.
141da177e4SLinus Torvalds *  2. Redistributions in binary form must reproduce the above copyright
151da177e4SLinus Torvalds *     notice, this list of conditions and the following disclaimer in the
161da177e4SLinus Torvalds *     documentation and/or other materials provided with the distribution.
171da177e4SLinus Torvalds *  3. Neither the name of the University nor the names of its
181da177e4SLinus Torvalds *     contributors may be used to endorse or promote products derived
191da177e4SLinus Torvalds *     from this software without specific prior written permission.
201da177e4SLinus Torvalds *
211da177e4SLinus Torvalds *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
221da177e4SLinus Torvalds *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
231da177e4SLinus Torvalds *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
241da177e4SLinus Torvalds *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251da177e4SLinus Torvalds *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
261da177e4SLinus Torvalds *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
271da177e4SLinus Torvalds *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
281da177e4SLinus Torvalds *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
291da177e4SLinus Torvalds *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
301da177e4SLinus Torvalds *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
311da177e4SLinus Torvalds *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
321da177e4SLinus Torvalds *
331da177e4SLinus Torvalds */
341da177e4SLinus Torvalds 
35aceaf78dSDave Hansen #include <linux/file.h>
36b89f4321SArnd Bergmann #include <linux/fs.h>
375a0e3ad6STejun Heo #include <linux/slab.h>
380964a3d3SNeilBrown #include <linux/namei.h>
39c2f1a551SMeelap Shah #include <linux/swap.h>
4017456804SBryan Schumaker #include <linux/pagemap.h>
417df302f7SChuck Lever #include <linux/ratelimit.h>
4268e76ad0SOlga Kornievskaia #include <linux/sunrpc/svcauth_gss.h>
435976687aSJeff Layton #include <linux/sunrpc/addr.h>
446282cd56SNeilBrown #include <linux/hash.h>
459a74af21SBoaz Harrosh #include "xdr4.h"
4606b332a5SJ. Bruce Fields #include "xdr4cb.h"
470a3adadeSJ. Bruce Fields #include "vfs.h"
48bfa4b365SJ. Bruce Fields #include "current_stateid.h"
491da177e4SLinus Torvalds 
505e1533c7SStanislav Kinsbursky #include "netns.h"
515e1533c7SStanislav Kinsbursky 
521da177e4SLinus Torvalds #define NFSDDBG_FACILITY                NFSDDBG_PROC
531da177e4SLinus Torvalds 
54f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0}
55f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = {
56f32f3c2dSJ. Bruce Fields 	.si_generation = ~0,
57f32f3c2dSJ. Bruce Fields 	.si_opaque = all_ones,
58f32f3c2dSJ. Bruce Fields };
59f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = {
60f32f3c2dSJ. Bruce Fields 	/* all fields zero */
61f32f3c2dSJ. Bruce Fields };
6219ff0f28STigran Mkrtchyan static const stateid_t currentstateid = {
6319ff0f28STigran Mkrtchyan 	.si_generation = 1,
6419ff0f28STigran Mkrtchyan };
65f32f3c2dSJ. Bruce Fields 
66ec6b5d7bSAndy Adamson static u64 current_sessionid = 1;
67fd39ca9aSNeilBrown 
68f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
69f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
7019ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds /* forward declarations */
73f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
746011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
751da177e4SLinus Torvalds 
768b671b80SJ. Bruce Fields /* Locking: */
778b671b80SJ. Bruce Fields 
788b671b80SJ. Bruce Fields /* Currently used for almost all code touching nfsv4 state: */
79353ab6e9SIngo Molnar static DEFINE_MUTEX(client_mutex);
801da177e4SLinus Torvalds 
818b671b80SJ. Bruce Fields /*
828b671b80SJ. Bruce Fields  * Currently used for the del_recall_lru and file hash table.  In an
838b671b80SJ. Bruce Fields  * effort to decrease the scope of the client_mutex, this spinlock may
848b671b80SJ. Bruce Fields  * eventually cover more:
858b671b80SJ. Bruce Fields  */
86cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock);
878b671b80SJ. Bruce Fields 
88b401be22SJeff Layton /*
89b401be22SJeff Layton  * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for
90b401be22SJeff Layton  * the refcount on the open stateid to drop.
91b401be22SJeff Layton  */
92b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq);
93b401be22SJeff Layton 
94abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab;
95abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab;
96abf1135bSChristoph Hellwig static struct kmem_cache *file_slab;
97abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab;
98abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab;
99e60d4398SNeilBrown 
1001da177e4SLinus Torvalds void
1011da177e4SLinus Torvalds nfs4_lock_state(void)
1021da177e4SLinus Torvalds {
103353ab6e9SIngo Molnar 	mutex_lock(&client_mutex);
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds 
10666b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *);
107508dc6e1SBenny Halevy 
10866b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses)
109508dc6e1SBenny Halevy {
11066b2b9b2SJ. Bruce Fields 	return ses->se_flags & NFS4_SESSION_DEAD;
11166b2b9b2SJ. Bruce Fields }
11266b2b9b2SJ. Bruce Fields 
113f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
114f0f51f5cSJ. Bruce Fields {
115f0f51f5cSJ. Bruce Fields 	if (atomic_read(&ses->se_ref) > ref_held_by_me)
11666b2b9b2SJ. Bruce Fields 		return nfserr_jukebox;
11766b2b9b2SJ. Bruce Fields 	ses->se_flags |= NFS4_SESSION_DEAD;
11866b2b9b2SJ. Bruce Fields 	return nfs_ok;
11966b2b9b2SJ. Bruce Fields }
12066b2b9b2SJ. Bruce Fields 
1211da177e4SLinus Torvalds void
1221da177e4SLinus Torvalds nfs4_unlock_state(void)
1231da177e4SLinus Torvalds {
124353ab6e9SIngo Molnar 	mutex_unlock(&client_mutex);
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds 
127221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp)
128221a6876SJ. Bruce Fields {
129221a6876SJ. Bruce Fields 	return clp->cl_time == 0;
130221a6876SJ. Bruce Fields }
131221a6876SJ. Bruce Fields 
132221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp)
133221a6876SJ. Bruce Fields {
1340a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1350a880a28STrond Myklebust 
1360a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1370a880a28STrond Myklebust 
138221a6876SJ. Bruce Fields 	if (is_client_expired(clp))
139221a6876SJ. Bruce Fields 		return nfserr_expired;
140221a6876SJ. Bruce Fields 	atomic_inc(&clp->cl_refcount);
141221a6876SJ. Bruce Fields 	return nfs_ok;
142221a6876SJ. Bruce Fields }
143221a6876SJ. Bruce Fields 
144221a6876SJ. Bruce Fields /* must be called under the client_lock */
145221a6876SJ. Bruce Fields static inline void
146221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp)
147221a6876SJ. Bruce Fields {
148221a6876SJ. Bruce Fields 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
149221a6876SJ. Bruce Fields 
150221a6876SJ. Bruce Fields 	if (is_client_expired(clp)) {
151221a6876SJ. Bruce Fields 		WARN_ON(1);
152221a6876SJ. Bruce Fields 		printk("%s: client (clientid %08x/%08x) already expired\n",
153221a6876SJ. Bruce Fields 			__func__,
154221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
155221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
156221a6876SJ. Bruce Fields 		return;
157221a6876SJ. Bruce Fields 	}
158221a6876SJ. Bruce Fields 
159221a6876SJ. Bruce Fields 	dprintk("renewing client (clientid %08x/%08x)\n",
160221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_boot,
161221a6876SJ. Bruce Fields 			clp->cl_clientid.cl_id);
162221a6876SJ. Bruce Fields 	list_move_tail(&clp->cl_lru, &nn->client_lru);
163221a6876SJ. Bruce Fields 	clp->cl_time = get_seconds();
164221a6876SJ. Bruce Fields }
165221a6876SJ. Bruce Fields 
166221a6876SJ. Bruce Fields static inline void
167221a6876SJ. Bruce Fields renew_client(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 	spin_lock(&nn->client_lock);
172221a6876SJ. Bruce Fields 	renew_client_locked(clp);
173221a6876SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
174221a6876SJ. Bruce Fields }
175221a6876SJ. Bruce Fields 
176ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp)
177221a6876SJ. Bruce Fields {
1780a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1790a880a28STrond Myklebust 
1800a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1810a880a28STrond Myklebust 
182221a6876SJ. Bruce Fields 	if (!atomic_dec_and_test(&clp->cl_refcount))
183221a6876SJ. Bruce Fields 		return;
184221a6876SJ. Bruce Fields 	if (!is_client_expired(clp))
185221a6876SJ. Bruce Fields 		renew_client_locked(clp);
186221a6876SJ. Bruce Fields }
187221a6876SJ. Bruce Fields 
1884b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp)
1894b24ca7dSJeff Layton {
1904b24ca7dSJeff Layton 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1914b24ca7dSJeff Layton 
192d6c249b4SJeff Layton 	if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
193d6c249b4SJeff Layton 		return;
194d6c249b4SJeff Layton 	if (!is_client_expired(clp))
195d6c249b4SJeff Layton 		renew_client_locked(clp);
1964b24ca7dSJeff Layton 	spin_unlock(&nn->client_lock);
1974b24ca7dSJeff Layton }
1984b24ca7dSJeff Layton 
199d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
200d4e19e70STrond Myklebust {
201d4e19e70STrond Myklebust 	__be32 status;
202d4e19e70STrond Myklebust 
203d4e19e70STrond Myklebust 	if (is_session_dead(ses))
204d4e19e70STrond Myklebust 		return nfserr_badsession;
205d4e19e70STrond Myklebust 	status = get_client_locked(ses->se_client);
206d4e19e70STrond Myklebust 	if (status)
207d4e19e70STrond Myklebust 		return status;
208d4e19e70STrond Myklebust 	atomic_inc(&ses->se_ref);
209d4e19e70STrond Myklebust 	return nfs_ok;
210d4e19e70STrond Myklebust }
211d4e19e70STrond Myklebust 
212d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses)
213d4e19e70STrond Myklebust {
214d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
2150a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2160a880a28STrond Myklebust 
2170a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
218d4e19e70STrond Myklebust 
219d4e19e70STrond Myklebust 	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
220d4e19e70STrond Myklebust 		free_session(ses);
221d4e19e70STrond Myklebust 	put_client_renew_locked(clp);
222d4e19e70STrond Myklebust }
223d4e19e70STrond Myklebust 
224d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses)
225d4e19e70STrond Myklebust {
226d4e19e70STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
227d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
228d4e19e70STrond Myklebust 
229d4e19e70STrond Myklebust 	spin_lock(&nn->client_lock);
230d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
231d4e19e70STrond Myklebust 	spin_unlock(&nn->client_lock);
232d4e19e70STrond Myklebust }
233d4e19e70STrond Myklebust 
2347ffb5880STrond Myklebust static int
235d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
2367ffb5880STrond Myklebust {
2377ffb5880STrond Myklebust 	return (sop->so_owner.len == owner->len) &&
238d4f0489fSTrond Myklebust 		0 == memcmp(sop->so_owner.data, owner->data, owner->len);
2397ffb5880STrond Myklebust }
2407ffb5880STrond Myklebust 
2417ffb5880STrond Myklebust static struct nfs4_openowner *
2427ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
243d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
2447ffb5880STrond Myklebust {
2457ffb5880STrond Myklebust 	struct nfs4_stateowner *so;
2467ffb5880STrond Myklebust 
247d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
2487ffb5880STrond Myklebust 
249d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval],
250d4f0489fSTrond Myklebust 			    so_strhash) {
2517ffb5880STrond Myklebust 		if (!so->so_is_open_owner)
2527ffb5880STrond Myklebust 			continue;
253d4f0489fSTrond Myklebust 		if (same_owner_str(so, &open->op_owner)) {
2547ffb5880STrond Myklebust 			atomic_inc(&so->so_count);
255d4f0489fSTrond Myklebust 			return openowner(so);
2567ffb5880STrond Myklebust 		}
2577ffb5880STrond Myklebust 	}
2587ffb5880STrond Myklebust 	return NULL;
2597ffb5880STrond Myklebust }
2607ffb5880STrond Myklebust 
2617ffb5880STrond Myklebust static struct nfs4_openowner *
2627ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
263d4f0489fSTrond Myklebust 			struct nfs4_client *clp)
2647ffb5880STrond Myklebust {
2657ffb5880STrond Myklebust 	struct nfs4_openowner *oo;
2667ffb5880STrond Myklebust 
267d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
268d4f0489fSTrond Myklebust 	oo = find_openstateowner_str_locked(hashval, open, clp);
269d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
2707ffb5880STrond Myklebust 	return oo;
2717ffb5880STrond Myklebust }
2727ffb5880STrond Myklebust 
2731da177e4SLinus Torvalds static inline u32
2741da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds 	unsigned char *cptr = (unsigned char *) ptr;
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	u32 x = 0;
2791da177e4SLinus Torvalds 	while (nbytes--) {
2801da177e4SLinus Torvalds 		x *= 37;
2811da177e4SLinus Torvalds 		x += *cptr++;
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds 	return x;
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
28632513b40SJ. Bruce Fields static void nfsd4_free_file(struct nfs4_file *f)
28732513b40SJ. Bruce Fields {
28832513b40SJ. Bruce Fields 	kmem_cache_free(file_slab, f);
28932513b40SJ. Bruce Fields }
29032513b40SJ. Bruce Fields 
29113cd2184SNeilBrown static inline void
29213cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi)
29313cd2184SNeilBrown {
29402e1215fSJeff Layton 	might_lock(&state_lock);
29502e1215fSJeff Layton 
296cdc97505SBenny Halevy 	if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
29789876f8cSJeff Layton 		hlist_del(&fi->fi_hash);
298cdc97505SBenny Halevy 		spin_unlock(&state_lock);
29932513b40SJ. Bruce Fields 		nfsd4_free_file(fi);
3008b671b80SJ. Bruce Fields 	}
30113cd2184SNeilBrown }
30213cd2184SNeilBrown 
30313cd2184SNeilBrown static inline void
30413cd2184SNeilBrown get_nfs4_file(struct nfs4_file *fi)
30513cd2184SNeilBrown {
3068b671b80SJ. Bruce Fields 	atomic_inc(&fi->fi_ref);
30713cd2184SNeilBrown }
30813cd2184SNeilBrown 
309de18643dSTrond Myklebust static struct file *
310de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag)
311de18643dSTrond Myklebust {
312de18643dSTrond Myklebust 	if (f->fi_fds[oflag])
313de18643dSTrond Myklebust 		return get_file(f->fi_fds[oflag]);
314de18643dSTrond Myklebust 	return NULL;
315de18643dSTrond Myklebust }
316de18643dSTrond Myklebust 
317de18643dSTrond Myklebust static struct file *
318de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f)
319de18643dSTrond Myklebust {
320de18643dSTrond Myklebust 	struct file *ret;
321de18643dSTrond Myklebust 
322de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
323de18643dSTrond Myklebust 
324de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_WRONLY);
325de18643dSTrond Myklebust 	if (!ret)
326de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
327de18643dSTrond Myklebust 	return ret;
328de18643dSTrond Myklebust }
329de18643dSTrond Myklebust 
330de18643dSTrond Myklebust static struct file *
331de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f)
332de18643dSTrond Myklebust {
333de18643dSTrond Myklebust 	struct file *ret;
334de18643dSTrond Myklebust 
335de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
336de18643dSTrond Myklebust 	ret = find_writeable_file_locked(f);
337de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
338de18643dSTrond Myklebust 
339de18643dSTrond Myklebust 	return ret;
340de18643dSTrond Myklebust }
341de18643dSTrond Myklebust 
342de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f)
343de18643dSTrond Myklebust {
344de18643dSTrond Myklebust 	struct file *ret;
345de18643dSTrond Myklebust 
346de18643dSTrond Myklebust 	lockdep_assert_held(&f->fi_lock);
347de18643dSTrond Myklebust 
348de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDONLY);
349de18643dSTrond Myklebust 	if (!ret)
350de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_RDWR);
351de18643dSTrond Myklebust 	return ret;
352de18643dSTrond Myklebust }
353de18643dSTrond Myklebust 
354de18643dSTrond Myklebust static struct file *
355de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f)
356de18643dSTrond Myklebust {
357de18643dSTrond Myklebust 	struct file *ret;
358de18643dSTrond Myklebust 
359de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
360de18643dSTrond Myklebust 	ret = find_readable_file_locked(f);
361de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
362de18643dSTrond Myklebust 
363de18643dSTrond Myklebust 	return ret;
364de18643dSTrond Myklebust }
365de18643dSTrond Myklebust 
366de18643dSTrond Myklebust static struct file *
367de18643dSTrond Myklebust find_any_file(struct nfs4_file *f)
368de18643dSTrond Myklebust {
369de18643dSTrond Myklebust 	struct file *ret;
370de18643dSTrond Myklebust 
371de18643dSTrond Myklebust 	spin_lock(&f->fi_lock);
372de18643dSTrond Myklebust 	ret = __nfs4_get_fd(f, O_RDWR);
373de18643dSTrond Myklebust 	if (!ret) {
374de18643dSTrond Myklebust 		ret = __nfs4_get_fd(f, O_WRONLY);
375de18643dSTrond Myklebust 		if (!ret)
376de18643dSTrond Myklebust 			ret = __nfs4_get_fd(f, O_RDONLY);
377de18643dSTrond Myklebust 	}
378de18643dSTrond Myklebust 	spin_unlock(&f->fi_lock);
379de18643dSTrond Myklebust 	return ret;
380de18643dSTrond Myklebust }
381de18643dSTrond Myklebust 
38202a3508dSTrond Myklebust static atomic_long_t num_delegations;
383697ce9beSZhang Yanfei unsigned long max_delegations;
384ef0f3390SNeilBrown 
385ef0f3390SNeilBrown /*
386ef0f3390SNeilBrown  * Open owner state (share locks)
387ef0f3390SNeilBrown  */
388ef0f3390SNeilBrown 
38916bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */
39016bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS              8
39116bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
39216bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
393ef0f3390SNeilBrown 
394d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername)
395ddc04c41SJ. Bruce Fields {
396ddc04c41SJ. Bruce Fields 	unsigned int ret;
397ddc04c41SJ. Bruce Fields 
398ddc04c41SJ. Bruce Fields 	ret = opaque_hashval(ownername->data, ownername->len);
39916bfdaafSJ. Bruce Fields 	return ret & OWNER_HASH_MASK;
400ddc04c41SJ. Bruce Fields }
401ef0f3390SNeilBrown 
402ef0f3390SNeilBrown /* hash table for nfs4_file */
403ef0f3390SNeilBrown #define FILE_HASH_BITS                   8
404ef0f3390SNeilBrown #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
40535079582SShan Wei 
406ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh)
407ddc04c41SJ. Bruce Fields {
408ca943217STrond Myklebust 	return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0);
409ca943217STrond Myklebust }
410ca943217STrond Myklebust 
411ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh)
412ca943217STrond Myklebust {
413ca943217STrond Myklebust 	return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1);
414ca943217STrond Myklebust }
415ca943217STrond Myklebust 
416ca943217STrond Myklebust static bool nfsd_fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
417ca943217STrond Myklebust {
418ca943217STrond Myklebust 	return fh1->fh_size == fh2->fh_size &&
419ca943217STrond Myklebust 		!memcmp(fh1->fh_base.fh_pad,
420ca943217STrond Myklebust 				fh2->fh_base.fh_pad,
421ca943217STrond Myklebust 				fh1->fh_size);
422ddc04c41SJ. Bruce Fields }
423ddc04c41SJ. Bruce Fields 
42489876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
425ef0f3390SNeilBrown 
42612659651SJeff Layton static void
42712659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
4283477565eSJ. Bruce Fields {
4297214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4307214e860SJeff Layton 
43112659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
43212659651SJeff Layton 		atomic_inc(&fp->fi_access[O_WRONLY]);
43312659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
43412659651SJeff Layton 		atomic_inc(&fp->fi_access[O_RDONLY]);
4353477565eSJ. Bruce Fields }
4363477565eSJ. Bruce Fields 
43712659651SJeff Layton static __be32
43812659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access)
439998db52cSJ. Bruce Fields {
4407214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
4417214e860SJeff Layton 
44212659651SJeff Layton 	/* Does this access mode make sense? */
44312659651SJeff Layton 	if (access & ~NFS4_SHARE_ACCESS_BOTH)
44412659651SJeff Layton 		return nfserr_inval;
44512659651SJeff Layton 
446baeb4ff0SJeff Layton 	/* Does it conflict with a deny mode already set? */
447baeb4ff0SJeff Layton 	if ((access & fp->fi_share_deny) != 0)
448baeb4ff0SJeff Layton 		return nfserr_share_denied;
449baeb4ff0SJeff Layton 
45012659651SJeff Layton 	__nfs4_file_get_access(fp, access);
45112659651SJeff Layton 	return nfs_ok;
452998db52cSJ. Bruce Fields }
453998db52cSJ. Bruce Fields 
454baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny)
455baeb4ff0SJeff Layton {
456baeb4ff0SJeff Layton 	/* Common case is that there is no deny mode. */
457baeb4ff0SJeff Layton 	if (deny) {
458baeb4ff0SJeff Layton 		/* Does this deny mode make sense? */
459baeb4ff0SJeff Layton 		if (deny & ~NFS4_SHARE_DENY_BOTH)
460baeb4ff0SJeff Layton 			return nfserr_inval;
461baeb4ff0SJeff Layton 
462baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_READ) &&
463baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_RDONLY]))
464baeb4ff0SJeff Layton 			return nfserr_share_denied;
465baeb4ff0SJeff Layton 
466baeb4ff0SJeff Layton 		if ((deny & NFS4_SHARE_DENY_WRITE) &&
467baeb4ff0SJeff Layton 		    atomic_read(&fp->fi_access[O_WRONLY]))
468baeb4ff0SJeff Layton 			return nfserr_share_denied;
469baeb4ff0SJeff Layton 	}
470baeb4ff0SJeff Layton 	return nfs_ok;
471baeb4ff0SJeff Layton }
472baeb4ff0SJeff Layton 
473998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
474f9d7562fSJ. Bruce Fields {
475de18643dSTrond Myklebust 	might_lock(&fp->fi_lock);
476de18643dSTrond Myklebust 
477de18643dSTrond Myklebust 	if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) {
478de18643dSTrond Myklebust 		struct file *f1 = NULL;
479de18643dSTrond Myklebust 		struct file *f2 = NULL;
480de18643dSTrond Myklebust 
4816d338b51SJeff Layton 		swap(f1, fp->fi_fds[oflag]);
4820c7c3e67SJ. Bruce Fields 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
4836d338b51SJeff Layton 			swap(f2, fp->fi_fds[O_RDWR]);
484de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
485de18643dSTrond Myklebust 		if (f1)
486de18643dSTrond Myklebust 			fput(f1);
487de18643dSTrond Myklebust 		if (f2)
488de18643dSTrond Myklebust 			fput(f2);
489f9d7562fSJ. Bruce Fields 	}
490f9d7562fSJ. Bruce Fields }
491f9d7562fSJ. Bruce Fields 
49212659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
493998db52cSJ. Bruce Fields {
49412659651SJeff Layton 	WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH);
49512659651SJeff Layton 
49612659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_WRITE)
497998db52cSJ. Bruce Fields 		__nfs4_file_put_access(fp, O_WRONLY);
49812659651SJeff Layton 	if (access & NFS4_SHARE_ACCESS_READ)
49912659651SJeff Layton 		__nfs4_file_put_access(fp, O_RDONLY);
500998db52cSJ. Bruce Fields }
501998db52cSJ. Bruce Fields 
5026011695dSTrond Myklebust static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
5036011695dSTrond Myklebust 					 struct kmem_cache *slab)
504996e0938SJ. Bruce Fields {
5053abdb607SJ. Bruce Fields 	struct nfs4_stid *stid;
5063abdb607SJ. Bruce Fields 	int new_id;
5073abdb607SJ. Bruce Fields 
508f8338834STrond Myklebust 	stid = kmem_cache_zalloc(slab, GFP_KERNEL);
5093abdb607SJ. Bruce Fields 	if (!stid)
5103abdb607SJ. Bruce Fields 		return NULL;
511996e0938SJ. Bruce Fields 
5124770d722SJeff Layton 	idr_preload(GFP_KERNEL);
5134770d722SJeff Layton 	spin_lock(&cl->cl_lock);
5144770d722SJeff Layton 	new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT);
5154770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
5164770d722SJeff Layton 	idr_preload_end();
517ebd6c707STejun Heo 	if (new_id < 0)
5183abdb607SJ. Bruce Fields 		goto out_free;
5193abdb607SJ. Bruce Fields 	stid->sc_client = cl;
5203abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_id = new_id;
5213abdb607SJ. Bruce Fields 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
5223abdb607SJ. Bruce Fields 	/* Will be incremented before return to client: */
52372c0b0fbSTrond Myklebust 	atomic_set(&stid->sc_count, 1);
5243abdb607SJ. Bruce Fields 
525996e0938SJ. Bruce Fields 	/*
5263abdb607SJ. Bruce Fields 	 * It shouldn't be a problem to reuse an opaque stateid value.
5273abdb607SJ. Bruce Fields 	 * I don't think it is for 4.1.  But with 4.0 I worry that, for
5283abdb607SJ. Bruce Fields 	 * example, a stray write retransmission could be accepted by
5293abdb607SJ. Bruce Fields 	 * the server when it should have been rejected.  Therefore,
5303abdb607SJ. Bruce Fields 	 * adopt a trick from the sctp code to attempt to maximize the
5313abdb607SJ. Bruce Fields 	 * amount of time until an id is reused, by ensuring they always
5323abdb607SJ. Bruce Fields 	 * "increase" (mod INT_MAX):
533996e0938SJ. Bruce Fields 	 */
5343abdb607SJ. Bruce Fields 	return stid;
5353abdb607SJ. Bruce Fields out_free:
5362c44a234SWei Yongjun 	kmem_cache_free(slab, stid);
5373abdb607SJ. Bruce Fields 	return NULL;
5382a74aba7SJ. Bruce Fields }
5392a74aba7SJ. Bruce Fields 
540b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
5414cdc951bSJ. Bruce Fields {
5426011695dSTrond Myklebust 	struct nfs4_stid *stid;
5436011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp;
5446011695dSTrond Myklebust 
5456011695dSTrond Myklebust 	stid = nfs4_alloc_stid(clp, stateid_slab);
5466011695dSTrond Myklebust 	if (!stid)
5476011695dSTrond Myklebust 		return NULL;
5486011695dSTrond Myklebust 
5496011695dSTrond Myklebust 	stp = openlockstateid(stid);
5506011695dSTrond Myklebust 	stp->st_stid.sc_free = nfs4_free_ol_stateid;
5516011695dSTrond Myklebust 	return stp;
5526011695dSTrond Myklebust }
5536011695dSTrond Myklebust 
5546011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid)
5556011695dSTrond Myklebust {
5566011695dSTrond Myklebust 	kmem_cache_free(deleg_slab, stid);
5576011695dSTrond Myklebust 	atomic_long_dec(&num_delegations);
5584cdc951bSJ. Bruce Fields }
5594cdc951bSJ. Bruce Fields 
5606282cd56SNeilBrown /*
5616282cd56SNeilBrown  * When we recall a delegation, we should be careful not to hand it
5626282cd56SNeilBrown  * out again straight away.
5636282cd56SNeilBrown  * To ensure this we keep a pair of bloom filters ('new' and 'old')
5646282cd56SNeilBrown  * in which the filehandles of recalled delegations are "stored".
5656282cd56SNeilBrown  * If a filehandle appear in either filter, a delegation is blocked.
5666282cd56SNeilBrown  * When a delegation is recalled, the filehandle is stored in the "new"
5676282cd56SNeilBrown  * filter.
5686282cd56SNeilBrown  * Every 30 seconds we swap the filters and clear the "new" one,
5696282cd56SNeilBrown  * unless both are empty of course.
5706282cd56SNeilBrown  *
5716282cd56SNeilBrown  * Each filter is 256 bits.  We hash the filehandle to 32bit and use the
5726282cd56SNeilBrown  * low 3 bytes as hash-table indices.
5736282cd56SNeilBrown  *
574f54fe962SJeff Layton  * 'blocked_delegations_lock', which is always taken in block_delegations(),
5756282cd56SNeilBrown  * is used to manage concurrent access.  Testing does not need the lock
5766282cd56SNeilBrown  * except when swapping the two filters.
5776282cd56SNeilBrown  */
578f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock);
5796282cd56SNeilBrown static struct bloom_pair {
5806282cd56SNeilBrown 	int	entries, old_entries;
5816282cd56SNeilBrown 	time_t	swap_time;
5826282cd56SNeilBrown 	int	new; /* index into 'set' */
5836282cd56SNeilBrown 	DECLARE_BITMAP(set[2], 256);
5846282cd56SNeilBrown } blocked_delegations;
5856282cd56SNeilBrown 
5866282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh)
5876282cd56SNeilBrown {
5886282cd56SNeilBrown 	u32 hash;
5896282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
5906282cd56SNeilBrown 
5916282cd56SNeilBrown 	if (bd->entries == 0)
5926282cd56SNeilBrown 		return 0;
5936282cd56SNeilBrown 	if (seconds_since_boot() - bd->swap_time > 30) {
594f54fe962SJeff Layton 		spin_lock(&blocked_delegations_lock);
5956282cd56SNeilBrown 		if (seconds_since_boot() - bd->swap_time > 30) {
5966282cd56SNeilBrown 			bd->entries -= bd->old_entries;
5976282cd56SNeilBrown 			bd->old_entries = bd->entries;
5986282cd56SNeilBrown 			memset(bd->set[bd->new], 0,
5996282cd56SNeilBrown 			       sizeof(bd->set[0]));
6006282cd56SNeilBrown 			bd->new = 1-bd->new;
6016282cd56SNeilBrown 			bd->swap_time = seconds_since_boot();
6026282cd56SNeilBrown 		}
603f54fe962SJeff Layton 		spin_unlock(&blocked_delegations_lock);
6046282cd56SNeilBrown 	}
6056282cd56SNeilBrown 	hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0);
6066282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[0]) &&
6076282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[0]) &&
6086282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[0]))
6096282cd56SNeilBrown 		return 1;
6106282cd56SNeilBrown 
6116282cd56SNeilBrown 	if (test_bit(hash&255, bd->set[1]) &&
6126282cd56SNeilBrown 	    test_bit((hash>>8)&255, bd->set[1]) &&
6136282cd56SNeilBrown 	    test_bit((hash>>16)&255, bd->set[1]))
6146282cd56SNeilBrown 		return 1;
6156282cd56SNeilBrown 
6166282cd56SNeilBrown 	return 0;
6176282cd56SNeilBrown }
6186282cd56SNeilBrown 
6196282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh)
6206282cd56SNeilBrown {
6216282cd56SNeilBrown 	u32 hash;
6226282cd56SNeilBrown 	struct bloom_pair *bd = &blocked_delegations;
6236282cd56SNeilBrown 
6246282cd56SNeilBrown 	hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0);
6256282cd56SNeilBrown 
626f54fe962SJeff Layton 	spin_lock(&blocked_delegations_lock);
6276282cd56SNeilBrown 	__set_bit(hash&255, bd->set[bd->new]);
6286282cd56SNeilBrown 	__set_bit((hash>>8)&255, bd->set[bd->new]);
6296282cd56SNeilBrown 	__set_bit((hash>>16)&255, bd->set[bd->new]);
6306282cd56SNeilBrown 	if (bd->entries == 0)
6316282cd56SNeilBrown 		bd->swap_time = seconds_since_boot();
6326282cd56SNeilBrown 	bd->entries += 1;
633f54fe962SJeff Layton 	spin_unlock(&blocked_delegations_lock);
6346282cd56SNeilBrown }
6356282cd56SNeilBrown 
6361da177e4SLinus Torvalds static struct nfs4_delegation *
637f9416e28SJeff Layton alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh)
6381da177e4SLinus Torvalds {
6391da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
64002a3508dSTrond Myklebust 	long n;
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds 	dprintk("NFSD alloc_init_deleg\n");
64302a3508dSTrond Myklebust 	n = atomic_long_inc_return(&num_delegations);
64402a3508dSTrond Myklebust 	if (n < 0 || n > max_delegations)
64502a3508dSTrond Myklebust 		goto out_dec;
6466282cd56SNeilBrown 	if (delegation_blocked(&current_fh->fh_handle))
64702a3508dSTrond Myklebust 		goto out_dec;
648996e0938SJ. Bruce Fields 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
6495b2d21c1SNeilBrown 	if (dp == NULL)
65002a3508dSTrond Myklebust 		goto out_dec;
6516011695dSTrond Myklebust 
6526011695dSTrond Myklebust 	dp->dl_stid.sc_free = nfs4_free_deleg;
6532a74aba7SJ. Bruce Fields 	/*
6542a74aba7SJ. Bruce Fields 	 * delegation seqid's are never incremented.  The 4.1 special
6556136d2b4SJ. Bruce Fields 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
6566136d2b4SJ. Bruce Fields 	 * 0 anyway just for consistency and use 1:
6572a74aba7SJ. Bruce Fields 	 */
6582a74aba7SJ. Bruce Fields 	dp->dl_stid.sc_stateid.si_generation = 1;
659ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perfile);
660ea1da636SNeilBrown 	INIT_LIST_HEAD(&dp->dl_perclnt);
6611da177e4SLinus Torvalds 	INIT_LIST_HEAD(&dp->dl_recall_lru);
66299c41515SJ. Bruce Fields 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
66302e1215fSJeff Layton 	INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall);
6641da177e4SLinus Torvalds 	return dp;
66502a3508dSTrond Myklebust out_dec:
66602a3508dSTrond Myklebust 	atomic_long_dec(&num_delegations);
66702a3508dSTrond Myklebust 	return NULL;
6681da177e4SLinus Torvalds }
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds void
6716011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s)
6721da177e4SLinus Torvalds {
67311b9164aSTrond Myklebust 	struct nfs4_file *fp = s->sc_file;
6746011695dSTrond Myklebust 	struct nfs4_client *clp = s->sc_client;
6756011695dSTrond Myklebust 
6764770d722SJeff Layton 	might_lock(&clp->cl_lock);
6774770d722SJeff Layton 
678b401be22SJeff Layton 	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
679b401be22SJeff Layton 		wake_up_all(&close_wq);
6806011695dSTrond Myklebust 		return;
681b401be22SJeff Layton 	}
6826011695dSTrond Myklebust 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
6834770d722SJeff Layton 	spin_unlock(&clp->cl_lock);
6846011695dSTrond Myklebust 	s->sc_free(s);
68511b9164aSTrond Myklebust 	if (fp)
68611b9164aSTrond Myklebust 		put_nfs4_file(fp);
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds 
689acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp)
6901da177e4SLinus Torvalds {
691417c6629SJeff Layton 	lockdep_assert_held(&state_lock);
692417c6629SJeff Layton 
693cbf7a75bSJ. Bruce Fields 	if (!fp->fi_lease)
694cbf7a75bSJ. Bruce Fields 		return;
695acfdf5c3SJ. Bruce Fields 	if (atomic_dec_and_test(&fp->fi_delegees)) {
696acfdf5c3SJ. Bruce Fields 		vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
697acfdf5c3SJ. Bruce Fields 		fp->fi_lease = NULL;
6984ee63624SJ. Bruce Fields 		fput(fp->fi_deleg_file);
699acfdf5c3SJ. Bruce Fields 		fp->fi_deleg_file = NULL;
700acfdf5c3SJ. Bruce Fields 	}
7011da177e4SLinus Torvalds }
7021da177e4SLinus Torvalds 
7036136d2b4SJ. Bruce Fields static void unhash_stid(struct nfs4_stid *s)
7046136d2b4SJ. Bruce Fields {
7053abdb607SJ. Bruce Fields 	s->sc_type = 0;
7066136d2b4SJ. Bruce Fields }
7076136d2b4SJ. Bruce Fields 
708931ee56cSBenny Halevy static void
709931ee56cSBenny Halevy hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
710931ee56cSBenny Halevy {
711cdc97505SBenny Halevy 	lockdep_assert_held(&state_lock);
712417c6629SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
713931ee56cSBenny Halevy 
71467cb1279STrond Myklebust 	atomic_inc(&dp->dl_stid.sc_count);
7153fb87d13SBenny Halevy 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
716931ee56cSBenny Halevy 	list_add(&dp->dl_perfile, &fp->fi_delegations);
717931ee56cSBenny Halevy 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
718931ee56cSBenny Halevy }
719931ee56cSBenny Halevy 
7201da177e4SLinus Torvalds static void
72142690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp)
7221da177e4SLinus Torvalds {
72311b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
72402e1215fSJeff Layton 
72542690676SJeff Layton 	lockdep_assert_held(&state_lock);
72642690676SJeff Layton 
727b0fc29d6STrond Myklebust 	dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
728d55a166cSJeff Layton 	/* Ensure that deleg break won't try to requeue it */
729d55a166cSJeff Layton 	++dp->dl_time;
730417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
731931ee56cSBenny Halevy 	list_del_init(&dp->dl_perclnt);
7321da177e4SLinus Torvalds 	list_del_init(&dp->dl_recall_lru);
73302e1215fSJeff Layton 	list_del_init(&dp->dl_perfile);
73402e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
735417c6629SJeff Layton 	if (fp)
736f8338834STrond Myklebust 		nfs4_put_deleg_lease(fp);
737cbf7a75bSJ. Bruce Fields }
7383bd64a5bSJ. Bruce Fields 
7393bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp)
7403bd64a5bSJ. Bruce Fields {
74142690676SJeff Layton 	spin_lock(&state_lock);
74242690676SJeff Layton 	unhash_delegation_locked(dp);
74342690676SJeff Layton 	spin_unlock(&state_lock);
7446011695dSTrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
7453bd64a5bSJ. Bruce Fields }
7463bd64a5bSJ. Bruce Fields 
7473bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp)
7483bd64a5bSJ. Bruce Fields {
7493bd64a5bSJ. Bruce Fields 	struct nfs4_client *clp = dp->dl_stid.sc_client;
7503bd64a5bSJ. Bruce Fields 
7512d4a532dSJeff Layton 	WARN_ON(!list_empty(&dp->dl_recall_lru));
7522d4a532dSJeff Layton 
7533bd64a5bSJ. Bruce Fields 	if (clp->cl_minorversion == 0)
7546011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
7553bd64a5bSJ. Bruce Fields 	else {
7563bd64a5bSJ. Bruce Fields 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
7572d4a532dSJeff Layton 		spin_lock(&clp->cl_lock);
7582d4a532dSJeff Layton 		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
7592d4a532dSJeff Layton 		spin_unlock(&clp->cl_lock);
7603bd64a5bSJ. Bruce Fields 	}
7613bd64a5bSJ. Bruce Fields }
7623bd64a5bSJ. Bruce Fields 
7631da177e4SLinus Torvalds /*
7641da177e4SLinus Torvalds  * SETCLIENTID state
7651da177e4SLinus Torvalds  */
7661da177e4SLinus Torvalds 
767ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id)
768ddc04c41SJ. Bruce Fields {
769ddc04c41SJ. Bruce Fields 	return id & CLIENT_HASH_MASK;
770ddc04c41SJ. Bruce Fields }
771ddc04c41SJ. Bruce Fields 
772ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name)
773ddc04c41SJ. Bruce Fields {
774ddc04c41SJ. Bruce Fields 	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
775ddc04c41SJ. Bruce Fields }
776ddc04c41SJ. Bruce Fields 
7771da177e4SLinus Torvalds /*
778f9d7562fSJ. Bruce Fields  * We store the NONE, READ, WRITE, and BOTH bits separately in the
779f9d7562fSJ. Bruce Fields  * st_{access,deny}_bmap field of the stateid, in order to track not
780f9d7562fSJ. Bruce Fields  * only what share bits are currently in force, but also what
781f9d7562fSJ. Bruce Fields  * combinations of share bits previous opens have used.  This allows us
782f9d7562fSJ. Bruce Fields  * to enforce the recommendation of rfc 3530 14.2.19 that the server
783f9d7562fSJ. Bruce Fields  * return an error if the client attempt to downgrade to a combination
784f9d7562fSJ. Bruce Fields  * of share bits not explicable by closing some of its previous opens.
785f9d7562fSJ. Bruce Fields  *
786f9d7562fSJ. Bruce Fields  * XXX: This enforcement is actually incomplete, since we don't keep
787f9d7562fSJ. Bruce Fields  * track of access/deny bit combinations; so, e.g., we allow:
788f9d7562fSJ. Bruce Fields  *
789f9d7562fSJ. Bruce Fields  *	OPEN allow read, deny write
790f9d7562fSJ. Bruce Fields  *	OPEN allow both, deny none
791f9d7562fSJ. Bruce Fields  *	DOWNGRADE allow read, deny none
792f9d7562fSJ. Bruce Fields  *
793f9d7562fSJ. Bruce Fields  * which we should reject.
794f9d7562fSJ. Bruce Fields  */
7955ae037e5SJeff Layton static unsigned int
7965ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) {
797f9d7562fSJ. Bruce Fields 	int i;
7985ae037e5SJeff Layton 	unsigned int access = 0;
799f9d7562fSJ. Bruce Fields 
800f9d7562fSJ. Bruce Fields 	for (i = 1; i < 4; i++) {
801f9d7562fSJ. Bruce Fields 		if (test_bit(i, &bmap))
8025ae037e5SJeff Layton 			access |= i;
803f9d7562fSJ. Bruce Fields 	}
8045ae037e5SJeff Layton 	return access;
805f9d7562fSJ. Bruce Fields }
806f9d7562fSJ. Bruce Fields 
80782c5ff1bSJeff Layton /* set share access for a given stateid */
80882c5ff1bSJeff Layton static inline void
80982c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp)
81082c5ff1bSJeff Layton {
811c11c591fSJeff Layton 	unsigned char mask = 1 << access;
812c11c591fSJeff Layton 
813c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
814c11c591fSJeff Layton 	stp->st_access_bmap |= mask;
81582c5ff1bSJeff Layton }
81682c5ff1bSJeff Layton 
81782c5ff1bSJeff Layton /* clear share access for a given stateid */
81882c5ff1bSJeff Layton static inline void
81982c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp)
82082c5ff1bSJeff Layton {
821c11c591fSJeff Layton 	unsigned char mask = 1 << access;
822c11c591fSJeff Layton 
823c11c591fSJeff Layton 	WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH);
824c11c591fSJeff Layton 	stp->st_access_bmap &= ~mask;
82582c5ff1bSJeff Layton }
82682c5ff1bSJeff Layton 
82782c5ff1bSJeff Layton /* test whether a given stateid has access */
82882c5ff1bSJeff Layton static inline bool
82982c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp)
83082c5ff1bSJeff Layton {
831c11c591fSJeff Layton 	unsigned char mask = 1 << access;
832c11c591fSJeff Layton 
833c11c591fSJeff Layton 	return (bool)(stp->st_access_bmap & mask);
83482c5ff1bSJeff Layton }
83582c5ff1bSJeff Layton 
836ce0fc43cSJeff Layton /* set share deny for a given stateid */
837ce0fc43cSJeff Layton static inline void
838c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp)
839ce0fc43cSJeff Layton {
840c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
841c11c591fSJeff Layton 
842c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
843c11c591fSJeff Layton 	stp->st_deny_bmap |= mask;
844ce0fc43cSJeff Layton }
845ce0fc43cSJeff Layton 
846ce0fc43cSJeff Layton /* clear share deny for a given stateid */
847ce0fc43cSJeff Layton static inline void
848c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp)
849ce0fc43cSJeff Layton {
850c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
851c11c591fSJeff Layton 
852c11c591fSJeff Layton 	WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH);
853c11c591fSJeff Layton 	stp->st_deny_bmap &= ~mask;
854ce0fc43cSJeff Layton }
855ce0fc43cSJeff Layton 
856ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */
857ce0fc43cSJeff Layton static inline bool
858c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp)
859ce0fc43cSJeff Layton {
860c11c591fSJeff Layton 	unsigned char mask = 1 << deny;
861c11c591fSJeff Layton 
862c11c591fSJeff Layton 	return (bool)(stp->st_deny_bmap & mask);
863f9d7562fSJ. Bruce Fields }
864f9d7562fSJ. Bruce Fields 
865f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access)
866f9d7562fSJ. Bruce Fields {
8678f34a430SJ. Bruce Fields 	switch (access & NFS4_SHARE_ACCESS_BOTH) {
868f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
869f9d7562fSJ. Bruce Fields 		return O_RDONLY;
870f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
871f9d7562fSJ. Bruce Fields 		return O_WRONLY;
872f9d7562fSJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
873f9d7562fSJ. Bruce Fields 		return O_RDWR;
874f9d7562fSJ. Bruce Fields 	}
875063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(1);
876063b0fb9SJ. Bruce Fields 	return O_RDONLY;
877f9d7562fSJ. Bruce Fields }
878f9d7562fSJ. Bruce Fields 
879baeb4ff0SJeff Layton /*
880baeb4ff0SJeff Layton  * A stateid that had a deny mode associated with it is being released
881baeb4ff0SJeff Layton  * or downgraded. Recalculate the deny mode on the file.
882baeb4ff0SJeff Layton  */
883baeb4ff0SJeff Layton static void
884baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp)
885baeb4ff0SJeff Layton {
886baeb4ff0SJeff Layton 	struct nfs4_ol_stateid *stp;
887baeb4ff0SJeff Layton 
888baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
889baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
890baeb4ff0SJeff Layton 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile)
891baeb4ff0SJeff Layton 		fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap);
892baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
893baeb4ff0SJeff Layton }
894baeb4ff0SJeff Layton 
895baeb4ff0SJeff Layton static void
896baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp)
897baeb4ff0SJeff Layton {
898baeb4ff0SJeff Layton 	int i;
899baeb4ff0SJeff Layton 	bool change = false;
900baeb4ff0SJeff Layton 
901baeb4ff0SJeff Layton 	for (i = 1; i < 4; i++) {
902baeb4ff0SJeff Layton 		if ((i & deny) != i) {
903baeb4ff0SJeff Layton 			change = true;
904baeb4ff0SJeff Layton 			clear_deny(i, stp);
905baeb4ff0SJeff Layton 		}
906baeb4ff0SJeff Layton 	}
907baeb4ff0SJeff Layton 
908baeb4ff0SJeff Layton 	/* Recalculate per-file deny mode if there was a change */
909baeb4ff0SJeff Layton 	if (change)
91011b9164aSTrond Myklebust 		recalculate_deny_mode(stp->st_stid.sc_file);
911baeb4ff0SJeff Layton }
912baeb4ff0SJeff Layton 
91382c5ff1bSJeff Layton /* release all access and file references for a given stateid */
91482c5ff1bSJeff Layton static void
91582c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp)
91682c5ff1bSJeff Layton {
91782c5ff1bSJeff Layton 	int i;
91811b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
919baeb4ff0SJeff Layton 
920baeb4ff0SJeff Layton 	if (fp && stp->st_deny_bmap != 0)
921baeb4ff0SJeff Layton 		recalculate_deny_mode(fp);
92282c5ff1bSJeff Layton 
92382c5ff1bSJeff Layton 	for (i = 1; i < 4; i++) {
92482c5ff1bSJeff Layton 		if (test_access(i, stp))
92511b9164aSTrond Myklebust 			nfs4_file_put_access(stp->st_stid.sc_file, i);
92682c5ff1bSJeff Layton 		clear_access(i, stp);
92782c5ff1bSJeff Layton 	}
92882c5ff1bSJeff Layton }
92982c5ff1bSJeff Layton 
9306b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
9316b180f0bSJeff Layton {
932a819ecc1SJeff Layton 	struct nfs4_client *clp = sop->so_client;
933a819ecc1SJeff Layton 
934a819ecc1SJeff Layton 	might_lock(&clp->cl_lock);
935a819ecc1SJeff Layton 
936a819ecc1SJeff Layton 	if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock))
9376b180f0bSJeff Layton 		return;
9388f4b54c5SJeff Layton 	sop->so_ops->so_unhash(sop);
939a819ecc1SJeff Layton 	spin_unlock(&clp->cl_lock);
9406b180f0bSJeff Layton 	kfree(sop->so_owner.data);
9416b180f0bSJeff Layton 	sop->so_ops->so_free(sop);
9426b180f0bSJeff Layton }
9436b180f0bSJeff Layton 
9444ae098d3SJeff Layton static void unhash_ol_stateid(struct nfs4_ol_stateid *stp)
945529d7b2aSJ. Bruce Fields {
94611b9164aSTrond Myklebust 	struct nfs4_file *fp = stp->st_stid.sc_file;
9471d31a253STrond Myklebust 
9481c755dc1SJeff Layton 	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
9491c755dc1SJeff Layton 
9501d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
951529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perfile);
9521d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
953529d7b2aSJ. Bruce Fields 	list_del(&stp->st_perstateowner);
954529d7b2aSJ. Bruce Fields }
955529d7b2aSJ. Bruce Fields 
9566011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
957529d7b2aSJ. Bruce Fields {
9586011695dSTrond Myklebust 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
9594665e2baSJ. Bruce Fields 
9606011695dSTrond Myklebust 	release_all_access(stp);
961d3134b10SJeff Layton 	if (stp->st_stateowner)
962d3134b10SJeff Layton 		nfs4_put_stateowner(stp->st_stateowner);
9636011695dSTrond Myklebust 	kmem_cache_free(stateid_slab, stid);
964529d7b2aSJ. Bruce Fields }
965529d7b2aSJ. Bruce Fields 
966b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid)
967529d7b2aSJ. Bruce Fields {
968b49e084dSJeff Layton 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
969b49e084dSJeff Layton 	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
970529d7b2aSJ. Bruce Fields 	struct file *file;
971529d7b2aSJ. Bruce Fields 
972b49e084dSJeff Layton 	file = find_any_file(stp->st_stid.sc_file);
973b49e084dSJeff Layton 	if (file)
974b49e084dSJeff Layton 		filp_close(file, (fl_owner_t)lo);
975b49e084dSJeff Layton 	nfs4_free_ol_stateid(stid);
976b49e084dSJeff Layton }
977b49e084dSJeff Layton 
9782c41beb0SJeff Layton /*
9792c41beb0SJeff Layton  * Put the persistent reference to an already unhashed generic stateid, while
9802c41beb0SJeff Layton  * holding the cl_lock. If it's the last reference, then put it onto the
9812c41beb0SJeff Layton  * reaplist for later destruction.
9822c41beb0SJeff Layton  */
9832c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
9842c41beb0SJeff Layton 				       struct list_head *reaplist)
9852c41beb0SJeff Layton {
9862c41beb0SJeff Layton 	struct nfs4_stid *s = &stp->st_stid;
9872c41beb0SJeff Layton 	struct nfs4_client *clp = s->sc_client;
9882c41beb0SJeff Layton 
9892c41beb0SJeff Layton 	lockdep_assert_held(&clp->cl_lock);
9902c41beb0SJeff Layton 
9912c41beb0SJeff Layton 	WARN_ON_ONCE(!list_empty(&stp->st_locks));
9922c41beb0SJeff Layton 
9932c41beb0SJeff Layton 	if (!atomic_dec_and_test(&s->sc_count)) {
9942c41beb0SJeff Layton 		wake_up_all(&close_wq);
9952c41beb0SJeff Layton 		return;
9962c41beb0SJeff Layton 	}
9972c41beb0SJeff Layton 
9982c41beb0SJeff Layton 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
9992c41beb0SJeff Layton 	list_add(&stp->st_locks, reaplist);
10002c41beb0SJeff Layton }
10012c41beb0SJeff Layton 
10023c1c995cSJeff Layton static void unhash_lock_stateid(struct nfs4_ol_stateid *stp)
10033c1c995cSJeff Layton {
10043c1c995cSJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
10053c1c995cSJeff Layton 
10063c1c995cSJeff Layton 	lockdep_assert_held(&oo->oo_owner.so_client->cl_lock);
10073c1c995cSJeff Layton 
10083c1c995cSJeff Layton 	list_del_init(&stp->st_locks);
10094ae098d3SJeff Layton 	unhash_ol_stateid(stp);
10103c1c995cSJeff Layton 	unhash_stid(&stp->st_stid);
10113c1c995cSJeff Layton }
10123c1c995cSJeff Layton 
10135adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp)
1014b49e084dSJeff Layton {
10151c755dc1SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
10161c755dc1SJeff Layton 
10171c755dc1SJeff Layton 	spin_lock(&oo->oo_owner.so_client->cl_lock);
10183c1c995cSJeff Layton 	unhash_lock_stateid(stp);
10191c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
10206011695dSTrond Myklebust 	nfs4_put_stid(&stp->st_stid);
1021529d7b2aSJ. Bruce Fields }
1022529d7b2aSJ. Bruce Fields 
1023c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
1024529d7b2aSJ. Bruce Fields {
1025d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
1026c58c6610STrond Myklebust 
1027d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
1028c58c6610STrond Myklebust 
10298f4b54c5SJeff Layton 	list_del_init(&lo->lo_owner.so_strhash);
10308f4b54c5SJeff Layton }
10318f4b54c5SJeff Layton 
10322c41beb0SJeff Layton /*
10332c41beb0SJeff Layton  * Free a list of generic stateids that were collected earlier after being
10342c41beb0SJeff Layton  * fully unhashed.
10352c41beb0SJeff Layton  */
10362c41beb0SJeff Layton static void
10372c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist)
10382c41beb0SJeff Layton {
10392c41beb0SJeff Layton 	struct nfs4_ol_stateid *stp;
1040fb94d766SKinglong Mee 	struct nfs4_file *fp;
10412c41beb0SJeff Layton 
10422c41beb0SJeff Layton 	might_sleep();
10432c41beb0SJeff Layton 
10442c41beb0SJeff Layton 	while (!list_empty(reaplist)) {
10452c41beb0SJeff Layton 		stp = list_first_entry(reaplist, struct nfs4_ol_stateid,
10462c41beb0SJeff Layton 				       st_locks);
10472c41beb0SJeff Layton 		list_del(&stp->st_locks);
1048fb94d766SKinglong Mee 		fp = stp->st_stid.sc_file;
10492c41beb0SJeff Layton 		stp->st_stid.sc_free(&stp->st_stid);
1050fb94d766SKinglong Mee 		if (fp)
1051fb94d766SKinglong Mee 			put_nfs4_file(fp);
10522c41beb0SJeff Layton 	}
10532c41beb0SJeff Layton }
10542c41beb0SJeff Layton 
1055fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo)
1056529d7b2aSJ. Bruce Fields {
1057d4f0489fSTrond Myklebust 	struct nfs4_client *clp = lo->lo_owner.so_client;
10583c1c995cSJeff Layton 	struct nfs4_ol_stateid *stp;
10593c1c995cSJeff Layton 	struct list_head reaplist;
10603c1c995cSJeff Layton 
10613c1c995cSJeff Layton 	INIT_LIST_HEAD(&reaplist);
1062c58c6610STrond Myklebust 
1063d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
1064c58c6610STrond Myklebust 	unhash_lockowner_locked(lo);
10653c1c995cSJeff Layton 	while (!list_empty(&lo->lo_owner.so_stateids)) {
10663c1c995cSJeff Layton 		stp = list_first_entry(&lo->lo_owner.so_stateids,
10673c1c995cSJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
10683c1c995cSJeff Layton 		unhash_lock_stateid(stp);
10692c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
10703c1c995cSJeff Layton 	}
1071d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
10722c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
10736b180f0bSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
1074529d7b2aSJ. Bruce Fields }
1075529d7b2aSJ. Bruce Fields 
1076d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
1077d83017f9SJeff Layton 				       struct list_head *reaplist)
10783c87b9b7STrond Myklebust {
10793c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *stp;
10803c87b9b7STrond Myklebust 
10813c87b9b7STrond Myklebust 	while (!list_empty(&open_stp->st_locks)) {
10823c87b9b7STrond Myklebust 		stp = list_entry(open_stp->st_locks.next,
10833c87b9b7STrond Myklebust 				struct nfs4_ol_stateid, st_locks);
1084d83017f9SJeff Layton 		unhash_lock_stateid(stp);
1085d83017f9SJeff Layton 		put_ol_stateid_locked(stp, reaplist);
1086529d7b2aSJ. Bruce Fields 	}
1087529d7b2aSJ. Bruce Fields }
1088529d7b2aSJ. Bruce Fields 
1089d83017f9SJeff Layton static void unhash_open_stateid(struct nfs4_ol_stateid *stp,
1090d83017f9SJeff Layton 				struct list_head *reaplist)
10912283963fSJ. Bruce Fields {
10922c41beb0SJeff Layton 	lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
10932c41beb0SJeff Layton 
10944ae098d3SJeff Layton 	unhash_ol_stateid(stp);
1095d83017f9SJeff Layton 	release_open_stateid_locks(stp, reaplist);
109638c387b5SJ. Bruce Fields }
109738c387b5SJ. Bruce Fields 
109838c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp)
109938c387b5SJ. Bruce Fields {
11002c41beb0SJeff Layton 	LIST_HEAD(reaplist);
11012c41beb0SJeff Layton 
11022c41beb0SJeff Layton 	spin_lock(&stp->st_stid.sc_client->cl_lock);
1103d83017f9SJeff Layton 	unhash_open_stateid(stp, &reaplist);
11042c41beb0SJeff Layton 	put_ol_stateid_locked(stp, &reaplist);
11052c41beb0SJeff Layton 	spin_unlock(&stp->st_stid.sc_client->cl_lock);
11062c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
11072283963fSJ. Bruce Fields }
11082283963fSJ. Bruce Fields 
11097ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo)
1110f1d110caSJ. Bruce Fields {
1111d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
11127ffb5880STrond Myklebust 
1113d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
11147ffb5880STrond Myklebust 
11158f4b54c5SJeff Layton 	list_del_init(&oo->oo_owner.so_strhash);
11168f4b54c5SJeff Layton 	list_del_init(&oo->oo_perclient);
1117f1d110caSJ. Bruce Fields }
1118f1d110caSJ. Bruce Fields 
1119f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo)
1120f7a4d872SJ. Bruce Fields {
1121217526e7SJeff Layton 	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
1122217526e7SJeff Layton 					  nfsd_net_id);
1123217526e7SJeff Layton 	struct nfs4_ol_stateid *s;
1124f7a4d872SJ. Bruce Fields 
1125217526e7SJeff Layton 	spin_lock(&nn->client_lock);
1126217526e7SJeff Layton 	s = oo->oo_last_closed_stid;
1127f7a4d872SJ. Bruce Fields 	if (s) {
1128d3134b10SJeff Layton 		list_del_init(&oo->oo_close_lru);
1129f7a4d872SJ. Bruce Fields 		oo->oo_last_closed_stid = NULL;
1130f7a4d872SJ. Bruce Fields 	}
1131217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
1132217526e7SJeff Layton 	if (s)
1133217526e7SJeff Layton 		nfs4_put_stid(&s->st_stid);
1134f7a4d872SJ. Bruce Fields }
1135f7a4d872SJ. Bruce Fields 
11362c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo)
11378f4b54c5SJeff Layton {
11388f4b54c5SJeff Layton 	struct nfs4_ol_stateid *stp;
1139d4f0489fSTrond Myklebust 	struct nfs4_client *clp = oo->oo_owner.so_client;
11402c41beb0SJeff Layton 	struct list_head reaplist;
11417ffb5880STrond Myklebust 
11422c41beb0SJeff Layton 	INIT_LIST_HEAD(&reaplist);
11437ffb5880STrond Myklebust 
1144d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
11457ffb5880STrond Myklebust 	unhash_openowner_locked(oo);
11462c41beb0SJeff Layton 	while (!list_empty(&oo->oo_owner.so_stateids)) {
11472c41beb0SJeff Layton 		stp = list_first_entry(&oo->oo_owner.so_stateids,
11482c41beb0SJeff Layton 				struct nfs4_ol_stateid, st_perstateowner);
1149d83017f9SJeff Layton 		unhash_open_stateid(stp, &reaplist);
11502c41beb0SJeff Layton 		put_ol_stateid_locked(stp, &reaplist);
11512c41beb0SJeff Layton 	}
1152d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
11532c41beb0SJeff Layton 	free_ol_stateid_reaplist(&reaplist);
1154f7a4d872SJ. Bruce Fields 	release_last_closed_stateid(oo);
11556b180f0bSJeff Layton 	nfs4_put_stateowner(&oo->oo_owner);
1156f1d110caSJ. Bruce Fields }
1157f1d110caSJ. Bruce Fields 
11585282fd72SMarc Eshel static inline int
11595282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid)
11605282fd72SMarc Eshel {
11615282fd72SMarc Eshel 	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
11625282fd72SMarc Eshel 
11635282fd72SMarc Eshel 	return sid->sequence % SESSION_HASH_SIZE;
11645282fd72SMarc Eshel }
11655282fd72SMarc Eshel 
11668f199b82STrond Myklebust #ifdef NFSD_DEBUG
11675282fd72SMarc Eshel static inline void
11685282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
11695282fd72SMarc Eshel {
11705282fd72SMarc Eshel 	u32 *ptr = (u32 *)(&sessionid->data[0]);
11715282fd72SMarc Eshel 	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
11725282fd72SMarc Eshel }
11738f199b82STrond Myklebust #else
11748f199b82STrond Myklebust static inline void
11758f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
11768f199b82STrond Myklebust {
11778f199b82STrond Myklebust }
11788f199b82STrond Myklebust #endif
11798f199b82STrond Myklebust 
11809411b1d4SJ. Bruce Fields /*
11819411b1d4SJ. Bruce Fields  * Bump the seqid on cstate->replay_owner, and clear replay_owner if it
11829411b1d4SJ. Bruce Fields  * won't be used for replay.
11839411b1d4SJ. Bruce Fields  */
11849411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
11859411b1d4SJ. Bruce Fields {
11869411b1d4SJ. Bruce Fields 	struct nfs4_stateowner *so = cstate->replay_owner;
11879411b1d4SJ. Bruce Fields 
11889411b1d4SJ. Bruce Fields 	if (nfserr == nfserr_replay_me)
11899411b1d4SJ. Bruce Fields 		return;
11909411b1d4SJ. Bruce Fields 
11919411b1d4SJ. Bruce Fields 	if (!seqid_mutating_err(ntohl(nfserr))) {
119258fb12e6SJeff Layton 		nfsd4_cstate_clear_replay(cstate);
11939411b1d4SJ. Bruce Fields 		return;
11949411b1d4SJ. Bruce Fields 	}
11959411b1d4SJ. Bruce Fields 	if (!so)
11969411b1d4SJ. Bruce Fields 		return;
11979411b1d4SJ. Bruce Fields 	if (so->so_is_open_owner)
11989411b1d4SJ. Bruce Fields 		release_last_closed_stateid(openowner(so));
11999411b1d4SJ. Bruce Fields 	so->so_seqid++;
12009411b1d4SJ. Bruce Fields 	return;
12019411b1d4SJ. Bruce Fields }
12025282fd72SMarc Eshel 
1203ec6b5d7bSAndy Adamson static void
1204ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses)
1205ec6b5d7bSAndy Adamson {
1206ec6b5d7bSAndy Adamson 	struct nfs4_client *clp = ses->se_client;
1207ec6b5d7bSAndy Adamson 	struct nfsd4_sessionid *sid;
1208ec6b5d7bSAndy Adamson 
1209ec6b5d7bSAndy Adamson 	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
1210ec6b5d7bSAndy Adamson 	sid->clientid = clp->cl_clientid;
1211ec6b5d7bSAndy Adamson 	sid->sequence = current_sessionid++;
1212ec6b5d7bSAndy Adamson 	sid->reserved = 0;
1213ec6b5d7bSAndy Adamson }
1214ec6b5d7bSAndy Adamson 
1215ec6b5d7bSAndy Adamson /*
1216a649637cSAndy Adamson  * The protocol defines ca_maxresponssize_cached to include the size of
1217a649637cSAndy Adamson  * the rpc header, but all we need to cache is the data starting after
1218a649637cSAndy Adamson  * the end of the initial SEQUENCE operation--the rest we regenerate
1219a649637cSAndy Adamson  * each time.  Therefore we can advertise a ca_maxresponssize_cached
1220a649637cSAndy Adamson  * value that is the number of bytes in our cache plus a few additional
1221a649637cSAndy Adamson  * bytes.  In order to stay on the safe side, and not promise more than
1222a649637cSAndy Adamson  * we can cache, those additional bytes must be the minimum possible: 24
1223a649637cSAndy Adamson  * bytes of rpc header (xid through accept state, with AUTH_NULL
1224a649637cSAndy Adamson  * verifier), 12 for the compound header (with zero-length tag), and 44
1225a649637cSAndy Adamson  * for the SEQUENCE op response:
1226ec6b5d7bSAndy Adamson  */
1227a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)
1228a649637cSAndy Adamson 
1229557ce264SAndy Adamson static void
1230557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses)
1231557ce264SAndy Adamson {
1232557ce264SAndy Adamson 	int i;
1233557ce264SAndy Adamson 
1234557ce264SAndy Adamson 	for (i = 0; i < ses->se_fchannel.maxreqs; i++)
1235557ce264SAndy Adamson 		kfree(ses->se_slots[i]);
1236557ce264SAndy Adamson }
1237557ce264SAndy Adamson 
1238efe0cb6dSJ. Bruce Fields /*
1239efe0cb6dSJ. Bruce Fields  * We don't actually need to cache the rpc and session headers, so we
1240efe0cb6dSJ. Bruce Fields  * can allocate a little less for each slot:
1241efe0cb6dSJ. Bruce Fields  */
124255c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca)
1243efe0cb6dSJ. Bruce Fields {
124455c760cfSJ. Bruce Fields 	u32 size;
1245efe0cb6dSJ. Bruce Fields 
124655c760cfSJ. Bruce Fields 	if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ)
124755c760cfSJ. Bruce Fields 		size = 0;
124855c760cfSJ. Bruce Fields 	else
124955c760cfSJ. Bruce Fields 		size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
125055c760cfSJ. Bruce Fields 	return size + sizeof(struct nfsd4_slot);
1251557ce264SAndy Adamson }
1252557ce264SAndy Adamson 
12535b6feee9SJ. Bruce Fields /*
12545b6feee9SJ. Bruce Fields  * XXX: If we run out of reserved DRC memory we could (up to a point)
12555b6feee9SJ. Bruce Fields  * re-negotiate active sessions and reduce their slot usage to make
125642b2aa86SJustin P. Mattock  * room for new connections. For now we just fail the create session.
12575b6feee9SJ. Bruce Fields  */
125855c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
12595b6feee9SJ. Bruce Fields {
126055c760cfSJ. Bruce Fields 	u32 slotsize = slot_bytes(ca);
126155c760cfSJ. Bruce Fields 	u32 num = ca->maxreqs;
12625b6feee9SJ. Bruce Fields 	int avail;
12635b6feee9SJ. Bruce Fields 
12645b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
1265697ce9beSZhang Yanfei 	avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
12665b6feee9SJ. Bruce Fields 		    nfsd_drc_max_mem - nfsd_drc_mem_used);
12675b6feee9SJ. Bruce Fields 	num = min_t(int, num, avail / slotsize);
12685b6feee9SJ. Bruce Fields 	nfsd_drc_mem_used += num * slotsize;
12695b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
12705b6feee9SJ. Bruce Fields 
12715b6feee9SJ. Bruce Fields 	return num;
12725b6feee9SJ. Bruce Fields }
12735b6feee9SJ. Bruce Fields 
127455c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
12755b6feee9SJ. Bruce Fields {
127655c760cfSJ. Bruce Fields 	int slotsize = slot_bytes(ca);
127755c760cfSJ. Bruce Fields 
12785b6feee9SJ. Bruce Fields 	spin_lock(&nfsd_drc_lock);
127955c760cfSJ. Bruce Fields 	nfsd_drc_mem_used -= slotsize * ca->maxreqs;
12805b6feee9SJ. Bruce Fields 	spin_unlock(&nfsd_drc_lock);
12815b6feee9SJ. Bruce Fields }
12825b6feee9SJ. Bruce Fields 
128360810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
128460810e54SKinglong Mee 					   struct nfsd4_channel_attrs *battrs)
12855b6feee9SJ. Bruce Fields {
128660810e54SKinglong Mee 	int numslots = fattrs->maxreqs;
128760810e54SKinglong Mee 	int slotsize = slot_bytes(fattrs);
12885b6feee9SJ. Bruce Fields 	struct nfsd4_session *new;
12895b6feee9SJ. Bruce Fields 	int mem, i;
1290ec6b5d7bSAndy Adamson 
1291c23753daSJ. Bruce Fields 	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
1292ec6b5d7bSAndy Adamson 			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
12935b6feee9SJ. Bruce Fields 	mem = numslots * sizeof(struct nfsd4_slot *);
1294ec6b5d7bSAndy Adamson 
12955b6feee9SJ. Bruce Fields 	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
12966c18ba9fSAlexandros Batsakis 	if (!new)
12975b6feee9SJ. Bruce Fields 		return NULL;
1298ec6b5d7bSAndy Adamson 	/* allocate each struct nfsd4_slot and data cache in one piece */
12995b6feee9SJ. Bruce Fields 	for (i = 0; i < numslots; i++) {
130055c760cfSJ. Bruce Fields 		new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL);
13015b6feee9SJ. Bruce Fields 		if (!new->se_slots[i])
1302ec6b5d7bSAndy Adamson 			goto out_free;
1303ec6b5d7bSAndy Adamson 	}
130460810e54SKinglong Mee 
130560810e54SKinglong Mee 	memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
130660810e54SKinglong Mee 	memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
130760810e54SKinglong Mee 
13085b6feee9SJ. Bruce Fields 	return new;
13095b6feee9SJ. Bruce Fields out_free:
13105b6feee9SJ. Bruce Fields 	while (i--)
13115b6feee9SJ. Bruce Fields 		kfree(new->se_slots[i]);
13125b6feee9SJ. Bruce Fields 	kfree(new);
13135b6feee9SJ. Bruce Fields 	return NULL;
13145b6feee9SJ. Bruce Fields }
13155b6feee9SJ. Bruce Fields 
131619cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c)
131719cf5c02SJ. Bruce Fields {
131819cf5c02SJ. Bruce Fields 	svc_xprt_put(c->cn_xprt);
131919cf5c02SJ. Bruce Fields 	kfree(c);
132019cf5c02SJ. Bruce Fields }
132119cf5c02SJ. Bruce Fields 
132219cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u)
132319cf5c02SJ. Bruce Fields {
132419cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
132519cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = c->cn_session->se_client;
132619cf5c02SJ. Bruce Fields 
132719cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
132819cf5c02SJ. Bruce Fields 	if (!list_empty(&c->cn_persession)) {
132919cf5c02SJ. Bruce Fields 		list_del(&c->cn_persession);
133019cf5c02SJ. Bruce Fields 		free_conn(c);
133119cf5c02SJ. Bruce Fields 	}
1332eea49806SJ. Bruce Fields 	nfsd4_probe_callback(clp);
13332e4b7239SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
133419cf5c02SJ. Bruce Fields }
133519cf5c02SJ. Bruce Fields 
1336d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
1337c7662518SJ. Bruce Fields {
1338c7662518SJ. Bruce Fields 	struct nfsd4_conn *conn;
1339c7662518SJ. Bruce Fields 
1340c7662518SJ. Bruce Fields 	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
1341c7662518SJ. Bruce Fields 	if (!conn)
1342db90681dSJ. Bruce Fields 		return NULL;
1343c7662518SJ. Bruce Fields 	svc_xprt_get(rqstp->rq_xprt);
1344c7662518SJ. Bruce Fields 	conn->cn_xprt = rqstp->rq_xprt;
1345d29c374cSJ. Bruce Fields 	conn->cn_flags = flags;
1346db90681dSJ. Bruce Fields 	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
1347db90681dSJ. Bruce Fields 	return conn;
1348db90681dSJ. Bruce Fields }
1349db90681dSJ. Bruce Fields 
1350328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1351328ead28SJ. Bruce Fields {
1352328ead28SJ. Bruce Fields 	conn->cn_session = ses;
1353328ead28SJ. Bruce Fields 	list_add(&conn->cn_persession, &ses->se_conns);
1354328ead28SJ. Bruce Fields }
1355328ead28SJ. Bruce Fields 
1356db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
1357db90681dSJ. Bruce Fields {
1358db90681dSJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
1359c7662518SJ. Bruce Fields 
1360c7662518SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1361328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(conn, ses);
1362c7662518SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1363db90681dSJ. Bruce Fields }
1364c7662518SJ. Bruce Fields 
136521b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn)
1366db90681dSJ. Bruce Fields {
136719cf5c02SJ. Bruce Fields 	conn->cn_xpt_user.callback = nfsd4_conn_lost;
136821b75b01SJ. Bruce Fields 	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
1369db90681dSJ. Bruce Fields }
1370db90681dSJ. Bruce Fields 
1371e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
1372db90681dSJ. Bruce Fields {
137321b75b01SJ. Bruce Fields 	int ret;
1374db90681dSJ. Bruce Fields 
1375db90681dSJ. Bruce Fields 	nfsd4_hash_conn(conn, ses);
137621b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(conn);
137721b75b01SJ. Bruce Fields 	if (ret)
137821b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
137921b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&conn->cn_xpt_user);
138057a37144SJ. Bruce Fields 	/* We may have gained or lost a callback channel: */
138157a37144SJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
1382c7662518SJ. Bruce Fields }
1383c7662518SJ. Bruce Fields 
1384e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
13851d1bc8f2SJ. Bruce Fields {
13861d1bc8f2SJ. Bruce Fields 	u32 dir = NFS4_CDFC4_FORE;
13871d1bc8f2SJ. Bruce Fields 
1388e1ff371fSJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN)
13891d1bc8f2SJ. Bruce Fields 		dir |= NFS4_CDFC4_BACK;
1390e1ff371fSJ. Bruce Fields 	return alloc_conn(rqstp, dir);
13911d1bc8f2SJ. Bruce Fields }
13921d1bc8f2SJ. Bruce Fields 
13931d1bc8f2SJ. Bruce Fields /* must be called under client_lock */
139419cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s)
1395c7662518SJ. Bruce Fields {
139619cf5c02SJ. Bruce Fields 	struct nfs4_client *clp = s->se_client;
139719cf5c02SJ. Bruce Fields 	struct nfsd4_conn *c;
139819cf5c02SJ. Bruce Fields 
139919cf5c02SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
140019cf5c02SJ. Bruce Fields 	while (!list_empty(&s->se_conns)) {
140119cf5c02SJ. Bruce Fields 		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
140219cf5c02SJ. Bruce Fields 		list_del_init(&c->cn_persession);
140319cf5c02SJ. Bruce Fields 		spin_unlock(&clp->cl_lock);
140419cf5c02SJ. Bruce Fields 
140519cf5c02SJ. Bruce Fields 		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
140619cf5c02SJ. Bruce Fields 		free_conn(c);
140719cf5c02SJ. Bruce Fields 
140819cf5c02SJ. Bruce Fields 		spin_lock(&clp->cl_lock);
140919cf5c02SJ. Bruce Fields 	}
141019cf5c02SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
1411c7662518SJ. Bruce Fields }
1412c7662518SJ. Bruce Fields 
14131377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses)
14141377b69eSJ. Bruce Fields {
14151377b69eSJ. Bruce Fields 	free_session_slots(ses);
14161377b69eSJ. Bruce Fields 	kfree(ses);
14171377b69eSJ. Bruce Fields }
14181377b69eSJ. Bruce Fields 
141966b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses)
1420508dc6e1SBenny Halevy {
1421c7662518SJ. Bruce Fields 	nfsd4_del_conns(ses);
142255c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&ses->se_fchannel);
1423c7662518SJ. Bruce Fields 	__free_session(ses);
1424a827bcb2SJ. Bruce Fields }
1425ec6b5d7bSAndy Adamson 
1426135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
1427a827bcb2SJ. Bruce Fields {
1428a827bcb2SJ. Bruce Fields 	int idx;
14291872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1430a827bcb2SJ. Bruce Fields 
1431ec6b5d7bSAndy Adamson 	new->se_client = clp;
1432ec6b5d7bSAndy Adamson 	gen_sessionid(new);
1433ec6b5d7bSAndy Adamson 
1434c7662518SJ. Bruce Fields 	INIT_LIST_HEAD(&new->se_conns);
1435c7662518SJ. Bruce Fields 
1436ac7c46f2SJ. Bruce Fields 	new->se_cb_seq_nr = 1;
1437ec6b5d7bSAndy Adamson 	new->se_flags = cses->flags;
14388b5ce5cdSJ. Bruce Fields 	new->se_cb_prog = cses->callback_prog;
1439c6bb3ca2SJ. Bruce Fields 	new->se_cb_sec = cses->cb_sec;
144066b2b9b2SJ. Bruce Fields 	atomic_set(&new->se_ref, 0);
14415b6feee9SJ. Bruce Fields 	idx = hash_sessionid(&new->se_sessionid);
14421872de0eSStanislav Kinsbursky 	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
14434c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1444ec6b5d7bSAndy Adamson 	list_add(&new->se_perclnt, &clp->cl_sessions);
14454c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
144660810e54SKinglong Mee 
1447dcbeaa68SJ. Bruce Fields 	if (cses->flags & SESSION4_BACK_CHAN) {
1448edd76786SJ. Bruce Fields 		struct sockaddr *sa = svc_addr(rqstp);
1449dcbeaa68SJ. Bruce Fields 		/*
1450dcbeaa68SJ. Bruce Fields 		 * This is a little silly; with sessions there's no real
1451dcbeaa68SJ. Bruce Fields 		 * use for the callback address.  Use the peer address
1452dcbeaa68SJ. Bruce Fields 		 * as a reasonable default for now, but consider fixing
1453dcbeaa68SJ. Bruce Fields 		 * the rpc client not to require an address in the
1454dcbeaa68SJ. Bruce Fields 		 * future:
1455dcbeaa68SJ. Bruce Fields 		 */
1456edd76786SJ. Bruce Fields 		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
1457edd76786SJ. Bruce Fields 		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
1458edd76786SJ. Bruce Fields 	}
1459ec6b5d7bSAndy Adamson }
1460ec6b5d7bSAndy Adamson 
14619089f1b4SBenny Halevy /* caller must hold client_lock */
14625282fd72SMarc Eshel static struct nfsd4_session *
1463d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
14645282fd72SMarc Eshel {
14655282fd72SMarc Eshel 	struct nfsd4_session *elem;
14665282fd72SMarc Eshel 	int idx;
14671872de0eSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
14685282fd72SMarc Eshel 
14690a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
14700a880a28STrond Myklebust 
14715282fd72SMarc Eshel 	dump_sessionid(__func__, sessionid);
14725282fd72SMarc Eshel 	idx = hash_sessionid(sessionid);
14735282fd72SMarc Eshel 	/* Search in the appropriate list */
14741872de0eSStanislav Kinsbursky 	list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) {
14755282fd72SMarc Eshel 		if (!memcmp(elem->se_sessionid.data, sessionid->data,
14765282fd72SMarc Eshel 			    NFS4_MAX_SESSIONID_LEN)) {
14775282fd72SMarc Eshel 			return elem;
14785282fd72SMarc Eshel 		}
14795282fd72SMarc Eshel 	}
14805282fd72SMarc Eshel 
14815282fd72SMarc Eshel 	dprintk("%s: session not found\n", __func__);
14825282fd72SMarc Eshel 	return NULL;
14835282fd72SMarc Eshel }
14845282fd72SMarc Eshel 
1485d4e19e70STrond Myklebust static struct nfsd4_session *
1486d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net,
1487d4e19e70STrond Myklebust 		__be32 *ret)
1488d4e19e70STrond Myklebust {
1489d4e19e70STrond Myklebust 	struct nfsd4_session *session;
1490d4e19e70STrond Myklebust 	__be32 status = nfserr_badsession;
1491d4e19e70STrond Myklebust 
1492d4e19e70STrond Myklebust 	session = __find_in_sessionid_hashtbl(sessionid, net);
1493d4e19e70STrond Myklebust 	if (!session)
1494d4e19e70STrond Myklebust 		goto out;
1495d4e19e70STrond Myklebust 	status = nfsd4_get_session_locked(session);
1496d4e19e70STrond Myklebust 	if (status)
1497d4e19e70STrond Myklebust 		session = NULL;
1498d4e19e70STrond Myklebust out:
1499d4e19e70STrond Myklebust 	*ret = status;
1500d4e19e70STrond Myklebust 	return session;
1501d4e19e70STrond Myklebust }
1502d4e19e70STrond Myklebust 
15039089f1b4SBenny Halevy /* caller must hold client_lock */
15047116ed6bSAndy Adamson static void
15055282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses)
15067116ed6bSAndy Adamson {
15070a880a28STrond Myklebust 	struct nfs4_client *clp = ses->se_client;
15080a880a28STrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
15090a880a28STrond Myklebust 
15100a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
15110a880a28STrond Myklebust 
15127116ed6bSAndy Adamson 	list_del(&ses->se_hash);
15134c649378SJ. Bruce Fields 	spin_lock(&ses->se_client->cl_lock);
15147116ed6bSAndy Adamson 	list_del(&ses->se_perclnt);
15154c649378SJ. Bruce Fields 	spin_unlock(&ses->se_client->cl_lock);
15165282fd72SMarc Eshel }
15175282fd72SMarc Eshel 
15181da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
15191da177e4SLinus Torvalds static int
15202c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
15211da177e4SLinus Torvalds {
15222c142baaSStanislav Kinsbursky 	if (clid->cl_boot == nn->boot_time)
15231da177e4SLinus Torvalds 		return 0;
152460adfc50SAndy Adamson 	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
15252c142baaSStanislav Kinsbursky 		clid->cl_boot, clid->cl_id, nn->boot_time);
15261da177e4SLinus Torvalds 	return 1;
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds 
15291da177e4SLinus Torvalds /*
15301da177e4SLinus Torvalds  * XXX Should we use a slab cache ?
15311da177e4SLinus Torvalds  * This type of memory management is somewhat inefficient, but we use it
15321da177e4SLinus Torvalds  * anyway since SETCLIENTID is not a common operation.
15331da177e4SLinus Torvalds  */
153435bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name)
15351da177e4SLinus Torvalds {
15361da177e4SLinus Torvalds 	struct nfs4_client *clp;
1537d4f0489fSTrond Myklebust 	int i;
15381da177e4SLinus Torvalds 
153935bba9a3SJ. Bruce Fields 	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
154035bba9a3SJ. Bruce Fields 	if (clp == NULL)
154135bba9a3SJ. Bruce Fields 		return NULL;
154267114fe6SThomas Meyer 	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
1543d4f0489fSTrond Myklebust 	if (clp->cl_name.data == NULL)
1544d4f0489fSTrond Myklebust 		goto err_no_name;
1545d4f0489fSTrond Myklebust 	clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
1546d4f0489fSTrond Myklebust 			OWNER_HASH_SIZE, GFP_KERNEL);
1547d4f0489fSTrond Myklebust 	if (!clp->cl_ownerstr_hashtbl)
1548d4f0489fSTrond Myklebust 		goto err_no_hashtbl;
1549d4f0489fSTrond Myklebust 	for (i = 0; i < OWNER_HASH_SIZE; i++)
1550d4f0489fSTrond Myklebust 		INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]);
15511da177e4SLinus Torvalds 	clp->cl_name.len = name.len;
15525694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_sessions);
15535694c93eSTrond Myklebust 	idr_init(&clp->cl_stateids);
15545694c93eSTrond Myklebust 	atomic_set(&clp->cl_refcount, 0);
15555694c93eSTrond Myklebust 	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
15565694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_idhash);
15575694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_openowners);
15585694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_delegations);
15595694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_lru);
15605694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_callbacks);
15615694c93eSTrond Myklebust 	INIT_LIST_HEAD(&clp->cl_revoked);
15625694c93eSTrond Myklebust 	spin_lock_init(&clp->cl_lock);
15635694c93eSTrond Myklebust 	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
15641da177e4SLinus Torvalds 	return clp;
1565d4f0489fSTrond Myklebust err_no_hashtbl:
1566d4f0489fSTrond Myklebust 	kfree(clp->cl_name.data);
1567d4f0489fSTrond Myklebust err_no_name:
1568d4f0489fSTrond Myklebust 	kfree(clp);
1569d4f0489fSTrond Myklebust 	return NULL;
15701da177e4SLinus Torvalds }
15711da177e4SLinus Torvalds 
15724dd86e15STrond Myklebust static void
15731da177e4SLinus Torvalds free_client(struct nfs4_client *clp)
15741da177e4SLinus Torvalds {
1575792c95ddSJ. Bruce Fields 	while (!list_empty(&clp->cl_sessions)) {
1576792c95ddSJ. Bruce Fields 		struct nfsd4_session *ses;
1577792c95ddSJ. Bruce Fields 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
1578792c95ddSJ. Bruce Fields 				se_perclnt);
1579792c95ddSJ. Bruce Fields 		list_del(&ses->se_perclnt);
158066b2b9b2SJ. Bruce Fields 		WARN_ON_ONCE(atomic_read(&ses->se_ref));
158166b2b9b2SJ. Bruce Fields 		free_session(ses);
1582792c95ddSJ. Bruce Fields 	}
15834cb57e30STrond Myklebust 	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
158403a4e1f6SJ. Bruce Fields 	free_svc_cred(&clp->cl_cred);
1585d4f0489fSTrond Myklebust 	kfree(clp->cl_ownerstr_hashtbl);
15861da177e4SLinus Torvalds 	kfree(clp->cl_name.data);
15872d32b29aSmajianpeng 	idr_destroy(&clp->cl_stateids);
15881da177e4SLinus Torvalds 	kfree(clp);
15891da177e4SLinus Torvalds }
15901da177e4SLinus Torvalds 
159184d38ac9SBenny Halevy /* must be called under the client_lock */
15924beb345bSTrond Myklebust static void
159384d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp)
159484d38ac9SBenny Halevy {
15954beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1596792c95ddSJ. Bruce Fields 	struct nfsd4_session *ses;
1597792c95ddSJ. Bruce Fields 
15980a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
15990a880a28STrond Myklebust 
16004beb345bSTrond Myklebust 	/* Mark the client as expired! */
16014beb345bSTrond Myklebust 	clp->cl_time = 0;
16024beb345bSTrond Myklebust 	/* Make it invisible */
16034beb345bSTrond Myklebust 	if (!list_empty(&clp->cl_idhash)) {
16044beb345bSTrond Myklebust 		list_del_init(&clp->cl_idhash);
16054beb345bSTrond Myklebust 		if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
16064beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
16074beb345bSTrond Myklebust 		else
16084beb345bSTrond Myklebust 			rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
16094beb345bSTrond Myklebust 	}
16104beb345bSTrond Myklebust 	list_del_init(&clp->cl_lru);
16114c649378SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
1612792c95ddSJ. Bruce Fields 	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
1613792c95ddSJ. Bruce Fields 		list_del_init(&ses->se_hash);
16144c649378SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
161584d38ac9SBenny Halevy }
161684d38ac9SBenny Halevy 
16171da177e4SLinus Torvalds static void
16184beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp)
16194beb345bSTrond Myklebust {
16204beb345bSTrond Myklebust 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
16214beb345bSTrond Myklebust 
16224beb345bSTrond Myklebust 	spin_lock(&nn->client_lock);
16234beb345bSTrond Myklebust 	unhash_client_locked(clp);
16244beb345bSTrond Myklebust 	spin_unlock(&nn->client_lock);
16254beb345bSTrond Myklebust }
16264beb345bSTrond Myklebust 
162797403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp)
162897403d95SJeff Layton {
162997403d95SJeff Layton 	if (atomic_read(&clp->cl_refcount))
163097403d95SJeff Layton 		return nfserr_jukebox;
163197403d95SJeff Layton 	unhash_client_locked(clp);
163297403d95SJeff Layton 	return nfs_ok;
163397403d95SJeff Layton }
163497403d95SJeff Layton 
16354beb345bSTrond Myklebust static void
16364beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp)
16371da177e4SLinus Torvalds {
1638fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
16391da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
16401da177e4SLinus Torvalds 	struct list_head reaplist;
16411da177e4SLinus Torvalds 
16421da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
1643cdc97505SBenny Halevy 	spin_lock(&state_lock);
1644ea1da636SNeilBrown 	while (!list_empty(&clp->cl_delegations)) {
1645ea1da636SNeilBrown 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
164642690676SJeff Layton 		unhash_delegation_locked(dp);
164742690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
16481da177e4SLinus Torvalds 	}
1649cdc97505SBenny Halevy 	spin_unlock(&state_lock);
16501da177e4SLinus Torvalds 	while (!list_empty(&reaplist)) {
16511da177e4SLinus Torvalds 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
165242690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
16536011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
16541da177e4SLinus Torvalds 	}
16552d4a532dSJeff Layton 	while (!list_empty(&clp->cl_revoked)) {
1656956c4feeSBenny Halevy 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
16572d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
16586011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
1659956c4feeSBenny Halevy 	}
1660ea1da636SNeilBrown 	while (!list_empty(&clp->cl_openowners)) {
1661fe0750e5SJ. Bruce Fields 		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
1662d3134b10SJeff Layton 		atomic_inc(&oo->oo_owner.so_count);
1663fe0750e5SJ. Bruce Fields 		release_openowner(oo);
16641da177e4SLinus Torvalds 	}
16656ff8da08SJ. Bruce Fields 	nfsd4_shutdown_callback(clp);
16662bf23875SJ. Bruce Fields 	if (clp->cl_cb_conn.cb_xprt)
16672bf23875SJ. Bruce Fields 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1668b12a05cbSJ. Bruce Fields 	free_client(clp);
16691da177e4SLinus Torvalds }
16701da177e4SLinus Torvalds 
16714beb345bSTrond Myklebust static void
16724beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp)
16734beb345bSTrond Myklebust {
16744beb345bSTrond Myklebust 	unhash_client(clp);
16754beb345bSTrond Myklebust 	__destroy_client(clp);
16764beb345bSTrond Myklebust }
16774beb345bSTrond Myklebust 
16780d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp)
16790d22f68fSJ. Bruce Fields {
16804beb345bSTrond Myklebust 	unhash_client(clp);
16810d22f68fSJ. Bruce Fields 	nfsd4_client_record_remove(clp);
16824beb345bSTrond Myklebust 	__destroy_client(clp);
16830d22f68fSJ. Bruce Fields }
16840d22f68fSJ. Bruce Fields 
168535bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
168635bba9a3SJ. Bruce Fields {
168735bba9a3SJ. Bruce Fields 	memcpy(target->cl_verifier.data, source->data,
168835bba9a3SJ. Bruce Fields 			sizeof(target->cl_verifier.data));
16891da177e4SLinus Torvalds }
16901da177e4SLinus Torvalds 
169135bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
169235bba9a3SJ. Bruce Fields {
16931da177e4SLinus Torvalds 	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
16941da177e4SLinus Torvalds 	target->cl_clientid.cl_id = source->cl_clientid.cl_id;
16951da177e4SLinus Torvalds }
16961da177e4SLinus Torvalds 
169703a4e1f6SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source)
169835bba9a3SJ. Bruce Fields {
169903a4e1f6SJ. Bruce Fields 	if (source->cr_principal) {
170003a4e1f6SJ. Bruce Fields 		target->cr_principal =
170103a4e1f6SJ. Bruce Fields 				kstrdup(source->cr_principal, GFP_KERNEL);
170203a4e1f6SJ. Bruce Fields 		if (target->cr_principal == NULL)
170303a4e1f6SJ. Bruce Fields 			return -ENOMEM;
170403a4e1f6SJ. Bruce Fields 	} else
170503a4e1f6SJ. Bruce Fields 		target->cr_principal = NULL;
1706d5497fc6SJ. Bruce Fields 	target->cr_flavor = source->cr_flavor;
17071da177e4SLinus Torvalds 	target->cr_uid = source->cr_uid;
17081da177e4SLinus Torvalds 	target->cr_gid = source->cr_gid;
17091da177e4SLinus Torvalds 	target->cr_group_info = source->cr_group_info;
17101da177e4SLinus Torvalds 	get_group_info(target->cr_group_info);
17110dc1531aSJ. Bruce Fields 	target->cr_gss_mech = source->cr_gss_mech;
17120dc1531aSJ. Bruce Fields 	if (source->cr_gss_mech)
17130dc1531aSJ. Bruce Fields 		gss_mech_get(source->cr_gss_mech);
171403a4e1f6SJ. Bruce Fields 	return 0;
17151da177e4SLinus Torvalds }
17161da177e4SLinus Torvalds 
1717ac55fdc4SJeff Layton static long long
1718ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
1719ac55fdc4SJeff Layton {
1720ac55fdc4SJeff Layton 	long long res;
1721ac55fdc4SJeff Layton 
1722ac55fdc4SJeff Layton 	res = o1->len - o2->len;
1723ac55fdc4SJeff Layton 	if (res)
1724ac55fdc4SJeff Layton 		return res;
1725ac55fdc4SJeff Layton 	return (long long)memcmp(o1->data, o2->data, o1->len);
1726ac55fdc4SJeff Layton }
1727ac55fdc4SJeff Layton 
172835bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2)
1729599e0a22SJ. Bruce Fields {
1730a55370a3SNeilBrown 	return 0 == memcmp(n1, n2, HEXDIR_LEN);
17311da177e4SLinus Torvalds }
17321da177e4SLinus Torvalds 
17331da177e4SLinus Torvalds static int
1734599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
1735599e0a22SJ. Bruce Fields {
1736599e0a22SJ. Bruce Fields 	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
17371da177e4SLinus Torvalds }
17381da177e4SLinus Torvalds 
17391da177e4SLinus Torvalds static int
1740599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2)
1741599e0a22SJ. Bruce Fields {
1742599e0a22SJ. Bruce Fields 	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
17431da177e4SLinus Torvalds }
17441da177e4SLinus Torvalds 
17458fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2)
17468fbba96eSJ. Bruce Fields {
17478fbba96eSJ. Bruce Fields 	int i;
17488fbba96eSJ. Bruce Fields 
17498fbba96eSJ. Bruce Fields 	if (g1->ngroups != g2->ngroups)
17508fbba96eSJ. Bruce Fields 		return false;
17518fbba96eSJ. Bruce Fields 	for (i=0; i<g1->ngroups; i++)
17526fab8779SEric W. Biederman 		if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i)))
17538fbba96eSJ. Bruce Fields 			return false;
17548fbba96eSJ. Bruce Fields 	return true;
17558fbba96eSJ. Bruce Fields }
17568fbba96eSJ. Bruce Fields 
175768eb3508SJ. Bruce Fields /*
175868eb3508SJ. Bruce Fields  * RFC 3530 language requires clid_inuse be returned when the
175968eb3508SJ. Bruce Fields  * "principal" associated with a requests differs from that previously
176068eb3508SJ. Bruce Fields  * used.  We use uid, gid's, and gss principal string as our best
176168eb3508SJ. Bruce Fields  * approximation.  We also don't want to allow non-gss use of a client
176268eb3508SJ. Bruce Fields  * established using gss: in theory cr_principal should catch that
176368eb3508SJ. Bruce Fields  * change, but in practice cr_principal can be null even in the gss case
176468eb3508SJ. Bruce Fields  * since gssd doesn't always pass down a principal string.
176568eb3508SJ. Bruce Fields  */
176668eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr)
176768eb3508SJ. Bruce Fields {
176868eb3508SJ. Bruce Fields 	/* Is cr_flavor one of the gss "pseudoflavors"?: */
176968eb3508SJ. Bruce Fields 	return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
177068eb3508SJ. Bruce Fields }
177168eb3508SJ. Bruce Fields 
177268eb3508SJ. Bruce Fields 
17735559b50aSVivek Trivedi static bool
1774599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
1775599e0a22SJ. Bruce Fields {
177668eb3508SJ. Bruce Fields 	if ((is_gss_cred(cr1) != is_gss_cred(cr2))
17776fab8779SEric W. Biederman 		|| (!uid_eq(cr1->cr_uid, cr2->cr_uid))
17786fab8779SEric W. Biederman 		|| (!gid_eq(cr1->cr_gid, cr2->cr_gid))
17798fbba96eSJ. Bruce Fields 		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
17808fbba96eSJ. Bruce Fields 		return false;
17818fbba96eSJ. Bruce Fields 	if (cr1->cr_principal == cr2->cr_principal)
17828fbba96eSJ. Bruce Fields 		return true;
17838fbba96eSJ. Bruce Fields 	if (!cr1->cr_principal || !cr2->cr_principal)
17848fbba96eSJ. Bruce Fields 		return false;
17855559b50aSVivek Trivedi 	return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
17861da177e4SLinus Torvalds }
17871da177e4SLinus Torvalds 
178857266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
178957266a6eSJ. Bruce Fields {
179057266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
179157266a6eSJ. Bruce Fields 	u32 service;
179257266a6eSJ. Bruce Fields 
1793c4720591SJ. Bruce Fields 	if (!cr->cr_gss_mech)
1794c4720591SJ. Bruce Fields 		return false;
179557266a6eSJ. Bruce Fields 	service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
179657266a6eSJ. Bruce Fields 	return service == RPC_GSS_SVC_INTEGRITY ||
179757266a6eSJ. Bruce Fields 	       service == RPC_GSS_SVC_PRIVACY;
179857266a6eSJ. Bruce Fields }
179957266a6eSJ. Bruce Fields 
180057266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
180157266a6eSJ. Bruce Fields {
180257266a6eSJ. Bruce Fields 	struct svc_cred *cr = &rqstp->rq_cred;
180357266a6eSJ. Bruce Fields 
180457266a6eSJ. Bruce Fields 	if (!cl->cl_mach_cred)
180557266a6eSJ. Bruce Fields 		return true;
180657266a6eSJ. Bruce Fields 	if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
180757266a6eSJ. Bruce Fields 		return false;
180857266a6eSJ. Bruce Fields 	if (!svc_rqst_integrity_protected(rqstp))
180957266a6eSJ. Bruce Fields 		return false;
181057266a6eSJ. Bruce Fields 	if (!cr->cr_principal)
181157266a6eSJ. Bruce Fields 		return false;
181257266a6eSJ. Bruce Fields 	return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
181357266a6eSJ. Bruce Fields }
181457266a6eSJ. Bruce Fields 
1815294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
1816deda2faaSJ. Bruce Fields {
1817ab4684d1SChuck Lever 	__be32 verf[2];
18181da177e4SLinus Torvalds 
1819f419992cSJeff Layton 	/*
1820f419992cSJeff Layton 	 * This is opaque to client, so no need to byte-swap. Use
1821f419992cSJeff Layton 	 * __force to keep sparse happy
1822f419992cSJeff Layton 	 */
1823f419992cSJeff Layton 	verf[0] = (__force __be32)get_seconds();
1824294ac32eSJeff Layton 	verf[1] = (__force __be32)nn->clientid_counter;
1825ab4684d1SChuck Lever 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
18261da177e4SLinus Torvalds }
18271da177e4SLinus Torvalds 
1828294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
1829294ac32eSJeff Layton {
1830294ac32eSJeff Layton 	clp->cl_clientid.cl_boot = nn->boot_time;
1831294ac32eSJeff Layton 	clp->cl_clientid.cl_id = nn->clientid_counter++;
1832294ac32eSJeff Layton 	gen_confirm(clp, nn);
1833294ac32eSJeff Layton }
1834294ac32eSJeff Layton 
18354770d722SJeff Layton static struct nfs4_stid *
18364770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
18374581d140SJ. Bruce Fields {
18383abdb607SJ. Bruce Fields 	struct nfs4_stid *ret;
18393abdb607SJ. Bruce Fields 
18403abdb607SJ. Bruce Fields 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
18413abdb607SJ. Bruce Fields 	if (!ret || !ret->sc_type)
18423abdb607SJ. Bruce Fields 		return NULL;
18433abdb607SJ. Bruce Fields 	return ret;
18444581d140SJ. Bruce Fields }
18454d71ab87SJ. Bruce Fields 
18464770d722SJeff Layton static struct nfs4_stid *
18474770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
1848f459e453SJ. Bruce Fields {
1849f459e453SJ. Bruce Fields 	struct nfs4_stid *s;
1850f459e453SJ. Bruce Fields 
18514770d722SJeff Layton 	spin_lock(&cl->cl_lock);
18524770d722SJeff Layton 	s = find_stateid_locked(cl, t);
18532d3f9668STrond Myklebust 	if (s != NULL) {
18542d3f9668STrond Myklebust 		if (typemask & s->sc_type)
18552d3f9668STrond Myklebust 			atomic_inc(&s->sc_count);
18562d3f9668STrond Myklebust 		else
18574770d722SJeff Layton 			s = NULL;
18582d3f9668STrond Myklebust 	}
18594770d722SJeff Layton 	spin_unlock(&cl->cl_lock);
18604d71ab87SJ. Bruce Fields 	return s;
18614581d140SJ. Bruce Fields }
18624581d140SJ. Bruce Fields 
18632216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name,
1864b09333c4SRicardo Labiaga 		struct svc_rqst *rqstp, nfs4_verifier *verf)
1865b09333c4SRicardo Labiaga {
1866b09333c4SRicardo Labiaga 	struct nfs4_client *clp;
1867b09333c4SRicardo Labiaga 	struct sockaddr *sa = svc_addr(rqstp);
186803a4e1f6SJ. Bruce Fields 	int ret;
1869c212cecfSStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
1870b09333c4SRicardo Labiaga 
1871b09333c4SRicardo Labiaga 	clp = alloc_client(name);
1872b09333c4SRicardo Labiaga 	if (clp == NULL)
1873b09333c4SRicardo Labiaga 		return NULL;
1874b09333c4SRicardo Labiaga 
187503a4e1f6SJ. Bruce Fields 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
187603a4e1f6SJ. Bruce Fields 	if (ret) {
1877b09333c4SRicardo Labiaga 		free_client(clp);
1878b09333c4SRicardo Labiaga 		return NULL;
1879b09333c4SRicardo Labiaga 	}
188002e1215fSJeff Layton 	INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null);
188107cd4909SBenny Halevy 	clp->cl_time = get_seconds();
1882b09333c4SRicardo Labiaga 	clear_bit(0, &clp->cl_cb_slot_busy);
1883b09333c4SRicardo Labiaga 	copy_verf(clp, verf);
1884b09333c4SRicardo Labiaga 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
1885edd76786SJ. Bruce Fields 	clp->cl_cb_session = NULL;
1886c212cecfSStanislav Kinsbursky 	clp->net = net;
1887b09333c4SRicardo Labiaga 	return clp;
1888b09333c4SRicardo Labiaga }
1889b09333c4SRicardo Labiaga 
1890fd39ca9aSNeilBrown static void
1891ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
1892ac55fdc4SJeff Layton {
1893ac55fdc4SJeff Layton 	struct rb_node **new = &(root->rb_node), *parent = NULL;
1894ac55fdc4SJeff Layton 	struct nfs4_client *clp;
1895ac55fdc4SJeff Layton 
1896ac55fdc4SJeff Layton 	while (*new) {
1897ac55fdc4SJeff Layton 		clp = rb_entry(*new, struct nfs4_client, cl_namenode);
1898ac55fdc4SJeff Layton 		parent = *new;
1899ac55fdc4SJeff Layton 
1900ac55fdc4SJeff Layton 		if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
1901ac55fdc4SJeff Layton 			new = &((*new)->rb_left);
1902ac55fdc4SJeff Layton 		else
1903ac55fdc4SJeff Layton 			new = &((*new)->rb_right);
1904ac55fdc4SJeff Layton 	}
1905ac55fdc4SJeff Layton 
1906ac55fdc4SJeff Layton 	rb_link_node(&new_clp->cl_namenode, parent, new);
1907ac55fdc4SJeff Layton 	rb_insert_color(&new_clp->cl_namenode, root);
1908ac55fdc4SJeff Layton }
1909ac55fdc4SJeff Layton 
1910ac55fdc4SJeff Layton static struct nfs4_client *
1911ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
1912ac55fdc4SJeff Layton {
1913ac55fdc4SJeff Layton 	long long cmp;
1914ac55fdc4SJeff Layton 	struct rb_node *node = root->rb_node;
1915ac55fdc4SJeff Layton 	struct nfs4_client *clp;
1916ac55fdc4SJeff Layton 
1917ac55fdc4SJeff Layton 	while (node) {
1918ac55fdc4SJeff Layton 		clp = rb_entry(node, struct nfs4_client, cl_namenode);
1919ac55fdc4SJeff Layton 		cmp = compare_blob(&clp->cl_name, name);
1920ac55fdc4SJeff Layton 		if (cmp > 0)
1921ac55fdc4SJeff Layton 			node = node->rb_left;
1922ac55fdc4SJeff Layton 		else if (cmp < 0)
1923ac55fdc4SJeff Layton 			node = node->rb_right;
1924ac55fdc4SJeff Layton 		else
1925ac55fdc4SJeff Layton 			return clp;
1926ac55fdc4SJeff Layton 	}
1927ac55fdc4SJeff Layton 	return NULL;
1928ac55fdc4SJeff Layton }
1929ac55fdc4SJeff Layton 
1930ac55fdc4SJeff Layton static void
1931ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp)
19321da177e4SLinus Torvalds {
19331da177e4SLinus Torvalds 	unsigned int idhashval;
19340a7ec377SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
19351da177e4SLinus Torvalds 
19360a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
19370a880a28STrond Myklebust 
1938ac55fdc4SJeff Layton 	clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
1939a99454aaSStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
19401da177e4SLinus Torvalds 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
19410a7ec377SStanislav Kinsbursky 	list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
19423dbacee6STrond Myklebust 	renew_client_locked(clp);
19431da177e4SLinus Torvalds }
19441da177e4SLinus Torvalds 
1945fd39ca9aSNeilBrown static void
19461da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp)
19471da177e4SLinus Torvalds {
19481da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
19498daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
19501da177e4SLinus Torvalds 
19510a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
19520a880a28STrond Myklebust 
19531da177e4SLinus Torvalds 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
19548daae4dcSStanislav Kinsbursky 	list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
1955a99454aaSStanislav Kinsbursky 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
1956382a62e7SStanislav Kinsbursky 	add_clp_to_name_tree(clp, &nn->conf_name_tree);
1957ac55fdc4SJeff Layton 	set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
19583dbacee6STrond Myklebust 	renew_client_locked(clp);
19591da177e4SLinus Torvalds }
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds static struct nfs4_client *
1962bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
19631da177e4SLinus Torvalds {
19641da177e4SLinus Torvalds 	struct nfs4_client *clp;
19651da177e4SLinus Torvalds 	unsigned int idhashval = clientid_hashval(clid->cl_id);
19661da177e4SLinus Torvalds 
1967bfa85e83SJ. Bruce Fields 	list_for_each_entry(clp, &tbl[idhashval], cl_idhash) {
1968a50d2ad1SJ. Bruce Fields 		if (same_clid(&clp->cl_clientid, clid)) {
1969d15c077eSJ. Bruce Fields 			if ((bool)clp->cl_minorversion != sessions)
1970d15c077eSJ. Bruce Fields 				return NULL;
19713dbacee6STrond Myklebust 			renew_client_locked(clp);
19721da177e4SLinus Torvalds 			return clp;
19731da177e4SLinus Torvalds 		}
1974a50d2ad1SJ. Bruce Fields 	}
19751da177e4SLinus Torvalds 	return NULL;
19761da177e4SLinus Torvalds }
19771da177e4SLinus Torvalds 
19781da177e4SLinus Torvalds static struct nfs4_client *
1979bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
1980bfa85e83SJ. Bruce Fields {
1981bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->conf_id_hashtbl;
1982bfa85e83SJ. Bruce Fields 
19830a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1984bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
1985bfa85e83SJ. Bruce Fields }
1986bfa85e83SJ. Bruce Fields 
1987bfa85e83SJ. Bruce Fields static struct nfs4_client *
19880a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
19891da177e4SLinus Torvalds {
1990bfa85e83SJ. Bruce Fields 	struct list_head *tbl = nn->unconf_id_hashtbl;
19911da177e4SLinus Torvalds 
19920a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
1993bfa85e83SJ. Bruce Fields 	return find_client_in_id_table(tbl, clid, sessions);
19941da177e4SLinus Torvalds }
19951da177e4SLinus Torvalds 
19966e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp)
1997a1bcecd2SAndy Adamson {
19986e5f15c9SJ. Bruce Fields 	return clp->cl_exchange_flags != 0;
1999a1bcecd2SAndy Adamson }
2000a1bcecd2SAndy Adamson 
200128ce6054SNeilBrown static struct nfs4_client *
2002382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
200328ce6054SNeilBrown {
20040a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2005382a62e7SStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->conf_name_tree);
200628ce6054SNeilBrown }
200728ce6054SNeilBrown 
200828ce6054SNeilBrown static struct nfs4_client *
2009a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
201028ce6054SNeilBrown {
20110a880a28STrond Myklebust 	lockdep_assert_held(&nn->client_lock);
2012a99454aaSStanislav Kinsbursky 	return find_clp_in_name_tree(name, &nn->unconf_name_tree);
201328ce6054SNeilBrown }
201428ce6054SNeilBrown 
2015fd39ca9aSNeilBrown static void
20166f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
20171da177e4SLinus Torvalds {
201807263f1eSJ. Bruce Fields 	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
20196f3d772fSTakuma Umeya 	struct sockaddr	*sa = svc_addr(rqstp);
20206f3d772fSTakuma Umeya 	u32 scopeid = rpc_get_scope_id(sa);
20217077ecbaSJeff Layton 	unsigned short expected_family;
20221da177e4SLinus Torvalds 
20237077ecbaSJeff Layton 	/* Currently, we only support tcp and tcp6 for the callback channel */
20247077ecbaSJeff Layton 	if (se->se_callback_netid_len == 3 &&
20257077ecbaSJeff Layton 	    !memcmp(se->se_callback_netid_val, "tcp", 3))
20267077ecbaSJeff Layton 		expected_family = AF_INET;
20277077ecbaSJeff Layton 	else if (se->se_callback_netid_len == 4 &&
20287077ecbaSJeff Layton 		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
20297077ecbaSJeff Layton 		expected_family = AF_INET6;
20307077ecbaSJeff Layton 	else
20311da177e4SLinus Torvalds 		goto out_err;
20321da177e4SLinus Torvalds 
2033c212cecfSStanislav Kinsbursky 	conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val,
2034aa9a4ec7SJeff Layton 					    se->se_callback_addr_len,
203507263f1eSJ. Bruce Fields 					    (struct sockaddr *)&conn->cb_addr,
203607263f1eSJ. Bruce Fields 					    sizeof(conn->cb_addr));
2037aa9a4ec7SJeff Layton 
203807263f1eSJ. Bruce Fields 	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
20391da177e4SLinus Torvalds 		goto out_err;
2040aa9a4ec7SJeff Layton 
204107263f1eSJ. Bruce Fields 	if (conn->cb_addr.ss_family == AF_INET6)
204207263f1eSJ. Bruce Fields 		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
2043fbf4665fSJeff Layton 
204407263f1eSJ. Bruce Fields 	conn->cb_prog = se->se_callback_prog;
204507263f1eSJ. Bruce Fields 	conn->cb_ident = se->se_callback_ident;
2046849a1cf1SMi Jinlong 	memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
20471da177e4SLinus Torvalds 	return;
20481da177e4SLinus Torvalds out_err:
204907263f1eSJ. Bruce Fields 	conn->cb_addr.ss_family = AF_UNSPEC;
205007263f1eSJ. Bruce Fields 	conn->cb_addrlen = 0;
2051849823c5SNeil Brown 	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
20521da177e4SLinus Torvalds 		"will not receive delegations\n",
20531da177e4SLinus Torvalds 		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
20541da177e4SLinus Torvalds 
20551da177e4SLinus Torvalds 	return;
20561da177e4SLinus Torvalds }
20571da177e4SLinus Torvalds 
2058074fe897SAndy Adamson /*
2059067e1aceSJ. Bruce Fields  * Cache a reply. nfsd4_check_resp_size() has bounded the cache size.
2060074fe897SAndy Adamson  */
2061b607664eSTrond Myklebust static void
2062074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
2063074fe897SAndy Adamson {
2064f5236013SJ. Bruce Fields 	struct xdr_buf *buf = resp->xdr.buf;
2065557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2066557ce264SAndy Adamson 	unsigned int base;
2067074fe897SAndy Adamson 
2068557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2069074fe897SAndy Adamson 
2070557ce264SAndy Adamson 	slot->sl_opcnt = resp->opcnt;
2071557ce264SAndy Adamson 	slot->sl_status = resp->cstate.status;
2072bf864a31SAndy Adamson 
2073bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
2074bf864a31SAndy Adamson 	if (nfsd4_not_cached(resp)) {
2075557ce264SAndy Adamson 		slot->sl_datalen = 0;
2076bf864a31SAndy Adamson 		return;
2077bf864a31SAndy Adamson 	}
2078f5236013SJ. Bruce Fields 	base = resp->cstate.data_offset;
2079f5236013SJ. Bruce Fields 	slot->sl_datalen = buf->len - base;
2080f5236013SJ. Bruce Fields 	if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
2081557ce264SAndy Adamson 		WARN("%s: sessions DRC could not cache compound\n", __func__);
2082557ce264SAndy Adamson 	return;
2083074fe897SAndy Adamson }
2084074fe897SAndy Adamson 
2085074fe897SAndy Adamson /*
2086abfabf8cSAndy Adamson  * Encode the replay sequence operation from the slot values.
2087abfabf8cSAndy Adamson  * If cachethis is FALSE encode the uncached rep error on the next
2088abfabf8cSAndy Adamson  * operation which sets resp->p and increments resp->opcnt for
2089abfabf8cSAndy Adamson  * nfs4svc_encode_compoundres.
2090abfabf8cSAndy Adamson  *
2091074fe897SAndy Adamson  */
2092abfabf8cSAndy Adamson static __be32
2093abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
2094abfabf8cSAndy Adamson 			  struct nfsd4_compoundres *resp)
2095074fe897SAndy Adamson {
2096abfabf8cSAndy Adamson 	struct nfsd4_op *op;
2097abfabf8cSAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2098074fe897SAndy Adamson 
2099abfabf8cSAndy Adamson 	/* Encode the replayed sequence operation */
2100abfabf8cSAndy Adamson 	op = &args->ops[resp->opcnt - 1];
2101abfabf8cSAndy Adamson 	nfsd4_encode_operation(resp, op);
2102abfabf8cSAndy Adamson 
2103abfabf8cSAndy Adamson 	/* Return nfserr_retry_uncached_rep in next operation. */
210473e79482SJ. Bruce Fields 	if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
2105abfabf8cSAndy Adamson 		op = &args->ops[resp->opcnt++];
2106abfabf8cSAndy Adamson 		op->status = nfserr_retry_uncached_rep;
2107abfabf8cSAndy Adamson 		nfsd4_encode_operation(resp, op);
2108074fe897SAndy Adamson 	}
2109abfabf8cSAndy Adamson 	return op->status;
2110074fe897SAndy Adamson }
2111074fe897SAndy Adamson 
2112074fe897SAndy Adamson /*
2113557ce264SAndy Adamson  * The sequence operation is not cached because we can use the slot and
2114557ce264SAndy Adamson  * session values.
2115074fe897SAndy Adamson  */
21163ca2eb98SJ. Bruce Fields static __be32
2117bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
2118bf864a31SAndy Adamson 			 struct nfsd4_sequence *seq)
2119074fe897SAndy Adamson {
2120557ce264SAndy Adamson 	struct nfsd4_slot *slot = resp->cstate.slot;
2121f5236013SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2122f5236013SJ. Bruce Fields 	__be32 *p;
2123074fe897SAndy Adamson 	__be32 status;
2124074fe897SAndy Adamson 
2125557ce264SAndy Adamson 	dprintk("--> %s slot %p\n", __func__, slot);
2126074fe897SAndy Adamson 
2127abfabf8cSAndy Adamson 	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
21280da7b19cSJ. Bruce Fields 	if (status)
2129abfabf8cSAndy Adamson 		return status;
2130074fe897SAndy Adamson 
2131f5236013SJ. Bruce Fields 	p = xdr_reserve_space(xdr, slot->sl_datalen);
2132f5236013SJ. Bruce Fields 	if (!p) {
2133f5236013SJ. Bruce Fields 		WARN_ON_ONCE(1);
2134f5236013SJ. Bruce Fields 		return nfserr_serverfault;
2135f5236013SJ. Bruce Fields 	}
2136f5236013SJ. Bruce Fields 	xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen);
2137f5236013SJ. Bruce Fields 	xdr_commit_encode(xdr);
2138074fe897SAndy Adamson 
2139557ce264SAndy Adamson 	resp->opcnt = slot->sl_opcnt;
2140f5236013SJ. Bruce Fields 	return slot->sl_status;
2141074fe897SAndy Adamson }
2142074fe897SAndy Adamson 
21430733d213SAndy Adamson /*
21440733d213SAndy Adamson  * Set the exchange_id flags returned by the server.
21450733d213SAndy Adamson  */
21460733d213SAndy Adamson static void
21470733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
21480733d213SAndy Adamson {
21490733d213SAndy Adamson 	/* pNFS is not supported */
21500733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
21510733d213SAndy Adamson 
21520733d213SAndy Adamson 	/* Referrals are supported, Migration is not. */
21530733d213SAndy Adamson 	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
21540733d213SAndy Adamson 
21550733d213SAndy Adamson 	/* set the wire flags to return to client. */
21560733d213SAndy Adamson 	clid->flags = new->cl_exchange_flags;
21570733d213SAndy Adamson }
21580733d213SAndy Adamson 
2159631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp)
2160631fc9eaSJ. Bruce Fields {
2161631fc9eaSJ. Bruce Fields 	/*
2162631fc9eaSJ. Bruce Fields 	 * Note clp->cl_openowners check isn't quite right: there's no
2163631fc9eaSJ. Bruce Fields 	 * need to count owners without stateid's.
2164631fc9eaSJ. Bruce Fields 	 *
2165631fc9eaSJ. Bruce Fields 	 * Also note we should probably be using this in 4.0 case too.
2166631fc9eaSJ. Bruce Fields 	 */
21676eccece9SJ. Bruce Fields 	return !list_empty(&clp->cl_openowners)
21686eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_delegations)
21696eccece9SJ. Bruce Fields 		|| !list_empty(&clp->cl_sessions);
2170631fc9eaSJ. Bruce Fields }
2171631fc9eaSJ. Bruce Fields 
2172b37ad28bSAl Viro __be32
2173069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp,
2174069b6ad4SAndy Adamson 		  struct nfsd4_compound_state *cstate,
2175069b6ad4SAndy Adamson 		  struct nfsd4_exchange_id *exid)
2176069b6ad4SAndy Adamson {
21773dbacee6STrond Myklebust 	struct nfs4_client *conf, *new;
21783dbacee6STrond Myklebust 	struct nfs4_client *unconf = NULL;
217957b7b43bSJ. Bruce Fields 	__be32 status;
2180363168b4SJeff Layton 	char			addr_str[INET6_ADDRSTRLEN];
21810733d213SAndy Adamson 	nfs4_verifier		verf = exid->verifier;
2182363168b4SJeff Layton 	struct sockaddr		*sa = svc_addr(rqstp);
218383e08fd4SJ. Bruce Fields 	bool	update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A;
2184c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
21850733d213SAndy Adamson 
2186363168b4SJeff Layton 	rpc_ntop(sa, addr_str, sizeof(addr_str));
21870733d213SAndy Adamson 	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
2188363168b4SJeff Layton 		"ip_addr=%s flags %x, spa_how %d\n",
21890733d213SAndy Adamson 		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
2190363168b4SJeff Layton 		addr_str, exid->flags, exid->spa_how);
21910733d213SAndy Adamson 
2192a084daf5SJ. Bruce Fields 	if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
21930733d213SAndy Adamson 		return nfserr_inval;
21940733d213SAndy Adamson 
21950733d213SAndy Adamson 	switch (exid->spa_how) {
219657266a6eSJ. Bruce Fields 	case SP4_MACH_CRED:
219757266a6eSJ. Bruce Fields 		if (!svc_rqst_integrity_protected(rqstp))
219857266a6eSJ. Bruce Fields 			return nfserr_inval;
21990733d213SAndy Adamson 	case SP4_NONE:
22000733d213SAndy Adamson 		break;
2201063b0fb9SJ. Bruce Fields 	default:				/* checked by xdr code */
2202063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
22030733d213SAndy Adamson 	case SP4_SSV:
2204dd30333cSJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
22050733d213SAndy Adamson 	}
22060733d213SAndy Adamson 
22075cc40fd7STrond Myklebust 	new = create_client(exid->clname, rqstp, &verf);
22085cc40fd7STrond Myklebust 	if (new == NULL)
22095cc40fd7STrond Myklebust 		return nfserr_jukebox;
22105cc40fd7STrond Myklebust 
22112dbb269dSJ. Bruce Fields 	/* Cases below refer to rfc 5661 section 18.35.4: */
22120733d213SAndy Adamson 	nfs4_lock_state();
22133dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
2214382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&exid->clname, nn);
22150733d213SAndy Adamson 	if (conf) {
221683e08fd4SJ. Bruce Fields 		bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
221783e08fd4SJ. Bruce Fields 		bool verfs_match = same_verf(&verf, &conf->cl_verifier);
221883e08fd4SJ. Bruce Fields 
2219136e658dSJ. Bruce Fields 		if (update) {
2220136e658dSJ. Bruce Fields 			if (!clp_used_exchangeid(conf)) { /* buggy client */
22212dbb269dSJ. Bruce Fields 				status = nfserr_inval;
2222e203d506SJ. Bruce Fields 				goto out;
2223e203d506SJ. Bruce Fields 			}
222457266a6eSJ. Bruce Fields 			if (!mach_creds_match(conf, rqstp)) {
222557266a6eSJ. Bruce Fields 				status = nfserr_wrong_cred;
222657266a6eSJ. Bruce Fields 				goto out;
222757266a6eSJ. Bruce Fields 			}
22282dbb269dSJ. Bruce Fields 			if (!creds_match) { /* case 9 */
22290733d213SAndy Adamson 				status = nfserr_perm;
22300733d213SAndy Adamson 				goto out;
22310733d213SAndy Adamson 			}
22322dbb269dSJ. Bruce Fields 			if (!verfs_match) { /* case 8 */
22330733d213SAndy Adamson 				status = nfserr_not_same;
22340733d213SAndy Adamson 				goto out;
22350733d213SAndy Adamson 			}
2236136e658dSJ. Bruce Fields 			/* case 6 */
22370733d213SAndy Adamson 			exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
22380733d213SAndy Adamson 			goto out_copy;
22396ddbbbfeSMike Sager 		}
2240136e658dSJ. Bruce Fields 		if (!creds_match) { /* case 3 */
2241631fc9eaSJ. Bruce Fields 			if (client_has_state(conf)) {
2242136e658dSJ. Bruce Fields 				status = nfserr_clid_inuse;
2243136e658dSJ. Bruce Fields 				goto out;
2244136e658dSJ. Bruce Fields 			}
2245b9831b59SJ. Bruce Fields 			goto out_new;
2246631fc9eaSJ. Bruce Fields 		}
2247136e658dSJ. Bruce Fields 		if (verfs_match) { /* case 2 */
22480f1ba0efSJ. Bruce Fields 			conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
2249136e658dSJ. Bruce Fields 			goto out_copy;
2250136e658dSJ. Bruce Fields 		}
22512dbb269dSJ. Bruce Fields 		/* case 5, client reboot */
22523dbacee6STrond Myklebust 		conf = NULL;
22530733d213SAndy Adamson 		goto out_new;
22540733d213SAndy Adamson 	}
22556ddbbbfeSMike Sager 
22562dbb269dSJ. Bruce Fields 	if (update) { /* case 7 */
22570733d213SAndy Adamson 		status = nfserr_noent;
22580733d213SAndy Adamson 		goto out;
22590733d213SAndy Adamson 	}
22600733d213SAndy Adamson 
2261a99454aaSStanislav Kinsbursky 	unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
22622dbb269dSJ. Bruce Fields 	if (unconf) /* case 4, possible retry or client restart */
22633dbacee6STrond Myklebust 		unhash_client_locked(unconf);
22640733d213SAndy Adamson 
22652dbb269dSJ. Bruce Fields 	/* case 1 (normal case) */
22660733d213SAndy Adamson out_new:
2267fd699b8aSJeff Layton 	if (conf) {
2268fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
2269fd699b8aSJeff Layton 		if (status)
2270fd699b8aSJeff Layton 			goto out;
2271fd699b8aSJeff Layton 	}
22724f540e29SJ. Bruce Fields 	new->cl_minorversion = cstate->minorversion;
227357266a6eSJ. Bruce Fields 	new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
22740733d213SAndy Adamson 
2275c212cecfSStanislav Kinsbursky 	gen_clid(new, nn);
2276ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
22773dbacee6STrond Myklebust 	swap(new, conf);
22780733d213SAndy Adamson out_copy:
22795cc40fd7STrond Myklebust 	exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
22805cc40fd7STrond Myklebust 	exid->clientid.cl_id = conf->cl_clientid.cl_id;
22810733d213SAndy Adamson 
22825cc40fd7STrond Myklebust 	exid->seqid = conf->cl_cs_slot.sl_seqid + 1;
22835cc40fd7STrond Myklebust 	nfsd4_set_ex_flags(conf, exid);
22840733d213SAndy Adamson 
22850733d213SAndy Adamson 	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
22865cc40fd7STrond Myklebust 		conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags);
22870733d213SAndy Adamson 	status = nfs_ok;
22880733d213SAndy Adamson 
22890733d213SAndy Adamson out:
22903dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
22910733d213SAndy Adamson 	nfs4_unlock_state();
22925cc40fd7STrond Myklebust 	if (new)
22933dbacee6STrond Myklebust 		expire_client(new);
22943dbacee6STrond Myklebust 	if (unconf)
22953dbacee6STrond Myklebust 		expire_client(unconf);
22960733d213SAndy Adamson 	return status;
2297069b6ad4SAndy Adamson }
2298069b6ad4SAndy Adamson 
229957b7b43bSJ. Bruce Fields static __be32
230088e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
2301b85d4c01SBenny Halevy {
230288e588d5SAndy Adamson 	dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
230388e588d5SAndy Adamson 		slot_seqid);
2304b85d4c01SBenny Halevy 
2305b85d4c01SBenny Halevy 	/* The slot is in use, and no response has been sent. */
230688e588d5SAndy Adamson 	if (slot_inuse) {
230788e588d5SAndy Adamson 		if (seqid == slot_seqid)
2308b85d4c01SBenny Halevy 			return nfserr_jukebox;
2309b85d4c01SBenny Halevy 		else
2310b85d4c01SBenny Halevy 			return nfserr_seq_misordered;
2311b85d4c01SBenny Halevy 	}
2312f6d82485SJ. Bruce Fields 	/* Note unsigned 32-bit arithmetic handles wraparound: */
231388e588d5SAndy Adamson 	if (likely(seqid == slot_seqid + 1))
2314b85d4c01SBenny Halevy 		return nfs_ok;
231588e588d5SAndy Adamson 	if (seqid == slot_seqid)
2316b85d4c01SBenny Halevy 		return nfserr_replay_cache;
2317b85d4c01SBenny Halevy 	return nfserr_seq_misordered;
2318b85d4c01SBenny Halevy }
2319b85d4c01SBenny Halevy 
232049557cc7SAndy Adamson /*
232149557cc7SAndy Adamson  * Cache the create session result into the create session single DRC
232249557cc7SAndy Adamson  * slot cache by saving the xdr structure. sl_seqid has been set.
232349557cc7SAndy Adamson  * Do this for solo or embedded create session operations.
232449557cc7SAndy Adamson  */
232549557cc7SAndy Adamson static void
232649557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
232757b7b43bSJ. Bruce Fields 			   struct nfsd4_clid_slot *slot, __be32 nfserr)
232849557cc7SAndy Adamson {
232949557cc7SAndy Adamson 	slot->sl_status = nfserr;
233049557cc7SAndy Adamson 	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
233149557cc7SAndy Adamson }
233249557cc7SAndy Adamson 
233349557cc7SAndy Adamson static __be32
233449557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
233549557cc7SAndy Adamson 			    struct nfsd4_clid_slot *slot)
233649557cc7SAndy Adamson {
233749557cc7SAndy Adamson 	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
233849557cc7SAndy Adamson 	return slot->sl_status;
233949557cc7SAndy Adamson }
234049557cc7SAndy Adamson 
23411b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
23421b74c25bSMi Jinlong 			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
23431b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
23441b74c25bSMi Jinlong 			3 +	/* version, opcount, opcode */ \
23451b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
23461b74c25bSMi Jinlong 				/* seqid, slotID, slotID, cache */ \
23471b74c25bSMi Jinlong 			4 ) * sizeof(__be32))
23481b74c25bSMi Jinlong 
23491b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
23501b74c25bSMi Jinlong 			2 +	/* verifier: AUTH_NULL, length 0 */\
23511b74c25bSMi Jinlong 			1 +	/* status */ \
23521b74c25bSMi Jinlong 			1 +	/* MIN tag is length with zero, only length */ \
23531b74c25bSMi Jinlong 			3 +	/* opcount, opcode, opstatus*/ \
23541b74c25bSMi Jinlong 			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
23551b74c25bSMi Jinlong 				/* seqid, slotID, slotID, slotID, status */ \
23561b74c25bSMi Jinlong 			5 ) * sizeof(__be32))
23571b74c25bSMi Jinlong 
235855c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn)
23591b74c25bSMi Jinlong {
236055c760cfSJ. Bruce Fields 	u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
236155c760cfSJ. Bruce Fields 
2362373cd409SJ. Bruce Fields 	if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
2363373cd409SJ. Bruce Fields 		return nfserr_toosmall;
2364373cd409SJ. Bruce Fields 	if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
2365373cd409SJ. Bruce Fields 		return nfserr_toosmall;
236655c760cfSJ. Bruce Fields 	ca->headerpadsz = 0;
236755c760cfSJ. Bruce Fields 	ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
236855c760cfSJ. Bruce Fields 	ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
236955c760cfSJ. Bruce Fields 	ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
237055c760cfSJ. Bruce Fields 	ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
237155c760cfSJ. Bruce Fields 			NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
237255c760cfSJ. Bruce Fields 	ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
237355c760cfSJ. Bruce Fields 	/*
237455c760cfSJ. Bruce Fields 	 * Note decreasing slot size below client's request may make it
237555c760cfSJ. Bruce Fields 	 * difficult for client to function correctly, whereas
237655c760cfSJ. Bruce Fields 	 * decreasing the number of slots will (just?) affect
237755c760cfSJ. Bruce Fields 	 * performance.  When short on memory we therefore prefer to
237855c760cfSJ. Bruce Fields 	 * decrease number of slots instead of their size.  Clients that
237955c760cfSJ. Bruce Fields 	 * request larger slots than they need will get poor results:
238055c760cfSJ. Bruce Fields 	 */
238155c760cfSJ. Bruce Fields 	ca->maxreqs = nfsd4_get_drc_mem(ca);
238255c760cfSJ. Bruce Fields 	if (!ca->maxreqs)
238355c760cfSJ. Bruce Fields 		return nfserr_jukebox;
238455c760cfSJ. Bruce Fields 
2385373cd409SJ. Bruce Fields 	return nfs_ok;
23861b74c25bSMi Jinlong }
23871b74c25bSMi Jinlong 
23888a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ	((NFS4_enc_cb_recall_sz + \
23898a891633SKinglong Mee 				 RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32))
23908a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ	((NFS4_dec_cb_recall_sz + \
23918a891633SKinglong Mee 				 RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32))
23928a891633SKinglong Mee 
239306b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
239406b332a5SJ. Bruce Fields {
239506b332a5SJ. Bruce Fields 	ca->headerpadsz = 0;
239606b332a5SJ. Bruce Fields 
239706b332a5SJ. Bruce Fields 	/*
239806b332a5SJ. Bruce Fields 	 * These RPC_MAX_HEADER macros are overkill, especially since we
239906b332a5SJ. Bruce Fields 	 * don't even do gss on the backchannel yet.  But this is still
240006b332a5SJ. Bruce Fields 	 * less than 1k.  Tighten up this estimate in the unlikely event
240106b332a5SJ. Bruce Fields 	 * it turns out to be a problem for some client:
240206b332a5SJ. Bruce Fields 	 */
24038a891633SKinglong Mee 	if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ)
240406b332a5SJ. Bruce Fields 		return nfserr_toosmall;
24058a891633SKinglong Mee 	if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ)
240606b332a5SJ. Bruce Fields 		return nfserr_toosmall;
240706b332a5SJ. Bruce Fields 	ca->maxresp_cached = 0;
240806b332a5SJ. Bruce Fields 	if (ca->maxops < 2)
240906b332a5SJ. Bruce Fields 		return nfserr_toosmall;
241006b332a5SJ. Bruce Fields 
241106b332a5SJ. Bruce Fields 	return nfs_ok;
2412069b6ad4SAndy Adamson }
2413069b6ad4SAndy Adamson 
2414b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
2415b78724b7SJ. Bruce Fields {
2416b78724b7SJ. Bruce Fields 	switch (cbs->flavor) {
2417b78724b7SJ. Bruce Fields 	case RPC_AUTH_NULL:
2418b78724b7SJ. Bruce Fields 	case RPC_AUTH_UNIX:
2419b78724b7SJ. Bruce Fields 		return nfs_ok;
2420b78724b7SJ. Bruce Fields 	default:
2421b78724b7SJ. Bruce Fields 		/*
2422b78724b7SJ. Bruce Fields 		 * GSS case: the spec doesn't allow us to return this
2423b78724b7SJ. Bruce Fields 		 * error.  But it also doesn't allow us not to support
2424b78724b7SJ. Bruce Fields 		 * GSS.
2425b78724b7SJ. Bruce Fields 		 * I'd rather this fail hard than return some error the
2426b78724b7SJ. Bruce Fields 		 * client might think it can already handle:
2427b78724b7SJ. Bruce Fields 		 */
2428b78724b7SJ. Bruce Fields 		return nfserr_encr_alg_unsupp;
2429b78724b7SJ. Bruce Fields 	}
2430b78724b7SJ. Bruce Fields }
2431b78724b7SJ. Bruce Fields 
2432069b6ad4SAndy Adamson __be32
2433069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp,
2434069b6ad4SAndy Adamson 		     struct nfsd4_compound_state *cstate,
2435069b6ad4SAndy Adamson 		     struct nfsd4_create_session *cr_ses)
2436069b6ad4SAndy Adamson {
2437363168b4SJeff Layton 	struct sockaddr *sa = svc_addr(rqstp);
2438ec6b5d7bSAndy Adamson 	struct nfs4_client *conf, *unconf;
2439d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
2440ac7c46f2SJ. Bruce Fields 	struct nfsd4_session *new;
244181f0b2a4SJ. Bruce Fields 	struct nfsd4_conn *conn;
244249557cc7SAndy Adamson 	struct nfsd4_clid_slot *cs_slot = NULL;
244357b7b43bSJ. Bruce Fields 	__be32 status = 0;
24448daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2445ec6b5d7bSAndy Adamson 
2446a62573dcSMi Jinlong 	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
2447a62573dcSMi Jinlong 		return nfserr_inval;
2448b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
2449b78724b7SJ. Bruce Fields 	if (status)
2450b78724b7SJ. Bruce Fields 		return status;
245155c760cfSJ. Bruce Fields 	status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
2452373cd409SJ. Bruce Fields 	if (status)
2453373cd409SJ. Bruce Fields 		return status;
245406b332a5SJ. Bruce Fields 	status = check_backchannel_attrs(&cr_ses->back_channel);
245506b332a5SJ. Bruce Fields 	if (status)
2456f403e450SKinglong Mee 		goto out_release_drc_mem;
245781f0b2a4SJ. Bruce Fields 	status = nfserr_jukebox;
245860810e54SKinglong Mee 	new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
245955c760cfSJ. Bruce Fields 	if (!new)
246055c760cfSJ. Bruce Fields 		goto out_release_drc_mem;
246181f0b2a4SJ. Bruce Fields 	conn = alloc_conn_from_crses(rqstp, cr_ses);
246281f0b2a4SJ. Bruce Fields 	if (!conn)
246381f0b2a4SJ. Bruce Fields 		goto out_free_session;
2464a62573dcSMi Jinlong 
2465ec6b5d7bSAndy Adamson 	nfs4_lock_state();
2466d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
24670a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
24688daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
246978389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2470ec6b5d7bSAndy Adamson 
2471ec6b5d7bSAndy Adamson 	if (conf) {
247257266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
247357266a6eSJ. Bruce Fields 		if (!mach_creds_match(conf, rqstp))
247457266a6eSJ. Bruce Fields 			goto out_free_conn;
247549557cc7SAndy Adamson 		cs_slot = &conf->cl_cs_slot;
247649557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
247738eb76a5SAndy Adamson 		if (status == nfserr_replay_cache) {
247849557cc7SAndy Adamson 			status = nfsd4_replay_create_session(cr_ses, cs_slot);
247981f0b2a4SJ. Bruce Fields 			goto out_free_conn;
248049557cc7SAndy Adamson 		} else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
2481ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
248281f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2483ec6b5d7bSAndy Adamson 		}
2484ec6b5d7bSAndy Adamson 	} else if (unconf) {
2485ec6b5d7bSAndy Adamson 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
2486363168b4SJeff Layton 		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
2487ec6b5d7bSAndy Adamson 			status = nfserr_clid_inuse;
248881f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2489ec6b5d7bSAndy Adamson 		}
249057266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
249157266a6eSJ. Bruce Fields 		if (!mach_creds_match(unconf, rqstp))
249257266a6eSJ. Bruce Fields 			goto out_free_conn;
249349557cc7SAndy Adamson 		cs_slot = &unconf->cl_cs_slot;
249449557cc7SAndy Adamson 		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
249538eb76a5SAndy Adamson 		if (status) {
249638eb76a5SAndy Adamson 			/* an unconfirmed replay returns misordered */
2497ec6b5d7bSAndy Adamson 			status = nfserr_seq_misordered;
249881f0b2a4SJ. Bruce Fields 			goto out_free_conn;
2499ec6b5d7bSAndy Adamson 		}
2500382a62e7SStanislav Kinsbursky 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
2501221a6876SJ. Bruce Fields 		if (old) {
2502d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
25037abea1e8SJeff Layton 			if (status) {
25047abea1e8SJeff Layton 				old = NULL;
2505221a6876SJ. Bruce Fields 				goto out_free_conn;
2506221a6876SJ. Bruce Fields 			}
25077abea1e8SJeff Layton 		}
25088f9d3d3bSJ. Bruce Fields 		move_to_confirmed(unconf);
2509ec6b5d7bSAndy Adamson 		conf = unconf;
2510ec6b5d7bSAndy Adamson 	} else {
2511ec6b5d7bSAndy Adamson 		status = nfserr_stale_clientid;
251281f0b2a4SJ. Bruce Fields 		goto out_free_conn;
2513ec6b5d7bSAndy Adamson 	}
251481f0b2a4SJ. Bruce Fields 	status = nfs_ok;
25158323c3b2SJ. Bruce Fields 	/*
2516408b79bcSJ. Bruce Fields 	 * We do not support RDMA or persistent sessions
2517408b79bcSJ. Bruce Fields 	 */
2518408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_PERSIST;
2519408b79bcSJ. Bruce Fields 	cr_ses->flags &= ~SESSION4_RDMA;
2520408b79bcSJ. Bruce Fields 
252181f0b2a4SJ. Bruce Fields 	init_session(rqstp, new, conf, cr_ses);
2522d20c11d8SJeff Layton 	nfsd4_get_session_locked(new);
252381f0b2a4SJ. Bruce Fields 
2524ac7c46f2SJ. Bruce Fields 	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
2525ec6b5d7bSAndy Adamson 	       NFS4_MAX_SESSIONID_LEN);
252686c3e16cSJ. Bruce Fields 	cs_slot->sl_seqid++;
252749557cc7SAndy Adamson 	cr_ses->seqid = cs_slot->sl_seqid;
2528ec6b5d7bSAndy Adamson 
2529d20c11d8SJeff Layton 	/* cache solo and embedded create sessions under the client_lock */
253049557cc7SAndy Adamson 	nfsd4_cache_create_session(cr_ses, cs_slot, status);
2531d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
2532d20c11d8SJeff Layton 	/* init connection and backchannel */
2533d20c11d8SJeff Layton 	nfsd4_init_conn(rqstp, conn, new);
2534d20c11d8SJeff Layton 	nfsd4_put_session(new);
2535ec6b5d7bSAndy Adamson 	nfs4_unlock_state();
2536d20c11d8SJeff Layton 	if (old)
2537d20c11d8SJeff Layton 		expire_client(old);
2538ec6b5d7bSAndy Adamson 	return status;
253981f0b2a4SJ. Bruce Fields out_free_conn:
2540d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
2541266533c6SYanchuan Nian 	nfs4_unlock_state();
254281f0b2a4SJ. Bruce Fields 	free_conn(conn);
2543d20c11d8SJeff Layton 	if (old)
2544d20c11d8SJeff Layton 		expire_client(old);
254581f0b2a4SJ. Bruce Fields out_free_session:
254681f0b2a4SJ. Bruce Fields 	__free_session(new);
254755c760cfSJ. Bruce Fields out_release_drc_mem:
254855c760cfSJ. Bruce Fields 	nfsd4_put_drc_mem(&cr_ses->fore_channel);
25491ca50792SJ. Bruce Fields 	return status;
2550069b6ad4SAndy Adamson }
2551069b6ad4SAndy Adamson 
25521d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir)
25531d1bc8f2SJ. Bruce Fields {
25541d1bc8f2SJ. Bruce Fields 	switch (*dir) {
25551d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE:
25561d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK:
25571d1bc8f2SJ. Bruce Fields 		return nfs_ok;
25581d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_FORE_OR_BOTH:
25591d1bc8f2SJ. Bruce Fields 	case NFS4_CDFC4_BACK_OR_BOTH:
25601d1bc8f2SJ. Bruce Fields 		*dir = NFS4_CDFC4_BOTH;
25611d1bc8f2SJ. Bruce Fields 		return nfs_ok;
25621d1bc8f2SJ. Bruce Fields 	};
25631d1bc8f2SJ. Bruce Fields 	return nfserr_inval;
25641d1bc8f2SJ. Bruce Fields }
25651d1bc8f2SJ. Bruce Fields 
2566cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc)
2567cb73a9f4SJ. Bruce Fields {
2568cb73a9f4SJ. Bruce Fields 	struct nfsd4_session *session = cstate->session;
2569c9a49628SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2570b78724b7SJ. Bruce Fields 	__be32 status;
2571cb73a9f4SJ. Bruce Fields 
2572b78724b7SJ. Bruce Fields 	status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
2573b78724b7SJ. Bruce Fields 	if (status)
2574b78724b7SJ. Bruce Fields 		return status;
2575c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2576cb73a9f4SJ. Bruce Fields 	session->se_cb_prog = bc->bc_cb_program;
2577cb73a9f4SJ. Bruce Fields 	session->se_cb_sec = bc->bc_cb_sec;
2578c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2579cb73a9f4SJ. Bruce Fields 
2580cb73a9f4SJ. Bruce Fields 	nfsd4_probe_callback(session->se_client);
2581cb73a9f4SJ. Bruce Fields 
2582cb73a9f4SJ. Bruce Fields 	return nfs_ok;
2583cb73a9f4SJ. Bruce Fields }
2584cb73a9f4SJ. Bruce Fields 
25851d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
25861d1bc8f2SJ. Bruce Fields 		     struct nfsd4_compound_state *cstate,
25871d1bc8f2SJ. Bruce Fields 		     struct nfsd4_bind_conn_to_session *bcts)
25881d1bc8f2SJ. Bruce Fields {
25891d1bc8f2SJ. Bruce Fields 	__be32 status;
25903ba63671SJ. Bruce Fields 	struct nfsd4_conn *conn;
25914f6e6c17SJ. Bruce Fields 	struct nfsd4_session *session;
2592d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2593d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
25941d1bc8f2SJ. Bruce Fields 
25951d1bc8f2SJ. Bruce Fields 	if (!nfsd4_last_compound_op(rqstp))
25961d1bc8f2SJ. Bruce Fields 		return nfserr_not_only_op;
25974f6e6c17SJ. Bruce Fields 	nfs4_lock_state();
2598c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2599d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status);
2600c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
26014f6e6c17SJ. Bruce Fields 	if (!session)
2602d4e19e70STrond Myklebust 		goto out_no_session;
260357266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
260457266a6eSJ. Bruce Fields 	if (!mach_creds_match(session->se_client, rqstp))
260557266a6eSJ. Bruce Fields 		goto out;
26061d1bc8f2SJ. Bruce Fields 	status = nfsd4_map_bcts_dir(&bcts->dir);
26073ba63671SJ. Bruce Fields 	if (status)
26084f6e6c17SJ. Bruce Fields 		goto out;
26093ba63671SJ. Bruce Fields 	conn = alloc_conn(rqstp, bcts->dir);
26104f6e6c17SJ. Bruce Fields 	status = nfserr_jukebox;
26113ba63671SJ. Bruce Fields 	if (!conn)
26124f6e6c17SJ. Bruce Fields 		goto out;
26134f6e6c17SJ. Bruce Fields 	nfsd4_init_conn(rqstp, conn, session);
26144f6e6c17SJ. Bruce Fields 	status = nfs_ok;
26154f6e6c17SJ. Bruce Fields out:
2616d4e19e70STrond Myklebust 	nfsd4_put_session(session);
2617d4e19e70STrond Myklebust out_no_session:
26184f6e6c17SJ. Bruce Fields 	nfs4_unlock_state();
26194f6e6c17SJ. Bruce Fields 	return status;
26201d1bc8f2SJ. Bruce Fields }
26211d1bc8f2SJ. Bruce Fields 
26225d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
26235d4cec2fSJ. Bruce Fields {
26245d4cec2fSJ. Bruce Fields 	if (!session)
26255d4cec2fSJ. Bruce Fields 		return 0;
26265d4cec2fSJ. Bruce Fields 	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
26275d4cec2fSJ. Bruce Fields }
26285d4cec2fSJ. Bruce Fields 
2629069b6ad4SAndy Adamson __be32
2630069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r,
2631069b6ad4SAndy Adamson 		      struct nfsd4_compound_state *cstate,
2632069b6ad4SAndy Adamson 		      struct nfsd4_destroy_session *sessionid)
2633069b6ad4SAndy Adamson {
2634e10e0cfcSBenny Halevy 	struct nfsd4_session *ses;
2635abcdff09SJ. Bruce Fields 	__be32 status;
2636f0f51f5cSJ. Bruce Fields 	int ref_held_by_me = 0;
2637d4e19e70STrond Myklebust 	struct net *net = SVC_NET(r);
2638d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2639e10e0cfcSBenny Halevy 
2640abcdff09SJ. Bruce Fields 	nfs4_lock_state();
2641abcdff09SJ. Bruce Fields 	status = nfserr_not_only_op;
26425d4cec2fSJ. Bruce Fields 	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
264357716355SJ. Bruce Fields 		if (!nfsd4_last_compound_op(r))
2644abcdff09SJ. Bruce Fields 			goto out;
2645f0f51f5cSJ. Bruce Fields 		ref_held_by_me++;
264657716355SJ. Bruce Fields 	}
2647e10e0cfcSBenny Halevy 	dump_sessionid(__func__, &sessionid->sessionid);
2648c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2649d4e19e70STrond Myklebust 	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status);
2650abcdff09SJ. Bruce Fields 	if (!ses)
2651abcdff09SJ. Bruce Fields 		goto out_client_lock;
265257266a6eSJ. Bruce Fields 	status = nfserr_wrong_cred;
265357266a6eSJ. Bruce Fields 	if (!mach_creds_match(ses->se_client, r))
2654d4e19e70STrond Myklebust 		goto out_put_session;
2655f0f51f5cSJ. Bruce Fields 	status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
265666b2b9b2SJ. Bruce Fields 	if (status)
2657f0f51f5cSJ. Bruce Fields 		goto out_put_session;
2658e10e0cfcSBenny Halevy 	unhash_session(ses);
2659c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2660e10e0cfcSBenny Halevy 
266184f5f7ccSJ. Bruce Fields 	nfsd4_probe_callback_sync(ses->se_client);
266219cf5c02SJ. Bruce Fields 
2663c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2664e10e0cfcSBenny Halevy 	status = nfs_ok;
2665f0f51f5cSJ. Bruce Fields out_put_session:
2666d4e19e70STrond Myklebust 	nfsd4_put_session_locked(ses);
2667abcdff09SJ. Bruce Fields out_client_lock:
2668abcdff09SJ. Bruce Fields 	spin_unlock(&nn->client_lock);
2669e10e0cfcSBenny Halevy out:
2670abcdff09SJ. Bruce Fields 	nfs4_unlock_state();
2671e10e0cfcSBenny Halevy 	return status;
2672069b6ad4SAndy Adamson }
2673069b6ad4SAndy Adamson 
2674a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
2675328ead28SJ. Bruce Fields {
2676328ead28SJ. Bruce Fields 	struct nfsd4_conn *c;
2677328ead28SJ. Bruce Fields 
2678328ead28SJ. Bruce Fields 	list_for_each_entry(c, &s->se_conns, cn_persession) {
2679a663bdd8SJ. Bruce Fields 		if (c->cn_xprt == xpt) {
2680328ead28SJ. Bruce Fields 			return c;
2681328ead28SJ. Bruce Fields 		}
2682328ead28SJ. Bruce Fields 	}
2683328ead28SJ. Bruce Fields 	return NULL;
2684328ead28SJ. Bruce Fields }
2685328ead28SJ. Bruce Fields 
268657266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
2687328ead28SJ. Bruce Fields {
2688328ead28SJ. Bruce Fields 	struct nfs4_client *clp = ses->se_client;
2689a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *c;
269057266a6eSJ. Bruce Fields 	__be32 status = nfs_ok;
269121b75b01SJ. Bruce Fields 	int ret;
2692328ead28SJ. Bruce Fields 
2693328ead28SJ. Bruce Fields 	spin_lock(&clp->cl_lock);
2694a663bdd8SJ. Bruce Fields 	c = __nfsd4_find_conn(new->cn_xprt, ses);
269557266a6eSJ. Bruce Fields 	if (c)
269657266a6eSJ. Bruce Fields 		goto out_free;
269757266a6eSJ. Bruce Fields 	status = nfserr_conn_not_bound_to_session;
269857266a6eSJ. Bruce Fields 	if (clp->cl_mach_cred)
269957266a6eSJ. Bruce Fields 		goto out_free;
2700328ead28SJ. Bruce Fields 	__nfsd4_hash_conn(new, ses);
2701328ead28SJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
270221b75b01SJ. Bruce Fields 	ret = nfsd4_register_conn(new);
270321b75b01SJ. Bruce Fields 	if (ret)
270421b75b01SJ. Bruce Fields 		/* oops; xprt is already down: */
270521b75b01SJ. Bruce Fields 		nfsd4_conn_lost(&new->cn_xpt_user);
270657266a6eSJ. Bruce Fields 	return nfs_ok;
270757266a6eSJ. Bruce Fields out_free:
270857266a6eSJ. Bruce Fields 	spin_unlock(&clp->cl_lock);
270957266a6eSJ. Bruce Fields 	free_conn(new);
271057266a6eSJ. Bruce Fields 	return status;
2711328ead28SJ. Bruce Fields }
2712328ead28SJ. Bruce Fields 
2713868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
2714868b89c3SMi Jinlong {
2715868b89c3SMi Jinlong 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
2716868b89c3SMi Jinlong 
2717868b89c3SMi Jinlong 	return args->opcnt > session->se_fchannel.maxops;
2718868b89c3SMi Jinlong }
2719868b89c3SMi Jinlong 
2720ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
2721ae82a8d0SMi Jinlong 				  struct nfsd4_session *session)
2722ae82a8d0SMi Jinlong {
2723ae82a8d0SMi Jinlong 	struct xdr_buf *xb = &rqstp->rq_arg;
2724ae82a8d0SMi Jinlong 
2725ae82a8d0SMi Jinlong 	return xb->len > session->se_fchannel.maxreq_sz;
2726ae82a8d0SMi Jinlong }
2727ae82a8d0SMi Jinlong 
2728069b6ad4SAndy Adamson __be32
2729b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp,
2730069b6ad4SAndy Adamson 	       struct nfsd4_compound_state *cstate,
2731069b6ad4SAndy Adamson 	       struct nfsd4_sequence *seq)
2732069b6ad4SAndy Adamson {
2733f9bb94c4SAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
273447ee5298SJ. Bruce Fields 	struct xdr_stream *xdr = &resp->xdr;
2735b85d4c01SBenny Halevy 	struct nfsd4_session *session;
2736221a6876SJ. Bruce Fields 	struct nfs4_client *clp;
2737b85d4c01SBenny Halevy 	struct nfsd4_slot *slot;
2738a663bdd8SJ. Bruce Fields 	struct nfsd4_conn *conn;
273957b7b43bSJ. Bruce Fields 	__be32 status;
274047ee5298SJ. Bruce Fields 	int buflen;
2741d4e19e70STrond Myklebust 	struct net *net = SVC_NET(rqstp);
2742d4e19e70STrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2743b85d4c01SBenny Halevy 
2744f9bb94c4SAndy Adamson 	if (resp->opcnt != 1)
2745f9bb94c4SAndy Adamson 		return nfserr_sequence_pos;
2746f9bb94c4SAndy Adamson 
2747a663bdd8SJ. Bruce Fields 	/*
2748a663bdd8SJ. Bruce Fields 	 * Will be either used or freed by nfsd4_sequence_check_conn
2749a663bdd8SJ. Bruce Fields 	 * below.
2750a663bdd8SJ. Bruce Fields 	 */
2751a663bdd8SJ. Bruce Fields 	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
2752a663bdd8SJ. Bruce Fields 	if (!conn)
2753a663bdd8SJ. Bruce Fields 		return nfserr_jukebox;
2754a663bdd8SJ. Bruce Fields 
2755c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
2756d4e19e70STrond Myklebust 	session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status);
2757b85d4c01SBenny Halevy 	if (!session)
2758221a6876SJ. Bruce Fields 		goto out_no_session;
2759221a6876SJ. Bruce Fields 	clp = session->se_client;
2760b85d4c01SBenny Halevy 
2761868b89c3SMi Jinlong 	status = nfserr_too_many_ops;
2762868b89c3SMi Jinlong 	if (nfsd4_session_too_many_ops(rqstp, session))
276366b2b9b2SJ. Bruce Fields 		goto out_put_session;
2764868b89c3SMi Jinlong 
2765ae82a8d0SMi Jinlong 	status = nfserr_req_too_big;
2766ae82a8d0SMi Jinlong 	if (nfsd4_request_too_big(rqstp, session))
276766b2b9b2SJ. Bruce Fields 		goto out_put_session;
2768ae82a8d0SMi Jinlong 
2769b85d4c01SBenny Halevy 	status = nfserr_badslot;
27706c18ba9fSAlexandros Batsakis 	if (seq->slotid >= session->se_fchannel.maxreqs)
277166b2b9b2SJ. Bruce Fields 		goto out_put_session;
2772b85d4c01SBenny Halevy 
2773557ce264SAndy Adamson 	slot = session->se_slots[seq->slotid];
2774b85d4c01SBenny Halevy 	dprintk("%s: slotid %d\n", __func__, seq->slotid);
2775b85d4c01SBenny Halevy 
2776a8dfdaebSAndy Adamson 	/* We do not negotiate the number of slots yet, so set the
2777a8dfdaebSAndy Adamson 	 * maxslots to the session maxreqs which is used to encode
2778a8dfdaebSAndy Adamson 	 * sr_highest_slotid and the sr_target_slot id to maxslots */
2779a8dfdaebSAndy Adamson 	seq->maxslots = session->se_fchannel.maxreqs;
2780a8dfdaebSAndy Adamson 
278173e79482SJ. Bruce Fields 	status = check_slot_seqid(seq->seqid, slot->sl_seqid,
278273e79482SJ. Bruce Fields 					slot->sl_flags & NFSD4_SLOT_INUSE);
2783b85d4c01SBenny Halevy 	if (status == nfserr_replay_cache) {
2784bf5c43c8SJ. Bruce Fields 		status = nfserr_seq_misordered;
2785bf5c43c8SJ. Bruce Fields 		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
278666b2b9b2SJ. Bruce Fields 			goto out_put_session;
2787b85d4c01SBenny Halevy 		cstate->slot = slot;
2788b85d4c01SBenny Halevy 		cstate->session = session;
27894b24ca7dSJeff Layton 		cstate->clp = clp;
2790da3846a2SAndy Adamson 		/* Return the cached reply status and set cstate->status
2791557ce264SAndy Adamson 		 * for nfsd4_proc_compound processing */
2792bf864a31SAndy Adamson 		status = nfsd4_replay_cache_entry(resp, seq);
2793da3846a2SAndy Adamson 		cstate->status = nfserr_replay_cache;
2794aaf84eb9SBenny Halevy 		goto out;
2795b85d4c01SBenny Halevy 	}
2796b85d4c01SBenny Halevy 	if (status)
279766b2b9b2SJ. Bruce Fields 		goto out_put_session;
2798b85d4c01SBenny Halevy 
279957266a6eSJ. Bruce Fields 	status = nfsd4_sequence_check_conn(conn, session);
2800a663bdd8SJ. Bruce Fields 	conn = NULL;
280157266a6eSJ. Bruce Fields 	if (status)
280257266a6eSJ. Bruce Fields 		goto out_put_session;
2803328ead28SJ. Bruce Fields 
280447ee5298SJ. Bruce Fields 	buflen = (seq->cachethis) ?
280547ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_cached :
280647ee5298SJ. Bruce Fields 			session->se_fchannel.maxresp_sz;
280747ee5298SJ. Bruce Fields 	status = (seq->cachethis) ? nfserr_rep_too_big_to_cache :
280847ee5298SJ. Bruce Fields 				    nfserr_rep_too_big;
2809a5cddc88SJ. Bruce Fields 	if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack))
281047ee5298SJ. Bruce Fields 		goto out_put_session;
281132aaa62eSJ. Bruce Fields 	svc_reserve(rqstp, buflen);
281247ee5298SJ. Bruce Fields 
281347ee5298SJ. Bruce Fields 	status = nfs_ok;
2814b85d4c01SBenny Halevy 	/* Success! bump slot seqid */
2815b85d4c01SBenny Halevy 	slot->sl_seqid = seq->seqid;
2816bf5c43c8SJ. Bruce Fields 	slot->sl_flags |= NFSD4_SLOT_INUSE;
281773e79482SJ. Bruce Fields 	if (seq->cachethis)
281873e79482SJ. Bruce Fields 		slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
2819bf5c43c8SJ. Bruce Fields 	else
2820bf5c43c8SJ. Bruce Fields 		slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
2821b85d4c01SBenny Halevy 
2822b85d4c01SBenny Halevy 	cstate->slot = slot;
2823b85d4c01SBenny Halevy 	cstate->session = session;
28244b24ca7dSJeff Layton 	cstate->clp = clp;
2825b85d4c01SBenny Halevy 
2826b85d4c01SBenny Halevy out:
28275423732aSBenny Halevy 	switch (clp->cl_cb_state) {
28285423732aSBenny Halevy 	case NFSD4_CB_DOWN:
2829fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
28305423732aSBenny Halevy 		break;
28315423732aSBenny Halevy 	case NFSD4_CB_FAULT:
2832fc0c3dd1SBenny Halevy 		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
28335423732aSBenny Halevy 		break;
2834fc0c3dd1SBenny Halevy 	default:
2835fc0c3dd1SBenny Halevy 		seq->status_flags = 0;
28365423732aSBenny Halevy 	}
28373bd64a5bSJ. Bruce Fields 	if (!list_empty(&clp->cl_revoked))
28383bd64a5bSJ. Bruce Fields 		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
2839221a6876SJ. Bruce Fields out_no_session:
28403f42d2c4SKinglong Mee 	if (conn)
28413f42d2c4SKinglong Mee 		free_conn(conn);
2842c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
2843b85d4c01SBenny Halevy 	return status;
284466b2b9b2SJ. Bruce Fields out_put_session:
2845d4e19e70STrond Myklebust 	nfsd4_put_session_locked(session);
2846221a6876SJ. Bruce Fields 	goto out_no_session;
2847069b6ad4SAndy Adamson }
2848069b6ad4SAndy Adamson 
2849b607664eSTrond Myklebust void
2850b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp)
2851b607664eSTrond Myklebust {
2852b607664eSTrond Myklebust 	struct nfsd4_compound_state *cs = &resp->cstate;
2853b607664eSTrond Myklebust 
2854b607664eSTrond Myklebust 	if (nfsd4_has_session(cs)) {
2855b607664eSTrond Myklebust 		if (cs->status != nfserr_replay_cache) {
2856b607664eSTrond Myklebust 			nfsd4_store_cache_entry(resp);
2857b607664eSTrond Myklebust 			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
2858b607664eSTrond Myklebust 		}
2859d4e19e70STrond Myklebust 		/* Drop session reference that was taken in nfsd4_sequence() */
2860b607664eSTrond Myklebust 		nfsd4_put_session(cs->session);
28614b24ca7dSJeff Layton 	} else if (cs->clp)
28624b24ca7dSJeff Layton 		put_client_renew(cs->clp);
2863b607664eSTrond Myklebust }
2864b607664eSTrond Myklebust 
2865345c2842SMi Jinlong __be32
2866345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
2867345c2842SMi Jinlong {
28686b10ad19STrond Myklebust 	struct nfs4_client *conf, *unconf;
28696b10ad19STrond Myklebust 	struct nfs4_client *clp = NULL;
287057b7b43bSJ. Bruce Fields 	__be32 status = 0;
28718daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2872345c2842SMi Jinlong 
2873345c2842SMi Jinlong 	nfs4_lock_state();
28746b10ad19STrond Myklebust 	spin_lock(&nn->client_lock);
28750a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
28768daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(&dc->clientid, true, nn);
287778389046SJ. Bruce Fields 	WARN_ON_ONCE(conf && unconf);
2878345c2842SMi Jinlong 
2879345c2842SMi Jinlong 	if (conf) {
2880c0293b01SJ. Bruce Fields 		if (client_has_state(conf)) {
2881345c2842SMi Jinlong 			status = nfserr_clientid_busy;
2882345c2842SMi Jinlong 			goto out;
2883345c2842SMi Jinlong 		}
2884fd699b8aSJeff Layton 		status = mark_client_expired_locked(conf);
2885fd699b8aSJeff Layton 		if (status)
2886fd699b8aSJeff Layton 			goto out;
28876b10ad19STrond Myklebust 		clp = conf;
2888345c2842SMi Jinlong 	} else if (unconf)
2889345c2842SMi Jinlong 		clp = unconf;
2890345c2842SMi Jinlong 	else {
2891345c2842SMi Jinlong 		status = nfserr_stale_clientid;
2892345c2842SMi Jinlong 		goto out;
2893345c2842SMi Jinlong 	}
289457266a6eSJ. Bruce Fields 	if (!mach_creds_match(clp, rqstp)) {
28956b10ad19STrond Myklebust 		clp = NULL;
289657266a6eSJ. Bruce Fields 		status = nfserr_wrong_cred;
289757266a6eSJ. Bruce Fields 		goto out;
289857266a6eSJ. Bruce Fields 	}
28996b10ad19STrond Myklebust 	unhash_client_locked(clp);
2900345c2842SMi Jinlong out:
29016b10ad19STrond Myklebust 	spin_unlock(&nn->client_lock);
2902345c2842SMi Jinlong 	nfs4_unlock_state();
29036b10ad19STrond Myklebust 	if (clp)
29046b10ad19STrond Myklebust 		expire_client(clp);
2905345c2842SMi Jinlong 	return status;
2906345c2842SMi Jinlong }
2907345c2842SMi Jinlong 
2908069b6ad4SAndy Adamson __be32
29094dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
29104dc6ec00SJ. Bruce Fields {
291157b7b43bSJ. Bruce Fields 	__be32 status = 0;
2912bcecf1ccSMi Jinlong 
29134dc6ec00SJ. Bruce Fields 	if (rc->rca_one_fs) {
29144dc6ec00SJ. Bruce Fields 		if (!cstate->current_fh.fh_dentry)
29154dc6ec00SJ. Bruce Fields 			return nfserr_nofilehandle;
29164dc6ec00SJ. Bruce Fields 		/*
29174dc6ec00SJ. Bruce Fields 		 * We don't take advantage of the rca_one_fs case.
29184dc6ec00SJ. Bruce Fields 		 * That's OK, it's optional, we can safely ignore it.
29194dc6ec00SJ. Bruce Fields 		 */
29204dc6ec00SJ. Bruce Fields 		 return nfs_ok;
29214dc6ec00SJ. Bruce Fields 	}
2922bcecf1ccSMi Jinlong 
29234dc6ec00SJ. Bruce Fields 	nfs4_lock_state();
2924bcecf1ccSMi Jinlong 	status = nfserr_complete_already;
2925a52d726bSJeff Layton 	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
2926a52d726bSJeff Layton 			     &cstate->session->se_client->cl_flags))
2927bcecf1ccSMi Jinlong 		goto out;
2928bcecf1ccSMi Jinlong 
2929bcecf1ccSMi Jinlong 	status = nfserr_stale_clientid;
2930bcecf1ccSMi Jinlong 	if (is_client_expired(cstate->session->se_client))
29314dc6ec00SJ. Bruce Fields 		/*
29324dc6ec00SJ. Bruce Fields 		 * The following error isn't really legal.
29334dc6ec00SJ. Bruce Fields 		 * But we only get here if the client just explicitly
29344dc6ec00SJ. Bruce Fields 		 * destroyed the client.  Surely it no longer cares what
29354dc6ec00SJ. Bruce Fields 		 * error it gets back on an operation for the dead
29364dc6ec00SJ. Bruce Fields 		 * client.
29374dc6ec00SJ. Bruce Fields 		 */
2938bcecf1ccSMi Jinlong 		goto out;
2939bcecf1ccSMi Jinlong 
2940bcecf1ccSMi Jinlong 	status = nfs_ok;
29412a4317c5SJeff Layton 	nfsd4_client_record_create(cstate->session->se_client);
2942bcecf1ccSMi Jinlong out:
29434dc6ec00SJ. Bruce Fields 	nfs4_unlock_state();
2944bcecf1ccSMi Jinlong 	return status;
29454dc6ec00SJ. Bruce Fields }
29464dc6ec00SJ. Bruce Fields 
29474dc6ec00SJ. Bruce Fields __be32
2948b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2949b591480bSJ.Bruce Fields 		  struct nfsd4_setclientid *setclid)
29501da177e4SLinus Torvalds {
2951a084daf5SJ. Bruce Fields 	struct xdr_netobj 	clname = setclid->se_name;
29521da177e4SLinus Torvalds 	nfs4_verifier		clverifier = setclid->se_verf;
29533dbacee6STrond Myklebust 	struct nfs4_client	*conf, *new;
29543dbacee6STrond Myklebust 	struct nfs4_client	*unconf = NULL;
2955b37ad28bSAl Viro 	__be32 			status;
2956c212cecfSStanislav Kinsbursky 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2957a55370a3SNeilBrown 
29585cc40fd7STrond Myklebust 	new = create_client(clname, rqstp, &clverifier);
29595cc40fd7STrond Myklebust 	if (new == NULL)
29605cc40fd7STrond Myklebust 		return nfserr_jukebox;
296163db4632SJ. Bruce Fields 	/* Cases below refer to rfc 3530 section 14.2.33: */
29621da177e4SLinus Torvalds 	nfs4_lock_state();
29633dbacee6STrond Myklebust 	spin_lock(&nn->client_lock);
2964382a62e7SStanislav Kinsbursky 	conf = find_confirmed_client_by_name(&clname, nn);
296528ce6054SNeilBrown 	if (conf) {
296663db4632SJ. Bruce Fields 		/* case 0: */
29671da177e4SLinus Torvalds 		status = nfserr_clid_inuse;
2968e203d506SJ. Bruce Fields 		if (clp_used_exchangeid(conf))
2969e203d506SJ. Bruce Fields 			goto out;
2970026722c2SJ. Bruce Fields 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
2971363168b4SJeff Layton 			char addr_str[INET6_ADDRSTRLEN];
2972363168b4SJeff Layton 			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
2973363168b4SJeff Layton 				 sizeof(addr_str));
2974026722c2SJ. Bruce Fields 			dprintk("NFSD: setclientid: string in use by client "
2975363168b4SJeff Layton 				"at %s\n", addr_str);
29761da177e4SLinus Torvalds 			goto out;
29771da177e4SLinus Torvalds 		}
29781da177e4SLinus Torvalds 	}
2979a99454aaSStanislav Kinsbursky 	unconf = find_unconfirmed_client_by_name(&clname, nn);
29801da177e4SLinus Torvalds 	if (unconf)
29813dbacee6STrond Myklebust 		unhash_client_locked(unconf);
298234b232bbSJ. Bruce Fields 	if (conf && same_verf(&conf->cl_verifier, &clverifier))
298363db4632SJ. Bruce Fields 		/* case 1: probable callback update */
29841da177e4SLinus Torvalds 		copy_clid(new, conf);
298534b232bbSJ. Bruce Fields 	else /* case 4 (new client) or cases 2, 3 (client reboot): */
2986c212cecfSStanislav Kinsbursky 		gen_clid(new, nn);
29878323c3b2SJ. Bruce Fields 	new->cl_minorversion = 0;
29886f3d772fSTakuma Umeya 	gen_callback(new, setclid, rqstp);
2989ac55fdc4SJeff Layton 	add_to_unconfirmed(new);
29901da177e4SLinus Torvalds 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
29911da177e4SLinus Torvalds 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
29921da177e4SLinus Torvalds 	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
29935cc40fd7STrond Myklebust 	new = NULL;
29941da177e4SLinus Torvalds 	status = nfs_ok;
29951da177e4SLinus Torvalds out:
29963dbacee6STrond Myklebust 	spin_unlock(&nn->client_lock);
29971da177e4SLinus Torvalds 	nfs4_unlock_state();
29985cc40fd7STrond Myklebust 	if (new)
29995cc40fd7STrond Myklebust 		free_client(new);
30003dbacee6STrond Myklebust 	if (unconf)
30013dbacee6STrond Myklebust 		expire_client(unconf);
30021da177e4SLinus Torvalds 	return status;
30031da177e4SLinus Torvalds }
30041da177e4SLinus Torvalds 
30051da177e4SLinus Torvalds 
3006b37ad28bSAl Viro __be32
3007b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
3008b591480bSJ.Bruce Fields 			 struct nfsd4_compound_state *cstate,
3009b591480bSJ.Bruce Fields 			 struct nfsd4_setclientid_confirm *setclientid_confirm)
30101da177e4SLinus Torvalds {
301121ab45a4SNeilBrown 	struct nfs4_client *conf, *unconf;
3012d20c11d8SJeff Layton 	struct nfs4_client *old = NULL;
30131da177e4SLinus Torvalds 	nfs4_verifier confirm = setclientid_confirm->sc_confirm;
30141da177e4SLinus Torvalds 	clientid_t * clid = &setclientid_confirm->sc_clientid;
3015b37ad28bSAl Viro 	__be32 status;
30167f2210faSStanislav Kinsbursky 	struct nfsd_net	*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
30171da177e4SLinus Torvalds 
30182c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(clid, nn))
30191da177e4SLinus Torvalds 		return nfserr_stale_clientid;
30201da177e4SLinus Torvalds 	nfs4_lock_state();
302121ab45a4SNeilBrown 
3022d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
30238daae4dcSStanislav Kinsbursky 	conf = find_confirmed_client(clid, false, nn);
30240a7ec377SStanislav Kinsbursky 	unconf = find_unconfirmed_client(clid, false, nn);
3025a186e767SJ. Bruce Fields 	/*
30268695b90aSJ. Bruce Fields 	 * We try hard to give out unique clientid's, so if we get an
30278695b90aSJ. Bruce Fields 	 * attempt to confirm the same clientid with a different cred,
30288695b90aSJ. Bruce Fields 	 * there's a bug somewhere.  Let's charitably assume it's our
30298695b90aSJ. Bruce Fields 	 * bug.
3030a186e767SJ. Bruce Fields 	 */
30318695b90aSJ. Bruce Fields 	status = nfserr_serverfault;
30328695b90aSJ. Bruce Fields 	if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred))
30338695b90aSJ. Bruce Fields 		goto out;
30348695b90aSJ. Bruce Fields 	if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred))
30358695b90aSJ. Bruce Fields 		goto out;
303663db4632SJ. Bruce Fields 	/* cases below refer to rfc 3530 section 14.2.34: */
303790d700b7SJ. Bruce Fields 	if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) {
303890d700b7SJ. Bruce Fields 		if (conf && !unconf) /* case 2: probable retransmit */
303990d700b7SJ. Bruce Fields 			status = nfs_ok;
304090d700b7SJ. Bruce Fields 		else /* case 4: client hasn't noticed we rebooted yet? */
304190d700b7SJ. Bruce Fields 			status = nfserr_stale_clientid;
304290d700b7SJ. Bruce Fields 		goto out;
304390d700b7SJ. Bruce Fields 	}
304490d700b7SJ. Bruce Fields 	status = nfs_ok;
304590d700b7SJ. Bruce Fields 	if (conf) { /* case 1: callback update */
3046d20c11d8SJeff Layton 		old = unconf;
3047d20c11d8SJeff Layton 		unhash_client_locked(old);
30485a3c9d71SJ. Bruce Fields 		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
304990d700b7SJ. Bruce Fields 	} else { /* case 3: normal case; new or rebooted client */
3050d20c11d8SJeff Layton 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
3051d20c11d8SJeff Layton 		if (old) {
3052d20c11d8SJeff Layton 			status = mark_client_expired_locked(old);
30537abea1e8SJeff Layton 			if (status) {
30547abea1e8SJeff Layton 				old = NULL;
3055221a6876SJ. Bruce Fields 				goto out;
3056221a6876SJ. Bruce Fields 			}
30577abea1e8SJeff Layton 		}
30581da177e4SLinus Torvalds 		move_to_confirmed(unconf);
3059d20c11d8SJeff Layton 		conf = unconf;
306008e8987cSNeilBrown 	}
3061d20c11d8SJeff Layton 	get_client_locked(conf);
3062d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3063d20c11d8SJeff Layton 	nfsd4_probe_callback(conf);
3064d20c11d8SJeff Layton 	spin_lock(&nn->client_lock);
3065d20c11d8SJeff Layton 	put_client_renew_locked(conf);
30661da177e4SLinus Torvalds out:
3067d20c11d8SJeff Layton 	spin_unlock(&nn->client_lock);
3068d20c11d8SJeff Layton 	if (old)
3069d20c11d8SJeff Layton 		expire_client(old);
30701da177e4SLinus Torvalds 	nfs4_unlock_state();
30711da177e4SLinus Torvalds 	return status;
30721da177e4SLinus Torvalds }
30731da177e4SLinus Torvalds 
307432513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void)
30751da177e4SLinus Torvalds {
307632513b40SJ. Bruce Fields 	return kmem_cache_alloc(file_slab, GFP_KERNEL);
307732513b40SJ. Bruce Fields }
307832513b40SJ. Bruce Fields 
307932513b40SJ. Bruce Fields /* OPEN Share state helper functions */
3080f9c00c3aSJeff Layton static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh)
308132513b40SJ. Bruce Fields {
3082ca943217STrond Myklebust 	unsigned int hashval = file_hashval(fh);
30831da177e4SLinus Torvalds 
3084950e0118STrond Myklebust 	lockdep_assert_held(&state_lock);
3085950e0118STrond Myklebust 
30868b671b80SJ. Bruce Fields 	atomic_set(&fp->fi_ref, 1);
30871d31a253STrond Myklebust 	spin_lock_init(&fp->fi_lock);
30888beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_stateids);
30898beefa24SNeilBrown 	INIT_LIST_HEAD(&fp->fi_delegations);
3090e2cf80d7STrond Myklebust 	fh_copy_shallow(&fp->fi_fhandle, fh);
309147f9940cSMeelap Shah 	fp->fi_had_conflict = false;
3092acfdf5c3SJ. Bruce Fields 	fp->fi_lease = NULL;
3093baeb4ff0SJeff Layton 	fp->fi_share_deny = 0;
3094f9d7562fSJ. Bruce Fields 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
3095f9d7562fSJ. Bruce Fields 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
309689876f8cSJeff Layton 	hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
30971da177e4SLinus Torvalds }
30981da177e4SLinus Torvalds 
3099e8ff2a84SJ. Bruce Fields void
3100e60d4398SNeilBrown nfsd4_free_slabs(void)
3101e60d4398SNeilBrown {
3102abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3103abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3104abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3105abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3106abf1135bSChristoph Hellwig 	kmem_cache_destroy(deleg_slab);
3107e60d4398SNeilBrown }
31081da177e4SLinus Torvalds 
310972083396SBryan Schumaker int
31101da177e4SLinus Torvalds nfsd4_init_slabs(void)
31111da177e4SLinus Torvalds {
3112fe0750e5SJ. Bruce Fields 	openowner_slab = kmem_cache_create("nfsd4_openowners",
3113fe0750e5SJ. Bruce Fields 			sizeof(struct nfs4_openowner), 0, 0, NULL);
3114fe0750e5SJ. Bruce Fields 	if (openowner_slab == NULL)
3115abf1135bSChristoph Hellwig 		goto out;
3116fe0750e5SJ. Bruce Fields 	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
31173c40794bSYanchuan Nian 			sizeof(struct nfs4_lockowner), 0, 0, NULL);
3118fe0750e5SJ. Bruce Fields 	if (lockowner_slab == NULL)
3119abf1135bSChristoph Hellwig 		goto out_free_openowner_slab;
3120e60d4398SNeilBrown 	file_slab = kmem_cache_create("nfsd4_files",
312120c2df83SPaul Mundt 			sizeof(struct nfs4_file), 0, 0, NULL);
3122e60d4398SNeilBrown 	if (file_slab == NULL)
3123abf1135bSChristoph Hellwig 		goto out_free_lockowner_slab;
31245ac049acSNeilBrown 	stateid_slab = kmem_cache_create("nfsd4_stateids",
3125dcef0413SJ. Bruce Fields 			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
31265ac049acSNeilBrown 	if (stateid_slab == NULL)
3127abf1135bSChristoph Hellwig 		goto out_free_file_slab;
31285b2d21c1SNeilBrown 	deleg_slab = kmem_cache_create("nfsd4_delegations",
312920c2df83SPaul Mundt 			sizeof(struct nfs4_delegation), 0, 0, NULL);
31305b2d21c1SNeilBrown 	if (deleg_slab == NULL)
3131abf1135bSChristoph Hellwig 		goto out_free_stateid_slab;
3132e60d4398SNeilBrown 	return 0;
3133abf1135bSChristoph Hellwig 
3134abf1135bSChristoph Hellwig out_free_stateid_slab:
3135abf1135bSChristoph Hellwig 	kmem_cache_destroy(stateid_slab);
3136abf1135bSChristoph Hellwig out_free_file_slab:
3137abf1135bSChristoph Hellwig 	kmem_cache_destroy(file_slab);
3138abf1135bSChristoph Hellwig out_free_lockowner_slab:
3139abf1135bSChristoph Hellwig 	kmem_cache_destroy(lockowner_slab);
3140abf1135bSChristoph Hellwig out_free_openowner_slab:
3141abf1135bSChristoph Hellwig 	kmem_cache_destroy(openowner_slab);
3142abf1135bSChristoph Hellwig out:
31431da177e4SLinus Torvalds 	dprintk("nfsd4: out of memory while initializing nfsv4\n");
31441da177e4SLinus Torvalds 	return -ENOMEM;
31451da177e4SLinus Torvalds }
31461da177e4SLinus Torvalds 
3147ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp)
3148ff194bd9SJ. Bruce Fields {
3149ff194bd9SJ. Bruce Fields 	rp->rp_status = nfserr_serverfault;
3150ff194bd9SJ. Bruce Fields 	rp->rp_buflen = 0;
3151ff194bd9SJ. Bruce Fields 	rp->rp_buf = rp->rp_ibuf;
315258fb12e6SJeff Layton 	mutex_init(&rp->rp_mutex);
315358fb12e6SJeff Layton }
315458fb12e6SJeff Layton 
315558fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
315658fb12e6SJeff Layton 		struct nfs4_stateowner *so)
315758fb12e6SJeff Layton {
315858fb12e6SJeff Layton 	if (!nfsd4_has_session(cstate)) {
315958fb12e6SJeff Layton 		mutex_lock(&so->so_replay.rp_mutex);
316058fb12e6SJeff Layton 		cstate->replay_owner = so;
316158fb12e6SJeff Layton 		atomic_inc(&so->so_count);
316258fb12e6SJeff Layton 	}
316358fb12e6SJeff Layton }
316458fb12e6SJeff Layton 
316558fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate)
316658fb12e6SJeff Layton {
316758fb12e6SJeff Layton 	struct nfs4_stateowner *so = cstate->replay_owner;
316858fb12e6SJeff Layton 
316958fb12e6SJeff Layton 	if (so != NULL) {
317058fb12e6SJeff Layton 		cstate->replay_owner = NULL;
317158fb12e6SJeff Layton 		mutex_unlock(&so->so_replay.rp_mutex);
317258fb12e6SJeff Layton 		nfs4_put_stateowner(so);
317358fb12e6SJeff Layton 	}
3174ff194bd9SJ. Bruce Fields }
3175ff194bd9SJ. Bruce Fields 
3176fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
31771da177e4SLinus Torvalds {
31781da177e4SLinus Torvalds 	struct nfs4_stateowner *sop;
31791da177e4SLinus Torvalds 
3180fe0750e5SJ. Bruce Fields 	sop = kmem_cache_alloc(slab, GFP_KERNEL);
3181ff194bd9SJ. Bruce Fields 	if (!sop)
3182ff194bd9SJ. Bruce Fields 		return NULL;
3183ff194bd9SJ. Bruce Fields 
3184ff194bd9SJ. Bruce Fields 	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
3185ff194bd9SJ. Bruce Fields 	if (!sop->so_owner.data) {
3186fe0750e5SJ. Bruce Fields 		kmem_cache_free(slab, sop);
3187ff194bd9SJ. Bruce Fields 		return NULL;
3188ff194bd9SJ. Bruce Fields 	}
31891da177e4SLinus Torvalds 	sop->so_owner.len = owner->len;
3190ff194bd9SJ. Bruce Fields 
3191ff194bd9SJ. Bruce Fields 	INIT_LIST_HEAD(&sop->so_stateids);
3192ff194bd9SJ. Bruce Fields 	sop->so_client = clp;
3193ff194bd9SJ. Bruce Fields 	init_nfs4_replay(&sop->so_replay);
31946b180f0bSJeff Layton 	atomic_set(&sop->so_count, 1);
31951da177e4SLinus Torvalds 	return sop;
31961da177e4SLinus Torvalds }
3197ff194bd9SJ. Bruce Fields 
3198fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
3199ff194bd9SJ. Bruce Fields {
3200d4f0489fSTrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
32019b531137SStanislav Kinsbursky 
3202d4f0489fSTrond Myklebust 	list_add(&oo->oo_owner.so_strhash,
3203d4f0489fSTrond Myklebust 		 &clp->cl_ownerstr_hashtbl[strhashval]);
3204fe0750e5SJ. Bruce Fields 	list_add(&oo->oo_perclient, &clp->cl_openowners);
32051da177e4SLinus Torvalds }
32061da177e4SLinus Torvalds 
32078f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
32088f4b54c5SJeff Layton {
3209d4f0489fSTrond Myklebust 	unhash_openowner_locked(openowner(so));
32108f4b54c5SJeff Layton }
32118f4b54c5SJeff Layton 
32126b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so)
32136b180f0bSJeff Layton {
32146b180f0bSJeff Layton 	struct nfs4_openowner *oo = openowner(so);
32156b180f0bSJeff Layton 
32166b180f0bSJeff Layton 	kmem_cache_free(openowner_slab, oo);
32176b180f0bSJeff Layton }
32186b180f0bSJeff Layton 
32196b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = {
32208f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_openowner,
32216b180f0bSJeff Layton 	.so_free =	nfs4_free_openowner,
32226b180f0bSJeff Layton };
32236b180f0bSJeff Layton 
3224fe0750e5SJ. Bruce Fields static struct nfs4_openowner *
322513d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3226db24b3b4SJeff Layton 			   struct nfsd4_compound_state *cstate)
3227db24b3b4SJeff Layton {
322813d6f66bSTrond Myklebust 	struct nfs4_client *clp = cstate->clp;
32297ffb5880STrond Myklebust 	struct nfs4_openowner *oo, *ret;
32301da177e4SLinus Torvalds 
3231fe0750e5SJ. Bruce Fields 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
3232fe0750e5SJ. Bruce Fields 	if (!oo)
32331da177e4SLinus Torvalds 		return NULL;
32346b180f0bSJeff Layton 	oo->oo_owner.so_ops = &openowner_ops;
3235fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_is_open_owner = 1;
3236fe0750e5SJ. Bruce Fields 	oo->oo_owner.so_seqid = open->op_seqid;
3237d3134b10SJeff Layton 	oo->oo_flags = 0;
3238db24b3b4SJeff Layton 	if (nfsd4_has_session(cstate))
3239db24b3b4SJeff Layton 		oo->oo_flags |= NFS4_OO_CONFIRMED;
3240fe0750e5SJ. Bruce Fields 	oo->oo_time = 0;
324138c387b5SJ. Bruce Fields 	oo->oo_last_closed_stid = NULL;
3242fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&oo->oo_close_lru);
3243d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
3244d4f0489fSTrond Myklebust 	ret = find_openstateowner_str_locked(strhashval, open, clp);
32457ffb5880STrond Myklebust 	if (ret == NULL) {
3246fe0750e5SJ. Bruce Fields 		hash_openowner(oo, clp, strhashval);
32477ffb5880STrond Myklebust 		ret = oo;
32487ffb5880STrond Myklebust 	} else
32497ffb5880STrond Myklebust 		nfs4_free_openowner(&oo->oo_owner);
3250d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
3251fe0750e5SJ. Bruce Fields 	return oo;
32521da177e4SLinus Torvalds }
32531da177e4SLinus Torvalds 
3254996e0938SJ. Bruce Fields static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
3255fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = open->op_openowner;
32561da177e4SLinus Torvalds 
3257d6f2bc5dSTrond Myklebust 	atomic_inc(&stp->st_stid.sc_count);
32583abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_OPEN_STID;
32593c87b9b7STrond Myklebust 	INIT_LIST_HEAD(&stp->st_locks);
3260fe0750e5SJ. Bruce Fields 	stp->st_stateowner = &oo->oo_owner;
3261d3134b10SJeff Layton 	atomic_inc(&stp->st_stateowner->so_count);
326213cd2184SNeilBrown 	get_nfs4_file(fp);
326311b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
32641da177e4SLinus Torvalds 	stp->st_access_bmap = 0;
32651da177e4SLinus Torvalds 	stp->st_deny_bmap = 0;
32664c4cd222SNeilBrown 	stp->st_openstp = NULL;
32671c755dc1SJeff Layton 	spin_lock(&oo->oo_owner.so_client->cl_lock);
32681c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
32691d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
32701d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
32711d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
32721c755dc1SJeff Layton 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
32731da177e4SLinus Torvalds }
32741da177e4SLinus Torvalds 
3275d3134b10SJeff Layton /*
3276d3134b10SJeff Layton  * In the 4.0 case we need to keep the owners around a little while to handle
3277d3134b10SJeff Layton  * CLOSE replay. We still do need to release any file access that is held by
3278d3134b10SJeff Layton  * them before returning however.
3279d3134b10SJeff Layton  */
32801da177e4SLinus Torvalds static void
3281d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
32821da177e4SLinus Torvalds {
3283217526e7SJeff Layton 	struct nfs4_ol_stateid *last;
3284d3134b10SJeff Layton 	struct nfs4_openowner *oo = openowner(s->st_stateowner);
3285d3134b10SJeff Layton 	struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net,
3286d3134b10SJeff Layton 						nfsd_net_id);
328773758fedSStanislav Kinsbursky 
3288fe0750e5SJ. Bruce Fields 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
32891da177e4SLinus Torvalds 
3290b401be22SJeff Layton 	/*
3291b401be22SJeff Layton 	 * We know that we hold one reference via nfsd4_close, and another
3292b401be22SJeff Layton 	 * "persistent" reference for the client. If the refcount is higher
3293b401be22SJeff Layton 	 * than 2, then there are still calls in progress that are using this
3294b401be22SJeff Layton 	 * stateid. We can't put the sc_file reference until they are finished.
3295b401be22SJeff Layton 	 * Wait for the refcount to drop to 2. Since it has been unhashed,
3296b401be22SJeff Layton 	 * there should be no danger of the refcount going back up again at
3297b401be22SJeff Layton 	 * this point.
3298b401be22SJeff Layton 	 */
3299b401be22SJeff Layton 	wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2);
3300b401be22SJeff Layton 
3301d3134b10SJeff Layton 	release_all_access(s);
3302d3134b10SJeff Layton 	if (s->st_stid.sc_file) {
3303d3134b10SJeff Layton 		put_nfs4_file(s->st_stid.sc_file);
3304d3134b10SJeff Layton 		s->st_stid.sc_file = NULL;
3305d3134b10SJeff Layton 	}
3306217526e7SJeff Layton 
3307217526e7SJeff Layton 	spin_lock(&nn->client_lock);
3308217526e7SJeff Layton 	last = oo->oo_last_closed_stid;
3309d3134b10SJeff Layton 	oo->oo_last_closed_stid = s;
331073758fedSStanislav Kinsbursky 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
3311fe0750e5SJ. Bruce Fields 	oo->oo_time = get_seconds();
3312217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
3313217526e7SJeff Layton 	if (last)
3314217526e7SJeff Layton 		nfs4_put_stid(&last->st_stid);
33151da177e4SLinus Torvalds }
33161da177e4SLinus Torvalds 
33171da177e4SLinus Torvalds /* search file_hashtbl[] for file */
33181da177e4SLinus Torvalds static struct nfs4_file *
3319ca943217STrond Myklebust find_file_locked(struct knfsd_fh *fh)
33201da177e4SLinus Torvalds {
3321ca943217STrond Myklebust 	unsigned int hashval = file_hashval(fh);
33221da177e4SLinus Torvalds 	struct nfs4_file *fp;
33231da177e4SLinus Torvalds 
3324950e0118STrond Myklebust 	lockdep_assert_held(&state_lock);
3325950e0118STrond Myklebust 
332689876f8cSJeff Layton 	hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
3327ca943217STrond Myklebust 		if (nfsd_fh_match(&fp->fi_fhandle, fh)) {
332813cd2184SNeilBrown 			get_nfs4_file(fp);
33291da177e4SLinus Torvalds 			return fp;
33301da177e4SLinus Torvalds 		}
333113cd2184SNeilBrown 	}
33321da177e4SLinus Torvalds 	return NULL;
33331da177e4SLinus Torvalds }
33341da177e4SLinus Torvalds 
3335950e0118STrond Myklebust static struct nfs4_file *
3336ca943217STrond Myklebust find_file(struct knfsd_fh *fh)
3337950e0118STrond Myklebust {
3338950e0118STrond Myklebust 	struct nfs4_file *fp;
3339950e0118STrond Myklebust 
3340950e0118STrond Myklebust 	spin_lock(&state_lock);
3341ca943217STrond Myklebust 	fp = find_file_locked(fh);
3342950e0118STrond Myklebust 	spin_unlock(&state_lock);
3343950e0118STrond Myklebust 	return fp;
3344950e0118STrond Myklebust }
3345950e0118STrond Myklebust 
3346950e0118STrond Myklebust static struct nfs4_file *
3347f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh)
3348950e0118STrond Myklebust {
3349950e0118STrond Myklebust 	struct nfs4_file *fp;
3350950e0118STrond Myklebust 
3351950e0118STrond Myklebust 	spin_lock(&state_lock);
3352ca943217STrond Myklebust 	fp = find_file_locked(fh);
3353950e0118STrond Myklebust 	if (fp == NULL) {
3354f9c00c3aSJeff Layton 		nfsd4_init_file(new, fh);
3355950e0118STrond Myklebust 		fp = new;
3356950e0118STrond Myklebust 	}
3357950e0118STrond Myklebust 	spin_unlock(&state_lock);
3358950e0118STrond Myklebust 
3359950e0118STrond Myklebust 	return fp;
3360950e0118STrond Myklebust }
3361950e0118STrond Myklebust 
33624f83aa30SJ. Bruce Fields /*
33631da177e4SLinus Torvalds  * Called to check deny when READ with all zero stateid or
33641da177e4SLinus Torvalds  * WRITE with all zero or all one stateid
33651da177e4SLinus Torvalds  */
3366b37ad28bSAl Viro static __be32
33671da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
33681da177e4SLinus Torvalds {
33691da177e4SLinus Torvalds 	struct nfs4_file *fp;
3370baeb4ff0SJeff Layton 	__be32 ret = nfs_ok;
33711da177e4SLinus Torvalds 
3372ca943217STrond Myklebust 	fp = find_file(&current_fh->fh_handle);
337313cd2184SNeilBrown 	if (!fp)
3374baeb4ff0SJeff Layton 		return ret;
3375baeb4ff0SJeff Layton 	/* Check for conflicting share reservations */
33761d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
3377baeb4ff0SJeff Layton 	if (fp->fi_share_deny & deny_type)
3378baeb4ff0SJeff Layton 		ret = nfserr_locked;
33791d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
338013cd2184SNeilBrown 	put_nfs4_file(fp);
338113cd2184SNeilBrown 	return ret;
33821da177e4SLinus Torvalds }
33831da177e4SLinus Torvalds 
338402e1215fSJeff Layton void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp)
33851da177e4SLinus Torvalds {
338611b9164aSTrond Myklebust 	struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net,
338711b9164aSTrond Myklebust 					  nfsd_net_id);
3388e8c69d17SJ. Bruce Fields 
338911b9164aSTrond Myklebust 	block_delegations(&dp->dl_stid.sc_file->fi_fhandle);
3390f54fe962SJeff Layton 
339102e1215fSJeff Layton 	/*
339202e1215fSJeff Layton 	 * We can't do this in nfsd_break_deleg_cb because it is
3393f54fe962SJeff Layton 	 * already holding inode->i_lock.
3394f54fe962SJeff Layton 	 *
3395dff1399fSJeff Layton 	 * If the dl_time != 0, then we know that it has already been
3396dff1399fSJeff Layton 	 * queued for a lease break. Don't queue it again.
3397dff1399fSJeff Layton 	 */
3398f54fe962SJeff Layton 	spin_lock(&state_lock);
3399dff1399fSJeff Layton 	if (dp->dl_time == 0) {
34001da177e4SLinus Torvalds 		dp->dl_time = get_seconds();
340102e1215fSJeff Layton 		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
340202e1215fSJeff Layton 	}
340302e1215fSJeff Layton 	spin_unlock(&state_lock);
3404dff1399fSJeff Layton }
34051da177e4SLinus Torvalds 
340602e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
340702e1215fSJeff Layton {
340802e1215fSJeff Layton 	/*
340902e1215fSJeff Layton 	 * We're assuming the state code never drops its reference
341002e1215fSJeff Layton 	 * without first removing the lease.  Since we're in this lease
341102e1215fSJeff Layton 	 * callback (and since the lease code is serialized by the kernel
341202e1215fSJeff Layton 	 * lock) we know the server hasn't removed the lease yet, we know
341302e1215fSJeff Layton 	 * it's safe to take a reference.
341402e1215fSJeff Layton 	 */
341572c0b0fbSTrond Myklebust 	atomic_inc(&dp->dl_stid.sc_count);
34166b57d9c8SJ. Bruce Fields 	nfsd4_cb_recall(dp);
34176b57d9c8SJ. Bruce Fields }
34186b57d9c8SJ. Bruce Fields 
34191c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */
34206b57d9c8SJ. Bruce Fields static void nfsd_break_deleg_cb(struct file_lock *fl)
34216b57d9c8SJ. Bruce Fields {
3422acfdf5c3SJ. Bruce Fields 	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
3423acfdf5c3SJ. Bruce Fields 	struct nfs4_delegation *dp;
34246b57d9c8SJ. Bruce Fields 
34257fa10cd1SJ. Bruce Fields 	if (!fp) {
34267fa10cd1SJ. Bruce Fields 		WARN(1, "(%p)->fl_owner NULL\n", fl);
34277fa10cd1SJ. Bruce Fields 		return;
34287fa10cd1SJ. Bruce Fields 	}
34297fa10cd1SJ. Bruce Fields 	if (fp->fi_had_conflict) {
34307fa10cd1SJ. Bruce Fields 		WARN(1, "duplicate break on %p\n", fp);
34317fa10cd1SJ. Bruce Fields 		return;
34327fa10cd1SJ. Bruce Fields 	}
34330272e1fdSJ. Bruce Fields 	/*
34340272e1fdSJ. Bruce Fields 	 * We don't want the locks code to timeout the lease for us;
3435acfdf5c3SJ. Bruce Fields 	 * we'll remove it ourself if a delegation isn't returned
34366b57d9c8SJ. Bruce Fields 	 * in time:
34370272e1fdSJ. Bruce Fields 	 */
34380272e1fdSJ. Bruce Fields 	fl->fl_break_time = 0;
34391da177e4SLinus Torvalds 
344002e1215fSJeff Layton 	spin_lock(&fp->fi_lock);
3441417c6629SJeff Layton 	fp->fi_had_conflict = true;
3442417c6629SJeff Layton 	/*
3443417c6629SJeff Layton 	 * If there are no delegations on the list, then we can't count on this
3444417c6629SJeff Layton 	 * lease ever being cleaned up. Set the fl_break_time to jiffies so that
3445417c6629SJeff Layton 	 * time_out_leases will do it ASAP. The fact that fi_had_conflict is now
3446417c6629SJeff Layton 	 * true should keep any new delegations from being hashed.
3447417c6629SJeff Layton 	 */
3448417c6629SJeff Layton 	if (list_empty(&fp->fi_delegations))
3449417c6629SJeff Layton 		fl->fl_break_time = jiffies;
3450417c6629SJeff Layton 	else
3451acfdf5c3SJ. Bruce Fields 		list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
34525d926e8cSJ. Bruce Fields 			nfsd_break_one_deleg(dp);
345302e1215fSJeff Layton 	spin_unlock(&fp->fi_lock);
34541da177e4SLinus Torvalds }
34551da177e4SLinus Torvalds 
34561da177e4SLinus Torvalds static
34571da177e4SLinus Torvalds int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
34581da177e4SLinus Torvalds {
34591da177e4SLinus Torvalds 	if (arg & F_UNLCK)
34601da177e4SLinus Torvalds 		return lease_modify(onlist, arg);
34611da177e4SLinus Torvalds 	else
34621da177e4SLinus Torvalds 		return -EAGAIN;
34631da177e4SLinus Torvalds }
34641da177e4SLinus Torvalds 
34657b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = {
34668fb47a4fSJ. Bruce Fields 	.lm_break = nfsd_break_deleg_cb,
34678fb47a4fSJ. Bruce Fields 	.lm_change = nfsd_change_deleg_cb,
34681da177e4SLinus Torvalds };
34691da177e4SLinus Torvalds 
34707a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
34717a8711c9SJ. Bruce Fields {
34727a8711c9SJ. Bruce Fields 	if (nfsd4_has_session(cstate))
34737a8711c9SJ. Bruce Fields 		return nfs_ok;
34747a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid - 1)
34757a8711c9SJ. Bruce Fields 		return nfserr_replay_me;
34767a8711c9SJ. Bruce Fields 	if (seqid == so->so_seqid)
34777a8711c9SJ. Bruce Fields 		return nfs_ok;
34787a8711c9SJ. Bruce Fields 	return nfserr_bad_seqid;
34797a8711c9SJ. Bruce Fields }
34801da177e4SLinus Torvalds 
34814b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid,
34824b24ca7dSJeff Layton 		struct nfsd4_compound_state *cstate,
34834b24ca7dSJeff Layton 		struct nfsd_net *nn)
34844b24ca7dSJeff Layton {
34854b24ca7dSJeff Layton 	struct nfs4_client *found;
34864b24ca7dSJeff Layton 
34874b24ca7dSJeff Layton 	if (cstate->clp) {
34884b24ca7dSJeff Layton 		found = cstate->clp;
34894b24ca7dSJeff Layton 		if (!same_clid(&found->cl_clientid, clid))
34904b24ca7dSJeff Layton 			return nfserr_stale_clientid;
34914b24ca7dSJeff Layton 		return nfs_ok;
34924b24ca7dSJeff Layton 	}
34934b24ca7dSJeff Layton 
34944b24ca7dSJeff Layton 	if (STALE_CLIENTID(clid, nn))
34954b24ca7dSJeff Layton 		return nfserr_stale_clientid;
34964b24ca7dSJeff Layton 
34974b24ca7dSJeff Layton 	/*
34984b24ca7dSJeff Layton 	 * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
34994b24ca7dSJeff Layton 	 * cached already then we know this is for is for v4.0 and "sessions"
35004b24ca7dSJeff Layton 	 * will be false.
35014b24ca7dSJeff Layton 	 */
35024b24ca7dSJeff Layton 	WARN_ON_ONCE(cstate->session);
35033e339f96STrond Myklebust 	spin_lock(&nn->client_lock);
35044b24ca7dSJeff Layton 	found = find_confirmed_client(clid, false, nn);
35053e339f96STrond Myklebust 	if (!found) {
35063e339f96STrond Myklebust 		spin_unlock(&nn->client_lock);
35074b24ca7dSJeff Layton 		return nfserr_expired;
35083e339f96STrond Myklebust 	}
35093e339f96STrond Myklebust 	atomic_inc(&found->cl_refcount);
35103e339f96STrond Myklebust 	spin_unlock(&nn->client_lock);
35114b24ca7dSJeff Layton 
35124b24ca7dSJeff Layton 	/* Cache the nfs4_client in cstate! */
35134b24ca7dSJeff Layton 	cstate->clp = found;
35144b24ca7dSJeff Layton 	return nfs_ok;
35154b24ca7dSJeff Layton }
35164b24ca7dSJeff Layton 
3517b37ad28bSAl Viro __be32
35186668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate,
35193320fef1SStanislav Kinsbursky 		    struct nfsd4_open *open, struct nfsd_net *nn)
35201da177e4SLinus Torvalds {
35211da177e4SLinus Torvalds 	clientid_t *clientid = &open->op_clientid;
35221da177e4SLinus Torvalds 	struct nfs4_client *clp = NULL;
35231da177e4SLinus Torvalds 	unsigned int strhashval;
3524fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = NULL;
35254cdc951bSJ. Bruce Fields 	__be32 status;
35261da177e4SLinus Torvalds 
35272c142baaSStanislav Kinsbursky 	if (STALE_CLIENTID(&open->op_clientid, nn))
35281da177e4SLinus Torvalds 		return nfserr_stale_clientid;
352932513b40SJ. Bruce Fields 	/*
353032513b40SJ. Bruce Fields 	 * In case we need it later, after we've already created the
353132513b40SJ. Bruce Fields 	 * file and don't want to risk a further failure:
353232513b40SJ. Bruce Fields 	 */
353332513b40SJ. Bruce Fields 	open->op_file = nfsd4_alloc_file();
353432513b40SJ. Bruce Fields 	if (open->op_file == NULL)
353532513b40SJ. Bruce Fields 		return nfserr_jukebox;
35361da177e4SLinus Torvalds 
353713d6f66bSTrond Myklebust 	status = lookup_clientid(clientid, cstate, nn);
353813d6f66bSTrond Myklebust 	if (status)
353913d6f66bSTrond Myklebust 		return status;
354013d6f66bSTrond Myklebust 	clp = cstate->clp;
35412d91e895STrond Myklebust 
3542d4f0489fSTrond Myklebust 	strhashval = ownerstr_hashval(&open->op_owner);
3543d4f0489fSTrond Myklebust 	oo = find_openstateowner_str(strhashval, open, clp);
35442d91e895STrond Myklebust 	open->op_openowner = oo;
35452d91e895STrond Myklebust 	if (!oo) {
3546bcf130f9SJ. Bruce Fields 		goto new_owner;
35470f442aa2SJ. Bruce Fields 	}
3548dad1c067SJ. Bruce Fields 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
35490f442aa2SJ. Bruce Fields 		/* Replace unconfirmed owners without checking for replay. */
3550fe0750e5SJ. Bruce Fields 		release_openowner(oo);
3551fe0750e5SJ. Bruce Fields 		open->op_openowner = NULL;
3552bcf130f9SJ. Bruce Fields 		goto new_owner;
35530f442aa2SJ. Bruce Fields 	}
35544cdc951bSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
35554cdc951bSJ. Bruce Fields 	if (status)
35564cdc951bSJ. Bruce Fields 		return status;
35574cdc951bSJ. Bruce Fields 	goto alloc_stateid;
3558bcf130f9SJ. Bruce Fields new_owner:
355913d6f66bSTrond Myklebust 	oo = alloc_init_open_stateowner(strhashval, open, cstate);
3560fe0750e5SJ. Bruce Fields 	if (oo == NULL)
35613e772463SJ. Bruce Fields 		return nfserr_jukebox;
3562fe0750e5SJ. Bruce Fields 	open->op_openowner = oo;
35634cdc951bSJ. Bruce Fields alloc_stateid:
3564b49e084dSJeff Layton 	open->op_stp = nfs4_alloc_open_stateid(clp);
35654cdc951bSJ. Bruce Fields 	if (!open->op_stp)
35664cdc951bSJ. Bruce Fields 		return nfserr_jukebox;
35670f442aa2SJ. Bruce Fields 	return nfs_ok;
35681da177e4SLinus Torvalds }
35691da177e4SLinus Torvalds 
3570b37ad28bSAl Viro static inline __be32
35714a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
35724a6e43e6SNeilBrown {
35734a6e43e6SNeilBrown 	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
35744a6e43e6SNeilBrown 		return nfserr_openmode;
35754a6e43e6SNeilBrown 	else
35764a6e43e6SNeilBrown 		return nfs_ok;
35774a6e43e6SNeilBrown }
35784a6e43e6SNeilBrown 
3579c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access)
358024a0111eSJ. Bruce Fields {
358124a0111eSJ. Bruce Fields 	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
358224a0111eSJ. Bruce Fields }
358324a0111eSJ. Bruce Fields 
358438c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
3585f459e453SJ. Bruce Fields {
3586f459e453SJ. Bruce Fields 	struct nfs4_stid *ret;
3587f459e453SJ. Bruce Fields 
358838c2f4b1SJ. Bruce Fields 	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
3589f459e453SJ. Bruce Fields 	if (!ret)
3590f459e453SJ. Bruce Fields 		return NULL;
3591f459e453SJ. Bruce Fields 	return delegstateid(ret);
3592f459e453SJ. Bruce Fields }
3593f459e453SJ. Bruce Fields 
35948b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
35958b289b2cSJ. Bruce Fields {
35968b289b2cSJ. Bruce Fields 	return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
35978b289b2cSJ. Bruce Fields 	       open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
35988b289b2cSJ. Bruce Fields }
35998b289b2cSJ. Bruce Fields 
3600b37ad28bSAl Viro static __be32
360141d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
3602567d9829SNeilBrown 		struct nfs4_delegation **dp)
3603567d9829SNeilBrown {
3604567d9829SNeilBrown 	int flags;
3605b37ad28bSAl Viro 	__be32 status = nfserr_bad_stateid;
3606dcd94cc2STrond Myklebust 	struct nfs4_delegation *deleg;
3607567d9829SNeilBrown 
3608dcd94cc2STrond Myklebust 	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
3609dcd94cc2STrond Myklebust 	if (deleg == NULL)
3610c44c5eebSNeilBrown 		goto out;
361124a0111eSJ. Bruce Fields 	flags = share_access_to_flags(open->op_share_access);
3612dcd94cc2STrond Myklebust 	status = nfs4_check_delegmode(deleg, flags);
3613dcd94cc2STrond Myklebust 	if (status) {
3614dcd94cc2STrond Myklebust 		nfs4_put_stid(&deleg->dl_stid);
3615dcd94cc2STrond Myklebust 		goto out;
3616dcd94cc2STrond Myklebust 	}
3617dcd94cc2STrond Myklebust 	*dp = deleg;
3618c44c5eebSNeilBrown out:
36198b289b2cSJ. Bruce Fields 	if (!nfsd4_is_deleg_cur(open))
3620c44c5eebSNeilBrown 		return nfs_ok;
3621c44c5eebSNeilBrown 	if (status)
3622c44c5eebSNeilBrown 		return status;
3623dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
3624c44c5eebSNeilBrown 	return nfs_ok;
3625567d9829SNeilBrown }
3626567d9829SNeilBrown 
3627a46cb7f2SJeff Layton static struct nfs4_ol_stateid *
3628a46cb7f2SJeff Layton nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
36291da177e4SLinus Torvalds {
3630a46cb7f2SJeff Layton 	struct nfs4_ol_stateid *local, *ret = NULL;
3631fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo = open->op_openowner;
36321da177e4SLinus Torvalds 
36331d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
36348beefa24SNeilBrown 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
36351da177e4SLinus Torvalds 		/* ignore lock owners */
36361da177e4SLinus Torvalds 		if (local->st_stateowner->so_is_open_owner == 0)
36371da177e4SLinus Torvalds 			continue;
3638baeb4ff0SJeff Layton 		if (local->st_stateowner == &oo->oo_owner) {
3639a46cb7f2SJeff Layton 			ret = local;
3640d6f2bc5dSTrond Myklebust 			atomic_inc(&ret->st_stid.sc_count);
3641baeb4ff0SJeff Layton 			break;
36421da177e4SLinus Torvalds 		}
36431d31a253STrond Myklebust 	}
36441d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
3645a46cb7f2SJeff Layton 	return ret;
36461da177e4SLinus Torvalds }
36471da177e4SLinus Torvalds 
364821fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access)
364921fb4016SJ. Bruce Fields {
365021fb4016SJ. Bruce Fields 	int flags = 0;
365121fb4016SJ. Bruce Fields 
365221fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
365321fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_READ;
365421fb4016SJ. Bruce Fields 	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
365521fb4016SJ. Bruce Fields 		flags |= NFSD_MAY_WRITE;
365621fb4016SJ. Bruce Fields 	return flags;
365721fb4016SJ. Bruce Fields }
365821fb4016SJ. Bruce Fields 
3659b37ad28bSAl Viro static inline __be32
36601da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
36611da177e4SLinus Torvalds 		struct nfsd4_open *open)
36621da177e4SLinus Torvalds {
36631da177e4SLinus Torvalds 	struct iattr iattr = {
36641da177e4SLinus Torvalds 		.ia_valid = ATTR_SIZE,
36651da177e4SLinus Torvalds 		.ia_size = 0,
36661da177e4SLinus Torvalds 	};
36671da177e4SLinus Torvalds 	if (!open->op_truncate)
36681da177e4SLinus Torvalds 		return 0;
36691da177e4SLinus Torvalds 	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
36709246585aSAl Viro 		return nfserr_inval;
36711da177e4SLinus Torvalds 	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
36721da177e4SLinus Torvalds }
36731da177e4SLinus Torvalds 
36747e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
36756eb3a1d0SJeff Layton 		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
36766eb3a1d0SJeff Layton 		struct nfsd4_open *open)
36777e6a72e5SChristoph Hellwig {
3678de18643dSTrond Myklebust 	struct file *filp = NULL;
36797e6a72e5SChristoph Hellwig 	__be32 status;
36807e6a72e5SChristoph Hellwig 	int oflag = nfs4_access_to_omode(open->op_share_access);
36817e6a72e5SChristoph Hellwig 	int access = nfs4_access_to_access(open->op_share_access);
3682baeb4ff0SJeff Layton 	unsigned char old_access_bmap, old_deny_bmap;
36837e6a72e5SChristoph Hellwig 
3684de18643dSTrond Myklebust 	spin_lock(&fp->fi_lock);
3685baeb4ff0SJeff Layton 
3686baeb4ff0SJeff Layton 	/*
3687baeb4ff0SJeff Layton 	 * Are we trying to set a deny mode that would conflict with
3688baeb4ff0SJeff Layton 	 * current access?
3689baeb4ff0SJeff Layton 	 */
3690baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
3691baeb4ff0SJeff Layton 	if (status != nfs_ok) {
3692baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
3693baeb4ff0SJeff Layton 		goto out;
3694baeb4ff0SJeff Layton 	}
3695baeb4ff0SJeff Layton 
3696baeb4ff0SJeff Layton 	/* set access to the file */
3697baeb4ff0SJeff Layton 	status = nfs4_file_get_access(fp, open->op_share_access);
3698baeb4ff0SJeff Layton 	if (status != nfs_ok) {
3699baeb4ff0SJeff Layton 		spin_unlock(&fp->fi_lock);
3700baeb4ff0SJeff Layton 		goto out;
3701baeb4ff0SJeff Layton 	}
3702baeb4ff0SJeff Layton 
3703baeb4ff0SJeff Layton 	/* Set access bits in stateid */
3704baeb4ff0SJeff Layton 	old_access_bmap = stp->st_access_bmap;
3705baeb4ff0SJeff Layton 	set_access(open->op_share_access, stp);
3706baeb4ff0SJeff Layton 
3707baeb4ff0SJeff Layton 	/* Set new deny mask */
3708baeb4ff0SJeff Layton 	old_deny_bmap = stp->st_deny_bmap;
3709baeb4ff0SJeff Layton 	set_deny(open->op_share_deny, stp);
3710baeb4ff0SJeff Layton 	fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH);
3711baeb4ff0SJeff Layton 
37127e6a72e5SChristoph Hellwig 	if (!fp->fi_fds[oflag]) {
3713de18643dSTrond Myklebust 		spin_unlock(&fp->fi_lock);
3714de18643dSTrond Myklebust 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
37157e6a72e5SChristoph Hellwig 		if (status)
3716baeb4ff0SJeff Layton 			goto out_put_access;
3717de18643dSTrond Myklebust 		spin_lock(&fp->fi_lock);
3718de18643dSTrond Myklebust 		if (!fp->fi_fds[oflag]) {
3719de18643dSTrond Myklebust 			fp->fi_fds[oflag] = filp;
3720de18643dSTrond Myklebust 			filp = NULL;
3721de18643dSTrond Myklebust 		}
37227e6a72e5SChristoph Hellwig 	}
3723de18643dSTrond Myklebust 	spin_unlock(&fp->fi_lock);
3724de18643dSTrond Myklebust 	if (filp)
3725de18643dSTrond Myklebust 		fput(filp);
37267e6a72e5SChristoph Hellwig 
37277e6a72e5SChristoph Hellwig 	status = nfsd4_truncate(rqstp, cur_fh, open);
37287e6a72e5SChristoph Hellwig 	if (status)
37297e6a72e5SChristoph Hellwig 		goto out_put_access;
37307e6a72e5SChristoph Hellwig out:
37317e6a72e5SChristoph Hellwig 	return status;
3732baeb4ff0SJeff Layton out_put_access:
3733baeb4ff0SJeff Layton 	stp->st_access_bmap = old_access_bmap;
3734baeb4ff0SJeff Layton 	nfs4_file_put_access(fp, open->op_share_access);
3735baeb4ff0SJeff Layton 	reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp);
3736baeb4ff0SJeff Layton 	goto out;
37377e6a72e5SChristoph Hellwig }
37387e6a72e5SChristoph Hellwig 
3739b37ad28bSAl Viro static __be32
3740dcef0413SJ. 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)
37411da177e4SLinus Torvalds {
3742b37ad28bSAl Viro 	__be32 status;
3743baeb4ff0SJeff Layton 	unsigned char old_deny_bmap;
37441da177e4SLinus Torvalds 
37456eb3a1d0SJeff Layton 	if (!test_access(open->op_share_access, stp))
3746baeb4ff0SJeff Layton 		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
37477e6a72e5SChristoph Hellwig 
3748baeb4ff0SJeff Layton 	/* test and set deny mode */
3749baeb4ff0SJeff Layton 	spin_lock(&fp->fi_lock);
3750baeb4ff0SJeff Layton 	status = nfs4_file_check_deny(fp, open->op_share_deny);
3751baeb4ff0SJeff Layton 	if (status == nfs_ok) {
3752baeb4ff0SJeff Layton 		old_deny_bmap = stp->st_deny_bmap;
3753baeb4ff0SJeff Layton 		set_deny(open->op_share_deny, stp);
3754baeb4ff0SJeff Layton 		fp->fi_share_deny |=
3755baeb4ff0SJeff Layton 				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
37561da177e4SLinus Torvalds 	}
3757baeb4ff0SJeff Layton 	spin_unlock(&fp->fi_lock);
37581da177e4SLinus Torvalds 
3759baeb4ff0SJeff Layton 	if (status != nfs_ok)
3760baeb4ff0SJeff Layton 		return status;
3761baeb4ff0SJeff Layton 
3762baeb4ff0SJeff Layton 	status = nfsd4_truncate(rqstp, cur_fh, open);
3763baeb4ff0SJeff Layton 	if (status != nfs_ok)
3764baeb4ff0SJeff Layton 		reset_union_bmap_deny(old_deny_bmap, stp);
3765baeb4ff0SJeff Layton 	return status;
3766baeb4ff0SJeff Layton }
37671da177e4SLinus Torvalds 
37681da177e4SLinus Torvalds static void
37691255a8f3SJ. Bruce Fields nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session)
37701da177e4SLinus Torvalds {
3771dad1c067SJ. Bruce Fields 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
37721da177e4SLinus Torvalds }
37731da177e4SLinus Torvalds 
377414a24e99SJ. Bruce Fields /* Should we give out recallable state?: */
377514a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
377614a24e99SJ. Bruce Fields {
377714a24e99SJ. Bruce Fields 	if (clp->cl_cb_state == NFSD4_CB_UP)
377814a24e99SJ. Bruce Fields 		return true;
377914a24e99SJ. Bruce Fields 	/*
378014a24e99SJ. Bruce Fields 	 * In the sessions case, since we don't have to establish a
378114a24e99SJ. Bruce Fields 	 * separate connection for callbacks, we assume it's OK
378214a24e99SJ. Bruce Fields 	 * until we hear otherwise:
378314a24e99SJ. Bruce Fields 	 */
378414a24e99SJ. Bruce Fields 	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
378514a24e99SJ. Bruce Fields }
378614a24e99SJ. Bruce Fields 
3787d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
378822d38c4cSJ. Bruce Fields {
378922d38c4cSJ. Bruce Fields 	struct file_lock *fl;
379022d38c4cSJ. Bruce Fields 
379122d38c4cSJ. Bruce Fields 	fl = locks_alloc_lock();
379222d38c4cSJ. Bruce Fields 	if (!fl)
379322d38c4cSJ. Bruce Fields 		return NULL;
379422d38c4cSJ. Bruce Fields 	locks_init_lock(fl);
379522d38c4cSJ. Bruce Fields 	fl->fl_lmops = &nfsd_lease_mng_ops;
3796617588d5SJ. Bruce Fields 	fl->fl_flags = FL_DELEG;
379722d38c4cSJ. Bruce Fields 	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
379822d38c4cSJ. Bruce Fields 	fl->fl_end = OFFSET_MAX;
3799d564fbecSJeff Layton 	fl->fl_owner = (fl_owner_t)fp;
380022d38c4cSJ. Bruce Fields 	fl->fl_pid = current->tgid;
380122d38c4cSJ. Bruce Fields 	return fl;
380222d38c4cSJ. Bruce Fields }
380322d38c4cSJ. Bruce Fields 
380499c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp)
3805edab9782SJ. Bruce Fields {
380611b9164aSTrond Myklebust 	struct nfs4_file *fp = dp->dl_stid.sc_file;
3807edab9782SJ. Bruce Fields 	struct file_lock *fl;
3808417c6629SJeff Layton 	struct file *filp;
3809417c6629SJeff Layton 	int status = 0;
3810edab9782SJ. Bruce Fields 
3811d564fbecSJeff Layton 	fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ);
3812edab9782SJ. Bruce Fields 	if (!fl)
3813edab9782SJ. Bruce Fields 		return -ENOMEM;
3814417c6629SJeff Layton 	filp = find_readable_file(fp);
3815417c6629SJeff Layton 	if (!filp) {
3816417c6629SJeff Layton 		/* We should always have a readable file here */
3817417c6629SJeff Layton 		WARN_ON_ONCE(1);
3818417c6629SJeff Layton 		return -EBADF;
3819417c6629SJeff Layton 	}
3820417c6629SJeff Layton 	fl->fl_file = filp;
3821417c6629SJeff Layton 	status = vfs_setlease(filp, fl->fl_type, &fl);
3822417c6629SJeff Layton 	if (status) {
3823417c6629SJeff Layton 		locks_free_lock(fl);
3824417c6629SJeff Layton 		goto out_fput;
3825417c6629SJeff Layton 	}
3826cdc97505SBenny Halevy 	spin_lock(&state_lock);
3827417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
3828417c6629SJeff Layton 	/* Did the lease get broken before we took the lock? */
3829417c6629SJeff Layton 	status = -EAGAIN;
3830417c6629SJeff Layton 	if (fp->fi_had_conflict)
3831417c6629SJeff Layton 		goto out_unlock;
3832417c6629SJeff Layton 	/* Race breaker */
3833417c6629SJeff Layton 	if (fp->fi_lease) {
3834417c6629SJeff Layton 		status = 0;
3835417c6629SJeff Layton 		atomic_inc(&fp->fi_delegees);
3836931ee56cSBenny Halevy 		hash_delegation_locked(dp, fp);
3837417c6629SJeff Layton 		goto out_unlock;
3838417c6629SJeff Layton 	}
3839417c6629SJeff Layton 	fp->fi_lease = fl;
3840417c6629SJeff Layton 	fp->fi_deleg_file = filp;
3841417c6629SJeff Layton 	atomic_set(&fp->fi_delegees, 1);
3842417c6629SJeff Layton 	hash_delegation_locked(dp, fp);
3843417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
3844cdc97505SBenny Halevy 	spin_unlock(&state_lock);
3845acfdf5c3SJ. Bruce Fields 	return 0;
3846417c6629SJeff Layton out_unlock:
3847417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
3848417c6629SJeff Layton 	spin_unlock(&state_lock);
3849417c6629SJeff Layton out_fput:
3850417c6629SJeff Layton 	fput(filp);
3851e873088fSJ. Bruce Fields 	return status;
3852acfdf5c3SJ. Bruce Fields }
3853acfdf5c3SJ. Bruce Fields 
38540b26693cSJeff Layton static struct nfs4_delegation *
38550b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
38560b26693cSJeff Layton 		    struct nfs4_file *fp)
3857acfdf5c3SJ. Bruce Fields {
38580b26693cSJeff Layton 	int status;
38590b26693cSJeff Layton 	struct nfs4_delegation *dp;
3860417c6629SJeff Layton 
3861bf7bd3e9SJ. Bruce Fields 	if (fp->fi_had_conflict)
38620b26693cSJeff Layton 		return ERR_PTR(-EAGAIN);
38630b26693cSJeff Layton 
38640b26693cSJeff Layton 	dp = alloc_init_deleg(clp, fh);
38650b26693cSJeff Layton 	if (!dp)
38660b26693cSJeff Layton 		return ERR_PTR(-ENOMEM);
38670b26693cSJeff Layton 
3868bf7bd3e9SJ. Bruce Fields 	get_nfs4_file(fp);
3869cdc97505SBenny Halevy 	spin_lock(&state_lock);
3870417c6629SJeff Layton 	spin_lock(&fp->fi_lock);
387111b9164aSTrond Myklebust 	dp->dl_stid.sc_file = fp;
3872417c6629SJeff Layton 	if (!fp->fi_lease) {
3873417c6629SJeff Layton 		spin_unlock(&fp->fi_lock);
3874417c6629SJeff Layton 		spin_unlock(&state_lock);
38750b26693cSJeff Layton 		status = nfs4_setlease(dp);
38760b26693cSJeff Layton 		goto out;
3877417c6629SJeff Layton 	}
3878cbf7a75bSJ. Bruce Fields 	atomic_inc(&fp->fi_delegees);
3879acfdf5c3SJ. Bruce Fields 	if (fp->fi_had_conflict) {
3880417c6629SJeff Layton 		status = -EAGAIN;
3881417c6629SJeff Layton 		goto out_unlock;
3882acfdf5c3SJ. Bruce Fields 	}
3883931ee56cSBenny Halevy 	hash_delegation_locked(dp, fp);
38840b26693cSJeff Layton 	status = 0;
3885417c6629SJeff Layton out_unlock:
3886417c6629SJeff Layton 	spin_unlock(&fp->fi_lock);
3887cdc97505SBenny Halevy 	spin_unlock(&state_lock);
38880b26693cSJeff Layton out:
38890b26693cSJeff Layton 	if (status) {
38906011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
38910b26693cSJeff Layton 		return ERR_PTR(status);
38920b26693cSJeff Layton 	}
38930b26693cSJeff Layton 	return dp;
3894edab9782SJ. Bruce Fields }
3895edab9782SJ. Bruce Fields 
38964aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
38974aa8913cSBenny Halevy {
38984aa8913cSBenny Halevy 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
38994aa8913cSBenny Halevy 	if (status == -EAGAIN)
39004aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_CONTENTION;
39014aa8913cSBenny Halevy 	else {
39024aa8913cSBenny Halevy 		open->op_why_no_deleg = WND4_RESOURCE;
39034aa8913cSBenny Halevy 		switch (open->op_deleg_want) {
39044aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_READ_DELEG:
39054aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_WRITE_DELEG:
39064aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_ANY_DELEG:
39074aa8913cSBenny Halevy 			break;
39084aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_CANCEL:
39094aa8913cSBenny Halevy 			open->op_why_no_deleg = WND4_CANCELLED;
39104aa8913cSBenny Halevy 			break;
39114aa8913cSBenny Halevy 		case NFS4_SHARE_WANT_NO_DELEG:
3912063b0fb9SJ. Bruce Fields 			WARN_ON_ONCE(1);
39134aa8913cSBenny Halevy 		}
39144aa8913cSBenny Halevy 	}
39154aa8913cSBenny Halevy }
39164aa8913cSBenny Halevy 
39171da177e4SLinus Torvalds /*
39181da177e4SLinus Torvalds  * Attempt to hand out a delegation.
391999c41515SJ. Bruce Fields  *
392099c41515SJ. Bruce Fields  * Note we don't support write delegations, and won't until the vfs has
392199c41515SJ. Bruce Fields  * proper support for them.
39221da177e4SLinus Torvalds  */
39231da177e4SLinus Torvalds static void
39244cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
39254cf59221SJeff Layton 			struct nfs4_ol_stateid *stp)
39261da177e4SLinus Torvalds {
39271da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
39284cf59221SJeff Layton 	struct nfs4_openowner *oo = openowner(stp->st_stateowner);
39294cf59221SJeff Layton 	struct nfs4_client *clp = stp->st_stid.sc_client;
393014a24e99SJ. Bruce Fields 	int cb_up;
393199c41515SJ. Bruce Fields 	int status = 0;
39321da177e4SLinus Torvalds 
3933fe0750e5SJ. Bruce Fields 	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
39347b190fecSNeilBrown 	open->op_recall = 0;
39357b190fecSNeilBrown 	switch (open->op_claim_type) {
39367b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_PREVIOUS:
39372bf23875SJ. Bruce Fields 			if (!cb_up)
39387b190fecSNeilBrown 				open->op_recall = 1;
393999c41515SJ. Bruce Fields 			if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
394099c41515SJ. Bruce Fields 				goto out_no_deleg;
39417b190fecSNeilBrown 			break;
39427b190fecSNeilBrown 		case NFS4_OPEN_CLAIM_NULL:
3943ed47b062SMing Chen 		case NFS4_OPEN_CLAIM_FH:
394499c41515SJ. Bruce Fields 			/*
394599c41515SJ. Bruce Fields 			 * Let's not give out any delegations till everyone's
394699c41515SJ. Bruce Fields 			 * had the chance to reclaim theirs....
394799c41515SJ. Bruce Fields 			 */
39484cf59221SJeff Layton 			if (locks_in_grace(clp->net))
394999c41515SJ. Bruce Fields 				goto out_no_deleg;
3950dad1c067SJ. Bruce Fields 			if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
395199c41515SJ. Bruce Fields 				goto out_no_deleg;
39529a0590aeSSteve Dickson 			/*
39539a0590aeSSteve Dickson 			 * Also, if the file was opened for write or
39549a0590aeSSteve Dickson 			 * create, there's a good chance the client's
39559a0590aeSSteve Dickson 			 * about to write to it, resulting in an
39569a0590aeSSteve Dickson 			 * immediate recall (since we don't support
39579a0590aeSSteve Dickson 			 * write delegations):
39589a0590aeSSteve Dickson 			 */
39591da177e4SLinus Torvalds 			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
396099c41515SJ. Bruce Fields 				goto out_no_deleg;
396199c41515SJ. Bruce Fields 			if (open->op_create == NFS4_OPEN_CREATE)
396299c41515SJ. Bruce Fields 				goto out_no_deleg;
39637b190fecSNeilBrown 			break;
39647b190fecSNeilBrown 		default:
396599c41515SJ. Bruce Fields 			goto out_no_deleg;
39667b190fecSNeilBrown 	}
396711b9164aSTrond Myklebust 	dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file);
39680b26693cSJeff Layton 	if (IS_ERR(dp))
3969dd239cc0SJ. Bruce Fields 		goto out_no_deleg;
39701da177e4SLinus Torvalds 
3971d5477a8dSJ. Bruce Fields 	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
39721da177e4SLinus Torvalds 
39738c10cbdbSBenny Halevy 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
3974d5477a8dSJ. Bruce Fields 		STATEID_VAL(&dp->dl_stid.sc_stateid));
397599c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
397667cb1279STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
3977dd239cc0SJ. Bruce Fields 	return;
3978dd239cc0SJ. Bruce Fields out_no_deleg:
397999c41515SJ. Bruce Fields 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
39807b190fecSNeilBrown 	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
3981d08d32e6SJ. Bruce Fields 	    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
39821da177e4SLinus Torvalds 		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
3983d08d32e6SJ. Bruce Fields 		open->op_recall = 1;
3984d08d32e6SJ. Bruce Fields 	}
3985dd239cc0SJ. Bruce Fields 
3986dd239cc0SJ. Bruce Fields 	/* 4.1 client asking for a delegation? */
3987dd239cc0SJ. Bruce Fields 	if (open->op_deleg_want)
3988dd239cc0SJ. Bruce Fields 		nfsd4_open_deleg_none_ext(open, status);
3989dd239cc0SJ. Bruce Fields 	return;
39901da177e4SLinus Torvalds }
39911da177e4SLinus Torvalds 
3992e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
3993e27f49c3SBenny Halevy 					struct nfs4_delegation *dp)
3994e27f49c3SBenny Halevy {
3995e27f49c3SBenny Halevy 	if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
3996e27f49c3SBenny Halevy 	    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
3997e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
3998e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
3999e27f49c3SBenny Halevy 	} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
4000e27f49c3SBenny Halevy 		   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
4001e27f49c3SBenny Halevy 		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4002e27f49c3SBenny Halevy 		open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
4003e27f49c3SBenny Halevy 	}
4004e27f49c3SBenny Halevy 	/* Otherwise the client must be confused wanting a delegation
4005e27f49c3SBenny Halevy 	 * it already has, therefore we don't return
4006e27f49c3SBenny Halevy 	 * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
4007e27f49c3SBenny Halevy 	 */
4008e27f49c3SBenny Halevy }
4009e27f49c3SBenny Halevy 
40101da177e4SLinus Torvalds /*
40111da177e4SLinus Torvalds  * called with nfs4_lock_state() held.
40121da177e4SLinus Torvalds  */
4013b37ad28bSAl Viro __be32
40141da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
40151da177e4SLinus Torvalds {
40166668958fSAndy Adamson 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
401738c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
40181da177e4SLinus Torvalds 	struct nfs4_file *fp = NULL;
4019dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
4020567d9829SNeilBrown 	struct nfs4_delegation *dp = NULL;
4021b37ad28bSAl Viro 	__be32 status;
40221da177e4SLinus Torvalds 
40231da177e4SLinus Torvalds 	/*
40241da177e4SLinus Torvalds 	 * Lookup file; if found, lookup stateid and check open request,
40251da177e4SLinus Torvalds 	 * and check for delegations in the process of being recalled.
40261da177e4SLinus Torvalds 	 * If not found, create the nfs4_file struct
40271da177e4SLinus Torvalds 	 */
4028f9c00c3aSJeff Layton 	fp = find_or_add_file(open->op_file, &current_fh->fh_handle);
4029950e0118STrond Myklebust 	if (fp != open->op_file) {
403041d22663SJ. Bruce Fields 		status = nfs4_check_deleg(cl, open, &dp);
4031c44c5eebSNeilBrown 		if (status)
4032c44c5eebSNeilBrown 			goto out;
4033a46cb7f2SJeff Layton 		stp = nfsd4_find_existing_open(fp, open);
40341da177e4SLinus Torvalds 	} else {
4035950e0118STrond Myklebust 		open->op_file = NULL;
4036c44c5eebSNeilBrown 		status = nfserr_bad_stateid;
40378b289b2cSJ. Bruce Fields 		if (nfsd4_is_deleg_cur(open))
4038c44c5eebSNeilBrown 			goto out;
40393e772463SJ. Bruce Fields 		status = nfserr_jukebox;
40401da177e4SLinus Torvalds 	}
40411da177e4SLinus Torvalds 
40421da177e4SLinus Torvalds 	/*
40431da177e4SLinus Torvalds 	 * OPEN the file, or upgrade an existing OPEN.
40441da177e4SLinus Torvalds 	 * If truncate fails, the OPEN fails.
40451da177e4SLinus Torvalds 	 */
40461da177e4SLinus Torvalds 	if (stp) {
40471da177e4SLinus Torvalds 		/* Stateid was found, this is an OPEN upgrade */
4048f9d7562fSJ. Bruce Fields 		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
40491da177e4SLinus Torvalds 		if (status)
40501da177e4SLinus Torvalds 			goto out;
40511da177e4SLinus Torvalds 	} else {
40524cdc951bSJ. Bruce Fields 		stp = open->op_stp;
40534cdc951bSJ. Bruce Fields 		open->op_stp = NULL;
4054996e0938SJ. Bruce Fields 		init_open_stateid(stp, fp, open);
40556eb3a1d0SJeff Layton 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
40566eb3a1d0SJeff Layton 		if (status) {
40576eb3a1d0SJeff Layton 			release_open_stateid(stp);
40586eb3a1d0SJeff Layton 			goto out;
40596eb3a1d0SJeff Layton 		}
40601da177e4SLinus Torvalds 	}
4061dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4062dcef0413SJ. Bruce Fields 	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
40631da177e4SLinus Torvalds 
4064d24433cdSBenny Halevy 	if (nfsd4_has_session(&resp->cstate)) {
4065d24433cdSBenny Halevy 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
4066d24433cdSBenny Halevy 			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
4067d24433cdSBenny Halevy 			open->op_why_no_deleg = WND4_NOT_WANTED;
4068d24433cdSBenny Halevy 			goto nodeleg;
4069d24433cdSBenny Halevy 		}
4070d24433cdSBenny Halevy 	}
4071d24433cdSBenny Halevy 
40721da177e4SLinus Torvalds 	/*
40731da177e4SLinus Torvalds 	* Attempt to hand out a delegation. No error return, because the
40741da177e4SLinus Torvalds 	* OPEN succeeds even if we fail.
40751da177e4SLinus Torvalds 	*/
40764cf59221SJeff Layton 	nfs4_open_delegation(current_fh, open, stp);
4077d24433cdSBenny Halevy nodeleg:
40781da177e4SLinus Torvalds 	status = nfs_ok;
40791da177e4SLinus Torvalds 
40808c10cbdbSBenny Halevy 	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
4081dcef0413SJ. Bruce Fields 		STATEID_VAL(&stp->st_stid.sc_stateid));
40821da177e4SLinus Torvalds out:
4083d24433cdSBenny Halevy 	/* 4.1 client trying to upgrade/downgrade delegation? */
4084d24433cdSBenny Halevy 	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
4085e27f49c3SBenny Halevy 	    open->op_deleg_want)
4086e27f49c3SBenny Halevy 		nfsd4_deleg_xgrade_none_ext(open, dp);
4087d24433cdSBenny Halevy 
408813cd2184SNeilBrown 	if (fp)
408913cd2184SNeilBrown 		put_nfs4_file(fp);
409037515177SNeilBrown 	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
40911255a8f3SJ. Bruce Fields 		nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate));
40921da177e4SLinus Torvalds 	/*
40931da177e4SLinus Torvalds 	* To finish the open response, we just need to set the rflags.
40941da177e4SLinus Torvalds 	*/
40951da177e4SLinus Torvalds 	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
4096dad1c067SJ. Bruce Fields 	if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
40976668958fSAndy Adamson 	    !nfsd4_has_session(&resp->cstate))
40981da177e4SLinus Torvalds 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
4099dcd94cc2STrond Myklebust 	if (dp)
4100dcd94cc2STrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
4101d6f2bc5dSTrond Myklebust 	if (stp)
4102d6f2bc5dSTrond Myklebust 		nfs4_put_stid(&stp->st_stid);
41031da177e4SLinus Torvalds 
41041da177e4SLinus Torvalds 	return status;
41051da177e4SLinus Torvalds }
41061da177e4SLinus Torvalds 
410758fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
410858fb12e6SJeff Layton 			      struct nfsd4_open *open, __be32 status)
4109d29b20cdSJ. Bruce Fields {
4110d29b20cdSJ. Bruce Fields 	if (open->op_openowner) {
4111d3134b10SJeff Layton 		struct nfs4_stateowner *so = &open->op_openowner->oo_owner;
4112d29b20cdSJ. Bruce Fields 
4113d3134b10SJeff Layton 		nfsd4_cstate_assign_replay(cstate, so);
4114d3134b10SJeff Layton 		nfs4_put_stateowner(so);
4115d29b20cdSJ. Bruce Fields 	}
411632513b40SJ. Bruce Fields 	if (open->op_file)
411732513b40SJ. Bruce Fields 		nfsd4_free_file(open->op_file);
41184cdc951bSJ. Bruce Fields 	if (open->op_stp)
41196011695dSTrond Myklebust 		nfs4_put_stid(&open->op_stp->st_stid);
4120d29b20cdSJ. Bruce Fields }
4121d29b20cdSJ. Bruce Fields 
4122b37ad28bSAl Viro __be32
4123b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4124b591480bSJ.Bruce Fields 	    clientid_t *clid)
41251da177e4SLinus Torvalds {
41261da177e4SLinus Torvalds 	struct nfs4_client *clp;
4127b37ad28bSAl Viro 	__be32 status;
41287f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
41291da177e4SLinus Torvalds 
41301da177e4SLinus Torvalds 	nfs4_lock_state();
41311da177e4SLinus Torvalds 	dprintk("process_renew(%08x/%08x): starting\n",
41321da177e4SLinus Torvalds 			clid->cl_boot, clid->cl_id);
41334b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
41349b2ef62bSJ. Bruce Fields 	if (status)
41351da177e4SLinus Torvalds 		goto out;
41364b24ca7dSJeff Layton 	clp = cstate->clp;
41371da177e4SLinus Torvalds 	status = nfserr_cb_path_down;
4138ea1da636SNeilBrown 	if (!list_empty(&clp->cl_delegations)
413977a3569dSJ. Bruce Fields 			&& clp->cl_cb_state != NFSD4_CB_UP)
41401da177e4SLinus Torvalds 		goto out;
41411da177e4SLinus Torvalds 	status = nfs_ok;
41421da177e4SLinus Torvalds out:
41431da177e4SLinus Torvalds 	nfs4_unlock_state();
41441da177e4SLinus Torvalds 	return status;
41451da177e4SLinus Torvalds }
41461da177e4SLinus Torvalds 
4147a76b4319SNeilBrown static void
414812760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn)
4149a76b4319SNeilBrown {
415033dcc481SJeff Layton 	/* do nothing if grace period already ended */
4151a51c84edSStanislav Kinsbursky 	if (nn->grace_ended)
415233dcc481SJeff Layton 		return;
415333dcc481SJeff Layton 
4154a76b4319SNeilBrown 	dprintk("NFSD: end of grace period\n");
4155a51c84edSStanislav Kinsbursky 	nn->grace_ended = true;
415612760c66SStanislav Kinsbursky 	nfsd4_record_grace_done(nn, nn->boot_time);
41575e1533c7SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
4158e46b498cSJ. Bruce Fields 	/*
4159e46b498cSJ. Bruce Fields 	 * Now that every NFSv4 client has had the chance to recover and
4160e46b498cSJ. Bruce Fields 	 * to see the (possibly new, possibly shorter) lease time, we
4161e46b498cSJ. Bruce Fields 	 * can safely set the next grace time to the current lease time:
4162e46b498cSJ. Bruce Fields 	 */
41635284b44eSStanislav Kinsbursky 	nn->nfsd4_grace = nn->nfsd4_lease;
4164a76b4319SNeilBrown }
4165a76b4319SNeilBrown 
4166fd39ca9aSNeilBrown static time_t
416709121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn)
41681da177e4SLinus Torvalds {
41691da177e4SLinus Torvalds 	struct nfs4_client *clp;
4170fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
41711da177e4SLinus Torvalds 	struct nfs4_delegation *dp;
4172217526e7SJeff Layton 	struct nfs4_ol_stateid *stp;
41731da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
41743d733711SStanislav Kinsbursky 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
4175a832e7aeSJeff Layton 	time_t t, new_timeo = nn->nfsd4_lease;
41761da177e4SLinus Torvalds 
41771da177e4SLinus Torvalds 	nfs4_lock_state();
41781da177e4SLinus Torvalds 
41791da177e4SLinus Torvalds 	dprintk("NFSD: laundromat service - starting\n");
418012760c66SStanislav Kinsbursky 	nfsd4_end_grace(nn);
418136acb66bSBenny Halevy 	INIT_LIST_HEAD(&reaplist);
4182c9a49628SStanislav Kinsbursky 	spin_lock(&nn->client_lock);
41835ed58bb2SStanislav Kinsbursky 	list_for_each_safe(pos, next, &nn->client_lru) {
41841da177e4SLinus Torvalds 		clp = list_entry(pos, struct nfs4_client, cl_lru);
41851da177e4SLinus Torvalds 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
41861da177e4SLinus Torvalds 			t = clp->cl_time - cutoff;
4187a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
41881da177e4SLinus Torvalds 			break;
41891da177e4SLinus Torvalds 		}
4190221a6876SJ. Bruce Fields 		if (mark_client_expired_locked(clp)) {
4191d7682988SBenny Halevy 			dprintk("NFSD: client in use (clientid %08x)\n",
4192d7682988SBenny Halevy 				clp->cl_clientid.cl_id);
4193d7682988SBenny Halevy 			continue;
4194d7682988SBenny Halevy 		}
41954864af97STrond Myklebust 		list_add(&clp->cl_lru, &reaplist);
419636acb66bSBenny Halevy 	}
4197c9a49628SStanislav Kinsbursky 	spin_unlock(&nn->client_lock);
419836acb66bSBenny Halevy 	list_for_each_safe(pos, next, &reaplist) {
419936acb66bSBenny Halevy 		clp = list_entry(pos, struct nfs4_client, cl_lru);
42001da177e4SLinus Torvalds 		dprintk("NFSD: purging unused client (clientid %08x)\n",
42011da177e4SLinus Torvalds 			clp->cl_clientid.cl_id);
42024864af97STrond Myklebust 		list_del_init(&clp->cl_lru);
42031da177e4SLinus Torvalds 		expire_client(clp);
42041da177e4SLinus Torvalds 	}
4205cdc97505SBenny Halevy 	spin_lock(&state_lock);
4206e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
42071da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
42084e37a7c2SStanislav Kinsbursky 		if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn)
42094e37a7c2SStanislav Kinsbursky 			continue;
42101da177e4SLinus Torvalds 		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
4211a832e7aeSJeff Layton 			t = dp->dl_time - cutoff;
4212a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
42131da177e4SLinus Torvalds 			break;
42141da177e4SLinus Torvalds 		}
421542690676SJeff Layton 		unhash_delegation_locked(dp);
421642690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
42171da177e4SLinus Torvalds 	}
4218cdc97505SBenny Halevy 	spin_unlock(&state_lock);
42192d4a532dSJeff Layton 	while (!list_empty(&reaplist)) {
42202d4a532dSJeff Layton 		dp = list_first_entry(&reaplist, struct nfs4_delegation,
42212d4a532dSJeff Layton 					dl_recall_lru);
42222d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
42233bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
42241da177e4SLinus Torvalds 	}
4225217526e7SJeff Layton 
4226217526e7SJeff Layton 	spin_lock(&nn->client_lock);
4227217526e7SJeff Layton 	while (!list_empty(&nn->close_lru)) {
4228217526e7SJeff Layton 		oo = list_first_entry(&nn->close_lru, struct nfs4_openowner,
4229217526e7SJeff Layton 					oo_close_lru);
4230217526e7SJeff Layton 		if (time_after((unsigned long)oo->oo_time,
4231217526e7SJeff Layton 			       (unsigned long)cutoff)) {
4232a832e7aeSJeff Layton 			t = oo->oo_time - cutoff;
4233a832e7aeSJeff Layton 			new_timeo = min(new_timeo, t);
42341da177e4SLinus Torvalds 			break;
42351da177e4SLinus Torvalds 		}
4236217526e7SJeff Layton 		list_del_init(&oo->oo_close_lru);
4237217526e7SJeff Layton 		stp = oo->oo_last_closed_stid;
4238217526e7SJeff Layton 		oo->oo_last_closed_stid = NULL;
4239217526e7SJeff Layton 		spin_unlock(&nn->client_lock);
4240217526e7SJeff Layton 		nfs4_put_stid(&stp->st_stid);
4241217526e7SJeff Layton 		spin_lock(&nn->client_lock);
42421da177e4SLinus Torvalds 	}
4243217526e7SJeff Layton 	spin_unlock(&nn->client_lock);
4244217526e7SJeff Layton 
4245a832e7aeSJeff Layton 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
42461da177e4SLinus Torvalds 	nfs4_unlock_state();
4247a832e7aeSJeff Layton 	return new_timeo;
42481da177e4SLinus Torvalds }
42491da177e4SLinus Torvalds 
4250a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq;
4251a254b246SHarvey Harrison static void laundromat_main(struct work_struct *);
4252a254b246SHarvey Harrison 
4253a254b246SHarvey Harrison static void
425409121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry)
42551da177e4SLinus Torvalds {
42561da177e4SLinus Torvalds 	time_t t;
425709121281SStanislav Kinsbursky 	struct delayed_work *dwork = container_of(laundry, struct delayed_work,
425809121281SStanislav Kinsbursky 						  work);
425909121281SStanislav Kinsbursky 	struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
426009121281SStanislav Kinsbursky 					   laundromat_work);
42611da177e4SLinus Torvalds 
426209121281SStanislav Kinsbursky 	t = nfs4_laundromat(nn);
42631da177e4SLinus Torvalds 	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
426409121281SStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
42651da177e4SLinus Torvalds }
42661da177e4SLinus Torvalds 
4267f7a4d872SJ. Bruce Fields static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
4268f8816512SNeilBrown {
426911b9164aSTrond Myklebust 	if (!nfsd_fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle))
4270f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
4271f7a4d872SJ. Bruce Fields 	return nfs_ok;
42721da177e4SLinus Torvalds }
42731da177e4SLinus Torvalds 
42741da177e4SLinus Torvalds static inline int
427582c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp)
42761da177e4SLinus Torvalds {
427782c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_READ, stp) ||
427882c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp) ||
427982c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_WRITE, stp);
42801da177e4SLinus Torvalds }
42811da177e4SLinus Torvalds 
42821da177e4SLinus Torvalds static inline int
428382c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp)
42841da177e4SLinus Torvalds {
428582c5ff1bSJeff Layton 	return test_access(NFS4_SHARE_ACCESS_WRITE, stp) ||
428682c5ff1bSJeff Layton 		test_access(NFS4_SHARE_ACCESS_BOTH, stp);
42871da177e4SLinus Torvalds }
42881da177e4SLinus Torvalds 
42891da177e4SLinus Torvalds static
4290dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
42911da177e4SLinus Torvalds {
4292b37ad28bSAl Viro         __be32 status = nfserr_openmode;
42931da177e4SLinus Torvalds 
429402921914SJ. Bruce Fields 	/* For lock stateid's, we test the parent open, not the lock: */
429502921914SJ. Bruce Fields 	if (stp->st_openstp)
429602921914SJ. Bruce Fields 		stp = stp->st_openstp;
429782c5ff1bSJeff Layton 	if ((flags & WR_STATE) && !access_permit_write(stp))
42981da177e4SLinus Torvalds                 goto out;
429982c5ff1bSJeff Layton 	if ((flags & RD_STATE) && !access_permit_read(stp))
43001da177e4SLinus Torvalds                 goto out;
43011da177e4SLinus Torvalds 	status = nfs_ok;
43021da177e4SLinus Torvalds out:
43031da177e4SLinus Torvalds 	return status;
43041da177e4SLinus Torvalds }
43051da177e4SLinus Torvalds 
4306b37ad28bSAl Viro static inline __be32
43075ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags)
43081da177e4SLinus Torvalds {
4309203a8c8eSJ. Bruce Fields 	if (ONE_STATEID(stateid) && (flags & RD_STATE))
43101da177e4SLinus Torvalds 		return nfs_ok;
43115ccb0066SStanislav Kinsbursky 	else if (locks_in_grace(net)) {
431225985edcSLucas De Marchi 		/* Answer in remaining cases depends on existence of
43131da177e4SLinus Torvalds 		 * conflicting state; so we must wait out the grace period. */
43141da177e4SLinus Torvalds 		return nfserr_grace;
43151da177e4SLinus Torvalds 	} else if (flags & WR_STATE)
43161da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
43171da177e4SLinus Torvalds 				NFS4_SHARE_DENY_WRITE);
43181da177e4SLinus Torvalds 	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
43191da177e4SLinus Torvalds 		return nfs4_share_conflict(current_fh,
43201da177e4SLinus Torvalds 				NFS4_SHARE_DENY_READ);
43211da177e4SLinus Torvalds }
43221da177e4SLinus Torvalds 
43231da177e4SLinus Torvalds /*
43241da177e4SLinus Torvalds  * Allow READ/WRITE during grace period on recovered state only for files
43251da177e4SLinus Torvalds  * that are not able to provide mandatory locking.
43261da177e4SLinus Torvalds  */
43271da177e4SLinus Torvalds static inline int
43285ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode)
43291da177e4SLinus Torvalds {
43305ccb0066SStanislav Kinsbursky 	return locks_in_grace(net) && mandatory_lock(inode);
43311da177e4SLinus Torvalds }
43321da177e4SLinus Torvalds 
433381b82965SJ. Bruce Fields /* Returns true iff a is later than b: */
433481b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b)
433581b82965SJ. Bruce Fields {
43361a9357f4SJim Rees 	return (s32)(a->si_generation - b->si_generation) > 0;
433781b82965SJ. Bruce Fields }
433881b82965SJ. Bruce Fields 
433957b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
43400836f587SJ. Bruce Fields {
43416668958fSAndy Adamson 	/*
43426668958fSAndy Adamson 	 * When sessions are used the stateid generation number is ignored
43436668958fSAndy Adamson 	 * when it is zero.
43446668958fSAndy Adamson 	 */
434528dde241SJ. Bruce Fields 	if (has_session && in->si_generation == 0)
434681b82965SJ. Bruce Fields 		return nfs_ok;
434781b82965SJ. Bruce Fields 
434881b82965SJ. Bruce Fields 	if (in->si_generation == ref->si_generation)
434981b82965SJ. Bruce Fields 		return nfs_ok;
43506668958fSAndy Adamson 
43510836f587SJ. Bruce Fields 	/* If the client sends us a stateid from the future, it's buggy: */
435281b82965SJ. Bruce Fields 	if (stateid_generation_after(in, ref))
43530836f587SJ. Bruce Fields 		return nfserr_bad_stateid;
43540836f587SJ. Bruce Fields 	/*
435581b82965SJ. Bruce Fields 	 * However, we could see a stateid from the past, even from a
435681b82965SJ. Bruce Fields 	 * non-buggy client.  For example, if the client sends a lock
435781b82965SJ. Bruce Fields 	 * while some IO is outstanding, the lock may bump si_generation
435881b82965SJ. Bruce Fields 	 * while the IO is still in flight.  The client could avoid that
435981b82965SJ. Bruce Fields 	 * situation by waiting for responses on all the IO requests,
436081b82965SJ. Bruce Fields 	 * but better performance may result in retrying IO that
436181b82965SJ. Bruce Fields 	 * receives an old_stateid error if requests are rarely
436281b82965SJ. Bruce Fields 	 * reordered in flight:
43630836f587SJ. Bruce Fields 	 */
43640836f587SJ. Bruce Fields 	return nfserr_old_stateid;
43650836f587SJ. Bruce Fields }
43660836f587SJ. Bruce Fields 
43677df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
436817456804SBryan Schumaker {
436997b7e3b6SJ. Bruce Fields 	struct nfs4_stid *s;
437097b7e3b6SJ. Bruce Fields 	struct nfs4_ol_stateid *ols;
43711af71cc8SJeff Layton 	__be32 status = nfserr_bad_stateid;
437217456804SBryan Schumaker 
43737df302f7SChuck Lever 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
43741af71cc8SJeff Layton 		return status;
43757df302f7SChuck Lever 	/* Client debugging aid. */
43767df302f7SChuck Lever 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
43777df302f7SChuck Lever 		char addr_str[INET6_ADDRSTRLEN];
43787df302f7SChuck Lever 		rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
43797df302f7SChuck Lever 				 sizeof(addr_str));
43807df302f7SChuck Lever 		pr_warn_ratelimited("NFSD: client %s testing state ID "
43817df302f7SChuck Lever 					"with incorrect client ID\n", addr_str);
43821af71cc8SJeff Layton 		return status;
43837df302f7SChuck Lever 	}
43841af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
43851af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
438697b7e3b6SJ. Bruce Fields 	if (!s)
43871af71cc8SJeff Layton 		goto out_unlock;
438836279ac1SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
438917456804SBryan Schumaker 	if (status)
43901af71cc8SJeff Layton 		goto out_unlock;
439123340032SJ. Bruce Fields 	switch (s->sc_type) {
439223340032SJ. Bruce Fields 	case NFS4_DELEG_STID:
43931af71cc8SJeff Layton 		status = nfs_ok;
43941af71cc8SJeff Layton 		break;
43953bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
43961af71cc8SJeff Layton 		status = nfserr_deleg_revoked;
43971af71cc8SJeff Layton 		break;
439823340032SJ. Bruce Fields 	case NFS4_OPEN_STID:
439923340032SJ. Bruce Fields 	case NFS4_LOCK_STID:
440097b7e3b6SJ. Bruce Fields 		ols = openlockstateid(s);
440197b7e3b6SJ. Bruce Fields 		if (ols->st_stateowner->so_is_open_owner
440223340032SJ. Bruce Fields 	    			&& !(openowner(ols->st_stateowner)->oo_flags
440323340032SJ. Bruce Fields 						& NFS4_OO_CONFIRMED))
44041af71cc8SJeff Layton 			status = nfserr_bad_stateid;
44051af71cc8SJeff Layton 		else
44061af71cc8SJeff Layton 			status = nfs_ok;
44071af71cc8SJeff Layton 		break;
440823340032SJ. Bruce Fields 	default:
440923340032SJ. Bruce Fields 		printk("unknown stateid type %x\n", s->sc_type);
4410b0fc29d6STrond Myklebust 		/* Fallthrough */
441123340032SJ. Bruce Fields 	case NFS4_CLOSED_STID:
4412b0fc29d6STrond Myklebust 	case NFS4_CLOSED_DELEG_STID:
44131af71cc8SJeff Layton 		status = nfserr_bad_stateid;
441423340032SJ. Bruce Fields 	}
44151af71cc8SJeff Layton out_unlock:
44161af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
44171af71cc8SJeff Layton 	return status;
441817456804SBryan Schumaker }
441917456804SBryan Schumaker 
44202dd6e458STrond Myklebust static __be32
44212dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
44222dd6e458STrond Myklebust 		     stateid_t *stateid, unsigned char typemask,
44232dd6e458STrond Myklebust 		     struct nfs4_stid **s, struct nfsd_net *nn)
442438c2f4b1SJ. Bruce Fields {
44250eb6f20aSJ. Bruce Fields 	__be32 status;
442638c2f4b1SJ. Bruce Fields 
442738c2f4b1SJ. Bruce Fields 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
442838c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
44294b24ca7dSJeff Layton 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
4430a8a7c677STrond Myklebust 	if (status == nfserr_stale_clientid) {
44314b24ca7dSJeff Layton 		if (cstate->session)
4432a8a7c677STrond Myklebust 			return nfserr_bad_stateid;
443338c2f4b1SJ. Bruce Fields 		return nfserr_stale_stateid;
4434a8a7c677STrond Myklebust 	}
44350eb6f20aSJ. Bruce Fields 	if (status)
44360eb6f20aSJ. Bruce Fields 		return status;
44374b24ca7dSJeff Layton 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
443838c2f4b1SJ. Bruce Fields 	if (!*s)
443938c2f4b1SJ. Bruce Fields 		return nfserr_bad_stateid;
444038c2f4b1SJ. Bruce Fields 	return nfs_ok;
444138c2f4b1SJ. Bruce Fields }
444238c2f4b1SJ. Bruce Fields 
44431da177e4SLinus Torvalds /*
44441da177e4SLinus Torvalds * Checks for stateid operations
44451da177e4SLinus Torvalds */
4446b37ad28bSAl Viro __be32
44475ccb0066SStanislav Kinsbursky nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
4448dd453dfdSBenny Halevy 			   stateid_t *stateid, int flags, struct file **filpp)
44491da177e4SLinus Torvalds {
445069064a27SJ. Bruce Fields 	struct nfs4_stid *s;
4451dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp = NULL;
44521da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
4453dd453dfdSBenny Halevy 	struct svc_fh *current_fh = &cstate->current_fh;
44541da177e4SLinus Torvalds 	struct inode *ino = current_fh->fh_dentry->d_inode;
44553320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
445614bcab1aSTrond Myklebust 	struct file *file = NULL;
4457b37ad28bSAl Viro 	__be32 status;
44581da177e4SLinus Torvalds 
44591da177e4SLinus Torvalds 	if (filpp)
44601da177e4SLinus Torvalds 		*filpp = NULL;
44611da177e4SLinus Torvalds 
44625ccb0066SStanislav Kinsbursky 	if (grace_disallows_io(net, ino))
44631da177e4SLinus Torvalds 		return nfserr_grace;
44641da177e4SLinus Torvalds 
44651da177e4SLinus Torvalds 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
44665ccb0066SStanislav Kinsbursky 		return check_special_stateids(net, current_fh, stateid, flags);
44671da177e4SLinus Torvalds 
446814bcab1aSTrond Myklebust 	nfs4_lock_state();
446914bcab1aSTrond Myklebust 
44702dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid,
4471db24b3b4SJeff Layton 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
44722dd6e458STrond Myklebust 				&s, nn);
447338c2f4b1SJ. Bruce Fields 	if (status)
4474fd911011STrond Myklebust 		goto unlock_state;
447569064a27SJ. Bruce Fields 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
44760c2a498fSJ. Bruce Fields 	if (status)
44770c2a498fSJ. Bruce Fields 		goto out;
4478f7a4d872SJ. Bruce Fields 	switch (s->sc_type) {
4479f7a4d872SJ. Bruce Fields 	case NFS4_DELEG_STID:
448069064a27SJ. Bruce Fields 		dp = delegstateid(s);
4481dc9bf700SJ. Bruce Fields 		status = nfs4_check_delegmode(dp, flags);
4482dc9bf700SJ. Bruce Fields 		if (status)
4483dc9bf700SJ. Bruce Fields 			goto out;
448443b0178eSDan Carpenter 		if (filpp) {
448511b9164aSTrond Myklebust 			file = dp->dl_stid.sc_file->fi_deleg_file;
448614bcab1aSTrond Myklebust 			if (!file) {
4487063b0fb9SJ. Bruce Fields 				WARN_ON_ONCE(1);
4488063b0fb9SJ. Bruce Fields 				status = nfserr_serverfault;
4489063b0fb9SJ. Bruce Fields 				goto out;
4490063b0fb9SJ. Bruce Fields 			}
4491de18643dSTrond Myklebust 			get_file(file);
449243b0178eSDan Carpenter 		}
4493f7a4d872SJ. Bruce Fields 		break;
4494f7a4d872SJ. Bruce Fields 	case NFS4_OPEN_STID:
4495f7a4d872SJ. Bruce Fields 	case NFS4_LOCK_STID:
449669064a27SJ. Bruce Fields 		stp = openlockstateid(s);
4497f7a4d872SJ. Bruce Fields 		status = nfs4_check_fh(current_fh, stp);
4498f7a4d872SJ. Bruce Fields 		if (status)
44991da177e4SLinus Torvalds 			goto out;
4500fe0750e5SJ. Bruce Fields 		if (stp->st_stateowner->so_is_open_owner
4501dad1c067SJ. Bruce Fields 		    && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
45021da177e4SLinus Torvalds 			goto out;
4503a4455be0SJ. Bruce Fields 		status = nfs4_check_openmode(stp, flags);
4504a4455be0SJ. Bruce Fields 		if (status)
45051da177e4SLinus Torvalds 			goto out;
4506f9d7562fSJ. Bruce Fields 		if (filpp) {
450711b9164aSTrond Myklebust 			struct nfs4_file *fp = stp->st_stid.sc_file;
450811b9164aSTrond Myklebust 
4509f9d7562fSJ. Bruce Fields 			if (flags & RD_STATE)
451011b9164aSTrond Myklebust 				file = find_readable_file(fp);
4511f9d7562fSJ. Bruce Fields 			else
451211b9164aSTrond Myklebust 				file = find_writeable_file(fp);
4513f9d7562fSJ. Bruce Fields 		}
4514f7a4d872SJ. Bruce Fields 		break;
4515f7a4d872SJ. Bruce Fields 	default:
451614bcab1aSTrond Myklebust 		status = nfserr_bad_stateid;
451714bcab1aSTrond Myklebust 		goto out;
45181da177e4SLinus Torvalds 	}
45191da177e4SLinus Torvalds 	status = nfs_ok;
452014bcab1aSTrond Myklebust 	if (file)
4521de18643dSTrond Myklebust 		*filpp = file;
45221da177e4SLinus Torvalds out:
4523fd911011STrond Myklebust 	nfs4_put_stid(s);
4524fd911011STrond Myklebust unlock_state:
452514bcab1aSTrond Myklebust 	nfs4_unlock_state();
45261da177e4SLinus Torvalds 	return status;
45271da177e4SLinus Torvalds }
45281da177e4SLinus Torvalds 
4529e1ca12dfSBryan Schumaker /*
453017456804SBryan Schumaker  * Test if the stateid is valid
453117456804SBryan Schumaker  */
453217456804SBryan Schumaker __be32
453317456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
453417456804SBryan Schumaker 		   struct nfsd4_test_stateid *test_stateid)
453517456804SBryan Schumaker {
453603cfb420SBryan Schumaker 	struct nfsd4_test_stateid_id *stateid;
453703cfb420SBryan Schumaker 	struct nfs4_client *cl = cstate->session->se_client;
453803cfb420SBryan Schumaker 
453903cfb420SBryan Schumaker 	nfs4_lock_state();
454003cfb420SBryan Schumaker 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
45417df302f7SChuck Lever 		stateid->ts_id_status =
45427df302f7SChuck Lever 			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
454303cfb420SBryan Schumaker 	nfs4_unlock_state();
454403cfb420SBryan Schumaker 
454517456804SBryan Schumaker 	return nfs_ok;
454617456804SBryan Schumaker }
454717456804SBryan Schumaker 
4548e1ca12dfSBryan Schumaker __be32
4549e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4550e1ca12dfSBryan Schumaker 		   struct nfsd4_free_stateid *free_stateid)
4551e1ca12dfSBryan Schumaker {
4552e1ca12dfSBryan Schumaker 	stateid_t *stateid = &free_stateid->fr_stateid;
45532da1cec7SJ. Bruce Fields 	struct nfs4_stid *s;
45543bd64a5bSJ. Bruce Fields 	struct nfs4_delegation *dp;
4555fc5a96c3SJeff Layton 	struct nfs4_ol_stateid *stp;
455638c2f4b1SJ. Bruce Fields 	struct nfs4_client *cl = cstate->session->se_client;
45572da1cec7SJ. Bruce Fields 	__be32 ret = nfserr_bad_stateid;
4558e1ca12dfSBryan Schumaker 
4559e1ca12dfSBryan Schumaker 	nfs4_lock_state();
45601af71cc8SJeff Layton 	spin_lock(&cl->cl_lock);
45611af71cc8SJeff Layton 	s = find_stateid_locked(cl, stateid);
45622da1cec7SJ. Bruce Fields 	if (!s)
45631af71cc8SJeff Layton 		goto out_unlock;
45642da1cec7SJ. Bruce Fields 	switch (s->sc_type) {
45652da1cec7SJ. Bruce Fields 	case NFS4_DELEG_STID:
4566e1ca12dfSBryan Schumaker 		ret = nfserr_locks_held;
45671af71cc8SJeff Layton 		break;
45682da1cec7SJ. Bruce Fields 	case NFS4_OPEN_STID:
45691af71cc8SJeff Layton 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
45701af71cc8SJeff Layton 		if (ret)
45711af71cc8SJeff Layton 			break;
45721af71cc8SJeff Layton 		ret = nfserr_locks_held;
45731af71cc8SJeff Layton 		break;
45742da1cec7SJ. Bruce Fields 	case NFS4_LOCK_STID:
45752da1cec7SJ. Bruce Fields 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
45762da1cec7SJ. Bruce Fields 		if (ret)
4577f7a4d872SJ. Bruce Fields 			break;
4578fc5a96c3SJeff Layton 		stp = openlockstateid(s);
4579fc5a96c3SJeff Layton 		ret = nfserr_locks_held;
4580fc5a96c3SJeff Layton 		if (check_for_locks(stp->st_stid.sc_file,
4581fc5a96c3SJeff Layton 				    lockowner(stp->st_stateowner)))
4582fc5a96c3SJeff Layton 			break;
4583fc5a96c3SJeff Layton 		unhash_lock_stateid(stp);
45841af71cc8SJeff Layton 		spin_unlock(&cl->cl_lock);
4585fc5a96c3SJeff Layton 		nfs4_put_stid(s);
4586fc5a96c3SJeff Layton 		ret = nfs_ok;
45871af71cc8SJeff Layton 		goto out;
45883bd64a5bSJ. Bruce Fields 	case NFS4_REVOKED_DELEG_STID:
45893bd64a5bSJ. Bruce Fields 		dp = delegstateid(s);
45902d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
45912d4a532dSJeff Layton 		spin_unlock(&cl->cl_lock);
45926011695dSTrond Myklebust 		nfs4_put_stid(s);
45933bd64a5bSJ. Bruce Fields 		ret = nfs_ok;
45941af71cc8SJeff Layton 		goto out;
45951af71cc8SJeff Layton 	/* Default falls through and returns nfserr_bad_stateid */
4596e1ca12dfSBryan Schumaker 	}
45971af71cc8SJeff Layton out_unlock:
45981af71cc8SJeff Layton 	spin_unlock(&cl->cl_lock);
4599e1ca12dfSBryan Schumaker out:
4600e1ca12dfSBryan Schumaker 	nfs4_unlock_state();
4601e1ca12dfSBryan Schumaker 	return ret;
4602e1ca12dfSBryan Schumaker }
4603e1ca12dfSBryan Schumaker 
46044c4cd222SNeilBrown static inline int
46054c4cd222SNeilBrown setlkflg (int type)
46064c4cd222SNeilBrown {
46074c4cd222SNeilBrown 	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
46084c4cd222SNeilBrown 		RD_STATE : WR_STATE;
46094c4cd222SNeilBrown }
46101da177e4SLinus Torvalds 
4611dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
4612c0a5d93eSJ. Bruce Fields {
4613c0a5d93eSJ. Bruce Fields 	struct svc_fh *current_fh = &cstate->current_fh;
4614c0a5d93eSJ. Bruce Fields 	struct nfs4_stateowner *sop = stp->st_stateowner;
4615c0a5d93eSJ. Bruce Fields 	__be32 status;
4616c0a5d93eSJ. Bruce Fields 
4617c0a5d93eSJ. Bruce Fields 	status = nfsd4_check_seqid(cstate, sop, seqid);
4618c0a5d93eSJ. Bruce Fields 	if (status)
4619c0a5d93eSJ. Bruce Fields 		return status;
46203bd64a5bSJ. Bruce Fields 	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
46213bd64a5bSJ. Bruce Fields 		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
4622f7a4d872SJ. Bruce Fields 		/*
4623f7a4d872SJ. Bruce Fields 		 * "Closed" stateid's exist *only* to return
46243bd64a5bSJ. Bruce Fields 		 * nfserr_replay_me from the previous step, and
46253bd64a5bSJ. Bruce Fields 		 * revoked delegations are kept only for free_stateid.
4626f7a4d872SJ. Bruce Fields 		 */
4627f7a4d872SJ. Bruce Fields 		return nfserr_bad_stateid;
4628f7a4d872SJ. Bruce Fields 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
4629f7a4d872SJ. Bruce Fields 	if (status)
4630f7a4d872SJ. Bruce Fields 		return status;
4631f7a4d872SJ. Bruce Fields 	return nfs4_check_fh(current_fh, stp);
4632c0a5d93eSJ. Bruce Fields }
4633c0a5d93eSJ. Bruce Fields 
46341da177e4SLinus Torvalds /*
46351da177e4SLinus Torvalds  * Checks for sequence id mutating operations.
46361da177e4SLinus Torvalds  */
4637b37ad28bSAl Viro static __be32
4638dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
46392288d0e3SJ. Bruce Fields 			 stateid_t *stateid, char typemask,
46403320fef1SStanislav Kinsbursky 			 struct nfs4_ol_stateid **stpp,
46413320fef1SStanislav Kinsbursky 			 struct nfsd_net *nn)
46421da177e4SLinus Torvalds {
46430836f587SJ. Bruce Fields 	__be32 status;
464438c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
4645e17f99b7STrond Myklebust 	struct nfs4_ol_stateid *stp = NULL;
46461da177e4SLinus Torvalds 
46478c10cbdbSBenny Halevy 	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
46488c10cbdbSBenny Halevy 		seqid, STATEID_VAL(stateid));
46491da177e4SLinus Torvalds 
46501da177e4SLinus Torvalds 	*stpp = NULL;
46512dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn);
4652c0a5d93eSJ. Bruce Fields 	if (status)
4653c0a5d93eSJ. Bruce Fields 		return status;
4654e17f99b7STrond Myklebust 	stp = openlockstateid(s);
465558fb12e6SJeff Layton 	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
46561da177e4SLinus Torvalds 
4657e17f99b7STrond Myklebust 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
4658fd911011STrond Myklebust 	if (!status)
4659e17f99b7STrond Myklebust 		*stpp = stp;
4660fd911011STrond Myklebust 	else
4661fd911011STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
4662e17f99b7STrond Myklebust 	return status;
46631da177e4SLinus Torvalds }
46641da177e4SLinus Torvalds 
46653320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
46663320fef1SStanislav Kinsbursky 						 stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn)
4667c0a5d93eSJ. Bruce Fields {
4668c0a5d93eSJ. Bruce Fields 	__be32 status;
4669c0a5d93eSJ. Bruce Fields 	struct nfs4_openowner *oo;
46704cbfc9f7STrond Myklebust 	struct nfs4_ol_stateid *stp;
46711da177e4SLinus Torvalds 
4672c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
46734cbfc9f7STrond Myklebust 						NFS4_OPEN_STID, &stp, nn);
46740836f587SJ. Bruce Fields 	if (status)
46750836f587SJ. Bruce Fields 		return status;
46764cbfc9f7STrond Myklebust 	oo = openowner(stp->st_stateowner);
46774cbfc9f7STrond Myklebust 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
46784cbfc9f7STrond Myklebust 		nfs4_put_stid(&stp->st_stid);
4679c0a5d93eSJ. Bruce Fields 		return nfserr_bad_stateid;
46804cbfc9f7STrond Myklebust 	}
46814cbfc9f7STrond Myklebust 	*stpp = stp;
46823a4f98bbSNeilBrown 	return nfs_ok;
46831da177e4SLinus Torvalds }
46841da177e4SLinus Torvalds 
4685b37ad28bSAl Viro __be32
4686ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4687a4f1706aSJ.Bruce Fields 		   struct nfsd4_open_confirm *oc)
46881da177e4SLinus Torvalds {
4689b37ad28bSAl Viro 	__be32 status;
4690fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *oo;
4691dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
46923320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
46931da177e4SLinus Torvalds 
4694a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_confirm on file %pd\n",
4695a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
46961da177e4SLinus Torvalds 
4697ca364317SJ.Bruce Fields 	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
4698a8cddc5dSJ. Bruce Fields 	if (status)
4699a8cddc5dSJ. Bruce Fields 		return status;
47001da177e4SLinus Torvalds 
47011da177e4SLinus Torvalds 	nfs4_lock_state();
47021da177e4SLinus Torvalds 
47039072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate,
4704ca364317SJ.Bruce Fields 					oc->oc_seqid, &oc->oc_req_stateid,
47053320fef1SStanislav Kinsbursky 					NFS4_OPEN_STID, &stp, nn);
47069072d5c6SJ. Bruce Fields 	if (status)
47071da177e4SLinus Torvalds 		goto out;
4708fe0750e5SJ. Bruce Fields 	oo = openowner(stp->st_stateowner);
470968b66e82SJ. Bruce Fields 	status = nfserr_bad_stateid;
4710dad1c067SJ. Bruce Fields 	if (oo->oo_flags & NFS4_OO_CONFIRMED)
47112585fc79STrond Myklebust 		goto put_stateid;
4712dad1c067SJ. Bruce Fields 	oo->oo_flags |= NFS4_OO_CONFIRMED;
4713dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4714dcef0413SJ. Bruce Fields 	memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
47158c10cbdbSBenny Halevy 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
4716dcef0413SJ. Bruce Fields 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
4717c7b9a459SNeilBrown 
47182a4317c5SJeff Layton 	nfsd4_client_record_create(oo->oo_owner.so_client);
471968b66e82SJ. Bruce Fields 	status = nfs_ok;
47202585fc79STrond Myklebust put_stateid:
47212585fc79STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
47221da177e4SLinus Torvalds out:
47239411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
47241da177e4SLinus Torvalds 	nfs4_unlock_state();
47251da177e4SLinus Torvalds 	return status;
47261da177e4SLinus Torvalds }
47271da177e4SLinus Torvalds 
47286409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
47291da177e4SLinus Torvalds {
473082c5ff1bSJeff Layton 	if (!test_access(access, stp))
47316409a5a6SJ. Bruce Fields 		return;
473211b9164aSTrond Myklebust 	nfs4_file_put_access(stp->st_stid.sc_file, access);
473382c5ff1bSJeff Layton 	clear_access(access, stp);
4734f197c271SJ. Bruce Fields }
47356409a5a6SJ. Bruce Fields 
47366409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
47376409a5a6SJ. Bruce Fields {
47386409a5a6SJ. Bruce Fields 	switch (to_access) {
47396409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_READ:
47406409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
47416409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
47426409a5a6SJ. Bruce Fields 		break;
47436409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_WRITE:
47446409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
47456409a5a6SJ. Bruce Fields 		nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
47466409a5a6SJ. Bruce Fields 		break;
47476409a5a6SJ. Bruce Fields 	case NFS4_SHARE_ACCESS_BOTH:
47486409a5a6SJ. Bruce Fields 		break;
47496409a5a6SJ. Bruce Fields 	default:
4750063b0fb9SJ. Bruce Fields 		WARN_ON_ONCE(1);
47511da177e4SLinus Torvalds 	}
47521da177e4SLinus Torvalds }
47531da177e4SLinus Torvalds 
4754b37ad28bSAl Viro __be32
4755ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp,
4756ca364317SJ.Bruce Fields 		     struct nfsd4_compound_state *cstate,
4757a4f1706aSJ.Bruce Fields 		     struct nfsd4_open_downgrade *od)
47581da177e4SLinus Torvalds {
4759b37ad28bSAl Viro 	__be32 status;
4760dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
47613320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
47621da177e4SLinus Torvalds 
4763a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_open_downgrade on file %pd\n",
4764a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
47651da177e4SLinus Torvalds 
4766c30e92dfSJ. Bruce Fields 	/* We don't yet support WANT bits: */
47672c8bd7e0SBenny Halevy 	if (od->od_deleg_want)
47682c8bd7e0SBenny Halevy 		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
47692c8bd7e0SBenny Halevy 			od->od_deleg_want);
47701da177e4SLinus Torvalds 
47711da177e4SLinus Torvalds 	nfs4_lock_state();
4772c0a5d93eSJ. Bruce Fields 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
47733320fef1SStanislav Kinsbursky 					&od->od_stateid, &stp, nn);
47749072d5c6SJ. Bruce Fields 	if (status)
47751da177e4SLinus Torvalds 		goto out;
47761da177e4SLinus Torvalds 	status = nfserr_inval;
477782c5ff1bSJeff Layton 	if (!test_access(od->od_share_access, stp)) {
4778c11c591fSJeff Layton 		dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n",
47791da177e4SLinus Torvalds 			stp->st_access_bmap, od->od_share_access);
47800667b1e9STrond Myklebust 		goto put_stateid;
47811da177e4SLinus Torvalds 	}
4782ce0fc43cSJeff Layton 	if (!test_deny(od->od_share_deny, stp)) {
4783c11c591fSJeff Layton 		dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n",
47841da177e4SLinus Torvalds 			stp->st_deny_bmap, od->od_share_deny);
47850667b1e9STrond Myklebust 		goto put_stateid;
47861da177e4SLinus Torvalds 	}
47876409a5a6SJ. Bruce Fields 	nfs4_stateid_downgrade(stp, od->od_share_access);
47881da177e4SLinus Torvalds 
4789ce0fc43cSJeff Layton 	reset_union_bmap_deny(od->od_share_deny, stp);
47901da177e4SLinus Torvalds 
4791dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4792dcef0413SJ. Bruce Fields 	memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
47931da177e4SLinus Torvalds 	status = nfs_ok;
47940667b1e9STrond Myklebust put_stateid:
47950667b1e9STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
47961da177e4SLinus Torvalds out:
47979411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
47981da177e4SLinus Torvalds 	nfs4_unlock_state();
47991da177e4SLinus Torvalds 	return status;
48001da177e4SLinus Torvalds }
48011da177e4SLinus Torvalds 
4802f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
4803f7a4d872SJ. Bruce Fields {
4804acf9295bSTrond Myklebust 	struct nfs4_client *clp = s->st_stid.sc_client;
4805d83017f9SJeff Layton 	LIST_HEAD(reaplist);
4806acf9295bSTrond Myklebust 
4807f7a4d872SJ. Bruce Fields 	s->st_stid.sc_type = NFS4_CLOSED_STID;
48082c41beb0SJeff Layton 	spin_lock(&clp->cl_lock);
4809d83017f9SJeff Layton 	unhash_open_stateid(s, &reaplist);
4810acf9295bSTrond Myklebust 
4811d83017f9SJeff Layton 	if (clp->cl_minorversion) {
4812d83017f9SJeff Layton 		put_ol_stateid_locked(s, &reaplist);
4813d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
4814d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
4815d83017f9SJeff Layton 	} else {
4816d83017f9SJeff Layton 		spin_unlock(&clp->cl_lock);
4817d83017f9SJeff Layton 		free_ol_stateid_reaplist(&reaplist);
4818d3134b10SJeff Layton 		move_to_close_lru(s, clp->net);
481938c387b5SJ. Bruce Fields 	}
4820d83017f9SJeff Layton }
482138c387b5SJ. Bruce Fields 
48221da177e4SLinus Torvalds /*
48231da177e4SLinus Torvalds  * nfs4_unlock_state() called after encode
48241da177e4SLinus Torvalds  */
4825b37ad28bSAl Viro __be32
4826ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4827a4f1706aSJ.Bruce Fields 	    struct nfsd4_close *close)
48281da177e4SLinus Torvalds {
4829b37ad28bSAl Viro 	__be32 status;
4830dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
48313320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
48323320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
48331da177e4SLinus Torvalds 
4834a6a9f18fSAl Viro 	dprintk("NFSD: nfsd4_close on file %pd\n",
4835a6a9f18fSAl Viro 			cstate->current_fh.fh_dentry);
48361da177e4SLinus Torvalds 
48371da177e4SLinus Torvalds 	nfs4_lock_state();
4838f7a4d872SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
4839f7a4d872SJ. Bruce Fields 					&close->cl_stateid,
4840f7a4d872SJ. Bruce Fields 					NFS4_OPEN_STID|NFS4_CLOSED_STID,
48413320fef1SStanislav Kinsbursky 					&stp, nn);
48429411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
48439072d5c6SJ. Bruce Fields 	if (status)
48441da177e4SLinus Torvalds 		goto out;
4845dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
4846dcef0413SJ. Bruce Fields 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
48471da177e4SLinus Torvalds 
4848f7a4d872SJ. Bruce Fields 	nfsd4_close_open_stateid(stp);
48498a0b589dSTrond Myklebust 
48508a0b589dSTrond Myklebust 	/* put reference from nfs4_preprocess_seqid_op */
48518a0b589dSTrond Myklebust 	nfs4_put_stid(&stp->st_stid);
48521da177e4SLinus Torvalds out:
48531da177e4SLinus Torvalds 	nfs4_unlock_state();
48541da177e4SLinus Torvalds 	return status;
48551da177e4SLinus Torvalds }
48561da177e4SLinus Torvalds 
4857b37ad28bSAl Viro __be32
4858ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4859ca364317SJ.Bruce Fields 		  struct nfsd4_delegreturn *dr)
48601da177e4SLinus Torvalds {
4861203a8c8eSJ. Bruce Fields 	struct nfs4_delegation *dp;
4862203a8c8eSJ. Bruce Fields 	stateid_t *stateid = &dr->dr_stateid;
486338c2f4b1SJ. Bruce Fields 	struct nfs4_stid *s;
4864b37ad28bSAl Viro 	__be32 status;
48653320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
48661da177e4SLinus Torvalds 
4867ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
4868203a8c8eSJ. Bruce Fields 		return status;
48691da177e4SLinus Torvalds 
48701da177e4SLinus Torvalds 	nfs4_lock_state();
48712dd6e458STrond Myklebust 	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
487238c2f4b1SJ. Bruce Fields 	if (status)
4873203a8c8eSJ. Bruce Fields 		goto out;
487438c2f4b1SJ. Bruce Fields 	dp = delegstateid(s);
4875d5477a8dSJ. Bruce Fields 	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
4876203a8c8eSJ. Bruce Fields 	if (status)
4877fd911011STrond Myklebust 		goto put_stateid;
4878203a8c8eSJ. Bruce Fields 
48793bd64a5bSJ. Bruce Fields 	destroy_delegation(dp);
4880fd911011STrond Myklebust put_stateid:
4881fd911011STrond Myklebust 	nfs4_put_stid(&dp->dl_stid);
48821da177e4SLinus Torvalds out:
4883203a8c8eSJ. Bruce Fields 	nfs4_unlock_state();
4884203a8c8eSJ. Bruce Fields 
48851da177e4SLinus Torvalds 	return status;
48861da177e4SLinus Torvalds }
48871da177e4SLinus Torvalds 
48881da177e4SLinus Torvalds 
48891da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
48901da177e4SLinus Torvalds 
489187df4de8SBenny Halevy static inline u64
489287df4de8SBenny Halevy end_offset(u64 start, u64 len)
489387df4de8SBenny Halevy {
489487df4de8SBenny Halevy 	u64 end;
489587df4de8SBenny Halevy 
489687df4de8SBenny Halevy 	end = start + len;
489787df4de8SBenny Halevy 	return end >= start ? end: NFS4_MAX_UINT64;
489887df4de8SBenny Halevy }
489987df4de8SBenny Halevy 
490087df4de8SBenny Halevy /* last octet in a range */
490187df4de8SBenny Halevy static inline u64
490287df4de8SBenny Halevy last_byte_offset(u64 start, u64 len)
490387df4de8SBenny Halevy {
490487df4de8SBenny Halevy 	u64 end;
490587df4de8SBenny Halevy 
4906063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(!len);
490787df4de8SBenny Halevy 	end = start + len;
490887df4de8SBenny Halevy 	return end > start ? end - 1: NFS4_MAX_UINT64;
490987df4de8SBenny Halevy }
491087df4de8SBenny Halevy 
49111da177e4SLinus Torvalds /*
49121da177e4SLinus Torvalds  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
49131da177e4SLinus Torvalds  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
49141da177e4SLinus Torvalds  * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
49151da177e4SLinus Torvalds  * locking, this prevents us from being completely protocol-compliant.  The
49161da177e4SLinus Torvalds  * real solution to this problem is to start using unsigned file offsets in
49171da177e4SLinus Torvalds  * the VFS, but this is a very deep change!
49181da177e4SLinus Torvalds  */
49191da177e4SLinus Torvalds static inline void
49201da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock)
49211da177e4SLinus Torvalds {
49221da177e4SLinus Torvalds 	if (lock->fl_start < 0)
49231da177e4SLinus Torvalds 		lock->fl_start = OFFSET_MAX;
49241da177e4SLinus Torvalds 	if (lock->fl_end < 0)
49251da177e4SLinus Torvalds 		lock->fl_end = OFFSET_MAX;
49261da177e4SLinus Torvalds }
49271da177e4SLinus Torvalds 
4928d5b9026aSNeilBrown /* Hack!: For now, we're defining this just so we can use a pointer to it
4929d5b9026aSNeilBrown  * as a unique cookie to identify our (NFSv4's) posix locks. */
49307b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops  = {
4931d5b9026aSNeilBrown };
49321da177e4SLinus Torvalds 
49331da177e4SLinus Torvalds static inline void
49341da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
49351da177e4SLinus Torvalds {
4936fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lo;
49371da177e4SLinus Torvalds 
4938d5b9026aSNeilBrown 	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
4939fe0750e5SJ. Bruce Fields 		lo = (struct nfs4_lockowner *) fl->fl_owner;
4940fe0750e5SJ. Bruce Fields 		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
4941fe0750e5SJ. Bruce Fields 					lo->lo_owner.so_owner.len, GFP_KERNEL);
49427c13f344SJ. Bruce Fields 		if (!deny->ld_owner.data)
49437c13f344SJ. Bruce Fields 			/* We just don't care that much */
49447c13f344SJ. Bruce Fields 			goto nevermind;
4945fe0750e5SJ. Bruce Fields 		deny->ld_owner.len = lo->lo_owner.so_owner.len;
4946fe0750e5SJ. Bruce Fields 		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
4947d5b9026aSNeilBrown 	} else {
49487c13f344SJ. Bruce Fields nevermind:
49497c13f344SJ. Bruce Fields 		deny->ld_owner.len = 0;
49507c13f344SJ. Bruce Fields 		deny->ld_owner.data = NULL;
4951d5b9026aSNeilBrown 		deny->ld_clientid.cl_boot = 0;
4952d5b9026aSNeilBrown 		deny->ld_clientid.cl_id = 0;
49531da177e4SLinus Torvalds 	}
49541da177e4SLinus Torvalds 	deny->ld_start = fl->fl_start;
495587df4de8SBenny Halevy 	deny->ld_length = NFS4_MAX_UINT64;
495687df4de8SBenny Halevy 	if (fl->fl_end != NFS4_MAX_UINT64)
49571da177e4SLinus Torvalds 		deny->ld_length = fl->fl_end - fl->fl_start + 1;
49581da177e4SLinus Torvalds 	deny->ld_type = NFS4_READ_LT;
49591da177e4SLinus Torvalds 	if (fl->fl_type != F_RDLCK)
49601da177e4SLinus Torvalds 		deny->ld_type = NFS4_WRITE_LT;
49611da177e4SLinus Torvalds }
49621da177e4SLinus Torvalds 
4963fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
4964c58c6610STrond Myklebust find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
4965d4f0489fSTrond Myklebust 		struct nfs4_client *clp)
49661da177e4SLinus Torvalds {
4967d4f0489fSTrond Myklebust 	unsigned int strhashval = ownerstr_hashval(owner);
4968b3c32bcdSTrond Myklebust 	struct nfs4_stateowner *so;
49691da177e4SLinus Torvalds 
49700a880a28STrond Myklebust 	lockdep_assert_held(&clp->cl_lock);
49710a880a28STrond Myklebust 
4972d4f0489fSTrond Myklebust 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval],
4973d4f0489fSTrond Myklebust 			    so_strhash) {
4974b3c32bcdSTrond Myklebust 		if (so->so_is_open_owner)
4975b3c32bcdSTrond Myklebust 			continue;
4976d4f0489fSTrond Myklebust 		if (!same_owner_str(so, owner))
4977b3c32bcdSTrond Myklebust 			continue;
49785db1c03fSJeff Layton 		atomic_inc(&so->so_count);
4979b3c32bcdSTrond Myklebust 		return lockowner(so);
49801da177e4SLinus Torvalds 	}
49811da177e4SLinus Torvalds 	return NULL;
49821da177e4SLinus Torvalds }
49831da177e4SLinus Torvalds 
4984c58c6610STrond Myklebust static struct nfs4_lockowner *
4985c58c6610STrond Myklebust find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
4986d4f0489fSTrond Myklebust 		struct nfs4_client *clp)
4987c58c6610STrond Myklebust {
4988c58c6610STrond Myklebust 	struct nfs4_lockowner *lo;
4989c58c6610STrond Myklebust 
4990d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
4991d4f0489fSTrond Myklebust 	lo = find_lockowner_str_locked(clid, owner, clp);
4992d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
4993c58c6610STrond Myklebust 	return lo;
4994c58c6610STrond Myklebust }
4995c58c6610STrond Myklebust 
49968f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
49978f4b54c5SJeff Layton {
4998c58c6610STrond Myklebust 	unhash_lockowner_locked(lockowner(sop));
49998f4b54c5SJeff Layton }
50008f4b54c5SJeff Layton 
50016b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
50026b180f0bSJeff Layton {
50036b180f0bSJeff Layton 	struct nfs4_lockowner *lo = lockowner(sop);
50046b180f0bSJeff Layton 
50056b180f0bSJeff Layton 	kmem_cache_free(lockowner_slab, lo);
50066b180f0bSJeff Layton }
50076b180f0bSJeff Layton 
50086b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = {
50098f4b54c5SJeff Layton 	.so_unhash =	nfs4_unhash_lockowner,
50106b180f0bSJeff Layton 	.so_free =	nfs4_free_lockowner,
50116b180f0bSJeff Layton };
50126b180f0bSJeff Layton 
50131da177e4SLinus Torvalds /*
50141da177e4SLinus Torvalds  * Alloc a lock owner structure.
50151da177e4SLinus Torvalds  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
501625985edcSLucas De Marchi  * occurred.
50171da177e4SLinus Torvalds  *
501816bfdaafSJ. Bruce Fields  * strhashval = ownerstr_hashval
50191da177e4SLinus Torvalds  */
5020fe0750e5SJ. Bruce Fields static struct nfs4_lockowner *
5021c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
5022c58c6610STrond Myklebust 			   struct nfs4_ol_stateid *open_stp,
5023c58c6610STrond Myklebust 			   struct nfsd4_lock *lock)
5024c58c6610STrond Myklebust {
5025c58c6610STrond Myklebust 	struct nfs4_lockowner *lo, *ret;
50261da177e4SLinus Torvalds 
5027fe0750e5SJ. Bruce Fields 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
5028fe0750e5SJ. Bruce Fields 	if (!lo)
50291da177e4SLinus Torvalds 		return NULL;
5030fe0750e5SJ. Bruce Fields 	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
5031fe0750e5SJ. Bruce Fields 	lo->lo_owner.so_is_open_owner = 0;
50325db1c03fSJeff Layton 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
50336b180f0bSJeff Layton 	lo->lo_owner.so_ops = &lockowner_ops;
5034d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5035c58c6610STrond Myklebust 	ret = find_lockowner_str_locked(&clp->cl_clientid,
5036d4f0489fSTrond Myklebust 			&lock->lk_new_owner, clp);
5037c58c6610STrond Myklebust 	if (ret == NULL) {
5038c58c6610STrond Myklebust 		list_add(&lo->lo_owner.so_strhash,
5039d4f0489fSTrond Myklebust 			 &clp->cl_ownerstr_hashtbl[strhashval]);
5040c58c6610STrond Myklebust 		ret = lo;
5041c58c6610STrond Myklebust 	} else
5042c58c6610STrond Myklebust 		nfs4_free_lockowner(&lo->lo_owner);
5043d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5044fe0750e5SJ. Bruce Fields 	return lo;
50451da177e4SLinus Torvalds }
50461da177e4SLinus Torvalds 
5047356a95ecSJeff Layton static void
5048356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5049356a95ecSJeff Layton 		  struct nfs4_file *fp, struct inode *inode,
5050f9c00c3aSJeff Layton 		  struct nfs4_ol_stateid *open_stp)
50511da177e4SLinus Torvalds {
5052d3b313a4SJ. Bruce Fields 	struct nfs4_client *clp = lo->lo_owner.so_client;
50531da177e4SLinus Torvalds 
5054356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5055356a95ecSJeff Layton 
50563d0fabd5STrond Myklebust 	atomic_inc(&stp->st_stid.sc_count);
50573abdb607SJ. Bruce Fields 	stp->st_stid.sc_type = NFS4_LOCK_STID;
5058fe0750e5SJ. Bruce Fields 	stp->st_stateowner = &lo->lo_owner;
5059e4f1dd7fSTrond Myklebust 	atomic_inc(&lo->lo_owner.so_count);
506013cd2184SNeilBrown 	get_nfs4_file(fp);
506111b9164aSTrond Myklebust 	stp->st_stid.sc_file = fp;
5062b49e084dSJeff Layton 	stp->st_stid.sc_free = nfs4_free_lock_stateid;
50630997b173SJ. Bruce Fields 	stp->st_access_bmap = 0;
50641da177e4SLinus Torvalds 	stp->st_deny_bmap = open_stp->st_deny_bmap;
50654c4cd222SNeilBrown 	stp->st_openstp = open_stp;
50663c87b9b7STrond Myklebust 	list_add(&stp->st_locks, &open_stp->st_locks);
50671c755dc1SJeff Layton 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
50681d31a253STrond Myklebust 	spin_lock(&fp->fi_lock);
50691d31a253STrond Myklebust 	list_add(&stp->st_perfile, &fp->fi_stateids);
50701d31a253STrond Myklebust 	spin_unlock(&fp->fi_lock);
50711da177e4SLinus Torvalds }
50721da177e4SLinus Torvalds 
5073c53530daSJeff Layton static struct nfs4_ol_stateid *
5074c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
5075c53530daSJeff Layton {
5076c53530daSJeff Layton 	struct nfs4_ol_stateid *lst;
5077356a95ecSJeff Layton 	struct nfs4_client *clp = lo->lo_owner.so_client;
5078356a95ecSJeff Layton 
5079356a95ecSJeff Layton 	lockdep_assert_held(&clp->cl_lock);
5080c53530daSJeff Layton 
5081c53530daSJeff Layton 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
50823d0fabd5STrond Myklebust 		if (lst->st_stid.sc_file == fp) {
50833d0fabd5STrond Myklebust 			atomic_inc(&lst->st_stid.sc_count);
5084c53530daSJeff Layton 			return lst;
5085c53530daSJeff Layton 		}
50863d0fabd5STrond Myklebust 	}
5087c53530daSJeff Layton 	return NULL;
5088c53530daSJeff Layton }
5089c53530daSJeff Layton 
5090356a95ecSJeff Layton static struct nfs4_ol_stateid *
5091356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
5092356a95ecSJeff Layton 			    struct inode *inode, struct nfs4_ol_stateid *ost,
5093356a95ecSJeff Layton 			    bool *new)
5094356a95ecSJeff Layton {
5095356a95ecSJeff Layton 	struct nfs4_stid *ns = NULL;
5096356a95ecSJeff Layton 	struct nfs4_ol_stateid *lst;
5097356a95ecSJeff Layton 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
5098356a95ecSJeff Layton 	struct nfs4_client *clp = oo->oo_owner.so_client;
5099356a95ecSJeff Layton 
5100356a95ecSJeff Layton 	spin_lock(&clp->cl_lock);
5101356a95ecSJeff Layton 	lst = find_lock_stateid(lo, fi);
5102356a95ecSJeff Layton 	if (lst == NULL) {
5103356a95ecSJeff Layton 		spin_unlock(&clp->cl_lock);
5104356a95ecSJeff Layton 		ns = nfs4_alloc_stid(clp, stateid_slab);
5105356a95ecSJeff Layton 		if (ns == NULL)
5106356a95ecSJeff Layton 			return NULL;
5107356a95ecSJeff Layton 
5108356a95ecSJeff Layton 		spin_lock(&clp->cl_lock);
5109356a95ecSJeff Layton 		lst = find_lock_stateid(lo, fi);
5110356a95ecSJeff Layton 		if (likely(!lst)) {
5111356a95ecSJeff Layton 			lst = openlockstateid(ns);
5112356a95ecSJeff Layton 			init_lock_stateid(lst, lo, fi, inode, ost);
5113356a95ecSJeff Layton 			ns = NULL;
5114356a95ecSJeff Layton 			*new = true;
5115356a95ecSJeff Layton 		}
5116356a95ecSJeff Layton 	}
5117356a95ecSJeff Layton 	spin_unlock(&clp->cl_lock);
5118356a95ecSJeff Layton 	if (ns)
5119356a95ecSJeff Layton 		nfs4_put_stid(ns);
5120356a95ecSJeff Layton 	return lst;
5121356a95ecSJeff Layton }
5122c53530daSJeff Layton 
5123fd39ca9aSNeilBrown static int
51241da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length)
51251da177e4SLinus Torvalds {
512687df4de8SBenny Halevy 	return ((length == 0)  || ((length != NFS4_MAX_UINT64) &&
51271da177e4SLinus Torvalds 	     LOFF_OVERFLOW(offset, length)));
51281da177e4SLinus Torvalds }
51291da177e4SLinus Torvalds 
5130dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
51310997b173SJ. Bruce Fields {
513211b9164aSTrond Myklebust 	struct nfs4_file *fp = lock_stp->st_stid.sc_file;
51330997b173SJ. Bruce Fields 
51347214e860SJeff Layton 	lockdep_assert_held(&fp->fi_lock);
51357214e860SJeff Layton 
513682c5ff1bSJeff Layton 	if (test_access(access, lock_stp))
51370997b173SJ. Bruce Fields 		return;
513812659651SJeff Layton 	__nfs4_file_get_access(fp, access);
513982c5ff1bSJeff Layton 	set_access(access, lock_stp);
51400997b173SJ. Bruce Fields }
51410997b173SJ. Bruce Fields 
5142356a95ecSJeff Layton static __be32
5143356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5144356a95ecSJeff Layton 			    struct nfs4_ol_stateid *ost,
5145356a95ecSJeff Layton 			    struct nfsd4_lock *lock,
5146356a95ecSJeff Layton 			    struct nfs4_ol_stateid **lst, bool *new)
514764a284d0SJ. Bruce Fields {
51485db1c03fSJeff Layton 	__be32 status;
514911b9164aSTrond Myklebust 	struct nfs4_file *fi = ost->st_stid.sc_file;
515064a284d0SJ. Bruce Fields 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
515164a284d0SJ. Bruce Fields 	struct nfs4_client *cl = oo->oo_owner.so_client;
5152f9c00c3aSJeff Layton 	struct inode *inode = cstate->current_fh.fh_dentry->d_inode;
515364a284d0SJ. Bruce Fields 	struct nfs4_lockowner *lo;
515464a284d0SJ. Bruce Fields 	unsigned int strhashval;
515564a284d0SJ. Bruce Fields 
5156d4f0489fSTrond Myklebust 	lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, cl);
5157c53530daSJeff Layton 	if (!lo) {
5158d4f0489fSTrond Myklebust 		strhashval = ownerstr_hashval(&lock->v.new.owner);
515964a284d0SJ. Bruce Fields 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
516064a284d0SJ. Bruce Fields 		if (lo == NULL)
516164a284d0SJ. Bruce Fields 			return nfserr_jukebox;
5162c53530daSJeff Layton 	} else {
5163c53530daSJeff Layton 		/* with an existing lockowner, seqids must be the same */
51645db1c03fSJeff Layton 		status = nfserr_bad_seqid;
5165c53530daSJeff Layton 		if (!cstate->minorversion &&
5166c53530daSJeff Layton 		    lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
51675db1c03fSJeff Layton 			goto out;
5168c53530daSJeff Layton 	}
5169c53530daSJeff Layton 
5170356a95ecSJeff Layton 	*lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
517164a284d0SJ. Bruce Fields 	if (*lst == NULL) {
51725db1c03fSJeff Layton 		status = nfserr_jukebox;
51735db1c03fSJeff Layton 		goto out;
517464a284d0SJ. Bruce Fields 	}
51755db1c03fSJeff Layton 	status = nfs_ok;
51765db1c03fSJeff Layton out:
51775db1c03fSJeff Layton 	nfs4_put_stateowner(&lo->lo_owner);
51785db1c03fSJeff Layton 	return status;
517964a284d0SJ. Bruce Fields }
518064a284d0SJ. Bruce Fields 
51811da177e4SLinus Torvalds /*
51821da177e4SLinus Torvalds  *  LOCK operation
51831da177e4SLinus Torvalds  */
5184b37ad28bSAl Viro __be32
5185ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5186a4f1706aSJ.Bruce Fields 	   struct nfsd4_lock *lock)
51871da177e4SLinus Torvalds {
5188fe0750e5SJ. Bruce Fields 	struct nfs4_openowner *open_sop = NULL;
5189fe0750e5SJ. Bruce Fields 	struct nfs4_lockowner *lock_sop = NULL;
51903d0fabd5STrond Myklebust 	struct nfs4_ol_stateid *lock_stp = NULL;
51910667b1e9STrond Myklebust 	struct nfs4_ol_stateid *open_stp = NULL;
51927214e860SJeff Layton 	struct nfs4_file *fp;
51937d947842SJ. Bruce Fields 	struct file *filp = NULL;
519421179d81SJeff Layton 	struct file_lock *file_lock = NULL;
519521179d81SJeff Layton 	struct file_lock *conflock = NULL;
5196b37ad28bSAl Viro 	__be32 status = 0;
5197b34f27aaSJ. Bruce Fields 	int lkflg;
5198b8dd7b9aSAl Viro 	int err;
51995db1c03fSJeff Layton 	bool new = false;
52003320fef1SStanislav Kinsbursky 	struct net *net = SVC_NET(rqstp);
52013320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
52021da177e4SLinus Torvalds 
52031da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
52041da177e4SLinus Torvalds 		(long long) lock->lk_offset,
52051da177e4SLinus Torvalds 		(long long) lock->lk_length);
52061da177e4SLinus Torvalds 
52071da177e4SLinus Torvalds 	if (check_lock_length(lock->lk_offset, lock->lk_length))
52081da177e4SLinus Torvalds 		 return nfserr_inval;
52091da177e4SLinus Torvalds 
5210ca364317SJ.Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh,
52118837abcaSMiklos Szeredi 				S_IFREG, NFSD_MAY_LOCK))) {
5212a6f6ef2fSAndy Adamson 		dprintk("NFSD: nfsd4_lock: permission denied!\n");
5213a6f6ef2fSAndy Adamson 		return status;
5214a6f6ef2fSAndy Adamson 	}
5215a6f6ef2fSAndy Adamson 
52161da177e4SLinus Torvalds 	nfs4_lock_state();
52171da177e4SLinus Torvalds 
52181da177e4SLinus Torvalds 	if (lock->lk_is_new) {
5219684e5638SJ. Bruce Fields 		if (nfsd4_has_session(cstate))
5220684e5638SJ. Bruce Fields 			/* See rfc 5661 18.10.3: given clientid is ignored: */
5221684e5638SJ. Bruce Fields 			memcpy(&lock->v.new.clientid,
5222684e5638SJ. Bruce Fields 				&cstate->session->se_client->cl_clientid,
5223684e5638SJ. Bruce Fields 				sizeof(clientid_t));
5224684e5638SJ. Bruce Fields 
52251da177e4SLinus Torvalds 		status = nfserr_stale_clientid;
52262c142baaSStanislav Kinsbursky 		if (STALE_CLIENTID(&lock->lk_new_clientid, nn))
52271da177e4SLinus Torvalds 			goto out;
52281da177e4SLinus Torvalds 
52291da177e4SLinus Torvalds 		/* validate and update open stateid and open seqid */
5230c0a5d93eSJ. Bruce Fields 		status = nfs4_preprocess_confirmed_seqid_op(cstate,
52311da177e4SLinus Torvalds 				        lock->lk_new_open_seqid,
52321da177e4SLinus Torvalds 		                        &lock->lk_new_open_stateid,
52333320fef1SStanislav Kinsbursky 					&open_stp, nn);
523437515177SNeilBrown 		if (status)
52351da177e4SLinus Torvalds 			goto out;
5236fe0750e5SJ. Bruce Fields 		open_sop = openowner(open_stp->st_stateowner);
5237b34f27aaSJ. Bruce Fields 		status = nfserr_bad_stateid;
5238684e5638SJ. Bruce Fields 		if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
5239b34f27aaSJ. Bruce Fields 						&lock->v.new.clientid))
5240b34f27aaSJ. Bruce Fields 			goto out;
524164a284d0SJ. Bruce Fields 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
52425db1c03fSJeff Layton 							&lock_stp, &new);
52433d0fabd5STrond Myklebust 	} else {
5244dd453dfdSBenny Halevy 		status = nfs4_preprocess_seqid_op(cstate,
52451da177e4SLinus Torvalds 				       lock->lk_old_lock_seqid,
52461da177e4SLinus Torvalds 				       &lock->lk_old_lock_stateid,
52473320fef1SStanislav Kinsbursky 				       NFS4_LOCK_STID, &lock_stp, nn);
52483d0fabd5STrond Myklebust 	}
52491da177e4SLinus Torvalds 	if (status)
52501da177e4SLinus Torvalds 		goto out;
5251fe0750e5SJ. Bruce Fields 	lock_sop = lockowner(lock_stp->st_stateowner);
52521da177e4SLinus Torvalds 
5253b34f27aaSJ. Bruce Fields 	lkflg = setlkflg(lock->lk_type);
5254b34f27aaSJ. Bruce Fields 	status = nfs4_check_openmode(lock_stp, lkflg);
5255b34f27aaSJ. Bruce Fields 	if (status)
5256b34f27aaSJ. Bruce Fields 		goto out;
5257b34f27aaSJ. Bruce Fields 
52580dd395dcSNeilBrown 	status = nfserr_grace;
52593320fef1SStanislav Kinsbursky 	if (locks_in_grace(net) && !lock->lk_reclaim)
52600dd395dcSNeilBrown 		goto out;
52610dd395dcSNeilBrown 	status = nfserr_no_grace;
52623320fef1SStanislav Kinsbursky 	if (!locks_in_grace(net) && lock->lk_reclaim)
52630dd395dcSNeilBrown 		goto out;
52640dd395dcSNeilBrown 
526521179d81SJeff Layton 	file_lock = locks_alloc_lock();
526621179d81SJeff Layton 	if (!file_lock) {
526721179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
526821179d81SJeff Layton 		status = nfserr_jukebox;
526921179d81SJeff Layton 		goto out;
527021179d81SJeff Layton 	}
527121179d81SJeff Layton 
527211b9164aSTrond Myklebust 	fp = lock_stp->st_stid.sc_file;
527321179d81SJeff Layton 	locks_init_lock(file_lock);
52741da177e4SLinus Torvalds 	switch (lock->lk_type) {
52751da177e4SLinus Torvalds 		case NFS4_READ_LT:
52761da177e4SLinus Torvalds 		case NFS4_READW_LT:
52777214e860SJeff Layton 			spin_lock(&fp->fi_lock);
52787214e860SJeff Layton 			filp = find_readable_file_locked(fp);
52790997b173SJ. Bruce Fields 			if (filp)
52800997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
52817214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
528221179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
52831da177e4SLinus Torvalds 			break;
52841da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
52851da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
52867214e860SJeff Layton 			spin_lock(&fp->fi_lock);
52877214e860SJeff Layton 			filp = find_writeable_file_locked(fp);
52880997b173SJ. Bruce Fields 			if (filp)
52890997b173SJ. Bruce Fields 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
52907214e860SJeff Layton 			spin_unlock(&fp->fi_lock);
529121179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
52921da177e4SLinus Torvalds 			break;
52931da177e4SLinus Torvalds 		default:
52941da177e4SLinus Torvalds 			status = nfserr_inval;
52951da177e4SLinus Torvalds 		goto out;
52961da177e4SLinus Torvalds 	}
5297f9d7562fSJ. Bruce Fields 	if (!filp) {
5298f9d7562fSJ. Bruce Fields 		status = nfserr_openmode;
5299f9d7562fSJ. Bruce Fields 		goto out;
5300f9d7562fSJ. Bruce Fields 	}
530121179d81SJeff Layton 	file_lock->fl_owner = (fl_owner_t)lock_sop;
530221179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
530321179d81SJeff Layton 	file_lock->fl_file = filp;
530421179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
530521179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
530621179d81SJeff Layton 	file_lock->fl_start = lock->lk_offset;
530721179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
530821179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
53091da177e4SLinus Torvalds 
531021179d81SJeff Layton 	conflock = locks_alloc_lock();
531121179d81SJeff Layton 	if (!conflock) {
531221179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
531321179d81SJeff Layton 		status = nfserr_jukebox;
531421179d81SJeff Layton 		goto out;
531521179d81SJeff Layton 	}
53161da177e4SLinus Torvalds 
531721179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
5318b8dd7b9aSAl Viro 	switch (-err) {
53191da177e4SLinus Torvalds 	case 0: /* success! */
5320dcef0413SJ. Bruce Fields 		update_stateid(&lock_stp->st_stid.sc_stateid);
5321dcef0413SJ. Bruce Fields 		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
53221da177e4SLinus Torvalds 				sizeof(stateid_t));
5323b8dd7b9aSAl Viro 		status = 0;
5324eb76b3fdSAndy Adamson 		break;
5325eb76b3fdSAndy Adamson 	case (EAGAIN):		/* conflock holds conflicting lock */
5326eb76b3fdSAndy Adamson 		status = nfserr_denied;
5327eb76b3fdSAndy Adamson 		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
532821179d81SJeff Layton 		nfs4_set_lock_denied(conflock, &lock->lk_denied);
5329eb76b3fdSAndy Adamson 		break;
53301da177e4SLinus Torvalds 	case (EDEADLK):
53311da177e4SLinus Torvalds 		status = nfserr_deadlock;
5332eb76b3fdSAndy Adamson 		break;
53331da177e4SLinus Torvalds 	default:
5334fd85b817SMarc Eshel 		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
53353e772463SJ. Bruce Fields 		status = nfserrno(err);
5336eb76b3fdSAndy Adamson 		break;
53371da177e4SLinus Torvalds 	}
53381da177e4SLinus Torvalds out:
5339de18643dSTrond Myklebust 	if (filp)
5340de18643dSTrond Myklebust 		fput(filp);
53415db1c03fSJeff Layton 	if (lock_stp) {
53425db1c03fSJeff Layton 		/* Bump seqid manually if the 4.0 replay owner is openowner */
53435db1c03fSJeff Layton 		if (cstate->replay_owner &&
53445db1c03fSJeff Layton 		    cstate->replay_owner != &lock_sop->lo_owner &&
53455db1c03fSJeff Layton 		    seqid_mutating_err(ntohl(status)))
53465db1c03fSJeff Layton 			lock_sop->lo_owner.so_seqid++;
53475db1c03fSJeff Layton 
53485db1c03fSJeff Layton 		/*
53495db1c03fSJeff Layton 		 * If this is a new, never-before-used stateid, and we are
53505db1c03fSJeff Layton 		 * returning an error, then just go ahead and release it.
53515db1c03fSJeff Layton 		 */
53525db1c03fSJeff Layton 		if (status && new)
53535db1c03fSJeff Layton 			release_lock_stateid(lock_stp);
53545db1c03fSJeff Layton 
53553d0fabd5STrond Myklebust 		nfs4_put_stid(&lock_stp->st_stid);
53565db1c03fSJeff Layton 	}
53570667b1e9STrond Myklebust 	if (open_stp)
53580667b1e9STrond Myklebust 		nfs4_put_stid(&open_stp->st_stid);
53599411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
53601da177e4SLinus Torvalds 	nfs4_unlock_state();
536121179d81SJeff Layton 	if (file_lock)
536221179d81SJeff Layton 		locks_free_lock(file_lock);
536321179d81SJeff Layton 	if (conflock)
536421179d81SJeff Layton 		locks_free_lock(conflock);
53651da177e4SLinus Torvalds 	return status;
53661da177e4SLinus Torvalds }
53671da177e4SLinus Torvalds 
53681da177e4SLinus Torvalds /*
536955ef1274SJ. Bruce Fields  * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
537055ef1274SJ. Bruce Fields  * so we do a temporary open here just to get an open file to pass to
537155ef1274SJ. Bruce Fields  * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
537255ef1274SJ. Bruce Fields  * inode operation.)
537355ef1274SJ. Bruce Fields  */
537404da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
537555ef1274SJ. Bruce Fields {
537655ef1274SJ. Bruce Fields 	struct file *file;
537704da6e9dSAl Viro 	__be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
537804da6e9dSAl Viro 	if (!err) {
537904da6e9dSAl Viro 		err = nfserrno(vfs_test_lock(file, lock));
538055ef1274SJ. Bruce Fields 		nfsd_close(file);
538104da6e9dSAl Viro 	}
538255ef1274SJ. Bruce Fields 	return err;
538355ef1274SJ. Bruce Fields }
538455ef1274SJ. Bruce Fields 
538555ef1274SJ. Bruce Fields /*
53861da177e4SLinus Torvalds  * LOCKT operation
53871da177e4SLinus Torvalds  */
5388b37ad28bSAl Viro __be32
5389ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5390ca364317SJ.Bruce Fields 	    struct nfsd4_lockt *lockt)
53911da177e4SLinus Torvalds {
539221179d81SJeff Layton 	struct file_lock *file_lock = NULL;
53935db1c03fSJeff Layton 	struct nfs4_lockowner *lo = NULL;
5394b37ad28bSAl Viro 	__be32 status;
53957f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
53961da177e4SLinus Torvalds 
53975ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp)))
53981da177e4SLinus Torvalds 		return nfserr_grace;
53991da177e4SLinus Torvalds 
54001da177e4SLinus Torvalds 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
54011da177e4SLinus Torvalds 		 return nfserr_inval;
54021da177e4SLinus Torvalds 
54031da177e4SLinus Torvalds 	nfs4_lock_state();
54041da177e4SLinus Torvalds 
54059b2ef62bSJ. Bruce Fields 	if (!nfsd4_has_session(cstate)) {
54064b24ca7dSJeff Layton 		status = lookup_clientid(&lockt->lt_clientid, cstate, nn);
54079b2ef62bSJ. Bruce Fields 		if (status)
54081da177e4SLinus Torvalds 			goto out;
54099b2ef62bSJ. Bruce Fields 	}
54101da177e4SLinus Torvalds 
541175c096f7SJ. Bruce Fields 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
54121da177e4SLinus Torvalds 		goto out;
54131da177e4SLinus Torvalds 
541421179d81SJeff Layton 	file_lock = locks_alloc_lock();
541521179d81SJeff Layton 	if (!file_lock) {
541621179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
541721179d81SJeff Layton 		status = nfserr_jukebox;
541821179d81SJeff Layton 		goto out;
541921179d81SJeff Layton 	}
542021179d81SJeff Layton 	locks_init_lock(file_lock);
54211da177e4SLinus Torvalds 	switch (lockt->lt_type) {
54221da177e4SLinus Torvalds 		case NFS4_READ_LT:
54231da177e4SLinus Torvalds 		case NFS4_READW_LT:
542421179d81SJeff Layton 			file_lock->fl_type = F_RDLCK;
54251da177e4SLinus Torvalds 		break;
54261da177e4SLinus Torvalds 		case NFS4_WRITE_LT:
54271da177e4SLinus Torvalds 		case NFS4_WRITEW_LT:
542821179d81SJeff Layton 			file_lock->fl_type = F_WRLCK;
54291da177e4SLinus Torvalds 		break;
54301da177e4SLinus Torvalds 		default:
54312fdada03SJ. Bruce Fields 			dprintk("NFSD: nfs4_lockt: bad lock type!\n");
54321da177e4SLinus Torvalds 			status = nfserr_inval;
54331da177e4SLinus Torvalds 		goto out;
54341da177e4SLinus Torvalds 	}
54351da177e4SLinus Torvalds 
5436d4f0489fSTrond Myklebust 	lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner,
5437d4f0489fSTrond Myklebust 				cstate->clp);
5438fe0750e5SJ. Bruce Fields 	if (lo)
543921179d81SJeff Layton 		file_lock->fl_owner = (fl_owner_t)lo;
544021179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
544121179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
54421da177e4SLinus Torvalds 
544321179d81SJeff Layton 	file_lock->fl_start = lockt->lt_offset;
544421179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
54451da177e4SLinus Torvalds 
544621179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
54471da177e4SLinus Torvalds 
544821179d81SJeff Layton 	status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
544904da6e9dSAl Viro 	if (status)
5450fd85b817SMarc Eshel 		goto out;
545104da6e9dSAl Viro 
545221179d81SJeff Layton 	if (file_lock->fl_type != F_UNLCK) {
54531da177e4SLinus Torvalds 		status = nfserr_denied;
545421179d81SJeff Layton 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
54551da177e4SLinus Torvalds 	}
54561da177e4SLinus Torvalds out:
54575db1c03fSJeff Layton 	if (lo)
54585db1c03fSJeff Layton 		nfs4_put_stateowner(&lo->lo_owner);
54591da177e4SLinus Torvalds 	nfs4_unlock_state();
546021179d81SJeff Layton 	if (file_lock)
546121179d81SJeff Layton 		locks_free_lock(file_lock);
54621da177e4SLinus Torvalds 	return status;
54631da177e4SLinus Torvalds }
54641da177e4SLinus Torvalds 
5465b37ad28bSAl Viro __be32
5466ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5467a4f1706aSJ.Bruce Fields 	    struct nfsd4_locku *locku)
54681da177e4SLinus Torvalds {
5469dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
54701da177e4SLinus Torvalds 	struct file *filp = NULL;
547121179d81SJeff Layton 	struct file_lock *file_lock = NULL;
5472b37ad28bSAl Viro 	__be32 status;
5473b8dd7b9aSAl Viro 	int err;
54743320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
54751da177e4SLinus Torvalds 
54761da177e4SLinus Torvalds 	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
54771da177e4SLinus Torvalds 		(long long) locku->lu_offset,
54781da177e4SLinus Torvalds 		(long long) locku->lu_length);
54791da177e4SLinus Torvalds 
54801da177e4SLinus Torvalds 	if (check_lock_length(locku->lu_offset, locku->lu_length))
54811da177e4SLinus Torvalds 		 return nfserr_inval;
54821da177e4SLinus Torvalds 
54831da177e4SLinus Torvalds 	nfs4_lock_state();
54841da177e4SLinus Torvalds 
54859072d5c6SJ. Bruce Fields 	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
54863320fef1SStanislav Kinsbursky 					&locku->lu_stateid, NFS4_LOCK_STID,
54873320fef1SStanislav Kinsbursky 					&stp, nn);
54889072d5c6SJ. Bruce Fields 	if (status)
54891da177e4SLinus Torvalds 		goto out;
549011b9164aSTrond Myklebust 	filp = find_any_file(stp->st_stid.sc_file);
5491f9d7562fSJ. Bruce Fields 	if (!filp) {
5492f9d7562fSJ. Bruce Fields 		status = nfserr_lock_range;
5493858cc573STrond Myklebust 		goto put_stateid;
5494f9d7562fSJ. Bruce Fields 	}
549521179d81SJeff Layton 	file_lock = locks_alloc_lock();
549621179d81SJeff Layton 	if (!file_lock) {
549721179d81SJeff Layton 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
549821179d81SJeff Layton 		status = nfserr_jukebox;
5499de18643dSTrond Myklebust 		goto fput;
550021179d81SJeff Layton 	}
550121179d81SJeff Layton 	locks_init_lock(file_lock);
550221179d81SJeff Layton 	file_lock->fl_type = F_UNLCK;
55030a262ffbSJ. Bruce Fields 	file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
550421179d81SJeff Layton 	file_lock->fl_pid = current->tgid;
550521179d81SJeff Layton 	file_lock->fl_file = filp;
550621179d81SJeff Layton 	file_lock->fl_flags = FL_POSIX;
550721179d81SJeff Layton 	file_lock->fl_lmops = &nfsd_posix_mng_ops;
550821179d81SJeff Layton 	file_lock->fl_start = locku->lu_offset;
55091da177e4SLinus Torvalds 
551021179d81SJeff Layton 	file_lock->fl_end = last_byte_offset(locku->lu_offset,
551121179d81SJeff Layton 						locku->lu_length);
551221179d81SJeff Layton 	nfs4_transform_lock_offset(file_lock);
55131da177e4SLinus Torvalds 
551421179d81SJeff Layton 	err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
5515b8dd7b9aSAl Viro 	if (err) {
5516fd85b817SMarc Eshel 		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
55171da177e4SLinus Torvalds 		goto out_nfserr;
55181da177e4SLinus Torvalds 	}
5519dcef0413SJ. Bruce Fields 	update_stateid(&stp->st_stid.sc_stateid);
5520dcef0413SJ. Bruce Fields 	memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
5521de18643dSTrond Myklebust fput:
5522de18643dSTrond Myklebust 	fput(filp);
5523858cc573STrond Myklebust put_stateid:
5524858cc573STrond Myklebust 	nfs4_put_stid(&stp->st_stid);
55251da177e4SLinus Torvalds out:
55269411b1d4SJ. Bruce Fields 	nfsd4_bump_seqid(cstate, status);
55271da177e4SLinus Torvalds 	nfs4_unlock_state();
552821179d81SJeff Layton 	if (file_lock)
552921179d81SJeff Layton 		locks_free_lock(file_lock);
55301da177e4SLinus Torvalds 	return status;
55311da177e4SLinus Torvalds 
55321da177e4SLinus Torvalds out_nfserr:
5533b8dd7b9aSAl Viro 	status = nfserrno(err);
5534de18643dSTrond Myklebust 	goto fput;
55351da177e4SLinus Torvalds }
55361da177e4SLinus Torvalds 
55371da177e4SLinus Torvalds /*
55381da177e4SLinus Torvalds  * returns
5539f9c00c3aSJeff Layton  * 	true:  locks held by lockowner
5540f9c00c3aSJeff Layton  * 	false: no locks held by lockowner
55411da177e4SLinus Torvalds  */
5542f9c00c3aSJeff Layton static bool
5543f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
55441da177e4SLinus Torvalds {
55451da177e4SLinus Torvalds 	struct file_lock **flpp;
5546f9c00c3aSJeff Layton 	int status = false;
5547f9c00c3aSJeff Layton 	struct file *filp = find_any_file(fp);
5548f9c00c3aSJeff Layton 	struct inode *inode;
5549f9c00c3aSJeff Layton 
5550f9c00c3aSJeff Layton 	if (!filp) {
5551f9c00c3aSJeff Layton 		/* Any valid lock stateid should have some sort of access */
5552f9c00c3aSJeff Layton 		WARN_ON_ONCE(1);
5553f9c00c3aSJeff Layton 		return status;
5554f9c00c3aSJeff Layton 	}
5555f9c00c3aSJeff Layton 
5556f9c00c3aSJeff Layton 	inode = file_inode(filp);
55571da177e4SLinus Torvalds 
55581c8c601aSJeff Layton 	spin_lock(&inode->i_lock);
55591da177e4SLinus Torvalds 	for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
5560796dadfdSJ. Bruce Fields 		if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
5561f9c00c3aSJeff Layton 			status = true;
5562f9c00c3aSJeff Layton 			break;
55631da177e4SLinus Torvalds 		}
5564796dadfdSJ. Bruce Fields 	}
55651c8c601aSJeff Layton 	spin_unlock(&inode->i_lock);
5566f9c00c3aSJeff Layton 	fput(filp);
55671da177e4SLinus Torvalds 	return status;
55681da177e4SLinus Torvalds }
55691da177e4SLinus Torvalds 
5570b37ad28bSAl Viro __be32
5571b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp,
5572b591480bSJ.Bruce Fields 			struct nfsd4_compound_state *cstate,
5573b591480bSJ.Bruce Fields 			struct nfsd4_release_lockowner *rlockowner)
55741da177e4SLinus Torvalds {
55751da177e4SLinus Torvalds 	clientid_t *clid = &rlockowner->rl_clientid;
5576882e9d25SJeff Layton 	struct nfs4_stateowner *sop;
5577882e9d25SJeff Layton 	struct nfs4_lockowner *lo = NULL;
5578dcef0413SJ. Bruce Fields 	struct nfs4_ol_stateid *stp;
55791da177e4SLinus Torvalds 	struct xdr_netobj *owner = &rlockowner->rl_owner;
5580d4f0489fSTrond Myklebust 	unsigned int hashval = ownerstr_hashval(owner);
5581b37ad28bSAl Viro 	__be32 status;
55827f2210faSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
5583c58c6610STrond Myklebust 	struct nfs4_client *clp;
55841da177e4SLinus Torvalds 
55851da177e4SLinus Torvalds 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
55861da177e4SLinus Torvalds 		clid->cl_boot, clid->cl_id);
55871da177e4SLinus Torvalds 
55881da177e4SLinus Torvalds 	nfs4_lock_state();
55891da177e4SLinus Torvalds 
55904b24ca7dSJeff Layton 	status = lookup_clientid(clid, cstate, nn);
55919b2ef62bSJ. Bruce Fields 	if (status)
55929b2ef62bSJ. Bruce Fields 		goto out;
55939b2ef62bSJ. Bruce Fields 
5594d4f0489fSTrond Myklebust 	clp = cstate->clp;
5595fd44907cSJeff Layton 	/* Find the matching lock stateowner */
5596d4f0489fSTrond Myklebust 	spin_lock(&clp->cl_lock);
5597882e9d25SJeff Layton 	list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval],
5598d4f0489fSTrond Myklebust 			    so_strhash) {
5599882e9d25SJeff Layton 
5600882e9d25SJeff Layton 		if (sop->so_is_open_owner || !same_owner_str(sop, owner))
560116bfdaafSJ. Bruce Fields 			continue;
5602882e9d25SJeff Layton 
5603882e9d25SJeff Layton 		/* see if there are still any locks associated with it */
5604882e9d25SJeff Layton 		lo = lockowner(sop);
5605882e9d25SJeff Layton 		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
5606882e9d25SJeff Layton 			if (check_for_locks(stp->st_stid.sc_file, lo)) {
5607882e9d25SJeff Layton 				status = nfserr_locks_held;
5608882e9d25SJeff Layton 				spin_unlock(&clp->cl_lock);
5609882e9d25SJeff Layton 				goto out;
5610882e9d25SJeff Layton 			}
5611882e9d25SJeff Layton 		}
5612882e9d25SJeff Layton 
56135adfd885SJeff Layton 		atomic_inc(&sop->so_count);
5614fd44907cSJeff Layton 		break;
5615fd44907cSJeff Layton 	}
5616d4f0489fSTrond Myklebust 	spin_unlock(&clp->cl_lock);
5617882e9d25SJeff Layton 	if (lo)
5618fe0750e5SJ. Bruce Fields 		release_lockowner(lo);
56191da177e4SLinus Torvalds out:
56201da177e4SLinus Torvalds 	nfs4_unlock_state();
56211da177e4SLinus Torvalds 	return status;
56221da177e4SLinus Torvalds }
56231da177e4SLinus Torvalds 
56241da177e4SLinus Torvalds static inline struct nfs4_client_reclaim *
5625a55370a3SNeilBrown alloc_reclaim(void)
56261da177e4SLinus Torvalds {
5627a55370a3SNeilBrown 	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
56281da177e4SLinus Torvalds }
56291da177e4SLinus Torvalds 
56300ce0c2b5SJeff Layton bool
563152e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
5632c7b9a459SNeilBrown {
56330ce0c2b5SJeff Layton 	struct nfs4_client_reclaim *crp;
5634c7b9a459SNeilBrown 
563552e19c09SStanislav Kinsbursky 	crp = nfsd4_find_reclaim_client(name, nn);
56360ce0c2b5SJeff Layton 	return (crp && crp->cr_clp);
5637c7b9a459SNeilBrown }
5638c7b9a459SNeilBrown 
56391da177e4SLinus Torvalds /*
56401da177e4SLinus Torvalds  * failure => all reset bets are off, nfserr_no_grace...
56411da177e4SLinus Torvalds  */
5642772a9bbbSJeff Layton struct nfs4_client_reclaim *
564352e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
56441da177e4SLinus Torvalds {
56451da177e4SLinus Torvalds 	unsigned int strhashval;
5646772a9bbbSJeff Layton 	struct nfs4_client_reclaim *crp;
56471da177e4SLinus Torvalds 
5648a55370a3SNeilBrown 	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
5649a55370a3SNeilBrown 	crp = alloc_reclaim();
5650772a9bbbSJeff Layton 	if (crp) {
5651a55370a3SNeilBrown 		strhashval = clientstr_hashval(name);
56521da177e4SLinus Torvalds 		INIT_LIST_HEAD(&crp->cr_strhash);
565352e19c09SStanislav Kinsbursky 		list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
5654a55370a3SNeilBrown 		memcpy(crp->cr_recdir, name, HEXDIR_LEN);
56550ce0c2b5SJeff Layton 		crp->cr_clp = NULL;
565652e19c09SStanislav Kinsbursky 		nn->reclaim_str_hashtbl_size++;
5657772a9bbbSJeff Layton 	}
5658772a9bbbSJeff Layton 	return crp;
56591da177e4SLinus Torvalds }
56601da177e4SLinus Torvalds 
56612a4317c5SJeff Layton void
566252e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
5663ce30e539SJeff Layton {
5664ce30e539SJeff Layton 	list_del(&crp->cr_strhash);
5665ce30e539SJeff Layton 	kfree(crp);
566652e19c09SStanislav Kinsbursky 	nn->reclaim_str_hashtbl_size--;
5667ce30e539SJeff Layton }
5668ce30e539SJeff Layton 
5669ce30e539SJeff Layton void
567052e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn)
56711da177e4SLinus Torvalds {
56721da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
56731da177e4SLinus Torvalds 	int i;
56741da177e4SLinus Torvalds 
56751da177e4SLinus Torvalds 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
567652e19c09SStanislav Kinsbursky 		while (!list_empty(&nn->reclaim_str_hashtbl[i])) {
567752e19c09SStanislav Kinsbursky 			crp = list_entry(nn->reclaim_str_hashtbl[i].next,
56781da177e4SLinus Torvalds 			                struct nfs4_client_reclaim, cr_strhash);
567952e19c09SStanislav Kinsbursky 			nfs4_remove_reclaim_record(crp, nn);
56801da177e4SLinus Torvalds 		}
56811da177e4SLinus Torvalds 	}
5682063b0fb9SJ. Bruce Fields 	WARN_ON_ONCE(nn->reclaim_str_hashtbl_size);
56831da177e4SLinus Torvalds }
56841da177e4SLinus Torvalds 
56851da177e4SLinus Torvalds /*
56861da177e4SLinus Torvalds  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
56872a4317c5SJeff Layton struct nfs4_client_reclaim *
568852e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
56891da177e4SLinus Torvalds {
56901da177e4SLinus Torvalds 	unsigned int strhashval;
56911da177e4SLinus Torvalds 	struct nfs4_client_reclaim *crp = NULL;
56921da177e4SLinus Torvalds 
5693278c931cSJeff Layton 	dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
56941da177e4SLinus Torvalds 
5695278c931cSJeff Layton 	strhashval = clientstr_hashval(recdir);
569652e19c09SStanislav Kinsbursky 	list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
5697278c931cSJeff Layton 		if (same_name(crp->cr_recdir, recdir)) {
56981da177e4SLinus Torvalds 			return crp;
56991da177e4SLinus Torvalds 		}
57001da177e4SLinus Torvalds 	}
57011da177e4SLinus Torvalds 	return NULL;
57021da177e4SLinus Torvalds }
57031da177e4SLinus Torvalds 
57041da177e4SLinus Torvalds /*
57051da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list.
57061da177e4SLinus Torvalds */
5707b37ad28bSAl Viro __be32
57080fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid,
57090fe492dbSTrond Myklebust 		struct nfsd4_compound_state *cstate,
57100fe492dbSTrond Myklebust 		struct nfsd_net *nn)
57111da177e4SLinus Torvalds {
57120fe492dbSTrond Myklebust 	__be32 status;
5713a52d726bSJeff Layton 
5714a52d726bSJeff Layton 	/* find clientid in conf_id_hashtbl */
57150fe492dbSTrond Myklebust 	status = lookup_clientid(clid, cstate, nn);
57160fe492dbSTrond Myklebust 	if (status)
5717a52d726bSJeff Layton 		return nfserr_reclaim_bad;
5718a52d726bSJeff Layton 
57190fe492dbSTrond Myklebust 	if (nfsd4_client_record_check(cstate->clp))
57200fe492dbSTrond Myklebust 		return nfserr_reclaim_bad;
57210fe492dbSTrond Myklebust 
57220fe492dbSTrond Myklebust 	return nfs_ok;
57231da177e4SLinus Torvalds }
57241da177e4SLinus Torvalds 
572565178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION
57267ec0e36fSJeff Layton u64
57277ec0e36fSJeff Layton nfsd_inject_print_clients(struct nfsd_fault_inject_op *op)
57287ec0e36fSJeff Layton {
57297ec0e36fSJeff Layton 	struct nfs4_client *clp;
57307ec0e36fSJeff Layton 	u64 count = 0;
57317ec0e36fSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
57327ec0e36fSJeff Layton 					  nfsd_net_id);
57337ec0e36fSJeff Layton 	char buf[INET6_ADDRSTRLEN];
57347ec0e36fSJeff Layton 
57357ec0e36fSJeff Layton 	if (!nfsd_netns_ready(nn))
57367ec0e36fSJeff Layton 		return 0;
57377ec0e36fSJeff Layton 
57387ec0e36fSJeff Layton 	spin_lock(&nn->client_lock);
57397ec0e36fSJeff Layton 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
57407ec0e36fSJeff Layton 		rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
57417ec0e36fSJeff Layton 		pr_info("NFS Client: %s\n", buf);
57427ec0e36fSJeff Layton 		++count;
57437ec0e36fSJeff Layton 	}
57447ec0e36fSJeff Layton 	spin_unlock(&nn->client_lock);
57457ec0e36fSJeff Layton 
57467ec0e36fSJeff Layton 	return count;
57477ec0e36fSJeff Layton }
574865178db4SBryan Schumaker 
5749a0926d15SJeff Layton u64
5750a0926d15SJeff Layton nfsd_inject_forget_client(struct nfsd_fault_inject_op *op,
5751a0926d15SJeff Layton 			  struct sockaddr_storage *addr, size_t addr_size)
5752a0926d15SJeff Layton {
5753a0926d15SJeff Layton 	u64 count = 0;
5754a0926d15SJeff Layton 	struct nfs4_client *clp;
5755a0926d15SJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5756a0926d15SJeff Layton 					  nfsd_net_id);
5757a0926d15SJeff Layton 
5758a0926d15SJeff Layton 	if (!nfsd_netns_ready(nn))
5759a0926d15SJeff Layton 		return count;
5760a0926d15SJeff Layton 
5761a0926d15SJeff Layton 	spin_lock(&nn->client_lock);
5762a0926d15SJeff Layton 	clp = nfsd_find_client(addr, addr_size);
5763a0926d15SJeff Layton 	if (clp) {
5764a0926d15SJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok)
5765a0926d15SJeff Layton 			++count;
5766a0926d15SJeff Layton 		else
5767a0926d15SJeff Layton 			clp = NULL;
5768a0926d15SJeff Layton 	}
5769a0926d15SJeff Layton 	spin_unlock(&nn->client_lock);
5770a0926d15SJeff Layton 
5771a0926d15SJeff Layton 	if (clp)
5772a0926d15SJeff Layton 		expire_client(clp);
5773a0926d15SJeff Layton 
5774a0926d15SJeff Layton 	return count;
5775a0926d15SJeff Layton }
5776a0926d15SJeff Layton 
577769fc9edfSJeff Layton u64
577869fc9edfSJeff Layton nfsd_inject_forget_clients(struct nfsd_fault_inject_op *op, u64 max)
577969fc9edfSJeff Layton {
578069fc9edfSJeff Layton 	u64 count = 0;
578169fc9edfSJeff Layton 	struct nfs4_client *clp, *next;
578269fc9edfSJeff Layton 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
578369fc9edfSJeff Layton 						nfsd_net_id);
578469fc9edfSJeff Layton 	LIST_HEAD(reaplist);
578569fc9edfSJeff Layton 
578669fc9edfSJeff Layton 	if (!nfsd_netns_ready(nn))
578769fc9edfSJeff Layton 		return count;
578869fc9edfSJeff Layton 
578969fc9edfSJeff Layton 	spin_lock(&nn->client_lock);
579069fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
579169fc9edfSJeff Layton 		if (mark_client_expired_locked(clp) == nfs_ok) {
579269fc9edfSJeff Layton 			list_add(&clp->cl_lru, &reaplist);
579369fc9edfSJeff Layton 			if (max != 0 && ++count >= max)
579469fc9edfSJeff Layton 				break;
579569fc9edfSJeff Layton 		}
579669fc9edfSJeff Layton 	}
579769fc9edfSJeff Layton 	spin_unlock(&nn->client_lock);
579869fc9edfSJeff Layton 
579969fc9edfSJeff Layton 	list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
580069fc9edfSJeff Layton 		expire_client(clp);
580169fc9edfSJeff Layton 
580269fc9edfSJeff Layton 	return count;
580369fc9edfSJeff Layton }
580469fc9edfSJeff Layton 
5805184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
5806184c1847SBryan Schumaker 			     const char *type)
5807184c1847SBryan Schumaker {
5808184c1847SBryan Schumaker 	char buf[INET6_ADDRSTRLEN];
58090a5c33e2SBryan Schumaker 	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
5810184c1847SBryan Schumaker 	printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
5811184c1847SBryan Schumaker }
5812184c1847SBryan Schumaker 
58133c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
58143738d50eSJeff Layton 				    struct list_head *collect,
58153c87b9b7STrond Myklebust 				    void (*func)(struct nfs4_ol_stateid *))
5816fc29171fSBryan Schumaker {
5817fc29171fSBryan Schumaker 	struct nfs4_openowner *oop;
5818fc29171fSBryan Schumaker 	struct nfs4_ol_stateid *stp, *st_next;
58193c87b9b7STrond Myklebust 	struct nfs4_ol_stateid *lst, *lst_next;
5820fc29171fSBryan Schumaker 	u64 count = 0;
5821fc29171fSBryan Schumaker 
5822fc29171fSBryan Schumaker 	list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
58233c87b9b7STrond Myklebust 		list_for_each_entry_safe(stp, st_next,
58243c87b9b7STrond Myklebust 				&oop->oo_owner.so_stateids, st_perstateowner) {
58253c87b9b7STrond Myklebust 			list_for_each_entry_safe(lst, lst_next,
58263c87b9b7STrond Myklebust 					&stp->st_locks, st_locks) {
58273738d50eSJeff Layton 				if (func) {
58283c87b9b7STrond Myklebust 					func(lst);
58293738d50eSJeff Layton 					if (collect)
58303738d50eSJeff Layton 						list_add(&lst->st_locks,
58313738d50eSJeff Layton 							 collect);
58323738d50eSJeff Layton 				}
5833fc29171fSBryan Schumaker 				if (++count == max)
5834fc29171fSBryan Schumaker 					return count;
5835fc29171fSBryan Schumaker 			}
5836fc29171fSBryan Schumaker 		}
5837fc29171fSBryan Schumaker 	}
5838fc29171fSBryan Schumaker 
5839fc29171fSBryan Schumaker 	return count;
5840fc29171fSBryan Schumaker }
5841fc29171fSBryan Schumaker 
5842fc29171fSBryan Schumaker u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max)
5843fc29171fSBryan Schumaker {
58443738d50eSJeff Layton 	return nfsd_foreach_client_lock(clp, max, NULL, release_lock_stateid);
5845fc29171fSBryan Schumaker }
5846fc29171fSBryan Schumaker 
5847184c1847SBryan Schumaker u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max)
5848184c1847SBryan Schumaker {
58493738d50eSJeff Layton 	u64 count = nfsd_foreach_client_lock(clp, max, NULL, NULL);
5850184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "locked files");
5851184c1847SBryan Schumaker 	return count;
5852184c1847SBryan Schumaker }
5853184c1847SBryan Schumaker 
58544dbdbda8SBryan Schumaker static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *))
58554dbdbda8SBryan Schumaker {
58564dbdbda8SBryan Schumaker 	struct nfs4_openowner *oop, *next;
58574dbdbda8SBryan Schumaker 	u64 count = 0;
58584dbdbda8SBryan Schumaker 
58594dbdbda8SBryan Schumaker 	list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
58604dbdbda8SBryan Schumaker 		if (func)
58614dbdbda8SBryan Schumaker 			func(oop);
58624dbdbda8SBryan Schumaker 		if (++count == max)
58634dbdbda8SBryan Schumaker 			break;
58644dbdbda8SBryan Schumaker 	}
58654dbdbda8SBryan Schumaker 
58664dbdbda8SBryan Schumaker 	return count;
58674dbdbda8SBryan Schumaker }
58684dbdbda8SBryan Schumaker 
58694dbdbda8SBryan Schumaker u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max)
58704dbdbda8SBryan Schumaker {
58714dbdbda8SBryan Schumaker 	return nfsd_foreach_client_open(clp, max, release_openowner);
58724dbdbda8SBryan Schumaker }
58734dbdbda8SBryan Schumaker 
5874184c1847SBryan Schumaker u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max)
5875184c1847SBryan Schumaker {
5876184c1847SBryan Schumaker 	u64 count = nfsd_foreach_client_open(clp, max, NULL);
5877184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "open files");
5878184c1847SBryan Schumaker 	return count;
5879184c1847SBryan Schumaker }
5880184c1847SBryan Schumaker 
5881269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
5882269de30fSBryan Schumaker 				     struct list_head *victims)
5883269de30fSBryan Schumaker {
5884269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
5885269de30fSBryan Schumaker 	u64 count = 0;
5886269de30fSBryan Schumaker 
5887cdc97505SBenny Halevy 	lockdep_assert_held(&state_lock);
5888269de30fSBryan Schumaker 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
5889dff1399fSJeff Layton 		if (victims) {
5890dff1399fSJeff Layton 			/*
5891dff1399fSJeff Layton 			 * It's not safe to mess with delegations that have a
5892dff1399fSJeff Layton 			 * non-zero dl_time. They might have already been broken
5893dff1399fSJeff Layton 			 * and could be processed by the laundromat outside of
5894dff1399fSJeff Layton 			 * the state_lock. Just leave them be.
5895dff1399fSJeff Layton 			 */
5896dff1399fSJeff Layton 			if (dp->dl_time != 0)
5897dff1399fSJeff Layton 				continue;
5898dff1399fSJeff Layton 
589942690676SJeff Layton 			unhash_delegation_locked(dp);
590042690676SJeff Layton 			list_add(&dp->dl_recall_lru, victims);
5901dff1399fSJeff Layton 		}
5902269de30fSBryan Schumaker 		if (++count == max)
5903269de30fSBryan Schumaker 			break;
5904269de30fSBryan Schumaker 	}
5905269de30fSBryan Schumaker 	return count;
5906269de30fSBryan Schumaker }
5907269de30fSBryan Schumaker 
5908269de30fSBryan Schumaker u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
5909269de30fSBryan Schumaker {
5910269de30fSBryan Schumaker 	struct nfs4_delegation *dp, *next;
5911269de30fSBryan Schumaker 	LIST_HEAD(victims);
5912269de30fSBryan Schumaker 	u64 count;
5913269de30fSBryan Schumaker 
5914cdc97505SBenny Halevy 	spin_lock(&state_lock);
5915269de30fSBryan Schumaker 	count = nfsd_find_all_delegations(clp, max, &victims);
5916cdc97505SBenny Halevy 	spin_unlock(&state_lock);
5917269de30fSBryan Schumaker 
59182d4a532dSJeff Layton 	list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) {
59192d4a532dSJeff Layton 		list_del_init(&dp->dl_recall_lru);
59203bd64a5bSJ. Bruce Fields 		revoke_delegation(dp);
59212d4a532dSJeff Layton 	}
5922269de30fSBryan Schumaker 
5923269de30fSBryan Schumaker 	return count;
5924269de30fSBryan Schumaker }
5925269de30fSBryan Schumaker 
5926269de30fSBryan Schumaker u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max)
5927269de30fSBryan Schumaker {
5928dff1399fSJeff Layton 	struct nfs4_delegation *dp;
5929269de30fSBryan Schumaker 	LIST_HEAD(victims);
5930269de30fSBryan Schumaker 	u64 count;
5931269de30fSBryan Schumaker 
5932cdc97505SBenny Halevy 	spin_lock(&state_lock);
5933269de30fSBryan Schumaker 	count = nfsd_find_all_delegations(clp, max, &victims);
5934dff1399fSJeff Layton 	while (!list_empty(&victims)) {
5935dff1399fSJeff Layton 		dp = list_first_entry(&victims, struct nfs4_delegation,
5936dff1399fSJeff Layton 					dl_recall_lru);
5937dff1399fSJeff Layton 		list_del_init(&dp->dl_recall_lru);
5938dff1399fSJeff Layton 		dp->dl_time = 0;
5939269de30fSBryan Schumaker 		nfsd_break_one_deleg(dp);
5940dff1399fSJeff Layton 	}
5941cdc97505SBenny Halevy 	spin_unlock(&state_lock);
5942269de30fSBryan Schumaker 
5943269de30fSBryan Schumaker 	return count;
5944269de30fSBryan Schumaker }
5945269de30fSBryan Schumaker 
5946184c1847SBryan Schumaker u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max)
5947184c1847SBryan Schumaker {
5948184c1847SBryan Schumaker 	u64 count = 0;
5949184c1847SBryan Schumaker 
5950cdc97505SBenny Halevy 	spin_lock(&state_lock);
5951184c1847SBryan Schumaker 	count = nfsd_find_all_delegations(clp, max, NULL);
5952cdc97505SBenny Halevy 	spin_unlock(&state_lock);
5953184c1847SBryan Schumaker 
5954184c1847SBryan Schumaker 	nfsd_print_count(clp, count, "delegations");
5955184c1847SBryan Schumaker 	return count;
5956184c1847SBryan Schumaker }
5957184c1847SBryan Schumaker 
595844e34da6SBryan Schumaker u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64))
595965178db4SBryan Schumaker {
596065178db4SBryan Schumaker 	struct nfs4_client *clp, *next;
596144e34da6SBryan Schumaker 	u64 count = 0;
59623320fef1SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
596365178db4SBryan Schumaker 
596444e34da6SBryan Schumaker 	if (!nfsd_netns_ready(nn))
596544e34da6SBryan Schumaker 		return 0;
596644e34da6SBryan Schumaker 
59675ed58bb2SStanislav Kinsbursky 	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
596844e34da6SBryan Schumaker 		count += func(clp, max - count);
596944e34da6SBryan Schumaker 		if ((max != 0) && (count >= max))
597065178db4SBryan Schumaker 			break;
597165178db4SBryan Schumaker 	}
597265178db4SBryan Schumaker 
597344e34da6SBryan Schumaker 	return count;
597444e34da6SBryan Schumaker }
597544e34da6SBryan Schumaker 
59766c1e82a4SBryan Schumaker struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
59776c1e82a4SBryan Schumaker {
59786c1e82a4SBryan Schumaker 	struct nfs4_client *clp;
59796c1e82a4SBryan Schumaker 	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
59806c1e82a4SBryan Schumaker 
59816c1e82a4SBryan Schumaker 	if (!nfsd_netns_ready(nn))
59826c1e82a4SBryan Schumaker 		return NULL;
59836c1e82a4SBryan Schumaker 
59846c1e82a4SBryan Schumaker 	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
59856c1e82a4SBryan Schumaker 		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
59866c1e82a4SBryan Schumaker 			return clp;
59876c1e82a4SBryan Schumaker 	}
59886c1e82a4SBryan Schumaker 	return NULL;
59896c1e82a4SBryan Schumaker }
59906c1e82a4SBryan Schumaker 
599165178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */
599265178db4SBryan Schumaker 
5993c2f1a551SMeelap Shah /*
5994c2f1a551SMeelap Shah  * Since the lifetime of a delegation isn't limited to that of an open, a
5995c2f1a551SMeelap Shah  * client may quite reasonably hang on to a delegation as long as it has
5996c2f1a551SMeelap Shah  * the inode cached.  This becomes an obvious problem the first time a
5997c2f1a551SMeelap Shah  * client's inode cache approaches the size of the server's total memory.
5998c2f1a551SMeelap Shah  *
5999c2f1a551SMeelap Shah  * For now we avoid this problem by imposing a hard limit on the number
6000c2f1a551SMeelap Shah  * of delegations, which varies according to the server's memory size.
6001c2f1a551SMeelap Shah  */
6002c2f1a551SMeelap Shah static void
6003c2f1a551SMeelap Shah set_max_delegations(void)
6004c2f1a551SMeelap Shah {
6005c2f1a551SMeelap Shah 	/*
6006c2f1a551SMeelap Shah 	 * Allow at most 4 delegations per megabyte of RAM.  Quick
6007c2f1a551SMeelap Shah 	 * estimates suggest that in the worst case (where every delegation
6008c2f1a551SMeelap Shah 	 * is for a different inode), a delegation could take about 1.5K,
6009c2f1a551SMeelap Shah 	 * giving a worst case usage of about 6% of memory.
6010c2f1a551SMeelap Shah 	 */
6011c2f1a551SMeelap Shah 	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
6012c2f1a551SMeelap Shah }
6013c2f1a551SMeelap Shah 
6014d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net)
60158daae4dcSStanislav Kinsbursky {
60168daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
60178daae4dcSStanislav Kinsbursky 	int i;
60188daae4dcSStanislav Kinsbursky 
60198daae4dcSStanislav Kinsbursky 	nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
60208daae4dcSStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
60218daae4dcSStanislav Kinsbursky 	if (!nn->conf_id_hashtbl)
6022382a62e7SStanislav Kinsbursky 		goto err;
60230a7ec377SStanislav Kinsbursky 	nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) *
60240a7ec377SStanislav Kinsbursky 			CLIENT_HASH_SIZE, GFP_KERNEL);
60250a7ec377SStanislav Kinsbursky 	if (!nn->unconf_id_hashtbl)
60260a7ec377SStanislav Kinsbursky 		goto err_unconf_id;
60271872de0eSStanislav Kinsbursky 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
60281872de0eSStanislav Kinsbursky 			SESSION_HASH_SIZE, GFP_KERNEL);
60291872de0eSStanislav Kinsbursky 	if (!nn->sessionid_hashtbl)
60301872de0eSStanislav Kinsbursky 		goto err_sessionid;
60318daae4dcSStanislav Kinsbursky 
6032382a62e7SStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
60338daae4dcSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
60340a7ec377SStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
6035382a62e7SStanislav Kinsbursky 	}
60361872de0eSStanislav Kinsbursky 	for (i = 0; i < SESSION_HASH_SIZE; i++)
60371872de0eSStanislav Kinsbursky 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
6038382a62e7SStanislav Kinsbursky 	nn->conf_name_tree = RB_ROOT;
6039a99454aaSStanislav Kinsbursky 	nn->unconf_name_tree = RB_ROOT;
60405ed58bb2SStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->client_lru);
604173758fedSStanislav Kinsbursky 	INIT_LIST_HEAD(&nn->close_lru);
6042e8c69d17SJ. Bruce Fields 	INIT_LIST_HEAD(&nn->del_recall_lru);
6043c9a49628SStanislav Kinsbursky 	spin_lock_init(&nn->client_lock);
60448daae4dcSStanislav Kinsbursky 
604509121281SStanislav Kinsbursky 	INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
6046d85ed443SStanislav Kinsbursky 	get_net(net);
604709121281SStanislav Kinsbursky 
60488daae4dcSStanislav Kinsbursky 	return 0;
6049382a62e7SStanislav Kinsbursky 
60501872de0eSStanislav Kinsbursky err_sessionid:
60519b531137SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
60520a7ec377SStanislav Kinsbursky err_unconf_id:
60530a7ec377SStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
6054382a62e7SStanislav Kinsbursky err:
6055382a62e7SStanislav Kinsbursky 	return -ENOMEM;
60568daae4dcSStanislav Kinsbursky }
60578daae4dcSStanislav Kinsbursky 
60588daae4dcSStanislav Kinsbursky static void
60594dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net)
60608daae4dcSStanislav Kinsbursky {
60618daae4dcSStanislav Kinsbursky 	int i;
60628daae4dcSStanislav Kinsbursky 	struct nfs4_client *clp = NULL;
60638daae4dcSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
60648daae4dcSStanislav Kinsbursky 
60658daae4dcSStanislav Kinsbursky 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
60668daae4dcSStanislav Kinsbursky 		while (!list_empty(&nn->conf_id_hashtbl[i])) {
60678daae4dcSStanislav Kinsbursky 			clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
60688daae4dcSStanislav Kinsbursky 			destroy_client(clp);
60698daae4dcSStanislav Kinsbursky 		}
60708daae4dcSStanislav Kinsbursky 	}
6071a99454aaSStanislav Kinsbursky 
60722b905635SKinglong Mee 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
60732b905635SKinglong Mee 		while (!list_empty(&nn->unconf_id_hashtbl[i])) {
60742b905635SKinglong Mee 			clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
6075a99454aaSStanislav Kinsbursky 			destroy_client(clp);
6076a99454aaSStanislav Kinsbursky 		}
60772b905635SKinglong Mee 	}
6078a99454aaSStanislav Kinsbursky 
60791872de0eSStanislav Kinsbursky 	kfree(nn->sessionid_hashtbl);
60800a7ec377SStanislav Kinsbursky 	kfree(nn->unconf_id_hashtbl);
60818daae4dcSStanislav Kinsbursky 	kfree(nn->conf_id_hashtbl);
60824dce0ac9SStanislav Kinsbursky 	put_net(net);
60838daae4dcSStanislav Kinsbursky }
60848daae4dcSStanislav Kinsbursky 
6085f252bc68SStanislav Kinsbursky int
6086d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net)
6087ac4d8ff2SNeilBrown {
60885e1533c7SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
6089b5a1a81eSJ. Bruce Fields 	int ret;
6090b5a1a81eSJ. Bruce Fields 
6091d85ed443SStanislav Kinsbursky 	ret = nfs4_state_create_net(net);
60928daae4dcSStanislav Kinsbursky 	if (ret)
60938daae4dcSStanislav Kinsbursky 		return ret;
60945e1533c7SStanislav Kinsbursky 	nfsd4_client_tracking_init(net);
60952c142baaSStanislav Kinsbursky 	nn->boot_time = get_seconds();
60965ccb0066SStanislav Kinsbursky 	locks_start_grace(net, &nn->nfsd4_manager);
6097a51c84edSStanislav Kinsbursky 	nn->grace_ended = false;
6098d85ed443SStanislav Kinsbursky 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
60995284b44eSStanislav Kinsbursky 	       nn->nfsd4_grace, net);
61005284b44eSStanislav Kinsbursky 	queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
6101d85ed443SStanislav Kinsbursky 	return 0;
6102a6d6b781SJeff Layton }
6103d85ed443SStanislav Kinsbursky 
6104d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */
6105d85ed443SStanislav Kinsbursky 
6106d85ed443SStanislav Kinsbursky int
6107d85ed443SStanislav Kinsbursky nfs4_state_start(void)
6108d85ed443SStanislav Kinsbursky {
6109d85ed443SStanislav Kinsbursky 	int ret;
6110d85ed443SStanislav Kinsbursky 
6111d85ed443SStanislav Kinsbursky 	ret = set_callback_cred();
6112d85ed443SStanislav Kinsbursky 	if (ret)
6113d85ed443SStanislav Kinsbursky 		return -ENOMEM;
611458da282bSNeilBrown 	laundry_wq = create_singlethread_workqueue("nfsd4");
6115a6d6b781SJeff Layton 	if (laundry_wq == NULL) {
6116a6d6b781SJeff Layton 		ret = -ENOMEM;
6117a6d6b781SJeff Layton 		goto out_recovery;
6118a6d6b781SJeff Layton 	}
6119b5a1a81eSJ. Bruce Fields 	ret = nfsd4_create_callback_queue();
6120b5a1a81eSJ. Bruce Fields 	if (ret)
6121b5a1a81eSJ. Bruce Fields 		goto out_free_laundry;
612209121281SStanislav Kinsbursky 
6123c2f1a551SMeelap Shah 	set_max_delegations();
6124d85ed443SStanislav Kinsbursky 
6125b5a1a81eSJ. Bruce Fields 	return 0;
6126d85ed443SStanislav Kinsbursky 
6127b5a1a81eSJ. Bruce Fields out_free_laundry:
6128b5a1a81eSJ. Bruce Fields 	destroy_workqueue(laundry_wq);
6129a6d6b781SJeff Layton out_recovery:
6130b5a1a81eSJ. Bruce Fields 	return ret;
61311da177e4SLinus Torvalds }
61321da177e4SLinus Torvalds 
6133f252bc68SStanislav Kinsbursky void
61344dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net)
61351da177e4SLinus Torvalds {
61361da177e4SLinus Torvalds 	struct nfs4_delegation *dp = NULL;
61371da177e4SLinus Torvalds 	struct list_head *pos, *next, reaplist;
61384dce0ac9SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
61391da177e4SLinus Torvalds 
61404dce0ac9SStanislav Kinsbursky 	cancel_delayed_work_sync(&nn->laundromat_work);
61414dce0ac9SStanislav Kinsbursky 	locks_end_grace(&nn->nfsd4_manager);
6142ac55fdc4SJeff Layton 
6143e50a26dcSJ. Bruce Fields 	nfs4_lock_state();
61441da177e4SLinus Torvalds 	INIT_LIST_HEAD(&reaplist);
6145cdc97505SBenny Halevy 	spin_lock(&state_lock);
6146e8c69d17SJ. Bruce Fields 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
61471da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
614842690676SJeff Layton 		unhash_delegation_locked(dp);
614942690676SJeff Layton 		list_add(&dp->dl_recall_lru, &reaplist);
61501da177e4SLinus Torvalds 	}
6151cdc97505SBenny Halevy 	spin_unlock(&state_lock);
61521da177e4SLinus Torvalds 	list_for_each_safe(pos, next, &reaplist) {
61531da177e4SLinus Torvalds 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
615442690676SJeff Layton 		list_del_init(&dp->dl_recall_lru);
61556011695dSTrond Myklebust 		nfs4_put_stid(&dp->dl_stid);
61561da177e4SLinus Torvalds 	}
61571da177e4SLinus Torvalds 
61583320fef1SStanislav Kinsbursky 	nfsd4_client_tracking_exit(net);
61594dce0ac9SStanislav Kinsbursky 	nfs4_state_destroy_net(net);
6160e50a26dcSJ. Bruce Fields 	nfs4_unlock_state();
61611da177e4SLinus Torvalds }
61621da177e4SLinus Torvalds 
61631da177e4SLinus Torvalds void
61641da177e4SLinus Torvalds nfs4_state_shutdown(void)
61651da177e4SLinus Torvalds {
61665e8d5c29SNeilBrown 	destroy_workqueue(laundry_wq);
6167c3935e30SJ. Bruce Fields 	nfsd4_destroy_callback_queue();
61681da177e4SLinus Torvalds }
61698b70484cSTigran Mkrtchyan 
61708b70484cSTigran Mkrtchyan static void
61718b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
61728b70484cSTigran Mkrtchyan {
617337c593c5STigran Mkrtchyan 	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
617437c593c5STigran Mkrtchyan 		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
61758b70484cSTigran Mkrtchyan }
61768b70484cSTigran Mkrtchyan 
61778b70484cSTigran Mkrtchyan static void
61788b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
61798b70484cSTigran Mkrtchyan {
618037c593c5STigran Mkrtchyan 	if (cstate->minorversion) {
618137c593c5STigran Mkrtchyan 		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
618237c593c5STigran Mkrtchyan 		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
618337c593c5STigran Mkrtchyan 	}
618437c593c5STigran Mkrtchyan }
618537c593c5STigran Mkrtchyan 
618637c593c5STigran Mkrtchyan void
618737c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate)
618837c593c5STigran Mkrtchyan {
618937c593c5STigran Mkrtchyan 	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
61908b70484cSTigran Mkrtchyan }
61918b70484cSTigran Mkrtchyan 
619262cd4a59STigran Mkrtchyan /*
619362cd4a59STigran Mkrtchyan  * functions to set current state id
619462cd4a59STigran Mkrtchyan  */
61958b70484cSTigran Mkrtchyan void
61969428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
61979428fe1aSTigran Mkrtchyan {
61989428fe1aSTigran Mkrtchyan 	put_stateid(cstate, &odp->od_stateid);
61999428fe1aSTigran Mkrtchyan }
62009428fe1aSTigran Mkrtchyan 
62019428fe1aSTigran Mkrtchyan void
62028b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
62038b70484cSTigran Mkrtchyan {
62048b70484cSTigran Mkrtchyan 	put_stateid(cstate, &open->op_stateid);
62058b70484cSTigran Mkrtchyan }
62068b70484cSTigran Mkrtchyan 
62078b70484cSTigran Mkrtchyan void
620862cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
620962cd4a59STigran Mkrtchyan {
621062cd4a59STigran Mkrtchyan 	put_stateid(cstate, &close->cl_stateid);
621162cd4a59STigran Mkrtchyan }
621262cd4a59STigran Mkrtchyan 
621362cd4a59STigran Mkrtchyan void
621462cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
621562cd4a59STigran Mkrtchyan {
621662cd4a59STigran Mkrtchyan 	put_stateid(cstate, &lock->lk_resp_stateid);
621762cd4a59STigran Mkrtchyan }
621862cd4a59STigran Mkrtchyan 
621962cd4a59STigran Mkrtchyan /*
622062cd4a59STigran Mkrtchyan  * functions to consume current state id
622162cd4a59STigran Mkrtchyan  */
62221e97b519STigran Mkrtchyan 
62231e97b519STigran Mkrtchyan void
62249428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
62259428fe1aSTigran Mkrtchyan {
62269428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &odp->od_stateid);
62279428fe1aSTigran Mkrtchyan }
62289428fe1aSTigran Mkrtchyan 
62299428fe1aSTigran Mkrtchyan void
62309428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
62319428fe1aSTigran Mkrtchyan {
62329428fe1aSTigran Mkrtchyan 	get_stateid(cstate, &drp->dr_stateid);
62339428fe1aSTigran Mkrtchyan }
62349428fe1aSTigran Mkrtchyan 
62359428fe1aSTigran Mkrtchyan void
62361e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
62371e97b519STigran Mkrtchyan {
62381e97b519STigran Mkrtchyan 	get_stateid(cstate, &fsp->fr_stateid);
62391e97b519STigran Mkrtchyan }
62401e97b519STigran Mkrtchyan 
62411e97b519STigran Mkrtchyan void
62421e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
62431e97b519STigran Mkrtchyan {
62441e97b519STigran Mkrtchyan 	get_stateid(cstate, &setattr->sa_stateid);
62451e97b519STigran Mkrtchyan }
62461e97b519STigran Mkrtchyan 
624762cd4a59STigran Mkrtchyan void
62488b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
62498b70484cSTigran Mkrtchyan {
62508b70484cSTigran Mkrtchyan 	get_stateid(cstate, &close->cl_stateid);
62518b70484cSTigran Mkrtchyan }
62528b70484cSTigran Mkrtchyan 
62538b70484cSTigran Mkrtchyan void
625462cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
62558b70484cSTigran Mkrtchyan {
625662cd4a59STigran Mkrtchyan 	get_stateid(cstate, &locku->lu_stateid);
62578b70484cSTigran Mkrtchyan }
625830813e27STigran Mkrtchyan 
625930813e27STigran Mkrtchyan void
626030813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
626130813e27STigran Mkrtchyan {
626230813e27STigran Mkrtchyan 	get_stateid(cstate, &read->rd_stateid);
626330813e27STigran Mkrtchyan }
626430813e27STigran Mkrtchyan 
626530813e27STigran Mkrtchyan void
626630813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
626730813e27STigran Mkrtchyan {
626830813e27STigran Mkrtchyan 	get_stateid(cstate, &write->wr_stateid);
626930813e27STigran Mkrtchyan }
6270