11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2001 The Regents of the University of Michigan. 31da177e4SLinus Torvalds * All rights reserved. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Kendrick Smith <kmsmith@umich.edu> 61da177e4SLinus Torvalds * Andy Adamson <kandros@umich.edu> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 91da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 101da177e4SLinus Torvalds * are met: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 131da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer. 141da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 151da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer in the 161da177e4SLinus Torvalds * documentation and/or other materials provided with the distribution. 171da177e4SLinus Torvalds * 3. Neither the name of the University nor the names of its 181da177e4SLinus Torvalds * contributors may be used to endorse or promote products derived 191da177e4SLinus Torvalds * from this software without specific prior written permission. 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 221da177e4SLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 231da177e4SLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 241da177e4SLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251da177e4SLinus Torvalds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 261da177e4SLinus Torvalds * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 271da177e4SLinus Torvalds * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 281da177e4SLinus Torvalds * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 291da177e4SLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 301da177e4SLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 311da177e4SLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds 35aceaf78dSDave Hansen #include <linux/file.h> 36b89f4321SArnd Bergmann #include <linux/fs.h> 375a0e3ad6STejun Heo #include <linux/slab.h> 380964a3d3SNeilBrown #include <linux/namei.h> 39c2f1a551SMeelap Shah #include <linux/swap.h> 4017456804SBryan Schumaker #include <linux/pagemap.h> 417df302f7SChuck Lever #include <linux/ratelimit.h> 4268e76ad0SOlga Kornievskaia #include <linux/sunrpc/svcauth_gss.h> 435976687aSJeff Layton #include <linux/sunrpc/addr.h> 4487545899SDaniel Borkmann #include <linux/jhash.h> 459a74af21SBoaz Harrosh #include "xdr4.h" 4606b332a5SJ. Bruce Fields #include "xdr4cb.h" 470a3adadeSJ. Bruce Fields #include "vfs.h" 48bfa4b365SJ. Bruce Fields #include "current_stateid.h" 491da177e4SLinus Torvalds 505e1533c7SStanislav Kinsbursky #include "netns.h" 519cf514ccSChristoph Hellwig #include "pnfs.h" 525e1533c7SStanislav Kinsbursky 531da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 541da177e4SLinus Torvalds 55f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 56f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 57f32f3c2dSJ. Bruce Fields .si_generation = ~0, 58f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 59f32f3c2dSJ. Bruce Fields }; 60f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 61f32f3c2dSJ. Bruce Fields /* all fields zero */ 62f32f3c2dSJ. Bruce Fields }; 6319ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 6419ff0f28STigran Mkrtchyan .si_generation = 1, 6519ff0f28STigran Mkrtchyan }; 66f32f3c2dSJ. Bruce Fields 67ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 68fd39ca9aSNeilBrown 69f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 70f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 7119ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* forward declarations */ 74f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 756011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 761da177e4SLinus Torvalds 778b671b80SJ. Bruce Fields /* Locking: */ 788b671b80SJ. Bruce Fields 798b671b80SJ. Bruce Fields /* 808b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 818b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 828b671b80SJ. Bruce Fields * eventually cover more: 838b671b80SJ. Bruce Fields */ 84cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 858b671b80SJ. Bruce Fields 86b401be22SJeff Layton /* 87b401be22SJeff Layton * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for 88b401be22SJeff Layton * the refcount on the open stateid to drop. 89b401be22SJeff Layton */ 90b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq); 91b401be22SJeff Layton 92abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 93abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 94abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 95abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 96abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 978287f009SSachin Bhamare static struct kmem_cache *odstate_slab; 98e60d4398SNeilBrown 9966b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 100508dc6e1SBenny Halevy 101c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; 1020162ac2bSChristoph Hellwig 10366b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 104508dc6e1SBenny Halevy { 10566b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 10666b2b9b2SJ. Bruce Fields } 10766b2b9b2SJ. Bruce Fields 108f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 109f0f51f5cSJ. Bruce Fields { 110f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 11166b2b9b2SJ. Bruce Fields return nfserr_jukebox; 11266b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 11366b2b9b2SJ. Bruce Fields return nfs_ok; 11466b2b9b2SJ. Bruce Fields } 11566b2b9b2SJ. Bruce Fields 116221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 117221a6876SJ. Bruce Fields { 118221a6876SJ. Bruce Fields return clp->cl_time == 0; 119221a6876SJ. Bruce Fields } 120221a6876SJ. Bruce Fields 121221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 122221a6876SJ. Bruce Fields { 1230a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1240a880a28STrond Myklebust 1250a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1260a880a28STrond Myklebust 127221a6876SJ. Bruce Fields if (is_client_expired(clp)) 128221a6876SJ. Bruce Fields return nfserr_expired; 129221a6876SJ. Bruce Fields atomic_inc(&clp->cl_refcount); 130221a6876SJ. Bruce Fields return nfs_ok; 131221a6876SJ. Bruce Fields } 132221a6876SJ. Bruce Fields 133221a6876SJ. Bruce Fields /* must be called under the client_lock */ 134221a6876SJ. Bruce Fields static inline void 135221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 136221a6876SJ. Bruce Fields { 137221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 138221a6876SJ. Bruce Fields 139221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 140221a6876SJ. Bruce Fields WARN_ON(1); 141221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 142221a6876SJ. Bruce Fields __func__, 143221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 144221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 145221a6876SJ. Bruce Fields return; 146221a6876SJ. Bruce Fields } 147221a6876SJ. Bruce Fields 148221a6876SJ. Bruce Fields dprintk("renewing client (clientid %08x/%08x)\n", 149221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 150221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 151221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 152221a6876SJ. Bruce Fields clp->cl_time = get_seconds(); 153221a6876SJ. Bruce Fields } 154221a6876SJ. Bruce Fields 155ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 156221a6876SJ. Bruce Fields { 1570a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1580a880a28STrond Myklebust 1590a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1600a880a28STrond Myklebust 161221a6876SJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_refcount)) 162221a6876SJ. Bruce Fields return; 163221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 164221a6876SJ. Bruce Fields renew_client_locked(clp); 165221a6876SJ. Bruce Fields } 166221a6876SJ. Bruce Fields 1674b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 1684b24ca7dSJeff Layton { 1694b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1704b24ca7dSJeff Layton 171d6c249b4SJeff Layton if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) 172d6c249b4SJeff Layton return; 173d6c249b4SJeff Layton if (!is_client_expired(clp)) 174d6c249b4SJeff Layton renew_client_locked(clp); 1754b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 1764b24ca7dSJeff Layton } 1774b24ca7dSJeff Layton 178d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 179d4e19e70STrond Myklebust { 180d4e19e70STrond Myklebust __be32 status; 181d4e19e70STrond Myklebust 182d4e19e70STrond Myklebust if (is_session_dead(ses)) 183d4e19e70STrond Myklebust return nfserr_badsession; 184d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 185d4e19e70STrond Myklebust if (status) 186d4e19e70STrond Myklebust return status; 187d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 188d4e19e70STrond Myklebust return nfs_ok; 189d4e19e70STrond Myklebust } 190d4e19e70STrond Myklebust 191d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 192d4e19e70STrond Myklebust { 193d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 1940a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1950a880a28STrond Myklebust 1960a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 197d4e19e70STrond Myklebust 198d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 199d4e19e70STrond Myklebust free_session(ses); 200d4e19e70STrond Myklebust put_client_renew_locked(clp); 201d4e19e70STrond Myklebust } 202d4e19e70STrond Myklebust 203d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 204d4e19e70STrond Myklebust { 205d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 206d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 207d4e19e70STrond Myklebust 208d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 209d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 210d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 211d4e19e70STrond Myklebust } 212d4e19e70STrond Myklebust 213b5971afaSKinglong Mee static inline struct nfs4_stateowner * 214b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop) 215b5971afaSKinglong Mee { 216b5971afaSKinglong Mee atomic_inc(&sop->so_count); 217b5971afaSKinglong Mee return sop; 218b5971afaSKinglong Mee } 219b5971afaSKinglong Mee 2207ffb5880STrond Myklebust static int 221d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) 2227ffb5880STrond Myklebust { 2237ffb5880STrond Myklebust return (sop->so_owner.len == owner->len) && 224d4f0489fSTrond Myklebust 0 == memcmp(sop->so_owner.data, owner->data, owner->len); 2257ffb5880STrond Myklebust } 2267ffb5880STrond Myklebust 2277ffb5880STrond Myklebust static struct nfs4_openowner * 2287ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, 229d4f0489fSTrond Myklebust struct nfs4_client *clp) 2307ffb5880STrond Myklebust { 2317ffb5880STrond Myklebust struct nfs4_stateowner *so; 2327ffb5880STrond Myklebust 233d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 2347ffb5880STrond Myklebust 235d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval], 236d4f0489fSTrond Myklebust so_strhash) { 2377ffb5880STrond Myklebust if (!so->so_is_open_owner) 2387ffb5880STrond Myklebust continue; 239b5971afaSKinglong Mee if (same_owner_str(so, &open->op_owner)) 240b5971afaSKinglong Mee return openowner(nfs4_get_stateowner(so)); 2417ffb5880STrond Myklebust } 2427ffb5880STrond Myklebust return NULL; 2437ffb5880STrond Myklebust } 2447ffb5880STrond Myklebust 2457ffb5880STrond Myklebust static struct nfs4_openowner * 2467ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 247d4f0489fSTrond Myklebust struct nfs4_client *clp) 2487ffb5880STrond Myklebust { 2497ffb5880STrond Myklebust struct nfs4_openowner *oo; 2507ffb5880STrond Myklebust 251d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 252d4f0489fSTrond Myklebust oo = find_openstateowner_str_locked(hashval, open, clp); 253d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 2547ffb5880STrond Myklebust return oo; 2557ffb5880STrond Myklebust } 2567ffb5880STrond Myklebust 2571da177e4SLinus Torvalds static inline u32 2581da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 2591da177e4SLinus Torvalds { 2601da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds u32 x = 0; 2631da177e4SLinus Torvalds while (nbytes--) { 2641da177e4SLinus Torvalds x *= 37; 2651da177e4SLinus Torvalds x += *cptr++; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds return x; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 2705b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu) 27132513b40SJ. Bruce Fields { 2725b095e99SJeff Layton struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu); 2735b095e99SJeff Layton 2745b095e99SJeff Layton kmem_cache_free(file_slab, fp); 27532513b40SJ. Bruce Fields } 27632513b40SJ. Bruce Fields 277e6ba76e1SChristoph Hellwig void 27813cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 27913cd2184SNeilBrown { 28002e1215fSJeff Layton might_lock(&state_lock); 28102e1215fSJeff Layton 282cdc97505SBenny Halevy if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { 2835b095e99SJeff Layton hlist_del_rcu(&fi->fi_hash); 284cdc97505SBenny Halevy spin_unlock(&state_lock); 2858287f009SSachin Bhamare WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); 2865b095e99SJeff Layton WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); 2875b095e99SJeff Layton call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); 2888b671b80SJ. Bruce Fields } 28913cd2184SNeilBrown } 29013cd2184SNeilBrown 291de18643dSTrond Myklebust static struct file * 292de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag) 293de18643dSTrond Myklebust { 294de18643dSTrond Myklebust if (f->fi_fds[oflag]) 295de18643dSTrond Myklebust return get_file(f->fi_fds[oflag]); 296de18643dSTrond Myklebust return NULL; 297de18643dSTrond Myklebust } 298de18643dSTrond Myklebust 299de18643dSTrond Myklebust static struct file * 300de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f) 301de18643dSTrond Myklebust { 302de18643dSTrond Myklebust struct file *ret; 303de18643dSTrond Myklebust 304de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 305de18643dSTrond Myklebust 306de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 307de18643dSTrond Myklebust if (!ret) 308de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 309de18643dSTrond Myklebust return ret; 310de18643dSTrond Myklebust } 311de18643dSTrond Myklebust 312de18643dSTrond Myklebust static struct file * 313de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 314de18643dSTrond Myklebust { 315de18643dSTrond Myklebust struct file *ret; 316de18643dSTrond Myklebust 317de18643dSTrond Myklebust spin_lock(&f->fi_lock); 318de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 319de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 320de18643dSTrond Myklebust 321de18643dSTrond Myklebust return ret; 322de18643dSTrond Myklebust } 323de18643dSTrond Myklebust 324de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f) 325de18643dSTrond Myklebust { 326de18643dSTrond Myklebust struct file *ret; 327de18643dSTrond Myklebust 328de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 329de18643dSTrond Myklebust 330de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 331de18643dSTrond Myklebust if (!ret) 332de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 333de18643dSTrond Myklebust return ret; 334de18643dSTrond Myklebust } 335de18643dSTrond Myklebust 336de18643dSTrond Myklebust static struct file * 337de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 338de18643dSTrond Myklebust { 339de18643dSTrond Myklebust struct file *ret; 340de18643dSTrond Myklebust 341de18643dSTrond Myklebust spin_lock(&f->fi_lock); 342de18643dSTrond Myklebust ret = find_readable_file_locked(f); 343de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 344de18643dSTrond Myklebust 345de18643dSTrond Myklebust return ret; 346de18643dSTrond Myklebust } 347de18643dSTrond Myklebust 3484d227fcaSChristoph Hellwig struct file * 349de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 350de18643dSTrond Myklebust { 351de18643dSTrond Myklebust struct file *ret; 352de18643dSTrond Myklebust 353de18643dSTrond Myklebust spin_lock(&f->fi_lock); 354de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 355de18643dSTrond Myklebust if (!ret) { 356de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 357de18643dSTrond Myklebust if (!ret) 358de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 359de18643dSTrond Myklebust } 360de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 361de18643dSTrond Myklebust return ret; 362de18643dSTrond Myklebust } 363de18643dSTrond Myklebust 36402a3508dSTrond Myklebust static atomic_long_t num_delegations; 365697ce9beSZhang Yanfei unsigned long max_delegations; 366ef0f3390SNeilBrown 367ef0f3390SNeilBrown /* 368ef0f3390SNeilBrown * Open owner state (share locks) 369ef0f3390SNeilBrown */ 370ef0f3390SNeilBrown 37116bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 37216bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 37316bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 37416bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 375ef0f3390SNeilBrown 376d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 377ddc04c41SJ. Bruce Fields { 378ddc04c41SJ. Bruce Fields unsigned int ret; 379ddc04c41SJ. Bruce Fields 380ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 38116bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 382ddc04c41SJ. Bruce Fields } 383ef0f3390SNeilBrown 384ef0f3390SNeilBrown /* hash table for nfs4_file */ 385ef0f3390SNeilBrown #define FILE_HASH_BITS 8 386ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 38735079582SShan Wei 388ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) 389ddc04c41SJ. Bruce Fields { 390ca943217STrond Myklebust return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); 391ca943217STrond Myklebust } 392ca943217STrond Myklebust 393ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh) 394ca943217STrond Myklebust { 395ca943217STrond Myklebust return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); 396ca943217STrond Myklebust } 397ca943217STrond Myklebust 39889876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 399ef0f3390SNeilBrown 40012659651SJeff Layton static void 40112659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 4023477565eSJ. Bruce Fields { 4037214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 4047214e860SJeff Layton 40512659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 40612659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 40712659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 40812659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 4093477565eSJ. Bruce Fields } 4103477565eSJ. Bruce Fields 41112659651SJeff Layton static __be32 41212659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 413998db52cSJ. Bruce Fields { 4147214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 4157214e860SJeff Layton 41612659651SJeff Layton /* Does this access mode make sense? */ 41712659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 41812659651SJeff Layton return nfserr_inval; 41912659651SJeff Layton 420baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 421baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 422baeb4ff0SJeff Layton return nfserr_share_denied; 423baeb4ff0SJeff Layton 42412659651SJeff Layton __nfs4_file_get_access(fp, access); 42512659651SJeff Layton return nfs_ok; 426998db52cSJ. Bruce Fields } 427998db52cSJ. Bruce Fields 428baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 429baeb4ff0SJeff Layton { 430baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 431baeb4ff0SJeff Layton if (deny) { 432baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 433baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 434baeb4ff0SJeff Layton return nfserr_inval; 435baeb4ff0SJeff Layton 436baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 437baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 438baeb4ff0SJeff Layton return nfserr_share_denied; 439baeb4ff0SJeff Layton 440baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 441baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 442baeb4ff0SJeff Layton return nfserr_share_denied; 443baeb4ff0SJeff Layton } 444baeb4ff0SJeff Layton return nfs_ok; 445baeb4ff0SJeff Layton } 446baeb4ff0SJeff Layton 447998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 448f9d7562fSJ. Bruce Fields { 449de18643dSTrond Myklebust might_lock(&fp->fi_lock); 450de18643dSTrond Myklebust 451de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 452de18643dSTrond Myklebust struct file *f1 = NULL; 453de18643dSTrond Myklebust struct file *f2 = NULL; 454de18643dSTrond Myklebust 4556d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 4560c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 4576d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 458de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 459de18643dSTrond Myklebust if (f1) 460de18643dSTrond Myklebust fput(f1); 461de18643dSTrond Myklebust if (f2) 462de18643dSTrond Myklebust fput(f2); 463f9d7562fSJ. Bruce Fields } 464f9d7562fSJ. Bruce Fields } 465f9d7562fSJ. Bruce Fields 46612659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 467998db52cSJ. Bruce Fields { 46812659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 46912659651SJeff Layton 47012659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 471998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 47212659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 47312659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 474998db52cSJ. Bruce Fields } 475998db52cSJ. Bruce Fields 4768287f009SSachin Bhamare /* 4778287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 4788287f009SSachin Bhamare * pNFS for proper return on close semantics. 4798287f009SSachin Bhamare * 4808287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 4818287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 4828287f009SSachin Bhamare */ 4838287f009SSachin Bhamare static struct nfs4_clnt_odstate * 4848287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 4858287f009SSachin Bhamare { 4868287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 4878287f009SSachin Bhamare 4888287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 4898287f009SSachin Bhamare if (co) { 4908287f009SSachin Bhamare co->co_client = clp; 4918287f009SSachin Bhamare atomic_set(&co->co_odcount, 1); 4928287f009SSachin Bhamare } 4938287f009SSachin Bhamare return co; 4948287f009SSachin Bhamare } 4958287f009SSachin Bhamare 4968287f009SSachin Bhamare static void 4978287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 4988287f009SSachin Bhamare { 4998287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 5008287f009SSachin Bhamare 5018287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 5028287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 5038287f009SSachin Bhamare } 5048287f009SSachin Bhamare 5058287f009SSachin Bhamare static inline void 5068287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 5078287f009SSachin Bhamare { 5088287f009SSachin Bhamare if (co) 5098287f009SSachin Bhamare atomic_inc(&co->co_odcount); 5108287f009SSachin Bhamare } 5118287f009SSachin Bhamare 5128287f009SSachin Bhamare static void 5138287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 5148287f009SSachin Bhamare { 5158287f009SSachin Bhamare struct nfs4_file *fp; 5168287f009SSachin Bhamare 5178287f009SSachin Bhamare if (!co) 5188287f009SSachin Bhamare return; 5198287f009SSachin Bhamare 5208287f009SSachin Bhamare fp = co->co_file; 5218287f009SSachin Bhamare if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 5228287f009SSachin Bhamare list_del(&co->co_perfile); 5238287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 5248287f009SSachin Bhamare 5258287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 5268287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 5278287f009SSachin Bhamare } 5288287f009SSachin Bhamare } 5298287f009SSachin Bhamare 5308287f009SSachin Bhamare static struct nfs4_clnt_odstate * 5318287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 5328287f009SSachin Bhamare { 5338287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 5348287f009SSachin Bhamare struct nfs4_client *cl; 5358287f009SSachin Bhamare 5368287f009SSachin Bhamare if (!new) 5378287f009SSachin Bhamare return NULL; 5388287f009SSachin Bhamare 5398287f009SSachin Bhamare cl = new->co_client; 5408287f009SSachin Bhamare 5418287f009SSachin Bhamare spin_lock(&fp->fi_lock); 5428287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 5438287f009SSachin Bhamare if (co->co_client == cl) { 5448287f009SSachin Bhamare get_clnt_odstate(co); 5458287f009SSachin Bhamare goto out; 5468287f009SSachin Bhamare } 5478287f009SSachin Bhamare } 5488287f009SSachin Bhamare co = new; 5498287f009SSachin Bhamare co->co_file = fp; 5508287f009SSachin Bhamare hash_clnt_odstate_locked(new); 5518287f009SSachin Bhamare out: 5528287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 5538287f009SSachin Bhamare return co; 5548287f009SSachin Bhamare } 5558287f009SSachin Bhamare 556cd61c522SChristoph Hellwig struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 5576011695dSTrond Myklebust struct kmem_cache *slab) 558996e0938SJ. Bruce Fields { 5593abdb607SJ. Bruce Fields struct nfs4_stid *stid; 5603abdb607SJ. Bruce Fields int new_id; 5613abdb607SJ. Bruce Fields 562f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 5633abdb607SJ. Bruce Fields if (!stid) 5643abdb607SJ. Bruce Fields return NULL; 565996e0938SJ. Bruce Fields 5664770d722SJeff Layton idr_preload(GFP_KERNEL); 5674770d722SJeff Layton spin_lock(&cl->cl_lock); 5684770d722SJeff Layton new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT); 5694770d722SJeff Layton spin_unlock(&cl->cl_lock); 5704770d722SJeff Layton idr_preload_end(); 571ebd6c707STejun Heo if (new_id < 0) 5723abdb607SJ. Bruce Fields goto out_free; 5733abdb607SJ. Bruce Fields stid->sc_client = cl; 5743abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 5753abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 5763abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 57772c0b0fbSTrond Myklebust atomic_set(&stid->sc_count, 1); 5789767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 5793abdb607SJ. Bruce Fields 580996e0938SJ. Bruce Fields /* 5813abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 5823abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 5833abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 5843abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 5853abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 5863abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 5873abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 588996e0938SJ. Bruce Fields */ 5893abdb607SJ. Bruce Fields return stid; 5903abdb607SJ. Bruce Fields out_free: 5912c44a234SWei Yongjun kmem_cache_free(slab, stid); 5923abdb607SJ. Bruce Fields return NULL; 5932a74aba7SJ. Bruce Fields } 5942a74aba7SJ. Bruce Fields 595b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 5964cdc951bSJ. Bruce Fields { 5976011695dSTrond Myklebust struct nfs4_stid *stid; 5986011695dSTrond Myklebust struct nfs4_ol_stateid *stp; 5996011695dSTrond Myklebust 6006011695dSTrond Myklebust stid = nfs4_alloc_stid(clp, stateid_slab); 6016011695dSTrond Myklebust if (!stid) 6026011695dSTrond Myklebust return NULL; 6036011695dSTrond Myklebust 6046011695dSTrond Myklebust stp = openlockstateid(stid); 6056011695dSTrond Myklebust stp->st_stid.sc_free = nfs4_free_ol_stateid; 6066011695dSTrond Myklebust return stp; 6076011695dSTrond Myklebust } 6086011695dSTrond Myklebust 6096011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 6106011695dSTrond Myklebust { 6116011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 6126011695dSTrond Myklebust atomic_long_dec(&num_delegations); 6134cdc951bSJ. Bruce Fields } 6144cdc951bSJ. Bruce Fields 6156282cd56SNeilBrown /* 6166282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 6176282cd56SNeilBrown * out again straight away. 6186282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 6196282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 6206282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 6216282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 6226282cd56SNeilBrown * filter. 6236282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 6246282cd56SNeilBrown * unless both are empty of course. 6256282cd56SNeilBrown * 6266282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 6276282cd56SNeilBrown * low 3 bytes as hash-table indices. 6286282cd56SNeilBrown * 629f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 6306282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 6316282cd56SNeilBrown * except when swapping the two filters. 6326282cd56SNeilBrown */ 633f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 6346282cd56SNeilBrown static struct bloom_pair { 6356282cd56SNeilBrown int entries, old_entries; 6366282cd56SNeilBrown time_t swap_time; 6376282cd56SNeilBrown int new; /* index into 'set' */ 6386282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 6396282cd56SNeilBrown } blocked_delegations; 6406282cd56SNeilBrown 6416282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 6426282cd56SNeilBrown { 6436282cd56SNeilBrown u32 hash; 6446282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 6456282cd56SNeilBrown 6466282cd56SNeilBrown if (bd->entries == 0) 6476282cd56SNeilBrown return 0; 6486282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 649f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 6506282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 6516282cd56SNeilBrown bd->entries -= bd->old_entries; 6526282cd56SNeilBrown bd->old_entries = bd->entries; 6536282cd56SNeilBrown memset(bd->set[bd->new], 0, 6546282cd56SNeilBrown sizeof(bd->set[0])); 6556282cd56SNeilBrown bd->new = 1-bd->new; 6566282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 6576282cd56SNeilBrown } 658f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 6596282cd56SNeilBrown } 66087545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 6616282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 6626282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 6636282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 6646282cd56SNeilBrown return 1; 6656282cd56SNeilBrown 6666282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 6676282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 6686282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 6696282cd56SNeilBrown return 1; 6706282cd56SNeilBrown 6716282cd56SNeilBrown return 0; 6726282cd56SNeilBrown } 6736282cd56SNeilBrown 6746282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 6756282cd56SNeilBrown { 6766282cd56SNeilBrown u32 hash; 6776282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 6786282cd56SNeilBrown 67987545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 6806282cd56SNeilBrown 681f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 6826282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 6836282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 6846282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 6856282cd56SNeilBrown if (bd->entries == 0) 6866282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 6876282cd56SNeilBrown bd->entries += 1; 688f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 6896282cd56SNeilBrown } 6906282cd56SNeilBrown 6911da177e4SLinus Torvalds static struct nfs4_delegation * 6928287f009SSachin Bhamare alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh, 6938287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 6941da177e4SLinus Torvalds { 6951da177e4SLinus Torvalds struct nfs4_delegation *dp; 69602a3508dSTrond Myklebust long n; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 69902a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 70002a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 70102a3508dSTrond Myklebust goto out_dec; 7026282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 70302a3508dSTrond Myklebust goto out_dec; 704996e0938SJ. Bruce Fields dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); 7055b2d21c1SNeilBrown if (dp == NULL) 70602a3508dSTrond Myklebust goto out_dec; 7076011695dSTrond Myklebust 7086011695dSTrond Myklebust dp->dl_stid.sc_free = nfs4_free_deleg; 7092a74aba7SJ. Bruce Fields /* 7102a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 7116136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 7126136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 7132a74aba7SJ. Bruce Fields */ 7142a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 715ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 716ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 7171da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 7188287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 7198287f009SSachin Bhamare get_clnt_odstate(odstate); 72099c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 721f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 722f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 7230162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 7241da177e4SLinus Torvalds return dp; 72502a3508dSTrond Myklebust out_dec: 72602a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 72702a3508dSTrond Myklebust return NULL; 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds void 7316011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 7321da177e4SLinus Torvalds { 73311b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 7346011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 7356011695dSTrond Myklebust 7364770d722SJeff Layton might_lock(&clp->cl_lock); 7374770d722SJeff Layton 738b401be22SJeff Layton if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 739b401be22SJeff Layton wake_up_all(&close_wq); 7406011695dSTrond Myklebust return; 741b401be22SJeff Layton } 7426011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 7434770d722SJeff Layton spin_unlock(&clp->cl_lock); 7446011695dSTrond Myklebust s->sc_free(s); 74511b9164aSTrond Myklebust if (fp) 74611b9164aSTrond Myklebust put_nfs4_file(fp); 7471da177e4SLinus Torvalds } 7481da177e4SLinus Torvalds 7499767feb2SJeff Layton void 7509767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 7519767feb2SJeff Layton { 7529767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 7539767feb2SJeff Layton 7549767feb2SJeff Layton spin_lock(&stid->sc_lock); 7559767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 7569767feb2SJeff Layton src->si_generation = 1; 7579767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 7589767feb2SJeff Layton spin_unlock(&stid->sc_lock); 7599767feb2SJeff Layton } 7609767feb2SJeff Layton 761acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp) 7621da177e4SLinus Torvalds { 7636bcc034eSJeff Layton struct file *filp = NULL; 764417c6629SJeff Layton 7656bcc034eSJeff Layton spin_lock(&fp->fi_lock); 76667db1034SJeff Layton if (fp->fi_deleg_file && --fp->fi_delegees == 0) 7676bcc034eSJeff Layton swap(filp, fp->fi_deleg_file); 7686bcc034eSJeff Layton spin_unlock(&fp->fi_lock); 7696bcc034eSJeff Layton 7706bcc034eSJeff Layton if (filp) { 7712ab99ee1SChristoph Hellwig vfs_setlease(filp, F_UNLCK, NULL, (void **)&fp); 7726bcc034eSJeff Layton fput(filp); 773acfdf5c3SJ. Bruce Fields } 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds 776cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 7776136d2b4SJ. Bruce Fields { 7783abdb607SJ. Bruce Fields s->sc_type = 0; 7796136d2b4SJ. Bruce Fields } 7806136d2b4SJ. Bruce Fields 78134ed9872SAndrew Elble /** 78234ed9872SAndrew Elble * nfs4_get_existing_delegation - Discover if this delegation already exists 78334ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 78434ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 78534ed9872SAndrew Elble * 78634ed9872SAndrew Elble * Return: 78734ed9872SAndrew Elble * On success: NULL if an existing delegation was not found. 78834ed9872SAndrew Elble * 78934ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this nfs4_client 79034ed9872SAndrew Elble * for this nfs4_file. 79134ed9872SAndrew Elble * 79234ed9872SAndrew Elble */ 79334ed9872SAndrew Elble 79434ed9872SAndrew Elble static int 79534ed9872SAndrew Elble nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp) 796931ee56cSBenny Halevy { 79734ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 79834ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 79934ed9872SAndrew Elble 800cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 801417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 802931ee56cSBenny Halevy 80334ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 80434ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 80534ed9872SAndrew Elble if (clp == searchclp) { 80634ed9872SAndrew Elble return -EAGAIN; 80734ed9872SAndrew Elble } 80834ed9872SAndrew Elble } 80934ed9872SAndrew Elble return 0; 81034ed9872SAndrew Elble } 81134ed9872SAndrew Elble 81234ed9872SAndrew Elble /** 81334ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 81434ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 81534ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 81634ed9872SAndrew Elble * 81734ed9872SAndrew Elble * Return: 81834ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 81934ed9872SAndrew Elble * 82034ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 82134ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 82234ed9872SAndrew Elble * 82334ed9872SAndrew Elble */ 82434ed9872SAndrew Elble 82534ed9872SAndrew Elble static int 82634ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 82734ed9872SAndrew Elble { 82834ed9872SAndrew Elble int status; 82934ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 83034ed9872SAndrew Elble 83134ed9872SAndrew Elble lockdep_assert_held(&state_lock); 83234ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 83334ed9872SAndrew Elble 83434ed9872SAndrew Elble status = nfs4_get_existing_delegation(clp, fp); 83534ed9872SAndrew Elble if (status) 83634ed9872SAndrew Elble return status; 83734ed9872SAndrew Elble ++fp->fi_delegees; 83867cb1279STrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 8393fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 840931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 84134ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 84234ed9872SAndrew Elble return 0; 843931ee56cSBenny Halevy } 844931ee56cSBenny Halevy 8453fcbbd24SJeff Layton static bool 84642690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 8471da177e4SLinus Torvalds { 84811b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 84902e1215fSJeff Layton 85042690676SJeff Layton lockdep_assert_held(&state_lock); 85142690676SJeff Layton 8523fcbbd24SJeff Layton if (list_empty(&dp->dl_perfile)) 8533fcbbd24SJeff Layton return false; 8543fcbbd24SJeff Layton 855b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 856d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 857d55a166cSJeff Layton ++dp->dl_time; 858417c6629SJeff Layton spin_lock(&fp->fi_lock); 859931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 8601da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 86102e1215fSJeff Layton list_del_init(&dp->dl_perfile); 86202e1215fSJeff Layton spin_unlock(&fp->fi_lock); 8633fcbbd24SJeff Layton return true; 864cbf7a75bSJ. Bruce Fields } 8653bd64a5bSJ. Bruce Fields 8663bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 8673bd64a5bSJ. Bruce Fields { 8683fcbbd24SJeff Layton bool unhashed; 8693fcbbd24SJeff Layton 87042690676SJeff Layton spin_lock(&state_lock); 8713fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 87242690676SJeff Layton spin_unlock(&state_lock); 8733fcbbd24SJeff Layton if (unhashed) { 8748287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 875afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 8766011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 8773bd64a5bSJ. Bruce Fields } 8783fcbbd24SJeff Layton } 8793bd64a5bSJ. Bruce Fields 8803bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 8813bd64a5bSJ. Bruce Fields { 8823bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 8833bd64a5bSJ. Bruce Fields 8842d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 8852d4a532dSJeff Layton 8868287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 887afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 888afbda402SJeff Layton 8893bd64a5bSJ. Bruce Fields if (clp->cl_minorversion == 0) 8906011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 8913bd64a5bSJ. Bruce Fields else { 8923bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 8932d4a532dSJeff Layton spin_lock(&clp->cl_lock); 8942d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 8952d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 8963bd64a5bSJ. Bruce Fields } 8973bd64a5bSJ. Bruce Fields } 8983bd64a5bSJ. Bruce Fields 8991da177e4SLinus Torvalds /* 9001da177e4SLinus Torvalds * SETCLIENTID state 9011da177e4SLinus Torvalds */ 9021da177e4SLinus Torvalds 903ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 904ddc04c41SJ. Bruce Fields { 905ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 906ddc04c41SJ. Bruce Fields } 907ddc04c41SJ. Bruce Fields 908ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 909ddc04c41SJ. Bruce Fields { 910ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 911ddc04c41SJ. Bruce Fields } 912ddc04c41SJ. Bruce Fields 9131da177e4SLinus Torvalds /* 914f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 915f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 916f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 917f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 918f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 919f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 920f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 921f9d7562fSJ. Bruce Fields * 922f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 923f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 924f9d7562fSJ. Bruce Fields * 925f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 926f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 927f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 928f9d7562fSJ. Bruce Fields * 929f9d7562fSJ. Bruce Fields * which we should reject. 930f9d7562fSJ. Bruce Fields */ 9315ae037e5SJeff Layton static unsigned int 9325ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 933f9d7562fSJ. Bruce Fields int i; 9345ae037e5SJeff Layton unsigned int access = 0; 935f9d7562fSJ. Bruce Fields 936f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 937f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 9385ae037e5SJeff Layton access |= i; 939f9d7562fSJ. Bruce Fields } 9405ae037e5SJeff Layton return access; 941f9d7562fSJ. Bruce Fields } 942f9d7562fSJ. Bruce Fields 94382c5ff1bSJeff Layton /* set share access for a given stateid */ 94482c5ff1bSJeff Layton static inline void 94582c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 94682c5ff1bSJeff Layton { 947c11c591fSJeff Layton unsigned char mask = 1 << access; 948c11c591fSJeff Layton 949c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 950c11c591fSJeff Layton stp->st_access_bmap |= mask; 95182c5ff1bSJeff Layton } 95282c5ff1bSJeff Layton 95382c5ff1bSJeff Layton /* clear share access for a given stateid */ 95482c5ff1bSJeff Layton static inline void 95582c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 95682c5ff1bSJeff Layton { 957c11c591fSJeff Layton unsigned char mask = 1 << access; 958c11c591fSJeff Layton 959c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 960c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 96182c5ff1bSJeff Layton } 96282c5ff1bSJeff Layton 96382c5ff1bSJeff Layton /* test whether a given stateid has access */ 96482c5ff1bSJeff Layton static inline bool 96582c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 96682c5ff1bSJeff Layton { 967c11c591fSJeff Layton unsigned char mask = 1 << access; 968c11c591fSJeff Layton 969c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 97082c5ff1bSJeff Layton } 97182c5ff1bSJeff Layton 972ce0fc43cSJeff Layton /* set share deny for a given stateid */ 973ce0fc43cSJeff Layton static inline void 974c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 975ce0fc43cSJeff Layton { 976c11c591fSJeff Layton unsigned char mask = 1 << deny; 977c11c591fSJeff Layton 978c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 979c11c591fSJeff Layton stp->st_deny_bmap |= mask; 980ce0fc43cSJeff Layton } 981ce0fc43cSJeff Layton 982ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 983ce0fc43cSJeff Layton static inline void 984c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 985ce0fc43cSJeff Layton { 986c11c591fSJeff Layton unsigned char mask = 1 << deny; 987c11c591fSJeff Layton 988c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 989c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 990ce0fc43cSJeff Layton } 991ce0fc43cSJeff Layton 992ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 993ce0fc43cSJeff Layton static inline bool 994c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 995ce0fc43cSJeff Layton { 996c11c591fSJeff Layton unsigned char mask = 1 << deny; 997c11c591fSJeff Layton 998c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 999f9d7562fSJ. Bruce Fields } 1000f9d7562fSJ. Bruce Fields 1001f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 1002f9d7562fSJ. Bruce Fields { 10038f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 1004f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 1005f9d7562fSJ. Bruce Fields return O_RDONLY; 1006f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 1007f9d7562fSJ. Bruce Fields return O_WRONLY; 1008f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 1009f9d7562fSJ. Bruce Fields return O_RDWR; 1010f9d7562fSJ. Bruce Fields } 1011063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 1012063b0fb9SJ. Bruce Fields return O_RDONLY; 1013f9d7562fSJ. Bruce Fields } 1014f9d7562fSJ. Bruce Fields 1015baeb4ff0SJeff Layton /* 1016baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1017baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1018baeb4ff0SJeff Layton */ 1019baeb4ff0SJeff Layton static void 1020baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1021baeb4ff0SJeff Layton { 1022baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1023baeb4ff0SJeff Layton 1024baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1025baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1026baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1027baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1028baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1029baeb4ff0SJeff Layton } 1030baeb4ff0SJeff Layton 1031baeb4ff0SJeff Layton static void 1032baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1033baeb4ff0SJeff Layton { 1034baeb4ff0SJeff Layton int i; 1035baeb4ff0SJeff Layton bool change = false; 1036baeb4ff0SJeff Layton 1037baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1038baeb4ff0SJeff Layton if ((i & deny) != i) { 1039baeb4ff0SJeff Layton change = true; 1040baeb4ff0SJeff Layton clear_deny(i, stp); 1041baeb4ff0SJeff Layton } 1042baeb4ff0SJeff Layton } 1043baeb4ff0SJeff Layton 1044baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1045baeb4ff0SJeff Layton if (change) 104611b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1047baeb4ff0SJeff Layton } 1048baeb4ff0SJeff Layton 104982c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 105082c5ff1bSJeff Layton static void 105182c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 105282c5ff1bSJeff Layton { 105382c5ff1bSJeff Layton int i; 105411b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1055baeb4ff0SJeff Layton 1056baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1057baeb4ff0SJeff Layton recalculate_deny_mode(fp); 105882c5ff1bSJeff Layton 105982c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 106082c5ff1bSJeff Layton if (test_access(i, stp)) 106111b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 106282c5ff1bSJeff Layton clear_access(i, stp); 106382c5ff1bSJeff Layton } 106482c5ff1bSJeff Layton } 106582c5ff1bSJeff Layton 1066d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1067d50ffdedSKinglong Mee { 1068d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1069d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1070d50ffdedSKinglong Mee } 1071d50ffdedSKinglong Mee 10726b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 10736b180f0bSJeff Layton { 1074a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1075a819ecc1SJeff Layton 1076a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1077a819ecc1SJeff Layton 1078a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 10796b180f0bSJeff Layton return; 10808f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1081a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1082d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 10836b180f0bSJeff Layton } 10846b180f0bSJeff Layton 1085e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1086529d7b2aSJ. Bruce Fields { 108711b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 10881d31a253STrond Myklebust 10891c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 10901c755dc1SJeff Layton 1091e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1092e8568739SJeff Layton return false; 1093e8568739SJeff Layton 10941d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1095e8568739SJeff Layton list_del_init(&stp->st_perfile); 10961d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1097529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1098e8568739SJeff Layton return true; 1099529d7b2aSJ. Bruce Fields } 1100529d7b2aSJ. Bruce Fields 11016011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1102529d7b2aSJ. Bruce Fields { 11036011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 11044665e2baSJ. Bruce Fields 11058287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 11066011695dSTrond Myklebust release_all_access(stp); 1107d3134b10SJeff Layton if (stp->st_stateowner) 1108d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 11096011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1110529d7b2aSJ. Bruce Fields } 1111529d7b2aSJ. Bruce Fields 1112b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1113529d7b2aSJ. Bruce Fields { 1114b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1115b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1116529d7b2aSJ. Bruce Fields struct file *file; 1117529d7b2aSJ. Bruce Fields 1118b49e084dSJeff Layton file = find_any_file(stp->st_stid.sc_file); 1119b49e084dSJeff Layton if (file) 1120b49e084dSJeff Layton filp_close(file, (fl_owner_t)lo); 1121b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1122b49e084dSJeff Layton } 1123b49e084dSJeff Layton 11242c41beb0SJeff Layton /* 11252c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 11262c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 11272c41beb0SJeff Layton * reaplist for later destruction. 11282c41beb0SJeff Layton */ 11292c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 11302c41beb0SJeff Layton struct list_head *reaplist) 11312c41beb0SJeff Layton { 11322c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 11332c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 11342c41beb0SJeff Layton 11352c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 11362c41beb0SJeff Layton 11372c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 11382c41beb0SJeff Layton 11392c41beb0SJeff Layton if (!atomic_dec_and_test(&s->sc_count)) { 11402c41beb0SJeff Layton wake_up_all(&close_wq); 11412c41beb0SJeff Layton return; 11422c41beb0SJeff Layton } 11432c41beb0SJeff Layton 11442c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 11452c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 11462c41beb0SJeff Layton } 11472c41beb0SJeff Layton 1148e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 11493c1c995cSJeff Layton { 11503c1c995cSJeff Layton struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 11513c1c995cSJeff Layton 11523c1c995cSJeff Layton lockdep_assert_held(&oo->oo_owner.so_client->cl_lock); 11533c1c995cSJeff Layton 11543c1c995cSJeff Layton list_del_init(&stp->st_locks); 1155cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1156e8568739SJeff Layton return unhash_ol_stateid(stp); 11573c1c995cSJeff Layton } 11583c1c995cSJeff Layton 11595adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1160b49e084dSJeff Layton { 11611c755dc1SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 1162e8568739SJeff Layton bool unhashed; 11631c755dc1SJeff Layton 11641c755dc1SJeff Layton spin_lock(&oo->oo_owner.so_client->cl_lock); 1165e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 11661c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 1167e8568739SJeff Layton if (unhashed) 11686011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1169529d7b2aSJ. Bruce Fields } 1170529d7b2aSJ. Bruce Fields 1171c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1172529d7b2aSJ. Bruce Fields { 1173d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1174c58c6610STrond Myklebust 1175d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1176c58c6610STrond Myklebust 11778f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 11788f4b54c5SJeff Layton } 11798f4b54c5SJeff Layton 11802c41beb0SJeff Layton /* 11812c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 11822c41beb0SJeff Layton * fully unhashed. 11832c41beb0SJeff Layton */ 11842c41beb0SJeff Layton static void 11852c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 11862c41beb0SJeff Layton { 11872c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1188fb94d766SKinglong Mee struct nfs4_file *fp; 11892c41beb0SJeff Layton 11902c41beb0SJeff Layton might_sleep(); 11912c41beb0SJeff Layton 11922c41beb0SJeff Layton while (!list_empty(reaplist)) { 11932c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 11942c41beb0SJeff Layton st_locks); 11952c41beb0SJeff Layton list_del(&stp->st_locks); 1196fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 11972c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1198fb94d766SKinglong Mee if (fp) 1199fb94d766SKinglong Mee put_nfs4_file(fp); 12002c41beb0SJeff Layton } 12012c41beb0SJeff Layton } 12022c41beb0SJeff Layton 1203fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo) 1204529d7b2aSJ. Bruce Fields { 1205d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 12063c1c995cSJeff Layton struct nfs4_ol_stateid *stp; 12073c1c995cSJeff Layton struct list_head reaplist; 12083c1c995cSJeff Layton 12093c1c995cSJeff Layton INIT_LIST_HEAD(&reaplist); 1210c58c6610STrond Myklebust 1211d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 1212c58c6610STrond Myklebust unhash_lockowner_locked(lo); 12133c1c995cSJeff Layton while (!list_empty(&lo->lo_owner.so_stateids)) { 12143c1c995cSJeff Layton stp = list_first_entry(&lo->lo_owner.so_stateids, 12153c1c995cSJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1216e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 12172c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 12183c1c995cSJeff Layton } 1219d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 12202c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 12216b180f0bSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 1222529d7b2aSJ. Bruce Fields } 1223529d7b2aSJ. Bruce Fields 1224d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1225d83017f9SJeff Layton struct list_head *reaplist) 12263c87b9b7STrond Myklebust { 12273c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 12283c87b9b7STrond Myklebust 1229e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1230e8568739SJeff Layton 12313c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 12323c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 12333c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1234e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1235d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1236529d7b2aSJ. Bruce Fields } 1237529d7b2aSJ. Bruce Fields } 1238529d7b2aSJ. Bruce Fields 1239e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1240d83017f9SJeff Layton struct list_head *reaplist) 12412283963fSJ. Bruce Fields { 1242e8568739SJeff Layton bool unhashed; 1243e8568739SJeff Layton 12442c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 12452c41beb0SJeff Layton 1246e8568739SJeff Layton unhashed = unhash_ol_stateid(stp); 1247d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1248e8568739SJeff Layton return unhashed; 124938c387b5SJ. Bruce Fields } 125038c387b5SJ. Bruce Fields 125138c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 125238c387b5SJ. Bruce Fields { 12532c41beb0SJeff Layton LIST_HEAD(reaplist); 12542c41beb0SJeff Layton 12552c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1256e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 12572c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 12582c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 12592c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 12602283963fSJ. Bruce Fields } 12612283963fSJ. Bruce Fields 12627ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1263f1d110caSJ. Bruce Fields { 1264d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 12657ffb5880STrond Myklebust 1266d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 12677ffb5880STrond Myklebust 12688f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 12698f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1270f1d110caSJ. Bruce Fields } 1271f1d110caSJ. Bruce Fields 1272f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1273f7a4d872SJ. Bruce Fields { 1274217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1275217526e7SJeff Layton nfsd_net_id); 1276217526e7SJeff Layton struct nfs4_ol_stateid *s; 1277f7a4d872SJ. Bruce Fields 1278217526e7SJeff Layton spin_lock(&nn->client_lock); 1279217526e7SJeff Layton s = oo->oo_last_closed_stid; 1280f7a4d872SJ. Bruce Fields if (s) { 1281d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1282f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1283f7a4d872SJ. Bruce Fields } 1284217526e7SJeff Layton spin_unlock(&nn->client_lock); 1285217526e7SJeff Layton if (s) 1286217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1287f7a4d872SJ. Bruce Fields } 1288f7a4d872SJ. Bruce Fields 12892c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 12908f4b54c5SJeff Layton { 12918f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1292d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 12932c41beb0SJeff Layton struct list_head reaplist; 12947ffb5880STrond Myklebust 12952c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 12967ffb5880STrond Myklebust 1297d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 12987ffb5880STrond Myklebust unhash_openowner_locked(oo); 12992c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 13002c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 13012c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1302e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 13032c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 13042c41beb0SJeff Layton } 1305d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 13062c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1307f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 13086b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1309f1d110caSJ. Bruce Fields } 1310f1d110caSJ. Bruce Fields 13115282fd72SMarc Eshel static inline int 13125282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 13135282fd72SMarc Eshel { 13145282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 13155282fd72SMarc Eshel 13165282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 13175282fd72SMarc Eshel } 13185282fd72SMarc Eshel 1319135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 13205282fd72SMarc Eshel static inline void 13215282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 13225282fd72SMarc Eshel { 13235282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 13245282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 13255282fd72SMarc Eshel } 13268f199b82STrond Myklebust #else 13278f199b82STrond Myklebust static inline void 13288f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 13298f199b82STrond Myklebust { 13308f199b82STrond Myklebust } 13318f199b82STrond Myklebust #endif 13328f199b82STrond Myklebust 13339411b1d4SJ. Bruce Fields /* 13349411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 13359411b1d4SJ. Bruce Fields * won't be used for replay. 13369411b1d4SJ. Bruce Fields */ 13379411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 13389411b1d4SJ. Bruce Fields { 13399411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 13409411b1d4SJ. Bruce Fields 13419411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 13429411b1d4SJ. Bruce Fields return; 13439411b1d4SJ. Bruce Fields 13449411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 134558fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 13469411b1d4SJ. Bruce Fields return; 13479411b1d4SJ. Bruce Fields } 13489411b1d4SJ. Bruce Fields if (!so) 13499411b1d4SJ. Bruce Fields return; 13509411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 13519411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 13529411b1d4SJ. Bruce Fields so->so_seqid++; 13539411b1d4SJ. Bruce Fields return; 13549411b1d4SJ. Bruce Fields } 13555282fd72SMarc Eshel 1356ec6b5d7bSAndy Adamson static void 1357ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1358ec6b5d7bSAndy Adamson { 1359ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1360ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1361ec6b5d7bSAndy Adamson 1362ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1363ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1364ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1365ec6b5d7bSAndy Adamson sid->reserved = 0; 1366ec6b5d7bSAndy Adamson } 1367ec6b5d7bSAndy Adamson 1368ec6b5d7bSAndy Adamson /* 1369a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1370a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1371a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1372a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1373a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1374a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1375a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1376a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1377a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1378a649637cSAndy Adamson * for the SEQUENCE op response: 1379ec6b5d7bSAndy Adamson */ 1380a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1381a649637cSAndy Adamson 1382557ce264SAndy Adamson static void 1383557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1384557ce264SAndy Adamson { 1385557ce264SAndy Adamson int i; 1386557ce264SAndy Adamson 1387557ce264SAndy Adamson for (i = 0; i < ses->se_fchannel.maxreqs; i++) 1388557ce264SAndy Adamson kfree(ses->se_slots[i]); 1389557ce264SAndy Adamson } 1390557ce264SAndy Adamson 1391efe0cb6dSJ. Bruce Fields /* 1392efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1393efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1394efe0cb6dSJ. Bruce Fields */ 139555c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1396efe0cb6dSJ. Bruce Fields { 139755c760cfSJ. Bruce Fields u32 size; 1398efe0cb6dSJ. Bruce Fields 139955c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 140055c760cfSJ. Bruce Fields size = 0; 140155c760cfSJ. Bruce Fields else 140255c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 140355c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1404557ce264SAndy Adamson } 1405557ce264SAndy Adamson 14065b6feee9SJ. Bruce Fields /* 14075b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 14085b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 140942b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 14105b6feee9SJ. Bruce Fields */ 141155c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 14125b6feee9SJ. Bruce Fields { 141355c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 141455c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 14155b6feee9SJ. Bruce Fields int avail; 14165b6feee9SJ. Bruce Fields 14175b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 1418697ce9beSZhang Yanfei avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, 14195b6feee9SJ. Bruce Fields nfsd_drc_max_mem - nfsd_drc_mem_used); 14205b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 14215b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 14225b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 14235b6feee9SJ. Bruce Fields 14245b6feee9SJ. Bruce Fields return num; 14255b6feee9SJ. Bruce Fields } 14265b6feee9SJ. Bruce Fields 142755c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 14285b6feee9SJ. Bruce Fields { 142955c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 143055c760cfSJ. Bruce Fields 14315b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 143255c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 14335b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 14345b6feee9SJ. Bruce Fields } 14355b6feee9SJ. Bruce Fields 143660810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 143760810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 14385b6feee9SJ. Bruce Fields { 143960810e54SKinglong Mee int numslots = fattrs->maxreqs; 144060810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 14415b6feee9SJ. Bruce Fields struct nfsd4_session *new; 14425b6feee9SJ. Bruce Fields int mem, i; 1443ec6b5d7bSAndy Adamson 1444c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1445ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 14465b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1447ec6b5d7bSAndy Adamson 14485b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 14496c18ba9fSAlexandros Batsakis if (!new) 14505b6feee9SJ. Bruce Fields return NULL; 1451ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 14525b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 145355c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 14545b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1455ec6b5d7bSAndy Adamson goto out_free; 1456ec6b5d7bSAndy Adamson } 145760810e54SKinglong Mee 145860810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 145960810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 146060810e54SKinglong Mee 14615b6feee9SJ. Bruce Fields return new; 14625b6feee9SJ. Bruce Fields out_free: 14635b6feee9SJ. Bruce Fields while (i--) 14645b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 14655b6feee9SJ. Bruce Fields kfree(new); 14665b6feee9SJ. Bruce Fields return NULL; 14675b6feee9SJ. Bruce Fields } 14685b6feee9SJ. Bruce Fields 146919cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 147019cf5c02SJ. Bruce Fields { 147119cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 147219cf5c02SJ. Bruce Fields kfree(c); 147319cf5c02SJ. Bruce Fields } 147419cf5c02SJ. Bruce Fields 147519cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 147619cf5c02SJ. Bruce Fields { 147719cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 147819cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 147919cf5c02SJ. Bruce Fields 148019cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 148119cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 148219cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 148319cf5c02SJ. Bruce Fields free_conn(c); 148419cf5c02SJ. Bruce Fields } 1485eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 14862e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 148719cf5c02SJ. Bruce Fields } 148819cf5c02SJ. Bruce Fields 1489d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1490c7662518SJ. Bruce Fields { 1491c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1492c7662518SJ. Bruce Fields 1493c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1494c7662518SJ. Bruce Fields if (!conn) 1495db90681dSJ. Bruce Fields return NULL; 1496c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1497c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1498d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1499db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1500db90681dSJ. Bruce Fields return conn; 1501db90681dSJ. Bruce Fields } 1502db90681dSJ. Bruce Fields 1503328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1504328ead28SJ. Bruce Fields { 1505328ead28SJ. Bruce Fields conn->cn_session = ses; 1506328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1507328ead28SJ. Bruce Fields } 1508328ead28SJ. Bruce Fields 1509db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1510db90681dSJ. Bruce Fields { 1511db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1512c7662518SJ. Bruce Fields 1513c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1514328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1515c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1516db90681dSJ. Bruce Fields } 1517c7662518SJ. Bruce Fields 151821b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1519db90681dSJ. Bruce Fields { 152019cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 152121b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1522db90681dSJ. Bruce Fields } 1523db90681dSJ. Bruce Fields 1524e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1525db90681dSJ. Bruce Fields { 152621b75b01SJ. Bruce Fields int ret; 1527db90681dSJ. Bruce Fields 1528db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 152921b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 153021b75b01SJ. Bruce Fields if (ret) 153121b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 153221b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 153357a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 153457a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1535c7662518SJ. Bruce Fields } 1536c7662518SJ. Bruce Fields 1537e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 15381d1bc8f2SJ. Bruce Fields { 15391d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 15401d1bc8f2SJ. Bruce Fields 1541e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 15421d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1543e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 15441d1bc8f2SJ. Bruce Fields } 15451d1bc8f2SJ. Bruce Fields 15461d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 154719cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1548c7662518SJ. Bruce Fields { 154919cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 155019cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 155119cf5c02SJ. Bruce Fields 155219cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 155319cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 155419cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 155519cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 155619cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 155719cf5c02SJ. Bruce Fields 155819cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 155919cf5c02SJ. Bruce Fields free_conn(c); 156019cf5c02SJ. Bruce Fields 156119cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 156219cf5c02SJ. Bruce Fields } 156319cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1564c7662518SJ. Bruce Fields } 1565c7662518SJ. Bruce Fields 15661377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 15671377b69eSJ. Bruce Fields { 15681377b69eSJ. Bruce Fields free_session_slots(ses); 15691377b69eSJ. Bruce Fields kfree(ses); 15701377b69eSJ. Bruce Fields } 15711377b69eSJ. Bruce Fields 157266b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1573508dc6e1SBenny Halevy { 1574c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 157555c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1576c7662518SJ. Bruce Fields __free_session(ses); 1577a827bcb2SJ. Bruce Fields } 1578ec6b5d7bSAndy Adamson 1579135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1580a827bcb2SJ. Bruce Fields { 1581a827bcb2SJ. Bruce Fields int idx; 15821872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1583a827bcb2SJ. Bruce Fields 1584ec6b5d7bSAndy Adamson new->se_client = clp; 1585ec6b5d7bSAndy Adamson gen_sessionid(new); 1586ec6b5d7bSAndy Adamson 1587c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1588c7662518SJ. Bruce Fields 1589ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1590ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 15918b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1592c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 159366b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 15945b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 15951872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 15964c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1597ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 15984c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 159960810e54SKinglong Mee 1600b0d2e42cSChuck Lever { 1601edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1602dcbeaa68SJ. Bruce Fields /* 1603dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1604dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1605dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1606dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1607dcbeaa68SJ. Bruce Fields * future: 1608dcbeaa68SJ. Bruce Fields */ 1609edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1610edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1611edd76786SJ. Bruce Fields } 1612ec6b5d7bSAndy Adamson } 1613ec6b5d7bSAndy Adamson 16149089f1b4SBenny Halevy /* caller must hold client_lock */ 16155282fd72SMarc Eshel static struct nfsd4_session * 1616d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 16175282fd72SMarc Eshel { 16185282fd72SMarc Eshel struct nfsd4_session *elem; 16195282fd72SMarc Eshel int idx; 16201872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 16215282fd72SMarc Eshel 16220a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 16230a880a28STrond Myklebust 16245282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 16255282fd72SMarc Eshel idx = hash_sessionid(sessionid); 16265282fd72SMarc Eshel /* Search in the appropriate list */ 16271872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 16285282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 16295282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 16305282fd72SMarc Eshel return elem; 16315282fd72SMarc Eshel } 16325282fd72SMarc Eshel } 16335282fd72SMarc Eshel 16345282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 16355282fd72SMarc Eshel return NULL; 16365282fd72SMarc Eshel } 16375282fd72SMarc Eshel 1638d4e19e70STrond Myklebust static struct nfsd4_session * 1639d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1640d4e19e70STrond Myklebust __be32 *ret) 1641d4e19e70STrond Myklebust { 1642d4e19e70STrond Myklebust struct nfsd4_session *session; 1643d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1644d4e19e70STrond Myklebust 1645d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1646d4e19e70STrond Myklebust if (!session) 1647d4e19e70STrond Myklebust goto out; 1648d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1649d4e19e70STrond Myklebust if (status) 1650d4e19e70STrond Myklebust session = NULL; 1651d4e19e70STrond Myklebust out: 1652d4e19e70STrond Myklebust *ret = status; 1653d4e19e70STrond Myklebust return session; 1654d4e19e70STrond Myklebust } 1655d4e19e70STrond Myklebust 16569089f1b4SBenny Halevy /* caller must hold client_lock */ 16577116ed6bSAndy Adamson static void 16585282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 16597116ed6bSAndy Adamson { 16600a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 16610a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 16620a880a28STrond Myklebust 16630a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 16640a880a28STrond Myklebust 16657116ed6bSAndy Adamson list_del(&ses->se_hash); 16664c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 16677116ed6bSAndy Adamson list_del(&ses->se_perclnt); 16684c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 16695282fd72SMarc Eshel } 16705282fd72SMarc Eshel 16711da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 16721da177e4SLinus Torvalds static int 16732c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 16741da177e4SLinus Torvalds { 1675bbc7f33aSJ. Bruce Fields /* 1676bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 1677bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 1678bbc7f33aSJ. Bruce Fields * a safe assumption: 1679bbc7f33aSJ. Bruce Fields */ 1680bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 16811da177e4SLinus Torvalds return 0; 168260adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 16832c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 16841da177e4SLinus Torvalds return 1; 16851da177e4SLinus Torvalds } 16861da177e4SLinus Torvalds 16871da177e4SLinus Torvalds /* 16881da177e4SLinus Torvalds * XXX Should we use a slab cache ? 16891da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 16901da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 16911da177e4SLinus Torvalds */ 169235bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 16931da177e4SLinus Torvalds { 16941da177e4SLinus Torvalds struct nfs4_client *clp; 1695d4f0489fSTrond Myklebust int i; 16961da177e4SLinus Torvalds 169735bba9a3SJ. Bruce Fields clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); 169835bba9a3SJ. Bruce Fields if (clp == NULL) 169935bba9a3SJ. Bruce Fields return NULL; 170067114fe6SThomas Meyer clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); 1701d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1702d4f0489fSTrond Myklebust goto err_no_name; 1703d4f0489fSTrond Myklebust clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * 1704d4f0489fSTrond Myklebust OWNER_HASH_SIZE, GFP_KERNEL); 1705d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1706d4f0489fSTrond Myklebust goto err_no_hashtbl; 1707d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1708d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 17091da177e4SLinus Torvalds clp->cl_name.len = name.len; 17105694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 17115694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 17125694c93eSTrond Myklebust atomic_set(&clp->cl_refcount, 0); 17135694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 17145694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 17155694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 17165694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 17175694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 17185694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 17199cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 17209cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 17219cf514ccSChristoph Hellwig #endif 17225694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 17235694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 17241da177e4SLinus Torvalds return clp; 1725d4f0489fSTrond Myklebust err_no_hashtbl: 1726d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1727d4f0489fSTrond Myklebust err_no_name: 1728d4f0489fSTrond Myklebust kfree(clp); 1729d4f0489fSTrond Myklebust return NULL; 17301da177e4SLinus Torvalds } 17311da177e4SLinus Torvalds 17324dd86e15STrond Myklebust static void 17331da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 17341da177e4SLinus Torvalds { 1735792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1736792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1737792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1738792c95ddSJ. Bruce Fields se_perclnt); 1739792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 174066b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 174166b2b9b2SJ. Bruce Fields free_session(ses); 1742792c95ddSJ. Bruce Fields } 17434cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 174403a4e1f6SJ. Bruce Fields free_svc_cred(&clp->cl_cred); 1745d4f0489fSTrond Myklebust kfree(clp->cl_ownerstr_hashtbl); 17461da177e4SLinus Torvalds kfree(clp->cl_name.data); 17472d32b29aSmajianpeng idr_destroy(&clp->cl_stateids); 17481da177e4SLinus Torvalds kfree(clp); 17491da177e4SLinus Torvalds } 17501da177e4SLinus Torvalds 175184d38ac9SBenny Halevy /* must be called under the client_lock */ 17524beb345bSTrond Myklebust static void 175384d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 175484d38ac9SBenny Halevy { 17554beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1756792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1757792c95ddSJ. Bruce Fields 17580a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 17590a880a28STrond Myklebust 17604beb345bSTrond Myklebust /* Mark the client as expired! */ 17614beb345bSTrond Myklebust clp->cl_time = 0; 17624beb345bSTrond Myklebust /* Make it invisible */ 17634beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 17644beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 17654beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 17664beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 17674beb345bSTrond Myklebust else 17684beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 17694beb345bSTrond Myklebust } 17704beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 17714c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1772792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1773792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 17744c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 177584d38ac9SBenny Halevy } 177684d38ac9SBenny Halevy 17771da177e4SLinus Torvalds static void 17784beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 17794beb345bSTrond Myklebust { 17804beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 17814beb345bSTrond Myklebust 17824beb345bSTrond Myklebust spin_lock(&nn->client_lock); 17834beb345bSTrond Myklebust unhash_client_locked(clp); 17844beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 17854beb345bSTrond Myklebust } 17864beb345bSTrond Myklebust 178797403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 178897403d95SJeff Layton { 178997403d95SJeff Layton if (atomic_read(&clp->cl_refcount)) 179097403d95SJeff Layton return nfserr_jukebox; 179197403d95SJeff Layton unhash_client_locked(clp); 179297403d95SJeff Layton return nfs_ok; 179397403d95SJeff Layton } 179497403d95SJeff Layton 17954beb345bSTrond Myklebust static void 17964beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 17971da177e4SLinus Torvalds { 1798fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 17991da177e4SLinus Torvalds struct nfs4_delegation *dp; 18001da177e4SLinus Torvalds struct list_head reaplist; 18011da177e4SLinus Torvalds 18021da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 1803cdc97505SBenny Halevy spin_lock(&state_lock); 1804ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 1805ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 18063fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 180742690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 18081da177e4SLinus Torvalds } 1809cdc97505SBenny Halevy spin_unlock(&state_lock); 18101da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 18111da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 181242690676SJeff Layton list_del_init(&dp->dl_recall_lru); 18138287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 1814afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 18156011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 18161da177e4SLinus Torvalds } 18172d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 1818c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 18192d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 18206011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 1821956c4feeSBenny Halevy } 1822ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 1823fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1824b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 1825fe0750e5SJ. Bruce Fields release_openowner(oo); 18261da177e4SLinus Torvalds } 18279cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 18286ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 18292bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 18302bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1831b12a05cbSJ. Bruce Fields free_client(clp); 18321da177e4SLinus Torvalds } 18331da177e4SLinus Torvalds 18344beb345bSTrond Myklebust static void 18354beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 18364beb345bSTrond Myklebust { 18374beb345bSTrond Myklebust unhash_client(clp); 18384beb345bSTrond Myklebust __destroy_client(clp); 18394beb345bSTrond Myklebust } 18404beb345bSTrond Myklebust 18410d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 18420d22f68fSJ. Bruce Fields { 18434beb345bSTrond Myklebust unhash_client(clp); 18440d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 18454beb345bSTrond Myklebust __destroy_client(clp); 18460d22f68fSJ. Bruce Fields } 18470d22f68fSJ. Bruce Fields 184835bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 184935bba9a3SJ. Bruce Fields { 185035bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 185135bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 18521da177e4SLinus Torvalds } 18531da177e4SLinus Torvalds 185435bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 185535bba9a3SJ. Bruce Fields { 18561da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 18571da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 18581da177e4SLinus Torvalds } 18591da177e4SLinus Torvalds 186050043859SJ. Bruce Fields int strdup_if_nonnull(char **target, char *source) 186135bba9a3SJ. Bruce Fields { 186250043859SJ. Bruce Fields if (source) { 186350043859SJ. Bruce Fields *target = kstrdup(source, GFP_KERNEL); 186450043859SJ. Bruce Fields if (!*target) 186503a4e1f6SJ. Bruce Fields return -ENOMEM; 186603a4e1f6SJ. Bruce Fields } else 186750043859SJ. Bruce Fields *target = NULL; 186850043859SJ. Bruce Fields return 0; 186950043859SJ. Bruce Fields } 187050043859SJ. Bruce Fields 187150043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 187250043859SJ. Bruce Fields { 187350043859SJ. Bruce Fields int ret; 187450043859SJ. Bruce Fields 187550043859SJ. Bruce Fields ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal); 187650043859SJ. Bruce Fields if (ret) 187750043859SJ. Bruce Fields return ret; 1878d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 18791da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 18801da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 18811da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 18821da177e4SLinus Torvalds get_group_info(target->cr_group_info); 18830dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 18840dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 18850dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 188603a4e1f6SJ. Bruce Fields return 0; 18871da177e4SLinus Torvalds } 18881da177e4SLinus Torvalds 1889ef17af2aSRasmus Villemoes static int 1890ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 1891ac55fdc4SJeff Layton { 1892ef17af2aSRasmus Villemoes if (o1->len < o2->len) 1893ef17af2aSRasmus Villemoes return -1; 1894ef17af2aSRasmus Villemoes if (o1->len > o2->len) 1895ef17af2aSRasmus Villemoes return 1; 1896ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 1897ac55fdc4SJeff Layton } 1898ac55fdc4SJeff Layton 189935bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 1900599e0a22SJ. Bruce Fields { 1901a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 19021da177e4SLinus Torvalds } 19031da177e4SLinus Torvalds 19041da177e4SLinus Torvalds static int 1905599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 1906599e0a22SJ. Bruce Fields { 1907599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 19081da177e4SLinus Torvalds } 19091da177e4SLinus Torvalds 19101da177e4SLinus Torvalds static int 1911599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 1912599e0a22SJ. Bruce Fields { 1913599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 19141da177e4SLinus Torvalds } 19151da177e4SLinus Torvalds 19168fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 19178fbba96eSJ. Bruce Fields { 19188fbba96eSJ. Bruce Fields int i; 19198fbba96eSJ. Bruce Fields 19208fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 19218fbba96eSJ. Bruce Fields return false; 19228fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 19236fab8779SEric W. Biederman if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i))) 19248fbba96eSJ. Bruce Fields return false; 19258fbba96eSJ. Bruce Fields return true; 19268fbba96eSJ. Bruce Fields } 19278fbba96eSJ. Bruce Fields 192868eb3508SJ. Bruce Fields /* 192968eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 193068eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 193168eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 193268eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 193368eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 193468eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 193568eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 193668eb3508SJ. Bruce Fields */ 193768eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 193868eb3508SJ. Bruce Fields { 193968eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 194068eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 194168eb3508SJ. Bruce Fields } 194268eb3508SJ. Bruce Fields 194368eb3508SJ. Bruce Fields 19445559b50aSVivek Trivedi static bool 1945599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 1946599e0a22SJ. Bruce Fields { 194768eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 19486fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 19496fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 19508fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 19518fbba96eSJ. Bruce Fields return false; 19528fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 19538fbba96eSJ. Bruce Fields return true; 19548fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 19558fbba96eSJ. Bruce Fields return false; 19565559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 19571da177e4SLinus Torvalds } 19581da177e4SLinus Torvalds 195957266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 196057266a6eSJ. Bruce Fields { 196157266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 196257266a6eSJ. Bruce Fields u32 service; 196357266a6eSJ. Bruce Fields 1964c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 1965c4720591SJ. Bruce Fields return false; 196657266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 196757266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 196857266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 196957266a6eSJ. Bruce Fields } 197057266a6eSJ. Bruce Fields 197157266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 197257266a6eSJ. Bruce Fields { 197357266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 197457266a6eSJ. Bruce Fields 197557266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 197657266a6eSJ. Bruce Fields return true; 197757266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 197857266a6eSJ. Bruce Fields return false; 197957266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 198057266a6eSJ. Bruce Fields return false; 198157266a6eSJ. Bruce Fields if (!cr->cr_principal) 198257266a6eSJ. Bruce Fields return false; 198357266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 198457266a6eSJ. Bruce Fields } 198557266a6eSJ. Bruce Fields 1986294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 1987deda2faaSJ. Bruce Fields { 1988ab4684d1SChuck Lever __be32 verf[2]; 19891da177e4SLinus Torvalds 1990f419992cSJeff Layton /* 1991f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 1992f419992cSJeff Layton * __force to keep sparse happy 1993f419992cSJeff Layton */ 1994f419992cSJeff Layton verf[0] = (__force __be32)get_seconds(); 199519311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 1996ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 19971da177e4SLinus Torvalds } 19981da177e4SLinus Torvalds 1999294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2000294ac32eSJeff Layton { 2001294ac32eSJeff Layton clp->cl_clientid.cl_boot = nn->boot_time; 2002294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2003294ac32eSJeff Layton gen_confirm(clp, nn); 2004294ac32eSJeff Layton } 2005294ac32eSJeff Layton 20064770d722SJeff Layton static struct nfs4_stid * 20074770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 20084581d140SJ. Bruce Fields { 20093abdb607SJ. Bruce Fields struct nfs4_stid *ret; 20103abdb607SJ. Bruce Fields 20113abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 20123abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 20133abdb607SJ. Bruce Fields return NULL; 20143abdb607SJ. Bruce Fields return ret; 20154581d140SJ. Bruce Fields } 20164d71ab87SJ. Bruce Fields 20174770d722SJeff Layton static struct nfs4_stid * 20184770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2019f459e453SJ. Bruce Fields { 2020f459e453SJ. Bruce Fields struct nfs4_stid *s; 2021f459e453SJ. Bruce Fields 20224770d722SJeff Layton spin_lock(&cl->cl_lock); 20234770d722SJeff Layton s = find_stateid_locked(cl, t); 20242d3f9668STrond Myklebust if (s != NULL) { 20252d3f9668STrond Myklebust if (typemask & s->sc_type) 20262d3f9668STrond Myklebust atomic_inc(&s->sc_count); 20272d3f9668STrond Myklebust else 20284770d722SJeff Layton s = NULL; 20292d3f9668STrond Myklebust } 20304770d722SJeff Layton spin_unlock(&cl->cl_lock); 20314d71ab87SJ. Bruce Fields return s; 20324581d140SJ. Bruce Fields } 20334581d140SJ. Bruce Fields 20342216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2035b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2036b09333c4SRicardo Labiaga { 2037b09333c4SRicardo Labiaga struct nfs4_client *clp; 2038b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 203903a4e1f6SJ. Bruce Fields int ret; 2040c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2041b09333c4SRicardo Labiaga 2042b09333c4SRicardo Labiaga clp = alloc_client(name); 2043b09333c4SRicardo Labiaga if (clp == NULL) 2044b09333c4SRicardo Labiaga return NULL; 2045b09333c4SRicardo Labiaga 204603a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 204703a4e1f6SJ. Bruce Fields if (ret) { 2048b09333c4SRicardo Labiaga free_client(clp); 2049b09333c4SRicardo Labiaga return NULL; 2050b09333c4SRicardo Labiaga } 20510162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 205207cd4909SBenny Halevy clp->cl_time = get_seconds(); 2053b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2054b09333c4SRicardo Labiaga copy_verf(clp, verf); 2055b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 2056edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2057c212cecfSStanislav Kinsbursky clp->net = net; 2058b09333c4SRicardo Labiaga return clp; 2059b09333c4SRicardo Labiaga } 2060b09333c4SRicardo Labiaga 2061fd39ca9aSNeilBrown static void 2062ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2063ac55fdc4SJeff Layton { 2064ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2065ac55fdc4SJeff Layton struct nfs4_client *clp; 2066ac55fdc4SJeff Layton 2067ac55fdc4SJeff Layton while (*new) { 2068ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2069ac55fdc4SJeff Layton parent = *new; 2070ac55fdc4SJeff Layton 2071ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2072ac55fdc4SJeff Layton new = &((*new)->rb_left); 2073ac55fdc4SJeff Layton else 2074ac55fdc4SJeff Layton new = &((*new)->rb_right); 2075ac55fdc4SJeff Layton } 2076ac55fdc4SJeff Layton 2077ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2078ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2079ac55fdc4SJeff Layton } 2080ac55fdc4SJeff Layton 2081ac55fdc4SJeff Layton static struct nfs4_client * 2082ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2083ac55fdc4SJeff Layton { 2084ef17af2aSRasmus Villemoes int cmp; 2085ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2086ac55fdc4SJeff Layton struct nfs4_client *clp; 2087ac55fdc4SJeff Layton 2088ac55fdc4SJeff Layton while (node) { 2089ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2090ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2091ac55fdc4SJeff Layton if (cmp > 0) 2092ac55fdc4SJeff Layton node = node->rb_left; 2093ac55fdc4SJeff Layton else if (cmp < 0) 2094ac55fdc4SJeff Layton node = node->rb_right; 2095ac55fdc4SJeff Layton else 2096ac55fdc4SJeff Layton return clp; 2097ac55fdc4SJeff Layton } 2098ac55fdc4SJeff Layton return NULL; 2099ac55fdc4SJeff Layton } 2100ac55fdc4SJeff Layton 2101ac55fdc4SJeff Layton static void 2102ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 21031da177e4SLinus Torvalds { 21041da177e4SLinus Torvalds unsigned int idhashval; 21050a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 21061da177e4SLinus Torvalds 21070a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 21080a880a28STrond Myklebust 2109ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2110a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 21111da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 21120a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 21133dbacee6STrond Myklebust renew_client_locked(clp); 21141da177e4SLinus Torvalds } 21151da177e4SLinus Torvalds 2116fd39ca9aSNeilBrown static void 21171da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 21181da177e4SLinus Torvalds { 21191da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 21208daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 21211da177e4SLinus Torvalds 21220a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 21230a880a28STrond Myklebust 21241da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 21258daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2126a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2127382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2128ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 21293dbacee6STrond Myklebust renew_client_locked(clp); 21301da177e4SLinus Torvalds } 21311da177e4SLinus Torvalds 21321da177e4SLinus Torvalds static struct nfs4_client * 2133bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 21341da177e4SLinus Torvalds { 21351da177e4SLinus Torvalds struct nfs4_client *clp; 21361da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 21371da177e4SLinus Torvalds 2138bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2139a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2140d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2141d15c077eSJ. Bruce Fields return NULL; 21423dbacee6STrond Myklebust renew_client_locked(clp); 21431da177e4SLinus Torvalds return clp; 21441da177e4SLinus Torvalds } 2145a50d2ad1SJ. Bruce Fields } 21461da177e4SLinus Torvalds return NULL; 21471da177e4SLinus Torvalds } 21481da177e4SLinus Torvalds 21491da177e4SLinus Torvalds static struct nfs4_client * 2150bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2151bfa85e83SJ. Bruce Fields { 2152bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2153bfa85e83SJ. Bruce Fields 21540a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2155bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2156bfa85e83SJ. Bruce Fields } 2157bfa85e83SJ. Bruce Fields 2158bfa85e83SJ. Bruce Fields static struct nfs4_client * 21590a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 21601da177e4SLinus Torvalds { 2161bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 21621da177e4SLinus Torvalds 21630a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2164bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 21651da177e4SLinus Torvalds } 21661da177e4SLinus Torvalds 21676e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2168a1bcecd2SAndy Adamson { 21696e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2170a1bcecd2SAndy Adamson } 2171a1bcecd2SAndy Adamson 217228ce6054SNeilBrown static struct nfs4_client * 2173382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 217428ce6054SNeilBrown { 21750a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2176382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 217728ce6054SNeilBrown } 217828ce6054SNeilBrown 217928ce6054SNeilBrown static struct nfs4_client * 2180a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 218128ce6054SNeilBrown { 21820a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2183a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 218428ce6054SNeilBrown } 218528ce6054SNeilBrown 2186fd39ca9aSNeilBrown static void 21876f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 21881da177e4SLinus Torvalds { 218907263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 21906f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 21916f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 21927077ecbaSJeff Layton unsigned short expected_family; 21931da177e4SLinus Torvalds 21947077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 21957077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 21967077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 21977077ecbaSJeff Layton expected_family = AF_INET; 21987077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 21997077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 22007077ecbaSJeff Layton expected_family = AF_INET6; 22017077ecbaSJeff Layton else 22021da177e4SLinus Torvalds goto out_err; 22031da177e4SLinus Torvalds 2204c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2205aa9a4ec7SJeff Layton se->se_callback_addr_len, 220607263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 220707263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2208aa9a4ec7SJeff Layton 220907263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 22101da177e4SLinus Torvalds goto out_err; 2211aa9a4ec7SJeff Layton 221207263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 221307263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2214fbf4665fSJeff Layton 221507263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 221607263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2217849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 22181da177e4SLinus Torvalds return; 22191da177e4SLinus Torvalds out_err: 222007263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 222107263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 2222849823c5SNeil Brown dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " 22231da177e4SLinus Torvalds "will not receive delegations\n", 22241da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 22251da177e4SLinus Torvalds 22261da177e4SLinus Torvalds return; 22271da177e4SLinus Torvalds } 22281da177e4SLinus Torvalds 2229074fe897SAndy Adamson /* 2230067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2231074fe897SAndy Adamson */ 2232b607664eSTrond Myklebust static void 2233074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2234074fe897SAndy Adamson { 2235f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2236557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2237557ce264SAndy Adamson unsigned int base; 2238074fe897SAndy Adamson 2239557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2240074fe897SAndy Adamson 2241557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2242557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 2243bf864a31SAndy Adamson 2244bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2245bf864a31SAndy Adamson if (nfsd4_not_cached(resp)) { 2246557ce264SAndy Adamson slot->sl_datalen = 0; 2247bf864a31SAndy Adamson return; 2248bf864a31SAndy Adamson } 2249f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2250f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2251f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2252d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 2253d3f03403SDan Carpenter __func__); 2254557ce264SAndy Adamson return; 2255074fe897SAndy Adamson } 2256074fe897SAndy Adamson 2257074fe897SAndy Adamson /* 2258abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2259abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2260abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2261abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2262abfabf8cSAndy Adamson * 2263074fe897SAndy Adamson */ 2264abfabf8cSAndy Adamson static __be32 2265abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2266abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2267074fe897SAndy Adamson { 2268abfabf8cSAndy Adamson struct nfsd4_op *op; 2269abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2270074fe897SAndy Adamson 2271abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2272abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2273abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2274abfabf8cSAndy Adamson 2275abfabf8cSAndy Adamson /* Return nfserr_retry_uncached_rep in next operation. */ 227673e79482SJ. Bruce Fields if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { 2277abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2278abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2279abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2280074fe897SAndy Adamson } 2281abfabf8cSAndy Adamson return op->status; 2282074fe897SAndy Adamson } 2283074fe897SAndy Adamson 2284074fe897SAndy Adamson /* 2285557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2286557ce264SAndy Adamson * session values. 2287074fe897SAndy Adamson */ 22883ca2eb98SJ. Bruce Fields static __be32 2289bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2290bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2291074fe897SAndy Adamson { 2292557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2293f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2294f5236013SJ. Bruce Fields __be32 *p; 2295074fe897SAndy Adamson __be32 status; 2296074fe897SAndy Adamson 2297557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2298074fe897SAndy Adamson 2299abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 23000da7b19cSJ. Bruce Fields if (status) 2301abfabf8cSAndy Adamson return status; 2302074fe897SAndy Adamson 2303f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2304f5236013SJ. Bruce Fields if (!p) { 2305f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2306f5236013SJ. Bruce Fields return nfserr_serverfault; 2307f5236013SJ. Bruce Fields } 2308f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2309f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2310074fe897SAndy Adamson 2311557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2312f5236013SJ. Bruce Fields return slot->sl_status; 2313074fe897SAndy Adamson } 2314074fe897SAndy Adamson 23150733d213SAndy Adamson /* 23160733d213SAndy Adamson * Set the exchange_id flags returned by the server. 23170733d213SAndy Adamson */ 23180733d213SAndy Adamson static void 23190733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 23200733d213SAndy Adamson { 23219cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 23229cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 23239cf514ccSChristoph Hellwig #else 23240733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 23259cf514ccSChristoph Hellwig #endif 23260733d213SAndy Adamson 23270733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 23280733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 23290733d213SAndy Adamson 23300733d213SAndy Adamson /* set the wire flags to return to client. */ 23310733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 23320733d213SAndy Adamson } 23330733d213SAndy Adamson 23344eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 23354eaea134SJ. Bruce Fields { 23364eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 23374eaea134SJ. Bruce Fields 23384eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 23394eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 23404eaea134SJ. Bruce Fields return true; 23414eaea134SJ. Bruce Fields } 23424eaea134SJ. Bruce Fields return false; 23434eaea134SJ. Bruce Fields } 23444eaea134SJ. Bruce Fields 2345631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 2346631fc9eaSJ. Bruce Fields { 23474eaea134SJ. Bruce Fields return client_has_openowners(clp) 234847e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 234947e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 235047e970beSKinglong Mee #endif 23516eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 23526eccece9SJ. Bruce Fields || !list_empty(&clp->cl_sessions); 2353631fc9eaSJ. Bruce Fields } 2354631fc9eaSJ. Bruce Fields 2355b37ad28bSAl Viro __be32 2356069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp, 2357069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2358069b6ad4SAndy Adamson struct nfsd4_exchange_id *exid) 2359069b6ad4SAndy Adamson { 23603dbacee6STrond Myklebust struct nfs4_client *conf, *new; 23613dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 236257b7b43bSJ. Bruce Fields __be32 status; 2363363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 23640733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 2365363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 236683e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 2367c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 23680733d213SAndy Adamson 2369363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 23700733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 2371363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 23720733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 2373363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 23740733d213SAndy Adamson 2375a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 23760733d213SAndy Adamson return nfserr_inval; 23770733d213SAndy Adamson 237850c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 237950c7b948SJ. Bruce Fields if (new == NULL) 238050c7b948SJ. Bruce Fields return nfserr_jukebox; 238150c7b948SJ. Bruce Fields 23820733d213SAndy Adamson switch (exid->spa_how) { 238357266a6eSJ. Bruce Fields case SP4_MACH_CRED: 238450c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 238550c7b948SJ. Bruce Fields status = nfserr_inval; 238650c7b948SJ. Bruce Fields goto out_nolock; 238750c7b948SJ. Bruce Fields } 2388920dd9bbSJ. Bruce Fields /* 2389920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 2390920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 2391920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 2392920dd9bbSJ. Bruce Fields */ 2393920dd9bbSJ. Bruce Fields if (!new->cl_cred.cr_principal) { 2394920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 2395920dd9bbSJ. Bruce Fields goto out_nolock; 2396920dd9bbSJ. Bruce Fields } 239750c7b948SJ. Bruce Fields new->cl_mach_cred = true; 23980733d213SAndy Adamson case SP4_NONE: 23990733d213SAndy Adamson break; 2400063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 2401063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 24020733d213SAndy Adamson case SP4_SSV: 2403dd30333cSJ. Bruce Fields return nfserr_encr_alg_unsupp; 24040733d213SAndy Adamson } 24050733d213SAndy Adamson 24062dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 24073dbacee6STrond Myklebust spin_lock(&nn->client_lock); 2408382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 24090733d213SAndy Adamson if (conf) { 241083e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 241183e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 241283e08fd4SJ. Bruce Fields 2413136e658dSJ. Bruce Fields if (update) { 2414136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 24152dbb269dSJ. Bruce Fields status = nfserr_inval; 2416e203d506SJ. Bruce Fields goto out; 2417e203d506SJ. Bruce Fields } 241857266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) { 241957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 242057266a6eSJ. Bruce Fields goto out; 242157266a6eSJ. Bruce Fields } 24222dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 24230733d213SAndy Adamson status = nfserr_perm; 24240733d213SAndy Adamson goto out; 24250733d213SAndy Adamson } 24262dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 24270733d213SAndy Adamson status = nfserr_not_same; 24280733d213SAndy Adamson goto out; 24290733d213SAndy Adamson } 2430136e658dSJ. Bruce Fields /* case 6 */ 24310733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 24320733d213SAndy Adamson goto out_copy; 24336ddbbbfeSMike Sager } 2434136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 2435631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 2436136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 2437136e658dSJ. Bruce Fields goto out; 2438136e658dSJ. Bruce Fields } 2439b9831b59SJ. Bruce Fields goto out_new; 2440631fc9eaSJ. Bruce Fields } 2441136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 24420f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 2443136e658dSJ. Bruce Fields goto out_copy; 2444136e658dSJ. Bruce Fields } 24452dbb269dSJ. Bruce Fields /* case 5, client reboot */ 24463dbacee6STrond Myklebust conf = NULL; 24470733d213SAndy Adamson goto out_new; 24480733d213SAndy Adamson } 24496ddbbbfeSMike Sager 24502dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 24510733d213SAndy Adamson status = nfserr_noent; 24520733d213SAndy Adamson goto out; 24530733d213SAndy Adamson } 24540733d213SAndy Adamson 2455a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 24562dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 24573dbacee6STrond Myklebust unhash_client_locked(unconf); 24580733d213SAndy Adamson 24592dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 24600733d213SAndy Adamson out_new: 2461fd699b8aSJeff Layton if (conf) { 2462fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 2463fd699b8aSJeff Layton if (status) 2464fd699b8aSJeff Layton goto out; 2465fd699b8aSJeff Layton } 24664f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 24670733d213SAndy Adamson 2468c212cecfSStanislav Kinsbursky gen_clid(new, nn); 2469ac55fdc4SJeff Layton add_to_unconfirmed(new); 24703dbacee6STrond Myklebust swap(new, conf); 24710733d213SAndy Adamson out_copy: 24725cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 24735cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 24740733d213SAndy Adamson 24755cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 24765cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 24770733d213SAndy Adamson 24780733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 24795cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 24800733d213SAndy Adamson status = nfs_ok; 24810733d213SAndy Adamson 24820733d213SAndy Adamson out: 24833dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 248450c7b948SJ. Bruce Fields out_nolock: 24855cc40fd7STrond Myklebust if (new) 24863dbacee6STrond Myklebust expire_client(new); 24873dbacee6STrond Myklebust if (unconf) 24883dbacee6STrond Myklebust expire_client(unconf); 24890733d213SAndy Adamson return status; 2490069b6ad4SAndy Adamson } 2491069b6ad4SAndy Adamson 249257b7b43bSJ. Bruce Fields static __be32 249388e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 2494b85d4c01SBenny Halevy { 249588e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 249688e588d5SAndy Adamson slot_seqid); 2497b85d4c01SBenny Halevy 2498b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 249988e588d5SAndy Adamson if (slot_inuse) { 250088e588d5SAndy Adamson if (seqid == slot_seqid) 2501b85d4c01SBenny Halevy return nfserr_jukebox; 2502b85d4c01SBenny Halevy else 2503b85d4c01SBenny Halevy return nfserr_seq_misordered; 2504b85d4c01SBenny Halevy } 2505f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 250688e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 2507b85d4c01SBenny Halevy return nfs_ok; 250888e588d5SAndy Adamson if (seqid == slot_seqid) 2509b85d4c01SBenny Halevy return nfserr_replay_cache; 2510b85d4c01SBenny Halevy return nfserr_seq_misordered; 2511b85d4c01SBenny Halevy } 2512b85d4c01SBenny Halevy 251349557cc7SAndy Adamson /* 251449557cc7SAndy Adamson * Cache the create session result into the create session single DRC 251549557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 251649557cc7SAndy Adamson * Do this for solo or embedded create session operations. 251749557cc7SAndy Adamson */ 251849557cc7SAndy Adamson static void 251949557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 252057b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 252149557cc7SAndy Adamson { 252249557cc7SAndy Adamson slot->sl_status = nfserr; 252349557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 252449557cc7SAndy Adamson } 252549557cc7SAndy Adamson 252649557cc7SAndy Adamson static __be32 252749557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 252849557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 252949557cc7SAndy Adamson { 253049557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 253149557cc7SAndy Adamson return slot->sl_status; 253249557cc7SAndy Adamson } 253349557cc7SAndy Adamson 25341b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 25351b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 25361b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 25371b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 25381b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 25391b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 25401b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 25411b74c25bSMi Jinlong 25421b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 25431b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 25441b74c25bSMi Jinlong 1 + /* status */ \ 25451b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 25461b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 25471b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 25481b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 25491b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 25501b74c25bSMi Jinlong 255155c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 25521b74c25bSMi Jinlong { 255355c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 255455c760cfSJ. Bruce Fields 2555373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 2556373cd409SJ. Bruce Fields return nfserr_toosmall; 2557373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 2558373cd409SJ. Bruce Fields return nfserr_toosmall; 255955c760cfSJ. Bruce Fields ca->headerpadsz = 0; 256055c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 256155c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 256255c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 256355c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 256455c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 256555c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 256655c760cfSJ. Bruce Fields /* 256755c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 256855c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 256955c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 257055c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 257155c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 257255c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 257355c760cfSJ. Bruce Fields */ 257455c760cfSJ. Bruce Fields ca->maxreqs = nfsd4_get_drc_mem(ca); 257555c760cfSJ. Bruce Fields if (!ca->maxreqs) 257655c760cfSJ. Bruce Fields return nfserr_jukebox; 257755c760cfSJ. Bruce Fields 2578373cd409SJ. Bruce Fields return nfs_ok; 25791b74c25bSMi Jinlong } 25801b74c25bSMi Jinlong 25818a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 25828a891633SKinglong Mee RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32)) 25838a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 25848a891633SKinglong Mee RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32)) 25858a891633SKinglong Mee 258606b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 258706b332a5SJ. Bruce Fields { 258806b332a5SJ. Bruce Fields ca->headerpadsz = 0; 258906b332a5SJ. Bruce Fields 259006b332a5SJ. Bruce Fields /* 259106b332a5SJ. Bruce Fields * These RPC_MAX_HEADER macros are overkill, especially since we 259206b332a5SJ. Bruce Fields * don't even do gss on the backchannel yet. But this is still 259306b332a5SJ. Bruce Fields * less than 1k. Tighten up this estimate in the unlikely event 259406b332a5SJ. Bruce Fields * it turns out to be a problem for some client: 259506b332a5SJ. Bruce Fields */ 25968a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 259706b332a5SJ. Bruce Fields return nfserr_toosmall; 25988a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 259906b332a5SJ. Bruce Fields return nfserr_toosmall; 260006b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 260106b332a5SJ. Bruce Fields if (ca->maxops < 2) 260206b332a5SJ. Bruce Fields return nfserr_toosmall; 260306b332a5SJ. Bruce Fields 260406b332a5SJ. Bruce Fields return nfs_ok; 2605069b6ad4SAndy Adamson } 2606069b6ad4SAndy Adamson 2607b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 2608b78724b7SJ. Bruce Fields { 2609b78724b7SJ. Bruce Fields switch (cbs->flavor) { 2610b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 2611b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 2612b78724b7SJ. Bruce Fields return nfs_ok; 2613b78724b7SJ. Bruce Fields default: 2614b78724b7SJ. Bruce Fields /* 2615b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 2616b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 2617b78724b7SJ. Bruce Fields * GSS. 2618b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 2619b78724b7SJ. Bruce Fields * client might think it can already handle: 2620b78724b7SJ. Bruce Fields */ 2621b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 2622b78724b7SJ. Bruce Fields } 2623b78724b7SJ. Bruce Fields } 2624b78724b7SJ. Bruce Fields 2625069b6ad4SAndy Adamson __be32 2626069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 2627069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2628069b6ad4SAndy Adamson struct nfsd4_create_session *cr_ses) 2629069b6ad4SAndy Adamson { 2630363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 2631ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 2632d20c11d8SJeff Layton struct nfs4_client *old = NULL; 2633ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 263481f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 263549557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 263657b7b43bSJ. Bruce Fields __be32 status = 0; 26378daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2638ec6b5d7bSAndy Adamson 2639a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 2640a62573dcSMi Jinlong return nfserr_inval; 2641b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 2642b78724b7SJ. Bruce Fields if (status) 2643b78724b7SJ. Bruce Fields return status; 264455c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 2645373cd409SJ. Bruce Fields if (status) 2646373cd409SJ. Bruce Fields return status; 264706b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 264806b332a5SJ. Bruce Fields if (status) 2649f403e450SKinglong Mee goto out_release_drc_mem; 265081f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 265160810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 265255c760cfSJ. Bruce Fields if (!new) 265355c760cfSJ. Bruce Fields goto out_release_drc_mem; 265481f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 265581f0b2a4SJ. Bruce Fields if (!conn) 265681f0b2a4SJ. Bruce Fields goto out_free_session; 2657a62573dcSMi Jinlong 2658d20c11d8SJeff Layton spin_lock(&nn->client_lock); 26590a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 26608daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 266178389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2662ec6b5d7bSAndy Adamson 2663ec6b5d7bSAndy Adamson if (conf) { 266457266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 266557266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) 266657266a6eSJ. Bruce Fields goto out_free_conn; 266749557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 266849557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 2669f5e22bb6SKinglong Mee if (status) { 2670f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 267149557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 267281f0b2a4SJ. Bruce Fields goto out_free_conn; 2673ec6b5d7bSAndy Adamson } 2674ec6b5d7bSAndy Adamson } else if (unconf) { 2675ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 2676363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 2677ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 267881f0b2a4SJ. Bruce Fields goto out_free_conn; 2679ec6b5d7bSAndy Adamson } 268057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 268157266a6eSJ. Bruce Fields if (!mach_creds_match(unconf, rqstp)) 268257266a6eSJ. Bruce Fields goto out_free_conn; 268349557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 268449557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 268538eb76a5SAndy Adamson if (status) { 268638eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 2687ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 268881f0b2a4SJ. Bruce Fields goto out_free_conn; 2689ec6b5d7bSAndy Adamson } 2690382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 2691221a6876SJ. Bruce Fields if (old) { 2692d20c11d8SJeff Layton status = mark_client_expired_locked(old); 26937abea1e8SJeff Layton if (status) { 26947abea1e8SJeff Layton old = NULL; 2695221a6876SJ. Bruce Fields goto out_free_conn; 2696221a6876SJ. Bruce Fields } 26977abea1e8SJeff Layton } 26988f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 2699ec6b5d7bSAndy Adamson conf = unconf; 2700ec6b5d7bSAndy Adamson } else { 2701ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 270281f0b2a4SJ. Bruce Fields goto out_free_conn; 2703ec6b5d7bSAndy Adamson } 270481f0b2a4SJ. Bruce Fields status = nfs_ok; 27058323c3b2SJ. Bruce Fields /* 2706408b79bcSJ. Bruce Fields * We do not support RDMA or persistent sessions 2707408b79bcSJ. Bruce Fields */ 2708408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 2709408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 2710408b79bcSJ. Bruce Fields 271181f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 2712d20c11d8SJeff Layton nfsd4_get_session_locked(new); 271381f0b2a4SJ. Bruce Fields 2714ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 2715ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 271686c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 271749557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 2718ec6b5d7bSAndy Adamson 2719d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 272049557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 2721d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 2722d20c11d8SJeff Layton /* init connection and backchannel */ 2723d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 2724d20c11d8SJeff Layton nfsd4_put_session(new); 2725d20c11d8SJeff Layton if (old) 2726d20c11d8SJeff Layton expire_client(old); 2727ec6b5d7bSAndy Adamson return status; 272881f0b2a4SJ. Bruce Fields out_free_conn: 2729d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 273081f0b2a4SJ. Bruce Fields free_conn(conn); 2731d20c11d8SJeff Layton if (old) 2732d20c11d8SJeff Layton expire_client(old); 273381f0b2a4SJ. Bruce Fields out_free_session: 273481f0b2a4SJ. Bruce Fields __free_session(new); 273555c760cfSJ. Bruce Fields out_release_drc_mem: 273655c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 27371ca50792SJ. Bruce Fields return status; 2738069b6ad4SAndy Adamson } 2739069b6ad4SAndy Adamson 27401d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 27411d1bc8f2SJ. Bruce Fields { 27421d1bc8f2SJ. Bruce Fields switch (*dir) { 27431d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 27441d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 27451d1bc8f2SJ. Bruce Fields return nfs_ok; 27461d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 27471d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 27481d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 27491d1bc8f2SJ. Bruce Fields return nfs_ok; 27501d1bc8f2SJ. Bruce Fields }; 27511d1bc8f2SJ. Bruce Fields return nfserr_inval; 27521d1bc8f2SJ. Bruce Fields } 27531d1bc8f2SJ. Bruce Fields 2754cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) 2755cb73a9f4SJ. Bruce Fields { 2756cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 2757c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2758b78724b7SJ. Bruce Fields __be32 status; 2759cb73a9f4SJ. Bruce Fields 2760b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 2761b78724b7SJ. Bruce Fields if (status) 2762b78724b7SJ. Bruce Fields return status; 2763c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2764cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 2765cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 2766c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2767cb73a9f4SJ. Bruce Fields 2768cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 2769cb73a9f4SJ. Bruce Fields 2770cb73a9f4SJ. Bruce Fields return nfs_ok; 2771cb73a9f4SJ. Bruce Fields } 2772cb73a9f4SJ. Bruce Fields 27731d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 27741d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 27751d1bc8f2SJ. Bruce Fields struct nfsd4_bind_conn_to_session *bcts) 27761d1bc8f2SJ. Bruce Fields { 27771d1bc8f2SJ. Bruce Fields __be32 status; 27783ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 27794f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 2780d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2781d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 27821d1bc8f2SJ. Bruce Fields 27831d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 27841d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 2785c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2786d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 2787c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 27884f6e6c17SJ. Bruce Fields if (!session) 2789d4e19e70STrond Myklebust goto out_no_session; 279057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 279157266a6eSJ. Bruce Fields if (!mach_creds_match(session->se_client, rqstp)) 279257266a6eSJ. Bruce Fields goto out; 27931d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 27943ba63671SJ. Bruce Fields if (status) 27954f6e6c17SJ. Bruce Fields goto out; 27963ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 27974f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 27983ba63671SJ. Bruce Fields if (!conn) 27994f6e6c17SJ. Bruce Fields goto out; 28004f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 28014f6e6c17SJ. Bruce Fields status = nfs_ok; 28024f6e6c17SJ. Bruce Fields out: 2803d4e19e70STrond Myklebust nfsd4_put_session(session); 2804d4e19e70STrond Myklebust out_no_session: 28054f6e6c17SJ. Bruce Fields return status; 28061d1bc8f2SJ. Bruce Fields } 28071d1bc8f2SJ. Bruce Fields 28085d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) 28095d4cec2fSJ. Bruce Fields { 28105d4cec2fSJ. Bruce Fields if (!session) 28115d4cec2fSJ. Bruce Fields return 0; 28125d4cec2fSJ. Bruce Fields return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); 28135d4cec2fSJ. Bruce Fields } 28145d4cec2fSJ. Bruce Fields 2815069b6ad4SAndy Adamson __be32 2816069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r, 2817069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2818069b6ad4SAndy Adamson struct nfsd4_destroy_session *sessionid) 2819069b6ad4SAndy Adamson { 2820e10e0cfcSBenny Halevy struct nfsd4_session *ses; 2821abcdff09SJ. Bruce Fields __be32 status; 2822f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 2823d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 2824d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2825e10e0cfcSBenny Halevy 2826abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 28275d4cec2fSJ. Bruce Fields if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { 282857716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 2829abcdff09SJ. Bruce Fields goto out; 2830f0f51f5cSJ. Bruce Fields ref_held_by_me++; 283157716355SJ. Bruce Fields } 2832e10e0cfcSBenny Halevy dump_sessionid(__func__, &sessionid->sessionid); 2833c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2834d4e19e70STrond Myklebust ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status); 2835abcdff09SJ. Bruce Fields if (!ses) 2836abcdff09SJ. Bruce Fields goto out_client_lock; 283757266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 283857266a6eSJ. Bruce Fields if (!mach_creds_match(ses->se_client, r)) 2839d4e19e70STrond Myklebust goto out_put_session; 2840f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 284166b2b9b2SJ. Bruce Fields if (status) 2842f0f51f5cSJ. Bruce Fields goto out_put_session; 2843e10e0cfcSBenny Halevy unhash_session(ses); 2844c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2845e10e0cfcSBenny Halevy 284684f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 284719cf5c02SJ. Bruce Fields 2848c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2849e10e0cfcSBenny Halevy status = nfs_ok; 2850f0f51f5cSJ. Bruce Fields out_put_session: 2851d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 2852abcdff09SJ. Bruce Fields out_client_lock: 2853abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 2854e10e0cfcSBenny Halevy out: 2855e10e0cfcSBenny Halevy return status; 2856069b6ad4SAndy Adamson } 2857069b6ad4SAndy Adamson 2858a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 2859328ead28SJ. Bruce Fields { 2860328ead28SJ. Bruce Fields struct nfsd4_conn *c; 2861328ead28SJ. Bruce Fields 2862328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 2863a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 2864328ead28SJ. Bruce Fields return c; 2865328ead28SJ. Bruce Fields } 2866328ead28SJ. Bruce Fields } 2867328ead28SJ. Bruce Fields return NULL; 2868328ead28SJ. Bruce Fields } 2869328ead28SJ. Bruce Fields 287057266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 2871328ead28SJ. Bruce Fields { 2872328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 2873a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 287457266a6eSJ. Bruce Fields __be32 status = nfs_ok; 287521b75b01SJ. Bruce Fields int ret; 2876328ead28SJ. Bruce Fields 2877328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 2878a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 287957266a6eSJ. Bruce Fields if (c) 288057266a6eSJ. Bruce Fields goto out_free; 288157266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 288257266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 288357266a6eSJ. Bruce Fields goto out_free; 2884328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 2885328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 288621b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 288721b75b01SJ. Bruce Fields if (ret) 288821b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 288921b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 289057266a6eSJ. Bruce Fields return nfs_ok; 289157266a6eSJ. Bruce Fields out_free: 289257266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 289357266a6eSJ. Bruce Fields free_conn(new); 289457266a6eSJ. Bruce Fields return status; 2895328ead28SJ. Bruce Fields } 2896328ead28SJ. Bruce Fields 2897868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 2898868b89c3SMi Jinlong { 2899868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 2900868b89c3SMi Jinlong 2901868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 2902868b89c3SMi Jinlong } 2903868b89c3SMi Jinlong 2904ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 2905ae82a8d0SMi Jinlong struct nfsd4_session *session) 2906ae82a8d0SMi Jinlong { 2907ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 2908ae82a8d0SMi Jinlong 2909ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 2910ae82a8d0SMi Jinlong } 2911ae82a8d0SMi Jinlong 2912069b6ad4SAndy Adamson __be32 2913b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp, 2914069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2915069b6ad4SAndy Adamson struct nfsd4_sequence *seq) 2916069b6ad4SAndy Adamson { 2917f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 291847ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2919b85d4c01SBenny Halevy struct nfsd4_session *session; 2920221a6876SJ. Bruce Fields struct nfs4_client *clp; 2921b85d4c01SBenny Halevy struct nfsd4_slot *slot; 2922a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 292357b7b43bSJ. Bruce Fields __be32 status; 292447ee5298SJ. Bruce Fields int buflen; 2925d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2926d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2927b85d4c01SBenny Halevy 2928f9bb94c4SAndy Adamson if (resp->opcnt != 1) 2929f9bb94c4SAndy Adamson return nfserr_sequence_pos; 2930f9bb94c4SAndy Adamson 2931a663bdd8SJ. Bruce Fields /* 2932a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 2933a663bdd8SJ. Bruce Fields * below. 2934a663bdd8SJ. Bruce Fields */ 2935a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 2936a663bdd8SJ. Bruce Fields if (!conn) 2937a663bdd8SJ. Bruce Fields return nfserr_jukebox; 2938a663bdd8SJ. Bruce Fields 2939c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2940d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 2941b85d4c01SBenny Halevy if (!session) 2942221a6876SJ. Bruce Fields goto out_no_session; 2943221a6876SJ. Bruce Fields clp = session->se_client; 2944b85d4c01SBenny Halevy 2945868b89c3SMi Jinlong status = nfserr_too_many_ops; 2946868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 294766b2b9b2SJ. Bruce Fields goto out_put_session; 2948868b89c3SMi Jinlong 2949ae82a8d0SMi Jinlong status = nfserr_req_too_big; 2950ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 295166b2b9b2SJ. Bruce Fields goto out_put_session; 2952ae82a8d0SMi Jinlong 2953b85d4c01SBenny Halevy status = nfserr_badslot; 29546c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 295566b2b9b2SJ. Bruce Fields goto out_put_session; 2956b85d4c01SBenny Halevy 2957557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 2958b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 2959b85d4c01SBenny Halevy 2960a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 2961a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 2962a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 2963a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 2964a8dfdaebSAndy Adamson 296573e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 296673e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 2967b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 2968bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 2969bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 297066b2b9b2SJ. Bruce Fields goto out_put_session; 2971b85d4c01SBenny Halevy cstate->slot = slot; 2972b85d4c01SBenny Halevy cstate->session = session; 29734b24ca7dSJeff Layton cstate->clp = clp; 2974da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 2975557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 2976bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 2977da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 2978aaf84eb9SBenny Halevy goto out; 2979b85d4c01SBenny Halevy } 2980b85d4c01SBenny Halevy if (status) 298166b2b9b2SJ. Bruce Fields goto out_put_session; 2982b85d4c01SBenny Halevy 298357266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 2984a663bdd8SJ. Bruce Fields conn = NULL; 298557266a6eSJ. Bruce Fields if (status) 298657266a6eSJ. Bruce Fields goto out_put_session; 2987328ead28SJ. Bruce Fields 298847ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 298947ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 299047ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 299147ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 299247ee5298SJ. Bruce Fields nfserr_rep_too_big; 2993a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 299447ee5298SJ. Bruce Fields goto out_put_session; 299532aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 299647ee5298SJ. Bruce Fields 299747ee5298SJ. Bruce Fields status = nfs_ok; 2998b85d4c01SBenny Halevy /* Success! bump slot seqid */ 2999b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 3000bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 300173e79482SJ. Bruce Fields if (seq->cachethis) 300273e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 3003bf5c43c8SJ. Bruce Fields else 3004bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 3005b85d4c01SBenny Halevy 3006b85d4c01SBenny Halevy cstate->slot = slot; 3007b85d4c01SBenny Halevy cstate->session = session; 30084b24ca7dSJeff Layton cstate->clp = clp; 3009b85d4c01SBenny Halevy 3010b85d4c01SBenny Halevy out: 30115423732aSBenny Halevy switch (clp->cl_cb_state) { 30125423732aSBenny Halevy case NFSD4_CB_DOWN: 3013fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 30145423732aSBenny Halevy break; 30155423732aSBenny Halevy case NFSD4_CB_FAULT: 3016fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 30175423732aSBenny Halevy break; 3018fc0c3dd1SBenny Halevy default: 3019fc0c3dd1SBenny Halevy seq->status_flags = 0; 30205423732aSBenny Halevy } 30213bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 30223bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 3023221a6876SJ. Bruce Fields out_no_session: 30243f42d2c4SKinglong Mee if (conn) 30253f42d2c4SKinglong Mee free_conn(conn); 3026c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3027b85d4c01SBenny Halevy return status; 302866b2b9b2SJ. Bruce Fields out_put_session: 3029d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 3030221a6876SJ. Bruce Fields goto out_no_session; 3031069b6ad4SAndy Adamson } 3032069b6ad4SAndy Adamson 3033b607664eSTrond Myklebust void 3034b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 3035b607664eSTrond Myklebust { 3036b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 3037b607664eSTrond Myklebust 3038b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 3039b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 3040b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 3041b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3042b607664eSTrond Myklebust } 3043d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 3044b607664eSTrond Myklebust nfsd4_put_session(cs->session); 30454b24ca7dSJeff Layton } else if (cs->clp) 30464b24ca7dSJeff Layton put_client_renew(cs->clp); 3047b607664eSTrond Myklebust } 3048b607664eSTrond Myklebust 3049345c2842SMi Jinlong __be32 3050345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) 3051345c2842SMi Jinlong { 30526b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 30536b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 305457b7b43bSJ. Bruce Fields __be32 status = 0; 30558daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3056345c2842SMi Jinlong 30576b10ad19STrond Myklebust spin_lock(&nn->client_lock); 30580a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 30598daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 306078389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3061345c2842SMi Jinlong 3062345c2842SMi Jinlong if (conf) { 3063c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 3064345c2842SMi Jinlong status = nfserr_clientid_busy; 3065345c2842SMi Jinlong goto out; 3066345c2842SMi Jinlong } 3067fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3068fd699b8aSJeff Layton if (status) 3069fd699b8aSJeff Layton goto out; 30706b10ad19STrond Myklebust clp = conf; 3071345c2842SMi Jinlong } else if (unconf) 3072345c2842SMi Jinlong clp = unconf; 3073345c2842SMi Jinlong else { 3074345c2842SMi Jinlong status = nfserr_stale_clientid; 3075345c2842SMi Jinlong goto out; 3076345c2842SMi Jinlong } 307757266a6eSJ. Bruce Fields if (!mach_creds_match(clp, rqstp)) { 30786b10ad19STrond Myklebust clp = NULL; 307957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 308057266a6eSJ. Bruce Fields goto out; 308157266a6eSJ. Bruce Fields } 30826b10ad19STrond Myklebust unhash_client_locked(clp); 3083345c2842SMi Jinlong out: 30846b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 30856b10ad19STrond Myklebust if (clp) 30866b10ad19STrond Myklebust expire_client(clp); 3087345c2842SMi Jinlong return status; 3088345c2842SMi Jinlong } 3089345c2842SMi Jinlong 3090069b6ad4SAndy Adamson __be32 30914dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) 30924dc6ec00SJ. Bruce Fields { 309357b7b43bSJ. Bruce Fields __be32 status = 0; 3094bcecf1ccSMi Jinlong 30954dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 30964dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 30974dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 30984dc6ec00SJ. Bruce Fields /* 30994dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 31004dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 31014dc6ec00SJ. Bruce Fields */ 31024dc6ec00SJ. Bruce Fields return nfs_ok; 31034dc6ec00SJ. Bruce Fields } 3104bcecf1ccSMi Jinlong 3105bcecf1ccSMi Jinlong status = nfserr_complete_already; 3106a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 3107a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 3108bcecf1ccSMi Jinlong goto out; 3109bcecf1ccSMi Jinlong 3110bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 3111bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 31124dc6ec00SJ. Bruce Fields /* 31134dc6ec00SJ. Bruce Fields * The following error isn't really legal. 31144dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 31154dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 31164dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 31174dc6ec00SJ. Bruce Fields * client. 31184dc6ec00SJ. Bruce Fields */ 3119bcecf1ccSMi Jinlong goto out; 3120bcecf1ccSMi Jinlong 3121bcecf1ccSMi Jinlong status = nfs_ok; 31222a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 3123bcecf1ccSMi Jinlong out: 3124bcecf1ccSMi Jinlong return status; 31254dc6ec00SJ. Bruce Fields } 31264dc6ec00SJ. Bruce Fields 31274dc6ec00SJ. Bruce Fields __be32 3128b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3129b591480bSJ.Bruce Fields struct nfsd4_setclientid *setclid) 31301da177e4SLinus Torvalds { 3131a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 31321da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 31333dbacee6STrond Myklebust struct nfs4_client *conf, *new; 31343dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 3135b37ad28bSAl Viro __be32 status; 3136c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3137a55370a3SNeilBrown 31385cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 31395cc40fd7STrond Myklebust if (new == NULL) 31405cc40fd7STrond Myklebust return nfserr_jukebox; 314163db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 31423dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3143382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 31442b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 314563db4632SJ. Bruce Fields /* case 0: */ 31461da177e4SLinus Torvalds status = nfserr_clid_inuse; 3147e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 3148e203d506SJ. Bruce Fields goto out; 3149026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 3150363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 3151363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 3152363168b4SJeff Layton sizeof(addr_str)); 3153026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 3154363168b4SJeff Layton "at %s\n", addr_str); 31551da177e4SLinus Torvalds goto out; 31561da177e4SLinus Torvalds } 31571da177e4SLinus Torvalds } 3158a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 31591da177e4SLinus Torvalds if (unconf) 31603dbacee6STrond Myklebust unhash_client_locked(unconf); 316141eb1670SKinglong Mee if (conf && same_verf(&conf->cl_verifier, &clverifier)) { 316263db4632SJ. Bruce Fields /* case 1: probable callback update */ 31631da177e4SLinus Torvalds copy_clid(new, conf); 316441eb1670SKinglong Mee gen_confirm(new, nn); 316541eb1670SKinglong Mee } else /* case 4 (new client) or cases 2, 3 (client reboot): */ 3166c212cecfSStanislav Kinsbursky gen_clid(new, nn); 31678323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 31686f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 3169ac55fdc4SJeff Layton add_to_unconfirmed(new); 31701da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 31711da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 31721da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 31735cc40fd7STrond Myklebust new = NULL; 31741da177e4SLinus Torvalds status = nfs_ok; 31751da177e4SLinus Torvalds out: 31763dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 31775cc40fd7STrond Myklebust if (new) 31785cc40fd7STrond Myklebust free_client(new); 31793dbacee6STrond Myklebust if (unconf) 31803dbacee6STrond Myklebust expire_client(unconf); 31811da177e4SLinus Torvalds return status; 31821da177e4SLinus Torvalds } 31831da177e4SLinus Torvalds 31841da177e4SLinus Torvalds 3185b37ad28bSAl Viro __be32 3186b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 3187b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 3188b591480bSJ.Bruce Fields struct nfsd4_setclientid_confirm *setclientid_confirm) 31891da177e4SLinus Torvalds { 319021ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 3191d20c11d8SJeff Layton struct nfs4_client *old = NULL; 31921da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 31931da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 3194b37ad28bSAl Viro __be32 status; 31957f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 31961da177e4SLinus Torvalds 31972c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 31981da177e4SLinus Torvalds return nfserr_stale_clientid; 319921ab45a4SNeilBrown 3200d20c11d8SJeff Layton spin_lock(&nn->client_lock); 32018daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 32020a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 3203a186e767SJ. Bruce Fields /* 32048695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 32058695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 3206f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 3207f984a7ceSJ. Bruce Fields * 3208f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 3209a186e767SJ. Bruce Fields */ 3210f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 32118695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 32128695b90aSJ. Bruce Fields goto out; 32138695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 32148695b90aSJ. Bruce Fields goto out; 321563db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 321690d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 321790d700b7SJ. Bruce Fields if (conf && !unconf) /* case 2: probable retransmit */ 321890d700b7SJ. Bruce Fields status = nfs_ok; 321990d700b7SJ. Bruce Fields else /* case 4: client hasn't noticed we rebooted yet? */ 322090d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 322190d700b7SJ. Bruce Fields goto out; 322290d700b7SJ. Bruce Fields } 322390d700b7SJ. Bruce Fields status = nfs_ok; 322490d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 3225d20c11d8SJeff Layton old = unconf; 3226d20c11d8SJeff Layton unhash_client_locked(old); 32275a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 322890d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 3229d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3230d20c11d8SJeff Layton if (old) { 32312b634821SJ. Bruce Fields status = nfserr_clid_inuse; 32322b634821SJ. Bruce Fields if (client_has_state(old) 32332b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 32342b634821SJ. Bruce Fields &old->cl_cred)) 32352b634821SJ. Bruce Fields goto out; 3236d20c11d8SJeff Layton status = mark_client_expired_locked(old); 32377abea1e8SJeff Layton if (status) { 32387abea1e8SJeff Layton old = NULL; 3239221a6876SJ. Bruce Fields goto out; 3240221a6876SJ. Bruce Fields } 32417abea1e8SJeff Layton } 32421da177e4SLinus Torvalds move_to_confirmed(unconf); 3243d20c11d8SJeff Layton conf = unconf; 324408e8987cSNeilBrown } 3245d20c11d8SJeff Layton get_client_locked(conf); 3246d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3247d20c11d8SJeff Layton nfsd4_probe_callback(conf); 3248d20c11d8SJeff Layton spin_lock(&nn->client_lock); 3249d20c11d8SJeff Layton put_client_renew_locked(conf); 32501da177e4SLinus Torvalds out: 3251d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3252d20c11d8SJeff Layton if (old) 3253d20c11d8SJeff Layton expire_client(old); 32541da177e4SLinus Torvalds return status; 32551da177e4SLinus Torvalds } 32561da177e4SLinus Torvalds 325732513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 32581da177e4SLinus Torvalds { 325932513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 326032513b40SJ. Bruce Fields } 326132513b40SJ. Bruce Fields 326232513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 32635b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, 32645b095e99SJeff Layton struct nfs4_file *fp) 326532513b40SJ. Bruce Fields { 3266950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3267950e0118STrond Myklebust 32688b671b80SJ. Bruce Fields atomic_set(&fp->fi_ref, 1); 32691d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 32708beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 32718beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 32728287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 3273e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 32740c637be8SJeff Layton fp->fi_deleg_file = NULL; 327547f9940cSMeelap Shah fp->fi_had_conflict = false; 3276baeb4ff0SJeff Layton fp->fi_share_deny = 0; 3277f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 3278f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 32799cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 32809cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 3281c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 32829cf514ccSChristoph Hellwig #endif 32835b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 32841da177e4SLinus Torvalds } 32851da177e4SLinus Torvalds 3286e8ff2a84SJ. Bruce Fields void 3287e60d4398SNeilBrown nfsd4_free_slabs(void) 3288e60d4398SNeilBrown { 32898287f009SSachin Bhamare kmem_cache_destroy(odstate_slab); 3290abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3291abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3292abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3293abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3294abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 3295e60d4398SNeilBrown } 32961da177e4SLinus Torvalds 329772083396SBryan Schumaker int 32981da177e4SLinus Torvalds nfsd4_init_slabs(void) 32991da177e4SLinus Torvalds { 3300fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 3301fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 3302fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 3303abf1135bSChristoph Hellwig goto out; 3304fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 33053c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 3306fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 3307abf1135bSChristoph Hellwig goto out_free_openowner_slab; 3308e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 330920c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 3310e60d4398SNeilBrown if (file_slab == NULL) 3311abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 33125ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 3313dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 33145ac049acSNeilBrown if (stateid_slab == NULL) 3315abf1135bSChristoph Hellwig goto out_free_file_slab; 33165b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 331720c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 33185b2d21c1SNeilBrown if (deleg_slab == NULL) 3319abf1135bSChristoph Hellwig goto out_free_stateid_slab; 33208287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 33218287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 33228287f009SSachin Bhamare if (odstate_slab == NULL) 33238287f009SSachin Bhamare goto out_free_deleg_slab; 3324e60d4398SNeilBrown return 0; 3325abf1135bSChristoph Hellwig 33268287f009SSachin Bhamare out_free_deleg_slab: 33278287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 3328abf1135bSChristoph Hellwig out_free_stateid_slab: 3329abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3330abf1135bSChristoph Hellwig out_free_file_slab: 3331abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3332abf1135bSChristoph Hellwig out_free_lockowner_slab: 3333abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3334abf1135bSChristoph Hellwig out_free_openowner_slab: 3335abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3336abf1135bSChristoph Hellwig out: 33371da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 33381da177e4SLinus Torvalds return -ENOMEM; 33391da177e4SLinus Torvalds } 33401da177e4SLinus Torvalds 3341ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 3342ff194bd9SJ. Bruce Fields { 3343ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 3344ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 3345ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 334658fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 334758fb12e6SJeff Layton } 334858fb12e6SJeff Layton 334958fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 335058fb12e6SJeff Layton struct nfs4_stateowner *so) 335158fb12e6SJeff Layton { 335258fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 335358fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 3354b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 335558fb12e6SJeff Layton } 335658fb12e6SJeff Layton } 335758fb12e6SJeff Layton 335858fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 335958fb12e6SJeff Layton { 336058fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 336158fb12e6SJeff Layton 336258fb12e6SJeff Layton if (so != NULL) { 336358fb12e6SJeff Layton cstate->replay_owner = NULL; 336458fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 336558fb12e6SJeff Layton nfs4_put_stateowner(so); 336658fb12e6SJeff Layton } 3367ff194bd9SJ. Bruce Fields } 3368ff194bd9SJ. Bruce Fields 3369fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 33701da177e4SLinus Torvalds { 33711da177e4SLinus Torvalds struct nfs4_stateowner *sop; 33721da177e4SLinus Torvalds 3373fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 3374ff194bd9SJ. Bruce Fields if (!sop) 3375ff194bd9SJ. Bruce Fields return NULL; 3376ff194bd9SJ. Bruce Fields 3377ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 3378ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 3379fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 3380ff194bd9SJ. Bruce Fields return NULL; 3381ff194bd9SJ. Bruce Fields } 33821da177e4SLinus Torvalds sop->so_owner.len = owner->len; 3383ff194bd9SJ. Bruce Fields 3384ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 3385ff194bd9SJ. Bruce Fields sop->so_client = clp; 3386ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 33876b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 33881da177e4SLinus Torvalds return sop; 33891da177e4SLinus Torvalds } 3390ff194bd9SJ. Bruce Fields 3391fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 3392ff194bd9SJ. Bruce Fields { 3393d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 33949b531137SStanislav Kinsbursky 3395d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 3396d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 3397fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 33981da177e4SLinus Torvalds } 33991da177e4SLinus Torvalds 34008f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 34018f4b54c5SJeff Layton { 3402d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 34038f4b54c5SJeff Layton } 34048f4b54c5SJeff Layton 34056b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 34066b180f0bSJeff Layton { 34076b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 34086b180f0bSJeff Layton 34096b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 34106b180f0bSJeff Layton } 34116b180f0bSJeff Layton 34126b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 34138f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 34146b180f0bSJeff Layton .so_free = nfs4_free_openowner, 34156b180f0bSJeff Layton }; 34166b180f0bSJeff Layton 34177fc0564eSAndrew Elble static struct nfs4_ol_stateid * 34187fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 34197fc0564eSAndrew Elble { 34207fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 34217fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 34227fc0564eSAndrew Elble 34237fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 34247fc0564eSAndrew Elble 34257fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 34267fc0564eSAndrew Elble /* ignore lock owners */ 34277fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 34287fc0564eSAndrew Elble continue; 34297fc0564eSAndrew Elble if (local->st_stateowner == &oo->oo_owner) { 34307fc0564eSAndrew Elble ret = local; 34317fc0564eSAndrew Elble atomic_inc(&ret->st_stid.sc_count); 34327fc0564eSAndrew Elble break; 34337fc0564eSAndrew Elble } 34347fc0564eSAndrew Elble } 34357fc0564eSAndrew Elble return ret; 34367fc0564eSAndrew Elble } 34377fc0564eSAndrew Elble 3438fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 343913d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 3440db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 3441db24b3b4SJeff Layton { 344213d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 34437ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 34441da177e4SLinus Torvalds 3445fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 3446fe0750e5SJ. Bruce Fields if (!oo) 34471da177e4SLinus Torvalds return NULL; 34486b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 3449fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 3450fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 3451d3134b10SJeff Layton oo->oo_flags = 0; 3452db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 3453db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 3454fe0750e5SJ. Bruce Fields oo->oo_time = 0; 345538c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 3456fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 3457d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 3458d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 34597ffb5880STrond Myklebust if (ret == NULL) { 3460fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 34617ffb5880STrond Myklebust ret = oo; 34627ffb5880STrond Myklebust } else 3463d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 3464d50ffdedSKinglong Mee 3465d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 3466c5952338SJeff Layton return ret; 34671da177e4SLinus Torvalds } 34681da177e4SLinus Torvalds 34697fc0564eSAndrew Elble static struct nfs4_ol_stateid * 34707fc0564eSAndrew Elble init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, 34717fc0564eSAndrew Elble struct nfsd4_open *open) 34727fc0564eSAndrew Elble { 34731da177e4SLinus Torvalds 34747fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 34757fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 34767fc0564eSAndrew Elble 34777fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 34787fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 34797fc0564eSAndrew Elble 34807fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 34817fc0564eSAndrew Elble if (retstp) 34827fc0564eSAndrew Elble goto out_unlock; 3483d6f2bc5dSTrond Myklebust atomic_inc(&stp->st_stid.sc_count); 34843abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 34853c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 3486b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 348713cd2184SNeilBrown get_nfs4_file(fp); 348811b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 34891da177e4SLinus Torvalds stp->st_access_bmap = 0; 34901da177e4SLinus Torvalds stp->st_deny_bmap = 0; 34914c4cd222SNeilBrown stp->st_openstp = NULL; 349235a92fe8SJeff Layton init_rwsem(&stp->st_rwsem); 34931c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 34941d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 34957fc0564eSAndrew Elble 34967fc0564eSAndrew Elble out_unlock: 34971d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 34981c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 34997fc0564eSAndrew Elble return retstp; 35001da177e4SLinus Torvalds } 35011da177e4SLinus Torvalds 3502d3134b10SJeff Layton /* 3503d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 3504d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 3505d3134b10SJeff Layton * them before returning however. 3506d3134b10SJeff Layton */ 35071da177e4SLinus Torvalds static void 3508d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 35091da177e4SLinus Torvalds { 3510217526e7SJeff Layton struct nfs4_ol_stateid *last; 3511d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 3512d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 3513d3134b10SJeff Layton nfsd_net_id); 351473758fedSStanislav Kinsbursky 3515fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 35161da177e4SLinus Torvalds 3517b401be22SJeff Layton /* 3518b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 3519b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 3520b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 3521b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 3522b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 3523b401be22SJeff Layton * there should be no danger of the refcount going back up again at 3524b401be22SJeff Layton * this point. 3525b401be22SJeff Layton */ 3526b401be22SJeff Layton wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2); 3527b401be22SJeff Layton 3528d3134b10SJeff Layton release_all_access(s); 3529d3134b10SJeff Layton if (s->st_stid.sc_file) { 3530d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 3531d3134b10SJeff Layton s->st_stid.sc_file = NULL; 3532d3134b10SJeff Layton } 3533217526e7SJeff Layton 3534217526e7SJeff Layton spin_lock(&nn->client_lock); 3535217526e7SJeff Layton last = oo->oo_last_closed_stid; 3536d3134b10SJeff Layton oo->oo_last_closed_stid = s; 353773758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 3538fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 3539217526e7SJeff Layton spin_unlock(&nn->client_lock); 3540217526e7SJeff Layton if (last) 3541217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 35421da177e4SLinus Torvalds } 35431da177e4SLinus Torvalds 35441da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 35451da177e4SLinus Torvalds static struct nfs4_file * 35465b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval) 35471da177e4SLinus Torvalds { 35481da177e4SLinus Torvalds struct nfs4_file *fp; 35491da177e4SLinus Torvalds 35505b095e99SJeff Layton hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { 35514d94c2efSChristoph Hellwig if (fh_match(&fp->fi_fhandle, fh)) { 35525b095e99SJeff Layton if (atomic_inc_not_zero(&fp->fi_ref)) 35531da177e4SLinus Torvalds return fp; 35541da177e4SLinus Torvalds } 355513cd2184SNeilBrown } 35561da177e4SLinus Torvalds return NULL; 35571da177e4SLinus Torvalds } 35581da177e4SLinus Torvalds 3559e6ba76e1SChristoph Hellwig struct nfs4_file * 3560ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 3561950e0118STrond Myklebust { 3562950e0118STrond Myklebust struct nfs4_file *fp; 35635b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 3564950e0118STrond Myklebust 35655b095e99SJeff Layton rcu_read_lock(); 35665b095e99SJeff Layton fp = find_file_locked(fh, hashval); 35675b095e99SJeff Layton rcu_read_unlock(); 3568950e0118STrond Myklebust return fp; 3569950e0118STrond Myklebust } 3570950e0118STrond Myklebust 3571950e0118STrond Myklebust static struct nfs4_file * 3572f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 3573950e0118STrond Myklebust { 3574950e0118STrond Myklebust struct nfs4_file *fp; 35755b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 35765b095e99SJeff Layton 35775b095e99SJeff Layton rcu_read_lock(); 35785b095e99SJeff Layton fp = find_file_locked(fh, hashval); 35795b095e99SJeff Layton rcu_read_unlock(); 35805b095e99SJeff Layton if (fp) 35815b095e99SJeff Layton return fp; 3582950e0118STrond Myklebust 3583950e0118STrond Myklebust spin_lock(&state_lock); 35845b095e99SJeff Layton fp = find_file_locked(fh, hashval); 35855b095e99SJeff Layton if (likely(fp == NULL)) { 35865b095e99SJeff Layton nfsd4_init_file(fh, hashval, new); 3587950e0118STrond Myklebust fp = new; 3588950e0118STrond Myklebust } 3589950e0118STrond Myklebust spin_unlock(&state_lock); 3590950e0118STrond Myklebust 3591950e0118STrond Myklebust return fp; 3592950e0118STrond Myklebust } 3593950e0118STrond Myklebust 35944f83aa30SJ. Bruce Fields /* 35951da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 35961da177e4SLinus Torvalds * WRITE with all zero or all one stateid 35971da177e4SLinus Torvalds */ 3598b37ad28bSAl Viro static __be32 35991da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 36001da177e4SLinus Torvalds { 36011da177e4SLinus Torvalds struct nfs4_file *fp; 3602baeb4ff0SJeff Layton __be32 ret = nfs_ok; 36031da177e4SLinus Torvalds 3604ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 360513cd2184SNeilBrown if (!fp) 3606baeb4ff0SJeff Layton return ret; 3607baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 36081d31a253STrond Myklebust spin_lock(&fp->fi_lock); 3609baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 3610baeb4ff0SJeff Layton ret = nfserr_locked; 36111d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 361213cd2184SNeilBrown put_nfs4_file(fp); 361313cd2184SNeilBrown return ret; 36141da177e4SLinus Torvalds } 36151da177e4SLinus Torvalds 36160162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 36171da177e4SLinus Torvalds { 36180162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 361911b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 362011b9164aSTrond Myklebust nfsd_net_id); 3621e8c69d17SJ. Bruce Fields 362211b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 3623f54fe962SJeff Layton 362402e1215fSJeff Layton /* 362502e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 3626f54fe962SJeff Layton * already holding inode->i_lock. 3627f54fe962SJeff Layton * 3628dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 3629dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 3630dff1399fSJeff Layton */ 3631f54fe962SJeff Layton spin_lock(&state_lock); 3632dff1399fSJeff Layton if (dp->dl_time == 0) { 36331da177e4SLinus Torvalds dp->dl_time = get_seconds(); 363402e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 363502e1215fSJeff Layton } 363602e1215fSJeff Layton spin_unlock(&state_lock); 3637dff1399fSJeff Layton } 36381da177e4SLinus Torvalds 36390162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 36400162ac2bSChristoph Hellwig struct rpc_task *task) 36410162ac2bSChristoph Hellwig { 36420162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 36430162ac2bSChristoph Hellwig 3644a457974fSAndrew Elble if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID) 3645a457974fSAndrew Elble return 1; 3646a457974fSAndrew Elble 36470162ac2bSChristoph Hellwig switch (task->tk_status) { 36480162ac2bSChristoph Hellwig case 0: 36490162ac2bSChristoph Hellwig return 1; 36500162ac2bSChristoph Hellwig case -EBADHANDLE: 36510162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 36520162ac2bSChristoph Hellwig /* 36530162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 36540162ac2bSChristoph Hellwig * granting delegation. 36550162ac2bSChristoph Hellwig */ 36560162ac2bSChristoph Hellwig if (dp->dl_retries--) { 36570162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 36580162ac2bSChristoph Hellwig return 0; 36590162ac2bSChristoph Hellwig } 36600162ac2bSChristoph Hellwig /*FALLTHRU*/ 36610162ac2bSChristoph Hellwig default: 36620162ac2bSChristoph Hellwig return -1; 36630162ac2bSChristoph Hellwig } 36640162ac2bSChristoph Hellwig } 36650162ac2bSChristoph Hellwig 36660162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 36670162ac2bSChristoph Hellwig { 36680162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 36690162ac2bSChristoph Hellwig 36700162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 36710162ac2bSChristoph Hellwig } 36720162ac2bSChristoph Hellwig 3673c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 36740162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 36750162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 36760162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 36770162ac2bSChristoph Hellwig }; 36780162ac2bSChristoph Hellwig 367902e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 368002e1215fSJeff Layton { 368102e1215fSJeff Layton /* 368202e1215fSJeff Layton * We're assuming the state code never drops its reference 368302e1215fSJeff Layton * without first removing the lease. Since we're in this lease 368402e1215fSJeff Layton * callback (and since the lease code is serialized by the kernel 368502e1215fSJeff Layton * lock) we know the server hasn't removed the lease yet, we know 368602e1215fSJeff Layton * it's safe to take a reference. 368702e1215fSJeff Layton */ 368872c0b0fbSTrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 3689f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 36906b57d9c8SJ. Bruce Fields } 36916b57d9c8SJ. Bruce Fields 36921c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 36934d01b7f5SJeff Layton static bool 36944d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 36956b57d9c8SJ. Bruce Fields { 36964d01b7f5SJeff Layton bool ret = false; 3697acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 3698acfdf5c3SJ. Bruce Fields struct nfs4_delegation *dp; 36996b57d9c8SJ. Bruce Fields 37007fa10cd1SJ. Bruce Fields if (!fp) { 37017fa10cd1SJ. Bruce Fields WARN(1, "(%p)->fl_owner NULL\n", fl); 37024d01b7f5SJeff Layton return ret; 37037fa10cd1SJ. Bruce Fields } 37047fa10cd1SJ. Bruce Fields if (fp->fi_had_conflict) { 37057fa10cd1SJ. Bruce Fields WARN(1, "duplicate break on %p\n", fp); 37064d01b7f5SJeff Layton return ret; 37077fa10cd1SJ. Bruce Fields } 37080272e1fdSJ. Bruce Fields /* 37090272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 3710acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 37116b57d9c8SJ. Bruce Fields * in time: 37120272e1fdSJ. Bruce Fields */ 37130272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 37141da177e4SLinus Torvalds 371502e1215fSJeff Layton spin_lock(&fp->fi_lock); 3716417c6629SJeff Layton fp->fi_had_conflict = true; 3717417c6629SJeff Layton /* 37184d01b7f5SJeff Layton * If there are no delegations on the list, then return true 37194d01b7f5SJeff Layton * so that the lease code will go ahead and delete it. 3720417c6629SJeff Layton */ 3721417c6629SJeff Layton if (list_empty(&fp->fi_delegations)) 37224d01b7f5SJeff Layton ret = true; 3723417c6629SJeff Layton else 3724acfdf5c3SJ. Bruce Fields list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 37255d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 372602e1215fSJeff Layton spin_unlock(&fp->fi_lock); 37274d01b7f5SJeff Layton return ret; 37281da177e4SLinus Torvalds } 37291da177e4SLinus Torvalds 3730c45198edSJeff Layton static int 37317448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 37327448cc37SJeff Layton struct list_head *dispose) 37331da177e4SLinus Torvalds { 37341da177e4SLinus Torvalds if (arg & F_UNLCK) 3735c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 37361da177e4SLinus Torvalds else 37371da177e4SLinus Torvalds return -EAGAIN; 37381da177e4SLinus Torvalds } 37391da177e4SLinus Torvalds 37407b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 37418fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 37428fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 37431da177e4SLinus Torvalds }; 37441da177e4SLinus Torvalds 37457a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 37467a8711c9SJ. Bruce Fields { 37477a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 37487a8711c9SJ. Bruce Fields return nfs_ok; 37497a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 37507a8711c9SJ. Bruce Fields return nfserr_replay_me; 37517a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 37527a8711c9SJ. Bruce Fields return nfs_ok; 37537a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 37547a8711c9SJ. Bruce Fields } 37551da177e4SLinus Torvalds 37564b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 37574b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 37584b24ca7dSJeff Layton struct nfsd_net *nn) 37594b24ca7dSJeff Layton { 37604b24ca7dSJeff Layton struct nfs4_client *found; 37614b24ca7dSJeff Layton 37624b24ca7dSJeff Layton if (cstate->clp) { 37634b24ca7dSJeff Layton found = cstate->clp; 37644b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 37654b24ca7dSJeff Layton return nfserr_stale_clientid; 37664b24ca7dSJeff Layton return nfs_ok; 37674b24ca7dSJeff Layton } 37684b24ca7dSJeff Layton 37694b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 37704b24ca7dSJeff Layton return nfserr_stale_clientid; 37714b24ca7dSJeff Layton 37724b24ca7dSJeff Layton /* 37734b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 37744b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 37754b24ca7dSJeff Layton * will be false. 37764b24ca7dSJeff Layton */ 37774b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 37783e339f96STrond Myklebust spin_lock(&nn->client_lock); 37794b24ca7dSJeff Layton found = find_confirmed_client(clid, false, nn); 37803e339f96STrond Myklebust if (!found) { 37813e339f96STrond Myklebust spin_unlock(&nn->client_lock); 37824b24ca7dSJeff Layton return nfserr_expired; 37833e339f96STrond Myklebust } 37843e339f96STrond Myklebust atomic_inc(&found->cl_refcount); 37853e339f96STrond Myklebust spin_unlock(&nn->client_lock); 37864b24ca7dSJeff Layton 37874b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 37884b24ca7dSJeff Layton cstate->clp = found; 37894b24ca7dSJeff Layton return nfs_ok; 37904b24ca7dSJeff Layton } 37914b24ca7dSJeff Layton 3792b37ad28bSAl Viro __be32 37936668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 37943320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 37951da177e4SLinus Torvalds { 37961da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 37971da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 37981da177e4SLinus Torvalds unsigned int strhashval; 3799fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 38004cdc951bSJ. Bruce Fields __be32 status; 38011da177e4SLinus Torvalds 38022c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 38031da177e4SLinus Torvalds return nfserr_stale_clientid; 380432513b40SJ. Bruce Fields /* 380532513b40SJ. Bruce Fields * In case we need it later, after we've already created the 380632513b40SJ. Bruce Fields * file and don't want to risk a further failure: 380732513b40SJ. Bruce Fields */ 380832513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 380932513b40SJ. Bruce Fields if (open->op_file == NULL) 381032513b40SJ. Bruce Fields return nfserr_jukebox; 38111da177e4SLinus Torvalds 381213d6f66bSTrond Myklebust status = lookup_clientid(clientid, cstate, nn); 381313d6f66bSTrond Myklebust if (status) 381413d6f66bSTrond Myklebust return status; 381513d6f66bSTrond Myklebust clp = cstate->clp; 38162d91e895STrond Myklebust 3817d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 3818d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 38192d91e895STrond Myklebust open->op_openowner = oo; 38202d91e895STrond Myklebust if (!oo) { 3821bcf130f9SJ. Bruce Fields goto new_owner; 38220f442aa2SJ. Bruce Fields } 3823dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 38240f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 3825fe0750e5SJ. Bruce Fields release_openowner(oo); 3826fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 3827bcf130f9SJ. Bruce Fields goto new_owner; 38280f442aa2SJ. Bruce Fields } 38294cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 38304cdc951bSJ. Bruce Fields if (status) 38314cdc951bSJ. Bruce Fields return status; 38324cdc951bSJ. Bruce Fields goto alloc_stateid; 3833bcf130f9SJ. Bruce Fields new_owner: 383413d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 3835fe0750e5SJ. Bruce Fields if (oo == NULL) 38363e772463SJ. Bruce Fields return nfserr_jukebox; 3837fe0750e5SJ. Bruce Fields open->op_openowner = oo; 38384cdc951bSJ. Bruce Fields alloc_stateid: 3839b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 38404cdc951bSJ. Bruce Fields if (!open->op_stp) 38414cdc951bSJ. Bruce Fields return nfserr_jukebox; 38428287f009SSachin Bhamare 38438287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 38448287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 38458287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 38468287f009SSachin Bhamare if (!open->op_odstate) 38478287f009SSachin Bhamare return nfserr_jukebox; 38488287f009SSachin Bhamare } 38498287f009SSachin Bhamare 38500f442aa2SJ. Bruce Fields return nfs_ok; 38511da177e4SLinus Torvalds } 38521da177e4SLinus Torvalds 3853b37ad28bSAl Viro static inline __be32 38544a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 38554a6e43e6SNeilBrown { 38564a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 38574a6e43e6SNeilBrown return nfserr_openmode; 38584a6e43e6SNeilBrown else 38594a6e43e6SNeilBrown return nfs_ok; 38604a6e43e6SNeilBrown } 38614a6e43e6SNeilBrown 3862c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 386324a0111eSJ. Bruce Fields { 386424a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 386524a0111eSJ. Bruce Fields } 386624a0111eSJ. Bruce Fields 386738c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 3868f459e453SJ. Bruce Fields { 3869f459e453SJ. Bruce Fields struct nfs4_stid *ret; 3870f459e453SJ. Bruce Fields 387138c2f4b1SJ. Bruce Fields ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); 3872f459e453SJ. Bruce Fields if (!ret) 3873f459e453SJ. Bruce Fields return NULL; 3874f459e453SJ. Bruce Fields return delegstateid(ret); 3875f459e453SJ. Bruce Fields } 3876f459e453SJ. Bruce Fields 38778b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 38788b289b2cSJ. Bruce Fields { 38798b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 38808b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 38818b289b2cSJ. Bruce Fields } 38828b289b2cSJ. Bruce Fields 3883b37ad28bSAl Viro static __be32 388441d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 3885567d9829SNeilBrown struct nfs4_delegation **dp) 3886567d9829SNeilBrown { 3887567d9829SNeilBrown int flags; 3888b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 3889dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 3890567d9829SNeilBrown 3891dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 3892dcd94cc2STrond Myklebust if (deleg == NULL) 3893c44c5eebSNeilBrown goto out; 389424a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 3895dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 3896dcd94cc2STrond Myklebust if (status) { 3897dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 3898dcd94cc2STrond Myklebust goto out; 3899dcd94cc2STrond Myklebust } 3900dcd94cc2STrond Myklebust *dp = deleg; 3901c44c5eebSNeilBrown out: 39028b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 3903c44c5eebSNeilBrown return nfs_ok; 3904c44c5eebSNeilBrown if (status) 3905c44c5eebSNeilBrown return status; 3906dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 3907c44c5eebSNeilBrown return nfs_ok; 3908567d9829SNeilBrown } 3909567d9829SNeilBrown 391021fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 391121fb4016SJ. Bruce Fields { 391221fb4016SJ. Bruce Fields int flags = 0; 391321fb4016SJ. Bruce Fields 391421fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 391521fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 391621fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 391721fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 391821fb4016SJ. Bruce Fields return flags; 391921fb4016SJ. Bruce Fields } 392021fb4016SJ. Bruce Fields 3921b37ad28bSAl Viro static inline __be32 39221da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 39231da177e4SLinus Torvalds struct nfsd4_open *open) 39241da177e4SLinus Torvalds { 39251da177e4SLinus Torvalds struct iattr iattr = { 39261da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 39271da177e4SLinus Torvalds .ia_size = 0, 39281da177e4SLinus Torvalds }; 39291da177e4SLinus Torvalds if (!open->op_truncate) 39301da177e4SLinus Torvalds return 0; 39311da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 39329246585aSAl Viro return nfserr_inval; 39331da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 39341da177e4SLinus Torvalds } 39351da177e4SLinus Torvalds 39367e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 39376eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 39386eb3a1d0SJeff Layton struct nfsd4_open *open) 39397e6a72e5SChristoph Hellwig { 3940de18643dSTrond Myklebust struct file *filp = NULL; 39417e6a72e5SChristoph Hellwig __be32 status; 39427e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 39437e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 3944baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 39457e6a72e5SChristoph Hellwig 3946de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3947baeb4ff0SJeff Layton 3948baeb4ff0SJeff Layton /* 3949baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 3950baeb4ff0SJeff Layton * current access? 3951baeb4ff0SJeff Layton */ 3952baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 3953baeb4ff0SJeff Layton if (status != nfs_ok) { 3954baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3955baeb4ff0SJeff Layton goto out; 3956baeb4ff0SJeff Layton } 3957baeb4ff0SJeff Layton 3958baeb4ff0SJeff Layton /* set access to the file */ 3959baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 3960baeb4ff0SJeff Layton if (status != nfs_ok) { 3961baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3962baeb4ff0SJeff Layton goto out; 3963baeb4ff0SJeff Layton } 3964baeb4ff0SJeff Layton 3965baeb4ff0SJeff Layton /* Set access bits in stateid */ 3966baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 3967baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 3968baeb4ff0SJeff Layton 3969baeb4ff0SJeff Layton /* Set new deny mask */ 3970baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 3971baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 3972baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 3973baeb4ff0SJeff Layton 39747e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 3975de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3976de18643dSTrond Myklebust status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); 39777e6a72e5SChristoph Hellwig if (status) 3978baeb4ff0SJeff Layton goto out_put_access; 3979de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3980de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 3981de18643dSTrond Myklebust fp->fi_fds[oflag] = filp; 3982de18643dSTrond Myklebust filp = NULL; 3983de18643dSTrond Myklebust } 39847e6a72e5SChristoph Hellwig } 3985de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3986de18643dSTrond Myklebust if (filp) 3987de18643dSTrond Myklebust fput(filp); 39887e6a72e5SChristoph Hellwig 39897e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 39907e6a72e5SChristoph Hellwig if (status) 39917e6a72e5SChristoph Hellwig goto out_put_access; 39927e6a72e5SChristoph Hellwig out: 39937e6a72e5SChristoph Hellwig return status; 3994baeb4ff0SJeff Layton out_put_access: 3995baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 3996baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 3997baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 3998baeb4ff0SJeff Layton goto out; 39997e6a72e5SChristoph Hellwig } 40007e6a72e5SChristoph Hellwig 4001b37ad28bSAl Viro static __be32 4002dcef0413SJ. 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) 40031da177e4SLinus Torvalds { 4004b37ad28bSAl Viro __be32 status; 40056ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 40061da177e4SLinus Torvalds 40076eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 4008baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 40097e6a72e5SChristoph Hellwig 4010baeb4ff0SJeff Layton /* test and set deny mode */ 4011baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 4012baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4013baeb4ff0SJeff Layton if (status == nfs_ok) { 4014baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4015baeb4ff0SJeff Layton fp->fi_share_deny |= 4016baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 40171da177e4SLinus Torvalds } 4018baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 40191da177e4SLinus Torvalds 4020baeb4ff0SJeff Layton if (status != nfs_ok) 4021baeb4ff0SJeff Layton return status; 4022baeb4ff0SJeff Layton 4023baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 4024baeb4ff0SJeff Layton if (status != nfs_ok) 4025baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 4026baeb4ff0SJeff Layton return status; 4027baeb4ff0SJeff Layton } 40281da177e4SLinus Torvalds 402914a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 403014a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 403114a24e99SJ. Bruce Fields { 403214a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 403314a24e99SJ. Bruce Fields return true; 403414a24e99SJ. Bruce Fields /* 403514a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 403614a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 403714a24e99SJ. Bruce Fields * until we hear otherwise: 403814a24e99SJ. Bruce Fields */ 403914a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 404014a24e99SJ. Bruce Fields } 404114a24e99SJ. Bruce Fields 4042d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag) 404322d38c4cSJ. Bruce Fields { 404422d38c4cSJ. Bruce Fields struct file_lock *fl; 404522d38c4cSJ. Bruce Fields 404622d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 404722d38c4cSJ. Bruce Fields if (!fl) 404822d38c4cSJ. Bruce Fields return NULL; 404922d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 4050617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 405122d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 405222d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 4053d564fbecSJeff Layton fl->fl_owner = (fl_owner_t)fp; 405422d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 405522d38c4cSJ. Bruce Fields return fl; 405622d38c4cSJ. Bruce Fields } 405722d38c4cSJ. Bruce Fields 405834ed9872SAndrew Elble /** 405934ed9872SAndrew Elble * nfs4_setlease - Obtain a delegation by requesting lease from vfs layer 406034ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we're adding. 406134ed9872SAndrew Elble * 406234ed9872SAndrew Elble * Return: 406334ed9872SAndrew Elble * On success: Return code will be 0 on success. 406434ed9872SAndrew Elble * 406534ed9872SAndrew Elble * On error: -EAGAIN if there was an existing delegation. 406634ed9872SAndrew Elble * nonzero if there is an error in other cases. 406734ed9872SAndrew Elble * 406834ed9872SAndrew Elble */ 406934ed9872SAndrew Elble 407099c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp) 4071edab9782SJ. Bruce Fields { 407211b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 4073efde6b4dSKinglong Mee struct file_lock *fl; 4074417c6629SJeff Layton struct file *filp; 4075417c6629SJeff Layton int status = 0; 4076edab9782SJ. Bruce Fields 4077d564fbecSJeff Layton fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ); 4078edab9782SJ. Bruce Fields if (!fl) 4079edab9782SJ. Bruce Fields return -ENOMEM; 4080417c6629SJeff Layton filp = find_readable_file(fp); 4081417c6629SJeff Layton if (!filp) { 4082417c6629SJeff Layton /* We should always have a readable file here */ 4083417c6629SJeff Layton WARN_ON_ONCE(1); 4084af9dbaf4SKinglong Mee locks_free_lock(fl); 4085417c6629SJeff Layton return -EBADF; 4086417c6629SJeff Layton } 4087417c6629SJeff Layton fl->fl_file = filp; 4088e6f5c789SJeff Layton status = vfs_setlease(filp, fl->fl_type, &fl, NULL); 40891c7dd2ffSJeff Layton if (fl) 4090417c6629SJeff Layton locks_free_lock(fl); 40911c7dd2ffSJeff Layton if (status) 4092417c6629SJeff Layton goto out_fput; 4093cdc97505SBenny Halevy spin_lock(&state_lock); 4094417c6629SJeff Layton spin_lock(&fp->fi_lock); 4095417c6629SJeff Layton /* Did the lease get broken before we took the lock? */ 4096417c6629SJeff Layton status = -EAGAIN; 4097417c6629SJeff Layton if (fp->fi_had_conflict) 4098417c6629SJeff Layton goto out_unlock; 4099417c6629SJeff Layton /* Race breaker */ 41000c637be8SJeff Layton if (fp->fi_deleg_file) { 410134ed9872SAndrew Elble status = hash_delegation_locked(dp, fp); 4102417c6629SJeff Layton goto out_unlock; 4103417c6629SJeff Layton } 4104417c6629SJeff Layton fp->fi_deleg_file = filp; 410534ed9872SAndrew Elble fp->fi_delegees = 0; 410634ed9872SAndrew Elble status = hash_delegation_locked(dp, fp); 4107417c6629SJeff Layton spin_unlock(&fp->fi_lock); 4108cdc97505SBenny Halevy spin_unlock(&state_lock); 410934ed9872SAndrew Elble if (status) { 411034ed9872SAndrew Elble /* Should never happen, this is a new fi_deleg_file */ 411134ed9872SAndrew Elble WARN_ON_ONCE(1); 411234ed9872SAndrew Elble goto out_fput; 411334ed9872SAndrew Elble } 4114acfdf5c3SJ. Bruce Fields return 0; 4115417c6629SJeff Layton out_unlock: 4116417c6629SJeff Layton spin_unlock(&fp->fi_lock); 4117417c6629SJeff Layton spin_unlock(&state_lock); 4118417c6629SJeff Layton out_fput: 4119417c6629SJeff Layton fput(filp); 4120e873088fSJ. Bruce Fields return status; 4121acfdf5c3SJ. Bruce Fields } 4122acfdf5c3SJ. Bruce Fields 41230b26693cSJeff Layton static struct nfs4_delegation * 41240b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 41258287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 4126acfdf5c3SJ. Bruce Fields { 41270b26693cSJeff Layton int status; 41280b26693cSJeff Layton struct nfs4_delegation *dp; 4129417c6629SJeff Layton 4130bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 41310b26693cSJeff Layton return ERR_PTR(-EAGAIN); 41320b26693cSJeff Layton 413334ed9872SAndrew Elble spin_lock(&state_lock); 413434ed9872SAndrew Elble spin_lock(&fp->fi_lock); 413534ed9872SAndrew Elble status = nfs4_get_existing_delegation(clp, fp); 413634ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 413734ed9872SAndrew Elble spin_unlock(&state_lock); 413834ed9872SAndrew Elble 413934ed9872SAndrew Elble if (status) 414034ed9872SAndrew Elble return ERR_PTR(status); 414134ed9872SAndrew Elble 41428287f009SSachin Bhamare dp = alloc_init_deleg(clp, fh, odstate); 41430b26693cSJeff Layton if (!dp) 41440b26693cSJeff Layton return ERR_PTR(-ENOMEM); 41450b26693cSJeff Layton 4146bf7bd3e9SJ. Bruce Fields get_nfs4_file(fp); 4147cdc97505SBenny Halevy spin_lock(&state_lock); 4148417c6629SJeff Layton spin_lock(&fp->fi_lock); 414911b9164aSTrond Myklebust dp->dl_stid.sc_file = fp; 41500c637be8SJeff Layton if (!fp->fi_deleg_file) { 4151417c6629SJeff Layton spin_unlock(&fp->fi_lock); 4152417c6629SJeff Layton spin_unlock(&state_lock); 41530b26693cSJeff Layton status = nfs4_setlease(dp); 41540b26693cSJeff Layton goto out; 4155417c6629SJeff Layton } 4156acfdf5c3SJ. Bruce Fields if (fp->fi_had_conflict) { 4157417c6629SJeff Layton status = -EAGAIN; 4158417c6629SJeff Layton goto out_unlock; 4159acfdf5c3SJ. Bruce Fields } 416034ed9872SAndrew Elble status = hash_delegation_locked(dp, fp); 4161417c6629SJeff Layton out_unlock: 4162417c6629SJeff Layton spin_unlock(&fp->fi_lock); 4163cdc97505SBenny Halevy spin_unlock(&state_lock); 41640b26693cSJeff Layton out: 41650b26693cSJeff Layton if (status) { 41668287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 41676011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 41680b26693cSJeff Layton return ERR_PTR(status); 41690b26693cSJeff Layton } 41700b26693cSJeff Layton return dp; 4171edab9782SJ. Bruce Fields } 4172edab9782SJ. Bruce Fields 41734aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 41744aa8913cSBenny Halevy { 41754aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 41764aa8913cSBenny Halevy if (status == -EAGAIN) 41774aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 41784aa8913cSBenny Halevy else { 41794aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 41804aa8913cSBenny Halevy switch (open->op_deleg_want) { 41814aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 41824aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 41834aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 41844aa8913cSBenny Halevy break; 41854aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 41864aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 41874aa8913cSBenny Halevy break; 41884aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 4189063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 41904aa8913cSBenny Halevy } 41914aa8913cSBenny Halevy } 41924aa8913cSBenny Halevy } 41934aa8913cSBenny Halevy 41941da177e4SLinus Torvalds /* 41951da177e4SLinus Torvalds * Attempt to hand out a delegation. 419699c41515SJ. Bruce Fields * 419799c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 419899c41515SJ. Bruce Fields * proper support for them. 41991da177e4SLinus Torvalds */ 42001da177e4SLinus Torvalds static void 42014cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 42024cf59221SJeff Layton struct nfs4_ol_stateid *stp) 42031da177e4SLinus Torvalds { 42041da177e4SLinus Torvalds struct nfs4_delegation *dp; 42054cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 42064cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 420714a24e99SJ. Bruce Fields int cb_up; 420899c41515SJ. Bruce Fields int status = 0; 42091da177e4SLinus Torvalds 4210fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 42117b190fecSNeilBrown open->op_recall = 0; 42127b190fecSNeilBrown switch (open->op_claim_type) { 42137b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 42142bf23875SJ. Bruce Fields if (!cb_up) 42157b190fecSNeilBrown open->op_recall = 1; 421699c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 421799c41515SJ. Bruce Fields goto out_no_deleg; 42187b190fecSNeilBrown break; 42197b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 4220ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 422199c41515SJ. Bruce Fields /* 422299c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 4223c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 4224c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 422599c41515SJ. Bruce Fields */ 42264cf59221SJeff Layton if (locks_in_grace(clp->net)) 422799c41515SJ. Bruce Fields goto out_no_deleg; 4228dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 422999c41515SJ. Bruce Fields goto out_no_deleg; 42309a0590aeSSteve Dickson /* 42319a0590aeSSteve Dickson * Also, if the file was opened for write or 42329a0590aeSSteve Dickson * create, there's a good chance the client's 42339a0590aeSSteve Dickson * about to write to it, resulting in an 42349a0590aeSSteve Dickson * immediate recall (since we don't support 42359a0590aeSSteve Dickson * write delegations): 42369a0590aeSSteve Dickson */ 42371da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 423899c41515SJ. Bruce Fields goto out_no_deleg; 423999c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 424099c41515SJ. Bruce Fields goto out_no_deleg; 42417b190fecSNeilBrown break; 42427b190fecSNeilBrown default: 424399c41515SJ. Bruce Fields goto out_no_deleg; 42447b190fecSNeilBrown } 42458287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 42460b26693cSJeff Layton if (IS_ERR(dp)) 4247dd239cc0SJ. Bruce Fields goto out_no_deleg; 42481da177e4SLinus Torvalds 4249d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 42501da177e4SLinus Torvalds 42518c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 4252d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 425399c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 425467cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4255dd239cc0SJ. Bruce Fields return; 4256dd239cc0SJ. Bruce Fields out_no_deleg: 425799c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 42587b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 4259d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 42601da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 4261d08d32e6SJ. Bruce Fields open->op_recall = 1; 4262d08d32e6SJ. Bruce Fields } 4263dd239cc0SJ. Bruce Fields 4264dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 4265dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 4266dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 4267dd239cc0SJ. Bruce Fields return; 42681da177e4SLinus Torvalds } 42691da177e4SLinus Torvalds 4270e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 4271e27f49c3SBenny Halevy struct nfs4_delegation *dp) 4272e27f49c3SBenny Halevy { 4273e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 4274e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4275e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4276e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 4277e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 4278e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4279e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4280e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 4281e27f49c3SBenny Halevy } 4282e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 4283e27f49c3SBenny Halevy * it already has, therefore we don't return 4284e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 4285e27f49c3SBenny Halevy */ 4286e27f49c3SBenny Halevy } 4287e27f49c3SBenny Halevy 4288b37ad28bSAl Viro __be32 42891da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 42901da177e4SLinus Torvalds { 42916668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 429238c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 42931da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 4294dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 42957fc0564eSAndrew Elble struct nfs4_ol_stateid *swapstp = NULL; 4296567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 4297b37ad28bSAl Viro __be32 status; 42981da177e4SLinus Torvalds 42991da177e4SLinus Torvalds /* 43001da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 43011da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 43021da177e4SLinus Torvalds * If not found, create the nfs4_file struct 43031da177e4SLinus Torvalds */ 4304f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 4305950e0118STrond Myklebust if (fp != open->op_file) { 430641d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 4307c44c5eebSNeilBrown if (status) 4308c44c5eebSNeilBrown goto out; 43097fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 4310a46cb7f2SJeff Layton stp = nfsd4_find_existing_open(fp, open); 43117fc0564eSAndrew Elble spin_unlock(&fp->fi_lock); 43121da177e4SLinus Torvalds } else { 4313950e0118STrond Myklebust open->op_file = NULL; 4314c44c5eebSNeilBrown status = nfserr_bad_stateid; 43158b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 4316c44c5eebSNeilBrown goto out; 43171da177e4SLinus Torvalds } 43181da177e4SLinus Torvalds 43191da177e4SLinus Torvalds /* 43201da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 43211da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 43221da177e4SLinus Torvalds */ 43231da177e4SLinus Torvalds if (stp) { 43241da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 432535a92fe8SJeff Layton down_read(&stp->st_rwsem); 4326f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 432735a92fe8SJeff Layton if (status) { 432835a92fe8SJeff Layton up_read(&stp->st_rwsem); 43291da177e4SLinus Torvalds goto out; 433035a92fe8SJeff Layton } 43311da177e4SLinus Torvalds } else { 43324cdc951bSJ. Bruce Fields stp = open->op_stp; 43334cdc951bSJ. Bruce Fields open->op_stp = NULL; 43347fc0564eSAndrew Elble swapstp = init_open_stateid(stp, fp, open); 43357fc0564eSAndrew Elble if (swapstp) { 43367fc0564eSAndrew Elble nfs4_put_stid(&stp->st_stid); 43377fc0564eSAndrew Elble stp = swapstp; 43387fc0564eSAndrew Elble down_read(&stp->st_rwsem); 43397fc0564eSAndrew Elble status = nfs4_upgrade_open(rqstp, fp, current_fh, 43407fc0564eSAndrew Elble stp, open); 43417fc0564eSAndrew Elble if (status) { 43427fc0564eSAndrew Elble up_read(&stp->st_rwsem); 43437fc0564eSAndrew Elble goto out; 43447fc0564eSAndrew Elble } 43457fc0564eSAndrew Elble goto upgrade_out; 43467fc0564eSAndrew Elble } 434735a92fe8SJeff Layton down_read(&stp->st_rwsem); 43486eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 43496eb3a1d0SJeff Layton if (status) { 435035a92fe8SJeff Layton up_read(&stp->st_rwsem); 43516eb3a1d0SJeff Layton release_open_stateid(stp); 43526eb3a1d0SJeff Layton goto out; 43536eb3a1d0SJeff Layton } 43548287f009SSachin Bhamare 43558287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 43568287f009SSachin Bhamare open->op_odstate); 43578287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 43588287f009SSachin Bhamare open->op_odstate = NULL; 43591da177e4SLinus Torvalds } 43607fc0564eSAndrew Elble upgrade_out: 43619767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 436235a92fe8SJeff Layton up_read(&stp->st_rwsem); 43631da177e4SLinus Torvalds 4364d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 4365d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 4366d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4367d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 4368d24433cdSBenny Halevy goto nodeleg; 4369d24433cdSBenny Halevy } 4370d24433cdSBenny Halevy } 4371d24433cdSBenny Halevy 43721da177e4SLinus Torvalds /* 43731da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 43741da177e4SLinus Torvalds * OPEN succeeds even if we fail. 43751da177e4SLinus Torvalds */ 43764cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 4377d24433cdSBenny Halevy nodeleg: 43781da177e4SLinus Torvalds status = nfs_ok; 43791da177e4SLinus Torvalds 43808c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 4381dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 43821da177e4SLinus Torvalds out: 4383d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 4384d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 4385e27f49c3SBenny Halevy open->op_deleg_want) 4386e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 4387d24433cdSBenny Halevy 438813cd2184SNeilBrown if (fp) 438913cd2184SNeilBrown put_nfs4_file(fp); 439037515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 439187186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 43921da177e4SLinus Torvalds /* 43931da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 43941da177e4SLinus Torvalds */ 43951da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 4396dad1c067SJ. Bruce Fields if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) && 43976668958fSAndy Adamson !nfsd4_has_session(&resp->cstate)) 43981da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 4399dcd94cc2STrond Myklebust if (dp) 4400dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4401d6f2bc5dSTrond Myklebust if (stp) 4402d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 44031da177e4SLinus Torvalds 44041da177e4SLinus Torvalds return status; 44051da177e4SLinus Torvalds } 44061da177e4SLinus Torvalds 440758fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 440842297899SJeff Layton struct nfsd4_open *open) 4409d29b20cdSJ. Bruce Fields { 4410d29b20cdSJ. Bruce Fields if (open->op_openowner) { 4411d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 4412d29b20cdSJ. Bruce Fields 4413d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 4414d3134b10SJeff Layton nfs4_put_stateowner(so); 4415d29b20cdSJ. Bruce Fields } 441632513b40SJ. Bruce Fields if (open->op_file) 44175b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 44184cdc951bSJ. Bruce Fields if (open->op_stp) 44196011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 44208287f009SSachin Bhamare if (open->op_odstate) 44218287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 4422d29b20cdSJ. Bruce Fields } 4423d29b20cdSJ. Bruce Fields 4424b37ad28bSAl Viro __be32 4425b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4426b591480bSJ.Bruce Fields clientid_t *clid) 44271da177e4SLinus Torvalds { 44281da177e4SLinus Torvalds struct nfs4_client *clp; 4429b37ad28bSAl Viro __be32 status; 44307f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 44311da177e4SLinus Torvalds 44321da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 44331da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 44344b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 44359b2ef62bSJ. Bruce Fields if (status) 44361da177e4SLinus Torvalds goto out; 44374b24ca7dSJeff Layton clp = cstate->clp; 44381da177e4SLinus Torvalds status = nfserr_cb_path_down; 4439ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 444077a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 44411da177e4SLinus Torvalds goto out; 44421da177e4SLinus Torvalds status = nfs_ok; 44431da177e4SLinus Torvalds out: 44441da177e4SLinus Torvalds return status; 44451da177e4SLinus Torvalds } 44461da177e4SLinus Torvalds 44477f5ef2e9SJeff Layton void 444812760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 4449a76b4319SNeilBrown { 445033dcc481SJeff Layton /* do nothing if grace period already ended */ 4451a51c84edSStanislav Kinsbursky if (nn->grace_ended) 445233dcc481SJeff Layton return; 445333dcc481SJeff Layton 4454a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 4455a51c84edSStanislav Kinsbursky nn->grace_ended = true; 445670b28235SJ. Bruce Fields /* 445770b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 445870b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 445970b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 446070b28235SJ. Bruce Fields * 446170b28235SJ. Bruce Fields */ 4462919b8049SJeff Layton nfsd4_record_grace_done(nn); 446370b28235SJ. Bruce Fields /* 446470b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 446570b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 446670b28235SJ. Bruce Fields * of luck on the next boot. 446770b28235SJ. Bruce Fields * 446870b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 446970b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 447070b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 447170b28235SJ. Bruce Fields */ 44725e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 447370b28235SJ. Bruce Fields /* 447470b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 447570b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 447670b28235SJ. Bruce Fields * regular locking can resume. 447770b28235SJ. Bruce Fields */ 4478a76b4319SNeilBrown } 4479a76b4319SNeilBrown 4480fd39ca9aSNeilBrown static time_t 448109121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 44821da177e4SLinus Torvalds { 44831da177e4SLinus Torvalds struct nfs4_client *clp; 4484fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 44851da177e4SLinus Torvalds struct nfs4_delegation *dp; 4486217526e7SJeff Layton struct nfs4_ol_stateid *stp; 44871da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 44883d733711SStanislav Kinsbursky time_t cutoff = get_seconds() - nn->nfsd4_lease; 4489a832e7aeSJeff Layton time_t t, new_timeo = nn->nfsd4_lease; 44901da177e4SLinus Torvalds 44911da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 449212760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 449336acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 4494c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 44955ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 44961da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 44971da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 44981da177e4SLinus Torvalds t = clp->cl_time - cutoff; 4499a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 45001da177e4SLinus Torvalds break; 45011da177e4SLinus Torvalds } 4502221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 4503d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 4504d7682988SBenny Halevy clp->cl_clientid.cl_id); 4505d7682988SBenny Halevy continue; 4506d7682988SBenny Halevy } 45074864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 450836acb66bSBenny Halevy } 4509c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 451036acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 451136acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 45121da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 45131da177e4SLinus Torvalds clp->cl_clientid.cl_id); 45144864af97STrond Myklebust list_del_init(&clp->cl_lru); 45151da177e4SLinus Torvalds expire_client(clp); 45161da177e4SLinus Torvalds } 4517cdc97505SBenny Halevy spin_lock(&state_lock); 4518e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 45191da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 45201da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 4521a832e7aeSJeff Layton t = dp->dl_time - cutoff; 4522a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 45231da177e4SLinus Torvalds break; 45241da177e4SLinus Torvalds } 45253fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 452642690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 45271da177e4SLinus Torvalds } 4528cdc97505SBenny Halevy spin_unlock(&state_lock); 45292d4a532dSJeff Layton while (!list_empty(&reaplist)) { 45302d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 45312d4a532dSJeff Layton dl_recall_lru); 45322d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 45333bd64a5bSJ. Bruce Fields revoke_delegation(dp); 45341da177e4SLinus Torvalds } 4535217526e7SJeff Layton 4536217526e7SJeff Layton spin_lock(&nn->client_lock); 4537217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 4538217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 4539217526e7SJeff Layton oo_close_lru); 4540217526e7SJeff Layton if (time_after((unsigned long)oo->oo_time, 4541217526e7SJeff Layton (unsigned long)cutoff)) { 4542a832e7aeSJeff Layton t = oo->oo_time - cutoff; 4543a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 45441da177e4SLinus Torvalds break; 45451da177e4SLinus Torvalds } 4546217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 4547217526e7SJeff Layton stp = oo->oo_last_closed_stid; 4548217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 4549217526e7SJeff Layton spin_unlock(&nn->client_lock); 4550217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 4551217526e7SJeff Layton spin_lock(&nn->client_lock); 45521da177e4SLinus Torvalds } 4553217526e7SJeff Layton spin_unlock(&nn->client_lock); 4554217526e7SJeff Layton 4555a832e7aeSJeff Layton new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 4556a832e7aeSJeff Layton return new_timeo; 45571da177e4SLinus Torvalds } 45581da177e4SLinus Torvalds 4559a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 4560a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 4561a254b246SHarvey Harrison 4562a254b246SHarvey Harrison static void 456309121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 45641da177e4SLinus Torvalds { 45651da177e4SLinus Torvalds time_t t; 456609121281SStanislav Kinsbursky struct delayed_work *dwork = container_of(laundry, struct delayed_work, 456709121281SStanislav Kinsbursky work); 456809121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 456909121281SStanislav Kinsbursky laundromat_work); 45701da177e4SLinus Torvalds 457109121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 45721da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 457309121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 45741da177e4SLinus Torvalds } 45751da177e4SLinus Torvalds 45768fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 4577f8816512SNeilBrown { 45788fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 4579f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4580f7a4d872SJ. Bruce Fields return nfs_ok; 45811da177e4SLinus Torvalds } 45821da177e4SLinus Torvalds 45831da177e4SLinus Torvalds static inline int 458482c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 45851da177e4SLinus Torvalds { 458682c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 458782c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 458882c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 45891da177e4SLinus Torvalds } 45901da177e4SLinus Torvalds 45911da177e4SLinus Torvalds static inline int 459282c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 45931da177e4SLinus Torvalds { 459482c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 459582c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 45961da177e4SLinus Torvalds } 45971da177e4SLinus Torvalds 45981da177e4SLinus Torvalds static 4599dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 46001da177e4SLinus Torvalds { 4601b37ad28bSAl Viro __be32 status = nfserr_openmode; 46021da177e4SLinus Torvalds 460302921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 460402921914SJ. Bruce Fields if (stp->st_openstp) 460502921914SJ. Bruce Fields stp = stp->st_openstp; 460682c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 46071da177e4SLinus Torvalds goto out; 460882c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 46091da177e4SLinus Torvalds goto out; 46101da177e4SLinus Torvalds status = nfs_ok; 46111da177e4SLinus Torvalds out: 46121da177e4SLinus Torvalds return status; 46131da177e4SLinus Torvalds } 46141da177e4SLinus Torvalds 4615b37ad28bSAl Viro static inline __be32 46165ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 46171da177e4SLinus Torvalds { 4618203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 46191da177e4SLinus Torvalds return nfs_ok; 4620c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 462125985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 46221da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 46231da177e4SLinus Torvalds return nfserr_grace; 46241da177e4SLinus Torvalds } else if (flags & WR_STATE) 46251da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 46261da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 46271da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 46281da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 46291da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 46301da177e4SLinus Torvalds } 46311da177e4SLinus Torvalds 46321da177e4SLinus Torvalds /* 46331da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 46341da177e4SLinus Torvalds * that are not able to provide mandatory locking. 46351da177e4SLinus Torvalds */ 46361da177e4SLinus Torvalds static inline int 46375ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 46381da177e4SLinus Torvalds { 4639c87fb4a3SJ. Bruce Fields return opens_in_grace(net) && mandatory_lock(inode); 46401da177e4SLinus Torvalds } 46411da177e4SLinus Torvalds 464281b82965SJ. Bruce Fields /* Returns true iff a is later than b: */ 464381b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b) 464481b82965SJ. Bruce Fields { 46451a9357f4SJim Rees return (s32)(a->si_generation - b->si_generation) > 0; 464681b82965SJ. Bruce Fields } 464781b82965SJ. Bruce Fields 464857b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 46490836f587SJ. Bruce Fields { 46506668958fSAndy Adamson /* 46516668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 46526668958fSAndy Adamson * when it is zero. 46536668958fSAndy Adamson */ 465428dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 465581b82965SJ. Bruce Fields return nfs_ok; 465681b82965SJ. Bruce Fields 465781b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 465881b82965SJ. Bruce Fields return nfs_ok; 46596668958fSAndy Adamson 46600836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 466181b82965SJ. Bruce Fields if (stateid_generation_after(in, ref)) 46620836f587SJ. Bruce Fields return nfserr_bad_stateid; 46630836f587SJ. Bruce Fields /* 466481b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 466581b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 466681b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 466781b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 466881b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 466981b82965SJ. Bruce Fields * but better performance may result in retrying IO that 467081b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 467181b82965SJ. Bruce Fields * reordered in flight: 46720836f587SJ. Bruce Fields */ 46730836f587SJ. Bruce Fields return nfserr_old_stateid; 46740836f587SJ. Bruce Fields } 46750836f587SJ. Bruce Fields 4676ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 4677ebe9cb3bSChristoph Hellwig { 4678ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 4679ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 4680ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 4681ebe9cb3bSChristoph Hellwig return nfs_ok; 4682ebe9cb3bSChristoph Hellwig } 4683ebe9cb3bSChristoph Hellwig 46847df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 468517456804SBryan Schumaker { 468697b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 46871af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 468817456804SBryan Schumaker 46897df302f7SChuck Lever if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 46901af71cc8SJeff Layton return status; 46917df302f7SChuck Lever /* Client debugging aid. */ 46927df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 46937df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 46947df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 46957df302f7SChuck Lever sizeof(addr_str)); 46967df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 46977df302f7SChuck Lever "with incorrect client ID\n", addr_str); 46981af71cc8SJeff Layton return status; 46997df302f7SChuck Lever } 47001af71cc8SJeff Layton spin_lock(&cl->cl_lock); 47011af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 470297b7e3b6SJ. Bruce Fields if (!s) 47031af71cc8SJeff Layton goto out_unlock; 470436279ac1SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, 1); 470517456804SBryan Schumaker if (status) 47061af71cc8SJeff Layton goto out_unlock; 470723340032SJ. Bruce Fields switch (s->sc_type) { 470823340032SJ. Bruce Fields case NFS4_DELEG_STID: 47091af71cc8SJeff Layton status = nfs_ok; 47101af71cc8SJeff Layton break; 47113bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 47121af71cc8SJeff Layton status = nfserr_deleg_revoked; 47131af71cc8SJeff Layton break; 471423340032SJ. Bruce Fields case NFS4_OPEN_STID: 471523340032SJ. Bruce Fields case NFS4_LOCK_STID: 4716ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 47171af71cc8SJeff Layton break; 471823340032SJ. Bruce Fields default: 471923340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 4720b0fc29d6STrond Myklebust /* Fallthrough */ 472123340032SJ. Bruce Fields case NFS4_CLOSED_STID: 4722b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 47231af71cc8SJeff Layton status = nfserr_bad_stateid; 472423340032SJ. Bruce Fields } 47251af71cc8SJeff Layton out_unlock: 47261af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 47271af71cc8SJeff Layton return status; 472817456804SBryan Schumaker } 472917456804SBryan Schumaker 4730cd61c522SChristoph Hellwig __be32 47312dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 47322dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 47332dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 473438c2f4b1SJ. Bruce Fields { 47350eb6f20aSJ. Bruce Fields __be32 status; 473638c2f4b1SJ. Bruce Fields 473738c2f4b1SJ. Bruce Fields if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 473838c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 47394b24ca7dSJeff Layton status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn); 4740a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 47414b24ca7dSJeff Layton if (cstate->session) 4742a8a7c677STrond Myklebust return nfserr_bad_stateid; 474338c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 4744a8a7c677STrond Myklebust } 47450eb6f20aSJ. Bruce Fields if (status) 47460eb6f20aSJ. Bruce Fields return status; 47474b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 474838c2f4b1SJ. Bruce Fields if (!*s) 474938c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 475038c2f4b1SJ. Bruce Fields return nfs_ok; 475138c2f4b1SJ. Bruce Fields } 475238c2f4b1SJ. Bruce Fields 4753a0649b2dSChristoph Hellwig static struct file * 4754a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 4755a0649b2dSChristoph Hellwig { 4756af90f707SChristoph Hellwig if (!s) 4757af90f707SChristoph Hellwig return NULL; 4758af90f707SChristoph Hellwig 4759a0649b2dSChristoph Hellwig switch (s->sc_type) { 4760a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 4761a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 4762a0649b2dSChristoph Hellwig return NULL; 4763a0649b2dSChristoph Hellwig return get_file(s->sc_file->fi_deleg_file); 4764a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 4765a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 4766a0649b2dSChristoph Hellwig if (flags & RD_STATE) 4767a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 4768a0649b2dSChristoph Hellwig else 4769a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 4770a0649b2dSChristoph Hellwig break; 4771a0649b2dSChristoph Hellwig } 4772a0649b2dSChristoph Hellwig 4773a0649b2dSChristoph Hellwig return NULL; 4774a0649b2dSChristoph Hellwig } 4775a0649b2dSChristoph Hellwig 4776a0649b2dSChristoph Hellwig static __be32 4777a0649b2dSChristoph Hellwig nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags) 4778a0649b2dSChristoph Hellwig { 4779a0649b2dSChristoph Hellwig __be32 status; 4780a0649b2dSChristoph Hellwig 4781a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 4782a0649b2dSChristoph Hellwig if (status) 4783a0649b2dSChristoph Hellwig return status; 4784a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 4785a0649b2dSChristoph Hellwig } 4786a0649b2dSChristoph Hellwig 4787af90f707SChristoph Hellwig static __be32 4788af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 4789af90f707SChristoph Hellwig struct file **filpp, bool *tmp_file, int flags) 4790af90f707SChristoph Hellwig { 4791af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 4792af90f707SChristoph Hellwig struct file *file; 4793af90f707SChristoph Hellwig __be32 status; 4794af90f707SChristoph Hellwig 4795af90f707SChristoph Hellwig file = nfs4_find_file(s, flags); 4796af90f707SChristoph Hellwig if (file) { 4797af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 4798af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 4799af90f707SChristoph Hellwig if (status) { 4800af90f707SChristoph Hellwig fput(file); 4801af90f707SChristoph Hellwig return status; 4802af90f707SChristoph Hellwig } 4803af90f707SChristoph Hellwig 4804af90f707SChristoph Hellwig *filpp = file; 4805af90f707SChristoph Hellwig } else { 4806af90f707SChristoph Hellwig status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp); 4807af90f707SChristoph Hellwig if (status) 4808af90f707SChristoph Hellwig return status; 4809af90f707SChristoph Hellwig 4810af90f707SChristoph Hellwig if (tmp_file) 4811af90f707SChristoph Hellwig *tmp_file = true; 4812af90f707SChristoph Hellwig } 4813af90f707SChristoph Hellwig 4814af90f707SChristoph Hellwig return 0; 4815af90f707SChristoph Hellwig } 4816af90f707SChristoph Hellwig 48171da177e4SLinus Torvalds /* 48181da177e4SLinus Torvalds * Checks for stateid operations 48191da177e4SLinus Torvalds */ 4820b37ad28bSAl Viro __be32 4821af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 4822af90f707SChristoph Hellwig struct nfsd4_compound_state *cstate, stateid_t *stateid, 4823af90f707SChristoph Hellwig int flags, struct file **filpp, bool *tmp_file) 48241da177e4SLinus Torvalds { 4825a0649b2dSChristoph Hellwig struct svc_fh *fhp = &cstate->current_fh; 4826a0649b2dSChristoph Hellwig struct inode *ino = d_inode(fhp->fh_dentry); 4827af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 48283320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 4829af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 4830b37ad28bSAl Viro __be32 status; 48311da177e4SLinus Torvalds 48321da177e4SLinus Torvalds if (filpp) 48331da177e4SLinus Torvalds *filpp = NULL; 4834af90f707SChristoph Hellwig if (tmp_file) 4835af90f707SChristoph Hellwig *tmp_file = false; 48361da177e4SLinus Torvalds 48375ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 48381da177e4SLinus Torvalds return nfserr_grace; 48391da177e4SLinus Torvalds 4840af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 4841af90f707SChristoph Hellwig status = check_special_stateids(net, fhp, stateid, flags); 4842af90f707SChristoph Hellwig goto done; 4843af90f707SChristoph Hellwig } 48441da177e4SLinus Torvalds 48452dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 4846db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 48472dd6e458STrond Myklebust &s, nn); 484838c2f4b1SJ. Bruce Fields if (status) 4849c2d1d6a8STrond Myklebust return status; 4850a0649b2dSChristoph Hellwig status = check_stateid_generation(stateid, &s->sc_stateid, 4851a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 48520c2a498fSJ. Bruce Fields if (status) 48530c2a498fSJ. Bruce Fields goto out; 4854a0649b2dSChristoph Hellwig 4855f7a4d872SJ. Bruce Fields switch (s->sc_type) { 4856f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 4857a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 4858f7a4d872SJ. Bruce Fields break; 4859f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 4860f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 4861a0649b2dSChristoph Hellwig status = nfs4_check_olstateid(fhp, openlockstateid(s), flags); 4862f7a4d872SJ. Bruce Fields break; 4863f7a4d872SJ. Bruce Fields default: 486414bcab1aSTrond Myklebust status = nfserr_bad_stateid; 4865a0649b2dSChristoph Hellwig break; 48661da177e4SLinus Torvalds } 48678fcd461dSJeff Layton if (status) 48688fcd461dSJeff Layton goto out; 48698fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 4870a0649b2dSChristoph Hellwig 4871af90f707SChristoph Hellwig done: 4872af90f707SChristoph Hellwig if (!status && filpp) 4873af90f707SChristoph Hellwig status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags); 48741da177e4SLinus Torvalds out: 4875af90f707SChristoph Hellwig if (s) 4876fd911011STrond Myklebust nfs4_put_stid(s); 48771da177e4SLinus Torvalds return status; 48781da177e4SLinus Torvalds } 48791da177e4SLinus Torvalds 4880e1ca12dfSBryan Schumaker /* 488117456804SBryan Schumaker * Test if the stateid is valid 488217456804SBryan Schumaker */ 488317456804SBryan Schumaker __be32 488417456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 488517456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 488617456804SBryan Schumaker { 488703cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 488803cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 488903cfb420SBryan Schumaker 489003cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 48917df302f7SChuck Lever stateid->ts_id_status = 48927df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 489303cfb420SBryan Schumaker 489417456804SBryan Schumaker return nfs_ok; 489517456804SBryan Schumaker } 489617456804SBryan Schumaker 4897e1ca12dfSBryan Schumaker __be32 4898e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4899e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 4900e1ca12dfSBryan Schumaker { 4901e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 49022da1cec7SJ. Bruce Fields struct nfs4_stid *s; 49033bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 4904fc5a96c3SJeff Layton struct nfs4_ol_stateid *stp; 490538c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 49062da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 4907e1ca12dfSBryan Schumaker 49081af71cc8SJeff Layton spin_lock(&cl->cl_lock); 49091af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 49102da1cec7SJ. Bruce Fields if (!s) 49111af71cc8SJeff Layton goto out_unlock; 49122da1cec7SJ. Bruce Fields switch (s->sc_type) { 49132da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 4914e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 49151af71cc8SJeff Layton break; 49162da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 49171af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 49181af71cc8SJeff Layton if (ret) 49191af71cc8SJeff Layton break; 49201af71cc8SJeff Layton ret = nfserr_locks_held; 49211af71cc8SJeff Layton break; 49222da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 49232da1cec7SJ. Bruce Fields ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 49242da1cec7SJ. Bruce Fields if (ret) 4925f7a4d872SJ. Bruce Fields break; 4926fc5a96c3SJeff Layton stp = openlockstateid(s); 4927fc5a96c3SJeff Layton ret = nfserr_locks_held; 4928fc5a96c3SJeff Layton if (check_for_locks(stp->st_stid.sc_file, 4929fc5a96c3SJeff Layton lockowner(stp->st_stateowner))) 4930fc5a96c3SJeff Layton break; 4931e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 49321af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 4933fc5a96c3SJeff Layton nfs4_put_stid(s); 4934fc5a96c3SJeff Layton ret = nfs_ok; 49351af71cc8SJeff Layton goto out; 49363bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 49373bd64a5bSJ. Bruce Fields dp = delegstateid(s); 49382d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 49392d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 49406011695dSTrond Myklebust nfs4_put_stid(s); 49413bd64a5bSJ. Bruce Fields ret = nfs_ok; 49421af71cc8SJeff Layton goto out; 49431af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 4944e1ca12dfSBryan Schumaker } 49451af71cc8SJeff Layton out_unlock: 49461af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 4947e1ca12dfSBryan Schumaker out: 4948e1ca12dfSBryan Schumaker return ret; 4949e1ca12dfSBryan Schumaker } 4950e1ca12dfSBryan Schumaker 49514c4cd222SNeilBrown static inline int 49524c4cd222SNeilBrown setlkflg (int type) 49534c4cd222SNeilBrown { 49544c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 49554c4cd222SNeilBrown RD_STATE : WR_STATE; 49564c4cd222SNeilBrown } 49571da177e4SLinus Torvalds 4958dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 4959c0a5d93eSJ. Bruce Fields { 4960c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 4961c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 4962c0a5d93eSJ. Bruce Fields __be32 status; 4963c0a5d93eSJ. Bruce Fields 4964c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 4965c0a5d93eSJ. Bruce Fields if (status) 4966c0a5d93eSJ. Bruce Fields return status; 49673bd64a5bSJ. Bruce Fields if (stp->st_stid.sc_type == NFS4_CLOSED_STID 49683bd64a5bSJ. Bruce Fields || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4969f7a4d872SJ. Bruce Fields /* 4970f7a4d872SJ. Bruce Fields * "Closed" stateid's exist *only* to return 49713bd64a5bSJ. Bruce Fields * nfserr_replay_me from the previous step, and 49723bd64a5bSJ. Bruce Fields * revoked delegations are kept only for free_stateid. 4973f7a4d872SJ. Bruce Fields */ 4974f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 497535a92fe8SJeff Layton down_write(&stp->st_rwsem); 4976f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 497735a92fe8SJeff Layton if (status == nfs_ok) 497835a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 497935a92fe8SJeff Layton if (status != nfs_ok) 498035a92fe8SJeff Layton up_write(&stp->st_rwsem); 4981f7a4d872SJ. Bruce Fields return status; 4982c0a5d93eSJ. Bruce Fields } 4983c0a5d93eSJ. Bruce Fields 49841da177e4SLinus Torvalds /* 49851da177e4SLinus Torvalds * Checks for sequence id mutating operations. 49861da177e4SLinus Torvalds */ 4987b37ad28bSAl Viro static __be32 4988dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 49892288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 49903320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 49913320fef1SStanislav Kinsbursky struct nfsd_net *nn) 49921da177e4SLinus Torvalds { 49930836f587SJ. Bruce Fields __be32 status; 499438c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 4995e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 49961da177e4SLinus Torvalds 49978c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 49988c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 49991da177e4SLinus Torvalds 50001da177e4SLinus Torvalds *stpp = NULL; 50012dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 5002c0a5d93eSJ. Bruce Fields if (status) 5003c0a5d93eSJ. Bruce Fields return status; 5004e17f99b7STrond Myklebust stp = openlockstateid(s); 500558fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 50061da177e4SLinus Torvalds 5007e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 5008fd911011STrond Myklebust if (!status) 5009e17f99b7STrond Myklebust *stpp = stp; 5010fd911011STrond Myklebust else 5011fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 5012e17f99b7STrond Myklebust return status; 50131da177e4SLinus Torvalds } 50141da177e4SLinus Torvalds 50153320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 50163320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 5017c0a5d93eSJ. Bruce Fields { 5018c0a5d93eSJ. Bruce Fields __be32 status; 5019c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 50204cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 50211da177e4SLinus Torvalds 5022c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 50234cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 50240836f587SJ. Bruce Fields if (status) 50250836f587SJ. Bruce Fields return status; 50264cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 50274cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 502835a92fe8SJeff Layton up_write(&stp->st_rwsem); 50294cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 5030c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 50314cbfc9f7STrond Myklebust } 50324cbfc9f7STrond Myklebust *stpp = stp; 50333a4f98bbSNeilBrown return nfs_ok; 50341da177e4SLinus Torvalds } 50351da177e4SLinus Torvalds 5036b37ad28bSAl Viro __be32 5037ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5038a4f1706aSJ.Bruce Fields struct nfsd4_open_confirm *oc) 50391da177e4SLinus Torvalds { 5040b37ad28bSAl Viro __be32 status; 5041fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 5042dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 50433320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 50441da177e4SLinus Torvalds 5045a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 5046a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 50471da177e4SLinus Torvalds 5048ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 5049a8cddc5dSJ. Bruce Fields if (status) 5050a8cddc5dSJ. Bruce Fields return status; 50511da177e4SLinus Torvalds 50529072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 5053ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 50543320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 50559072d5c6SJ. Bruce Fields if (status) 50561da177e4SLinus Torvalds goto out; 5057fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 505868b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 505935a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 506035a92fe8SJeff Layton up_write(&stp->st_rwsem); 50612585fc79STrond Myklebust goto put_stateid; 506235a92fe8SJeff Layton } 5063dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 50649767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 506535a92fe8SJeff Layton up_write(&stp->st_rwsem); 50668c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 5067dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 5068c7b9a459SNeilBrown 50692a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 507068b66e82SJ. Bruce Fields status = nfs_ok; 50712585fc79STrond Myklebust put_stateid: 50722585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 50731da177e4SLinus Torvalds out: 50749411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 50751da177e4SLinus Torvalds return status; 50761da177e4SLinus Torvalds } 50771da177e4SLinus Torvalds 50786409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 50791da177e4SLinus Torvalds { 508082c5ff1bSJeff Layton if (!test_access(access, stp)) 50816409a5a6SJ. Bruce Fields return; 508211b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 508382c5ff1bSJeff Layton clear_access(access, stp); 5084f197c271SJ. Bruce Fields } 50856409a5a6SJ. Bruce Fields 50866409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 50876409a5a6SJ. Bruce Fields { 50886409a5a6SJ. Bruce Fields switch (to_access) { 50896409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 50906409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 50916409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 50926409a5a6SJ. Bruce Fields break; 50936409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 50946409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 50956409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 50966409a5a6SJ. Bruce Fields break; 50976409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 50986409a5a6SJ. Bruce Fields break; 50996409a5a6SJ. Bruce Fields default: 5100063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 51011da177e4SLinus Torvalds } 51021da177e4SLinus Torvalds } 51031da177e4SLinus Torvalds 5104b37ad28bSAl Viro __be32 5105ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 5106ca364317SJ.Bruce Fields struct nfsd4_compound_state *cstate, 5107a4f1706aSJ.Bruce Fields struct nfsd4_open_downgrade *od) 51081da177e4SLinus Torvalds { 5109b37ad28bSAl Viro __be32 status; 5110dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 51113320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 51121da177e4SLinus Torvalds 5113a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 5114a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 51151da177e4SLinus Torvalds 5116c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 51172c8bd7e0SBenny Halevy if (od->od_deleg_want) 51182c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 51192c8bd7e0SBenny Halevy od->od_deleg_want); 51201da177e4SLinus Torvalds 5121c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 51223320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 51239072d5c6SJ. Bruce Fields if (status) 51241da177e4SLinus Torvalds goto out; 51251da177e4SLinus Torvalds status = nfserr_inval; 512682c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 5127c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 51281da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 51290667b1e9STrond Myklebust goto put_stateid; 51301da177e4SLinus Torvalds } 5131ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 5132c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 51331da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 51340667b1e9STrond Myklebust goto put_stateid; 51351da177e4SLinus Torvalds } 51366409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 5137ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 51389767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 51391da177e4SLinus Torvalds status = nfs_ok; 51400667b1e9STrond Myklebust put_stateid: 514135a92fe8SJeff Layton up_write(&stp->st_rwsem); 51420667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 51431da177e4SLinus Torvalds out: 51449411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 51451da177e4SLinus Torvalds return status; 51461da177e4SLinus Torvalds } 51471da177e4SLinus Torvalds 5148f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 5149f7a4d872SJ. Bruce Fields { 5150acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 5151e8568739SJeff Layton bool unhashed; 5152d83017f9SJeff Layton LIST_HEAD(reaplist); 5153acf9295bSTrond Myklebust 5154f7a4d872SJ. Bruce Fields s->st_stid.sc_type = NFS4_CLOSED_STID; 51552c41beb0SJeff Layton spin_lock(&clp->cl_lock); 5156e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 5157acf9295bSTrond Myklebust 5158d83017f9SJeff Layton if (clp->cl_minorversion) { 5159e8568739SJeff Layton if (unhashed) 5160d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 5161d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 5162d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 5163d83017f9SJeff Layton } else { 5164d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 5165d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 5166e8568739SJeff Layton if (unhashed) 5167d3134b10SJeff Layton move_to_close_lru(s, clp->net); 516838c387b5SJ. Bruce Fields } 5169d83017f9SJeff Layton } 517038c387b5SJ. Bruce Fields 51711da177e4SLinus Torvalds /* 51721da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 51731da177e4SLinus Torvalds */ 5174b37ad28bSAl Viro __be32 5175ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5176a4f1706aSJ.Bruce Fields struct nfsd4_close *close) 51771da177e4SLinus Torvalds { 5178b37ad28bSAl Viro __be32 status; 5179dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 51803320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 51813320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 51821da177e4SLinus Torvalds 5183a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 5184a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 51851da177e4SLinus Torvalds 5186f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 5187f7a4d872SJ. Bruce Fields &close->cl_stateid, 5188f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 51893320fef1SStanislav Kinsbursky &stp, nn); 51909411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 51919072d5c6SJ. Bruce Fields if (status) 51921da177e4SLinus Torvalds goto out; 51939767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 519435a92fe8SJeff Layton up_write(&stp->st_rwsem); 51951da177e4SLinus Torvalds 5196f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 51978a0b589dSTrond Myklebust 51988a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 51998a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 52001da177e4SLinus Torvalds out: 52011da177e4SLinus Torvalds return status; 52021da177e4SLinus Torvalds } 52031da177e4SLinus Torvalds 5204b37ad28bSAl Viro __be32 5205ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5206ca364317SJ.Bruce Fields struct nfsd4_delegreturn *dr) 52071da177e4SLinus Torvalds { 5208203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 5209203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 521038c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 5211b37ad28bSAl Viro __be32 status; 52123320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 52131da177e4SLinus Torvalds 5214ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 5215203a8c8eSJ. Bruce Fields return status; 52161da177e4SLinus Torvalds 52172dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 521838c2f4b1SJ. Bruce Fields if (status) 5219203a8c8eSJ. Bruce Fields goto out; 522038c2f4b1SJ. Bruce Fields dp = delegstateid(s); 5221d5477a8dSJ. Bruce Fields status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); 5222203a8c8eSJ. Bruce Fields if (status) 5223fd911011STrond Myklebust goto put_stateid; 5224203a8c8eSJ. Bruce Fields 52253bd64a5bSJ. Bruce Fields destroy_delegation(dp); 5226fd911011STrond Myklebust put_stateid: 5227fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 52281da177e4SLinus Torvalds out: 52291da177e4SLinus Torvalds return status; 52301da177e4SLinus Torvalds } 52311da177e4SLinus Torvalds 523287df4de8SBenny Halevy static inline u64 523387df4de8SBenny Halevy end_offset(u64 start, u64 len) 523487df4de8SBenny Halevy { 523587df4de8SBenny Halevy u64 end; 523687df4de8SBenny Halevy 523787df4de8SBenny Halevy end = start + len; 523887df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 523987df4de8SBenny Halevy } 524087df4de8SBenny Halevy 524187df4de8SBenny Halevy /* last octet in a range */ 524287df4de8SBenny Halevy static inline u64 524387df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 524487df4de8SBenny Halevy { 524587df4de8SBenny Halevy u64 end; 524687df4de8SBenny Halevy 5247063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 524887df4de8SBenny Halevy end = start + len; 524987df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 525087df4de8SBenny Halevy } 525187df4de8SBenny Halevy 52521da177e4SLinus Torvalds /* 52531da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 52541da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 52551da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 52561da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 52571da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 52581da177e4SLinus Torvalds * the VFS, but this is a very deep change! 52591da177e4SLinus Torvalds */ 52601da177e4SLinus Torvalds static inline void 52611da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 52621da177e4SLinus Torvalds { 52631da177e4SLinus Torvalds if (lock->fl_start < 0) 52641da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 52651da177e4SLinus Torvalds if (lock->fl_end < 0) 52661da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 52671da177e4SLinus Torvalds } 52681da177e4SLinus Torvalds 5269cae80b30SJeff Layton static fl_owner_t 5270cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner) 5271aef9583bSKinglong Mee { 5272cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5273cae80b30SJeff Layton 5274cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 5275cae80b30SJeff Layton return owner; 5276aef9583bSKinglong Mee } 5277aef9583bSKinglong Mee 5278cae80b30SJeff Layton static void 5279cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner) 5280aef9583bSKinglong Mee { 5281cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5282aef9583bSKinglong Mee 5283cae80b30SJeff Layton if (lo) 5284aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 5285aef9583bSKinglong Mee } 5286aef9583bSKinglong Mee 52877b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 5288aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 5289aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 5290d5b9026aSNeilBrown }; 52911da177e4SLinus Torvalds 52921da177e4SLinus Torvalds static inline void 52931da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 52941da177e4SLinus Torvalds { 5295fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 52961da177e4SLinus Torvalds 5297d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 5298fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 5299fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 5300fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 53017c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 53027c13f344SJ. Bruce Fields /* We just don't care that much */ 53037c13f344SJ. Bruce Fields goto nevermind; 5304fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 5305fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 5306d5b9026aSNeilBrown } else { 53077c13f344SJ. Bruce Fields nevermind: 53087c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 53097c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 5310d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 5311d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 53121da177e4SLinus Torvalds } 53131da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 531487df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 531587df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 53161da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 53171da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 53181da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 53191da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 53201da177e4SLinus Torvalds } 53211da177e4SLinus Torvalds 5322fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5323c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 53241da177e4SLinus Torvalds { 5325d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 5326b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 53271da177e4SLinus Torvalds 53280a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 53290a880a28STrond Myklebust 5330d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 5331d4f0489fSTrond Myklebust so_strhash) { 5332b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 5333b3c32bcdSTrond Myklebust continue; 5334b5971afaSKinglong Mee if (same_owner_str(so, owner)) 5335b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 53361da177e4SLinus Torvalds } 53371da177e4SLinus Torvalds return NULL; 53381da177e4SLinus Torvalds } 53391da177e4SLinus Torvalds 5340c58c6610STrond Myklebust static struct nfs4_lockowner * 5341c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 5342c58c6610STrond Myklebust { 5343c58c6610STrond Myklebust struct nfs4_lockowner *lo; 5344c58c6610STrond Myklebust 5345d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5346c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 5347d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5348c58c6610STrond Myklebust return lo; 5349c58c6610STrond Myklebust } 5350c58c6610STrond Myklebust 53518f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 53528f4b54c5SJeff Layton { 5353c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 53548f4b54c5SJeff Layton } 53558f4b54c5SJeff Layton 53566b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 53576b180f0bSJeff Layton { 53586b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 53596b180f0bSJeff Layton 53606b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 53616b180f0bSJeff Layton } 53626b180f0bSJeff Layton 53636b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 53648f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 53656b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 53666b180f0bSJeff Layton }; 53676b180f0bSJeff Layton 53681da177e4SLinus Torvalds /* 53691da177e4SLinus Torvalds * Alloc a lock owner structure. 53701da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 537125985edcSLucas De Marchi * occurred. 53721da177e4SLinus Torvalds * 537316bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 53741da177e4SLinus Torvalds */ 5375fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5376c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 5377c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 5378c58c6610STrond Myklebust struct nfsd4_lock *lock) 5379c58c6610STrond Myklebust { 5380c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 53811da177e4SLinus Torvalds 5382fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 5383fe0750e5SJ. Bruce Fields if (!lo) 53841da177e4SLinus Torvalds return NULL; 5385fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 5386fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 53875db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 53886b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 5389d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5390c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 5391c58c6610STrond Myklebust if (ret == NULL) { 5392c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 5393d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 5394c58c6610STrond Myklebust ret = lo; 5395c58c6610STrond Myklebust } else 5396d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 5397d50ffdedSKinglong Mee 5398d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5399340f0ba1SJ. Bruce Fields return ret; 54001da177e4SLinus Torvalds } 54011da177e4SLinus Torvalds 5402356a95ecSJeff Layton static void 5403356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 5404356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 5405f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 54061da177e4SLinus Torvalds { 5407d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 54081da177e4SLinus Torvalds 5409356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 5410356a95ecSJeff Layton 54113d0fabd5STrond Myklebust atomic_inc(&stp->st_stid.sc_count); 54123abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 5413b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 541413cd2184SNeilBrown get_nfs4_file(fp); 541511b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 5416b49e084dSJeff Layton stp->st_stid.sc_free = nfs4_free_lock_stateid; 54170997b173SJ. Bruce Fields stp->st_access_bmap = 0; 54181da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 54194c4cd222SNeilBrown stp->st_openstp = open_stp; 542035a92fe8SJeff Layton init_rwsem(&stp->st_rwsem); 54213c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 54221c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 54231d31a253STrond Myklebust spin_lock(&fp->fi_lock); 54241d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 54251d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 54261da177e4SLinus Torvalds } 54271da177e4SLinus Torvalds 5428c53530daSJeff Layton static struct nfs4_ol_stateid * 5429c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) 5430c53530daSJeff Layton { 5431c53530daSJeff Layton struct nfs4_ol_stateid *lst; 5432356a95ecSJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 5433356a95ecSJeff Layton 5434356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 5435c53530daSJeff Layton 5436c53530daSJeff Layton list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { 54373d0fabd5STrond Myklebust if (lst->st_stid.sc_file == fp) { 54383d0fabd5STrond Myklebust atomic_inc(&lst->st_stid.sc_count); 5439c53530daSJeff Layton return lst; 5440c53530daSJeff Layton } 54413d0fabd5STrond Myklebust } 5442c53530daSJeff Layton return NULL; 5443c53530daSJeff Layton } 5444c53530daSJeff Layton 5445356a95ecSJeff Layton static struct nfs4_ol_stateid * 5446356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 5447356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 5448356a95ecSJeff Layton bool *new) 5449356a95ecSJeff Layton { 5450356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 5451356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 5452356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 5453356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 5454356a95ecSJeff Layton 5455356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5456356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5457356a95ecSJeff Layton if (lst == NULL) { 5458356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5459356a95ecSJeff Layton ns = nfs4_alloc_stid(clp, stateid_slab); 5460356a95ecSJeff Layton if (ns == NULL) 5461356a95ecSJeff Layton return NULL; 5462356a95ecSJeff Layton 5463356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5464356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5465356a95ecSJeff Layton if (likely(!lst)) { 5466356a95ecSJeff Layton lst = openlockstateid(ns); 5467356a95ecSJeff Layton init_lock_stateid(lst, lo, fi, inode, ost); 5468356a95ecSJeff Layton ns = NULL; 5469356a95ecSJeff Layton *new = true; 5470356a95ecSJeff Layton } 5471356a95ecSJeff Layton } 5472356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5473356a95ecSJeff Layton if (ns) 5474356a95ecSJeff Layton nfs4_put_stid(ns); 5475356a95ecSJeff Layton return lst; 5476356a95ecSJeff Layton } 5477c53530daSJeff Layton 5478fd39ca9aSNeilBrown static int 54791da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 54801da177e4SLinus Torvalds { 548187df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 5482e7969315SKinglong Mee (length > ~offset))); 54831da177e4SLinus Torvalds } 54841da177e4SLinus Torvalds 5485dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 54860997b173SJ. Bruce Fields { 548711b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 54880997b173SJ. Bruce Fields 54897214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 54907214e860SJeff Layton 549182c5ff1bSJeff Layton if (test_access(access, lock_stp)) 54920997b173SJ. Bruce Fields return; 549312659651SJeff Layton __nfs4_file_get_access(fp, access); 549482c5ff1bSJeff Layton set_access(access, lock_stp); 54950997b173SJ. Bruce Fields } 54960997b173SJ. Bruce Fields 5497356a95ecSJeff Layton static __be32 5498356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 5499356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 5500356a95ecSJeff Layton struct nfsd4_lock *lock, 5501356a95ecSJeff Layton struct nfs4_ol_stateid **lst, bool *new) 550264a284d0SJ. Bruce Fields { 55035db1c03fSJeff Layton __be32 status; 550411b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 550564a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 550664a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 55072b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 550864a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 550964a284d0SJ. Bruce Fields unsigned int strhashval; 551064a284d0SJ. Bruce Fields 5511c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 5512c53530daSJeff Layton if (!lo) { 551376f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 551464a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 551564a284d0SJ. Bruce Fields if (lo == NULL) 551664a284d0SJ. Bruce Fields return nfserr_jukebox; 5517c53530daSJeff Layton } else { 5518c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 55195db1c03fSJeff Layton status = nfserr_bad_seqid; 5520c53530daSJeff Layton if (!cstate->minorversion && 5521c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 55225db1c03fSJeff Layton goto out; 5523c53530daSJeff Layton } 5524c53530daSJeff Layton 5525356a95ecSJeff Layton *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 552664a284d0SJ. Bruce Fields if (*lst == NULL) { 55275db1c03fSJeff Layton status = nfserr_jukebox; 55285db1c03fSJeff Layton goto out; 552964a284d0SJ. Bruce Fields } 55305db1c03fSJeff Layton status = nfs_ok; 55315db1c03fSJeff Layton out: 55325db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 55335db1c03fSJeff Layton return status; 553464a284d0SJ. Bruce Fields } 553564a284d0SJ. Bruce Fields 55361da177e4SLinus Torvalds /* 55371da177e4SLinus Torvalds * LOCK operation 55381da177e4SLinus Torvalds */ 5539b37ad28bSAl Viro __be32 5540ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5541a4f1706aSJ.Bruce Fields struct nfsd4_lock *lock) 55421da177e4SLinus Torvalds { 5543fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 5544fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 55453d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 55460667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 55477214e860SJeff Layton struct nfs4_file *fp; 55487d947842SJ. Bruce Fields struct file *filp = NULL; 554921179d81SJeff Layton struct file_lock *file_lock = NULL; 555021179d81SJeff Layton struct file_lock *conflock = NULL; 5551b37ad28bSAl Viro __be32 status = 0; 5552b34f27aaSJ. Bruce Fields int lkflg; 5553b8dd7b9aSAl Viro int err; 55545db1c03fSJeff Layton bool new = false; 55553320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 55563320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 55571da177e4SLinus Torvalds 55581da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 55591da177e4SLinus Torvalds (long long) lock->lk_offset, 55601da177e4SLinus Torvalds (long long) lock->lk_length); 55611da177e4SLinus Torvalds 55621da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 55631da177e4SLinus Torvalds return nfserr_inval; 55641da177e4SLinus Torvalds 5565ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 55668837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 5567a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 5568a6f6ef2fSAndy Adamson return status; 5569a6f6ef2fSAndy Adamson } 5570a6f6ef2fSAndy Adamson 55711da177e4SLinus Torvalds if (lock->lk_is_new) { 5572684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 5573684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 557476f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 5575684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 5576684e5638SJ. Bruce Fields sizeof(clientid_t)); 5577684e5638SJ. Bruce Fields 55781da177e4SLinus Torvalds status = nfserr_stale_clientid; 55792c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 55801da177e4SLinus Torvalds goto out; 55811da177e4SLinus Torvalds 55821da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 5583c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 55841da177e4SLinus Torvalds lock->lk_new_open_seqid, 55851da177e4SLinus Torvalds &lock->lk_new_open_stateid, 55863320fef1SStanislav Kinsbursky &open_stp, nn); 558737515177SNeilBrown if (status) 55881da177e4SLinus Torvalds goto out; 558935a92fe8SJeff Layton up_write(&open_stp->st_rwsem); 5590fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 5591b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 5592684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 559376f6c9e1SKinglong Mee &lock->lk_new_clientid)) 5594b34f27aaSJ. Bruce Fields goto out; 559564a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 55965db1c03fSJeff Layton &lock_stp, &new); 559735a92fe8SJeff Layton if (status == nfs_ok) 559835a92fe8SJeff Layton down_write(&lock_stp->st_rwsem); 55993d0fabd5STrond Myklebust } else { 5600dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 56011da177e4SLinus Torvalds lock->lk_old_lock_seqid, 56021da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 56033320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 56043d0fabd5STrond Myklebust } 56051da177e4SLinus Torvalds if (status) 56061da177e4SLinus Torvalds goto out; 5607fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 56081da177e4SLinus Torvalds 5609b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 5610b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 5611b34f27aaSJ. Bruce Fields if (status) 5612b34f27aaSJ. Bruce Fields goto out; 5613b34f27aaSJ. Bruce Fields 56140dd395dcSNeilBrown status = nfserr_grace; 56153320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 56160dd395dcSNeilBrown goto out; 56170dd395dcSNeilBrown status = nfserr_no_grace; 56183320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 56190dd395dcSNeilBrown goto out; 56200dd395dcSNeilBrown 562121179d81SJeff Layton file_lock = locks_alloc_lock(); 562221179d81SJeff Layton if (!file_lock) { 562321179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 562421179d81SJeff Layton status = nfserr_jukebox; 562521179d81SJeff Layton goto out; 562621179d81SJeff Layton } 562721179d81SJeff Layton 562811b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 56291da177e4SLinus Torvalds switch (lock->lk_type) { 56301da177e4SLinus Torvalds case NFS4_READ_LT: 56311da177e4SLinus Torvalds case NFS4_READW_LT: 56327214e860SJeff Layton spin_lock(&fp->fi_lock); 56337214e860SJeff Layton filp = find_readable_file_locked(fp); 56340997b173SJ. Bruce Fields if (filp) 56350997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 56367214e860SJeff Layton spin_unlock(&fp->fi_lock); 563721179d81SJeff Layton file_lock->fl_type = F_RDLCK; 56381da177e4SLinus Torvalds break; 56391da177e4SLinus Torvalds case NFS4_WRITE_LT: 56401da177e4SLinus Torvalds case NFS4_WRITEW_LT: 56417214e860SJeff Layton spin_lock(&fp->fi_lock); 56427214e860SJeff Layton filp = find_writeable_file_locked(fp); 56430997b173SJ. Bruce Fields if (filp) 56440997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 56457214e860SJeff Layton spin_unlock(&fp->fi_lock); 564621179d81SJeff Layton file_lock->fl_type = F_WRLCK; 56471da177e4SLinus Torvalds break; 56481da177e4SLinus Torvalds default: 56491da177e4SLinus Torvalds status = nfserr_inval; 56501da177e4SLinus Torvalds goto out; 56511da177e4SLinus Torvalds } 5652f9d7562fSJ. Bruce Fields if (!filp) { 5653f9d7562fSJ. Bruce Fields status = nfserr_openmode; 5654f9d7562fSJ. Bruce Fields goto out; 5655f9d7562fSJ. Bruce Fields } 5656aef9583bSKinglong Mee 5657aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 565821179d81SJeff Layton file_lock->fl_pid = current->tgid; 565921179d81SJeff Layton file_lock->fl_file = filp; 566021179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 566121179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 566221179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 566321179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 566421179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 56651da177e4SLinus Torvalds 566621179d81SJeff Layton conflock = locks_alloc_lock(); 566721179d81SJeff Layton if (!conflock) { 566821179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 566921179d81SJeff Layton status = nfserr_jukebox; 567021179d81SJeff Layton goto out; 567121179d81SJeff Layton } 56721da177e4SLinus Torvalds 567321179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); 5674b8dd7b9aSAl Viro switch (-err) { 56751da177e4SLinus Torvalds case 0: /* success! */ 56769767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 5677b8dd7b9aSAl Viro status = 0; 5678eb76b3fdSAndy Adamson break; 5679eb76b3fdSAndy Adamson case (EAGAIN): /* conflock holds conflicting lock */ 5680eb76b3fdSAndy Adamson status = nfserr_denied; 5681eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 568221179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 5683eb76b3fdSAndy Adamson break; 56841da177e4SLinus Torvalds case (EDEADLK): 56851da177e4SLinus Torvalds status = nfserr_deadlock; 5686eb76b3fdSAndy Adamson break; 56871da177e4SLinus Torvalds default: 5688fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 56893e772463SJ. Bruce Fields status = nfserrno(err); 5690eb76b3fdSAndy Adamson break; 56911da177e4SLinus Torvalds } 56921da177e4SLinus Torvalds out: 5693de18643dSTrond Myklebust if (filp) 5694de18643dSTrond Myklebust fput(filp); 56955db1c03fSJeff Layton if (lock_stp) { 56965db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 56975db1c03fSJeff Layton if (cstate->replay_owner && 56985db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 56995db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 57005db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 57015db1c03fSJeff Layton 570235a92fe8SJeff Layton up_write(&lock_stp->st_rwsem); 570335a92fe8SJeff Layton 57045db1c03fSJeff Layton /* 57055db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 57065db1c03fSJeff Layton * returning an error, then just go ahead and release it. 57075db1c03fSJeff Layton */ 57085db1c03fSJeff Layton if (status && new) 57095db1c03fSJeff Layton release_lock_stateid(lock_stp); 57105db1c03fSJeff Layton 57113d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 57125db1c03fSJeff Layton } 57130667b1e9STrond Myklebust if (open_stp) 57140667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 57159411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 571621179d81SJeff Layton if (file_lock) 571721179d81SJeff Layton locks_free_lock(file_lock); 571821179d81SJeff Layton if (conflock) 571921179d81SJeff Layton locks_free_lock(conflock); 57201da177e4SLinus Torvalds return status; 57211da177e4SLinus Torvalds } 57221da177e4SLinus Torvalds 57231da177e4SLinus Torvalds /* 572455ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 572555ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 572655ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 572755ef1274SJ. Bruce Fields * inode operation.) 572855ef1274SJ. Bruce Fields */ 572904da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 573055ef1274SJ. Bruce Fields { 573155ef1274SJ. Bruce Fields struct file *file; 573204da6e9dSAl Viro __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 573304da6e9dSAl Viro if (!err) { 573404da6e9dSAl Viro err = nfserrno(vfs_test_lock(file, lock)); 5735fd891454SChristoph Hellwig fput(file); 573604da6e9dSAl Viro } 573755ef1274SJ. Bruce Fields return err; 573855ef1274SJ. Bruce Fields } 573955ef1274SJ. Bruce Fields 574055ef1274SJ. Bruce Fields /* 57411da177e4SLinus Torvalds * LOCKT operation 57421da177e4SLinus Torvalds */ 5743b37ad28bSAl Viro __be32 5744ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5745ca364317SJ.Bruce Fields struct nfsd4_lockt *lockt) 57461da177e4SLinus Torvalds { 574721179d81SJeff Layton struct file_lock *file_lock = NULL; 57485db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 5749b37ad28bSAl Viro __be32 status; 57507f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 57511da177e4SLinus Torvalds 57525ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 57531da177e4SLinus Torvalds return nfserr_grace; 57541da177e4SLinus Torvalds 57551da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 57561da177e4SLinus Torvalds return nfserr_inval; 57571da177e4SLinus Torvalds 57589b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 57594b24ca7dSJeff Layton status = lookup_clientid(&lockt->lt_clientid, cstate, nn); 57609b2ef62bSJ. Bruce Fields if (status) 57611da177e4SLinus Torvalds goto out; 57629b2ef62bSJ. Bruce Fields } 57631da177e4SLinus Torvalds 576475c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 57651da177e4SLinus Torvalds goto out; 57661da177e4SLinus Torvalds 576721179d81SJeff Layton file_lock = locks_alloc_lock(); 576821179d81SJeff Layton if (!file_lock) { 576921179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 577021179d81SJeff Layton status = nfserr_jukebox; 577121179d81SJeff Layton goto out; 577221179d81SJeff Layton } 57736cd90662SKinglong Mee 57741da177e4SLinus Torvalds switch (lockt->lt_type) { 57751da177e4SLinus Torvalds case NFS4_READ_LT: 57761da177e4SLinus Torvalds case NFS4_READW_LT: 577721179d81SJeff Layton file_lock->fl_type = F_RDLCK; 57781da177e4SLinus Torvalds break; 57791da177e4SLinus Torvalds case NFS4_WRITE_LT: 57801da177e4SLinus Torvalds case NFS4_WRITEW_LT: 578121179d81SJeff Layton file_lock->fl_type = F_WRLCK; 57821da177e4SLinus Torvalds break; 57831da177e4SLinus Torvalds default: 57842fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 57851da177e4SLinus Torvalds status = nfserr_inval; 57861da177e4SLinus Torvalds goto out; 57871da177e4SLinus Torvalds } 57881da177e4SLinus Torvalds 5789c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 5790fe0750e5SJ. Bruce Fields if (lo) 579121179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 579221179d81SJeff Layton file_lock->fl_pid = current->tgid; 579321179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 57941da177e4SLinus Torvalds 579521179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 579621179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 57971da177e4SLinus Torvalds 579821179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 57991da177e4SLinus Torvalds 580021179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 580104da6e9dSAl Viro if (status) 5802fd85b817SMarc Eshel goto out; 580304da6e9dSAl Viro 580421179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 58051da177e4SLinus Torvalds status = nfserr_denied; 580621179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 58071da177e4SLinus Torvalds } 58081da177e4SLinus Torvalds out: 58095db1c03fSJeff Layton if (lo) 58105db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 581121179d81SJeff Layton if (file_lock) 581221179d81SJeff Layton locks_free_lock(file_lock); 58131da177e4SLinus Torvalds return status; 58141da177e4SLinus Torvalds } 58151da177e4SLinus Torvalds 5816b37ad28bSAl Viro __be32 5817ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5818a4f1706aSJ.Bruce Fields struct nfsd4_locku *locku) 58191da177e4SLinus Torvalds { 5820dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 58211da177e4SLinus Torvalds struct file *filp = NULL; 582221179d81SJeff Layton struct file_lock *file_lock = NULL; 5823b37ad28bSAl Viro __be32 status; 5824b8dd7b9aSAl Viro int err; 58253320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 58261da177e4SLinus Torvalds 58271da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 58281da177e4SLinus Torvalds (long long) locku->lu_offset, 58291da177e4SLinus Torvalds (long long) locku->lu_length); 58301da177e4SLinus Torvalds 58311da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 58321da177e4SLinus Torvalds return nfserr_inval; 58331da177e4SLinus Torvalds 58349072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 58353320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 58363320fef1SStanislav Kinsbursky &stp, nn); 58379072d5c6SJ. Bruce Fields if (status) 58381da177e4SLinus Torvalds goto out; 583911b9164aSTrond Myklebust filp = find_any_file(stp->st_stid.sc_file); 5840f9d7562fSJ. Bruce Fields if (!filp) { 5841f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 5842858cc573STrond Myklebust goto put_stateid; 5843f9d7562fSJ. Bruce Fields } 584421179d81SJeff Layton file_lock = locks_alloc_lock(); 584521179d81SJeff Layton if (!file_lock) { 584621179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 584721179d81SJeff Layton status = nfserr_jukebox; 5848de18643dSTrond Myklebust goto fput; 584921179d81SJeff Layton } 58506cd90662SKinglong Mee 585121179d81SJeff Layton file_lock->fl_type = F_UNLCK; 5852aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 585321179d81SJeff Layton file_lock->fl_pid = current->tgid; 585421179d81SJeff Layton file_lock->fl_file = filp; 585521179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 585621179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 585721179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 58581da177e4SLinus Torvalds 585921179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 586021179d81SJeff Layton locku->lu_length); 586121179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 58621da177e4SLinus Torvalds 586321179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); 5864b8dd7b9aSAl Viro if (err) { 5865fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 58661da177e4SLinus Torvalds goto out_nfserr; 58671da177e4SLinus Torvalds } 58689767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 5869de18643dSTrond Myklebust fput: 5870de18643dSTrond Myklebust fput(filp); 5871858cc573STrond Myklebust put_stateid: 587235a92fe8SJeff Layton up_write(&stp->st_rwsem); 5873858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 58741da177e4SLinus Torvalds out: 58759411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 587621179d81SJeff Layton if (file_lock) 587721179d81SJeff Layton locks_free_lock(file_lock); 58781da177e4SLinus Torvalds return status; 58791da177e4SLinus Torvalds 58801da177e4SLinus Torvalds out_nfserr: 5881b8dd7b9aSAl Viro status = nfserrno(err); 5882de18643dSTrond Myklebust goto fput; 58831da177e4SLinus Torvalds } 58841da177e4SLinus Torvalds 58851da177e4SLinus Torvalds /* 58861da177e4SLinus Torvalds * returns 5887f9c00c3aSJeff Layton * true: locks held by lockowner 5888f9c00c3aSJeff Layton * false: no locks held by lockowner 58891da177e4SLinus Torvalds */ 5890f9c00c3aSJeff Layton static bool 5891f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 58921da177e4SLinus Torvalds { 5893bd61e0a9SJeff Layton struct file_lock *fl; 5894f9c00c3aSJeff Layton int status = false; 5895f9c00c3aSJeff Layton struct file *filp = find_any_file(fp); 5896f9c00c3aSJeff Layton struct inode *inode; 5897bd61e0a9SJeff Layton struct file_lock_context *flctx; 5898f9c00c3aSJeff Layton 5899f9c00c3aSJeff Layton if (!filp) { 5900f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 5901f9c00c3aSJeff Layton WARN_ON_ONCE(1); 5902f9c00c3aSJeff Layton return status; 5903f9c00c3aSJeff Layton } 5904f9c00c3aSJeff Layton 5905f9c00c3aSJeff Layton inode = file_inode(filp); 5906bd61e0a9SJeff Layton flctx = inode->i_flctx; 59071da177e4SLinus Torvalds 5908bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 59096109c850SJeff Layton spin_lock(&flctx->flc_lock); 5910bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 5911bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 5912f9c00c3aSJeff Layton status = true; 5913f9c00c3aSJeff Layton break; 59141da177e4SLinus Torvalds } 5915796dadfdSJ. Bruce Fields } 59166109c850SJeff Layton spin_unlock(&flctx->flc_lock); 5917bd61e0a9SJeff Layton } 5918f9c00c3aSJeff Layton fput(filp); 59191da177e4SLinus Torvalds return status; 59201da177e4SLinus Torvalds } 59211da177e4SLinus Torvalds 5922b37ad28bSAl Viro __be32 5923b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 5924b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 5925b591480bSJ.Bruce Fields struct nfsd4_release_lockowner *rlockowner) 59261da177e4SLinus Torvalds { 59271da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 5928882e9d25SJeff Layton struct nfs4_stateowner *sop; 5929882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 5930dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 59311da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 5932d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 5933b37ad28bSAl Viro __be32 status; 59347f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5935c58c6610STrond Myklebust struct nfs4_client *clp; 59361da177e4SLinus Torvalds 59371da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 59381da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 59391da177e4SLinus Torvalds 59404b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 59419b2ef62bSJ. Bruce Fields if (status) 594251f5e783STrond Myklebust return status; 59439b2ef62bSJ. Bruce Fields 5944d4f0489fSTrond Myklebust clp = cstate->clp; 5945fd44907cSJeff Layton /* Find the matching lock stateowner */ 5946d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5947882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 5948d4f0489fSTrond Myklebust so_strhash) { 5949882e9d25SJeff Layton 5950882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 595116bfdaafSJ. Bruce Fields continue; 5952882e9d25SJeff Layton 5953882e9d25SJeff Layton /* see if there are still any locks associated with it */ 5954882e9d25SJeff Layton lo = lockowner(sop); 5955882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 5956882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 5957882e9d25SJeff Layton status = nfserr_locks_held; 5958882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 595951f5e783STrond Myklebust return status; 5960882e9d25SJeff Layton } 5961882e9d25SJeff Layton } 5962882e9d25SJeff Layton 5963b5971afaSKinglong Mee nfs4_get_stateowner(sop); 5964fd44907cSJeff Layton break; 5965fd44907cSJeff Layton } 5966d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5967882e9d25SJeff Layton if (lo) 5968fe0750e5SJ. Bruce Fields release_lockowner(lo); 59691da177e4SLinus Torvalds return status; 59701da177e4SLinus Torvalds } 59711da177e4SLinus Torvalds 59721da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 5973a55370a3SNeilBrown alloc_reclaim(void) 59741da177e4SLinus Torvalds { 5975a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 59761da177e4SLinus Torvalds } 59771da177e4SLinus Torvalds 59780ce0c2b5SJeff Layton bool 597952e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 5980c7b9a459SNeilBrown { 59810ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 5982c7b9a459SNeilBrown 598352e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 59840ce0c2b5SJeff Layton return (crp && crp->cr_clp); 5985c7b9a459SNeilBrown } 5986c7b9a459SNeilBrown 59871da177e4SLinus Torvalds /* 59881da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 59891da177e4SLinus Torvalds */ 5990772a9bbbSJeff Layton struct nfs4_client_reclaim * 599152e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 59921da177e4SLinus Torvalds { 59931da177e4SLinus Torvalds unsigned int strhashval; 5994772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 59951da177e4SLinus Torvalds 5996a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 5997a55370a3SNeilBrown crp = alloc_reclaim(); 5998772a9bbbSJeff Layton if (crp) { 5999a55370a3SNeilBrown strhashval = clientstr_hashval(name); 60001da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 600152e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 6002a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 60030ce0c2b5SJeff Layton crp->cr_clp = NULL; 600452e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 6005772a9bbbSJeff Layton } 6006772a9bbbSJeff Layton return crp; 60071da177e4SLinus Torvalds } 60081da177e4SLinus Torvalds 60092a4317c5SJeff Layton void 601052e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 6011ce30e539SJeff Layton { 6012ce30e539SJeff Layton list_del(&crp->cr_strhash); 6013ce30e539SJeff Layton kfree(crp); 601452e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 6015ce30e539SJeff Layton } 6016ce30e539SJeff Layton 6017ce30e539SJeff Layton void 601852e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 60191da177e4SLinus Torvalds { 60201da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 60211da177e4SLinus Torvalds int i; 60221da177e4SLinus Torvalds 60231da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 602452e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 602552e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 60261da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 602752e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 60281da177e4SLinus Torvalds } 60291da177e4SLinus Torvalds } 6030063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 60311da177e4SLinus Torvalds } 60321da177e4SLinus Torvalds 60331da177e4SLinus Torvalds /* 60341da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 60352a4317c5SJeff Layton struct nfs4_client_reclaim * 603652e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 60371da177e4SLinus Torvalds { 60381da177e4SLinus Torvalds unsigned int strhashval; 60391da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 60401da177e4SLinus Torvalds 6041278c931cSJeff Layton dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 60421da177e4SLinus Torvalds 6043278c931cSJeff Layton strhashval = clientstr_hashval(recdir); 604452e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 6045278c931cSJeff Layton if (same_name(crp->cr_recdir, recdir)) { 60461da177e4SLinus Torvalds return crp; 60471da177e4SLinus Torvalds } 60481da177e4SLinus Torvalds } 60491da177e4SLinus Torvalds return NULL; 60501da177e4SLinus Torvalds } 60511da177e4SLinus Torvalds 60521da177e4SLinus Torvalds /* 60531da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 60541da177e4SLinus Torvalds */ 6055b37ad28bSAl Viro __be32 60560fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 60570fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 60580fe492dbSTrond Myklebust struct nfsd_net *nn) 60591da177e4SLinus Torvalds { 60600fe492dbSTrond Myklebust __be32 status; 6061a52d726bSJeff Layton 6062a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 60630fe492dbSTrond Myklebust status = lookup_clientid(clid, cstate, nn); 60640fe492dbSTrond Myklebust if (status) 6065a52d726bSJeff Layton return nfserr_reclaim_bad; 6066a52d726bSJeff Layton 60673b3e7b72SJeff Layton if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) 60683b3e7b72SJeff Layton return nfserr_no_grace; 60693b3e7b72SJeff Layton 60700fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 60710fe492dbSTrond Myklebust return nfserr_reclaim_bad; 60720fe492dbSTrond Myklebust 60730fe492dbSTrond Myklebust return nfs_ok; 60741da177e4SLinus Torvalds } 60751da177e4SLinus Torvalds 607665178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 6077016200c3SJeff Layton static inline void 6078016200c3SJeff Layton put_client(struct nfs4_client *clp) 6079016200c3SJeff Layton { 6080016200c3SJeff Layton atomic_dec(&clp->cl_refcount); 6081016200c3SJeff Layton } 6082016200c3SJeff Layton 6083285abdeeSJeff Layton static struct nfs4_client * 6084285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 6085285abdeeSJeff Layton { 6086285abdeeSJeff Layton struct nfs4_client *clp; 6087285abdeeSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6088285abdeeSJeff Layton nfsd_net_id); 6089285abdeeSJeff Layton 6090285abdeeSJeff Layton if (!nfsd_netns_ready(nn)) 6091285abdeeSJeff Layton return NULL; 6092285abdeeSJeff Layton 6093285abdeeSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 6094285abdeeSJeff Layton if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 6095285abdeeSJeff Layton return clp; 6096285abdeeSJeff Layton } 6097285abdeeSJeff Layton return NULL; 6098285abdeeSJeff Layton } 6099285abdeeSJeff Layton 61007ec0e36fSJeff Layton u64 6101285abdeeSJeff Layton nfsd_inject_print_clients(void) 61027ec0e36fSJeff Layton { 61037ec0e36fSJeff Layton struct nfs4_client *clp; 61047ec0e36fSJeff Layton u64 count = 0; 61057ec0e36fSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 61067ec0e36fSJeff Layton nfsd_net_id); 61077ec0e36fSJeff Layton char buf[INET6_ADDRSTRLEN]; 61087ec0e36fSJeff Layton 61097ec0e36fSJeff Layton if (!nfsd_netns_ready(nn)) 61107ec0e36fSJeff Layton return 0; 61117ec0e36fSJeff Layton 61127ec0e36fSJeff Layton spin_lock(&nn->client_lock); 61137ec0e36fSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 61147ec0e36fSJeff Layton rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 61157ec0e36fSJeff Layton pr_info("NFS Client: %s\n", buf); 61167ec0e36fSJeff Layton ++count; 61177ec0e36fSJeff Layton } 61187ec0e36fSJeff Layton spin_unlock(&nn->client_lock); 61197ec0e36fSJeff Layton 61207ec0e36fSJeff Layton return count; 61217ec0e36fSJeff Layton } 612265178db4SBryan Schumaker 6123a0926d15SJeff Layton u64 6124285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) 6125a0926d15SJeff Layton { 6126a0926d15SJeff Layton u64 count = 0; 6127a0926d15SJeff Layton struct nfs4_client *clp; 6128a0926d15SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6129a0926d15SJeff Layton nfsd_net_id); 6130a0926d15SJeff Layton 6131a0926d15SJeff Layton if (!nfsd_netns_ready(nn)) 6132a0926d15SJeff Layton return count; 6133a0926d15SJeff Layton 6134a0926d15SJeff Layton spin_lock(&nn->client_lock); 6135a0926d15SJeff Layton clp = nfsd_find_client(addr, addr_size); 6136a0926d15SJeff Layton if (clp) { 6137a0926d15SJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) 6138a0926d15SJeff Layton ++count; 6139a0926d15SJeff Layton else 6140a0926d15SJeff Layton clp = NULL; 6141a0926d15SJeff Layton } 6142a0926d15SJeff Layton spin_unlock(&nn->client_lock); 6143a0926d15SJeff Layton 6144a0926d15SJeff Layton if (clp) 6145a0926d15SJeff Layton expire_client(clp); 6146a0926d15SJeff Layton 6147a0926d15SJeff Layton return count; 6148a0926d15SJeff Layton } 6149a0926d15SJeff Layton 615069fc9edfSJeff Layton u64 6151285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max) 615269fc9edfSJeff Layton { 615369fc9edfSJeff Layton u64 count = 0; 615469fc9edfSJeff Layton struct nfs4_client *clp, *next; 615569fc9edfSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 615669fc9edfSJeff Layton nfsd_net_id); 615769fc9edfSJeff Layton LIST_HEAD(reaplist); 615869fc9edfSJeff Layton 615969fc9edfSJeff Layton if (!nfsd_netns_ready(nn)) 616069fc9edfSJeff Layton return count; 616169fc9edfSJeff Layton 616269fc9edfSJeff Layton spin_lock(&nn->client_lock); 616369fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 616469fc9edfSJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) { 616569fc9edfSJeff Layton list_add(&clp->cl_lru, &reaplist); 616669fc9edfSJeff Layton if (max != 0 && ++count >= max) 616769fc9edfSJeff Layton break; 616869fc9edfSJeff Layton } 616969fc9edfSJeff Layton } 617069fc9edfSJeff Layton spin_unlock(&nn->client_lock); 617169fc9edfSJeff Layton 617269fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &reaplist, cl_lru) 617369fc9edfSJeff Layton expire_client(clp); 617469fc9edfSJeff Layton 617569fc9edfSJeff Layton return count; 617669fc9edfSJeff Layton } 617769fc9edfSJeff Layton 6178184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 6179184c1847SBryan Schumaker const char *type) 6180184c1847SBryan Schumaker { 6181184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 61820a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 6183184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 6184184c1847SBryan Schumaker } 6185184c1847SBryan Schumaker 6186016200c3SJeff Layton static void 6187016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, 6188016200c3SJeff Layton struct list_head *collect) 6189016200c3SJeff Layton { 6190016200c3SJeff Layton struct nfs4_client *clp = lst->st_stid.sc_client; 6191016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6192016200c3SJeff Layton nfsd_net_id); 6193016200c3SJeff Layton 6194016200c3SJeff Layton if (!collect) 6195016200c3SJeff Layton return; 6196016200c3SJeff Layton 6197016200c3SJeff Layton lockdep_assert_held(&nn->client_lock); 6198016200c3SJeff Layton atomic_inc(&clp->cl_refcount); 6199016200c3SJeff Layton list_add(&lst->st_locks, collect); 6200016200c3SJeff Layton } 6201016200c3SJeff Layton 62023c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 62033738d50eSJeff Layton struct list_head *collect, 6204e8568739SJeff Layton bool (*func)(struct nfs4_ol_stateid *)) 6205fc29171fSBryan Schumaker { 6206fc29171fSBryan Schumaker struct nfs4_openowner *oop; 6207fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 62083c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 6209fc29171fSBryan Schumaker u64 count = 0; 6210fc29171fSBryan Schumaker 6211016200c3SJeff Layton spin_lock(&clp->cl_lock); 6212fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 62133c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 62143c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 62153c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 62163c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 62173738d50eSJeff Layton if (func) { 6218e8568739SJeff Layton if (func(lst)) 6219016200c3SJeff Layton nfsd_inject_add_lock_to_list(lst, 62203738d50eSJeff Layton collect); 62213738d50eSJeff Layton } 6222016200c3SJeff Layton ++count; 6223016200c3SJeff Layton /* 6224016200c3SJeff Layton * Despite the fact that these functions deal 6225016200c3SJeff Layton * with 64-bit integers for "count", we must 6226016200c3SJeff Layton * ensure that it doesn't blow up the 6227016200c3SJeff Layton * clp->cl_refcount. Throw a warning if we 6228016200c3SJeff Layton * start to approach INT_MAX here. 6229016200c3SJeff Layton */ 6230016200c3SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 6231016200c3SJeff Layton if (count == max) 6232016200c3SJeff Layton goto out; 6233fc29171fSBryan Schumaker } 6234fc29171fSBryan Schumaker } 6235fc29171fSBryan Schumaker } 6236016200c3SJeff Layton out: 6237016200c3SJeff Layton spin_unlock(&clp->cl_lock); 6238fc29171fSBryan Schumaker 6239fc29171fSBryan Schumaker return count; 6240fc29171fSBryan Schumaker } 6241fc29171fSBryan Schumaker 6242016200c3SJeff Layton static u64 6243016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, 6244016200c3SJeff Layton u64 max) 6245fc29171fSBryan Schumaker { 6246016200c3SJeff Layton return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); 6247fc29171fSBryan Schumaker } 6248fc29171fSBryan Schumaker 6249016200c3SJeff Layton static u64 6250016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp) 6251184c1847SBryan Schumaker { 6252016200c3SJeff Layton u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); 6253184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 6254184c1847SBryan Schumaker return count; 6255184c1847SBryan Schumaker } 6256184c1847SBryan Schumaker 6257016200c3SJeff Layton u64 6258285abdeeSJeff Layton nfsd_inject_print_locks(void) 6259016200c3SJeff Layton { 6260016200c3SJeff Layton struct nfs4_client *clp; 6261016200c3SJeff Layton u64 count = 0; 6262016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6263016200c3SJeff Layton nfsd_net_id); 6264016200c3SJeff Layton 6265016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6266016200c3SJeff Layton return 0; 6267016200c3SJeff Layton 6268016200c3SJeff Layton spin_lock(&nn->client_lock); 6269016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 6270016200c3SJeff Layton count += nfsd_print_client_locks(clp); 6271016200c3SJeff Layton spin_unlock(&nn->client_lock); 6272016200c3SJeff Layton 6273016200c3SJeff Layton return count; 6274016200c3SJeff Layton } 6275016200c3SJeff Layton 6276016200c3SJeff Layton static void 6277016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist) 6278016200c3SJeff Layton { 6279016200c3SJeff Layton struct nfs4_client *clp; 6280016200c3SJeff Layton struct nfs4_ol_stateid *stp, *next; 6281016200c3SJeff Layton 6282016200c3SJeff Layton list_for_each_entry_safe(stp, next, reaplist, st_locks) { 6283016200c3SJeff Layton list_del_init(&stp->st_locks); 6284016200c3SJeff Layton clp = stp->st_stid.sc_client; 6285016200c3SJeff Layton nfs4_put_stid(&stp->st_stid); 6286016200c3SJeff Layton put_client(clp); 6287016200c3SJeff Layton } 6288016200c3SJeff Layton } 6289016200c3SJeff Layton 6290016200c3SJeff Layton u64 6291285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) 6292016200c3SJeff Layton { 6293016200c3SJeff Layton unsigned int count = 0; 6294016200c3SJeff Layton struct nfs4_client *clp; 6295016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6296016200c3SJeff Layton nfsd_net_id); 6297016200c3SJeff Layton LIST_HEAD(reaplist); 6298016200c3SJeff Layton 6299016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6300016200c3SJeff Layton return count; 6301016200c3SJeff Layton 6302016200c3SJeff Layton spin_lock(&nn->client_lock); 6303016200c3SJeff Layton clp = nfsd_find_client(addr, addr_size); 6304016200c3SJeff Layton if (clp) 6305016200c3SJeff Layton count = nfsd_collect_client_locks(clp, &reaplist, 0); 6306016200c3SJeff Layton spin_unlock(&nn->client_lock); 6307016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6308016200c3SJeff Layton return count; 6309016200c3SJeff Layton } 6310016200c3SJeff Layton 6311016200c3SJeff Layton u64 6312285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max) 6313016200c3SJeff Layton { 6314016200c3SJeff Layton u64 count = 0; 6315016200c3SJeff Layton struct nfs4_client *clp; 6316016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6317016200c3SJeff Layton nfsd_net_id); 6318016200c3SJeff Layton LIST_HEAD(reaplist); 6319016200c3SJeff Layton 6320016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6321016200c3SJeff Layton return count; 6322016200c3SJeff Layton 6323016200c3SJeff Layton spin_lock(&nn->client_lock); 6324016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 6325016200c3SJeff Layton count += nfsd_collect_client_locks(clp, &reaplist, max - count); 6326016200c3SJeff Layton if (max != 0 && count >= max) 6327016200c3SJeff Layton break; 6328016200c3SJeff Layton } 6329016200c3SJeff Layton spin_unlock(&nn->client_lock); 6330016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6331016200c3SJeff Layton return count; 6332016200c3SJeff Layton } 6333016200c3SJeff Layton 633482e05efaSJeff Layton static u64 633582e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, 633682e05efaSJeff Layton struct list_head *collect, 633782e05efaSJeff Layton void (*func)(struct nfs4_openowner *)) 63384dbdbda8SBryan Schumaker { 63394dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 634082e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 634182e05efaSJeff Layton nfsd_net_id); 63424dbdbda8SBryan Schumaker u64 count = 0; 63434dbdbda8SBryan Schumaker 634482e05efaSJeff Layton lockdep_assert_held(&nn->client_lock); 634582e05efaSJeff Layton 634682e05efaSJeff Layton spin_lock(&clp->cl_lock); 63474dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 634882e05efaSJeff Layton if (func) { 63494dbdbda8SBryan Schumaker func(oop); 635082e05efaSJeff Layton if (collect) { 635182e05efaSJeff Layton atomic_inc(&clp->cl_refcount); 635282e05efaSJeff Layton list_add(&oop->oo_perclient, collect); 635382e05efaSJeff Layton } 635482e05efaSJeff Layton } 635582e05efaSJeff Layton ++count; 635682e05efaSJeff Layton /* 635782e05efaSJeff Layton * Despite the fact that these functions deal with 635882e05efaSJeff Layton * 64-bit integers for "count", we must ensure that 635982e05efaSJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 636082e05efaSJeff Layton * warning if we start to approach INT_MAX here. 636182e05efaSJeff Layton */ 636282e05efaSJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 636382e05efaSJeff Layton if (count == max) 63644dbdbda8SBryan Schumaker break; 63654dbdbda8SBryan Schumaker } 636682e05efaSJeff Layton spin_unlock(&clp->cl_lock); 63674dbdbda8SBryan Schumaker 63684dbdbda8SBryan Schumaker return count; 63694dbdbda8SBryan Schumaker } 63704dbdbda8SBryan Schumaker 637182e05efaSJeff Layton static u64 637282e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp) 63734dbdbda8SBryan Schumaker { 637482e05efaSJeff Layton u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); 637582e05efaSJeff Layton 637682e05efaSJeff Layton nfsd_print_count(clp, count, "openowners"); 637782e05efaSJeff Layton return count; 63784dbdbda8SBryan Schumaker } 63794dbdbda8SBryan Schumaker 638082e05efaSJeff Layton static u64 638182e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp, 638282e05efaSJeff Layton struct list_head *collect, u64 max) 6383184c1847SBryan Schumaker { 638482e05efaSJeff Layton return nfsd_foreach_client_openowner(clp, max, collect, 638582e05efaSJeff Layton unhash_openowner_locked); 638682e05efaSJeff Layton } 638782e05efaSJeff Layton 638882e05efaSJeff Layton u64 6389285abdeeSJeff Layton nfsd_inject_print_openowners(void) 639082e05efaSJeff Layton { 639182e05efaSJeff Layton struct nfs4_client *clp; 639282e05efaSJeff Layton u64 count = 0; 639382e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 639482e05efaSJeff Layton nfsd_net_id); 639582e05efaSJeff Layton 639682e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 639782e05efaSJeff Layton return 0; 639882e05efaSJeff Layton 639982e05efaSJeff Layton spin_lock(&nn->client_lock); 640082e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 640182e05efaSJeff Layton count += nfsd_print_client_openowners(clp); 640282e05efaSJeff Layton spin_unlock(&nn->client_lock); 640382e05efaSJeff Layton 640482e05efaSJeff Layton return count; 640582e05efaSJeff Layton } 640682e05efaSJeff Layton 640782e05efaSJeff Layton static void 640882e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist) 640982e05efaSJeff Layton { 641082e05efaSJeff Layton struct nfs4_client *clp; 641182e05efaSJeff Layton struct nfs4_openowner *oop, *next; 641282e05efaSJeff Layton 641382e05efaSJeff Layton list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { 641482e05efaSJeff Layton list_del_init(&oop->oo_perclient); 641582e05efaSJeff Layton clp = oop->oo_owner.so_client; 641682e05efaSJeff Layton release_openowner(oop); 641782e05efaSJeff Layton put_client(clp); 641882e05efaSJeff Layton } 641982e05efaSJeff Layton } 642082e05efaSJeff Layton 642182e05efaSJeff Layton u64 6422285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, 6423285abdeeSJeff Layton size_t addr_size) 642482e05efaSJeff Layton { 642582e05efaSJeff Layton unsigned int count = 0; 642682e05efaSJeff Layton struct nfs4_client *clp; 642782e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 642882e05efaSJeff Layton nfsd_net_id); 642982e05efaSJeff Layton LIST_HEAD(reaplist); 643082e05efaSJeff Layton 643182e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 643282e05efaSJeff Layton return count; 643382e05efaSJeff Layton 643482e05efaSJeff Layton spin_lock(&nn->client_lock); 643582e05efaSJeff Layton clp = nfsd_find_client(addr, addr_size); 643682e05efaSJeff Layton if (clp) 643782e05efaSJeff Layton count = nfsd_collect_client_openowners(clp, &reaplist, 0); 643882e05efaSJeff Layton spin_unlock(&nn->client_lock); 643982e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 644082e05efaSJeff Layton return count; 644182e05efaSJeff Layton } 644282e05efaSJeff Layton 644382e05efaSJeff Layton u64 6444285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max) 644582e05efaSJeff Layton { 644682e05efaSJeff Layton u64 count = 0; 644782e05efaSJeff Layton struct nfs4_client *clp; 644882e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 644982e05efaSJeff Layton nfsd_net_id); 645082e05efaSJeff Layton LIST_HEAD(reaplist); 645182e05efaSJeff Layton 645282e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 645382e05efaSJeff Layton return count; 645482e05efaSJeff Layton 645582e05efaSJeff Layton spin_lock(&nn->client_lock); 645682e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 645782e05efaSJeff Layton count += nfsd_collect_client_openowners(clp, &reaplist, 645882e05efaSJeff Layton max - count); 645982e05efaSJeff Layton if (max != 0 && count >= max) 646082e05efaSJeff Layton break; 646182e05efaSJeff Layton } 646282e05efaSJeff Layton spin_unlock(&nn->client_lock); 646382e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 6464184c1847SBryan Schumaker return count; 6465184c1847SBryan Schumaker } 6466184c1847SBryan Schumaker 6467269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 6468269de30fSBryan Schumaker struct list_head *victims) 6469269de30fSBryan Schumaker { 6470269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 647198d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 647298d5c7c5SJeff Layton nfsd_net_id); 6473269de30fSBryan Schumaker u64 count = 0; 6474269de30fSBryan Schumaker 647598d5c7c5SJeff Layton lockdep_assert_held(&nn->client_lock); 647698d5c7c5SJeff Layton 647798d5c7c5SJeff Layton spin_lock(&state_lock); 6478269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 6479dff1399fSJeff Layton if (victims) { 6480dff1399fSJeff Layton /* 6481dff1399fSJeff Layton * It's not safe to mess with delegations that have a 6482dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 6483dff1399fSJeff Layton * and could be processed by the laundromat outside of 6484dff1399fSJeff Layton * the state_lock. Just leave them be. 6485dff1399fSJeff Layton */ 6486dff1399fSJeff Layton if (dp->dl_time != 0) 6487dff1399fSJeff Layton continue; 6488dff1399fSJeff Layton 648998d5c7c5SJeff Layton atomic_inc(&clp->cl_refcount); 64903fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 649142690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 6492dff1399fSJeff Layton } 649398d5c7c5SJeff Layton ++count; 649498d5c7c5SJeff Layton /* 649598d5c7c5SJeff Layton * Despite the fact that these functions deal with 649698d5c7c5SJeff Layton * 64-bit integers for "count", we must ensure that 649798d5c7c5SJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 649898d5c7c5SJeff Layton * warning if we start to approach INT_MAX here. 649998d5c7c5SJeff Layton */ 650098d5c7c5SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 650198d5c7c5SJeff Layton if (count == max) 6502269de30fSBryan Schumaker break; 6503269de30fSBryan Schumaker } 650498d5c7c5SJeff Layton spin_unlock(&state_lock); 6505269de30fSBryan Schumaker return count; 6506269de30fSBryan Schumaker } 6507269de30fSBryan Schumaker 650898d5c7c5SJeff Layton static u64 650998d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp) 6510269de30fSBryan Schumaker { 651198d5c7c5SJeff Layton u64 count = nfsd_find_all_delegations(clp, 0, NULL); 6512184c1847SBryan Schumaker 6513184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 6514184c1847SBryan Schumaker return count; 6515184c1847SBryan Schumaker } 6516184c1847SBryan Schumaker 651798d5c7c5SJeff Layton u64 6518285abdeeSJeff Layton nfsd_inject_print_delegations(void) 651998d5c7c5SJeff Layton { 652098d5c7c5SJeff Layton struct nfs4_client *clp; 652198d5c7c5SJeff Layton u64 count = 0; 652298d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 652398d5c7c5SJeff Layton nfsd_net_id); 652498d5c7c5SJeff Layton 652598d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 652698d5c7c5SJeff Layton return 0; 652798d5c7c5SJeff Layton 652898d5c7c5SJeff Layton spin_lock(&nn->client_lock); 652998d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 653098d5c7c5SJeff Layton count += nfsd_print_client_delegations(clp); 653198d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 653298d5c7c5SJeff Layton 653398d5c7c5SJeff Layton return count; 653498d5c7c5SJeff Layton } 653598d5c7c5SJeff Layton 653698d5c7c5SJeff Layton static void 653798d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist) 653898d5c7c5SJeff Layton { 653998d5c7c5SJeff Layton struct nfs4_client *clp; 654098d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 654198d5c7c5SJeff Layton 654298d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 654398d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 654498d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 654598d5c7c5SJeff Layton revoke_delegation(dp); 654698d5c7c5SJeff Layton put_client(clp); 654798d5c7c5SJeff Layton } 654898d5c7c5SJeff Layton } 654998d5c7c5SJeff Layton 655098d5c7c5SJeff Layton u64 6551285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, 6552285abdeeSJeff Layton size_t addr_size) 655398d5c7c5SJeff Layton { 655498d5c7c5SJeff Layton u64 count = 0; 655598d5c7c5SJeff Layton struct nfs4_client *clp; 655698d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 655798d5c7c5SJeff Layton nfsd_net_id); 655898d5c7c5SJeff Layton LIST_HEAD(reaplist); 655998d5c7c5SJeff Layton 656098d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 656198d5c7c5SJeff Layton return count; 656298d5c7c5SJeff Layton 656398d5c7c5SJeff Layton spin_lock(&nn->client_lock); 656498d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 656598d5c7c5SJeff Layton if (clp) 656698d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 656798d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 656898d5c7c5SJeff Layton 656998d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 657098d5c7c5SJeff Layton return count; 657198d5c7c5SJeff Layton } 657298d5c7c5SJeff Layton 657398d5c7c5SJeff Layton u64 6574285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max) 657598d5c7c5SJeff Layton { 657698d5c7c5SJeff Layton u64 count = 0; 657798d5c7c5SJeff Layton struct nfs4_client *clp; 657898d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 657998d5c7c5SJeff Layton nfsd_net_id); 658098d5c7c5SJeff Layton LIST_HEAD(reaplist); 658198d5c7c5SJeff Layton 658298d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 658398d5c7c5SJeff Layton return count; 658498d5c7c5SJeff Layton 658598d5c7c5SJeff Layton spin_lock(&nn->client_lock); 658698d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 658798d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 658898d5c7c5SJeff Layton if (max != 0 && count >= max) 658998d5c7c5SJeff Layton break; 659098d5c7c5SJeff Layton } 659198d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 659298d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 659398d5c7c5SJeff Layton return count; 659498d5c7c5SJeff Layton } 659598d5c7c5SJeff Layton 659698d5c7c5SJeff Layton static void 659798d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist) 659898d5c7c5SJeff Layton { 659998d5c7c5SJeff Layton struct nfs4_client *clp; 660098d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 660198d5c7c5SJeff Layton 660298d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 660398d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 660498d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 660598d5c7c5SJeff Layton /* 660698d5c7c5SJeff Layton * We skipped all entries that had a zero dl_time before, 660798d5c7c5SJeff Layton * so we can now reset the dl_time back to 0. If a delegation 660898d5c7c5SJeff Layton * break comes in now, then it won't make any difference since 660998d5c7c5SJeff Layton * we're recalling it either way. 661098d5c7c5SJeff Layton */ 661198d5c7c5SJeff Layton spin_lock(&state_lock); 661298d5c7c5SJeff Layton dp->dl_time = 0; 661398d5c7c5SJeff Layton spin_unlock(&state_lock); 661498d5c7c5SJeff Layton nfsd_break_one_deleg(dp); 661598d5c7c5SJeff Layton put_client(clp); 661698d5c7c5SJeff Layton } 661798d5c7c5SJeff Layton } 661898d5c7c5SJeff Layton 661998d5c7c5SJeff Layton u64 6620285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, 662198d5c7c5SJeff Layton size_t addr_size) 662298d5c7c5SJeff Layton { 662398d5c7c5SJeff Layton u64 count = 0; 662498d5c7c5SJeff Layton struct nfs4_client *clp; 662598d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 662698d5c7c5SJeff Layton nfsd_net_id); 662798d5c7c5SJeff Layton LIST_HEAD(reaplist); 662898d5c7c5SJeff Layton 662998d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 663098d5c7c5SJeff Layton return count; 663198d5c7c5SJeff Layton 663298d5c7c5SJeff Layton spin_lock(&nn->client_lock); 663398d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 663498d5c7c5SJeff Layton if (clp) 663598d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 663698d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 663798d5c7c5SJeff Layton 663898d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 663998d5c7c5SJeff Layton return count; 664098d5c7c5SJeff Layton } 664198d5c7c5SJeff Layton 664298d5c7c5SJeff Layton u64 6643285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max) 664498d5c7c5SJeff Layton { 664598d5c7c5SJeff Layton u64 count = 0; 664698d5c7c5SJeff Layton struct nfs4_client *clp, *next; 664798d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 664898d5c7c5SJeff Layton nfsd_net_id); 664998d5c7c5SJeff Layton LIST_HEAD(reaplist); 665098d5c7c5SJeff Layton 665198d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 665298d5c7c5SJeff Layton return count; 665398d5c7c5SJeff Layton 665498d5c7c5SJeff Layton spin_lock(&nn->client_lock); 665598d5c7c5SJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 665698d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 665798d5c7c5SJeff Layton if (max != 0 && ++count >= max) 665898d5c7c5SJeff Layton break; 665998d5c7c5SJeff Layton } 666098d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 666198d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 666298d5c7c5SJeff Layton return count; 666398d5c7c5SJeff Layton } 666465178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 666565178db4SBryan Schumaker 6666c2f1a551SMeelap Shah /* 6667c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 6668c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 6669c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 6670c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 6671c2f1a551SMeelap Shah * 6672c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 6673c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 6674c2f1a551SMeelap Shah */ 6675c2f1a551SMeelap Shah static void 6676c2f1a551SMeelap Shah set_max_delegations(void) 6677c2f1a551SMeelap Shah { 6678c2f1a551SMeelap Shah /* 6679c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 6680c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 6681c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 6682c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 6683c2f1a551SMeelap Shah */ 6684c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 6685c2f1a551SMeelap Shah } 6686c2f1a551SMeelap Shah 6687d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 66888daae4dcSStanislav Kinsbursky { 66898daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 66908daae4dcSStanislav Kinsbursky int i; 66918daae4dcSStanislav Kinsbursky 66928daae4dcSStanislav Kinsbursky nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * 66938daae4dcSStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 66948daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 6695382a62e7SStanislav Kinsbursky goto err; 66960a7ec377SStanislav Kinsbursky nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * 66970a7ec377SStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 66980a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 66990a7ec377SStanislav Kinsbursky goto err_unconf_id; 67001872de0eSStanislav Kinsbursky nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * 67011872de0eSStanislav Kinsbursky SESSION_HASH_SIZE, GFP_KERNEL); 67021872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 67031872de0eSStanislav Kinsbursky goto err_sessionid; 67048daae4dcSStanislav Kinsbursky 6705382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 67068daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 67070a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 6708382a62e7SStanislav Kinsbursky } 67091872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 67101872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 6711382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 6712a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 67135ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 671473758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 6715e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 6716c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 67178daae4dcSStanislav Kinsbursky 671809121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 6719d85ed443SStanislav Kinsbursky get_net(net); 672009121281SStanislav Kinsbursky 67218daae4dcSStanislav Kinsbursky return 0; 6722382a62e7SStanislav Kinsbursky 67231872de0eSStanislav Kinsbursky err_sessionid: 67249b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 67250a7ec377SStanislav Kinsbursky err_unconf_id: 67260a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 6727382a62e7SStanislav Kinsbursky err: 6728382a62e7SStanislav Kinsbursky return -ENOMEM; 67298daae4dcSStanislav Kinsbursky } 67308daae4dcSStanislav Kinsbursky 67318daae4dcSStanislav Kinsbursky static void 67324dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 67338daae4dcSStanislav Kinsbursky { 67348daae4dcSStanislav Kinsbursky int i; 67358daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 67368daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 67378daae4dcSStanislav Kinsbursky 67388daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 67398daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 67408daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 67418daae4dcSStanislav Kinsbursky destroy_client(clp); 67428daae4dcSStanislav Kinsbursky } 67438daae4dcSStanislav Kinsbursky } 6744a99454aaSStanislav Kinsbursky 67452b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 67462b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 67472b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 6748a99454aaSStanislav Kinsbursky destroy_client(clp); 6749a99454aaSStanislav Kinsbursky } 67502b905635SKinglong Mee } 6751a99454aaSStanislav Kinsbursky 67521872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 67530a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 67548daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 67554dce0ac9SStanislav Kinsbursky put_net(net); 67568daae4dcSStanislav Kinsbursky } 67578daae4dcSStanislav Kinsbursky 6758f252bc68SStanislav Kinsbursky int 6759d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 6760ac4d8ff2SNeilBrown { 67615e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 6762b5a1a81eSJ. Bruce Fields int ret; 6763b5a1a81eSJ. Bruce Fields 6764d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 67658daae4dcSStanislav Kinsbursky if (ret) 67668daae4dcSStanislav Kinsbursky return ret; 67672c142baaSStanislav Kinsbursky nn->boot_time = get_seconds(); 6768a51c84edSStanislav Kinsbursky nn->grace_ended = false; 6769c87fb4a3SJ. Bruce Fields nn->nfsd4_manager.block_opens = true; 6770d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 6771d4318acdSJeff Layton nfsd4_client_tracking_init(net); 6772d85ed443SStanislav Kinsbursky printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", 67735284b44eSStanislav Kinsbursky nn->nfsd4_grace, net); 67745284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 6775d85ed443SStanislav Kinsbursky return 0; 6776a6d6b781SJeff Layton } 6777d85ed443SStanislav Kinsbursky 6778d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 6779d85ed443SStanislav Kinsbursky 6780d85ed443SStanislav Kinsbursky int 6781d85ed443SStanislav Kinsbursky nfs4_state_start(void) 6782d85ed443SStanislav Kinsbursky { 6783d85ed443SStanislav Kinsbursky int ret; 6784d85ed443SStanislav Kinsbursky 6785d85ed443SStanislav Kinsbursky ret = set_callback_cred(); 6786d85ed443SStanislav Kinsbursky if (ret) 6787d85ed443SStanislav Kinsbursky return -ENOMEM; 678851a54568SJeff Layton laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 6789a6d6b781SJeff Layton if (laundry_wq == NULL) { 6790a6d6b781SJeff Layton ret = -ENOMEM; 6791a6d6b781SJeff Layton goto out_recovery; 6792a6d6b781SJeff Layton } 6793b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 6794b5a1a81eSJ. Bruce Fields if (ret) 6795b5a1a81eSJ. Bruce Fields goto out_free_laundry; 679609121281SStanislav Kinsbursky 6797c2f1a551SMeelap Shah set_max_delegations(); 6798d85ed443SStanislav Kinsbursky 6799b5a1a81eSJ. Bruce Fields return 0; 6800d85ed443SStanislav Kinsbursky 6801b5a1a81eSJ. Bruce Fields out_free_laundry: 6802b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 6803a6d6b781SJeff Layton out_recovery: 6804b5a1a81eSJ. Bruce Fields return ret; 68051da177e4SLinus Torvalds } 68061da177e4SLinus Torvalds 6807f252bc68SStanislav Kinsbursky void 68084dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 68091da177e4SLinus Torvalds { 68101da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 68111da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 68124dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 68131da177e4SLinus Torvalds 68144dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 68154dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 6816ac55fdc4SJeff Layton 68171da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 6818cdc97505SBenny Halevy spin_lock(&state_lock); 6819e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 68201da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 68213fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 682242690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 68231da177e4SLinus Torvalds } 6824cdc97505SBenny Halevy spin_unlock(&state_lock); 68251da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 68261da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 682742690676SJeff Layton list_del_init(&dp->dl_recall_lru); 68288287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 6829afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 68306011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 68311da177e4SLinus Torvalds } 68321da177e4SLinus Torvalds 68333320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 68344dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 68351da177e4SLinus Torvalds } 68361da177e4SLinus Torvalds 68371da177e4SLinus Torvalds void 68381da177e4SLinus Torvalds nfs4_state_shutdown(void) 68391da177e4SLinus Torvalds { 68405e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 6841c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 68421da177e4SLinus Torvalds } 68438b70484cSTigran Mkrtchyan 68448b70484cSTigran Mkrtchyan static void 68458b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 68468b70484cSTigran Mkrtchyan { 684737c593c5STigran Mkrtchyan if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) 684837c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 68498b70484cSTigran Mkrtchyan } 68508b70484cSTigran Mkrtchyan 68518b70484cSTigran Mkrtchyan static void 68528b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 68538b70484cSTigran Mkrtchyan { 685437c593c5STigran Mkrtchyan if (cstate->minorversion) { 685537c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 685637c593c5STigran Mkrtchyan SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 685737c593c5STigran Mkrtchyan } 685837c593c5STigran Mkrtchyan } 685937c593c5STigran Mkrtchyan 686037c593c5STigran Mkrtchyan void 686137c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 686237c593c5STigran Mkrtchyan { 686337c593c5STigran Mkrtchyan CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 68648b70484cSTigran Mkrtchyan } 68658b70484cSTigran Mkrtchyan 686662cd4a59STigran Mkrtchyan /* 686762cd4a59STigran Mkrtchyan * functions to set current state id 686862cd4a59STigran Mkrtchyan */ 68698b70484cSTigran Mkrtchyan void 68709428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 68719428fe1aSTigran Mkrtchyan { 68729428fe1aSTigran Mkrtchyan put_stateid(cstate, &odp->od_stateid); 68739428fe1aSTigran Mkrtchyan } 68749428fe1aSTigran Mkrtchyan 68759428fe1aSTigran Mkrtchyan void 68768b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open) 68778b70484cSTigran Mkrtchyan { 68788b70484cSTigran Mkrtchyan put_stateid(cstate, &open->op_stateid); 68798b70484cSTigran Mkrtchyan } 68808b70484cSTigran Mkrtchyan 68818b70484cSTigran Mkrtchyan void 688262cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 688362cd4a59STigran Mkrtchyan { 688462cd4a59STigran Mkrtchyan put_stateid(cstate, &close->cl_stateid); 688562cd4a59STigran Mkrtchyan } 688662cd4a59STigran Mkrtchyan 688762cd4a59STigran Mkrtchyan void 688862cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock) 688962cd4a59STigran Mkrtchyan { 689062cd4a59STigran Mkrtchyan put_stateid(cstate, &lock->lk_resp_stateid); 689162cd4a59STigran Mkrtchyan } 689262cd4a59STigran Mkrtchyan 689362cd4a59STigran Mkrtchyan /* 689462cd4a59STigran Mkrtchyan * functions to consume current state id 689562cd4a59STigran Mkrtchyan */ 68961e97b519STigran Mkrtchyan 68971e97b519STigran Mkrtchyan void 68989428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 68999428fe1aSTigran Mkrtchyan { 69009428fe1aSTigran Mkrtchyan get_stateid(cstate, &odp->od_stateid); 69019428fe1aSTigran Mkrtchyan } 69029428fe1aSTigran Mkrtchyan 69039428fe1aSTigran Mkrtchyan void 69049428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp) 69059428fe1aSTigran Mkrtchyan { 69069428fe1aSTigran Mkrtchyan get_stateid(cstate, &drp->dr_stateid); 69079428fe1aSTigran Mkrtchyan } 69089428fe1aSTigran Mkrtchyan 69099428fe1aSTigran Mkrtchyan void 69101e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp) 69111e97b519STigran Mkrtchyan { 69121e97b519STigran Mkrtchyan get_stateid(cstate, &fsp->fr_stateid); 69131e97b519STigran Mkrtchyan } 69141e97b519STigran Mkrtchyan 69151e97b519STigran Mkrtchyan void 69161e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) 69171e97b519STigran Mkrtchyan { 69181e97b519STigran Mkrtchyan get_stateid(cstate, &setattr->sa_stateid); 69191e97b519STigran Mkrtchyan } 69201e97b519STigran Mkrtchyan 692162cd4a59STigran Mkrtchyan void 69228b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 69238b70484cSTigran Mkrtchyan { 69248b70484cSTigran Mkrtchyan get_stateid(cstate, &close->cl_stateid); 69258b70484cSTigran Mkrtchyan } 69268b70484cSTigran Mkrtchyan 69278b70484cSTigran Mkrtchyan void 692862cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku) 69298b70484cSTigran Mkrtchyan { 693062cd4a59STigran Mkrtchyan get_stateid(cstate, &locku->lu_stateid); 69318b70484cSTigran Mkrtchyan } 693230813e27STigran Mkrtchyan 693330813e27STigran Mkrtchyan void 693430813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read) 693530813e27STigran Mkrtchyan { 693630813e27STigran Mkrtchyan get_stateid(cstate, &read->rd_stateid); 693730813e27STigran Mkrtchyan } 693830813e27STigran Mkrtchyan 693930813e27STigran Mkrtchyan void 694030813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write) 694130813e27STigran Mkrtchyan { 694230813e27STigran Mkrtchyan get_stateid(cstate, &write->wr_stateid); 694330813e27STigran Mkrtchyan } 6944