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