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 /* 798b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 808b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 818b671b80SJ. Bruce Fields * eventually cover more: 828b671b80SJ. Bruce Fields */ 83cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 848b671b80SJ. Bruce Fields 85b401be22SJeff Layton /* 86b401be22SJeff Layton * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for 87b401be22SJeff Layton * the refcount on the open stateid to drop. 88b401be22SJeff Layton */ 89b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq); 90b401be22SJeff Layton 91abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 92abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 93abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 94abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 95abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 96e60d4398SNeilBrown 9766b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 98508dc6e1SBenny Halevy 9966b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 100508dc6e1SBenny Halevy { 10166b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 10266b2b9b2SJ. Bruce Fields } 10366b2b9b2SJ. Bruce Fields 104f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 105f0f51f5cSJ. Bruce Fields { 106f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 10766b2b9b2SJ. Bruce Fields return nfserr_jukebox; 10866b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 10966b2b9b2SJ. Bruce Fields return nfs_ok; 11066b2b9b2SJ. Bruce Fields } 11166b2b9b2SJ. Bruce Fields 112221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 113221a6876SJ. Bruce Fields { 114221a6876SJ. Bruce Fields return clp->cl_time == 0; 115221a6876SJ. Bruce Fields } 116221a6876SJ. Bruce Fields 117221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 118221a6876SJ. Bruce Fields { 1190a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1200a880a28STrond Myklebust 1210a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1220a880a28STrond Myklebust 123221a6876SJ. Bruce Fields if (is_client_expired(clp)) 124221a6876SJ. Bruce Fields return nfserr_expired; 125221a6876SJ. Bruce Fields atomic_inc(&clp->cl_refcount); 126221a6876SJ. Bruce Fields return nfs_ok; 127221a6876SJ. Bruce Fields } 128221a6876SJ. Bruce Fields 129221a6876SJ. Bruce Fields /* must be called under the client_lock */ 130221a6876SJ. Bruce Fields static inline void 131221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 132221a6876SJ. Bruce Fields { 133221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 134221a6876SJ. Bruce Fields 135221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 136221a6876SJ. Bruce Fields WARN_ON(1); 137221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 138221a6876SJ. Bruce Fields __func__, 139221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 140221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 141221a6876SJ. Bruce Fields return; 142221a6876SJ. Bruce Fields } 143221a6876SJ. Bruce Fields 144221a6876SJ. Bruce Fields dprintk("renewing client (clientid %08x/%08x)\n", 145221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 146221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 147221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 148221a6876SJ. Bruce Fields clp->cl_time = get_seconds(); 149221a6876SJ. Bruce Fields } 150221a6876SJ. Bruce Fields 151221a6876SJ. Bruce Fields static inline void 152221a6876SJ. Bruce Fields renew_client(struct nfs4_client *clp) 153221a6876SJ. Bruce Fields { 154221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 155221a6876SJ. Bruce Fields 156221a6876SJ. Bruce Fields spin_lock(&nn->client_lock); 157221a6876SJ. Bruce Fields renew_client_locked(clp); 158221a6876SJ. Bruce Fields spin_unlock(&nn->client_lock); 159221a6876SJ. Bruce Fields } 160221a6876SJ. Bruce Fields 161ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 162221a6876SJ. Bruce Fields { 1630a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1640a880a28STrond Myklebust 1650a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1660a880a28STrond Myklebust 167221a6876SJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_refcount)) 168221a6876SJ. Bruce Fields return; 169221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 170221a6876SJ. Bruce Fields renew_client_locked(clp); 171221a6876SJ. Bruce Fields } 172221a6876SJ. Bruce Fields 1734b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 1744b24ca7dSJeff Layton { 1754b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1764b24ca7dSJeff Layton 177d6c249b4SJeff Layton if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) 178d6c249b4SJeff Layton return; 179d6c249b4SJeff Layton if (!is_client_expired(clp)) 180d6c249b4SJeff Layton renew_client_locked(clp); 1814b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 1824b24ca7dSJeff Layton } 1834b24ca7dSJeff Layton 184d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 185d4e19e70STrond Myklebust { 186d4e19e70STrond Myklebust __be32 status; 187d4e19e70STrond Myklebust 188d4e19e70STrond Myklebust if (is_session_dead(ses)) 189d4e19e70STrond Myklebust return nfserr_badsession; 190d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 191d4e19e70STrond Myklebust if (status) 192d4e19e70STrond Myklebust return status; 193d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 194d4e19e70STrond Myklebust return nfs_ok; 195d4e19e70STrond Myklebust } 196d4e19e70STrond Myklebust 197d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 198d4e19e70STrond Myklebust { 199d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 2000a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2010a880a28STrond Myklebust 2020a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 203d4e19e70STrond Myklebust 204d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 205d4e19e70STrond Myklebust free_session(ses); 206d4e19e70STrond Myklebust put_client_renew_locked(clp); 207d4e19e70STrond Myklebust } 208d4e19e70STrond Myklebust 209d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 210d4e19e70STrond Myklebust { 211d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 212d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 213d4e19e70STrond Myklebust 214d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 215d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 216d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 217d4e19e70STrond Myklebust } 218d4e19e70STrond Myklebust 219b5971afaSKinglong Mee static inline struct nfs4_stateowner * 220b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop) 221b5971afaSKinglong Mee { 222b5971afaSKinglong Mee atomic_inc(&sop->so_count); 223b5971afaSKinglong Mee return sop; 224b5971afaSKinglong Mee } 225b5971afaSKinglong Mee 2267ffb5880STrond Myklebust static int 227d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) 2287ffb5880STrond Myklebust { 2297ffb5880STrond Myklebust return (sop->so_owner.len == owner->len) && 230d4f0489fSTrond Myklebust 0 == memcmp(sop->so_owner.data, owner->data, owner->len); 2317ffb5880STrond Myklebust } 2327ffb5880STrond Myklebust 2337ffb5880STrond Myklebust static struct nfs4_openowner * 2347ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, 235d4f0489fSTrond Myklebust struct nfs4_client *clp) 2367ffb5880STrond Myklebust { 2377ffb5880STrond Myklebust struct nfs4_stateowner *so; 2387ffb5880STrond Myklebust 239d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 2407ffb5880STrond Myklebust 241d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval], 242d4f0489fSTrond Myklebust so_strhash) { 2437ffb5880STrond Myklebust if (!so->so_is_open_owner) 2447ffb5880STrond Myklebust continue; 245b5971afaSKinglong Mee if (same_owner_str(so, &open->op_owner)) 246b5971afaSKinglong Mee return openowner(nfs4_get_stateowner(so)); 2477ffb5880STrond Myklebust } 2487ffb5880STrond Myklebust return NULL; 2497ffb5880STrond Myklebust } 2507ffb5880STrond Myklebust 2517ffb5880STrond Myklebust static struct nfs4_openowner * 2527ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 253d4f0489fSTrond Myklebust struct nfs4_client *clp) 2547ffb5880STrond Myklebust { 2557ffb5880STrond Myklebust struct nfs4_openowner *oo; 2567ffb5880STrond Myklebust 257d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 258d4f0489fSTrond Myklebust oo = find_openstateowner_str_locked(hashval, open, clp); 259d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 2607ffb5880STrond Myklebust return oo; 2617ffb5880STrond Myklebust } 2627ffb5880STrond Myklebust 2631da177e4SLinus Torvalds static inline u32 2641da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 2651da177e4SLinus Torvalds { 2661da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds u32 x = 0; 2691da177e4SLinus Torvalds while (nbytes--) { 2701da177e4SLinus Torvalds x *= 37; 2711da177e4SLinus Torvalds x += *cptr++; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds return x; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 27632513b40SJ. Bruce Fields static void nfsd4_free_file(struct nfs4_file *f) 27732513b40SJ. Bruce Fields { 27832513b40SJ. Bruce Fields kmem_cache_free(file_slab, f); 27932513b40SJ. Bruce Fields } 28032513b40SJ. Bruce Fields 28113cd2184SNeilBrown static inline void 28213cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 28313cd2184SNeilBrown { 28402e1215fSJeff Layton might_lock(&state_lock); 28502e1215fSJeff Layton 286cdc97505SBenny Halevy if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { 28789876f8cSJeff Layton hlist_del(&fi->fi_hash); 288cdc97505SBenny Halevy spin_unlock(&state_lock); 28932513b40SJ. Bruce Fields nfsd4_free_file(fi); 2908b671b80SJ. Bruce Fields } 29113cd2184SNeilBrown } 29213cd2184SNeilBrown 29313cd2184SNeilBrown static inline void 29413cd2184SNeilBrown get_nfs4_file(struct nfs4_file *fi) 29513cd2184SNeilBrown { 2968b671b80SJ. Bruce Fields atomic_inc(&fi->fi_ref); 29713cd2184SNeilBrown } 29813cd2184SNeilBrown 299de18643dSTrond Myklebust static struct file * 300de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag) 301de18643dSTrond Myklebust { 302de18643dSTrond Myklebust if (f->fi_fds[oflag]) 303de18643dSTrond Myklebust return get_file(f->fi_fds[oflag]); 304de18643dSTrond Myklebust return NULL; 305de18643dSTrond Myklebust } 306de18643dSTrond Myklebust 307de18643dSTrond Myklebust static struct file * 308de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f) 309de18643dSTrond Myklebust { 310de18643dSTrond Myklebust struct file *ret; 311de18643dSTrond Myklebust 312de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 313de18643dSTrond Myklebust 314de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 315de18643dSTrond Myklebust if (!ret) 316de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 317de18643dSTrond Myklebust return ret; 318de18643dSTrond Myklebust } 319de18643dSTrond Myklebust 320de18643dSTrond Myklebust static struct file * 321de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 322de18643dSTrond Myklebust { 323de18643dSTrond Myklebust struct file *ret; 324de18643dSTrond Myklebust 325de18643dSTrond Myklebust spin_lock(&f->fi_lock); 326de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 327de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 328de18643dSTrond Myklebust 329de18643dSTrond Myklebust return ret; 330de18643dSTrond Myklebust } 331de18643dSTrond Myklebust 332de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f) 333de18643dSTrond Myklebust { 334de18643dSTrond Myklebust struct file *ret; 335de18643dSTrond Myklebust 336de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 337de18643dSTrond Myklebust 338de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 339de18643dSTrond Myklebust if (!ret) 340de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 341de18643dSTrond Myklebust return ret; 342de18643dSTrond Myklebust } 343de18643dSTrond Myklebust 344de18643dSTrond Myklebust static struct file * 345de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 346de18643dSTrond Myklebust { 347de18643dSTrond Myklebust struct file *ret; 348de18643dSTrond Myklebust 349de18643dSTrond Myklebust spin_lock(&f->fi_lock); 350de18643dSTrond Myklebust ret = find_readable_file_locked(f); 351de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 352de18643dSTrond Myklebust 353de18643dSTrond Myklebust return ret; 354de18643dSTrond Myklebust } 355de18643dSTrond Myklebust 356de18643dSTrond Myklebust static struct file * 357de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 358de18643dSTrond Myklebust { 359de18643dSTrond Myklebust struct file *ret; 360de18643dSTrond Myklebust 361de18643dSTrond Myklebust spin_lock(&f->fi_lock); 362de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 363de18643dSTrond Myklebust if (!ret) { 364de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 365de18643dSTrond Myklebust if (!ret) 366de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 367de18643dSTrond Myklebust } 368de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 369de18643dSTrond Myklebust return ret; 370de18643dSTrond Myklebust } 371de18643dSTrond Myklebust 37202a3508dSTrond Myklebust static atomic_long_t num_delegations; 373697ce9beSZhang Yanfei unsigned long max_delegations; 374ef0f3390SNeilBrown 375ef0f3390SNeilBrown /* 376ef0f3390SNeilBrown * Open owner state (share locks) 377ef0f3390SNeilBrown */ 378ef0f3390SNeilBrown 37916bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 38016bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 38116bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 38216bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 383ef0f3390SNeilBrown 384d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 385ddc04c41SJ. Bruce Fields { 386ddc04c41SJ. Bruce Fields unsigned int ret; 387ddc04c41SJ. Bruce Fields 388ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 38916bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 390ddc04c41SJ. Bruce Fields } 391ef0f3390SNeilBrown 392ef0f3390SNeilBrown /* hash table for nfs4_file */ 393ef0f3390SNeilBrown #define FILE_HASH_BITS 8 394ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 39535079582SShan Wei 396ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) 397ddc04c41SJ. Bruce Fields { 398ca943217STrond Myklebust return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); 399ca943217STrond Myklebust } 400ca943217STrond Myklebust 401ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh) 402ca943217STrond Myklebust { 403ca943217STrond Myklebust return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); 404ca943217STrond Myklebust } 405ca943217STrond Myklebust 406ca943217STrond Myklebust static bool nfsd_fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) 407ca943217STrond Myklebust { 408ca943217STrond Myklebust return fh1->fh_size == fh2->fh_size && 409ca943217STrond Myklebust !memcmp(fh1->fh_base.fh_pad, 410ca943217STrond Myklebust fh2->fh_base.fh_pad, 411ca943217STrond Myklebust fh1->fh_size); 412ddc04c41SJ. Bruce Fields } 413ddc04c41SJ. Bruce Fields 41489876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 415ef0f3390SNeilBrown 41612659651SJeff Layton static void 41712659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 4183477565eSJ. Bruce Fields { 4197214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 4207214e860SJeff Layton 42112659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 42212659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 42312659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 42412659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 4253477565eSJ. Bruce Fields } 4263477565eSJ. Bruce Fields 42712659651SJeff Layton static __be32 42812659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 429998db52cSJ. Bruce Fields { 4307214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 4317214e860SJeff Layton 43212659651SJeff Layton /* Does this access mode make sense? */ 43312659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 43412659651SJeff Layton return nfserr_inval; 43512659651SJeff Layton 436baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 437baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 438baeb4ff0SJeff Layton return nfserr_share_denied; 439baeb4ff0SJeff Layton 44012659651SJeff Layton __nfs4_file_get_access(fp, access); 44112659651SJeff Layton return nfs_ok; 442998db52cSJ. Bruce Fields } 443998db52cSJ. Bruce Fields 444baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 445baeb4ff0SJeff Layton { 446baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 447baeb4ff0SJeff Layton if (deny) { 448baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 449baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 450baeb4ff0SJeff Layton return nfserr_inval; 451baeb4ff0SJeff Layton 452baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 453baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 454baeb4ff0SJeff Layton return nfserr_share_denied; 455baeb4ff0SJeff Layton 456baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 457baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 458baeb4ff0SJeff Layton return nfserr_share_denied; 459baeb4ff0SJeff Layton } 460baeb4ff0SJeff Layton return nfs_ok; 461baeb4ff0SJeff Layton } 462baeb4ff0SJeff Layton 463998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 464f9d7562fSJ. Bruce Fields { 465de18643dSTrond Myklebust might_lock(&fp->fi_lock); 466de18643dSTrond Myklebust 467de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 468de18643dSTrond Myklebust struct file *f1 = NULL; 469de18643dSTrond Myklebust struct file *f2 = NULL; 470de18643dSTrond Myklebust 4716d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 4720c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 4736d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 474de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 475de18643dSTrond Myklebust if (f1) 476de18643dSTrond Myklebust fput(f1); 477de18643dSTrond Myklebust if (f2) 478de18643dSTrond Myklebust fput(f2); 479f9d7562fSJ. Bruce Fields } 480f9d7562fSJ. Bruce Fields } 481f9d7562fSJ. Bruce Fields 48212659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 483998db52cSJ. Bruce Fields { 48412659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 48512659651SJeff Layton 48612659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 487998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 48812659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 48912659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 490998db52cSJ. Bruce Fields } 491998db52cSJ. Bruce Fields 4926011695dSTrond Myklebust static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 4936011695dSTrond Myklebust struct kmem_cache *slab) 494996e0938SJ. Bruce Fields { 4953abdb607SJ. Bruce Fields struct nfs4_stid *stid; 4963abdb607SJ. Bruce Fields int new_id; 4973abdb607SJ. Bruce Fields 498f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 4993abdb607SJ. Bruce Fields if (!stid) 5003abdb607SJ. Bruce Fields return NULL; 501996e0938SJ. Bruce Fields 5024770d722SJeff Layton idr_preload(GFP_KERNEL); 5034770d722SJeff Layton spin_lock(&cl->cl_lock); 5044770d722SJeff Layton new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT); 5054770d722SJeff Layton spin_unlock(&cl->cl_lock); 5064770d722SJeff Layton idr_preload_end(); 507ebd6c707STejun Heo if (new_id < 0) 5083abdb607SJ. Bruce Fields goto out_free; 5093abdb607SJ. Bruce Fields stid->sc_client = cl; 5103abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 5113abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 5123abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 51372c0b0fbSTrond Myklebust atomic_set(&stid->sc_count, 1); 5143abdb607SJ. Bruce Fields 515996e0938SJ. Bruce Fields /* 5163abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 5173abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 5183abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 5193abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 5203abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 5213abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 5223abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 523996e0938SJ. Bruce Fields */ 5243abdb607SJ. Bruce Fields return stid; 5253abdb607SJ. Bruce Fields out_free: 5262c44a234SWei Yongjun kmem_cache_free(slab, stid); 5273abdb607SJ. Bruce Fields return NULL; 5282a74aba7SJ. Bruce Fields } 5292a74aba7SJ. Bruce Fields 530b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 5314cdc951bSJ. Bruce Fields { 5326011695dSTrond Myklebust struct nfs4_stid *stid; 5336011695dSTrond Myklebust struct nfs4_ol_stateid *stp; 5346011695dSTrond Myklebust 5356011695dSTrond Myklebust stid = nfs4_alloc_stid(clp, stateid_slab); 5366011695dSTrond Myklebust if (!stid) 5376011695dSTrond Myklebust return NULL; 5386011695dSTrond Myklebust 5396011695dSTrond Myklebust stp = openlockstateid(stid); 5406011695dSTrond Myklebust stp->st_stid.sc_free = nfs4_free_ol_stateid; 5416011695dSTrond Myklebust return stp; 5426011695dSTrond Myklebust } 5436011695dSTrond Myklebust 5446011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 5456011695dSTrond Myklebust { 5466011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 5476011695dSTrond Myklebust atomic_long_dec(&num_delegations); 5484cdc951bSJ. Bruce Fields } 5494cdc951bSJ. Bruce Fields 5506282cd56SNeilBrown /* 5516282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 5526282cd56SNeilBrown * out again straight away. 5536282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 5546282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 5556282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 5566282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 5576282cd56SNeilBrown * filter. 5586282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 5596282cd56SNeilBrown * unless both are empty of course. 5606282cd56SNeilBrown * 5616282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 5626282cd56SNeilBrown * low 3 bytes as hash-table indices. 5636282cd56SNeilBrown * 564f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 5656282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 5666282cd56SNeilBrown * except when swapping the two filters. 5676282cd56SNeilBrown */ 568f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 5696282cd56SNeilBrown static struct bloom_pair { 5706282cd56SNeilBrown int entries, old_entries; 5716282cd56SNeilBrown time_t swap_time; 5726282cd56SNeilBrown int new; /* index into 'set' */ 5736282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 5746282cd56SNeilBrown } blocked_delegations; 5756282cd56SNeilBrown 5766282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 5776282cd56SNeilBrown { 5786282cd56SNeilBrown u32 hash; 5796282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 5806282cd56SNeilBrown 5816282cd56SNeilBrown if (bd->entries == 0) 5826282cd56SNeilBrown return 0; 5836282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 584f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 5856282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 5866282cd56SNeilBrown bd->entries -= bd->old_entries; 5876282cd56SNeilBrown bd->old_entries = bd->entries; 5886282cd56SNeilBrown memset(bd->set[bd->new], 0, 5896282cd56SNeilBrown sizeof(bd->set[0])); 5906282cd56SNeilBrown bd->new = 1-bd->new; 5916282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 5926282cd56SNeilBrown } 593f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 5946282cd56SNeilBrown } 5956282cd56SNeilBrown hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0); 5966282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 5976282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 5986282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 5996282cd56SNeilBrown return 1; 6006282cd56SNeilBrown 6016282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 6026282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 6036282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 6046282cd56SNeilBrown return 1; 6056282cd56SNeilBrown 6066282cd56SNeilBrown return 0; 6076282cd56SNeilBrown } 6086282cd56SNeilBrown 6096282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 6106282cd56SNeilBrown { 6116282cd56SNeilBrown u32 hash; 6126282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 6136282cd56SNeilBrown 6146282cd56SNeilBrown hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0); 6156282cd56SNeilBrown 616f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 6176282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 6186282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 6196282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 6206282cd56SNeilBrown if (bd->entries == 0) 6216282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 6226282cd56SNeilBrown bd->entries += 1; 623f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 6246282cd56SNeilBrown } 6256282cd56SNeilBrown 6261da177e4SLinus Torvalds static struct nfs4_delegation * 627f9416e28SJeff Layton alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) 6281da177e4SLinus Torvalds { 6291da177e4SLinus Torvalds struct nfs4_delegation *dp; 63002a3508dSTrond Myklebust long n; 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 63302a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 63402a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 63502a3508dSTrond Myklebust goto out_dec; 6366282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 63702a3508dSTrond Myklebust goto out_dec; 638996e0938SJ. Bruce Fields dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); 6395b2d21c1SNeilBrown if (dp == NULL) 64002a3508dSTrond Myklebust goto out_dec; 6416011695dSTrond Myklebust 6426011695dSTrond Myklebust dp->dl_stid.sc_free = nfs4_free_deleg; 6432a74aba7SJ. Bruce Fields /* 6442a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 6456136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 6466136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 6472a74aba7SJ. Bruce Fields */ 6482a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 649ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 650ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 6511da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 65299c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 65302e1215fSJeff Layton INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall); 6541da177e4SLinus Torvalds return dp; 65502a3508dSTrond Myklebust out_dec: 65602a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 65702a3508dSTrond Myklebust return NULL; 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds void 6616011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 6621da177e4SLinus Torvalds { 66311b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 6646011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 6656011695dSTrond Myklebust 6664770d722SJeff Layton might_lock(&clp->cl_lock); 6674770d722SJeff Layton 668b401be22SJeff Layton if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 669b401be22SJeff Layton wake_up_all(&close_wq); 6706011695dSTrond Myklebust return; 671b401be22SJeff Layton } 6726011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 6734770d722SJeff Layton spin_unlock(&clp->cl_lock); 6746011695dSTrond Myklebust s->sc_free(s); 67511b9164aSTrond Myklebust if (fp) 67611b9164aSTrond Myklebust put_nfs4_file(fp); 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 679acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp) 6801da177e4SLinus Torvalds { 6816bcc034eSJeff Layton struct file *filp = NULL; 6826bcc034eSJeff Layton struct file_lock *fl; 683417c6629SJeff Layton 6846bcc034eSJeff Layton spin_lock(&fp->fi_lock); 6856bcc034eSJeff Layton if (fp->fi_lease && atomic_dec_and_test(&fp->fi_delegees)) { 6866bcc034eSJeff Layton swap(filp, fp->fi_deleg_file); 6876bcc034eSJeff Layton fl = fp->fi_lease; 688acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 6896bcc034eSJeff Layton } 6906bcc034eSJeff Layton spin_unlock(&fp->fi_lock); 6916bcc034eSJeff Layton 6926bcc034eSJeff Layton if (filp) { 6936bcc034eSJeff Layton vfs_setlease(filp, F_UNLCK, &fl); 6946bcc034eSJeff Layton fput(filp); 695acfdf5c3SJ. Bruce Fields } 6961da177e4SLinus Torvalds } 6971da177e4SLinus Torvalds 6986136d2b4SJ. Bruce Fields static void unhash_stid(struct nfs4_stid *s) 6996136d2b4SJ. Bruce Fields { 7003abdb607SJ. Bruce Fields s->sc_type = 0; 7016136d2b4SJ. Bruce Fields } 7026136d2b4SJ. Bruce Fields 703931ee56cSBenny Halevy static void 704931ee56cSBenny Halevy hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 705931ee56cSBenny Halevy { 706cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 707417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 708931ee56cSBenny Halevy 70967cb1279STrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 7103fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 711931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 712931ee56cSBenny Halevy list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); 713931ee56cSBenny Halevy } 714931ee56cSBenny Halevy 7151da177e4SLinus Torvalds static void 71642690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 7171da177e4SLinus Torvalds { 71811b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 71902e1215fSJeff Layton 72042690676SJeff Layton lockdep_assert_held(&state_lock); 72142690676SJeff Layton 722b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 723d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 724d55a166cSJeff Layton ++dp->dl_time; 725417c6629SJeff Layton spin_lock(&fp->fi_lock); 726931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 7271da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 72802e1215fSJeff Layton list_del_init(&dp->dl_perfile); 72902e1215fSJeff Layton spin_unlock(&fp->fi_lock); 730cbf7a75bSJ. Bruce Fields } 7313bd64a5bSJ. Bruce Fields 7323bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 7333bd64a5bSJ. Bruce Fields { 73442690676SJeff Layton spin_lock(&state_lock); 73542690676SJeff Layton unhash_delegation_locked(dp); 73642690676SJeff Layton spin_unlock(&state_lock); 737afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 7386011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 7393bd64a5bSJ. Bruce Fields } 7403bd64a5bSJ. Bruce Fields 7413bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 7423bd64a5bSJ. Bruce Fields { 7433bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 7443bd64a5bSJ. Bruce Fields 7452d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 7462d4a532dSJeff Layton 747afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 748afbda402SJeff Layton 7493bd64a5bSJ. Bruce Fields if (clp->cl_minorversion == 0) 7506011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 7513bd64a5bSJ. Bruce Fields else { 7523bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 7532d4a532dSJeff Layton spin_lock(&clp->cl_lock); 7542d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 7552d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 7563bd64a5bSJ. Bruce Fields } 7573bd64a5bSJ. Bruce Fields } 7583bd64a5bSJ. Bruce Fields 7591da177e4SLinus Torvalds /* 7601da177e4SLinus Torvalds * SETCLIENTID state 7611da177e4SLinus Torvalds */ 7621da177e4SLinus Torvalds 763ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 764ddc04c41SJ. Bruce Fields { 765ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 766ddc04c41SJ. Bruce Fields } 767ddc04c41SJ. Bruce Fields 768ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 769ddc04c41SJ. Bruce Fields { 770ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 771ddc04c41SJ. Bruce Fields } 772ddc04c41SJ. Bruce Fields 7731da177e4SLinus Torvalds /* 774f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 775f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 776f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 777f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 778f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 779f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 780f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 781f9d7562fSJ. Bruce Fields * 782f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 783f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 784f9d7562fSJ. Bruce Fields * 785f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 786f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 787f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 788f9d7562fSJ. Bruce Fields * 789f9d7562fSJ. Bruce Fields * which we should reject. 790f9d7562fSJ. Bruce Fields */ 7915ae037e5SJeff Layton static unsigned int 7925ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 793f9d7562fSJ. Bruce Fields int i; 7945ae037e5SJeff Layton unsigned int access = 0; 795f9d7562fSJ. Bruce Fields 796f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 797f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 7985ae037e5SJeff Layton access |= i; 799f9d7562fSJ. Bruce Fields } 8005ae037e5SJeff Layton return access; 801f9d7562fSJ. Bruce Fields } 802f9d7562fSJ. Bruce Fields 80382c5ff1bSJeff Layton /* set share access for a given stateid */ 80482c5ff1bSJeff Layton static inline void 80582c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 80682c5ff1bSJeff Layton { 807c11c591fSJeff Layton unsigned char mask = 1 << access; 808c11c591fSJeff Layton 809c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 810c11c591fSJeff Layton stp->st_access_bmap |= mask; 81182c5ff1bSJeff Layton } 81282c5ff1bSJeff Layton 81382c5ff1bSJeff Layton /* clear share access for a given stateid */ 81482c5ff1bSJeff Layton static inline void 81582c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 81682c5ff1bSJeff Layton { 817c11c591fSJeff Layton unsigned char mask = 1 << access; 818c11c591fSJeff Layton 819c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 820c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 82182c5ff1bSJeff Layton } 82282c5ff1bSJeff Layton 82382c5ff1bSJeff Layton /* test whether a given stateid has access */ 82482c5ff1bSJeff Layton static inline bool 82582c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 82682c5ff1bSJeff Layton { 827c11c591fSJeff Layton unsigned char mask = 1 << access; 828c11c591fSJeff Layton 829c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 83082c5ff1bSJeff Layton } 83182c5ff1bSJeff Layton 832ce0fc43cSJeff Layton /* set share deny for a given stateid */ 833ce0fc43cSJeff Layton static inline void 834c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 835ce0fc43cSJeff Layton { 836c11c591fSJeff Layton unsigned char mask = 1 << deny; 837c11c591fSJeff Layton 838c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 839c11c591fSJeff Layton stp->st_deny_bmap |= mask; 840ce0fc43cSJeff Layton } 841ce0fc43cSJeff Layton 842ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 843ce0fc43cSJeff Layton static inline void 844c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 845ce0fc43cSJeff Layton { 846c11c591fSJeff Layton unsigned char mask = 1 << deny; 847c11c591fSJeff Layton 848c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 849c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 850ce0fc43cSJeff Layton } 851ce0fc43cSJeff Layton 852ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 853ce0fc43cSJeff Layton static inline bool 854c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 855ce0fc43cSJeff Layton { 856c11c591fSJeff Layton unsigned char mask = 1 << deny; 857c11c591fSJeff Layton 858c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 859f9d7562fSJ. Bruce Fields } 860f9d7562fSJ. Bruce Fields 861f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 862f9d7562fSJ. Bruce Fields { 8638f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 864f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 865f9d7562fSJ. Bruce Fields return O_RDONLY; 866f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 867f9d7562fSJ. Bruce Fields return O_WRONLY; 868f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 869f9d7562fSJ. Bruce Fields return O_RDWR; 870f9d7562fSJ. Bruce Fields } 871063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 872063b0fb9SJ. Bruce Fields return O_RDONLY; 873f9d7562fSJ. Bruce Fields } 874f9d7562fSJ. Bruce Fields 875baeb4ff0SJeff Layton /* 876baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 877baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 878baeb4ff0SJeff Layton */ 879baeb4ff0SJeff Layton static void 880baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 881baeb4ff0SJeff Layton { 882baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 883baeb4ff0SJeff Layton 884baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 885baeb4ff0SJeff Layton fp->fi_share_deny = 0; 886baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 887baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 888baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 889baeb4ff0SJeff Layton } 890baeb4ff0SJeff Layton 891baeb4ff0SJeff Layton static void 892baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 893baeb4ff0SJeff Layton { 894baeb4ff0SJeff Layton int i; 895baeb4ff0SJeff Layton bool change = false; 896baeb4ff0SJeff Layton 897baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 898baeb4ff0SJeff Layton if ((i & deny) != i) { 899baeb4ff0SJeff Layton change = true; 900baeb4ff0SJeff Layton clear_deny(i, stp); 901baeb4ff0SJeff Layton } 902baeb4ff0SJeff Layton } 903baeb4ff0SJeff Layton 904baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 905baeb4ff0SJeff Layton if (change) 90611b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 907baeb4ff0SJeff Layton } 908baeb4ff0SJeff Layton 90982c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 91082c5ff1bSJeff Layton static void 91182c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 91282c5ff1bSJeff Layton { 91382c5ff1bSJeff Layton int i; 91411b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 915baeb4ff0SJeff Layton 916baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 917baeb4ff0SJeff Layton recalculate_deny_mode(fp); 91882c5ff1bSJeff Layton 91982c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 92082c5ff1bSJeff Layton if (test_access(i, stp)) 92111b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 92282c5ff1bSJeff Layton clear_access(i, stp); 92382c5ff1bSJeff Layton } 92482c5ff1bSJeff Layton } 92582c5ff1bSJeff Layton 9266b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 9276b180f0bSJeff Layton { 928a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 929a819ecc1SJeff Layton 930a819ecc1SJeff Layton might_lock(&clp->cl_lock); 931a819ecc1SJeff Layton 932a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 9336b180f0bSJeff Layton return; 9348f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 935a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 9366b180f0bSJeff Layton kfree(sop->so_owner.data); 9376b180f0bSJeff Layton sop->so_ops->so_free(sop); 9386b180f0bSJeff Layton } 9396b180f0bSJeff Layton 9404ae098d3SJeff Layton static void unhash_ol_stateid(struct nfs4_ol_stateid *stp) 941529d7b2aSJ. Bruce Fields { 94211b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 9431d31a253STrond Myklebust 9441c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 9451c755dc1SJeff Layton 9461d31a253STrond Myklebust spin_lock(&fp->fi_lock); 947529d7b2aSJ. Bruce Fields list_del(&stp->st_perfile); 9481d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 949529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 950529d7b2aSJ. Bruce Fields } 951529d7b2aSJ. Bruce Fields 9526011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 953529d7b2aSJ. Bruce Fields { 9546011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 9554665e2baSJ. Bruce Fields 9566011695dSTrond Myklebust release_all_access(stp); 957d3134b10SJeff Layton if (stp->st_stateowner) 958d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 9596011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 960529d7b2aSJ. Bruce Fields } 961529d7b2aSJ. Bruce Fields 962b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 963529d7b2aSJ. Bruce Fields { 964b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 965b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 966529d7b2aSJ. Bruce Fields struct file *file; 967529d7b2aSJ. Bruce Fields 968b49e084dSJeff Layton file = find_any_file(stp->st_stid.sc_file); 969b49e084dSJeff Layton if (file) 970b49e084dSJeff Layton filp_close(file, (fl_owner_t)lo); 971b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 972b49e084dSJeff Layton } 973b49e084dSJeff Layton 9742c41beb0SJeff Layton /* 9752c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 9762c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 9772c41beb0SJeff Layton * reaplist for later destruction. 9782c41beb0SJeff Layton */ 9792c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 9802c41beb0SJeff Layton struct list_head *reaplist) 9812c41beb0SJeff Layton { 9822c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 9832c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 9842c41beb0SJeff Layton 9852c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 9862c41beb0SJeff Layton 9872c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 9882c41beb0SJeff Layton 9892c41beb0SJeff Layton if (!atomic_dec_and_test(&s->sc_count)) { 9902c41beb0SJeff Layton wake_up_all(&close_wq); 9912c41beb0SJeff Layton return; 9922c41beb0SJeff Layton } 9932c41beb0SJeff Layton 9942c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 9952c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 9962c41beb0SJeff Layton } 9972c41beb0SJeff Layton 9983c1c995cSJeff Layton static void unhash_lock_stateid(struct nfs4_ol_stateid *stp) 9993c1c995cSJeff Layton { 10003c1c995cSJeff Layton struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 10013c1c995cSJeff Layton 10023c1c995cSJeff Layton lockdep_assert_held(&oo->oo_owner.so_client->cl_lock); 10033c1c995cSJeff Layton 10043c1c995cSJeff Layton list_del_init(&stp->st_locks); 10054ae098d3SJeff Layton unhash_ol_stateid(stp); 10063c1c995cSJeff Layton unhash_stid(&stp->st_stid); 10073c1c995cSJeff Layton } 10083c1c995cSJeff Layton 10095adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1010b49e084dSJeff Layton { 10111c755dc1SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 10121c755dc1SJeff Layton 10131c755dc1SJeff Layton spin_lock(&oo->oo_owner.so_client->cl_lock); 10143c1c995cSJeff Layton unhash_lock_stateid(stp); 10151c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 10166011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1017529d7b2aSJ. Bruce Fields } 1018529d7b2aSJ. Bruce Fields 1019c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1020529d7b2aSJ. Bruce Fields { 1021d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1022c58c6610STrond Myklebust 1023d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1024c58c6610STrond Myklebust 10258f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 10268f4b54c5SJeff Layton } 10278f4b54c5SJeff Layton 10282c41beb0SJeff Layton /* 10292c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 10302c41beb0SJeff Layton * fully unhashed. 10312c41beb0SJeff Layton */ 10322c41beb0SJeff Layton static void 10332c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 10342c41beb0SJeff Layton { 10352c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1036fb94d766SKinglong Mee struct nfs4_file *fp; 10372c41beb0SJeff Layton 10382c41beb0SJeff Layton might_sleep(); 10392c41beb0SJeff Layton 10402c41beb0SJeff Layton while (!list_empty(reaplist)) { 10412c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 10422c41beb0SJeff Layton st_locks); 10432c41beb0SJeff Layton list_del(&stp->st_locks); 1044fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 10452c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1046fb94d766SKinglong Mee if (fp) 1047fb94d766SKinglong Mee put_nfs4_file(fp); 10482c41beb0SJeff Layton } 10492c41beb0SJeff Layton } 10502c41beb0SJeff Layton 1051fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo) 1052529d7b2aSJ. Bruce Fields { 1053d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 10543c1c995cSJeff Layton struct nfs4_ol_stateid *stp; 10553c1c995cSJeff Layton struct list_head reaplist; 10563c1c995cSJeff Layton 10573c1c995cSJeff Layton INIT_LIST_HEAD(&reaplist); 1058c58c6610STrond Myklebust 1059d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 1060c58c6610STrond Myklebust unhash_lockowner_locked(lo); 10613c1c995cSJeff Layton while (!list_empty(&lo->lo_owner.so_stateids)) { 10623c1c995cSJeff Layton stp = list_first_entry(&lo->lo_owner.so_stateids, 10633c1c995cSJeff Layton struct nfs4_ol_stateid, st_perstateowner); 10643c1c995cSJeff Layton unhash_lock_stateid(stp); 10652c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 10663c1c995cSJeff Layton } 1067d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 10682c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 10696b180f0bSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 1070529d7b2aSJ. Bruce Fields } 1071529d7b2aSJ. Bruce Fields 1072d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1073d83017f9SJeff Layton struct list_head *reaplist) 10743c87b9b7STrond Myklebust { 10753c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 10763c87b9b7STrond Myklebust 10773c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 10783c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 10793c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1080d83017f9SJeff Layton unhash_lock_stateid(stp); 1081d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1082529d7b2aSJ. Bruce Fields } 1083529d7b2aSJ. Bruce Fields } 1084529d7b2aSJ. Bruce Fields 1085d83017f9SJeff Layton static void unhash_open_stateid(struct nfs4_ol_stateid *stp, 1086d83017f9SJeff Layton struct list_head *reaplist) 10872283963fSJ. Bruce Fields { 10882c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 10892c41beb0SJeff Layton 10904ae098d3SJeff Layton unhash_ol_stateid(stp); 1091d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 109238c387b5SJ. Bruce Fields } 109338c387b5SJ. Bruce Fields 109438c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 109538c387b5SJ. Bruce Fields { 10962c41beb0SJeff Layton LIST_HEAD(reaplist); 10972c41beb0SJeff Layton 10982c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1099d83017f9SJeff Layton unhash_open_stateid(stp, &reaplist); 11002c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 11012c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 11022c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 11032283963fSJ. Bruce Fields } 11042283963fSJ. Bruce Fields 11057ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1106f1d110caSJ. Bruce Fields { 1107d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 11087ffb5880STrond Myklebust 1109d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 11107ffb5880STrond Myklebust 11118f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 11128f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1113f1d110caSJ. Bruce Fields } 1114f1d110caSJ. Bruce Fields 1115f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1116f7a4d872SJ. Bruce Fields { 1117217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1118217526e7SJeff Layton nfsd_net_id); 1119217526e7SJeff Layton struct nfs4_ol_stateid *s; 1120f7a4d872SJ. Bruce Fields 1121217526e7SJeff Layton spin_lock(&nn->client_lock); 1122217526e7SJeff Layton s = oo->oo_last_closed_stid; 1123f7a4d872SJ. Bruce Fields if (s) { 1124d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1125f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1126f7a4d872SJ. Bruce Fields } 1127217526e7SJeff Layton spin_unlock(&nn->client_lock); 1128217526e7SJeff Layton if (s) 1129217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1130f7a4d872SJ. Bruce Fields } 1131f7a4d872SJ. Bruce Fields 11322c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 11338f4b54c5SJeff Layton { 11348f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1135d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 11362c41beb0SJeff Layton struct list_head reaplist; 11377ffb5880STrond Myklebust 11382c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 11397ffb5880STrond Myklebust 1140d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 11417ffb5880STrond Myklebust unhash_openowner_locked(oo); 11422c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 11432c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 11442c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1145d83017f9SJeff Layton unhash_open_stateid(stp, &reaplist); 11462c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 11472c41beb0SJeff Layton } 1148d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 11492c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1150f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 11516b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1152f1d110caSJ. Bruce Fields } 1153f1d110caSJ. Bruce Fields 11545282fd72SMarc Eshel static inline int 11555282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 11565282fd72SMarc Eshel { 11575282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 11585282fd72SMarc Eshel 11595282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 11605282fd72SMarc Eshel } 11615282fd72SMarc Eshel 11628f199b82STrond Myklebust #ifdef NFSD_DEBUG 11635282fd72SMarc Eshel static inline void 11645282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 11655282fd72SMarc Eshel { 11665282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 11675282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 11685282fd72SMarc Eshel } 11698f199b82STrond Myklebust #else 11708f199b82STrond Myklebust static inline void 11718f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 11728f199b82STrond Myklebust { 11738f199b82STrond Myklebust } 11748f199b82STrond Myklebust #endif 11758f199b82STrond Myklebust 11769411b1d4SJ. Bruce Fields /* 11779411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 11789411b1d4SJ. Bruce Fields * won't be used for replay. 11799411b1d4SJ. Bruce Fields */ 11809411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 11819411b1d4SJ. Bruce Fields { 11829411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 11839411b1d4SJ. Bruce Fields 11849411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 11859411b1d4SJ. Bruce Fields return; 11869411b1d4SJ. Bruce Fields 11879411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 118858fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 11899411b1d4SJ. Bruce Fields return; 11909411b1d4SJ. Bruce Fields } 11919411b1d4SJ. Bruce Fields if (!so) 11929411b1d4SJ. Bruce Fields return; 11939411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 11949411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 11959411b1d4SJ. Bruce Fields so->so_seqid++; 11969411b1d4SJ. Bruce Fields return; 11979411b1d4SJ. Bruce Fields } 11985282fd72SMarc Eshel 1199ec6b5d7bSAndy Adamson static void 1200ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1201ec6b5d7bSAndy Adamson { 1202ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1203ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1204ec6b5d7bSAndy Adamson 1205ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1206ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1207ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1208ec6b5d7bSAndy Adamson sid->reserved = 0; 1209ec6b5d7bSAndy Adamson } 1210ec6b5d7bSAndy Adamson 1211ec6b5d7bSAndy Adamson /* 1212a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1213a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1214a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1215a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1216a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1217a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1218a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1219a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1220a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1221a649637cSAndy Adamson * for the SEQUENCE op response: 1222ec6b5d7bSAndy Adamson */ 1223a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1224a649637cSAndy Adamson 1225557ce264SAndy Adamson static void 1226557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1227557ce264SAndy Adamson { 1228557ce264SAndy Adamson int i; 1229557ce264SAndy Adamson 1230557ce264SAndy Adamson for (i = 0; i < ses->se_fchannel.maxreqs; i++) 1231557ce264SAndy Adamson kfree(ses->se_slots[i]); 1232557ce264SAndy Adamson } 1233557ce264SAndy Adamson 1234efe0cb6dSJ. Bruce Fields /* 1235efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1236efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1237efe0cb6dSJ. Bruce Fields */ 123855c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1239efe0cb6dSJ. Bruce Fields { 124055c760cfSJ. Bruce Fields u32 size; 1241efe0cb6dSJ. Bruce Fields 124255c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 124355c760cfSJ. Bruce Fields size = 0; 124455c760cfSJ. Bruce Fields else 124555c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 124655c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1247557ce264SAndy Adamson } 1248557ce264SAndy Adamson 12495b6feee9SJ. Bruce Fields /* 12505b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 12515b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 125242b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 12535b6feee9SJ. Bruce Fields */ 125455c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 12555b6feee9SJ. Bruce Fields { 125655c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 125755c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 12585b6feee9SJ. Bruce Fields int avail; 12595b6feee9SJ. Bruce Fields 12605b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 1261697ce9beSZhang Yanfei avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, 12625b6feee9SJ. Bruce Fields nfsd_drc_max_mem - nfsd_drc_mem_used); 12635b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 12645b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 12655b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 12665b6feee9SJ. Bruce Fields 12675b6feee9SJ. Bruce Fields return num; 12685b6feee9SJ. Bruce Fields } 12695b6feee9SJ. Bruce Fields 127055c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 12715b6feee9SJ. Bruce Fields { 127255c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 127355c760cfSJ. Bruce Fields 12745b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 127555c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 12765b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 12775b6feee9SJ. Bruce Fields } 12785b6feee9SJ. Bruce Fields 127960810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 128060810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 12815b6feee9SJ. Bruce Fields { 128260810e54SKinglong Mee int numslots = fattrs->maxreqs; 128360810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 12845b6feee9SJ. Bruce Fields struct nfsd4_session *new; 12855b6feee9SJ. Bruce Fields int mem, i; 1286ec6b5d7bSAndy Adamson 1287c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1288ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 12895b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1290ec6b5d7bSAndy Adamson 12915b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 12926c18ba9fSAlexandros Batsakis if (!new) 12935b6feee9SJ. Bruce Fields return NULL; 1294ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 12955b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 129655c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 12975b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1298ec6b5d7bSAndy Adamson goto out_free; 1299ec6b5d7bSAndy Adamson } 130060810e54SKinglong Mee 130160810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 130260810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 130360810e54SKinglong Mee 13045b6feee9SJ. Bruce Fields return new; 13055b6feee9SJ. Bruce Fields out_free: 13065b6feee9SJ. Bruce Fields while (i--) 13075b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 13085b6feee9SJ. Bruce Fields kfree(new); 13095b6feee9SJ. Bruce Fields return NULL; 13105b6feee9SJ. Bruce Fields } 13115b6feee9SJ. Bruce Fields 131219cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 131319cf5c02SJ. Bruce Fields { 131419cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 131519cf5c02SJ. Bruce Fields kfree(c); 131619cf5c02SJ. Bruce Fields } 131719cf5c02SJ. Bruce Fields 131819cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 131919cf5c02SJ. Bruce Fields { 132019cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 132119cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 132219cf5c02SJ. Bruce Fields 132319cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 132419cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 132519cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 132619cf5c02SJ. Bruce Fields free_conn(c); 132719cf5c02SJ. Bruce Fields } 1328eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 13292e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 133019cf5c02SJ. Bruce Fields } 133119cf5c02SJ. Bruce Fields 1332d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1333c7662518SJ. Bruce Fields { 1334c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1335c7662518SJ. Bruce Fields 1336c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1337c7662518SJ. Bruce Fields if (!conn) 1338db90681dSJ. Bruce Fields return NULL; 1339c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1340c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1341d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1342db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1343db90681dSJ. Bruce Fields return conn; 1344db90681dSJ. Bruce Fields } 1345db90681dSJ. Bruce Fields 1346328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1347328ead28SJ. Bruce Fields { 1348328ead28SJ. Bruce Fields conn->cn_session = ses; 1349328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1350328ead28SJ. Bruce Fields } 1351328ead28SJ. Bruce Fields 1352db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1353db90681dSJ. Bruce Fields { 1354db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1355c7662518SJ. Bruce Fields 1356c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1357328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1358c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1359db90681dSJ. Bruce Fields } 1360c7662518SJ. Bruce Fields 136121b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1362db90681dSJ. Bruce Fields { 136319cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 136421b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1365db90681dSJ. Bruce Fields } 1366db90681dSJ. Bruce Fields 1367e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1368db90681dSJ. Bruce Fields { 136921b75b01SJ. Bruce Fields int ret; 1370db90681dSJ. Bruce Fields 1371db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 137221b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 137321b75b01SJ. Bruce Fields if (ret) 137421b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 137521b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 137657a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 137757a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1378c7662518SJ. Bruce Fields } 1379c7662518SJ. Bruce Fields 1380e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 13811d1bc8f2SJ. Bruce Fields { 13821d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 13831d1bc8f2SJ. Bruce Fields 1384e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 13851d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1386e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 13871d1bc8f2SJ. Bruce Fields } 13881d1bc8f2SJ. Bruce Fields 13891d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 139019cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1391c7662518SJ. Bruce Fields { 139219cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 139319cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 139419cf5c02SJ. Bruce Fields 139519cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 139619cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 139719cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 139819cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 139919cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 140019cf5c02SJ. Bruce Fields 140119cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 140219cf5c02SJ. Bruce Fields free_conn(c); 140319cf5c02SJ. Bruce Fields 140419cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 140519cf5c02SJ. Bruce Fields } 140619cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1407c7662518SJ. Bruce Fields } 1408c7662518SJ. Bruce Fields 14091377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 14101377b69eSJ. Bruce Fields { 14111377b69eSJ. Bruce Fields free_session_slots(ses); 14121377b69eSJ. Bruce Fields kfree(ses); 14131377b69eSJ. Bruce Fields } 14141377b69eSJ. Bruce Fields 141566b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1416508dc6e1SBenny Halevy { 1417c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 141855c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1419c7662518SJ. Bruce Fields __free_session(ses); 1420a827bcb2SJ. Bruce Fields } 1421ec6b5d7bSAndy Adamson 1422135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1423a827bcb2SJ. Bruce Fields { 1424a827bcb2SJ. Bruce Fields int idx; 14251872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1426a827bcb2SJ. Bruce Fields 1427ec6b5d7bSAndy Adamson new->se_client = clp; 1428ec6b5d7bSAndy Adamson gen_sessionid(new); 1429ec6b5d7bSAndy Adamson 1430c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1431c7662518SJ. Bruce Fields 1432ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1433ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 14348b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1435c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 143666b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 14375b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 14381872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 14394c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1440ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 14414c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 144260810e54SKinglong Mee 1443dcbeaa68SJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) { 1444edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1445dcbeaa68SJ. Bruce Fields /* 1446dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1447dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1448dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1449dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1450dcbeaa68SJ. Bruce Fields * future: 1451dcbeaa68SJ. Bruce Fields */ 1452edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1453edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1454edd76786SJ. Bruce Fields } 1455ec6b5d7bSAndy Adamson } 1456ec6b5d7bSAndy Adamson 14579089f1b4SBenny Halevy /* caller must hold client_lock */ 14585282fd72SMarc Eshel static struct nfsd4_session * 1459d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 14605282fd72SMarc Eshel { 14615282fd72SMarc Eshel struct nfsd4_session *elem; 14625282fd72SMarc Eshel int idx; 14631872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 14645282fd72SMarc Eshel 14650a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 14660a880a28STrond Myklebust 14675282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 14685282fd72SMarc Eshel idx = hash_sessionid(sessionid); 14695282fd72SMarc Eshel /* Search in the appropriate list */ 14701872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 14715282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 14725282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 14735282fd72SMarc Eshel return elem; 14745282fd72SMarc Eshel } 14755282fd72SMarc Eshel } 14765282fd72SMarc Eshel 14775282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 14785282fd72SMarc Eshel return NULL; 14795282fd72SMarc Eshel } 14805282fd72SMarc Eshel 1481d4e19e70STrond Myklebust static struct nfsd4_session * 1482d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1483d4e19e70STrond Myklebust __be32 *ret) 1484d4e19e70STrond Myklebust { 1485d4e19e70STrond Myklebust struct nfsd4_session *session; 1486d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1487d4e19e70STrond Myklebust 1488d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1489d4e19e70STrond Myklebust if (!session) 1490d4e19e70STrond Myklebust goto out; 1491d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1492d4e19e70STrond Myklebust if (status) 1493d4e19e70STrond Myklebust session = NULL; 1494d4e19e70STrond Myklebust out: 1495d4e19e70STrond Myklebust *ret = status; 1496d4e19e70STrond Myklebust return session; 1497d4e19e70STrond Myklebust } 1498d4e19e70STrond Myklebust 14999089f1b4SBenny Halevy /* caller must hold client_lock */ 15007116ed6bSAndy Adamson static void 15015282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 15027116ed6bSAndy Adamson { 15030a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 15040a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 15050a880a28STrond Myklebust 15060a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 15070a880a28STrond Myklebust 15087116ed6bSAndy Adamson list_del(&ses->se_hash); 15094c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 15107116ed6bSAndy Adamson list_del(&ses->se_perclnt); 15114c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 15125282fd72SMarc Eshel } 15135282fd72SMarc Eshel 15141da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 15151da177e4SLinus Torvalds static int 15162c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 15171da177e4SLinus Torvalds { 15182c142baaSStanislav Kinsbursky if (clid->cl_boot == nn->boot_time) 15191da177e4SLinus Torvalds return 0; 152060adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 15212c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 15221da177e4SLinus Torvalds return 1; 15231da177e4SLinus Torvalds } 15241da177e4SLinus Torvalds 15251da177e4SLinus Torvalds /* 15261da177e4SLinus Torvalds * XXX Should we use a slab cache ? 15271da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 15281da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 15291da177e4SLinus Torvalds */ 153035bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 15311da177e4SLinus Torvalds { 15321da177e4SLinus Torvalds struct nfs4_client *clp; 1533d4f0489fSTrond Myklebust int i; 15341da177e4SLinus Torvalds 153535bba9a3SJ. Bruce Fields clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); 153635bba9a3SJ. Bruce Fields if (clp == NULL) 153735bba9a3SJ. Bruce Fields return NULL; 153867114fe6SThomas Meyer clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); 1539d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1540d4f0489fSTrond Myklebust goto err_no_name; 1541d4f0489fSTrond Myklebust clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * 1542d4f0489fSTrond Myklebust OWNER_HASH_SIZE, GFP_KERNEL); 1543d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1544d4f0489fSTrond Myklebust goto err_no_hashtbl; 1545d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1546d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 15471da177e4SLinus Torvalds clp->cl_name.len = name.len; 15485694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 15495694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 15505694c93eSTrond Myklebust atomic_set(&clp->cl_refcount, 0); 15515694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 15525694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 15535694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 15545694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 15555694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 15565694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_callbacks); 15575694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 15585694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 15595694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 15601da177e4SLinus Torvalds return clp; 1561d4f0489fSTrond Myklebust err_no_hashtbl: 1562d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1563d4f0489fSTrond Myklebust err_no_name: 1564d4f0489fSTrond Myklebust kfree(clp); 1565d4f0489fSTrond Myklebust return NULL; 15661da177e4SLinus Torvalds } 15671da177e4SLinus Torvalds 15684dd86e15STrond Myklebust static void 15691da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 15701da177e4SLinus Torvalds { 1571792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1572792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1573792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1574792c95ddSJ. Bruce Fields se_perclnt); 1575792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 157666b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 157766b2b9b2SJ. Bruce Fields free_session(ses); 1578792c95ddSJ. Bruce Fields } 15794cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 158003a4e1f6SJ. Bruce Fields free_svc_cred(&clp->cl_cred); 1581d4f0489fSTrond Myklebust kfree(clp->cl_ownerstr_hashtbl); 15821da177e4SLinus Torvalds kfree(clp->cl_name.data); 15832d32b29aSmajianpeng idr_destroy(&clp->cl_stateids); 15841da177e4SLinus Torvalds kfree(clp); 15851da177e4SLinus Torvalds } 15861da177e4SLinus Torvalds 158784d38ac9SBenny Halevy /* must be called under the client_lock */ 15884beb345bSTrond Myklebust static void 158984d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 159084d38ac9SBenny Halevy { 15914beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1592792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1593792c95ddSJ. Bruce Fields 15940a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 15950a880a28STrond Myklebust 15964beb345bSTrond Myklebust /* Mark the client as expired! */ 15974beb345bSTrond Myklebust clp->cl_time = 0; 15984beb345bSTrond Myklebust /* Make it invisible */ 15994beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 16004beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 16014beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 16024beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 16034beb345bSTrond Myklebust else 16044beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 16054beb345bSTrond Myklebust } 16064beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 16074c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1608792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1609792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 16104c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 161184d38ac9SBenny Halevy } 161284d38ac9SBenny Halevy 16131da177e4SLinus Torvalds static void 16144beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 16154beb345bSTrond Myklebust { 16164beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 16174beb345bSTrond Myklebust 16184beb345bSTrond Myklebust spin_lock(&nn->client_lock); 16194beb345bSTrond Myklebust unhash_client_locked(clp); 16204beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 16214beb345bSTrond Myklebust } 16224beb345bSTrond Myklebust 162397403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 162497403d95SJeff Layton { 162597403d95SJeff Layton if (atomic_read(&clp->cl_refcount)) 162697403d95SJeff Layton return nfserr_jukebox; 162797403d95SJeff Layton unhash_client_locked(clp); 162897403d95SJeff Layton return nfs_ok; 162997403d95SJeff Layton } 163097403d95SJeff Layton 16314beb345bSTrond Myklebust static void 16324beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 16331da177e4SLinus Torvalds { 1634fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 16351da177e4SLinus Torvalds struct nfs4_delegation *dp; 16361da177e4SLinus Torvalds struct list_head reaplist; 16371da177e4SLinus Torvalds 16381da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 1639cdc97505SBenny Halevy spin_lock(&state_lock); 1640ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 1641ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 164242690676SJeff Layton unhash_delegation_locked(dp); 164342690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 16441da177e4SLinus Torvalds } 1645cdc97505SBenny Halevy spin_unlock(&state_lock); 16461da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 16471da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 164842690676SJeff Layton list_del_init(&dp->dl_recall_lru); 1649afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 16506011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 16511da177e4SLinus Torvalds } 16522d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 1653956c4feeSBenny Halevy dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 16542d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 16556011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 1656956c4feeSBenny Halevy } 1657ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 1658fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1659b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 1660fe0750e5SJ. Bruce Fields release_openowner(oo); 16611da177e4SLinus Torvalds } 16626ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 16632bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 16642bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1665b12a05cbSJ. Bruce Fields free_client(clp); 16661da177e4SLinus Torvalds } 16671da177e4SLinus Torvalds 16684beb345bSTrond Myklebust static void 16694beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 16704beb345bSTrond Myklebust { 16714beb345bSTrond Myklebust unhash_client(clp); 16724beb345bSTrond Myklebust __destroy_client(clp); 16734beb345bSTrond Myklebust } 16744beb345bSTrond Myklebust 16750d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 16760d22f68fSJ. Bruce Fields { 16774beb345bSTrond Myklebust unhash_client(clp); 16780d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 16794beb345bSTrond Myklebust __destroy_client(clp); 16800d22f68fSJ. Bruce Fields } 16810d22f68fSJ. Bruce Fields 168235bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 168335bba9a3SJ. Bruce Fields { 168435bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 168535bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 16861da177e4SLinus Torvalds } 16871da177e4SLinus Torvalds 168835bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 168935bba9a3SJ. Bruce Fields { 16901da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 16911da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 16921da177e4SLinus Torvalds } 16931da177e4SLinus Torvalds 169403a4e1f6SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 169535bba9a3SJ. Bruce Fields { 169603a4e1f6SJ. Bruce Fields if (source->cr_principal) { 169703a4e1f6SJ. Bruce Fields target->cr_principal = 169803a4e1f6SJ. Bruce Fields kstrdup(source->cr_principal, GFP_KERNEL); 169903a4e1f6SJ. Bruce Fields if (target->cr_principal == NULL) 170003a4e1f6SJ. Bruce Fields return -ENOMEM; 170103a4e1f6SJ. Bruce Fields } else 170203a4e1f6SJ. Bruce Fields target->cr_principal = NULL; 1703d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 17041da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 17051da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 17061da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 17071da177e4SLinus Torvalds get_group_info(target->cr_group_info); 17080dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 17090dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 17100dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 171103a4e1f6SJ. Bruce Fields return 0; 17121da177e4SLinus Torvalds } 17131da177e4SLinus Torvalds 1714ac55fdc4SJeff Layton static long long 1715ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 1716ac55fdc4SJeff Layton { 1717ac55fdc4SJeff Layton long long res; 1718ac55fdc4SJeff Layton 1719ac55fdc4SJeff Layton res = o1->len - o2->len; 1720ac55fdc4SJeff Layton if (res) 1721ac55fdc4SJeff Layton return res; 1722ac55fdc4SJeff Layton return (long long)memcmp(o1->data, o2->data, o1->len); 1723ac55fdc4SJeff Layton } 1724ac55fdc4SJeff Layton 172535bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 1726599e0a22SJ. Bruce Fields { 1727a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 17281da177e4SLinus Torvalds } 17291da177e4SLinus Torvalds 17301da177e4SLinus Torvalds static int 1731599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 1732599e0a22SJ. Bruce Fields { 1733599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds 17361da177e4SLinus Torvalds static int 1737599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 1738599e0a22SJ. Bruce Fields { 1739599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 17401da177e4SLinus Torvalds } 17411da177e4SLinus Torvalds 17428fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 17438fbba96eSJ. Bruce Fields { 17448fbba96eSJ. Bruce Fields int i; 17458fbba96eSJ. Bruce Fields 17468fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 17478fbba96eSJ. Bruce Fields return false; 17488fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 17496fab8779SEric W. Biederman if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i))) 17508fbba96eSJ. Bruce Fields return false; 17518fbba96eSJ. Bruce Fields return true; 17528fbba96eSJ. Bruce Fields } 17538fbba96eSJ. Bruce Fields 175468eb3508SJ. Bruce Fields /* 175568eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 175668eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 175768eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 175868eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 175968eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 176068eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 176168eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 176268eb3508SJ. Bruce Fields */ 176368eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 176468eb3508SJ. Bruce Fields { 176568eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 176668eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 176768eb3508SJ. Bruce Fields } 176868eb3508SJ. Bruce Fields 176968eb3508SJ. Bruce Fields 17705559b50aSVivek Trivedi static bool 1771599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 1772599e0a22SJ. Bruce Fields { 177368eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 17746fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 17756fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 17768fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 17778fbba96eSJ. Bruce Fields return false; 17788fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 17798fbba96eSJ. Bruce Fields return true; 17808fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 17818fbba96eSJ. Bruce Fields return false; 17825559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 17831da177e4SLinus Torvalds } 17841da177e4SLinus Torvalds 178557266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 178657266a6eSJ. Bruce Fields { 178757266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 178857266a6eSJ. Bruce Fields u32 service; 178957266a6eSJ. Bruce Fields 1790c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 1791c4720591SJ. Bruce Fields return false; 179257266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 179357266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 179457266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 179557266a6eSJ. Bruce Fields } 179657266a6eSJ. Bruce Fields 179757266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 179857266a6eSJ. Bruce Fields { 179957266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 180057266a6eSJ. Bruce Fields 180157266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 180257266a6eSJ. Bruce Fields return true; 180357266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 180457266a6eSJ. Bruce Fields return false; 180557266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 180657266a6eSJ. Bruce Fields return false; 180757266a6eSJ. Bruce Fields if (!cr->cr_principal) 180857266a6eSJ. Bruce Fields return false; 180957266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 181057266a6eSJ. Bruce Fields } 181157266a6eSJ. Bruce Fields 1812294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 1813deda2faaSJ. Bruce Fields { 1814ab4684d1SChuck Lever __be32 verf[2]; 18151da177e4SLinus Torvalds 1816f419992cSJeff Layton /* 1817f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 1818f419992cSJeff Layton * __force to keep sparse happy 1819f419992cSJeff Layton */ 1820f419992cSJeff Layton verf[0] = (__force __be32)get_seconds(); 1821294ac32eSJeff Layton verf[1] = (__force __be32)nn->clientid_counter; 1822ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 18231da177e4SLinus Torvalds } 18241da177e4SLinus Torvalds 1825294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 1826294ac32eSJeff Layton { 1827294ac32eSJeff Layton clp->cl_clientid.cl_boot = nn->boot_time; 1828294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 1829294ac32eSJeff Layton gen_confirm(clp, nn); 1830294ac32eSJeff Layton } 1831294ac32eSJeff Layton 18324770d722SJeff Layton static struct nfs4_stid * 18334770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 18344581d140SJ. Bruce Fields { 18353abdb607SJ. Bruce Fields struct nfs4_stid *ret; 18363abdb607SJ. Bruce Fields 18373abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 18383abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 18393abdb607SJ. Bruce Fields return NULL; 18403abdb607SJ. Bruce Fields return ret; 18414581d140SJ. Bruce Fields } 18424d71ab87SJ. Bruce Fields 18434770d722SJeff Layton static struct nfs4_stid * 18444770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 1845f459e453SJ. Bruce Fields { 1846f459e453SJ. Bruce Fields struct nfs4_stid *s; 1847f459e453SJ. Bruce Fields 18484770d722SJeff Layton spin_lock(&cl->cl_lock); 18494770d722SJeff Layton s = find_stateid_locked(cl, t); 18502d3f9668STrond Myklebust if (s != NULL) { 18512d3f9668STrond Myklebust if (typemask & s->sc_type) 18522d3f9668STrond Myklebust atomic_inc(&s->sc_count); 18532d3f9668STrond Myklebust else 18544770d722SJeff Layton s = NULL; 18552d3f9668STrond Myklebust } 18564770d722SJeff Layton spin_unlock(&cl->cl_lock); 18574d71ab87SJ. Bruce Fields return s; 18584581d140SJ. Bruce Fields } 18594581d140SJ. Bruce Fields 18602216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 1861b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 1862b09333c4SRicardo Labiaga { 1863b09333c4SRicardo Labiaga struct nfs4_client *clp; 1864b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 186503a4e1f6SJ. Bruce Fields int ret; 1866c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 1867b09333c4SRicardo Labiaga 1868b09333c4SRicardo Labiaga clp = alloc_client(name); 1869b09333c4SRicardo Labiaga if (clp == NULL) 1870b09333c4SRicardo Labiaga return NULL; 1871b09333c4SRicardo Labiaga 187203a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 187303a4e1f6SJ. Bruce Fields if (ret) { 1874b09333c4SRicardo Labiaga free_client(clp); 1875b09333c4SRicardo Labiaga return NULL; 1876b09333c4SRicardo Labiaga } 187702e1215fSJeff Layton INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null); 187807cd4909SBenny Halevy clp->cl_time = get_seconds(); 1879b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 1880b09333c4SRicardo Labiaga copy_verf(clp, verf); 1881b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 1882edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 1883c212cecfSStanislav Kinsbursky clp->net = net; 1884b09333c4SRicardo Labiaga return clp; 1885b09333c4SRicardo Labiaga } 1886b09333c4SRicardo Labiaga 1887fd39ca9aSNeilBrown static void 1888ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 1889ac55fdc4SJeff Layton { 1890ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 1891ac55fdc4SJeff Layton struct nfs4_client *clp; 1892ac55fdc4SJeff Layton 1893ac55fdc4SJeff Layton while (*new) { 1894ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 1895ac55fdc4SJeff Layton parent = *new; 1896ac55fdc4SJeff Layton 1897ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 1898ac55fdc4SJeff Layton new = &((*new)->rb_left); 1899ac55fdc4SJeff Layton else 1900ac55fdc4SJeff Layton new = &((*new)->rb_right); 1901ac55fdc4SJeff Layton } 1902ac55fdc4SJeff Layton 1903ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 1904ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 1905ac55fdc4SJeff Layton } 1906ac55fdc4SJeff Layton 1907ac55fdc4SJeff Layton static struct nfs4_client * 1908ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 1909ac55fdc4SJeff Layton { 1910ac55fdc4SJeff Layton long long cmp; 1911ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 1912ac55fdc4SJeff Layton struct nfs4_client *clp; 1913ac55fdc4SJeff Layton 1914ac55fdc4SJeff Layton while (node) { 1915ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 1916ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 1917ac55fdc4SJeff Layton if (cmp > 0) 1918ac55fdc4SJeff Layton node = node->rb_left; 1919ac55fdc4SJeff Layton else if (cmp < 0) 1920ac55fdc4SJeff Layton node = node->rb_right; 1921ac55fdc4SJeff Layton else 1922ac55fdc4SJeff Layton return clp; 1923ac55fdc4SJeff Layton } 1924ac55fdc4SJeff Layton return NULL; 1925ac55fdc4SJeff Layton } 1926ac55fdc4SJeff Layton 1927ac55fdc4SJeff Layton static void 1928ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 19291da177e4SLinus Torvalds { 19301da177e4SLinus Torvalds unsigned int idhashval; 19310a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 19321da177e4SLinus Torvalds 19330a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 19340a880a28STrond Myklebust 1935ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 1936a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 19371da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 19380a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 19393dbacee6STrond Myklebust renew_client_locked(clp); 19401da177e4SLinus Torvalds } 19411da177e4SLinus Torvalds 1942fd39ca9aSNeilBrown static void 19431da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 19441da177e4SLinus Torvalds { 19451da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 19468daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 19471da177e4SLinus Torvalds 19480a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 19490a880a28STrond Myklebust 19501da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 19518daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 1952a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 1953382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 1954ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 19553dbacee6STrond Myklebust renew_client_locked(clp); 19561da177e4SLinus Torvalds } 19571da177e4SLinus Torvalds 19581da177e4SLinus Torvalds static struct nfs4_client * 1959bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 19601da177e4SLinus Torvalds { 19611da177e4SLinus Torvalds struct nfs4_client *clp; 19621da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 19631da177e4SLinus Torvalds 1964bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 1965a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 1966d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 1967d15c077eSJ. Bruce Fields return NULL; 19683dbacee6STrond Myklebust renew_client_locked(clp); 19691da177e4SLinus Torvalds return clp; 19701da177e4SLinus Torvalds } 1971a50d2ad1SJ. Bruce Fields } 19721da177e4SLinus Torvalds return NULL; 19731da177e4SLinus Torvalds } 19741da177e4SLinus Torvalds 19751da177e4SLinus Torvalds static struct nfs4_client * 1976bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 1977bfa85e83SJ. Bruce Fields { 1978bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 1979bfa85e83SJ. Bruce Fields 19800a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1981bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 1982bfa85e83SJ. Bruce Fields } 1983bfa85e83SJ. Bruce Fields 1984bfa85e83SJ. Bruce Fields static struct nfs4_client * 19850a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 19861da177e4SLinus Torvalds { 1987bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 19881da177e4SLinus Torvalds 19890a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1990bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 19911da177e4SLinus Torvalds } 19921da177e4SLinus Torvalds 19936e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 1994a1bcecd2SAndy Adamson { 19956e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 1996a1bcecd2SAndy Adamson } 1997a1bcecd2SAndy Adamson 199828ce6054SNeilBrown static struct nfs4_client * 1999382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 200028ce6054SNeilBrown { 20010a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2002382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 200328ce6054SNeilBrown } 200428ce6054SNeilBrown 200528ce6054SNeilBrown static struct nfs4_client * 2006a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 200728ce6054SNeilBrown { 20080a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2009a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 201028ce6054SNeilBrown } 201128ce6054SNeilBrown 2012fd39ca9aSNeilBrown static void 20136f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 20141da177e4SLinus Torvalds { 201507263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 20166f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 20176f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 20187077ecbaSJeff Layton unsigned short expected_family; 20191da177e4SLinus Torvalds 20207077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 20217077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 20227077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 20237077ecbaSJeff Layton expected_family = AF_INET; 20247077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 20257077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 20267077ecbaSJeff Layton expected_family = AF_INET6; 20277077ecbaSJeff Layton else 20281da177e4SLinus Torvalds goto out_err; 20291da177e4SLinus Torvalds 2030c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2031aa9a4ec7SJeff Layton se->se_callback_addr_len, 203207263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 203307263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2034aa9a4ec7SJeff Layton 203507263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 20361da177e4SLinus Torvalds goto out_err; 2037aa9a4ec7SJeff Layton 203807263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 203907263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2040fbf4665fSJeff Layton 204107263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 204207263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2043849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 20441da177e4SLinus Torvalds return; 20451da177e4SLinus Torvalds out_err: 204607263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 204707263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 2048849823c5SNeil Brown dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " 20491da177e4SLinus Torvalds "will not receive delegations\n", 20501da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 20511da177e4SLinus Torvalds 20521da177e4SLinus Torvalds return; 20531da177e4SLinus Torvalds } 20541da177e4SLinus Torvalds 2055074fe897SAndy Adamson /* 2056067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2057074fe897SAndy Adamson */ 2058b607664eSTrond Myklebust static void 2059074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2060074fe897SAndy Adamson { 2061f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2062557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2063557ce264SAndy Adamson unsigned int base; 2064074fe897SAndy Adamson 2065557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2066074fe897SAndy Adamson 2067557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2068557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 2069bf864a31SAndy Adamson 2070bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2071bf864a31SAndy Adamson if (nfsd4_not_cached(resp)) { 2072557ce264SAndy Adamson slot->sl_datalen = 0; 2073bf864a31SAndy Adamson return; 2074bf864a31SAndy Adamson } 2075f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2076f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2077f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2078557ce264SAndy Adamson WARN("%s: sessions DRC could not cache compound\n", __func__); 2079557ce264SAndy Adamson return; 2080074fe897SAndy Adamson } 2081074fe897SAndy Adamson 2082074fe897SAndy Adamson /* 2083abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2084abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2085abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2086abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2087abfabf8cSAndy Adamson * 2088074fe897SAndy Adamson */ 2089abfabf8cSAndy Adamson static __be32 2090abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2091abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2092074fe897SAndy Adamson { 2093abfabf8cSAndy Adamson struct nfsd4_op *op; 2094abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2095074fe897SAndy Adamson 2096abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2097abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2098abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2099abfabf8cSAndy Adamson 2100abfabf8cSAndy Adamson /* Return nfserr_retry_uncached_rep in next operation. */ 210173e79482SJ. Bruce Fields if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { 2102abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2103abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2104abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2105074fe897SAndy Adamson } 2106abfabf8cSAndy Adamson return op->status; 2107074fe897SAndy Adamson } 2108074fe897SAndy Adamson 2109074fe897SAndy Adamson /* 2110557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2111557ce264SAndy Adamson * session values. 2112074fe897SAndy Adamson */ 21133ca2eb98SJ. Bruce Fields static __be32 2114bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2115bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2116074fe897SAndy Adamson { 2117557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2118f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2119f5236013SJ. Bruce Fields __be32 *p; 2120074fe897SAndy Adamson __be32 status; 2121074fe897SAndy Adamson 2122557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2123074fe897SAndy Adamson 2124abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 21250da7b19cSJ. Bruce Fields if (status) 2126abfabf8cSAndy Adamson return status; 2127074fe897SAndy Adamson 2128f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2129f5236013SJ. Bruce Fields if (!p) { 2130f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2131f5236013SJ. Bruce Fields return nfserr_serverfault; 2132f5236013SJ. Bruce Fields } 2133f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2134f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2135074fe897SAndy Adamson 2136557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2137f5236013SJ. Bruce Fields return slot->sl_status; 2138074fe897SAndy Adamson } 2139074fe897SAndy Adamson 21400733d213SAndy Adamson /* 21410733d213SAndy Adamson * Set the exchange_id flags returned by the server. 21420733d213SAndy Adamson */ 21430733d213SAndy Adamson static void 21440733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 21450733d213SAndy Adamson { 21460733d213SAndy Adamson /* pNFS is not supported */ 21470733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 21480733d213SAndy Adamson 21490733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 21500733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 21510733d213SAndy Adamson 21520733d213SAndy Adamson /* set the wire flags to return to client. */ 21530733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 21540733d213SAndy Adamson } 21550733d213SAndy Adamson 2156631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 2157631fc9eaSJ. Bruce Fields { 2158631fc9eaSJ. Bruce Fields /* 2159631fc9eaSJ. Bruce Fields * Note clp->cl_openowners check isn't quite right: there's no 2160631fc9eaSJ. Bruce Fields * need to count owners without stateid's. 2161631fc9eaSJ. Bruce Fields * 2162631fc9eaSJ. Bruce Fields * Also note we should probably be using this in 4.0 case too. 2163631fc9eaSJ. Bruce Fields */ 21646eccece9SJ. Bruce Fields return !list_empty(&clp->cl_openowners) 21656eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 21666eccece9SJ. Bruce Fields || !list_empty(&clp->cl_sessions); 2167631fc9eaSJ. Bruce Fields } 2168631fc9eaSJ. Bruce Fields 2169b37ad28bSAl Viro __be32 2170069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp, 2171069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2172069b6ad4SAndy Adamson struct nfsd4_exchange_id *exid) 2173069b6ad4SAndy Adamson { 21743dbacee6STrond Myklebust struct nfs4_client *conf, *new; 21753dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 217657b7b43bSJ. Bruce Fields __be32 status; 2177363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 21780733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 2179363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 218083e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 2181c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 21820733d213SAndy Adamson 2183363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 21840733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 2185363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 21860733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 2187363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 21880733d213SAndy Adamson 2189a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 21900733d213SAndy Adamson return nfserr_inval; 21910733d213SAndy Adamson 21920733d213SAndy Adamson switch (exid->spa_how) { 219357266a6eSJ. Bruce Fields case SP4_MACH_CRED: 219457266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 219557266a6eSJ. Bruce Fields return nfserr_inval; 21960733d213SAndy Adamson case SP4_NONE: 21970733d213SAndy Adamson break; 2198063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 2199063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 22000733d213SAndy Adamson case SP4_SSV: 2201dd30333cSJ. Bruce Fields return nfserr_encr_alg_unsupp; 22020733d213SAndy Adamson } 22030733d213SAndy Adamson 22045cc40fd7STrond Myklebust new = create_client(exid->clname, rqstp, &verf); 22055cc40fd7STrond Myklebust if (new == NULL) 22065cc40fd7STrond Myklebust return nfserr_jukebox; 22075cc40fd7STrond Myklebust 22082dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 22093dbacee6STrond Myklebust spin_lock(&nn->client_lock); 2210382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 22110733d213SAndy Adamson if (conf) { 221283e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 221383e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 221483e08fd4SJ. Bruce Fields 2215136e658dSJ. Bruce Fields if (update) { 2216136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 22172dbb269dSJ. Bruce Fields status = nfserr_inval; 2218e203d506SJ. Bruce Fields goto out; 2219e203d506SJ. Bruce Fields } 222057266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) { 222157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 222257266a6eSJ. Bruce Fields goto out; 222357266a6eSJ. Bruce Fields } 22242dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 22250733d213SAndy Adamson status = nfserr_perm; 22260733d213SAndy Adamson goto out; 22270733d213SAndy Adamson } 22282dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 22290733d213SAndy Adamson status = nfserr_not_same; 22300733d213SAndy Adamson goto out; 22310733d213SAndy Adamson } 2232136e658dSJ. Bruce Fields /* case 6 */ 22330733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 22340733d213SAndy Adamson goto out_copy; 22356ddbbbfeSMike Sager } 2236136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 2237631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 2238136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 2239136e658dSJ. Bruce Fields goto out; 2240136e658dSJ. Bruce Fields } 2241b9831b59SJ. Bruce Fields goto out_new; 2242631fc9eaSJ. Bruce Fields } 2243136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 22440f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 2245136e658dSJ. Bruce Fields goto out_copy; 2246136e658dSJ. Bruce Fields } 22472dbb269dSJ. Bruce Fields /* case 5, client reboot */ 22483dbacee6STrond Myklebust conf = NULL; 22490733d213SAndy Adamson goto out_new; 22500733d213SAndy Adamson } 22516ddbbbfeSMike Sager 22522dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 22530733d213SAndy Adamson status = nfserr_noent; 22540733d213SAndy Adamson goto out; 22550733d213SAndy Adamson } 22560733d213SAndy Adamson 2257a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 22582dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 22593dbacee6STrond Myklebust unhash_client_locked(unconf); 22600733d213SAndy Adamson 22612dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 22620733d213SAndy Adamson out_new: 2263fd699b8aSJeff Layton if (conf) { 2264fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 2265fd699b8aSJeff Layton if (status) 2266fd699b8aSJeff Layton goto out; 2267fd699b8aSJeff Layton } 22684f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 226957266a6eSJ. Bruce Fields new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); 22700733d213SAndy Adamson 2271c212cecfSStanislav Kinsbursky gen_clid(new, nn); 2272ac55fdc4SJeff Layton add_to_unconfirmed(new); 22733dbacee6STrond Myklebust swap(new, conf); 22740733d213SAndy Adamson out_copy: 22755cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 22765cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 22770733d213SAndy Adamson 22785cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 22795cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 22800733d213SAndy Adamson 22810733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 22825cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 22830733d213SAndy Adamson status = nfs_ok; 22840733d213SAndy Adamson 22850733d213SAndy Adamson out: 22863dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 22875cc40fd7STrond Myklebust if (new) 22883dbacee6STrond Myklebust expire_client(new); 22893dbacee6STrond Myklebust if (unconf) 22903dbacee6STrond Myklebust expire_client(unconf); 22910733d213SAndy Adamson return status; 2292069b6ad4SAndy Adamson } 2293069b6ad4SAndy Adamson 229457b7b43bSJ. Bruce Fields static __be32 229588e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 2296b85d4c01SBenny Halevy { 229788e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 229888e588d5SAndy Adamson slot_seqid); 2299b85d4c01SBenny Halevy 2300b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 230188e588d5SAndy Adamson if (slot_inuse) { 230288e588d5SAndy Adamson if (seqid == slot_seqid) 2303b85d4c01SBenny Halevy return nfserr_jukebox; 2304b85d4c01SBenny Halevy else 2305b85d4c01SBenny Halevy return nfserr_seq_misordered; 2306b85d4c01SBenny Halevy } 2307f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 230888e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 2309b85d4c01SBenny Halevy return nfs_ok; 231088e588d5SAndy Adamson if (seqid == slot_seqid) 2311b85d4c01SBenny Halevy return nfserr_replay_cache; 2312b85d4c01SBenny Halevy return nfserr_seq_misordered; 2313b85d4c01SBenny Halevy } 2314b85d4c01SBenny Halevy 231549557cc7SAndy Adamson /* 231649557cc7SAndy Adamson * Cache the create session result into the create session single DRC 231749557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 231849557cc7SAndy Adamson * Do this for solo or embedded create session operations. 231949557cc7SAndy Adamson */ 232049557cc7SAndy Adamson static void 232149557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 232257b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 232349557cc7SAndy Adamson { 232449557cc7SAndy Adamson slot->sl_status = nfserr; 232549557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 232649557cc7SAndy Adamson } 232749557cc7SAndy Adamson 232849557cc7SAndy Adamson static __be32 232949557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 233049557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 233149557cc7SAndy Adamson { 233249557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 233349557cc7SAndy Adamson return slot->sl_status; 233449557cc7SAndy Adamson } 233549557cc7SAndy Adamson 23361b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 23371b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 23381b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 23391b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 23401b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 23411b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 23421b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 23431b74c25bSMi Jinlong 23441b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 23451b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 23461b74c25bSMi Jinlong 1 + /* status */ \ 23471b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 23481b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 23491b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 23501b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 23511b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 23521b74c25bSMi Jinlong 235355c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 23541b74c25bSMi Jinlong { 235555c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 235655c760cfSJ. Bruce Fields 2357373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 2358373cd409SJ. Bruce Fields return nfserr_toosmall; 2359373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 2360373cd409SJ. Bruce Fields return nfserr_toosmall; 236155c760cfSJ. Bruce Fields ca->headerpadsz = 0; 236255c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 236355c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 236455c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 236555c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 236655c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 236755c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 236855c760cfSJ. Bruce Fields /* 236955c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 237055c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 237155c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 237255c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 237355c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 237455c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 237555c760cfSJ. Bruce Fields */ 237655c760cfSJ. Bruce Fields ca->maxreqs = nfsd4_get_drc_mem(ca); 237755c760cfSJ. Bruce Fields if (!ca->maxreqs) 237855c760cfSJ. Bruce Fields return nfserr_jukebox; 237955c760cfSJ. Bruce Fields 2380373cd409SJ. Bruce Fields return nfs_ok; 23811b74c25bSMi Jinlong } 23821b74c25bSMi Jinlong 23838a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 23848a891633SKinglong Mee RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32)) 23858a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 23868a891633SKinglong Mee RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32)) 23878a891633SKinglong Mee 238806b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 238906b332a5SJ. Bruce Fields { 239006b332a5SJ. Bruce Fields ca->headerpadsz = 0; 239106b332a5SJ. Bruce Fields 239206b332a5SJ. Bruce Fields /* 239306b332a5SJ. Bruce Fields * These RPC_MAX_HEADER macros are overkill, especially since we 239406b332a5SJ. Bruce Fields * don't even do gss on the backchannel yet. But this is still 239506b332a5SJ. Bruce Fields * less than 1k. Tighten up this estimate in the unlikely event 239606b332a5SJ. Bruce Fields * it turns out to be a problem for some client: 239706b332a5SJ. Bruce Fields */ 23988a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 239906b332a5SJ. Bruce Fields return nfserr_toosmall; 24008a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 240106b332a5SJ. Bruce Fields return nfserr_toosmall; 240206b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 240306b332a5SJ. Bruce Fields if (ca->maxops < 2) 240406b332a5SJ. Bruce Fields return nfserr_toosmall; 240506b332a5SJ. Bruce Fields 240606b332a5SJ. Bruce Fields return nfs_ok; 2407069b6ad4SAndy Adamson } 2408069b6ad4SAndy Adamson 2409b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 2410b78724b7SJ. Bruce Fields { 2411b78724b7SJ. Bruce Fields switch (cbs->flavor) { 2412b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 2413b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 2414b78724b7SJ. Bruce Fields return nfs_ok; 2415b78724b7SJ. Bruce Fields default: 2416b78724b7SJ. Bruce Fields /* 2417b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 2418b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 2419b78724b7SJ. Bruce Fields * GSS. 2420b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 2421b78724b7SJ. Bruce Fields * client might think it can already handle: 2422b78724b7SJ. Bruce Fields */ 2423b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 2424b78724b7SJ. Bruce Fields } 2425b78724b7SJ. Bruce Fields } 2426b78724b7SJ. Bruce Fields 2427069b6ad4SAndy Adamson __be32 2428069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 2429069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2430069b6ad4SAndy Adamson struct nfsd4_create_session *cr_ses) 2431069b6ad4SAndy Adamson { 2432363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 2433ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 2434d20c11d8SJeff Layton struct nfs4_client *old = NULL; 2435ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 243681f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 243749557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 243857b7b43bSJ. Bruce Fields __be32 status = 0; 24398daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2440ec6b5d7bSAndy Adamson 2441a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 2442a62573dcSMi Jinlong return nfserr_inval; 2443b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 2444b78724b7SJ. Bruce Fields if (status) 2445b78724b7SJ. Bruce Fields return status; 244655c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 2447373cd409SJ. Bruce Fields if (status) 2448373cd409SJ. Bruce Fields return status; 244906b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 245006b332a5SJ. Bruce Fields if (status) 2451f403e450SKinglong Mee goto out_release_drc_mem; 245281f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 245360810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 245455c760cfSJ. Bruce Fields if (!new) 245555c760cfSJ. Bruce Fields goto out_release_drc_mem; 245681f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 245781f0b2a4SJ. Bruce Fields if (!conn) 245881f0b2a4SJ. Bruce Fields goto out_free_session; 2459a62573dcSMi Jinlong 2460d20c11d8SJeff Layton spin_lock(&nn->client_lock); 24610a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 24628daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 246378389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2464ec6b5d7bSAndy Adamson 2465ec6b5d7bSAndy Adamson if (conf) { 246657266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 246757266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) 246857266a6eSJ. Bruce Fields goto out_free_conn; 246949557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 247049557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 247138eb76a5SAndy Adamson if (status == nfserr_replay_cache) { 247249557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 247381f0b2a4SJ. Bruce Fields goto out_free_conn; 247449557cc7SAndy Adamson } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { 2475ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 247681f0b2a4SJ. Bruce Fields goto out_free_conn; 2477ec6b5d7bSAndy Adamson } 2478ec6b5d7bSAndy Adamson } else if (unconf) { 2479ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 2480363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 2481ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 248281f0b2a4SJ. Bruce Fields goto out_free_conn; 2483ec6b5d7bSAndy Adamson } 248457266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 248557266a6eSJ. Bruce Fields if (!mach_creds_match(unconf, rqstp)) 248657266a6eSJ. Bruce Fields goto out_free_conn; 248749557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 248849557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 248938eb76a5SAndy Adamson if (status) { 249038eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 2491ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 249281f0b2a4SJ. Bruce Fields goto out_free_conn; 2493ec6b5d7bSAndy Adamson } 2494382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 2495221a6876SJ. Bruce Fields if (old) { 2496d20c11d8SJeff Layton status = mark_client_expired_locked(old); 24977abea1e8SJeff Layton if (status) { 24987abea1e8SJeff Layton old = NULL; 2499221a6876SJ. Bruce Fields goto out_free_conn; 2500221a6876SJ. Bruce Fields } 25017abea1e8SJeff Layton } 25028f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 2503ec6b5d7bSAndy Adamson conf = unconf; 2504ec6b5d7bSAndy Adamson } else { 2505ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 250681f0b2a4SJ. Bruce Fields goto out_free_conn; 2507ec6b5d7bSAndy Adamson } 250881f0b2a4SJ. Bruce Fields status = nfs_ok; 25098323c3b2SJ. Bruce Fields /* 2510408b79bcSJ. Bruce Fields * We do not support RDMA or persistent sessions 2511408b79bcSJ. Bruce Fields */ 2512408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 2513408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 2514408b79bcSJ. Bruce Fields 251581f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 2516d20c11d8SJeff Layton nfsd4_get_session_locked(new); 251781f0b2a4SJ. Bruce Fields 2518ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 2519ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 252086c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 252149557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 2522ec6b5d7bSAndy Adamson 2523d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 252449557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 2525d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 2526d20c11d8SJeff Layton /* init connection and backchannel */ 2527d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 2528d20c11d8SJeff Layton nfsd4_put_session(new); 2529d20c11d8SJeff Layton if (old) 2530d20c11d8SJeff Layton expire_client(old); 2531ec6b5d7bSAndy Adamson return status; 253281f0b2a4SJ. Bruce Fields out_free_conn: 2533d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 253481f0b2a4SJ. Bruce Fields free_conn(conn); 2535d20c11d8SJeff Layton if (old) 2536d20c11d8SJeff Layton expire_client(old); 253781f0b2a4SJ. Bruce Fields out_free_session: 253881f0b2a4SJ. Bruce Fields __free_session(new); 253955c760cfSJ. Bruce Fields out_release_drc_mem: 254055c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 25411ca50792SJ. Bruce Fields return status; 2542069b6ad4SAndy Adamson } 2543069b6ad4SAndy Adamson 25441d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 25451d1bc8f2SJ. Bruce Fields { 25461d1bc8f2SJ. Bruce Fields switch (*dir) { 25471d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 25481d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 25491d1bc8f2SJ. Bruce Fields return nfs_ok; 25501d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 25511d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 25521d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 25531d1bc8f2SJ. Bruce Fields return nfs_ok; 25541d1bc8f2SJ. Bruce Fields }; 25551d1bc8f2SJ. Bruce Fields return nfserr_inval; 25561d1bc8f2SJ. Bruce Fields } 25571d1bc8f2SJ. Bruce Fields 2558cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) 2559cb73a9f4SJ. Bruce Fields { 2560cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 2561c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2562b78724b7SJ. Bruce Fields __be32 status; 2563cb73a9f4SJ. Bruce Fields 2564b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 2565b78724b7SJ. Bruce Fields if (status) 2566b78724b7SJ. Bruce Fields return status; 2567c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2568cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 2569cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 2570c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2571cb73a9f4SJ. Bruce Fields 2572cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 2573cb73a9f4SJ. Bruce Fields 2574cb73a9f4SJ. Bruce Fields return nfs_ok; 2575cb73a9f4SJ. Bruce Fields } 2576cb73a9f4SJ. Bruce Fields 25771d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 25781d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 25791d1bc8f2SJ. Bruce Fields struct nfsd4_bind_conn_to_session *bcts) 25801d1bc8f2SJ. Bruce Fields { 25811d1bc8f2SJ. Bruce Fields __be32 status; 25823ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 25834f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 2584d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2585d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 25861d1bc8f2SJ. Bruce Fields 25871d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 25881d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 2589c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2590d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 2591c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 25924f6e6c17SJ. Bruce Fields if (!session) 2593d4e19e70STrond Myklebust goto out_no_session; 259457266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 259557266a6eSJ. Bruce Fields if (!mach_creds_match(session->se_client, rqstp)) 259657266a6eSJ. Bruce Fields goto out; 25971d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 25983ba63671SJ. Bruce Fields if (status) 25994f6e6c17SJ. Bruce Fields goto out; 26003ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 26014f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 26023ba63671SJ. Bruce Fields if (!conn) 26034f6e6c17SJ. Bruce Fields goto out; 26044f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 26054f6e6c17SJ. Bruce Fields status = nfs_ok; 26064f6e6c17SJ. Bruce Fields out: 2607d4e19e70STrond Myklebust nfsd4_put_session(session); 2608d4e19e70STrond Myklebust out_no_session: 26094f6e6c17SJ. Bruce Fields return status; 26101d1bc8f2SJ. Bruce Fields } 26111d1bc8f2SJ. Bruce Fields 26125d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) 26135d4cec2fSJ. Bruce Fields { 26145d4cec2fSJ. Bruce Fields if (!session) 26155d4cec2fSJ. Bruce Fields return 0; 26165d4cec2fSJ. Bruce Fields return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); 26175d4cec2fSJ. Bruce Fields } 26185d4cec2fSJ. Bruce Fields 2619069b6ad4SAndy Adamson __be32 2620069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r, 2621069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2622069b6ad4SAndy Adamson struct nfsd4_destroy_session *sessionid) 2623069b6ad4SAndy Adamson { 2624e10e0cfcSBenny Halevy struct nfsd4_session *ses; 2625abcdff09SJ. Bruce Fields __be32 status; 2626f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 2627d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 2628d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2629e10e0cfcSBenny Halevy 2630abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 26315d4cec2fSJ. Bruce Fields if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { 263257716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 2633abcdff09SJ. Bruce Fields goto out; 2634f0f51f5cSJ. Bruce Fields ref_held_by_me++; 263557716355SJ. Bruce Fields } 2636e10e0cfcSBenny Halevy dump_sessionid(__func__, &sessionid->sessionid); 2637c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2638d4e19e70STrond Myklebust ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status); 2639abcdff09SJ. Bruce Fields if (!ses) 2640abcdff09SJ. Bruce Fields goto out_client_lock; 264157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 264257266a6eSJ. Bruce Fields if (!mach_creds_match(ses->se_client, r)) 2643d4e19e70STrond Myklebust goto out_put_session; 2644f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 264566b2b9b2SJ. Bruce Fields if (status) 2646f0f51f5cSJ. Bruce Fields goto out_put_session; 2647e10e0cfcSBenny Halevy unhash_session(ses); 2648c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2649e10e0cfcSBenny Halevy 265084f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 265119cf5c02SJ. Bruce Fields 2652c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2653e10e0cfcSBenny Halevy status = nfs_ok; 2654f0f51f5cSJ. Bruce Fields out_put_session: 2655d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 2656abcdff09SJ. Bruce Fields out_client_lock: 2657abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 2658e10e0cfcSBenny Halevy out: 2659e10e0cfcSBenny Halevy return status; 2660069b6ad4SAndy Adamson } 2661069b6ad4SAndy Adamson 2662a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 2663328ead28SJ. Bruce Fields { 2664328ead28SJ. Bruce Fields struct nfsd4_conn *c; 2665328ead28SJ. Bruce Fields 2666328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 2667a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 2668328ead28SJ. Bruce Fields return c; 2669328ead28SJ. Bruce Fields } 2670328ead28SJ. Bruce Fields } 2671328ead28SJ. Bruce Fields return NULL; 2672328ead28SJ. Bruce Fields } 2673328ead28SJ. Bruce Fields 267457266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 2675328ead28SJ. Bruce Fields { 2676328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 2677a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 267857266a6eSJ. Bruce Fields __be32 status = nfs_ok; 267921b75b01SJ. Bruce Fields int ret; 2680328ead28SJ. Bruce Fields 2681328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 2682a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 268357266a6eSJ. Bruce Fields if (c) 268457266a6eSJ. Bruce Fields goto out_free; 268557266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 268657266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 268757266a6eSJ. Bruce Fields goto out_free; 2688328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 2689328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 269021b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 269121b75b01SJ. Bruce Fields if (ret) 269221b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 269321b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 269457266a6eSJ. Bruce Fields return nfs_ok; 269557266a6eSJ. Bruce Fields out_free: 269657266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 269757266a6eSJ. Bruce Fields free_conn(new); 269857266a6eSJ. Bruce Fields return status; 2699328ead28SJ. Bruce Fields } 2700328ead28SJ. Bruce Fields 2701868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 2702868b89c3SMi Jinlong { 2703868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 2704868b89c3SMi Jinlong 2705868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 2706868b89c3SMi Jinlong } 2707868b89c3SMi Jinlong 2708ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 2709ae82a8d0SMi Jinlong struct nfsd4_session *session) 2710ae82a8d0SMi Jinlong { 2711ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 2712ae82a8d0SMi Jinlong 2713ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 2714ae82a8d0SMi Jinlong } 2715ae82a8d0SMi Jinlong 2716069b6ad4SAndy Adamson __be32 2717b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp, 2718069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2719069b6ad4SAndy Adamson struct nfsd4_sequence *seq) 2720069b6ad4SAndy Adamson { 2721f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 272247ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2723b85d4c01SBenny Halevy struct nfsd4_session *session; 2724221a6876SJ. Bruce Fields struct nfs4_client *clp; 2725b85d4c01SBenny Halevy struct nfsd4_slot *slot; 2726a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 272757b7b43bSJ. Bruce Fields __be32 status; 272847ee5298SJ. Bruce Fields int buflen; 2729d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2730d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2731b85d4c01SBenny Halevy 2732f9bb94c4SAndy Adamson if (resp->opcnt != 1) 2733f9bb94c4SAndy Adamson return nfserr_sequence_pos; 2734f9bb94c4SAndy Adamson 2735a663bdd8SJ. Bruce Fields /* 2736a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 2737a663bdd8SJ. Bruce Fields * below. 2738a663bdd8SJ. Bruce Fields */ 2739a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 2740a663bdd8SJ. Bruce Fields if (!conn) 2741a663bdd8SJ. Bruce Fields return nfserr_jukebox; 2742a663bdd8SJ. Bruce Fields 2743c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2744d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 2745b85d4c01SBenny Halevy if (!session) 2746221a6876SJ. Bruce Fields goto out_no_session; 2747221a6876SJ. Bruce Fields clp = session->se_client; 2748b85d4c01SBenny Halevy 2749868b89c3SMi Jinlong status = nfserr_too_many_ops; 2750868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 275166b2b9b2SJ. Bruce Fields goto out_put_session; 2752868b89c3SMi Jinlong 2753ae82a8d0SMi Jinlong status = nfserr_req_too_big; 2754ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 275566b2b9b2SJ. Bruce Fields goto out_put_session; 2756ae82a8d0SMi Jinlong 2757b85d4c01SBenny Halevy status = nfserr_badslot; 27586c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 275966b2b9b2SJ. Bruce Fields goto out_put_session; 2760b85d4c01SBenny Halevy 2761557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 2762b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 2763b85d4c01SBenny Halevy 2764a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 2765a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 2766a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 2767a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 2768a8dfdaebSAndy Adamson 276973e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 277073e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 2771b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 2772bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 2773bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 277466b2b9b2SJ. Bruce Fields goto out_put_session; 2775b85d4c01SBenny Halevy cstate->slot = slot; 2776b85d4c01SBenny Halevy cstate->session = session; 27774b24ca7dSJeff Layton cstate->clp = clp; 2778da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 2779557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 2780bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 2781da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 2782aaf84eb9SBenny Halevy goto out; 2783b85d4c01SBenny Halevy } 2784b85d4c01SBenny Halevy if (status) 278566b2b9b2SJ. Bruce Fields goto out_put_session; 2786b85d4c01SBenny Halevy 278757266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 2788a663bdd8SJ. Bruce Fields conn = NULL; 278957266a6eSJ. Bruce Fields if (status) 279057266a6eSJ. Bruce Fields goto out_put_session; 2791328ead28SJ. Bruce Fields 279247ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 279347ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 279447ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 279547ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 279647ee5298SJ. Bruce Fields nfserr_rep_too_big; 2797a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 279847ee5298SJ. Bruce Fields goto out_put_session; 279932aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 280047ee5298SJ. Bruce Fields 280147ee5298SJ. Bruce Fields status = nfs_ok; 2802b85d4c01SBenny Halevy /* Success! bump slot seqid */ 2803b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 2804bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 280573e79482SJ. Bruce Fields if (seq->cachethis) 280673e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 2807bf5c43c8SJ. Bruce Fields else 2808bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 2809b85d4c01SBenny Halevy 2810b85d4c01SBenny Halevy cstate->slot = slot; 2811b85d4c01SBenny Halevy cstate->session = session; 28124b24ca7dSJeff Layton cstate->clp = clp; 2813b85d4c01SBenny Halevy 2814b85d4c01SBenny Halevy out: 28155423732aSBenny Halevy switch (clp->cl_cb_state) { 28165423732aSBenny Halevy case NFSD4_CB_DOWN: 2817fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 28185423732aSBenny Halevy break; 28195423732aSBenny Halevy case NFSD4_CB_FAULT: 2820fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 28215423732aSBenny Halevy break; 2822fc0c3dd1SBenny Halevy default: 2823fc0c3dd1SBenny Halevy seq->status_flags = 0; 28245423732aSBenny Halevy } 28253bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 28263bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 2827221a6876SJ. Bruce Fields out_no_session: 28283f42d2c4SKinglong Mee if (conn) 28293f42d2c4SKinglong Mee free_conn(conn); 2830c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2831b85d4c01SBenny Halevy return status; 283266b2b9b2SJ. Bruce Fields out_put_session: 2833d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 2834221a6876SJ. Bruce Fields goto out_no_session; 2835069b6ad4SAndy Adamson } 2836069b6ad4SAndy Adamson 2837b607664eSTrond Myklebust void 2838b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 2839b607664eSTrond Myklebust { 2840b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 2841b607664eSTrond Myklebust 2842b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 2843b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 2844b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 2845b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 2846b607664eSTrond Myklebust } 2847d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 2848b607664eSTrond Myklebust nfsd4_put_session(cs->session); 28494b24ca7dSJeff Layton } else if (cs->clp) 28504b24ca7dSJeff Layton put_client_renew(cs->clp); 2851b607664eSTrond Myklebust } 2852b607664eSTrond Myklebust 2853345c2842SMi Jinlong __be32 2854345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) 2855345c2842SMi Jinlong { 28566b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 28576b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 285857b7b43bSJ. Bruce Fields __be32 status = 0; 28598daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2860345c2842SMi Jinlong 28616b10ad19STrond Myklebust spin_lock(&nn->client_lock); 28620a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 28638daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 286478389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2865345c2842SMi Jinlong 2866345c2842SMi Jinlong if (conf) { 2867c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 2868345c2842SMi Jinlong status = nfserr_clientid_busy; 2869345c2842SMi Jinlong goto out; 2870345c2842SMi Jinlong } 2871fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 2872fd699b8aSJeff Layton if (status) 2873fd699b8aSJeff Layton goto out; 28746b10ad19STrond Myklebust clp = conf; 2875345c2842SMi Jinlong } else if (unconf) 2876345c2842SMi Jinlong clp = unconf; 2877345c2842SMi Jinlong else { 2878345c2842SMi Jinlong status = nfserr_stale_clientid; 2879345c2842SMi Jinlong goto out; 2880345c2842SMi Jinlong } 288157266a6eSJ. Bruce Fields if (!mach_creds_match(clp, rqstp)) { 28826b10ad19STrond Myklebust clp = NULL; 288357266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 288457266a6eSJ. Bruce Fields goto out; 288557266a6eSJ. Bruce Fields } 28866b10ad19STrond Myklebust unhash_client_locked(clp); 2887345c2842SMi Jinlong out: 28886b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 28896b10ad19STrond Myklebust if (clp) 28906b10ad19STrond Myklebust expire_client(clp); 2891345c2842SMi Jinlong return status; 2892345c2842SMi Jinlong } 2893345c2842SMi Jinlong 2894069b6ad4SAndy Adamson __be32 28954dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) 28964dc6ec00SJ. Bruce Fields { 289757b7b43bSJ. Bruce Fields __be32 status = 0; 2898bcecf1ccSMi Jinlong 28994dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 29004dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 29014dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 29024dc6ec00SJ. Bruce Fields /* 29034dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 29044dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 29054dc6ec00SJ. Bruce Fields */ 29064dc6ec00SJ. Bruce Fields return nfs_ok; 29074dc6ec00SJ. Bruce Fields } 2908bcecf1ccSMi Jinlong 2909bcecf1ccSMi Jinlong status = nfserr_complete_already; 2910a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 2911a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 2912bcecf1ccSMi Jinlong goto out; 2913bcecf1ccSMi Jinlong 2914bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 2915bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 29164dc6ec00SJ. Bruce Fields /* 29174dc6ec00SJ. Bruce Fields * The following error isn't really legal. 29184dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 29194dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 29204dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 29214dc6ec00SJ. Bruce Fields * client. 29224dc6ec00SJ. Bruce Fields */ 2923bcecf1ccSMi Jinlong goto out; 2924bcecf1ccSMi Jinlong 2925bcecf1ccSMi Jinlong status = nfs_ok; 29262a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 2927bcecf1ccSMi Jinlong out: 2928bcecf1ccSMi Jinlong return status; 29294dc6ec00SJ. Bruce Fields } 29304dc6ec00SJ. Bruce Fields 29314dc6ec00SJ. Bruce Fields __be32 2932b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 2933b591480bSJ.Bruce Fields struct nfsd4_setclientid *setclid) 29341da177e4SLinus Torvalds { 2935a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 29361da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 29373dbacee6STrond Myklebust struct nfs4_client *conf, *new; 29383dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 2939b37ad28bSAl Viro __be32 status; 2940c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2941a55370a3SNeilBrown 29425cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 29435cc40fd7STrond Myklebust if (new == NULL) 29445cc40fd7STrond Myklebust return nfserr_jukebox; 294563db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 29463dbacee6STrond Myklebust spin_lock(&nn->client_lock); 2947382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 294828ce6054SNeilBrown if (conf) { 294963db4632SJ. Bruce Fields /* case 0: */ 29501da177e4SLinus Torvalds status = nfserr_clid_inuse; 2951e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 2952e203d506SJ. Bruce Fields goto out; 2953026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 2954363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 2955363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 2956363168b4SJeff Layton sizeof(addr_str)); 2957026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 2958363168b4SJeff Layton "at %s\n", addr_str); 29591da177e4SLinus Torvalds goto out; 29601da177e4SLinus Torvalds } 29611da177e4SLinus Torvalds } 2962a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 29631da177e4SLinus Torvalds if (unconf) 29643dbacee6STrond Myklebust unhash_client_locked(unconf); 296534b232bbSJ. Bruce Fields if (conf && same_verf(&conf->cl_verifier, &clverifier)) 296663db4632SJ. Bruce Fields /* case 1: probable callback update */ 29671da177e4SLinus Torvalds copy_clid(new, conf); 296834b232bbSJ. Bruce Fields else /* case 4 (new client) or cases 2, 3 (client reboot): */ 2969c212cecfSStanislav Kinsbursky gen_clid(new, nn); 29708323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 29716f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 2972ac55fdc4SJeff Layton add_to_unconfirmed(new); 29731da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 29741da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 29751da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 29765cc40fd7STrond Myklebust new = NULL; 29771da177e4SLinus Torvalds status = nfs_ok; 29781da177e4SLinus Torvalds out: 29793dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 29805cc40fd7STrond Myklebust if (new) 29815cc40fd7STrond Myklebust free_client(new); 29823dbacee6STrond Myklebust if (unconf) 29833dbacee6STrond Myklebust expire_client(unconf); 29841da177e4SLinus Torvalds return status; 29851da177e4SLinus Torvalds } 29861da177e4SLinus Torvalds 29871da177e4SLinus Torvalds 2988b37ad28bSAl Viro __be32 2989b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 2990b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 2991b591480bSJ.Bruce Fields struct nfsd4_setclientid_confirm *setclientid_confirm) 29921da177e4SLinus Torvalds { 299321ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 2994d20c11d8SJeff Layton struct nfs4_client *old = NULL; 29951da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 29961da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 2997b37ad28bSAl Viro __be32 status; 29987f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 29991da177e4SLinus Torvalds 30002c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 30011da177e4SLinus Torvalds return nfserr_stale_clientid; 300221ab45a4SNeilBrown 3003d20c11d8SJeff Layton spin_lock(&nn->client_lock); 30048daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 30050a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 3006a186e767SJ. Bruce Fields /* 30078695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 30088695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 30098695b90aSJ. Bruce Fields * there's a bug somewhere. Let's charitably assume it's our 30108695b90aSJ. Bruce Fields * bug. 3011a186e767SJ. Bruce Fields */ 30128695b90aSJ. Bruce Fields status = nfserr_serverfault; 30138695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 30148695b90aSJ. Bruce Fields goto out; 30158695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 30168695b90aSJ. Bruce Fields goto out; 301763db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 301890d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 301990d700b7SJ. Bruce Fields if (conf && !unconf) /* case 2: probable retransmit */ 302090d700b7SJ. Bruce Fields status = nfs_ok; 302190d700b7SJ. Bruce Fields else /* case 4: client hasn't noticed we rebooted yet? */ 302290d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 302390d700b7SJ. Bruce Fields goto out; 302490d700b7SJ. Bruce Fields } 302590d700b7SJ. Bruce Fields status = nfs_ok; 302690d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 3027d20c11d8SJeff Layton old = unconf; 3028d20c11d8SJeff Layton unhash_client_locked(old); 30295a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 303090d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 3031d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3032d20c11d8SJeff Layton if (old) { 3033d20c11d8SJeff Layton status = mark_client_expired_locked(old); 30347abea1e8SJeff Layton if (status) { 30357abea1e8SJeff Layton old = NULL; 3036221a6876SJ. Bruce Fields goto out; 3037221a6876SJ. Bruce Fields } 30387abea1e8SJeff Layton } 30391da177e4SLinus Torvalds move_to_confirmed(unconf); 3040d20c11d8SJeff Layton conf = unconf; 304108e8987cSNeilBrown } 3042d20c11d8SJeff Layton get_client_locked(conf); 3043d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3044d20c11d8SJeff Layton nfsd4_probe_callback(conf); 3045d20c11d8SJeff Layton spin_lock(&nn->client_lock); 3046d20c11d8SJeff Layton put_client_renew_locked(conf); 30471da177e4SLinus Torvalds out: 3048d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3049d20c11d8SJeff Layton if (old) 3050d20c11d8SJeff Layton expire_client(old); 30511da177e4SLinus Torvalds return status; 30521da177e4SLinus Torvalds } 30531da177e4SLinus Torvalds 305432513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 30551da177e4SLinus Torvalds { 305632513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 305732513b40SJ. Bruce Fields } 305832513b40SJ. Bruce Fields 305932513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 3060f9c00c3aSJeff Layton static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh) 306132513b40SJ. Bruce Fields { 3062ca943217STrond Myklebust unsigned int hashval = file_hashval(fh); 30631da177e4SLinus Torvalds 3064950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3065950e0118STrond Myklebust 30668b671b80SJ. Bruce Fields atomic_set(&fp->fi_ref, 1); 30671d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 30688beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 30698beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 3070e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 307147f9940cSMeelap Shah fp->fi_had_conflict = false; 3072acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 3073baeb4ff0SJeff Layton fp->fi_share_deny = 0; 3074f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 3075f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 307689876f8cSJeff Layton hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]); 30771da177e4SLinus Torvalds } 30781da177e4SLinus Torvalds 3079e8ff2a84SJ. Bruce Fields void 3080e60d4398SNeilBrown nfsd4_free_slabs(void) 3081e60d4398SNeilBrown { 3082abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3083abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3084abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3085abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3086abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 3087e60d4398SNeilBrown } 30881da177e4SLinus Torvalds 308972083396SBryan Schumaker int 30901da177e4SLinus Torvalds nfsd4_init_slabs(void) 30911da177e4SLinus Torvalds { 3092fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 3093fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 3094fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 3095abf1135bSChristoph Hellwig goto out; 3096fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 30973c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 3098fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 3099abf1135bSChristoph Hellwig goto out_free_openowner_slab; 3100e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 310120c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 3102e60d4398SNeilBrown if (file_slab == NULL) 3103abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 31045ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 3105dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 31065ac049acSNeilBrown if (stateid_slab == NULL) 3107abf1135bSChristoph Hellwig goto out_free_file_slab; 31085b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 310920c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 31105b2d21c1SNeilBrown if (deleg_slab == NULL) 3111abf1135bSChristoph Hellwig goto out_free_stateid_slab; 3112e60d4398SNeilBrown return 0; 3113abf1135bSChristoph Hellwig 3114abf1135bSChristoph Hellwig out_free_stateid_slab: 3115abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3116abf1135bSChristoph Hellwig out_free_file_slab: 3117abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3118abf1135bSChristoph Hellwig out_free_lockowner_slab: 3119abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3120abf1135bSChristoph Hellwig out_free_openowner_slab: 3121abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3122abf1135bSChristoph Hellwig out: 31231da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 31241da177e4SLinus Torvalds return -ENOMEM; 31251da177e4SLinus Torvalds } 31261da177e4SLinus Torvalds 3127ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 3128ff194bd9SJ. Bruce Fields { 3129ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 3130ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 3131ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 313258fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 313358fb12e6SJeff Layton } 313458fb12e6SJeff Layton 313558fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 313658fb12e6SJeff Layton struct nfs4_stateowner *so) 313758fb12e6SJeff Layton { 313858fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 313958fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 3140b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 314158fb12e6SJeff Layton } 314258fb12e6SJeff Layton } 314358fb12e6SJeff Layton 314458fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 314558fb12e6SJeff Layton { 314658fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 314758fb12e6SJeff Layton 314858fb12e6SJeff Layton if (so != NULL) { 314958fb12e6SJeff Layton cstate->replay_owner = NULL; 315058fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 315158fb12e6SJeff Layton nfs4_put_stateowner(so); 315258fb12e6SJeff Layton } 3153ff194bd9SJ. Bruce Fields } 3154ff194bd9SJ. Bruce Fields 3155fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 31561da177e4SLinus Torvalds { 31571da177e4SLinus Torvalds struct nfs4_stateowner *sop; 31581da177e4SLinus Torvalds 3159fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 3160ff194bd9SJ. Bruce Fields if (!sop) 3161ff194bd9SJ. Bruce Fields return NULL; 3162ff194bd9SJ. Bruce Fields 3163ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 3164ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 3165fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 3166ff194bd9SJ. Bruce Fields return NULL; 3167ff194bd9SJ. Bruce Fields } 31681da177e4SLinus Torvalds sop->so_owner.len = owner->len; 3169ff194bd9SJ. Bruce Fields 3170ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 3171ff194bd9SJ. Bruce Fields sop->so_client = clp; 3172ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 31736b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 31741da177e4SLinus Torvalds return sop; 31751da177e4SLinus Torvalds } 3176ff194bd9SJ. Bruce Fields 3177fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 3178ff194bd9SJ. Bruce Fields { 3179d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 31809b531137SStanislav Kinsbursky 3181d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 3182d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 3183fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 31841da177e4SLinus Torvalds } 31851da177e4SLinus Torvalds 31868f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 31878f4b54c5SJeff Layton { 3188d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 31898f4b54c5SJeff Layton } 31908f4b54c5SJeff Layton 31916b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 31926b180f0bSJeff Layton { 31936b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 31946b180f0bSJeff Layton 31956b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 31966b180f0bSJeff Layton } 31976b180f0bSJeff Layton 31986b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 31998f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 32006b180f0bSJeff Layton .so_free = nfs4_free_openowner, 32016b180f0bSJeff Layton }; 32026b180f0bSJeff Layton 3203fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 320413d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 3205db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 3206db24b3b4SJeff Layton { 320713d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 32087ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 32091da177e4SLinus Torvalds 3210fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 3211fe0750e5SJ. Bruce Fields if (!oo) 32121da177e4SLinus Torvalds return NULL; 32136b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 3214fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 3215fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 3216d3134b10SJeff Layton oo->oo_flags = 0; 3217db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 3218db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 3219fe0750e5SJ. Bruce Fields oo->oo_time = 0; 322038c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 3221fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 3222d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 3223d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 32247ffb5880STrond Myklebust if (ret == NULL) { 3225fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 32267ffb5880STrond Myklebust ret = oo; 32277ffb5880STrond Myklebust } else 32287ffb5880STrond Myklebust nfs4_free_openowner(&oo->oo_owner); 3229d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 3230fe0750e5SJ. Bruce Fields return oo; 32311da177e4SLinus Torvalds } 32321da177e4SLinus Torvalds 3233996e0938SJ. Bruce Fields static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { 3234fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 32351da177e4SLinus Torvalds 3236d6f2bc5dSTrond Myklebust atomic_inc(&stp->st_stid.sc_count); 32373abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 32383c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 3239b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 324013cd2184SNeilBrown get_nfs4_file(fp); 324111b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 32421da177e4SLinus Torvalds stp->st_access_bmap = 0; 32431da177e4SLinus Torvalds stp->st_deny_bmap = 0; 32444c4cd222SNeilBrown stp->st_openstp = NULL; 32451c755dc1SJeff Layton spin_lock(&oo->oo_owner.so_client->cl_lock); 32461c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 32471d31a253STrond Myklebust spin_lock(&fp->fi_lock); 32481d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 32491d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 32501c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 32511da177e4SLinus Torvalds } 32521da177e4SLinus Torvalds 3253d3134b10SJeff Layton /* 3254d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 3255d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 3256d3134b10SJeff Layton * them before returning however. 3257d3134b10SJeff Layton */ 32581da177e4SLinus Torvalds static void 3259d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 32601da177e4SLinus Torvalds { 3261217526e7SJeff Layton struct nfs4_ol_stateid *last; 3262d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 3263d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 3264d3134b10SJeff Layton nfsd_net_id); 326573758fedSStanislav Kinsbursky 3266fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 32671da177e4SLinus Torvalds 3268b401be22SJeff Layton /* 3269b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 3270b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 3271b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 3272b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 3273b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 3274b401be22SJeff Layton * there should be no danger of the refcount going back up again at 3275b401be22SJeff Layton * this point. 3276b401be22SJeff Layton */ 3277b401be22SJeff Layton wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2); 3278b401be22SJeff Layton 3279d3134b10SJeff Layton release_all_access(s); 3280d3134b10SJeff Layton if (s->st_stid.sc_file) { 3281d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 3282d3134b10SJeff Layton s->st_stid.sc_file = NULL; 3283d3134b10SJeff Layton } 3284217526e7SJeff Layton 3285217526e7SJeff Layton spin_lock(&nn->client_lock); 3286217526e7SJeff Layton last = oo->oo_last_closed_stid; 3287d3134b10SJeff Layton oo->oo_last_closed_stid = s; 328873758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 3289fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 3290217526e7SJeff Layton spin_unlock(&nn->client_lock); 3291217526e7SJeff Layton if (last) 3292217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 32931da177e4SLinus Torvalds } 32941da177e4SLinus Torvalds 32951da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 32961da177e4SLinus Torvalds static struct nfs4_file * 3297ca943217STrond Myklebust find_file_locked(struct knfsd_fh *fh) 32981da177e4SLinus Torvalds { 3299ca943217STrond Myklebust unsigned int hashval = file_hashval(fh); 33001da177e4SLinus Torvalds struct nfs4_file *fp; 33011da177e4SLinus Torvalds 3302950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3303950e0118STrond Myklebust 330489876f8cSJeff Layton hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { 3305ca943217STrond Myklebust if (nfsd_fh_match(&fp->fi_fhandle, fh)) { 330613cd2184SNeilBrown get_nfs4_file(fp); 33071da177e4SLinus Torvalds return fp; 33081da177e4SLinus Torvalds } 330913cd2184SNeilBrown } 33101da177e4SLinus Torvalds return NULL; 33111da177e4SLinus Torvalds } 33121da177e4SLinus Torvalds 3313950e0118STrond Myklebust static struct nfs4_file * 3314ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 3315950e0118STrond Myklebust { 3316950e0118STrond Myklebust struct nfs4_file *fp; 3317950e0118STrond Myklebust 3318950e0118STrond Myklebust spin_lock(&state_lock); 3319ca943217STrond Myklebust fp = find_file_locked(fh); 3320950e0118STrond Myklebust spin_unlock(&state_lock); 3321950e0118STrond Myklebust return fp; 3322950e0118STrond Myklebust } 3323950e0118STrond Myklebust 3324950e0118STrond Myklebust static struct nfs4_file * 3325f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 3326950e0118STrond Myklebust { 3327950e0118STrond Myklebust struct nfs4_file *fp; 3328950e0118STrond Myklebust 3329950e0118STrond Myklebust spin_lock(&state_lock); 3330ca943217STrond Myklebust fp = find_file_locked(fh); 3331950e0118STrond Myklebust if (fp == NULL) { 3332f9c00c3aSJeff Layton nfsd4_init_file(new, fh); 3333950e0118STrond Myklebust fp = new; 3334950e0118STrond Myklebust } 3335950e0118STrond Myklebust spin_unlock(&state_lock); 3336950e0118STrond Myklebust 3337950e0118STrond Myklebust return fp; 3338950e0118STrond Myklebust } 3339950e0118STrond Myklebust 33404f83aa30SJ. Bruce Fields /* 33411da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 33421da177e4SLinus Torvalds * WRITE with all zero or all one stateid 33431da177e4SLinus Torvalds */ 3344b37ad28bSAl Viro static __be32 33451da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 33461da177e4SLinus Torvalds { 33471da177e4SLinus Torvalds struct nfs4_file *fp; 3348baeb4ff0SJeff Layton __be32 ret = nfs_ok; 33491da177e4SLinus Torvalds 3350ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 335113cd2184SNeilBrown if (!fp) 3352baeb4ff0SJeff Layton return ret; 3353baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 33541d31a253STrond Myklebust spin_lock(&fp->fi_lock); 3355baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 3356baeb4ff0SJeff Layton ret = nfserr_locked; 33571d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 335813cd2184SNeilBrown put_nfs4_file(fp); 335913cd2184SNeilBrown return ret; 33601da177e4SLinus Torvalds } 33611da177e4SLinus Torvalds 336202e1215fSJeff Layton void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) 33631da177e4SLinus Torvalds { 336411b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 336511b9164aSTrond Myklebust nfsd_net_id); 3366e8c69d17SJ. Bruce Fields 336711b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 3368f54fe962SJeff Layton 336902e1215fSJeff Layton /* 337002e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 3371f54fe962SJeff Layton * already holding inode->i_lock. 3372f54fe962SJeff Layton * 3373dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 3374dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 3375dff1399fSJeff Layton */ 3376f54fe962SJeff Layton spin_lock(&state_lock); 3377dff1399fSJeff Layton if (dp->dl_time == 0) { 33781da177e4SLinus Torvalds dp->dl_time = get_seconds(); 337902e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 338002e1215fSJeff Layton } 338102e1215fSJeff Layton spin_unlock(&state_lock); 3382dff1399fSJeff Layton } 33831da177e4SLinus Torvalds 338402e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 338502e1215fSJeff Layton { 338602e1215fSJeff Layton /* 338702e1215fSJeff Layton * We're assuming the state code never drops its reference 338802e1215fSJeff Layton * without first removing the lease. Since we're in this lease 338902e1215fSJeff Layton * callback (and since the lease code is serialized by the kernel 339002e1215fSJeff Layton * lock) we know the server hasn't removed the lease yet, we know 339102e1215fSJeff Layton * it's safe to take a reference. 339202e1215fSJeff Layton */ 339372c0b0fbSTrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 33946b57d9c8SJ. Bruce Fields nfsd4_cb_recall(dp); 33956b57d9c8SJ. Bruce Fields } 33966b57d9c8SJ. Bruce Fields 33971c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 33986b57d9c8SJ. Bruce Fields static void nfsd_break_deleg_cb(struct file_lock *fl) 33996b57d9c8SJ. Bruce Fields { 3400acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 3401acfdf5c3SJ. Bruce Fields struct nfs4_delegation *dp; 34026b57d9c8SJ. Bruce Fields 34037fa10cd1SJ. Bruce Fields if (!fp) { 34047fa10cd1SJ. Bruce Fields WARN(1, "(%p)->fl_owner NULL\n", fl); 34057fa10cd1SJ. Bruce Fields return; 34067fa10cd1SJ. Bruce Fields } 34077fa10cd1SJ. Bruce Fields if (fp->fi_had_conflict) { 34087fa10cd1SJ. Bruce Fields WARN(1, "duplicate break on %p\n", fp); 34097fa10cd1SJ. Bruce Fields return; 34107fa10cd1SJ. Bruce Fields } 34110272e1fdSJ. Bruce Fields /* 34120272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 3413acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 34146b57d9c8SJ. Bruce Fields * in time: 34150272e1fdSJ. Bruce Fields */ 34160272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 34171da177e4SLinus Torvalds 341802e1215fSJeff Layton spin_lock(&fp->fi_lock); 3419417c6629SJeff Layton fp->fi_had_conflict = true; 3420417c6629SJeff Layton /* 3421417c6629SJeff Layton * If there are no delegations on the list, then we can't count on this 3422417c6629SJeff Layton * lease ever being cleaned up. Set the fl_break_time to jiffies so that 3423417c6629SJeff Layton * time_out_leases will do it ASAP. The fact that fi_had_conflict is now 3424417c6629SJeff Layton * true should keep any new delegations from being hashed. 3425417c6629SJeff Layton */ 3426417c6629SJeff Layton if (list_empty(&fp->fi_delegations)) 3427417c6629SJeff Layton fl->fl_break_time = jiffies; 3428417c6629SJeff Layton else 3429acfdf5c3SJ. Bruce Fields list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 34305d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 343102e1215fSJeff Layton spin_unlock(&fp->fi_lock); 34321da177e4SLinus Torvalds } 34331da177e4SLinus Torvalds 34341da177e4SLinus Torvalds static 34351da177e4SLinus Torvalds int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) 34361da177e4SLinus Torvalds { 34371da177e4SLinus Torvalds if (arg & F_UNLCK) 34381da177e4SLinus Torvalds return lease_modify(onlist, arg); 34391da177e4SLinus Torvalds else 34401da177e4SLinus Torvalds return -EAGAIN; 34411da177e4SLinus Torvalds } 34421da177e4SLinus Torvalds 34437b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 34448fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 34458fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 34461da177e4SLinus Torvalds }; 34471da177e4SLinus Torvalds 34487a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 34497a8711c9SJ. Bruce Fields { 34507a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 34517a8711c9SJ. Bruce Fields return nfs_ok; 34527a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 34537a8711c9SJ. Bruce Fields return nfserr_replay_me; 34547a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 34557a8711c9SJ. Bruce Fields return nfs_ok; 34567a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 34577a8711c9SJ. Bruce Fields } 34581da177e4SLinus Torvalds 34594b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 34604b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 34614b24ca7dSJeff Layton struct nfsd_net *nn) 34624b24ca7dSJeff Layton { 34634b24ca7dSJeff Layton struct nfs4_client *found; 34644b24ca7dSJeff Layton 34654b24ca7dSJeff Layton if (cstate->clp) { 34664b24ca7dSJeff Layton found = cstate->clp; 34674b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 34684b24ca7dSJeff Layton return nfserr_stale_clientid; 34694b24ca7dSJeff Layton return nfs_ok; 34704b24ca7dSJeff Layton } 34714b24ca7dSJeff Layton 34724b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 34734b24ca7dSJeff Layton return nfserr_stale_clientid; 34744b24ca7dSJeff Layton 34754b24ca7dSJeff Layton /* 34764b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 34774b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 34784b24ca7dSJeff Layton * will be false. 34794b24ca7dSJeff Layton */ 34804b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 34813e339f96STrond Myklebust spin_lock(&nn->client_lock); 34824b24ca7dSJeff Layton found = find_confirmed_client(clid, false, nn); 34833e339f96STrond Myklebust if (!found) { 34843e339f96STrond Myklebust spin_unlock(&nn->client_lock); 34854b24ca7dSJeff Layton return nfserr_expired; 34863e339f96STrond Myklebust } 34873e339f96STrond Myklebust atomic_inc(&found->cl_refcount); 34883e339f96STrond Myklebust spin_unlock(&nn->client_lock); 34894b24ca7dSJeff Layton 34904b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 34914b24ca7dSJeff Layton cstate->clp = found; 34924b24ca7dSJeff Layton return nfs_ok; 34934b24ca7dSJeff Layton } 34944b24ca7dSJeff Layton 3495b37ad28bSAl Viro __be32 34966668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 34973320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 34981da177e4SLinus Torvalds { 34991da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 35001da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 35011da177e4SLinus Torvalds unsigned int strhashval; 3502fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 35034cdc951bSJ. Bruce Fields __be32 status; 35041da177e4SLinus Torvalds 35052c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 35061da177e4SLinus Torvalds return nfserr_stale_clientid; 350732513b40SJ. Bruce Fields /* 350832513b40SJ. Bruce Fields * In case we need it later, after we've already created the 350932513b40SJ. Bruce Fields * file and don't want to risk a further failure: 351032513b40SJ. Bruce Fields */ 351132513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 351232513b40SJ. Bruce Fields if (open->op_file == NULL) 351332513b40SJ. Bruce Fields return nfserr_jukebox; 35141da177e4SLinus Torvalds 351513d6f66bSTrond Myklebust status = lookup_clientid(clientid, cstate, nn); 351613d6f66bSTrond Myklebust if (status) 351713d6f66bSTrond Myklebust return status; 351813d6f66bSTrond Myklebust clp = cstate->clp; 35192d91e895STrond Myklebust 3520d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 3521d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 35222d91e895STrond Myklebust open->op_openowner = oo; 35232d91e895STrond Myklebust if (!oo) { 3524bcf130f9SJ. Bruce Fields goto new_owner; 35250f442aa2SJ. Bruce Fields } 3526dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 35270f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 3528fe0750e5SJ. Bruce Fields release_openowner(oo); 3529fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 3530bcf130f9SJ. Bruce Fields goto new_owner; 35310f442aa2SJ. Bruce Fields } 35324cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 35334cdc951bSJ. Bruce Fields if (status) 35344cdc951bSJ. Bruce Fields return status; 35354cdc951bSJ. Bruce Fields goto alloc_stateid; 3536bcf130f9SJ. Bruce Fields new_owner: 353713d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 3538fe0750e5SJ. Bruce Fields if (oo == NULL) 35393e772463SJ. Bruce Fields return nfserr_jukebox; 3540fe0750e5SJ. Bruce Fields open->op_openowner = oo; 35414cdc951bSJ. Bruce Fields alloc_stateid: 3542b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 35434cdc951bSJ. Bruce Fields if (!open->op_stp) 35444cdc951bSJ. Bruce Fields return nfserr_jukebox; 35450f442aa2SJ. Bruce Fields return nfs_ok; 35461da177e4SLinus Torvalds } 35471da177e4SLinus Torvalds 3548b37ad28bSAl Viro static inline __be32 35494a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 35504a6e43e6SNeilBrown { 35514a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 35524a6e43e6SNeilBrown return nfserr_openmode; 35534a6e43e6SNeilBrown else 35544a6e43e6SNeilBrown return nfs_ok; 35554a6e43e6SNeilBrown } 35564a6e43e6SNeilBrown 3557c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 355824a0111eSJ. Bruce Fields { 355924a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 356024a0111eSJ. Bruce Fields } 356124a0111eSJ. Bruce Fields 356238c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 3563f459e453SJ. Bruce Fields { 3564f459e453SJ. Bruce Fields struct nfs4_stid *ret; 3565f459e453SJ. Bruce Fields 356638c2f4b1SJ. Bruce Fields ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); 3567f459e453SJ. Bruce Fields if (!ret) 3568f459e453SJ. Bruce Fields return NULL; 3569f459e453SJ. Bruce Fields return delegstateid(ret); 3570f459e453SJ. Bruce Fields } 3571f459e453SJ. Bruce Fields 35728b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 35738b289b2cSJ. Bruce Fields { 35748b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 35758b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 35768b289b2cSJ. Bruce Fields } 35778b289b2cSJ. Bruce Fields 3578b37ad28bSAl Viro static __be32 357941d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 3580567d9829SNeilBrown struct nfs4_delegation **dp) 3581567d9829SNeilBrown { 3582567d9829SNeilBrown int flags; 3583b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 3584dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 3585567d9829SNeilBrown 3586dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 3587dcd94cc2STrond Myklebust if (deleg == NULL) 3588c44c5eebSNeilBrown goto out; 358924a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 3590dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 3591dcd94cc2STrond Myklebust if (status) { 3592dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 3593dcd94cc2STrond Myklebust goto out; 3594dcd94cc2STrond Myklebust } 3595dcd94cc2STrond Myklebust *dp = deleg; 3596c44c5eebSNeilBrown out: 35978b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 3598c44c5eebSNeilBrown return nfs_ok; 3599c44c5eebSNeilBrown if (status) 3600c44c5eebSNeilBrown return status; 3601dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 3602c44c5eebSNeilBrown return nfs_ok; 3603567d9829SNeilBrown } 3604567d9829SNeilBrown 3605a46cb7f2SJeff Layton static struct nfs4_ol_stateid * 3606a46cb7f2SJeff Layton nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 36071da177e4SLinus Torvalds { 3608a46cb7f2SJeff Layton struct nfs4_ol_stateid *local, *ret = NULL; 3609fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 36101da177e4SLinus Torvalds 36111d31a253STrond Myklebust spin_lock(&fp->fi_lock); 36128beefa24SNeilBrown list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 36131da177e4SLinus Torvalds /* ignore lock owners */ 36141da177e4SLinus Torvalds if (local->st_stateowner->so_is_open_owner == 0) 36151da177e4SLinus Torvalds continue; 3616baeb4ff0SJeff Layton if (local->st_stateowner == &oo->oo_owner) { 3617a46cb7f2SJeff Layton ret = local; 3618d6f2bc5dSTrond Myklebust atomic_inc(&ret->st_stid.sc_count); 3619baeb4ff0SJeff Layton break; 36201da177e4SLinus Torvalds } 36211d31a253STrond Myklebust } 36221d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 3623a46cb7f2SJeff Layton return ret; 36241da177e4SLinus Torvalds } 36251da177e4SLinus Torvalds 362621fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 362721fb4016SJ. Bruce Fields { 362821fb4016SJ. Bruce Fields int flags = 0; 362921fb4016SJ. Bruce Fields 363021fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 363121fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 363221fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 363321fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 363421fb4016SJ. Bruce Fields return flags; 363521fb4016SJ. Bruce Fields } 363621fb4016SJ. Bruce Fields 3637b37ad28bSAl Viro static inline __be32 36381da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 36391da177e4SLinus Torvalds struct nfsd4_open *open) 36401da177e4SLinus Torvalds { 36411da177e4SLinus Torvalds struct iattr iattr = { 36421da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 36431da177e4SLinus Torvalds .ia_size = 0, 36441da177e4SLinus Torvalds }; 36451da177e4SLinus Torvalds if (!open->op_truncate) 36461da177e4SLinus Torvalds return 0; 36471da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 36489246585aSAl Viro return nfserr_inval; 36491da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 36501da177e4SLinus Torvalds } 36511da177e4SLinus Torvalds 36527e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 36536eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 36546eb3a1d0SJeff Layton struct nfsd4_open *open) 36557e6a72e5SChristoph Hellwig { 3656de18643dSTrond Myklebust struct file *filp = NULL; 36577e6a72e5SChristoph Hellwig __be32 status; 36587e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 36597e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 3660baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 36617e6a72e5SChristoph Hellwig 3662de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3663baeb4ff0SJeff Layton 3664baeb4ff0SJeff Layton /* 3665baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 3666baeb4ff0SJeff Layton * current access? 3667baeb4ff0SJeff Layton */ 3668baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 3669baeb4ff0SJeff Layton if (status != nfs_ok) { 3670baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3671baeb4ff0SJeff Layton goto out; 3672baeb4ff0SJeff Layton } 3673baeb4ff0SJeff Layton 3674baeb4ff0SJeff Layton /* set access to the file */ 3675baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 3676baeb4ff0SJeff Layton if (status != nfs_ok) { 3677baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3678baeb4ff0SJeff Layton goto out; 3679baeb4ff0SJeff Layton } 3680baeb4ff0SJeff Layton 3681baeb4ff0SJeff Layton /* Set access bits in stateid */ 3682baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 3683baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 3684baeb4ff0SJeff Layton 3685baeb4ff0SJeff Layton /* Set new deny mask */ 3686baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 3687baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 3688baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 3689baeb4ff0SJeff Layton 36907e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 3691de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3692de18643dSTrond Myklebust status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); 36937e6a72e5SChristoph Hellwig if (status) 3694baeb4ff0SJeff Layton goto out_put_access; 3695de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3696de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 3697de18643dSTrond Myklebust fp->fi_fds[oflag] = filp; 3698de18643dSTrond Myklebust filp = NULL; 3699de18643dSTrond Myklebust } 37007e6a72e5SChristoph Hellwig } 3701de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3702de18643dSTrond Myklebust if (filp) 3703de18643dSTrond Myklebust fput(filp); 37047e6a72e5SChristoph Hellwig 37057e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 37067e6a72e5SChristoph Hellwig if (status) 37077e6a72e5SChristoph Hellwig goto out_put_access; 37087e6a72e5SChristoph Hellwig out: 37097e6a72e5SChristoph Hellwig return status; 3710baeb4ff0SJeff Layton out_put_access: 3711baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 3712baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 3713baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 3714baeb4ff0SJeff Layton goto out; 37157e6a72e5SChristoph Hellwig } 37167e6a72e5SChristoph Hellwig 3717b37ad28bSAl Viro static __be32 3718dcef0413SJ. 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) 37191da177e4SLinus Torvalds { 3720b37ad28bSAl Viro __be32 status; 3721baeb4ff0SJeff Layton unsigned char old_deny_bmap; 37221da177e4SLinus Torvalds 37236eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 3724baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 37257e6a72e5SChristoph Hellwig 3726baeb4ff0SJeff Layton /* test and set deny mode */ 3727baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 3728baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 3729baeb4ff0SJeff Layton if (status == nfs_ok) { 3730baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 3731baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 3732baeb4ff0SJeff Layton fp->fi_share_deny |= 3733baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 37341da177e4SLinus Torvalds } 3735baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 37361da177e4SLinus Torvalds 3737baeb4ff0SJeff Layton if (status != nfs_ok) 3738baeb4ff0SJeff Layton return status; 3739baeb4ff0SJeff Layton 3740baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 3741baeb4ff0SJeff Layton if (status != nfs_ok) 3742baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 3743baeb4ff0SJeff Layton return status; 3744baeb4ff0SJeff Layton } 37451da177e4SLinus Torvalds 37461da177e4SLinus Torvalds static void 37471255a8f3SJ. Bruce Fields nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session) 37481da177e4SLinus Torvalds { 3749dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 37501da177e4SLinus Torvalds } 37511da177e4SLinus Torvalds 375214a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 375314a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 375414a24e99SJ. Bruce Fields { 375514a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 375614a24e99SJ. Bruce Fields return true; 375714a24e99SJ. Bruce Fields /* 375814a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 375914a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 376014a24e99SJ. Bruce Fields * until we hear otherwise: 376114a24e99SJ. Bruce Fields */ 376214a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 376314a24e99SJ. Bruce Fields } 376414a24e99SJ. Bruce Fields 3765d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag) 376622d38c4cSJ. Bruce Fields { 376722d38c4cSJ. Bruce Fields struct file_lock *fl; 376822d38c4cSJ. Bruce Fields 376922d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 377022d38c4cSJ. Bruce Fields if (!fl) 377122d38c4cSJ. Bruce Fields return NULL; 377222d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 3773617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 377422d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 377522d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 3776d564fbecSJeff Layton fl->fl_owner = (fl_owner_t)fp; 377722d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 377822d38c4cSJ. Bruce Fields return fl; 377922d38c4cSJ. Bruce Fields } 378022d38c4cSJ. Bruce Fields 378199c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp) 3782edab9782SJ. Bruce Fields { 378311b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 3784415b96c5SJeff Layton struct file_lock *fl, *ret; 3785417c6629SJeff Layton struct file *filp; 3786417c6629SJeff Layton int status = 0; 3787edab9782SJ. Bruce Fields 3788d564fbecSJeff Layton fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ); 3789edab9782SJ. Bruce Fields if (!fl) 3790edab9782SJ. Bruce Fields return -ENOMEM; 3791417c6629SJeff Layton filp = find_readable_file(fp); 3792417c6629SJeff Layton if (!filp) { 3793417c6629SJeff Layton /* We should always have a readable file here */ 3794417c6629SJeff Layton WARN_ON_ONCE(1); 3795417c6629SJeff Layton return -EBADF; 3796417c6629SJeff Layton } 3797417c6629SJeff Layton fl->fl_file = filp; 3798415b96c5SJeff Layton ret = fl; 3799415b96c5SJeff Layton status = vfs_setlease(filp, fl->fl_type, &ret); 3800417c6629SJeff Layton if (status) { 3801417c6629SJeff Layton locks_free_lock(fl); 3802417c6629SJeff Layton goto out_fput; 3803417c6629SJeff Layton } 3804415b96c5SJeff Layton if (ret != fl) 3805415b96c5SJeff Layton locks_free_lock(fl); 3806cdc97505SBenny Halevy spin_lock(&state_lock); 3807417c6629SJeff Layton spin_lock(&fp->fi_lock); 3808417c6629SJeff Layton /* Did the lease get broken before we took the lock? */ 3809417c6629SJeff Layton status = -EAGAIN; 3810417c6629SJeff Layton if (fp->fi_had_conflict) 3811417c6629SJeff Layton goto out_unlock; 3812417c6629SJeff Layton /* Race breaker */ 3813417c6629SJeff Layton if (fp->fi_lease) { 3814417c6629SJeff Layton status = 0; 3815417c6629SJeff Layton atomic_inc(&fp->fi_delegees); 3816931ee56cSBenny Halevy hash_delegation_locked(dp, fp); 3817417c6629SJeff Layton goto out_unlock; 3818417c6629SJeff Layton } 3819417c6629SJeff Layton fp->fi_lease = fl; 3820417c6629SJeff Layton fp->fi_deleg_file = filp; 3821417c6629SJeff Layton atomic_set(&fp->fi_delegees, 1); 3822417c6629SJeff Layton hash_delegation_locked(dp, fp); 3823417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3824cdc97505SBenny Halevy spin_unlock(&state_lock); 3825acfdf5c3SJ. Bruce Fields return 0; 3826417c6629SJeff Layton out_unlock: 3827417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3828417c6629SJeff Layton spin_unlock(&state_lock); 3829417c6629SJeff Layton out_fput: 3830417c6629SJeff Layton fput(filp); 3831e873088fSJ. Bruce Fields return status; 3832acfdf5c3SJ. Bruce Fields } 3833acfdf5c3SJ. Bruce Fields 38340b26693cSJeff Layton static struct nfs4_delegation * 38350b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 38360b26693cSJeff Layton struct nfs4_file *fp) 3837acfdf5c3SJ. Bruce Fields { 38380b26693cSJeff Layton int status; 38390b26693cSJeff Layton struct nfs4_delegation *dp; 3840417c6629SJeff Layton 3841bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 38420b26693cSJeff Layton return ERR_PTR(-EAGAIN); 38430b26693cSJeff Layton 38440b26693cSJeff Layton dp = alloc_init_deleg(clp, fh); 38450b26693cSJeff Layton if (!dp) 38460b26693cSJeff Layton return ERR_PTR(-ENOMEM); 38470b26693cSJeff Layton 3848bf7bd3e9SJ. Bruce Fields get_nfs4_file(fp); 3849cdc97505SBenny Halevy spin_lock(&state_lock); 3850417c6629SJeff Layton spin_lock(&fp->fi_lock); 385111b9164aSTrond Myklebust dp->dl_stid.sc_file = fp; 3852417c6629SJeff Layton if (!fp->fi_lease) { 3853417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3854417c6629SJeff Layton spin_unlock(&state_lock); 38550b26693cSJeff Layton status = nfs4_setlease(dp); 38560b26693cSJeff Layton goto out; 3857417c6629SJeff Layton } 3858cbf7a75bSJ. Bruce Fields atomic_inc(&fp->fi_delegees); 3859acfdf5c3SJ. Bruce Fields if (fp->fi_had_conflict) { 3860417c6629SJeff Layton status = -EAGAIN; 3861417c6629SJeff Layton goto out_unlock; 3862acfdf5c3SJ. Bruce Fields } 3863931ee56cSBenny Halevy hash_delegation_locked(dp, fp); 38640b26693cSJeff Layton status = 0; 3865417c6629SJeff Layton out_unlock: 3866417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3867cdc97505SBenny Halevy spin_unlock(&state_lock); 38680b26693cSJeff Layton out: 38690b26693cSJeff Layton if (status) { 38706011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 38710b26693cSJeff Layton return ERR_PTR(status); 38720b26693cSJeff Layton } 38730b26693cSJeff Layton return dp; 3874edab9782SJ. Bruce Fields } 3875edab9782SJ. Bruce Fields 38764aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 38774aa8913cSBenny Halevy { 38784aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 38794aa8913cSBenny Halevy if (status == -EAGAIN) 38804aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 38814aa8913cSBenny Halevy else { 38824aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 38834aa8913cSBenny Halevy switch (open->op_deleg_want) { 38844aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 38854aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 38864aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 38874aa8913cSBenny Halevy break; 38884aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 38894aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 38904aa8913cSBenny Halevy break; 38914aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 3892063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 38934aa8913cSBenny Halevy } 38944aa8913cSBenny Halevy } 38954aa8913cSBenny Halevy } 38964aa8913cSBenny Halevy 38971da177e4SLinus Torvalds /* 38981da177e4SLinus Torvalds * Attempt to hand out a delegation. 389999c41515SJ. Bruce Fields * 390099c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 390199c41515SJ. Bruce Fields * proper support for them. 39021da177e4SLinus Torvalds */ 39031da177e4SLinus Torvalds static void 39044cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 39054cf59221SJeff Layton struct nfs4_ol_stateid *stp) 39061da177e4SLinus Torvalds { 39071da177e4SLinus Torvalds struct nfs4_delegation *dp; 39084cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 39094cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 391014a24e99SJ. Bruce Fields int cb_up; 391199c41515SJ. Bruce Fields int status = 0; 39121da177e4SLinus Torvalds 3913fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 39147b190fecSNeilBrown open->op_recall = 0; 39157b190fecSNeilBrown switch (open->op_claim_type) { 39167b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 39172bf23875SJ. Bruce Fields if (!cb_up) 39187b190fecSNeilBrown open->op_recall = 1; 391999c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 392099c41515SJ. Bruce Fields goto out_no_deleg; 39217b190fecSNeilBrown break; 39227b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 3923ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 392499c41515SJ. Bruce Fields /* 392599c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 392699c41515SJ. Bruce Fields * had the chance to reclaim theirs.... 392799c41515SJ. Bruce Fields */ 39284cf59221SJeff Layton if (locks_in_grace(clp->net)) 392999c41515SJ. Bruce Fields goto out_no_deleg; 3930dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 393199c41515SJ. Bruce Fields goto out_no_deleg; 39329a0590aeSSteve Dickson /* 39339a0590aeSSteve Dickson * Also, if the file was opened for write or 39349a0590aeSSteve Dickson * create, there's a good chance the client's 39359a0590aeSSteve Dickson * about to write to it, resulting in an 39369a0590aeSSteve Dickson * immediate recall (since we don't support 39379a0590aeSSteve Dickson * write delegations): 39389a0590aeSSteve Dickson */ 39391da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 394099c41515SJ. Bruce Fields goto out_no_deleg; 394199c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 394299c41515SJ. Bruce Fields goto out_no_deleg; 39437b190fecSNeilBrown break; 39447b190fecSNeilBrown default: 394599c41515SJ. Bruce Fields goto out_no_deleg; 39467b190fecSNeilBrown } 394711b9164aSTrond Myklebust dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file); 39480b26693cSJeff Layton if (IS_ERR(dp)) 3949dd239cc0SJ. Bruce Fields goto out_no_deleg; 39501da177e4SLinus Torvalds 3951d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 39521da177e4SLinus Torvalds 39538c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 3954d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 395599c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 395667cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 3957dd239cc0SJ. Bruce Fields return; 3958dd239cc0SJ. Bruce Fields out_no_deleg: 395999c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 39607b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 3961d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 39621da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 3963d08d32e6SJ. Bruce Fields open->op_recall = 1; 3964d08d32e6SJ. Bruce Fields } 3965dd239cc0SJ. Bruce Fields 3966dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 3967dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 3968dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 3969dd239cc0SJ. Bruce Fields return; 39701da177e4SLinus Torvalds } 39711da177e4SLinus Torvalds 3972e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 3973e27f49c3SBenny Halevy struct nfs4_delegation *dp) 3974e27f49c3SBenny Halevy { 3975e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 3976e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 3977e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3978e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 3979e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 3980e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 3981e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3982e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 3983e27f49c3SBenny Halevy } 3984e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 3985e27f49c3SBenny Halevy * it already has, therefore we don't return 3986e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 3987e27f49c3SBenny Halevy */ 3988e27f49c3SBenny Halevy } 3989e27f49c3SBenny Halevy 3990b37ad28bSAl Viro __be32 39911da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 39921da177e4SLinus Torvalds { 39936668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 399438c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 39951da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 3996dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 3997567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 3998b37ad28bSAl Viro __be32 status; 39991da177e4SLinus Torvalds 40001da177e4SLinus Torvalds /* 40011da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 40021da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 40031da177e4SLinus Torvalds * If not found, create the nfs4_file struct 40041da177e4SLinus Torvalds */ 4005f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 4006950e0118STrond Myklebust if (fp != open->op_file) { 400741d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 4008c44c5eebSNeilBrown if (status) 4009c44c5eebSNeilBrown goto out; 4010a46cb7f2SJeff Layton stp = nfsd4_find_existing_open(fp, open); 40111da177e4SLinus Torvalds } else { 4012950e0118STrond Myklebust open->op_file = NULL; 4013c44c5eebSNeilBrown status = nfserr_bad_stateid; 40148b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 4015c44c5eebSNeilBrown goto out; 40163e772463SJ. Bruce Fields status = nfserr_jukebox; 40171da177e4SLinus Torvalds } 40181da177e4SLinus Torvalds 40191da177e4SLinus Torvalds /* 40201da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 40211da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 40221da177e4SLinus Torvalds */ 40231da177e4SLinus Torvalds if (stp) { 40241da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 4025f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 40261da177e4SLinus Torvalds if (status) 40271da177e4SLinus Torvalds goto out; 40281da177e4SLinus Torvalds } else { 40294cdc951bSJ. Bruce Fields stp = open->op_stp; 40304cdc951bSJ. Bruce Fields open->op_stp = NULL; 4031996e0938SJ. Bruce Fields init_open_stateid(stp, fp, open); 40326eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 40336eb3a1d0SJeff Layton if (status) { 40346eb3a1d0SJeff Layton release_open_stateid(stp); 40356eb3a1d0SJeff Layton goto out; 40366eb3a1d0SJeff Layton } 40371da177e4SLinus Torvalds } 4038dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4039dcef0413SJ. Bruce Fields memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 40401da177e4SLinus Torvalds 4041d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 4042d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 4043d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4044d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 4045d24433cdSBenny Halevy goto nodeleg; 4046d24433cdSBenny Halevy } 4047d24433cdSBenny Halevy } 4048d24433cdSBenny Halevy 40491da177e4SLinus Torvalds /* 40501da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 40511da177e4SLinus Torvalds * OPEN succeeds even if we fail. 40521da177e4SLinus Torvalds */ 40534cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 4054d24433cdSBenny Halevy nodeleg: 40551da177e4SLinus Torvalds status = nfs_ok; 40561da177e4SLinus Torvalds 40578c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 4058dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 40591da177e4SLinus Torvalds out: 4060d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 4061d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 4062e27f49c3SBenny Halevy open->op_deleg_want) 4063e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 4064d24433cdSBenny Halevy 406513cd2184SNeilBrown if (fp) 406613cd2184SNeilBrown put_nfs4_file(fp); 406737515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 40681255a8f3SJ. Bruce Fields nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate)); 40691da177e4SLinus Torvalds /* 40701da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 40711da177e4SLinus Torvalds */ 40721da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 4073dad1c067SJ. Bruce Fields if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) && 40746668958fSAndy Adamson !nfsd4_has_session(&resp->cstate)) 40751da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 4076dcd94cc2STrond Myklebust if (dp) 4077dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4078d6f2bc5dSTrond Myklebust if (stp) 4079d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 40801da177e4SLinus Torvalds 40811da177e4SLinus Torvalds return status; 40821da177e4SLinus Torvalds } 40831da177e4SLinus Torvalds 408458fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 408558fb12e6SJeff Layton struct nfsd4_open *open, __be32 status) 4086d29b20cdSJ. Bruce Fields { 4087d29b20cdSJ. Bruce Fields if (open->op_openowner) { 4088d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 4089d29b20cdSJ. Bruce Fields 4090d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 4091d3134b10SJeff Layton nfs4_put_stateowner(so); 4092d29b20cdSJ. Bruce Fields } 409332513b40SJ. Bruce Fields if (open->op_file) 409432513b40SJ. Bruce Fields nfsd4_free_file(open->op_file); 40954cdc951bSJ. Bruce Fields if (open->op_stp) 40966011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 4097d29b20cdSJ. Bruce Fields } 4098d29b20cdSJ. Bruce Fields 4099b37ad28bSAl Viro __be32 4100b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4101b591480bSJ.Bruce Fields clientid_t *clid) 41021da177e4SLinus Torvalds { 41031da177e4SLinus Torvalds struct nfs4_client *clp; 4104b37ad28bSAl Viro __be32 status; 41057f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 41061da177e4SLinus Torvalds 41071da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 41081da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 41094b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 41109b2ef62bSJ. Bruce Fields if (status) 41111da177e4SLinus Torvalds goto out; 41124b24ca7dSJeff Layton clp = cstate->clp; 41131da177e4SLinus Torvalds status = nfserr_cb_path_down; 4114ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 411577a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 41161da177e4SLinus Torvalds goto out; 41171da177e4SLinus Torvalds status = nfs_ok; 41181da177e4SLinus Torvalds out: 41191da177e4SLinus Torvalds return status; 41201da177e4SLinus Torvalds } 41211da177e4SLinus Torvalds 4122a76b4319SNeilBrown static void 412312760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 4124a76b4319SNeilBrown { 412533dcc481SJeff Layton /* do nothing if grace period already ended */ 4126a51c84edSStanislav Kinsbursky if (nn->grace_ended) 412733dcc481SJeff Layton return; 412833dcc481SJeff Layton 4129a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 4130a51c84edSStanislav Kinsbursky nn->grace_ended = true; 413112760c66SStanislav Kinsbursky nfsd4_record_grace_done(nn, nn->boot_time); 41325e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 4133e46b498cSJ. Bruce Fields /* 4134e46b498cSJ. Bruce Fields * Now that every NFSv4 client has had the chance to recover and 4135e46b498cSJ. Bruce Fields * to see the (possibly new, possibly shorter) lease time, we 4136e46b498cSJ. Bruce Fields * can safely set the next grace time to the current lease time: 4137e46b498cSJ. Bruce Fields */ 41385284b44eSStanislav Kinsbursky nn->nfsd4_grace = nn->nfsd4_lease; 4139a76b4319SNeilBrown } 4140a76b4319SNeilBrown 4141fd39ca9aSNeilBrown static time_t 414209121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 41431da177e4SLinus Torvalds { 41441da177e4SLinus Torvalds struct nfs4_client *clp; 4145fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 41461da177e4SLinus Torvalds struct nfs4_delegation *dp; 4147217526e7SJeff Layton struct nfs4_ol_stateid *stp; 41481da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 41493d733711SStanislav Kinsbursky time_t cutoff = get_seconds() - nn->nfsd4_lease; 4150a832e7aeSJeff Layton time_t t, new_timeo = nn->nfsd4_lease; 41511da177e4SLinus Torvalds 41521da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 415312760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 415436acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 4155c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 41565ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 41571da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 41581da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 41591da177e4SLinus Torvalds t = clp->cl_time - cutoff; 4160a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 41611da177e4SLinus Torvalds break; 41621da177e4SLinus Torvalds } 4163221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 4164d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 4165d7682988SBenny Halevy clp->cl_clientid.cl_id); 4166d7682988SBenny Halevy continue; 4167d7682988SBenny Halevy } 41684864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 416936acb66bSBenny Halevy } 4170c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 417136acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 417236acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 41731da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 41741da177e4SLinus Torvalds clp->cl_clientid.cl_id); 41754864af97STrond Myklebust list_del_init(&clp->cl_lru); 41761da177e4SLinus Torvalds expire_client(clp); 41771da177e4SLinus Torvalds } 4178cdc97505SBenny Halevy spin_lock(&state_lock); 4179e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 41801da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 41814e37a7c2SStanislav Kinsbursky if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) 41824e37a7c2SStanislav Kinsbursky continue; 41831da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 4184a832e7aeSJeff Layton t = dp->dl_time - cutoff; 4185a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 41861da177e4SLinus Torvalds break; 41871da177e4SLinus Torvalds } 418842690676SJeff Layton unhash_delegation_locked(dp); 418942690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 41901da177e4SLinus Torvalds } 4191cdc97505SBenny Halevy spin_unlock(&state_lock); 41922d4a532dSJeff Layton while (!list_empty(&reaplist)) { 41932d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 41942d4a532dSJeff Layton dl_recall_lru); 41952d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 41963bd64a5bSJ. Bruce Fields revoke_delegation(dp); 41971da177e4SLinus Torvalds } 4198217526e7SJeff Layton 4199217526e7SJeff Layton spin_lock(&nn->client_lock); 4200217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 4201217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 4202217526e7SJeff Layton oo_close_lru); 4203217526e7SJeff Layton if (time_after((unsigned long)oo->oo_time, 4204217526e7SJeff Layton (unsigned long)cutoff)) { 4205a832e7aeSJeff Layton t = oo->oo_time - cutoff; 4206a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 42071da177e4SLinus Torvalds break; 42081da177e4SLinus Torvalds } 4209217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 4210217526e7SJeff Layton stp = oo->oo_last_closed_stid; 4211217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 4212217526e7SJeff Layton spin_unlock(&nn->client_lock); 4213217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 4214217526e7SJeff Layton spin_lock(&nn->client_lock); 42151da177e4SLinus Torvalds } 4216217526e7SJeff Layton spin_unlock(&nn->client_lock); 4217217526e7SJeff Layton 4218a832e7aeSJeff Layton new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 4219a832e7aeSJeff Layton return new_timeo; 42201da177e4SLinus Torvalds } 42211da177e4SLinus Torvalds 4222a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 4223a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 4224a254b246SHarvey Harrison 4225a254b246SHarvey Harrison static void 422609121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 42271da177e4SLinus Torvalds { 42281da177e4SLinus Torvalds time_t t; 422909121281SStanislav Kinsbursky struct delayed_work *dwork = container_of(laundry, struct delayed_work, 423009121281SStanislav Kinsbursky work); 423109121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 423209121281SStanislav Kinsbursky laundromat_work); 42331da177e4SLinus Torvalds 423409121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 42351da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 423609121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 42371da177e4SLinus Torvalds } 42381da177e4SLinus Torvalds 4239f7a4d872SJ. Bruce Fields static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) 4240f8816512SNeilBrown { 424111b9164aSTrond Myklebust if (!nfsd_fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle)) 4242f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4243f7a4d872SJ. Bruce Fields return nfs_ok; 42441da177e4SLinus Torvalds } 42451da177e4SLinus Torvalds 42461da177e4SLinus Torvalds static inline int 424782c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 42481da177e4SLinus Torvalds { 424982c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 425082c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 425182c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 42521da177e4SLinus Torvalds } 42531da177e4SLinus Torvalds 42541da177e4SLinus Torvalds static inline int 425582c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 42561da177e4SLinus Torvalds { 425782c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 425882c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 42591da177e4SLinus Torvalds } 42601da177e4SLinus Torvalds 42611da177e4SLinus Torvalds static 4262dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 42631da177e4SLinus Torvalds { 4264b37ad28bSAl Viro __be32 status = nfserr_openmode; 42651da177e4SLinus Torvalds 426602921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 426702921914SJ. Bruce Fields if (stp->st_openstp) 426802921914SJ. Bruce Fields stp = stp->st_openstp; 426982c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 42701da177e4SLinus Torvalds goto out; 427182c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 42721da177e4SLinus Torvalds goto out; 42731da177e4SLinus Torvalds status = nfs_ok; 42741da177e4SLinus Torvalds out: 42751da177e4SLinus Torvalds return status; 42761da177e4SLinus Torvalds } 42771da177e4SLinus Torvalds 4278b37ad28bSAl Viro static inline __be32 42795ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 42801da177e4SLinus Torvalds { 4281203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 42821da177e4SLinus Torvalds return nfs_ok; 42835ccb0066SStanislav Kinsbursky else if (locks_in_grace(net)) { 428425985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 42851da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 42861da177e4SLinus Torvalds return nfserr_grace; 42871da177e4SLinus Torvalds } else if (flags & WR_STATE) 42881da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 42891da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 42901da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 42911da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 42921da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 42931da177e4SLinus Torvalds } 42941da177e4SLinus Torvalds 42951da177e4SLinus Torvalds /* 42961da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 42971da177e4SLinus Torvalds * that are not able to provide mandatory locking. 42981da177e4SLinus Torvalds */ 42991da177e4SLinus Torvalds static inline int 43005ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 43011da177e4SLinus Torvalds { 43025ccb0066SStanislav Kinsbursky return locks_in_grace(net) && mandatory_lock(inode); 43031da177e4SLinus Torvalds } 43041da177e4SLinus Torvalds 430581b82965SJ. Bruce Fields /* Returns true iff a is later than b: */ 430681b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b) 430781b82965SJ. Bruce Fields { 43081a9357f4SJim Rees return (s32)(a->si_generation - b->si_generation) > 0; 430981b82965SJ. Bruce Fields } 431081b82965SJ. Bruce Fields 431157b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 43120836f587SJ. Bruce Fields { 43136668958fSAndy Adamson /* 43146668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 43156668958fSAndy Adamson * when it is zero. 43166668958fSAndy Adamson */ 431728dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 431881b82965SJ. Bruce Fields return nfs_ok; 431981b82965SJ. Bruce Fields 432081b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 432181b82965SJ. Bruce Fields return nfs_ok; 43226668958fSAndy Adamson 43230836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 432481b82965SJ. Bruce Fields if (stateid_generation_after(in, ref)) 43250836f587SJ. Bruce Fields return nfserr_bad_stateid; 43260836f587SJ. Bruce Fields /* 432781b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 432881b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 432981b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 433081b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 433181b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 433281b82965SJ. Bruce Fields * but better performance may result in retrying IO that 433381b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 433481b82965SJ. Bruce Fields * reordered in flight: 43350836f587SJ. Bruce Fields */ 43360836f587SJ. Bruce Fields return nfserr_old_stateid; 43370836f587SJ. Bruce Fields } 43380836f587SJ. Bruce Fields 43397df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 434017456804SBryan Schumaker { 434197b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 434297b7e3b6SJ. Bruce Fields struct nfs4_ol_stateid *ols; 43431af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 434417456804SBryan Schumaker 43457df302f7SChuck Lever if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 43461af71cc8SJeff Layton return status; 43477df302f7SChuck Lever /* Client debugging aid. */ 43487df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 43497df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 43507df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 43517df302f7SChuck Lever sizeof(addr_str)); 43527df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 43537df302f7SChuck Lever "with incorrect client ID\n", addr_str); 43541af71cc8SJeff Layton return status; 43557df302f7SChuck Lever } 43561af71cc8SJeff Layton spin_lock(&cl->cl_lock); 43571af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 435897b7e3b6SJ. Bruce Fields if (!s) 43591af71cc8SJeff Layton goto out_unlock; 436036279ac1SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, 1); 436117456804SBryan Schumaker if (status) 43621af71cc8SJeff Layton goto out_unlock; 436323340032SJ. Bruce Fields switch (s->sc_type) { 436423340032SJ. Bruce Fields case NFS4_DELEG_STID: 43651af71cc8SJeff Layton status = nfs_ok; 43661af71cc8SJeff Layton break; 43673bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 43681af71cc8SJeff Layton status = nfserr_deleg_revoked; 43691af71cc8SJeff Layton break; 437023340032SJ. Bruce Fields case NFS4_OPEN_STID: 437123340032SJ. Bruce Fields case NFS4_LOCK_STID: 437297b7e3b6SJ. Bruce Fields ols = openlockstateid(s); 437397b7e3b6SJ. Bruce Fields if (ols->st_stateowner->so_is_open_owner 437423340032SJ. Bruce Fields && !(openowner(ols->st_stateowner)->oo_flags 437523340032SJ. Bruce Fields & NFS4_OO_CONFIRMED)) 43761af71cc8SJeff Layton status = nfserr_bad_stateid; 43771af71cc8SJeff Layton else 43781af71cc8SJeff Layton status = nfs_ok; 43791af71cc8SJeff Layton break; 438023340032SJ. Bruce Fields default: 438123340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 4382b0fc29d6STrond Myklebust /* Fallthrough */ 438323340032SJ. Bruce Fields case NFS4_CLOSED_STID: 4384b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 43851af71cc8SJeff Layton status = nfserr_bad_stateid; 438623340032SJ. Bruce Fields } 43871af71cc8SJeff Layton out_unlock: 43881af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 43891af71cc8SJeff Layton return status; 439017456804SBryan Schumaker } 439117456804SBryan Schumaker 43922dd6e458STrond Myklebust static __be32 43932dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 43942dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 43952dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 439638c2f4b1SJ. Bruce Fields { 43970eb6f20aSJ. Bruce Fields __be32 status; 439838c2f4b1SJ. Bruce Fields 439938c2f4b1SJ. Bruce Fields if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 440038c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 44014b24ca7dSJeff Layton status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn); 4402a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 44034b24ca7dSJeff Layton if (cstate->session) 4404a8a7c677STrond Myklebust return nfserr_bad_stateid; 440538c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 4406a8a7c677STrond Myklebust } 44070eb6f20aSJ. Bruce Fields if (status) 44080eb6f20aSJ. Bruce Fields return status; 44094b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 441038c2f4b1SJ. Bruce Fields if (!*s) 441138c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 441238c2f4b1SJ. Bruce Fields return nfs_ok; 441338c2f4b1SJ. Bruce Fields } 441438c2f4b1SJ. Bruce Fields 44151da177e4SLinus Torvalds /* 44161da177e4SLinus Torvalds * Checks for stateid operations 44171da177e4SLinus Torvalds */ 4418b37ad28bSAl Viro __be32 44195ccb0066SStanislav Kinsbursky nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, 4420dd453dfdSBenny Halevy stateid_t *stateid, int flags, struct file **filpp) 44211da177e4SLinus Torvalds { 442269064a27SJ. Bruce Fields struct nfs4_stid *s; 4423dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 44241da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 4425dd453dfdSBenny Halevy struct svc_fh *current_fh = &cstate->current_fh; 44261da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 44273320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 442814bcab1aSTrond Myklebust struct file *file = NULL; 4429b37ad28bSAl Viro __be32 status; 44301da177e4SLinus Torvalds 44311da177e4SLinus Torvalds if (filpp) 44321da177e4SLinus Torvalds *filpp = NULL; 44331da177e4SLinus Torvalds 44345ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 44351da177e4SLinus Torvalds return nfserr_grace; 44361da177e4SLinus Torvalds 44371da177e4SLinus Torvalds if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 44385ccb0066SStanislav Kinsbursky return check_special_stateids(net, current_fh, stateid, flags); 44391da177e4SLinus Torvalds 44402dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 4441db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 44422dd6e458STrond Myklebust &s, nn); 444338c2f4b1SJ. Bruce Fields if (status) 4444c2d1d6a8STrond Myklebust return status; 444569064a27SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); 44460c2a498fSJ. Bruce Fields if (status) 44470c2a498fSJ. Bruce Fields goto out; 4448f7a4d872SJ. Bruce Fields switch (s->sc_type) { 4449f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 445069064a27SJ. Bruce Fields dp = delegstateid(s); 4451dc9bf700SJ. Bruce Fields status = nfs4_check_delegmode(dp, flags); 4452dc9bf700SJ. Bruce Fields if (status) 4453dc9bf700SJ. Bruce Fields goto out; 445443b0178eSDan Carpenter if (filpp) { 445511b9164aSTrond Myklebust file = dp->dl_stid.sc_file->fi_deleg_file; 445614bcab1aSTrond Myklebust if (!file) { 4457063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 4458063b0fb9SJ. Bruce Fields status = nfserr_serverfault; 4459063b0fb9SJ. Bruce Fields goto out; 4460063b0fb9SJ. Bruce Fields } 4461de18643dSTrond Myklebust get_file(file); 446243b0178eSDan Carpenter } 4463f7a4d872SJ. Bruce Fields break; 4464f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 4465f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 446669064a27SJ. Bruce Fields stp = openlockstateid(s); 4467f7a4d872SJ. Bruce Fields status = nfs4_check_fh(current_fh, stp); 4468f7a4d872SJ. Bruce Fields if (status) 44691da177e4SLinus Torvalds goto out; 4470fe0750e5SJ. Bruce Fields if (stp->st_stateowner->so_is_open_owner 4471dad1c067SJ. Bruce Fields && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 44721da177e4SLinus Torvalds goto out; 4473a4455be0SJ. Bruce Fields status = nfs4_check_openmode(stp, flags); 4474a4455be0SJ. Bruce Fields if (status) 44751da177e4SLinus Torvalds goto out; 4476f9d7562fSJ. Bruce Fields if (filpp) { 447711b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 447811b9164aSTrond Myklebust 4479f9d7562fSJ. Bruce Fields if (flags & RD_STATE) 448011b9164aSTrond Myklebust file = find_readable_file(fp); 4481f9d7562fSJ. Bruce Fields else 448211b9164aSTrond Myklebust file = find_writeable_file(fp); 4483f9d7562fSJ. Bruce Fields } 4484f7a4d872SJ. Bruce Fields break; 4485f7a4d872SJ. Bruce Fields default: 448614bcab1aSTrond Myklebust status = nfserr_bad_stateid; 448714bcab1aSTrond Myklebust goto out; 44881da177e4SLinus Torvalds } 44891da177e4SLinus Torvalds status = nfs_ok; 449014bcab1aSTrond Myklebust if (file) 4491de18643dSTrond Myklebust *filpp = file; 44921da177e4SLinus Torvalds out: 4493fd911011STrond Myklebust nfs4_put_stid(s); 44941da177e4SLinus Torvalds return status; 44951da177e4SLinus Torvalds } 44961da177e4SLinus Torvalds 4497e1ca12dfSBryan Schumaker /* 449817456804SBryan Schumaker * Test if the stateid is valid 449917456804SBryan Schumaker */ 450017456804SBryan Schumaker __be32 450117456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 450217456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 450317456804SBryan Schumaker { 450403cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 450503cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 450603cfb420SBryan Schumaker 450703cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 45087df302f7SChuck Lever stateid->ts_id_status = 45097df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 451003cfb420SBryan Schumaker 451117456804SBryan Schumaker return nfs_ok; 451217456804SBryan Schumaker } 451317456804SBryan Schumaker 4514e1ca12dfSBryan Schumaker __be32 4515e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4516e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 4517e1ca12dfSBryan Schumaker { 4518e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 45192da1cec7SJ. Bruce Fields struct nfs4_stid *s; 45203bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 4521fc5a96c3SJeff Layton struct nfs4_ol_stateid *stp; 452238c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 45232da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 4524e1ca12dfSBryan Schumaker 45251af71cc8SJeff Layton spin_lock(&cl->cl_lock); 45261af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 45272da1cec7SJ. Bruce Fields if (!s) 45281af71cc8SJeff Layton goto out_unlock; 45292da1cec7SJ. Bruce Fields switch (s->sc_type) { 45302da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 4531e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 45321af71cc8SJeff Layton break; 45332da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 45341af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 45351af71cc8SJeff Layton if (ret) 45361af71cc8SJeff Layton break; 45371af71cc8SJeff Layton ret = nfserr_locks_held; 45381af71cc8SJeff Layton break; 45392da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 45402da1cec7SJ. Bruce Fields ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 45412da1cec7SJ. Bruce Fields if (ret) 4542f7a4d872SJ. Bruce Fields break; 4543fc5a96c3SJeff Layton stp = openlockstateid(s); 4544fc5a96c3SJeff Layton ret = nfserr_locks_held; 4545fc5a96c3SJeff Layton if (check_for_locks(stp->st_stid.sc_file, 4546fc5a96c3SJeff Layton lockowner(stp->st_stateowner))) 4547fc5a96c3SJeff Layton break; 4548fc5a96c3SJeff Layton unhash_lock_stateid(stp); 45491af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 4550fc5a96c3SJeff Layton nfs4_put_stid(s); 4551fc5a96c3SJeff Layton ret = nfs_ok; 45521af71cc8SJeff Layton goto out; 45533bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 45543bd64a5bSJ. Bruce Fields dp = delegstateid(s); 45552d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 45562d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 45576011695dSTrond Myklebust nfs4_put_stid(s); 45583bd64a5bSJ. Bruce Fields ret = nfs_ok; 45591af71cc8SJeff Layton goto out; 45601af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 4561e1ca12dfSBryan Schumaker } 45621af71cc8SJeff Layton out_unlock: 45631af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 4564e1ca12dfSBryan Schumaker out: 4565e1ca12dfSBryan Schumaker return ret; 4566e1ca12dfSBryan Schumaker } 4567e1ca12dfSBryan Schumaker 45684c4cd222SNeilBrown static inline int 45694c4cd222SNeilBrown setlkflg (int type) 45704c4cd222SNeilBrown { 45714c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 45724c4cd222SNeilBrown RD_STATE : WR_STATE; 45734c4cd222SNeilBrown } 45741da177e4SLinus Torvalds 4575dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 4576c0a5d93eSJ. Bruce Fields { 4577c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 4578c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 4579c0a5d93eSJ. Bruce Fields __be32 status; 4580c0a5d93eSJ. Bruce Fields 4581c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 4582c0a5d93eSJ. Bruce Fields if (status) 4583c0a5d93eSJ. Bruce Fields return status; 45843bd64a5bSJ. Bruce Fields if (stp->st_stid.sc_type == NFS4_CLOSED_STID 45853bd64a5bSJ. Bruce Fields || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4586f7a4d872SJ. Bruce Fields /* 4587f7a4d872SJ. Bruce Fields * "Closed" stateid's exist *only* to return 45883bd64a5bSJ. Bruce Fields * nfserr_replay_me from the previous step, and 45893bd64a5bSJ. Bruce Fields * revoked delegations are kept only for free_stateid. 4590f7a4d872SJ. Bruce Fields */ 4591f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4592f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 4593f7a4d872SJ. Bruce Fields if (status) 4594f7a4d872SJ. Bruce Fields return status; 4595f7a4d872SJ. Bruce Fields return nfs4_check_fh(current_fh, stp); 4596c0a5d93eSJ. Bruce Fields } 4597c0a5d93eSJ. Bruce Fields 45981da177e4SLinus Torvalds /* 45991da177e4SLinus Torvalds * Checks for sequence id mutating operations. 46001da177e4SLinus Torvalds */ 4601b37ad28bSAl Viro static __be32 4602dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 46032288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 46043320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 46053320fef1SStanislav Kinsbursky struct nfsd_net *nn) 46061da177e4SLinus Torvalds { 46070836f587SJ. Bruce Fields __be32 status; 460838c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 4609e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 46101da177e4SLinus Torvalds 46118c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 46128c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 46131da177e4SLinus Torvalds 46141da177e4SLinus Torvalds *stpp = NULL; 46152dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 4616c0a5d93eSJ. Bruce Fields if (status) 4617c0a5d93eSJ. Bruce Fields return status; 4618e17f99b7STrond Myklebust stp = openlockstateid(s); 461958fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 46201da177e4SLinus Torvalds 4621e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 4622fd911011STrond Myklebust if (!status) 4623e17f99b7STrond Myklebust *stpp = stp; 4624fd911011STrond Myklebust else 4625fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 4626e17f99b7STrond Myklebust return status; 46271da177e4SLinus Torvalds } 46281da177e4SLinus Torvalds 46293320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 46303320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 4631c0a5d93eSJ. Bruce Fields { 4632c0a5d93eSJ. Bruce Fields __be32 status; 4633c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 46344cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 46351da177e4SLinus Torvalds 4636c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 46374cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 46380836f587SJ. Bruce Fields if (status) 46390836f587SJ. Bruce Fields return status; 46404cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 46414cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 46424cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 4643c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 46444cbfc9f7STrond Myklebust } 46454cbfc9f7STrond Myklebust *stpp = stp; 46463a4f98bbSNeilBrown return nfs_ok; 46471da177e4SLinus Torvalds } 46481da177e4SLinus Torvalds 4649b37ad28bSAl Viro __be32 4650ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4651a4f1706aSJ.Bruce Fields struct nfsd4_open_confirm *oc) 46521da177e4SLinus Torvalds { 4653b37ad28bSAl Viro __be32 status; 4654fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 4655dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 46563320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 46571da177e4SLinus Torvalds 4658a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 4659a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 46601da177e4SLinus Torvalds 4661ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 4662a8cddc5dSJ. Bruce Fields if (status) 4663a8cddc5dSJ. Bruce Fields return status; 46641da177e4SLinus Torvalds 46659072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 4666ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 46673320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 46689072d5c6SJ. Bruce Fields if (status) 46691da177e4SLinus Torvalds goto out; 4670fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 467168b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 4672dad1c067SJ. Bruce Fields if (oo->oo_flags & NFS4_OO_CONFIRMED) 46732585fc79STrond Myklebust goto put_stateid; 4674dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 4675dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4676dcef0413SJ. Bruce Fields memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 46778c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 4678dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 4679c7b9a459SNeilBrown 46802a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 468168b66e82SJ. Bruce Fields status = nfs_ok; 46822585fc79STrond Myklebust put_stateid: 46832585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 46841da177e4SLinus Torvalds out: 46859411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 46861da177e4SLinus Torvalds return status; 46871da177e4SLinus Torvalds } 46881da177e4SLinus Torvalds 46896409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 46901da177e4SLinus Torvalds { 469182c5ff1bSJeff Layton if (!test_access(access, stp)) 46926409a5a6SJ. Bruce Fields return; 469311b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 469482c5ff1bSJeff Layton clear_access(access, stp); 4695f197c271SJ. Bruce Fields } 46966409a5a6SJ. Bruce Fields 46976409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 46986409a5a6SJ. Bruce Fields { 46996409a5a6SJ. Bruce Fields switch (to_access) { 47006409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 47016409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 47026409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 47036409a5a6SJ. Bruce Fields break; 47046409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 47056409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 47066409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 47076409a5a6SJ. Bruce Fields break; 47086409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 47096409a5a6SJ. Bruce Fields break; 47106409a5a6SJ. Bruce Fields default: 4711063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 47121da177e4SLinus Torvalds } 47131da177e4SLinus Torvalds } 47141da177e4SLinus Torvalds 4715b37ad28bSAl Viro __be32 4716ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 4717ca364317SJ.Bruce Fields struct nfsd4_compound_state *cstate, 4718a4f1706aSJ.Bruce Fields struct nfsd4_open_downgrade *od) 47191da177e4SLinus Torvalds { 4720b37ad28bSAl Viro __be32 status; 4721dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 47223320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 47231da177e4SLinus Torvalds 4724a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 4725a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 47261da177e4SLinus Torvalds 4727c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 47282c8bd7e0SBenny Halevy if (od->od_deleg_want) 47292c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 47302c8bd7e0SBenny Halevy od->od_deleg_want); 47311da177e4SLinus Torvalds 4732c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 47333320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 47349072d5c6SJ. Bruce Fields if (status) 47351da177e4SLinus Torvalds goto out; 47361da177e4SLinus Torvalds status = nfserr_inval; 473782c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 4738c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 47391da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 47400667b1e9STrond Myklebust goto put_stateid; 47411da177e4SLinus Torvalds } 4742ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 4743c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 47441da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 47450667b1e9STrond Myklebust goto put_stateid; 47461da177e4SLinus Torvalds } 47476409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 47481da177e4SLinus Torvalds 4749ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 47501da177e4SLinus Torvalds 4751dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4752dcef0413SJ. Bruce Fields memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 47531da177e4SLinus Torvalds status = nfs_ok; 47540667b1e9STrond Myklebust put_stateid: 47550667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 47561da177e4SLinus Torvalds out: 47579411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 47581da177e4SLinus Torvalds return status; 47591da177e4SLinus Torvalds } 47601da177e4SLinus Torvalds 4761f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 4762f7a4d872SJ. Bruce Fields { 4763acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 4764d83017f9SJeff Layton LIST_HEAD(reaplist); 4765acf9295bSTrond Myklebust 4766f7a4d872SJ. Bruce Fields s->st_stid.sc_type = NFS4_CLOSED_STID; 47672c41beb0SJeff Layton spin_lock(&clp->cl_lock); 4768d83017f9SJeff Layton unhash_open_stateid(s, &reaplist); 4769acf9295bSTrond Myklebust 4770d83017f9SJeff Layton if (clp->cl_minorversion) { 4771d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 4772d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 4773d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 4774d83017f9SJeff Layton } else { 4775d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 4776d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 4777d3134b10SJeff Layton move_to_close_lru(s, clp->net); 477838c387b5SJ. Bruce Fields } 4779d83017f9SJeff Layton } 478038c387b5SJ. Bruce Fields 47811da177e4SLinus Torvalds /* 47821da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 47831da177e4SLinus Torvalds */ 4784b37ad28bSAl Viro __be32 4785ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4786a4f1706aSJ.Bruce Fields struct nfsd4_close *close) 47871da177e4SLinus Torvalds { 4788b37ad28bSAl Viro __be32 status; 4789dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 47903320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 47913320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 47921da177e4SLinus Torvalds 4793a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 4794a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 47951da177e4SLinus Torvalds 4796f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 4797f7a4d872SJ. Bruce Fields &close->cl_stateid, 4798f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 47993320fef1SStanislav Kinsbursky &stp, nn); 48009411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 48019072d5c6SJ. Bruce Fields if (status) 48021da177e4SLinus Torvalds goto out; 4803dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4804dcef0413SJ. Bruce Fields memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 48051da177e4SLinus Torvalds 4806f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 48078a0b589dSTrond Myklebust 48088a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 48098a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 48101da177e4SLinus Torvalds out: 48111da177e4SLinus Torvalds return status; 48121da177e4SLinus Torvalds } 48131da177e4SLinus Torvalds 4814b37ad28bSAl Viro __be32 4815ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4816ca364317SJ.Bruce Fields struct nfsd4_delegreturn *dr) 48171da177e4SLinus Torvalds { 4818203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 4819203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 482038c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 4821b37ad28bSAl Viro __be32 status; 48223320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 48231da177e4SLinus Torvalds 4824ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 4825203a8c8eSJ. Bruce Fields return status; 48261da177e4SLinus Torvalds 48272dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 482838c2f4b1SJ. Bruce Fields if (status) 4829203a8c8eSJ. Bruce Fields goto out; 483038c2f4b1SJ. Bruce Fields dp = delegstateid(s); 4831d5477a8dSJ. Bruce Fields status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); 4832203a8c8eSJ. Bruce Fields if (status) 4833fd911011STrond Myklebust goto put_stateid; 4834203a8c8eSJ. Bruce Fields 48353bd64a5bSJ. Bruce Fields destroy_delegation(dp); 4836fd911011STrond Myklebust put_stateid: 4837fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 48381da177e4SLinus Torvalds out: 48391da177e4SLinus Torvalds return status; 48401da177e4SLinus Torvalds } 48411da177e4SLinus Torvalds 48421da177e4SLinus Torvalds 48431da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) 48441da177e4SLinus Torvalds 484587df4de8SBenny Halevy static inline u64 484687df4de8SBenny Halevy end_offset(u64 start, u64 len) 484787df4de8SBenny Halevy { 484887df4de8SBenny Halevy u64 end; 484987df4de8SBenny Halevy 485087df4de8SBenny Halevy end = start + len; 485187df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 485287df4de8SBenny Halevy } 485387df4de8SBenny Halevy 485487df4de8SBenny Halevy /* last octet in a range */ 485587df4de8SBenny Halevy static inline u64 485687df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 485787df4de8SBenny Halevy { 485887df4de8SBenny Halevy u64 end; 485987df4de8SBenny Halevy 4860063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 486187df4de8SBenny Halevy end = start + len; 486287df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 486387df4de8SBenny Halevy } 486487df4de8SBenny Halevy 48651da177e4SLinus Torvalds /* 48661da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 48671da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 48681da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 48691da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 48701da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 48711da177e4SLinus Torvalds * the VFS, but this is a very deep change! 48721da177e4SLinus Torvalds */ 48731da177e4SLinus Torvalds static inline void 48741da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 48751da177e4SLinus Torvalds { 48761da177e4SLinus Torvalds if (lock->fl_start < 0) 48771da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 48781da177e4SLinus Torvalds if (lock->fl_end < 0) 48791da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 48801da177e4SLinus Torvalds } 48811da177e4SLinus Torvalds 4882aef9583bSKinglong Mee static void nfsd4_fl_get_owner(struct file_lock *dst, struct file_lock *src) 4883aef9583bSKinglong Mee { 4884aef9583bSKinglong Mee struct nfs4_lockowner *lo = (struct nfs4_lockowner *)src->fl_owner; 4885aef9583bSKinglong Mee dst->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lo->lo_owner)); 4886aef9583bSKinglong Mee } 4887aef9583bSKinglong Mee 4888aef9583bSKinglong Mee static void nfsd4_fl_put_owner(struct file_lock *fl) 4889aef9583bSKinglong Mee { 4890aef9583bSKinglong Mee struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 4891aef9583bSKinglong Mee 4892aef9583bSKinglong Mee if (lo) { 4893aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 4894aef9583bSKinglong Mee fl->fl_owner = NULL; 4895aef9583bSKinglong Mee } 4896aef9583bSKinglong Mee } 4897aef9583bSKinglong Mee 48987b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 4899aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 4900aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 4901d5b9026aSNeilBrown }; 49021da177e4SLinus Torvalds 49031da177e4SLinus Torvalds static inline void 49041da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 49051da177e4SLinus Torvalds { 4906fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 49071da177e4SLinus Torvalds 4908d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 4909fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 4910fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 4911fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 49127c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 49137c13f344SJ. Bruce Fields /* We just don't care that much */ 49147c13f344SJ. Bruce Fields goto nevermind; 4915fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 4916fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 4917d5b9026aSNeilBrown } else { 49187c13f344SJ. Bruce Fields nevermind: 49197c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 49207c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 4921d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 4922d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 49231da177e4SLinus Torvalds } 49241da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 492587df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 492687df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 49271da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 49281da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 49291da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 49301da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 49311da177e4SLinus Torvalds } 49321da177e4SLinus Torvalds 4933fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 4934c58c6610STrond Myklebust find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner, 4935d4f0489fSTrond Myklebust struct nfs4_client *clp) 49361da177e4SLinus Torvalds { 4937d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 4938b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 49391da177e4SLinus Torvalds 49400a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 49410a880a28STrond Myklebust 4942d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 4943d4f0489fSTrond Myklebust so_strhash) { 4944b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 4945b3c32bcdSTrond Myklebust continue; 4946b5971afaSKinglong Mee if (same_owner_str(so, owner)) 4947b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 49481da177e4SLinus Torvalds } 49491da177e4SLinus Torvalds return NULL; 49501da177e4SLinus Torvalds } 49511da177e4SLinus Torvalds 4952c58c6610STrond Myklebust static struct nfs4_lockowner * 4953c58c6610STrond Myklebust find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner, 4954d4f0489fSTrond Myklebust struct nfs4_client *clp) 4955c58c6610STrond Myklebust { 4956c58c6610STrond Myklebust struct nfs4_lockowner *lo; 4957c58c6610STrond Myklebust 4958d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 4959d4f0489fSTrond Myklebust lo = find_lockowner_str_locked(clid, owner, clp); 4960d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 4961c58c6610STrond Myklebust return lo; 4962c58c6610STrond Myklebust } 4963c58c6610STrond Myklebust 49648f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 49658f4b54c5SJeff Layton { 4966c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 49678f4b54c5SJeff Layton } 49688f4b54c5SJeff Layton 49696b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 49706b180f0bSJeff Layton { 49716b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 49726b180f0bSJeff Layton 49736b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 49746b180f0bSJeff Layton } 49756b180f0bSJeff Layton 49766b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 49778f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 49786b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 49796b180f0bSJeff Layton }; 49806b180f0bSJeff Layton 49811da177e4SLinus Torvalds /* 49821da177e4SLinus Torvalds * Alloc a lock owner structure. 49831da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 498425985edcSLucas De Marchi * occurred. 49851da177e4SLinus Torvalds * 498616bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 49871da177e4SLinus Torvalds */ 4988fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 4989c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 4990c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 4991c58c6610STrond Myklebust struct nfsd4_lock *lock) 4992c58c6610STrond Myklebust { 4993c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 49941da177e4SLinus Torvalds 4995fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 4996fe0750e5SJ. Bruce Fields if (!lo) 49971da177e4SLinus Torvalds return NULL; 4998fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 4999fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 50005db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 50016b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 5002d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5003c58c6610STrond Myklebust ret = find_lockowner_str_locked(&clp->cl_clientid, 5004d4f0489fSTrond Myklebust &lock->lk_new_owner, clp); 5005c58c6610STrond Myklebust if (ret == NULL) { 5006c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 5007d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 5008c58c6610STrond Myklebust ret = lo; 5009c58c6610STrond Myklebust } else 5010c58c6610STrond Myklebust nfs4_free_lockowner(&lo->lo_owner); 5011d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5012fe0750e5SJ. Bruce Fields return lo; 50131da177e4SLinus Torvalds } 50141da177e4SLinus Torvalds 5015356a95ecSJeff Layton static void 5016356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 5017356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 5018f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 50191da177e4SLinus Torvalds { 5020d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 50211da177e4SLinus Torvalds 5022356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 5023356a95ecSJeff Layton 50243d0fabd5STrond Myklebust atomic_inc(&stp->st_stid.sc_count); 50253abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 5026b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 502713cd2184SNeilBrown get_nfs4_file(fp); 502811b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 5029b49e084dSJeff Layton stp->st_stid.sc_free = nfs4_free_lock_stateid; 50300997b173SJ. Bruce Fields stp->st_access_bmap = 0; 50311da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 50324c4cd222SNeilBrown stp->st_openstp = open_stp; 50333c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 50341c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 50351d31a253STrond Myklebust spin_lock(&fp->fi_lock); 50361d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 50371d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 50381da177e4SLinus Torvalds } 50391da177e4SLinus Torvalds 5040c53530daSJeff Layton static struct nfs4_ol_stateid * 5041c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) 5042c53530daSJeff Layton { 5043c53530daSJeff Layton struct nfs4_ol_stateid *lst; 5044356a95ecSJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 5045356a95ecSJeff Layton 5046356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 5047c53530daSJeff Layton 5048c53530daSJeff Layton list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { 50493d0fabd5STrond Myklebust if (lst->st_stid.sc_file == fp) { 50503d0fabd5STrond Myklebust atomic_inc(&lst->st_stid.sc_count); 5051c53530daSJeff Layton return lst; 5052c53530daSJeff Layton } 50533d0fabd5STrond Myklebust } 5054c53530daSJeff Layton return NULL; 5055c53530daSJeff Layton } 5056c53530daSJeff Layton 5057356a95ecSJeff Layton static struct nfs4_ol_stateid * 5058356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 5059356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 5060356a95ecSJeff Layton bool *new) 5061356a95ecSJeff Layton { 5062356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 5063356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 5064356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 5065356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 5066356a95ecSJeff Layton 5067356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5068356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5069356a95ecSJeff Layton if (lst == NULL) { 5070356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5071356a95ecSJeff Layton ns = nfs4_alloc_stid(clp, stateid_slab); 5072356a95ecSJeff Layton if (ns == NULL) 5073356a95ecSJeff Layton return NULL; 5074356a95ecSJeff Layton 5075356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5076356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5077356a95ecSJeff Layton if (likely(!lst)) { 5078356a95ecSJeff Layton lst = openlockstateid(ns); 5079356a95ecSJeff Layton init_lock_stateid(lst, lo, fi, inode, ost); 5080356a95ecSJeff Layton ns = NULL; 5081356a95ecSJeff Layton *new = true; 5082356a95ecSJeff Layton } 5083356a95ecSJeff Layton } 5084356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5085356a95ecSJeff Layton if (ns) 5086356a95ecSJeff Layton nfs4_put_stid(ns); 5087356a95ecSJeff Layton return lst; 5088356a95ecSJeff Layton } 5089c53530daSJeff Layton 5090fd39ca9aSNeilBrown static int 50911da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 50921da177e4SLinus Torvalds { 509387df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 50941da177e4SLinus Torvalds LOFF_OVERFLOW(offset, length))); 50951da177e4SLinus Torvalds } 50961da177e4SLinus Torvalds 5097dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 50980997b173SJ. Bruce Fields { 509911b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 51000997b173SJ. Bruce Fields 51017214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 51027214e860SJeff Layton 510382c5ff1bSJeff Layton if (test_access(access, lock_stp)) 51040997b173SJ. Bruce Fields return; 510512659651SJeff Layton __nfs4_file_get_access(fp, access); 510682c5ff1bSJeff Layton set_access(access, lock_stp); 51070997b173SJ. Bruce Fields } 51080997b173SJ. Bruce Fields 5109356a95ecSJeff Layton static __be32 5110356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 5111356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 5112356a95ecSJeff Layton struct nfsd4_lock *lock, 5113356a95ecSJeff Layton struct nfs4_ol_stateid **lst, bool *new) 511464a284d0SJ. Bruce Fields { 51155db1c03fSJeff Layton __be32 status; 511611b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 511764a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 511864a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 5119f9c00c3aSJeff Layton struct inode *inode = cstate->current_fh.fh_dentry->d_inode; 512064a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 512164a284d0SJ. Bruce Fields unsigned int strhashval; 512264a284d0SJ. Bruce Fields 5123d4f0489fSTrond Myklebust lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, cl); 5124c53530daSJeff Layton if (!lo) { 5125d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&lock->v.new.owner); 512664a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 512764a284d0SJ. Bruce Fields if (lo == NULL) 512864a284d0SJ. Bruce Fields return nfserr_jukebox; 5129c53530daSJeff Layton } else { 5130c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 51315db1c03fSJeff Layton status = nfserr_bad_seqid; 5132c53530daSJeff Layton if (!cstate->minorversion && 5133c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 51345db1c03fSJeff Layton goto out; 5135c53530daSJeff Layton } 5136c53530daSJeff Layton 5137356a95ecSJeff Layton *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 513864a284d0SJ. Bruce Fields if (*lst == NULL) { 51395db1c03fSJeff Layton status = nfserr_jukebox; 51405db1c03fSJeff Layton goto out; 514164a284d0SJ. Bruce Fields } 51425db1c03fSJeff Layton status = nfs_ok; 51435db1c03fSJeff Layton out: 51445db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 51455db1c03fSJeff Layton return status; 514664a284d0SJ. Bruce Fields } 514764a284d0SJ. Bruce Fields 51481da177e4SLinus Torvalds /* 51491da177e4SLinus Torvalds * LOCK operation 51501da177e4SLinus Torvalds */ 5151b37ad28bSAl Viro __be32 5152ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5153a4f1706aSJ.Bruce Fields struct nfsd4_lock *lock) 51541da177e4SLinus Torvalds { 5155fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 5156fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 51573d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 51580667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 51597214e860SJeff Layton struct nfs4_file *fp; 51607d947842SJ. Bruce Fields struct file *filp = NULL; 516121179d81SJeff Layton struct file_lock *file_lock = NULL; 516221179d81SJeff Layton struct file_lock *conflock = NULL; 5163b37ad28bSAl Viro __be32 status = 0; 5164b34f27aaSJ. Bruce Fields int lkflg; 5165b8dd7b9aSAl Viro int err; 51665db1c03fSJeff Layton bool new = false; 51673320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 51683320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 51691da177e4SLinus Torvalds 51701da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 51711da177e4SLinus Torvalds (long long) lock->lk_offset, 51721da177e4SLinus Torvalds (long long) lock->lk_length); 51731da177e4SLinus Torvalds 51741da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 51751da177e4SLinus Torvalds return nfserr_inval; 51761da177e4SLinus Torvalds 5177ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 51788837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 5179a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 5180a6f6ef2fSAndy Adamson return status; 5181a6f6ef2fSAndy Adamson } 5182a6f6ef2fSAndy Adamson 51831da177e4SLinus Torvalds if (lock->lk_is_new) { 5184684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 5185684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 5186684e5638SJ. Bruce Fields memcpy(&lock->v.new.clientid, 5187684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 5188684e5638SJ. Bruce Fields sizeof(clientid_t)); 5189684e5638SJ. Bruce Fields 51901da177e4SLinus Torvalds status = nfserr_stale_clientid; 51912c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 51921da177e4SLinus Torvalds goto out; 51931da177e4SLinus Torvalds 51941da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 5195c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 51961da177e4SLinus Torvalds lock->lk_new_open_seqid, 51971da177e4SLinus Torvalds &lock->lk_new_open_stateid, 51983320fef1SStanislav Kinsbursky &open_stp, nn); 519937515177SNeilBrown if (status) 52001da177e4SLinus Torvalds goto out; 5201fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 5202b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 5203684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 5204b34f27aaSJ. Bruce Fields &lock->v.new.clientid)) 5205b34f27aaSJ. Bruce Fields goto out; 520664a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 52075db1c03fSJeff Layton &lock_stp, &new); 52083d0fabd5STrond Myklebust } else { 5209dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 52101da177e4SLinus Torvalds lock->lk_old_lock_seqid, 52111da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 52123320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 52133d0fabd5STrond Myklebust } 52141da177e4SLinus Torvalds if (status) 52151da177e4SLinus Torvalds goto out; 5216fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 52171da177e4SLinus Torvalds 5218b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 5219b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 5220b34f27aaSJ. Bruce Fields if (status) 5221b34f27aaSJ. Bruce Fields goto out; 5222b34f27aaSJ. Bruce Fields 52230dd395dcSNeilBrown status = nfserr_grace; 52243320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 52250dd395dcSNeilBrown goto out; 52260dd395dcSNeilBrown status = nfserr_no_grace; 52273320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 52280dd395dcSNeilBrown goto out; 52290dd395dcSNeilBrown 523021179d81SJeff Layton file_lock = locks_alloc_lock(); 523121179d81SJeff Layton if (!file_lock) { 523221179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 523321179d81SJeff Layton status = nfserr_jukebox; 523421179d81SJeff Layton goto out; 523521179d81SJeff Layton } 523621179d81SJeff Layton 523711b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 52381da177e4SLinus Torvalds switch (lock->lk_type) { 52391da177e4SLinus Torvalds case NFS4_READ_LT: 52401da177e4SLinus Torvalds case NFS4_READW_LT: 52417214e860SJeff Layton spin_lock(&fp->fi_lock); 52427214e860SJeff Layton filp = find_readable_file_locked(fp); 52430997b173SJ. Bruce Fields if (filp) 52440997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 52457214e860SJeff Layton spin_unlock(&fp->fi_lock); 524621179d81SJeff Layton file_lock->fl_type = F_RDLCK; 52471da177e4SLinus Torvalds break; 52481da177e4SLinus Torvalds case NFS4_WRITE_LT: 52491da177e4SLinus Torvalds case NFS4_WRITEW_LT: 52507214e860SJeff Layton spin_lock(&fp->fi_lock); 52517214e860SJeff Layton filp = find_writeable_file_locked(fp); 52520997b173SJ. Bruce Fields if (filp) 52530997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 52547214e860SJeff Layton spin_unlock(&fp->fi_lock); 525521179d81SJeff Layton file_lock->fl_type = F_WRLCK; 52561da177e4SLinus Torvalds break; 52571da177e4SLinus Torvalds default: 52581da177e4SLinus Torvalds status = nfserr_inval; 52591da177e4SLinus Torvalds goto out; 52601da177e4SLinus Torvalds } 5261f9d7562fSJ. Bruce Fields if (!filp) { 5262f9d7562fSJ. Bruce Fields status = nfserr_openmode; 5263f9d7562fSJ. Bruce Fields goto out; 5264f9d7562fSJ. Bruce Fields } 5265aef9583bSKinglong Mee 5266aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 526721179d81SJeff Layton file_lock->fl_pid = current->tgid; 526821179d81SJeff Layton file_lock->fl_file = filp; 526921179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 527021179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 527121179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 527221179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 527321179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 52741da177e4SLinus Torvalds 527521179d81SJeff Layton conflock = locks_alloc_lock(); 527621179d81SJeff Layton if (!conflock) { 527721179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 527821179d81SJeff Layton status = nfserr_jukebox; 527921179d81SJeff Layton goto out; 528021179d81SJeff Layton } 52811da177e4SLinus Torvalds 528221179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); 5283b8dd7b9aSAl Viro switch (-err) { 52841da177e4SLinus Torvalds case 0: /* success! */ 5285dcef0413SJ. Bruce Fields update_stateid(&lock_stp->st_stid.sc_stateid); 5286dcef0413SJ. Bruce Fields memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, 52871da177e4SLinus Torvalds sizeof(stateid_t)); 5288b8dd7b9aSAl Viro status = 0; 5289eb76b3fdSAndy Adamson break; 5290eb76b3fdSAndy Adamson case (EAGAIN): /* conflock holds conflicting lock */ 5291eb76b3fdSAndy Adamson status = nfserr_denied; 5292eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 529321179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 5294eb76b3fdSAndy Adamson break; 52951da177e4SLinus Torvalds case (EDEADLK): 52961da177e4SLinus Torvalds status = nfserr_deadlock; 5297eb76b3fdSAndy Adamson break; 52981da177e4SLinus Torvalds default: 5299fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 53003e772463SJ. Bruce Fields status = nfserrno(err); 5301eb76b3fdSAndy Adamson break; 53021da177e4SLinus Torvalds } 53031da177e4SLinus Torvalds out: 5304de18643dSTrond Myklebust if (filp) 5305de18643dSTrond Myklebust fput(filp); 53065db1c03fSJeff Layton if (lock_stp) { 53075db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 53085db1c03fSJeff Layton if (cstate->replay_owner && 53095db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 53105db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 53115db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 53125db1c03fSJeff Layton 53135db1c03fSJeff Layton /* 53145db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 53155db1c03fSJeff Layton * returning an error, then just go ahead and release it. 53165db1c03fSJeff Layton */ 53175db1c03fSJeff Layton if (status && new) 53185db1c03fSJeff Layton release_lock_stateid(lock_stp); 53195db1c03fSJeff Layton 53203d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 53215db1c03fSJeff Layton } 53220667b1e9STrond Myklebust if (open_stp) 53230667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 53249411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 532521179d81SJeff Layton if (file_lock) 532621179d81SJeff Layton locks_free_lock(file_lock); 532721179d81SJeff Layton if (conflock) 532821179d81SJeff Layton locks_free_lock(conflock); 53291da177e4SLinus Torvalds return status; 53301da177e4SLinus Torvalds } 53311da177e4SLinus Torvalds 53321da177e4SLinus Torvalds /* 533355ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 533455ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 533555ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 533655ef1274SJ. Bruce Fields * inode operation.) 533755ef1274SJ. Bruce Fields */ 533804da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 533955ef1274SJ. Bruce Fields { 534055ef1274SJ. Bruce Fields struct file *file; 534104da6e9dSAl Viro __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 534204da6e9dSAl Viro if (!err) { 534304da6e9dSAl Viro err = nfserrno(vfs_test_lock(file, lock)); 534455ef1274SJ. Bruce Fields nfsd_close(file); 534504da6e9dSAl Viro } 534655ef1274SJ. Bruce Fields return err; 534755ef1274SJ. Bruce Fields } 534855ef1274SJ. Bruce Fields 534955ef1274SJ. Bruce Fields /* 53501da177e4SLinus Torvalds * LOCKT operation 53511da177e4SLinus Torvalds */ 5352b37ad28bSAl Viro __be32 5353ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5354ca364317SJ.Bruce Fields struct nfsd4_lockt *lockt) 53551da177e4SLinus Torvalds { 535621179d81SJeff Layton struct file_lock *file_lock = NULL; 53575db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 5358b37ad28bSAl Viro __be32 status; 53597f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 53601da177e4SLinus Torvalds 53615ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 53621da177e4SLinus Torvalds return nfserr_grace; 53631da177e4SLinus Torvalds 53641da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 53651da177e4SLinus Torvalds return nfserr_inval; 53661da177e4SLinus Torvalds 53679b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 53684b24ca7dSJeff Layton status = lookup_clientid(&lockt->lt_clientid, cstate, nn); 53699b2ef62bSJ. Bruce Fields if (status) 53701da177e4SLinus Torvalds goto out; 53719b2ef62bSJ. Bruce Fields } 53721da177e4SLinus Torvalds 537375c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 53741da177e4SLinus Torvalds goto out; 53751da177e4SLinus Torvalds 537621179d81SJeff Layton file_lock = locks_alloc_lock(); 537721179d81SJeff Layton if (!file_lock) { 537821179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 537921179d81SJeff Layton status = nfserr_jukebox; 538021179d81SJeff Layton goto out; 538121179d81SJeff Layton } 53826cd90662SKinglong Mee 53831da177e4SLinus Torvalds switch (lockt->lt_type) { 53841da177e4SLinus Torvalds case NFS4_READ_LT: 53851da177e4SLinus Torvalds case NFS4_READW_LT: 538621179d81SJeff Layton file_lock->fl_type = F_RDLCK; 53871da177e4SLinus Torvalds break; 53881da177e4SLinus Torvalds case NFS4_WRITE_LT: 53891da177e4SLinus Torvalds case NFS4_WRITEW_LT: 539021179d81SJeff Layton file_lock->fl_type = F_WRLCK; 53911da177e4SLinus Torvalds break; 53921da177e4SLinus Torvalds default: 53932fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 53941da177e4SLinus Torvalds status = nfserr_inval; 53951da177e4SLinus Torvalds goto out; 53961da177e4SLinus Torvalds } 53971da177e4SLinus Torvalds 5398d4f0489fSTrond Myklebust lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner, 5399d4f0489fSTrond Myklebust cstate->clp); 5400fe0750e5SJ. Bruce Fields if (lo) 540121179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 540221179d81SJeff Layton file_lock->fl_pid = current->tgid; 540321179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 54041da177e4SLinus Torvalds 540521179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 540621179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 54071da177e4SLinus Torvalds 540821179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 54091da177e4SLinus Torvalds 541021179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 541104da6e9dSAl Viro if (status) 5412fd85b817SMarc Eshel goto out; 541304da6e9dSAl Viro 541421179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 54151da177e4SLinus Torvalds status = nfserr_denied; 541621179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 54171da177e4SLinus Torvalds } 54181da177e4SLinus Torvalds out: 54195db1c03fSJeff Layton if (lo) 54205db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 542121179d81SJeff Layton if (file_lock) 542221179d81SJeff Layton locks_free_lock(file_lock); 54231da177e4SLinus Torvalds return status; 54241da177e4SLinus Torvalds } 54251da177e4SLinus Torvalds 5426b37ad28bSAl Viro __be32 5427ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5428a4f1706aSJ.Bruce Fields struct nfsd4_locku *locku) 54291da177e4SLinus Torvalds { 5430dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 54311da177e4SLinus Torvalds struct file *filp = NULL; 543221179d81SJeff Layton struct file_lock *file_lock = NULL; 5433b37ad28bSAl Viro __be32 status; 5434b8dd7b9aSAl Viro int err; 54353320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 54361da177e4SLinus Torvalds 54371da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 54381da177e4SLinus Torvalds (long long) locku->lu_offset, 54391da177e4SLinus Torvalds (long long) locku->lu_length); 54401da177e4SLinus Torvalds 54411da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 54421da177e4SLinus Torvalds return nfserr_inval; 54431da177e4SLinus Torvalds 54449072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 54453320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 54463320fef1SStanislav Kinsbursky &stp, nn); 54479072d5c6SJ. Bruce Fields if (status) 54481da177e4SLinus Torvalds goto out; 544911b9164aSTrond Myklebust filp = find_any_file(stp->st_stid.sc_file); 5450f9d7562fSJ. Bruce Fields if (!filp) { 5451f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 5452858cc573STrond Myklebust goto put_stateid; 5453f9d7562fSJ. Bruce Fields } 545421179d81SJeff Layton file_lock = locks_alloc_lock(); 545521179d81SJeff Layton if (!file_lock) { 545621179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 545721179d81SJeff Layton status = nfserr_jukebox; 5458de18643dSTrond Myklebust goto fput; 545921179d81SJeff Layton } 54606cd90662SKinglong Mee 546121179d81SJeff Layton file_lock->fl_type = F_UNLCK; 5462aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 546321179d81SJeff Layton file_lock->fl_pid = current->tgid; 546421179d81SJeff Layton file_lock->fl_file = filp; 546521179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 546621179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 546721179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 54681da177e4SLinus Torvalds 546921179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 547021179d81SJeff Layton locku->lu_length); 547121179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 54721da177e4SLinus Torvalds 547321179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); 5474b8dd7b9aSAl Viro if (err) { 5475fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 54761da177e4SLinus Torvalds goto out_nfserr; 54771da177e4SLinus Torvalds } 5478dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 5479dcef0413SJ. Bruce Fields memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 5480de18643dSTrond Myklebust fput: 5481de18643dSTrond Myklebust fput(filp); 5482858cc573STrond Myklebust put_stateid: 5483858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 54841da177e4SLinus Torvalds out: 54859411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 548621179d81SJeff Layton if (file_lock) 548721179d81SJeff Layton locks_free_lock(file_lock); 54881da177e4SLinus Torvalds return status; 54891da177e4SLinus Torvalds 54901da177e4SLinus Torvalds out_nfserr: 5491b8dd7b9aSAl Viro status = nfserrno(err); 5492de18643dSTrond Myklebust goto fput; 54931da177e4SLinus Torvalds } 54941da177e4SLinus Torvalds 54951da177e4SLinus Torvalds /* 54961da177e4SLinus Torvalds * returns 5497f9c00c3aSJeff Layton * true: locks held by lockowner 5498f9c00c3aSJeff Layton * false: no locks held by lockowner 54991da177e4SLinus Torvalds */ 5500f9c00c3aSJeff Layton static bool 5501f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 55021da177e4SLinus Torvalds { 55031da177e4SLinus Torvalds struct file_lock **flpp; 5504f9c00c3aSJeff Layton int status = false; 5505f9c00c3aSJeff Layton struct file *filp = find_any_file(fp); 5506f9c00c3aSJeff Layton struct inode *inode; 5507f9c00c3aSJeff Layton 5508f9c00c3aSJeff Layton if (!filp) { 5509f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 5510f9c00c3aSJeff Layton WARN_ON_ONCE(1); 5511f9c00c3aSJeff Layton return status; 5512f9c00c3aSJeff Layton } 5513f9c00c3aSJeff Layton 5514f9c00c3aSJeff Layton inode = file_inode(filp); 55151da177e4SLinus Torvalds 55161c8c601aSJeff Layton spin_lock(&inode->i_lock); 55171da177e4SLinus Torvalds for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { 5518796dadfdSJ. Bruce Fields if ((*flpp)->fl_owner == (fl_owner_t)lowner) { 5519f9c00c3aSJeff Layton status = true; 5520f9c00c3aSJeff Layton break; 55211da177e4SLinus Torvalds } 5522796dadfdSJ. Bruce Fields } 55231c8c601aSJeff Layton spin_unlock(&inode->i_lock); 5524f9c00c3aSJeff Layton fput(filp); 55251da177e4SLinus Torvalds return status; 55261da177e4SLinus Torvalds } 55271da177e4SLinus Torvalds 5528b37ad28bSAl Viro __be32 5529b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 5530b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 5531b591480bSJ.Bruce Fields struct nfsd4_release_lockowner *rlockowner) 55321da177e4SLinus Torvalds { 55331da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 5534882e9d25SJeff Layton struct nfs4_stateowner *sop; 5535882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 5536dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 55371da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 5538d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 5539b37ad28bSAl Viro __be32 status; 55407f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5541c58c6610STrond Myklebust struct nfs4_client *clp; 55421da177e4SLinus Torvalds 55431da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 55441da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 55451da177e4SLinus Torvalds 55464b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 55479b2ef62bSJ. Bruce Fields if (status) 554851f5e783STrond Myklebust return status; 55499b2ef62bSJ. Bruce Fields 5550d4f0489fSTrond Myklebust clp = cstate->clp; 5551fd44907cSJeff Layton /* Find the matching lock stateowner */ 5552d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5553882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 5554d4f0489fSTrond Myklebust so_strhash) { 5555882e9d25SJeff Layton 5556882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 555716bfdaafSJ. Bruce Fields continue; 5558882e9d25SJeff Layton 5559882e9d25SJeff Layton /* see if there are still any locks associated with it */ 5560882e9d25SJeff Layton lo = lockowner(sop); 5561882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 5562882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 5563882e9d25SJeff Layton status = nfserr_locks_held; 5564882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 556551f5e783STrond Myklebust return status; 5566882e9d25SJeff Layton } 5567882e9d25SJeff Layton } 5568882e9d25SJeff Layton 5569b5971afaSKinglong Mee nfs4_get_stateowner(sop); 5570fd44907cSJeff Layton break; 5571fd44907cSJeff Layton } 5572d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5573882e9d25SJeff Layton if (lo) 5574fe0750e5SJ. Bruce Fields release_lockowner(lo); 55751da177e4SLinus Torvalds return status; 55761da177e4SLinus Torvalds } 55771da177e4SLinus Torvalds 55781da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 5579a55370a3SNeilBrown alloc_reclaim(void) 55801da177e4SLinus Torvalds { 5581a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 55821da177e4SLinus Torvalds } 55831da177e4SLinus Torvalds 55840ce0c2b5SJeff Layton bool 558552e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 5586c7b9a459SNeilBrown { 55870ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 5588c7b9a459SNeilBrown 558952e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 55900ce0c2b5SJeff Layton return (crp && crp->cr_clp); 5591c7b9a459SNeilBrown } 5592c7b9a459SNeilBrown 55931da177e4SLinus Torvalds /* 55941da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 55951da177e4SLinus Torvalds */ 5596772a9bbbSJeff Layton struct nfs4_client_reclaim * 559752e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 55981da177e4SLinus Torvalds { 55991da177e4SLinus Torvalds unsigned int strhashval; 5600772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 56011da177e4SLinus Torvalds 5602a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 5603a55370a3SNeilBrown crp = alloc_reclaim(); 5604772a9bbbSJeff Layton if (crp) { 5605a55370a3SNeilBrown strhashval = clientstr_hashval(name); 56061da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 560752e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 5608a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 56090ce0c2b5SJeff Layton crp->cr_clp = NULL; 561052e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 5611772a9bbbSJeff Layton } 5612772a9bbbSJeff Layton return crp; 56131da177e4SLinus Torvalds } 56141da177e4SLinus Torvalds 56152a4317c5SJeff Layton void 561652e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 5617ce30e539SJeff Layton { 5618ce30e539SJeff Layton list_del(&crp->cr_strhash); 5619ce30e539SJeff Layton kfree(crp); 562052e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 5621ce30e539SJeff Layton } 5622ce30e539SJeff Layton 5623ce30e539SJeff Layton void 562452e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 56251da177e4SLinus Torvalds { 56261da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 56271da177e4SLinus Torvalds int i; 56281da177e4SLinus Torvalds 56291da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 563052e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 563152e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 56321da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 563352e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 56341da177e4SLinus Torvalds } 56351da177e4SLinus Torvalds } 5636063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 56371da177e4SLinus Torvalds } 56381da177e4SLinus Torvalds 56391da177e4SLinus Torvalds /* 56401da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 56412a4317c5SJeff Layton struct nfs4_client_reclaim * 564252e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 56431da177e4SLinus Torvalds { 56441da177e4SLinus Torvalds unsigned int strhashval; 56451da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 56461da177e4SLinus Torvalds 5647278c931cSJeff Layton dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 56481da177e4SLinus Torvalds 5649278c931cSJeff Layton strhashval = clientstr_hashval(recdir); 565052e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 5651278c931cSJeff Layton if (same_name(crp->cr_recdir, recdir)) { 56521da177e4SLinus Torvalds return crp; 56531da177e4SLinus Torvalds } 56541da177e4SLinus Torvalds } 56551da177e4SLinus Torvalds return NULL; 56561da177e4SLinus Torvalds } 56571da177e4SLinus Torvalds 56581da177e4SLinus Torvalds /* 56591da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 56601da177e4SLinus Torvalds */ 5661b37ad28bSAl Viro __be32 56620fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 56630fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 56640fe492dbSTrond Myklebust struct nfsd_net *nn) 56651da177e4SLinus Torvalds { 56660fe492dbSTrond Myklebust __be32 status; 5667a52d726bSJeff Layton 5668a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 56690fe492dbSTrond Myklebust status = lookup_clientid(clid, cstate, nn); 56700fe492dbSTrond Myklebust if (status) 5671a52d726bSJeff Layton return nfserr_reclaim_bad; 5672a52d726bSJeff Layton 56730fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 56740fe492dbSTrond Myklebust return nfserr_reclaim_bad; 56750fe492dbSTrond Myklebust 56760fe492dbSTrond Myklebust return nfs_ok; 56771da177e4SLinus Torvalds } 56781da177e4SLinus Torvalds 567965178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 5680016200c3SJeff Layton static inline void 5681016200c3SJeff Layton put_client(struct nfs4_client *clp) 5682016200c3SJeff Layton { 5683016200c3SJeff Layton atomic_dec(&clp->cl_refcount); 5684016200c3SJeff Layton } 5685016200c3SJeff Layton 5686285abdeeSJeff Layton static struct nfs4_client * 5687285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 5688285abdeeSJeff Layton { 5689285abdeeSJeff Layton struct nfs4_client *clp; 5690285abdeeSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5691285abdeeSJeff Layton nfsd_net_id); 5692285abdeeSJeff Layton 5693285abdeeSJeff Layton if (!nfsd_netns_ready(nn)) 5694285abdeeSJeff Layton return NULL; 5695285abdeeSJeff Layton 5696285abdeeSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 5697285abdeeSJeff Layton if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 5698285abdeeSJeff Layton return clp; 5699285abdeeSJeff Layton } 5700285abdeeSJeff Layton return NULL; 5701285abdeeSJeff Layton } 5702285abdeeSJeff Layton 57037ec0e36fSJeff Layton u64 5704285abdeeSJeff Layton nfsd_inject_print_clients(void) 57057ec0e36fSJeff Layton { 57067ec0e36fSJeff Layton struct nfs4_client *clp; 57077ec0e36fSJeff Layton u64 count = 0; 57087ec0e36fSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 57097ec0e36fSJeff Layton nfsd_net_id); 57107ec0e36fSJeff Layton char buf[INET6_ADDRSTRLEN]; 57117ec0e36fSJeff Layton 57127ec0e36fSJeff Layton if (!nfsd_netns_ready(nn)) 57137ec0e36fSJeff Layton return 0; 57147ec0e36fSJeff Layton 57157ec0e36fSJeff Layton spin_lock(&nn->client_lock); 57167ec0e36fSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 57177ec0e36fSJeff Layton rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 57187ec0e36fSJeff Layton pr_info("NFS Client: %s\n", buf); 57197ec0e36fSJeff Layton ++count; 57207ec0e36fSJeff Layton } 57217ec0e36fSJeff Layton spin_unlock(&nn->client_lock); 57227ec0e36fSJeff Layton 57237ec0e36fSJeff Layton return count; 57247ec0e36fSJeff Layton } 572565178db4SBryan Schumaker 5726a0926d15SJeff Layton u64 5727285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) 5728a0926d15SJeff Layton { 5729a0926d15SJeff Layton u64 count = 0; 5730a0926d15SJeff Layton struct nfs4_client *clp; 5731a0926d15SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5732a0926d15SJeff Layton nfsd_net_id); 5733a0926d15SJeff Layton 5734a0926d15SJeff Layton if (!nfsd_netns_ready(nn)) 5735a0926d15SJeff Layton return count; 5736a0926d15SJeff Layton 5737a0926d15SJeff Layton spin_lock(&nn->client_lock); 5738a0926d15SJeff Layton clp = nfsd_find_client(addr, addr_size); 5739a0926d15SJeff Layton if (clp) { 5740a0926d15SJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) 5741a0926d15SJeff Layton ++count; 5742a0926d15SJeff Layton else 5743a0926d15SJeff Layton clp = NULL; 5744a0926d15SJeff Layton } 5745a0926d15SJeff Layton spin_unlock(&nn->client_lock); 5746a0926d15SJeff Layton 5747a0926d15SJeff Layton if (clp) 5748a0926d15SJeff Layton expire_client(clp); 5749a0926d15SJeff Layton 5750a0926d15SJeff Layton return count; 5751a0926d15SJeff Layton } 5752a0926d15SJeff Layton 575369fc9edfSJeff Layton u64 5754285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max) 575569fc9edfSJeff Layton { 575669fc9edfSJeff Layton u64 count = 0; 575769fc9edfSJeff Layton struct nfs4_client *clp, *next; 575869fc9edfSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 575969fc9edfSJeff Layton nfsd_net_id); 576069fc9edfSJeff Layton LIST_HEAD(reaplist); 576169fc9edfSJeff Layton 576269fc9edfSJeff Layton if (!nfsd_netns_ready(nn)) 576369fc9edfSJeff Layton return count; 576469fc9edfSJeff Layton 576569fc9edfSJeff Layton spin_lock(&nn->client_lock); 576669fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 576769fc9edfSJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) { 576869fc9edfSJeff Layton list_add(&clp->cl_lru, &reaplist); 576969fc9edfSJeff Layton if (max != 0 && ++count >= max) 577069fc9edfSJeff Layton break; 577169fc9edfSJeff Layton } 577269fc9edfSJeff Layton } 577369fc9edfSJeff Layton spin_unlock(&nn->client_lock); 577469fc9edfSJeff Layton 577569fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &reaplist, cl_lru) 577669fc9edfSJeff Layton expire_client(clp); 577769fc9edfSJeff Layton 577869fc9edfSJeff Layton return count; 577969fc9edfSJeff Layton } 578069fc9edfSJeff Layton 5781184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 5782184c1847SBryan Schumaker const char *type) 5783184c1847SBryan Schumaker { 5784184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 57850a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 5786184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 5787184c1847SBryan Schumaker } 5788184c1847SBryan Schumaker 5789016200c3SJeff Layton static void 5790016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, 5791016200c3SJeff Layton struct list_head *collect) 5792016200c3SJeff Layton { 5793016200c3SJeff Layton struct nfs4_client *clp = lst->st_stid.sc_client; 5794016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5795016200c3SJeff Layton nfsd_net_id); 5796016200c3SJeff Layton 5797016200c3SJeff Layton if (!collect) 5798016200c3SJeff Layton return; 5799016200c3SJeff Layton 5800016200c3SJeff Layton lockdep_assert_held(&nn->client_lock); 5801016200c3SJeff Layton atomic_inc(&clp->cl_refcount); 5802016200c3SJeff Layton list_add(&lst->st_locks, collect); 5803016200c3SJeff Layton } 5804016200c3SJeff Layton 58053c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 58063738d50eSJeff Layton struct list_head *collect, 58073c87b9b7STrond Myklebust void (*func)(struct nfs4_ol_stateid *)) 5808fc29171fSBryan Schumaker { 5809fc29171fSBryan Schumaker struct nfs4_openowner *oop; 5810fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 58113c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 5812fc29171fSBryan Schumaker u64 count = 0; 5813fc29171fSBryan Schumaker 5814016200c3SJeff Layton spin_lock(&clp->cl_lock); 5815fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 58163c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 58173c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 58183c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 58193c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 58203738d50eSJeff Layton if (func) { 58213c87b9b7STrond Myklebust func(lst); 5822016200c3SJeff Layton nfsd_inject_add_lock_to_list(lst, 58233738d50eSJeff Layton collect); 58243738d50eSJeff Layton } 5825016200c3SJeff Layton ++count; 5826016200c3SJeff Layton /* 5827016200c3SJeff Layton * Despite the fact that these functions deal 5828016200c3SJeff Layton * with 64-bit integers for "count", we must 5829016200c3SJeff Layton * ensure that it doesn't blow up the 5830016200c3SJeff Layton * clp->cl_refcount. Throw a warning if we 5831016200c3SJeff Layton * start to approach INT_MAX here. 5832016200c3SJeff Layton */ 5833016200c3SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 5834016200c3SJeff Layton if (count == max) 5835016200c3SJeff Layton goto out; 5836fc29171fSBryan Schumaker } 5837fc29171fSBryan Schumaker } 5838fc29171fSBryan Schumaker } 5839016200c3SJeff Layton out: 5840016200c3SJeff Layton spin_unlock(&clp->cl_lock); 5841fc29171fSBryan Schumaker 5842fc29171fSBryan Schumaker return count; 5843fc29171fSBryan Schumaker } 5844fc29171fSBryan Schumaker 5845016200c3SJeff Layton static u64 5846016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, 5847016200c3SJeff Layton u64 max) 5848fc29171fSBryan Schumaker { 5849016200c3SJeff Layton return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); 5850fc29171fSBryan Schumaker } 5851fc29171fSBryan Schumaker 5852016200c3SJeff Layton static u64 5853016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp) 5854184c1847SBryan Schumaker { 5855016200c3SJeff Layton u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); 5856184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 5857184c1847SBryan Schumaker return count; 5858184c1847SBryan Schumaker } 5859184c1847SBryan Schumaker 5860016200c3SJeff Layton u64 5861285abdeeSJeff Layton nfsd_inject_print_locks(void) 5862016200c3SJeff Layton { 5863016200c3SJeff Layton struct nfs4_client *clp; 5864016200c3SJeff Layton u64 count = 0; 5865016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5866016200c3SJeff Layton nfsd_net_id); 5867016200c3SJeff Layton 5868016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 5869016200c3SJeff Layton return 0; 5870016200c3SJeff Layton 5871016200c3SJeff Layton spin_lock(&nn->client_lock); 5872016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 5873016200c3SJeff Layton count += nfsd_print_client_locks(clp); 5874016200c3SJeff Layton spin_unlock(&nn->client_lock); 5875016200c3SJeff Layton 5876016200c3SJeff Layton return count; 5877016200c3SJeff Layton } 5878016200c3SJeff Layton 5879016200c3SJeff Layton static void 5880016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist) 5881016200c3SJeff Layton { 5882016200c3SJeff Layton struct nfs4_client *clp; 5883016200c3SJeff Layton struct nfs4_ol_stateid *stp, *next; 5884016200c3SJeff Layton 5885016200c3SJeff Layton list_for_each_entry_safe(stp, next, reaplist, st_locks) { 5886016200c3SJeff Layton list_del_init(&stp->st_locks); 5887016200c3SJeff Layton clp = stp->st_stid.sc_client; 5888016200c3SJeff Layton nfs4_put_stid(&stp->st_stid); 5889016200c3SJeff Layton put_client(clp); 5890016200c3SJeff Layton } 5891016200c3SJeff Layton } 5892016200c3SJeff Layton 5893016200c3SJeff Layton u64 5894285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) 5895016200c3SJeff Layton { 5896016200c3SJeff Layton unsigned int count = 0; 5897016200c3SJeff Layton struct nfs4_client *clp; 5898016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5899016200c3SJeff Layton nfsd_net_id); 5900016200c3SJeff Layton LIST_HEAD(reaplist); 5901016200c3SJeff Layton 5902016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 5903016200c3SJeff Layton return count; 5904016200c3SJeff Layton 5905016200c3SJeff Layton spin_lock(&nn->client_lock); 5906016200c3SJeff Layton clp = nfsd_find_client(addr, addr_size); 5907016200c3SJeff Layton if (clp) 5908016200c3SJeff Layton count = nfsd_collect_client_locks(clp, &reaplist, 0); 5909016200c3SJeff Layton spin_unlock(&nn->client_lock); 5910016200c3SJeff Layton nfsd_reap_locks(&reaplist); 5911016200c3SJeff Layton return count; 5912016200c3SJeff Layton } 5913016200c3SJeff Layton 5914016200c3SJeff Layton u64 5915285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max) 5916016200c3SJeff Layton { 5917016200c3SJeff Layton u64 count = 0; 5918016200c3SJeff Layton struct nfs4_client *clp; 5919016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5920016200c3SJeff Layton nfsd_net_id); 5921016200c3SJeff Layton LIST_HEAD(reaplist); 5922016200c3SJeff Layton 5923016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 5924016200c3SJeff Layton return count; 5925016200c3SJeff Layton 5926016200c3SJeff Layton spin_lock(&nn->client_lock); 5927016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 5928016200c3SJeff Layton count += nfsd_collect_client_locks(clp, &reaplist, max - count); 5929016200c3SJeff Layton if (max != 0 && count >= max) 5930016200c3SJeff Layton break; 5931016200c3SJeff Layton } 5932016200c3SJeff Layton spin_unlock(&nn->client_lock); 5933016200c3SJeff Layton nfsd_reap_locks(&reaplist); 5934016200c3SJeff Layton return count; 5935016200c3SJeff Layton } 5936016200c3SJeff Layton 593782e05efaSJeff Layton static u64 593882e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, 593982e05efaSJeff Layton struct list_head *collect, 594082e05efaSJeff Layton void (*func)(struct nfs4_openowner *)) 59414dbdbda8SBryan Schumaker { 59424dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 594382e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 594482e05efaSJeff Layton nfsd_net_id); 59454dbdbda8SBryan Schumaker u64 count = 0; 59464dbdbda8SBryan Schumaker 594782e05efaSJeff Layton lockdep_assert_held(&nn->client_lock); 594882e05efaSJeff Layton 594982e05efaSJeff Layton spin_lock(&clp->cl_lock); 59504dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 595182e05efaSJeff Layton if (func) { 59524dbdbda8SBryan Schumaker func(oop); 595382e05efaSJeff Layton if (collect) { 595482e05efaSJeff Layton atomic_inc(&clp->cl_refcount); 595582e05efaSJeff Layton list_add(&oop->oo_perclient, collect); 595682e05efaSJeff Layton } 595782e05efaSJeff Layton } 595882e05efaSJeff Layton ++count; 595982e05efaSJeff Layton /* 596082e05efaSJeff Layton * Despite the fact that these functions deal with 596182e05efaSJeff Layton * 64-bit integers for "count", we must ensure that 596282e05efaSJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 596382e05efaSJeff Layton * warning if we start to approach INT_MAX here. 596482e05efaSJeff Layton */ 596582e05efaSJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 596682e05efaSJeff Layton if (count == max) 59674dbdbda8SBryan Schumaker break; 59684dbdbda8SBryan Schumaker } 596982e05efaSJeff Layton spin_unlock(&clp->cl_lock); 59704dbdbda8SBryan Schumaker 59714dbdbda8SBryan Schumaker return count; 59724dbdbda8SBryan Schumaker } 59734dbdbda8SBryan Schumaker 597482e05efaSJeff Layton static u64 597582e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp) 59764dbdbda8SBryan Schumaker { 597782e05efaSJeff Layton u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); 597882e05efaSJeff Layton 597982e05efaSJeff Layton nfsd_print_count(clp, count, "openowners"); 598082e05efaSJeff Layton return count; 59814dbdbda8SBryan Schumaker } 59824dbdbda8SBryan Schumaker 598382e05efaSJeff Layton static u64 598482e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp, 598582e05efaSJeff Layton struct list_head *collect, u64 max) 5986184c1847SBryan Schumaker { 598782e05efaSJeff Layton return nfsd_foreach_client_openowner(clp, max, collect, 598882e05efaSJeff Layton unhash_openowner_locked); 598982e05efaSJeff Layton } 599082e05efaSJeff Layton 599182e05efaSJeff Layton u64 5992285abdeeSJeff Layton nfsd_inject_print_openowners(void) 599382e05efaSJeff Layton { 599482e05efaSJeff Layton struct nfs4_client *clp; 599582e05efaSJeff Layton u64 count = 0; 599682e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 599782e05efaSJeff Layton nfsd_net_id); 599882e05efaSJeff Layton 599982e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 600082e05efaSJeff Layton return 0; 600182e05efaSJeff Layton 600282e05efaSJeff Layton spin_lock(&nn->client_lock); 600382e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 600482e05efaSJeff Layton count += nfsd_print_client_openowners(clp); 600582e05efaSJeff Layton spin_unlock(&nn->client_lock); 600682e05efaSJeff Layton 600782e05efaSJeff Layton return count; 600882e05efaSJeff Layton } 600982e05efaSJeff Layton 601082e05efaSJeff Layton static void 601182e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist) 601282e05efaSJeff Layton { 601382e05efaSJeff Layton struct nfs4_client *clp; 601482e05efaSJeff Layton struct nfs4_openowner *oop, *next; 601582e05efaSJeff Layton 601682e05efaSJeff Layton list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { 601782e05efaSJeff Layton list_del_init(&oop->oo_perclient); 601882e05efaSJeff Layton clp = oop->oo_owner.so_client; 601982e05efaSJeff Layton release_openowner(oop); 602082e05efaSJeff Layton put_client(clp); 602182e05efaSJeff Layton } 602282e05efaSJeff Layton } 602382e05efaSJeff Layton 602482e05efaSJeff Layton u64 6025285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, 6026285abdeeSJeff Layton size_t addr_size) 602782e05efaSJeff Layton { 602882e05efaSJeff Layton unsigned int count = 0; 602982e05efaSJeff Layton struct nfs4_client *clp; 603082e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 603182e05efaSJeff Layton nfsd_net_id); 603282e05efaSJeff Layton LIST_HEAD(reaplist); 603382e05efaSJeff Layton 603482e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 603582e05efaSJeff Layton return count; 603682e05efaSJeff Layton 603782e05efaSJeff Layton spin_lock(&nn->client_lock); 603882e05efaSJeff Layton clp = nfsd_find_client(addr, addr_size); 603982e05efaSJeff Layton if (clp) 604082e05efaSJeff Layton count = nfsd_collect_client_openowners(clp, &reaplist, 0); 604182e05efaSJeff Layton spin_unlock(&nn->client_lock); 604282e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 604382e05efaSJeff Layton return count; 604482e05efaSJeff Layton } 604582e05efaSJeff Layton 604682e05efaSJeff Layton u64 6047285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max) 604882e05efaSJeff Layton { 604982e05efaSJeff Layton u64 count = 0; 605082e05efaSJeff Layton struct nfs4_client *clp; 605182e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 605282e05efaSJeff Layton nfsd_net_id); 605382e05efaSJeff Layton LIST_HEAD(reaplist); 605482e05efaSJeff Layton 605582e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 605682e05efaSJeff Layton return count; 605782e05efaSJeff Layton 605882e05efaSJeff Layton spin_lock(&nn->client_lock); 605982e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 606082e05efaSJeff Layton count += nfsd_collect_client_openowners(clp, &reaplist, 606182e05efaSJeff Layton max - count); 606282e05efaSJeff Layton if (max != 0 && count >= max) 606382e05efaSJeff Layton break; 606482e05efaSJeff Layton } 606582e05efaSJeff Layton spin_unlock(&nn->client_lock); 606682e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 6067184c1847SBryan Schumaker return count; 6068184c1847SBryan Schumaker } 6069184c1847SBryan Schumaker 6070269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 6071269de30fSBryan Schumaker struct list_head *victims) 6072269de30fSBryan Schumaker { 6073269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 607498d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 607598d5c7c5SJeff Layton nfsd_net_id); 6076269de30fSBryan Schumaker u64 count = 0; 6077269de30fSBryan Schumaker 607898d5c7c5SJeff Layton lockdep_assert_held(&nn->client_lock); 607998d5c7c5SJeff Layton 608098d5c7c5SJeff Layton spin_lock(&state_lock); 6081269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 6082dff1399fSJeff Layton if (victims) { 6083dff1399fSJeff Layton /* 6084dff1399fSJeff Layton * It's not safe to mess with delegations that have a 6085dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 6086dff1399fSJeff Layton * and could be processed by the laundromat outside of 6087dff1399fSJeff Layton * the state_lock. Just leave them be. 6088dff1399fSJeff Layton */ 6089dff1399fSJeff Layton if (dp->dl_time != 0) 6090dff1399fSJeff Layton continue; 6091dff1399fSJeff Layton 609298d5c7c5SJeff Layton atomic_inc(&clp->cl_refcount); 609342690676SJeff Layton unhash_delegation_locked(dp); 609442690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 6095dff1399fSJeff Layton } 609698d5c7c5SJeff Layton ++count; 609798d5c7c5SJeff Layton /* 609898d5c7c5SJeff Layton * Despite the fact that these functions deal with 609998d5c7c5SJeff Layton * 64-bit integers for "count", we must ensure that 610098d5c7c5SJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 610198d5c7c5SJeff Layton * warning if we start to approach INT_MAX here. 610298d5c7c5SJeff Layton */ 610398d5c7c5SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 610498d5c7c5SJeff Layton if (count == max) 6105269de30fSBryan Schumaker break; 6106269de30fSBryan Schumaker } 610798d5c7c5SJeff Layton spin_unlock(&state_lock); 6108269de30fSBryan Schumaker return count; 6109269de30fSBryan Schumaker } 6110269de30fSBryan Schumaker 611198d5c7c5SJeff Layton static u64 611298d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp) 6113269de30fSBryan Schumaker { 611498d5c7c5SJeff Layton u64 count = nfsd_find_all_delegations(clp, 0, NULL); 6115184c1847SBryan Schumaker 6116184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 6117184c1847SBryan Schumaker return count; 6118184c1847SBryan Schumaker } 6119184c1847SBryan Schumaker 612098d5c7c5SJeff Layton u64 6121285abdeeSJeff Layton nfsd_inject_print_delegations(void) 612298d5c7c5SJeff Layton { 612398d5c7c5SJeff Layton struct nfs4_client *clp; 612498d5c7c5SJeff Layton u64 count = 0; 612598d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 612698d5c7c5SJeff Layton nfsd_net_id); 612798d5c7c5SJeff Layton 612898d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 612998d5c7c5SJeff Layton return 0; 613098d5c7c5SJeff Layton 613198d5c7c5SJeff Layton spin_lock(&nn->client_lock); 613298d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 613398d5c7c5SJeff Layton count += nfsd_print_client_delegations(clp); 613498d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 613598d5c7c5SJeff Layton 613698d5c7c5SJeff Layton return count; 613798d5c7c5SJeff Layton } 613898d5c7c5SJeff Layton 613998d5c7c5SJeff Layton static void 614098d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist) 614198d5c7c5SJeff Layton { 614298d5c7c5SJeff Layton struct nfs4_client *clp; 614398d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 614498d5c7c5SJeff Layton 614598d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 614698d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 614798d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 614898d5c7c5SJeff Layton revoke_delegation(dp); 614998d5c7c5SJeff Layton put_client(clp); 615098d5c7c5SJeff Layton } 615198d5c7c5SJeff Layton } 615298d5c7c5SJeff Layton 615398d5c7c5SJeff Layton u64 6154285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, 6155285abdeeSJeff Layton size_t addr_size) 615698d5c7c5SJeff Layton { 615798d5c7c5SJeff Layton u64 count = 0; 615898d5c7c5SJeff Layton struct nfs4_client *clp; 615998d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 616098d5c7c5SJeff Layton nfsd_net_id); 616198d5c7c5SJeff Layton LIST_HEAD(reaplist); 616298d5c7c5SJeff Layton 616398d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 616498d5c7c5SJeff Layton return count; 616598d5c7c5SJeff Layton 616698d5c7c5SJeff Layton spin_lock(&nn->client_lock); 616798d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 616898d5c7c5SJeff Layton if (clp) 616998d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 617098d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 617198d5c7c5SJeff Layton 617298d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 617398d5c7c5SJeff Layton return count; 617498d5c7c5SJeff Layton } 617598d5c7c5SJeff Layton 617698d5c7c5SJeff Layton u64 6177285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max) 617898d5c7c5SJeff Layton { 617998d5c7c5SJeff Layton u64 count = 0; 618098d5c7c5SJeff Layton struct nfs4_client *clp; 618198d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 618298d5c7c5SJeff Layton nfsd_net_id); 618398d5c7c5SJeff Layton LIST_HEAD(reaplist); 618498d5c7c5SJeff Layton 618598d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 618698d5c7c5SJeff Layton return count; 618798d5c7c5SJeff Layton 618898d5c7c5SJeff Layton spin_lock(&nn->client_lock); 618998d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 619098d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 619198d5c7c5SJeff Layton if (max != 0 && count >= max) 619298d5c7c5SJeff Layton break; 619398d5c7c5SJeff Layton } 619498d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 619598d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 619698d5c7c5SJeff Layton return count; 619798d5c7c5SJeff Layton } 619898d5c7c5SJeff Layton 619998d5c7c5SJeff Layton static void 620098d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist) 620198d5c7c5SJeff Layton { 620298d5c7c5SJeff Layton struct nfs4_client *clp; 620398d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 620498d5c7c5SJeff Layton 620598d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 620698d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 620798d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 620898d5c7c5SJeff Layton /* 620998d5c7c5SJeff Layton * We skipped all entries that had a zero dl_time before, 621098d5c7c5SJeff Layton * so we can now reset the dl_time back to 0. If a delegation 621198d5c7c5SJeff Layton * break comes in now, then it won't make any difference since 621298d5c7c5SJeff Layton * we're recalling it either way. 621398d5c7c5SJeff Layton */ 621498d5c7c5SJeff Layton spin_lock(&state_lock); 621598d5c7c5SJeff Layton dp->dl_time = 0; 621698d5c7c5SJeff Layton spin_unlock(&state_lock); 621798d5c7c5SJeff Layton nfsd_break_one_deleg(dp); 621898d5c7c5SJeff Layton put_client(clp); 621998d5c7c5SJeff Layton } 622098d5c7c5SJeff Layton } 622198d5c7c5SJeff Layton 622298d5c7c5SJeff Layton u64 6223285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, 622498d5c7c5SJeff Layton size_t addr_size) 622598d5c7c5SJeff Layton { 622698d5c7c5SJeff Layton u64 count = 0; 622798d5c7c5SJeff Layton struct nfs4_client *clp; 622898d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 622998d5c7c5SJeff Layton nfsd_net_id); 623098d5c7c5SJeff Layton LIST_HEAD(reaplist); 623198d5c7c5SJeff Layton 623298d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 623398d5c7c5SJeff Layton return count; 623498d5c7c5SJeff Layton 623598d5c7c5SJeff Layton spin_lock(&nn->client_lock); 623698d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 623798d5c7c5SJeff Layton if (clp) 623898d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 623998d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 624098d5c7c5SJeff Layton 624198d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 624298d5c7c5SJeff Layton return count; 624398d5c7c5SJeff Layton } 624498d5c7c5SJeff Layton 624598d5c7c5SJeff Layton u64 6246285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max) 624798d5c7c5SJeff Layton { 624898d5c7c5SJeff Layton u64 count = 0; 624998d5c7c5SJeff Layton struct nfs4_client *clp, *next; 625098d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 625198d5c7c5SJeff Layton nfsd_net_id); 625298d5c7c5SJeff Layton LIST_HEAD(reaplist); 625398d5c7c5SJeff Layton 625498d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 625598d5c7c5SJeff Layton return count; 625698d5c7c5SJeff Layton 625798d5c7c5SJeff Layton spin_lock(&nn->client_lock); 625898d5c7c5SJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 625998d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 626098d5c7c5SJeff Layton if (max != 0 && ++count >= max) 626198d5c7c5SJeff Layton break; 626298d5c7c5SJeff Layton } 626398d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 626498d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 626598d5c7c5SJeff Layton return count; 626698d5c7c5SJeff Layton } 626765178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 626865178db4SBryan Schumaker 6269c2f1a551SMeelap Shah /* 6270c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 6271c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 6272c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 6273c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 6274c2f1a551SMeelap Shah * 6275c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 6276c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 6277c2f1a551SMeelap Shah */ 6278c2f1a551SMeelap Shah static void 6279c2f1a551SMeelap Shah set_max_delegations(void) 6280c2f1a551SMeelap Shah { 6281c2f1a551SMeelap Shah /* 6282c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 6283c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 6284c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 6285c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 6286c2f1a551SMeelap Shah */ 6287c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 6288c2f1a551SMeelap Shah } 6289c2f1a551SMeelap Shah 6290d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 62918daae4dcSStanislav Kinsbursky { 62928daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 62938daae4dcSStanislav Kinsbursky int i; 62948daae4dcSStanislav Kinsbursky 62958daae4dcSStanislav Kinsbursky nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * 62968daae4dcSStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 62978daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 6298382a62e7SStanislav Kinsbursky goto err; 62990a7ec377SStanislav Kinsbursky nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * 63000a7ec377SStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 63010a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 63020a7ec377SStanislav Kinsbursky goto err_unconf_id; 63031872de0eSStanislav Kinsbursky nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * 63041872de0eSStanislav Kinsbursky SESSION_HASH_SIZE, GFP_KERNEL); 63051872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 63061872de0eSStanislav Kinsbursky goto err_sessionid; 63078daae4dcSStanislav Kinsbursky 6308382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 63098daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 63100a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 6311382a62e7SStanislav Kinsbursky } 63121872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 63131872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 6314382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 6315a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 63165ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 631773758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 6318e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 6319c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 63208daae4dcSStanislav Kinsbursky 632109121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 6322d85ed443SStanislav Kinsbursky get_net(net); 632309121281SStanislav Kinsbursky 63248daae4dcSStanislav Kinsbursky return 0; 6325382a62e7SStanislav Kinsbursky 63261872de0eSStanislav Kinsbursky err_sessionid: 63279b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 63280a7ec377SStanislav Kinsbursky err_unconf_id: 63290a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 6330382a62e7SStanislav Kinsbursky err: 6331382a62e7SStanislav Kinsbursky return -ENOMEM; 63328daae4dcSStanislav Kinsbursky } 63338daae4dcSStanislav Kinsbursky 63348daae4dcSStanislav Kinsbursky static void 63354dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 63368daae4dcSStanislav Kinsbursky { 63378daae4dcSStanislav Kinsbursky int i; 63388daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 63398daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 63408daae4dcSStanislav Kinsbursky 63418daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 63428daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 63438daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 63448daae4dcSStanislav Kinsbursky destroy_client(clp); 63458daae4dcSStanislav Kinsbursky } 63468daae4dcSStanislav Kinsbursky } 6347a99454aaSStanislav Kinsbursky 63482b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 63492b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 63502b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 6351a99454aaSStanislav Kinsbursky destroy_client(clp); 6352a99454aaSStanislav Kinsbursky } 63532b905635SKinglong Mee } 6354a99454aaSStanislav Kinsbursky 63551872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 63560a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 63578daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 63584dce0ac9SStanislav Kinsbursky put_net(net); 63598daae4dcSStanislav Kinsbursky } 63608daae4dcSStanislav Kinsbursky 6361f252bc68SStanislav Kinsbursky int 6362d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 6363ac4d8ff2SNeilBrown { 63645e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 6365b5a1a81eSJ. Bruce Fields int ret; 6366b5a1a81eSJ. Bruce Fields 6367d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 63688daae4dcSStanislav Kinsbursky if (ret) 63698daae4dcSStanislav Kinsbursky return ret; 63705e1533c7SStanislav Kinsbursky nfsd4_client_tracking_init(net); 63712c142baaSStanislav Kinsbursky nn->boot_time = get_seconds(); 63725ccb0066SStanislav Kinsbursky locks_start_grace(net, &nn->nfsd4_manager); 6373a51c84edSStanislav Kinsbursky nn->grace_ended = false; 6374d85ed443SStanislav Kinsbursky printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", 63755284b44eSStanislav Kinsbursky nn->nfsd4_grace, net); 63765284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 6377d85ed443SStanislav Kinsbursky return 0; 6378a6d6b781SJeff Layton } 6379d85ed443SStanislav Kinsbursky 6380d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 6381d85ed443SStanislav Kinsbursky 6382d85ed443SStanislav Kinsbursky int 6383d85ed443SStanislav Kinsbursky nfs4_state_start(void) 6384d85ed443SStanislav Kinsbursky { 6385d85ed443SStanislav Kinsbursky int ret; 6386d85ed443SStanislav Kinsbursky 6387d85ed443SStanislav Kinsbursky ret = set_callback_cred(); 6388d85ed443SStanislav Kinsbursky if (ret) 6389d85ed443SStanislav Kinsbursky return -ENOMEM; 639058da282bSNeilBrown laundry_wq = create_singlethread_workqueue("nfsd4"); 6391a6d6b781SJeff Layton if (laundry_wq == NULL) { 6392a6d6b781SJeff Layton ret = -ENOMEM; 6393a6d6b781SJeff Layton goto out_recovery; 6394a6d6b781SJeff Layton } 6395b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 6396b5a1a81eSJ. Bruce Fields if (ret) 6397b5a1a81eSJ. Bruce Fields goto out_free_laundry; 639809121281SStanislav Kinsbursky 6399c2f1a551SMeelap Shah set_max_delegations(); 6400d85ed443SStanislav Kinsbursky 6401b5a1a81eSJ. Bruce Fields return 0; 6402d85ed443SStanislav Kinsbursky 6403b5a1a81eSJ. Bruce Fields out_free_laundry: 6404b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 6405a6d6b781SJeff Layton out_recovery: 6406b5a1a81eSJ. Bruce Fields return ret; 64071da177e4SLinus Torvalds } 64081da177e4SLinus Torvalds 6409f252bc68SStanislav Kinsbursky void 64104dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 64111da177e4SLinus Torvalds { 64121da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 64131da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 64144dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 64151da177e4SLinus Torvalds 64164dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 64174dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 6418ac55fdc4SJeff Layton 64191da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 6420cdc97505SBenny Halevy spin_lock(&state_lock); 6421e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 64221da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 642342690676SJeff Layton unhash_delegation_locked(dp); 642442690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 64251da177e4SLinus Torvalds } 6426cdc97505SBenny Halevy spin_unlock(&state_lock); 64271da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 64281da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 642942690676SJeff Layton list_del_init(&dp->dl_recall_lru); 6430afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 64316011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 64321da177e4SLinus Torvalds } 64331da177e4SLinus Torvalds 64343320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 64354dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 64361da177e4SLinus Torvalds } 64371da177e4SLinus Torvalds 64381da177e4SLinus Torvalds void 64391da177e4SLinus Torvalds nfs4_state_shutdown(void) 64401da177e4SLinus Torvalds { 64415e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 6442c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 64431da177e4SLinus Torvalds } 64448b70484cSTigran Mkrtchyan 64458b70484cSTigran Mkrtchyan static void 64468b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 64478b70484cSTigran Mkrtchyan { 644837c593c5STigran Mkrtchyan if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) 644937c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 64508b70484cSTigran Mkrtchyan } 64518b70484cSTigran Mkrtchyan 64528b70484cSTigran Mkrtchyan static void 64538b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 64548b70484cSTigran Mkrtchyan { 645537c593c5STigran Mkrtchyan if (cstate->minorversion) { 645637c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 645737c593c5STigran Mkrtchyan SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 645837c593c5STigran Mkrtchyan } 645937c593c5STigran Mkrtchyan } 646037c593c5STigran Mkrtchyan 646137c593c5STigran Mkrtchyan void 646237c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 646337c593c5STigran Mkrtchyan { 646437c593c5STigran Mkrtchyan CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 64658b70484cSTigran Mkrtchyan } 64668b70484cSTigran Mkrtchyan 646762cd4a59STigran Mkrtchyan /* 646862cd4a59STigran Mkrtchyan * functions to set current state id 646962cd4a59STigran Mkrtchyan */ 64708b70484cSTigran Mkrtchyan void 64719428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 64729428fe1aSTigran Mkrtchyan { 64739428fe1aSTigran Mkrtchyan put_stateid(cstate, &odp->od_stateid); 64749428fe1aSTigran Mkrtchyan } 64759428fe1aSTigran Mkrtchyan 64769428fe1aSTigran Mkrtchyan void 64778b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open) 64788b70484cSTigran Mkrtchyan { 64798b70484cSTigran Mkrtchyan put_stateid(cstate, &open->op_stateid); 64808b70484cSTigran Mkrtchyan } 64818b70484cSTigran Mkrtchyan 64828b70484cSTigran Mkrtchyan void 648362cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 648462cd4a59STigran Mkrtchyan { 648562cd4a59STigran Mkrtchyan put_stateid(cstate, &close->cl_stateid); 648662cd4a59STigran Mkrtchyan } 648762cd4a59STigran Mkrtchyan 648862cd4a59STigran Mkrtchyan void 648962cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock) 649062cd4a59STigran Mkrtchyan { 649162cd4a59STigran Mkrtchyan put_stateid(cstate, &lock->lk_resp_stateid); 649262cd4a59STigran Mkrtchyan } 649362cd4a59STigran Mkrtchyan 649462cd4a59STigran Mkrtchyan /* 649562cd4a59STigran Mkrtchyan * functions to consume current state id 649662cd4a59STigran Mkrtchyan */ 64971e97b519STigran Mkrtchyan 64981e97b519STigran Mkrtchyan void 64999428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 65009428fe1aSTigran Mkrtchyan { 65019428fe1aSTigran Mkrtchyan get_stateid(cstate, &odp->od_stateid); 65029428fe1aSTigran Mkrtchyan } 65039428fe1aSTigran Mkrtchyan 65049428fe1aSTigran Mkrtchyan void 65059428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp) 65069428fe1aSTigran Mkrtchyan { 65079428fe1aSTigran Mkrtchyan get_stateid(cstate, &drp->dr_stateid); 65089428fe1aSTigran Mkrtchyan } 65099428fe1aSTigran Mkrtchyan 65109428fe1aSTigran Mkrtchyan void 65111e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp) 65121e97b519STigran Mkrtchyan { 65131e97b519STigran Mkrtchyan get_stateid(cstate, &fsp->fr_stateid); 65141e97b519STigran Mkrtchyan } 65151e97b519STigran Mkrtchyan 65161e97b519STigran Mkrtchyan void 65171e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) 65181e97b519STigran Mkrtchyan { 65191e97b519STigran Mkrtchyan get_stateid(cstate, &setattr->sa_stateid); 65201e97b519STigran Mkrtchyan } 65211e97b519STigran Mkrtchyan 652262cd4a59STigran Mkrtchyan void 65238b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 65248b70484cSTigran Mkrtchyan { 65258b70484cSTigran Mkrtchyan get_stateid(cstate, &close->cl_stateid); 65268b70484cSTigran Mkrtchyan } 65278b70484cSTigran Mkrtchyan 65288b70484cSTigran Mkrtchyan void 652962cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku) 65308b70484cSTigran Mkrtchyan { 653162cd4a59STigran Mkrtchyan get_stateid(cstate, &locku->lu_stateid); 65328b70484cSTigran Mkrtchyan } 653330813e27STigran Mkrtchyan 653430813e27STigran Mkrtchyan void 653530813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read) 653630813e27STigran Mkrtchyan { 653730813e27STigran Mkrtchyan get_stateid(cstate, &read->rd_stateid); 653830813e27STigran Mkrtchyan } 653930813e27STigran Mkrtchyan 654030813e27STigran Mkrtchyan void 654130813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write) 654230813e27STigran Mkrtchyan { 654330813e27STigran Mkrtchyan get_stateid(cstate, &write->wr_stateid); 654430813e27STigran Mkrtchyan } 6545