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