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