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 1010162ac2bSChristoph Hellwig static 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); 5783abdb607SJ. Bruce Fields 579996e0938SJ. Bruce Fields /* 5803abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 5813abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 5823abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 5833abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 5843abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 5853abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 5863abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 587996e0938SJ. Bruce Fields */ 5883abdb607SJ. Bruce Fields return stid; 5893abdb607SJ. Bruce Fields out_free: 5902c44a234SWei Yongjun kmem_cache_free(slab, stid); 5913abdb607SJ. Bruce Fields return NULL; 5922a74aba7SJ. Bruce Fields } 5932a74aba7SJ. Bruce Fields 594b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 5954cdc951bSJ. Bruce Fields { 5966011695dSTrond Myklebust struct nfs4_stid *stid; 5976011695dSTrond Myklebust struct nfs4_ol_stateid *stp; 5986011695dSTrond Myklebust 5996011695dSTrond Myklebust stid = nfs4_alloc_stid(clp, stateid_slab); 6006011695dSTrond Myklebust if (!stid) 6016011695dSTrond Myklebust return NULL; 6026011695dSTrond Myklebust 6036011695dSTrond Myklebust stp = openlockstateid(stid); 6046011695dSTrond Myklebust stp->st_stid.sc_free = nfs4_free_ol_stateid; 6056011695dSTrond Myklebust return stp; 6066011695dSTrond Myklebust } 6076011695dSTrond Myklebust 6086011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 6096011695dSTrond Myklebust { 6106011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 6116011695dSTrond Myklebust atomic_long_dec(&num_delegations); 6124cdc951bSJ. Bruce Fields } 6134cdc951bSJ. Bruce Fields 6146282cd56SNeilBrown /* 6156282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 6166282cd56SNeilBrown * out again straight away. 6176282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 6186282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 6196282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 6206282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 6216282cd56SNeilBrown * filter. 6226282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 6236282cd56SNeilBrown * unless both are empty of course. 6246282cd56SNeilBrown * 6256282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 6266282cd56SNeilBrown * low 3 bytes as hash-table indices. 6276282cd56SNeilBrown * 628f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 6296282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 6306282cd56SNeilBrown * except when swapping the two filters. 6316282cd56SNeilBrown */ 632f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 6336282cd56SNeilBrown static struct bloom_pair { 6346282cd56SNeilBrown int entries, old_entries; 6356282cd56SNeilBrown time_t swap_time; 6366282cd56SNeilBrown int new; /* index into 'set' */ 6376282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 6386282cd56SNeilBrown } blocked_delegations; 6396282cd56SNeilBrown 6406282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 6416282cd56SNeilBrown { 6426282cd56SNeilBrown u32 hash; 6436282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 6446282cd56SNeilBrown 6456282cd56SNeilBrown if (bd->entries == 0) 6466282cd56SNeilBrown return 0; 6476282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 648f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 6496282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 6506282cd56SNeilBrown bd->entries -= bd->old_entries; 6516282cd56SNeilBrown bd->old_entries = bd->entries; 6526282cd56SNeilBrown memset(bd->set[bd->new], 0, 6536282cd56SNeilBrown sizeof(bd->set[0])); 6546282cd56SNeilBrown bd->new = 1-bd->new; 6556282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 6566282cd56SNeilBrown } 657f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 6586282cd56SNeilBrown } 65987545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 6606282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 6616282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 6626282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 6636282cd56SNeilBrown return 1; 6646282cd56SNeilBrown 6656282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 6666282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 6676282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 6686282cd56SNeilBrown return 1; 6696282cd56SNeilBrown 6706282cd56SNeilBrown return 0; 6716282cd56SNeilBrown } 6726282cd56SNeilBrown 6736282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 6746282cd56SNeilBrown { 6756282cd56SNeilBrown u32 hash; 6766282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 6776282cd56SNeilBrown 67887545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 6796282cd56SNeilBrown 680f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 6816282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 6826282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 6836282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 6846282cd56SNeilBrown if (bd->entries == 0) 6856282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 6866282cd56SNeilBrown bd->entries += 1; 687f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 6886282cd56SNeilBrown } 6896282cd56SNeilBrown 6901da177e4SLinus Torvalds static struct nfs4_delegation * 6918287f009SSachin Bhamare alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh, 6928287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 6931da177e4SLinus Torvalds { 6941da177e4SLinus Torvalds struct nfs4_delegation *dp; 69502a3508dSTrond Myklebust long n; 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 69802a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 69902a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 70002a3508dSTrond Myklebust goto out_dec; 7016282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 70202a3508dSTrond Myklebust goto out_dec; 703996e0938SJ. Bruce Fields dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); 7045b2d21c1SNeilBrown if (dp == NULL) 70502a3508dSTrond Myklebust goto out_dec; 7066011695dSTrond Myklebust 7076011695dSTrond Myklebust dp->dl_stid.sc_free = nfs4_free_deleg; 7082a74aba7SJ. Bruce Fields /* 7092a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 7106136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 7116136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 7122a74aba7SJ. Bruce Fields */ 7132a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 714ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 715ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 7161da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 7178287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 7188287f009SSachin Bhamare get_clnt_odstate(odstate); 71999c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 720f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 721f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 7220162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 7231da177e4SLinus Torvalds return dp; 72402a3508dSTrond Myklebust out_dec: 72502a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 72602a3508dSTrond Myklebust return NULL; 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds void 7306011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 7311da177e4SLinus Torvalds { 73211b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 7336011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 7346011695dSTrond Myklebust 7354770d722SJeff Layton might_lock(&clp->cl_lock); 7364770d722SJeff Layton 737b401be22SJeff Layton if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 738b401be22SJeff Layton wake_up_all(&close_wq); 7396011695dSTrond Myklebust return; 740b401be22SJeff Layton } 7416011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 7424770d722SJeff Layton spin_unlock(&clp->cl_lock); 7436011695dSTrond Myklebust s->sc_free(s); 74411b9164aSTrond Myklebust if (fp) 74511b9164aSTrond Myklebust put_nfs4_file(fp); 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds 748acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp) 7491da177e4SLinus Torvalds { 7506bcc034eSJeff Layton struct file *filp = NULL; 751417c6629SJeff Layton 7526bcc034eSJeff Layton spin_lock(&fp->fi_lock); 75367db1034SJeff Layton if (fp->fi_deleg_file && --fp->fi_delegees == 0) 7546bcc034eSJeff Layton swap(filp, fp->fi_deleg_file); 7556bcc034eSJeff Layton spin_unlock(&fp->fi_lock); 7566bcc034eSJeff Layton 7576bcc034eSJeff Layton if (filp) { 7582ab99ee1SChristoph Hellwig vfs_setlease(filp, F_UNLCK, NULL, (void **)&fp); 7596bcc034eSJeff Layton fput(filp); 760acfdf5c3SJ. Bruce Fields } 7611da177e4SLinus Torvalds } 7621da177e4SLinus Torvalds 763cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 7646136d2b4SJ. Bruce Fields { 7653abdb607SJ. Bruce Fields s->sc_type = 0; 7666136d2b4SJ. Bruce Fields } 7676136d2b4SJ. Bruce Fields 768931ee56cSBenny Halevy static void 769931ee56cSBenny Halevy hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 770931ee56cSBenny Halevy { 771cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 772417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 773931ee56cSBenny Halevy 77467cb1279STrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 7753fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 776931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 777931ee56cSBenny Halevy list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); 778931ee56cSBenny Halevy } 779931ee56cSBenny Halevy 7801da177e4SLinus Torvalds static void 78142690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 7821da177e4SLinus Torvalds { 78311b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 78402e1215fSJeff Layton 78542690676SJeff Layton lockdep_assert_held(&state_lock); 78642690676SJeff Layton 787b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 788d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 789d55a166cSJeff Layton ++dp->dl_time; 790417c6629SJeff Layton spin_lock(&fp->fi_lock); 791931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 7921da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 79302e1215fSJeff Layton list_del_init(&dp->dl_perfile); 79402e1215fSJeff Layton spin_unlock(&fp->fi_lock); 795cbf7a75bSJ. Bruce Fields } 7963bd64a5bSJ. Bruce Fields 7973bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 7983bd64a5bSJ. Bruce Fields { 79942690676SJeff Layton spin_lock(&state_lock); 80042690676SJeff Layton unhash_delegation_locked(dp); 80142690676SJeff Layton spin_unlock(&state_lock); 8028287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 803afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 8046011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 8053bd64a5bSJ. Bruce Fields } 8063bd64a5bSJ. Bruce Fields 8073bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 8083bd64a5bSJ. Bruce Fields { 8093bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 8103bd64a5bSJ. Bruce Fields 8112d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 8122d4a532dSJeff Layton 8138287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 814afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 815afbda402SJeff Layton 8163bd64a5bSJ. Bruce Fields if (clp->cl_minorversion == 0) 8176011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 8183bd64a5bSJ. Bruce Fields else { 8193bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 8202d4a532dSJeff Layton spin_lock(&clp->cl_lock); 8212d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 8222d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 8233bd64a5bSJ. Bruce Fields } 8243bd64a5bSJ. Bruce Fields } 8253bd64a5bSJ. Bruce Fields 8261da177e4SLinus Torvalds /* 8271da177e4SLinus Torvalds * SETCLIENTID state 8281da177e4SLinus Torvalds */ 8291da177e4SLinus Torvalds 830ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 831ddc04c41SJ. Bruce Fields { 832ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 833ddc04c41SJ. Bruce Fields } 834ddc04c41SJ. Bruce Fields 835ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 836ddc04c41SJ. Bruce Fields { 837ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 838ddc04c41SJ. Bruce Fields } 839ddc04c41SJ. Bruce Fields 8401da177e4SLinus Torvalds /* 841f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 842f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 843f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 844f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 845f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 846f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 847f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 848f9d7562fSJ. Bruce Fields * 849f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 850f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 851f9d7562fSJ. Bruce Fields * 852f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 853f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 854f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 855f9d7562fSJ. Bruce Fields * 856f9d7562fSJ. Bruce Fields * which we should reject. 857f9d7562fSJ. Bruce Fields */ 8585ae037e5SJeff Layton static unsigned int 8595ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 860f9d7562fSJ. Bruce Fields int i; 8615ae037e5SJeff Layton unsigned int access = 0; 862f9d7562fSJ. Bruce Fields 863f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 864f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 8655ae037e5SJeff Layton access |= i; 866f9d7562fSJ. Bruce Fields } 8675ae037e5SJeff Layton return access; 868f9d7562fSJ. Bruce Fields } 869f9d7562fSJ. Bruce Fields 87082c5ff1bSJeff Layton /* set share access for a given stateid */ 87182c5ff1bSJeff Layton static inline void 87282c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 87382c5ff1bSJeff Layton { 874c11c591fSJeff Layton unsigned char mask = 1 << access; 875c11c591fSJeff Layton 876c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 877c11c591fSJeff Layton stp->st_access_bmap |= mask; 87882c5ff1bSJeff Layton } 87982c5ff1bSJeff Layton 88082c5ff1bSJeff Layton /* clear share access for a given stateid */ 88182c5ff1bSJeff Layton static inline void 88282c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 88382c5ff1bSJeff Layton { 884c11c591fSJeff Layton unsigned char mask = 1 << access; 885c11c591fSJeff Layton 886c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 887c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 88882c5ff1bSJeff Layton } 88982c5ff1bSJeff Layton 89082c5ff1bSJeff Layton /* test whether a given stateid has access */ 89182c5ff1bSJeff Layton static inline bool 89282c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 89382c5ff1bSJeff Layton { 894c11c591fSJeff Layton unsigned char mask = 1 << access; 895c11c591fSJeff Layton 896c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 89782c5ff1bSJeff Layton } 89882c5ff1bSJeff Layton 899ce0fc43cSJeff Layton /* set share deny for a given stateid */ 900ce0fc43cSJeff Layton static inline void 901c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 902ce0fc43cSJeff Layton { 903c11c591fSJeff Layton unsigned char mask = 1 << deny; 904c11c591fSJeff Layton 905c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 906c11c591fSJeff Layton stp->st_deny_bmap |= mask; 907ce0fc43cSJeff Layton } 908ce0fc43cSJeff Layton 909ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 910ce0fc43cSJeff Layton static inline void 911c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 912ce0fc43cSJeff Layton { 913c11c591fSJeff Layton unsigned char mask = 1 << deny; 914c11c591fSJeff Layton 915c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 916c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 917ce0fc43cSJeff Layton } 918ce0fc43cSJeff Layton 919ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 920ce0fc43cSJeff Layton static inline bool 921c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 922ce0fc43cSJeff Layton { 923c11c591fSJeff Layton unsigned char mask = 1 << deny; 924c11c591fSJeff Layton 925c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 926f9d7562fSJ. Bruce Fields } 927f9d7562fSJ. Bruce Fields 928f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 929f9d7562fSJ. Bruce Fields { 9308f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 931f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 932f9d7562fSJ. Bruce Fields return O_RDONLY; 933f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 934f9d7562fSJ. Bruce Fields return O_WRONLY; 935f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 936f9d7562fSJ. Bruce Fields return O_RDWR; 937f9d7562fSJ. Bruce Fields } 938063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 939063b0fb9SJ. Bruce Fields return O_RDONLY; 940f9d7562fSJ. Bruce Fields } 941f9d7562fSJ. Bruce Fields 942baeb4ff0SJeff Layton /* 943baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 944baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 945baeb4ff0SJeff Layton */ 946baeb4ff0SJeff Layton static void 947baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 948baeb4ff0SJeff Layton { 949baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 950baeb4ff0SJeff Layton 951baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 952baeb4ff0SJeff Layton fp->fi_share_deny = 0; 953baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 954baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 955baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 956baeb4ff0SJeff Layton } 957baeb4ff0SJeff Layton 958baeb4ff0SJeff Layton static void 959baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 960baeb4ff0SJeff Layton { 961baeb4ff0SJeff Layton int i; 962baeb4ff0SJeff Layton bool change = false; 963baeb4ff0SJeff Layton 964baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 965baeb4ff0SJeff Layton if ((i & deny) != i) { 966baeb4ff0SJeff Layton change = true; 967baeb4ff0SJeff Layton clear_deny(i, stp); 968baeb4ff0SJeff Layton } 969baeb4ff0SJeff Layton } 970baeb4ff0SJeff Layton 971baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 972baeb4ff0SJeff Layton if (change) 97311b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 974baeb4ff0SJeff Layton } 975baeb4ff0SJeff Layton 97682c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 97782c5ff1bSJeff Layton static void 97882c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 97982c5ff1bSJeff Layton { 98082c5ff1bSJeff Layton int i; 98111b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 982baeb4ff0SJeff Layton 983baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 984baeb4ff0SJeff Layton recalculate_deny_mode(fp); 98582c5ff1bSJeff Layton 98682c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 98782c5ff1bSJeff Layton if (test_access(i, stp)) 98811b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 98982c5ff1bSJeff Layton clear_access(i, stp); 99082c5ff1bSJeff Layton } 99182c5ff1bSJeff Layton } 99282c5ff1bSJeff Layton 993d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 994d50ffdedSKinglong Mee { 995d50ffdedSKinglong Mee kfree(sop->so_owner.data); 996d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 997d50ffdedSKinglong Mee } 998d50ffdedSKinglong Mee 9996b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 10006b180f0bSJeff Layton { 1001a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1002a819ecc1SJeff Layton 1003a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1004a819ecc1SJeff Layton 1005a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 10066b180f0bSJeff Layton return; 10078f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1008a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1009d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 10106b180f0bSJeff Layton } 10116b180f0bSJeff Layton 10124ae098d3SJeff Layton static void unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1013529d7b2aSJ. Bruce Fields { 101411b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 10151d31a253STrond Myklebust 10161c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 10171c755dc1SJeff Layton 10181d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1019529d7b2aSJ. Bruce Fields list_del(&stp->st_perfile); 10201d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1021529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1022529d7b2aSJ. Bruce Fields } 1023529d7b2aSJ. Bruce Fields 10246011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1025529d7b2aSJ. Bruce Fields { 10266011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 10274665e2baSJ. Bruce Fields 10288287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 10296011695dSTrond Myklebust release_all_access(stp); 1030d3134b10SJeff Layton if (stp->st_stateowner) 1031d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 10326011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1033529d7b2aSJ. Bruce Fields } 1034529d7b2aSJ. Bruce Fields 1035b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1036529d7b2aSJ. Bruce Fields { 1037b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1038b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1039529d7b2aSJ. Bruce Fields struct file *file; 1040529d7b2aSJ. Bruce Fields 1041b49e084dSJeff Layton file = find_any_file(stp->st_stid.sc_file); 1042b49e084dSJeff Layton if (file) 1043b49e084dSJeff Layton filp_close(file, (fl_owner_t)lo); 1044b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1045b49e084dSJeff Layton } 1046b49e084dSJeff Layton 10472c41beb0SJeff Layton /* 10482c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 10492c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 10502c41beb0SJeff Layton * reaplist for later destruction. 10512c41beb0SJeff Layton */ 10522c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 10532c41beb0SJeff Layton struct list_head *reaplist) 10542c41beb0SJeff Layton { 10552c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 10562c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 10572c41beb0SJeff Layton 10582c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 10592c41beb0SJeff Layton 10602c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 10612c41beb0SJeff Layton 10622c41beb0SJeff Layton if (!atomic_dec_and_test(&s->sc_count)) { 10632c41beb0SJeff Layton wake_up_all(&close_wq); 10642c41beb0SJeff Layton return; 10652c41beb0SJeff Layton } 10662c41beb0SJeff Layton 10672c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 10682c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 10692c41beb0SJeff Layton } 10702c41beb0SJeff Layton 10713c1c995cSJeff Layton static void unhash_lock_stateid(struct nfs4_ol_stateid *stp) 10723c1c995cSJeff Layton { 10733c1c995cSJeff Layton struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 10743c1c995cSJeff Layton 10753c1c995cSJeff Layton lockdep_assert_held(&oo->oo_owner.so_client->cl_lock); 10763c1c995cSJeff Layton 10773c1c995cSJeff Layton list_del_init(&stp->st_locks); 10784ae098d3SJeff Layton unhash_ol_stateid(stp); 1079cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 10803c1c995cSJeff Layton } 10813c1c995cSJeff Layton 10825adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1083b49e084dSJeff Layton { 10841c755dc1SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 10851c755dc1SJeff Layton 10861c755dc1SJeff Layton spin_lock(&oo->oo_owner.so_client->cl_lock); 10873c1c995cSJeff Layton unhash_lock_stateid(stp); 10881c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 10896011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1090529d7b2aSJ. Bruce Fields } 1091529d7b2aSJ. Bruce Fields 1092c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1093529d7b2aSJ. Bruce Fields { 1094d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1095c58c6610STrond Myklebust 1096d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1097c58c6610STrond Myklebust 10988f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 10998f4b54c5SJeff Layton } 11008f4b54c5SJeff Layton 11012c41beb0SJeff Layton /* 11022c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 11032c41beb0SJeff Layton * fully unhashed. 11042c41beb0SJeff Layton */ 11052c41beb0SJeff Layton static void 11062c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 11072c41beb0SJeff Layton { 11082c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1109fb94d766SKinglong Mee struct nfs4_file *fp; 11102c41beb0SJeff Layton 11112c41beb0SJeff Layton might_sleep(); 11122c41beb0SJeff Layton 11132c41beb0SJeff Layton while (!list_empty(reaplist)) { 11142c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 11152c41beb0SJeff Layton st_locks); 11162c41beb0SJeff Layton list_del(&stp->st_locks); 1117fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 11182c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1119fb94d766SKinglong Mee if (fp) 1120fb94d766SKinglong Mee put_nfs4_file(fp); 11212c41beb0SJeff Layton } 11222c41beb0SJeff Layton } 11232c41beb0SJeff Layton 1124fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo) 1125529d7b2aSJ. Bruce Fields { 1126d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 11273c1c995cSJeff Layton struct nfs4_ol_stateid *stp; 11283c1c995cSJeff Layton struct list_head reaplist; 11293c1c995cSJeff Layton 11303c1c995cSJeff Layton INIT_LIST_HEAD(&reaplist); 1131c58c6610STrond Myklebust 1132d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 1133c58c6610STrond Myklebust unhash_lockowner_locked(lo); 11343c1c995cSJeff Layton while (!list_empty(&lo->lo_owner.so_stateids)) { 11353c1c995cSJeff Layton stp = list_first_entry(&lo->lo_owner.so_stateids, 11363c1c995cSJeff Layton struct nfs4_ol_stateid, st_perstateowner); 11373c1c995cSJeff Layton unhash_lock_stateid(stp); 11382c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 11393c1c995cSJeff Layton } 1140d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 11412c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 11426b180f0bSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 1143529d7b2aSJ. Bruce Fields } 1144529d7b2aSJ. Bruce Fields 1145d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1146d83017f9SJeff Layton struct list_head *reaplist) 11473c87b9b7STrond Myklebust { 11483c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 11493c87b9b7STrond Myklebust 11503c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 11513c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 11523c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1153d83017f9SJeff Layton unhash_lock_stateid(stp); 1154d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1155529d7b2aSJ. Bruce Fields } 1156529d7b2aSJ. Bruce Fields } 1157529d7b2aSJ. Bruce Fields 1158d83017f9SJeff Layton static void unhash_open_stateid(struct nfs4_ol_stateid *stp, 1159d83017f9SJeff Layton struct list_head *reaplist) 11602283963fSJ. Bruce Fields { 11612c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 11622c41beb0SJeff Layton 11634ae098d3SJeff Layton unhash_ol_stateid(stp); 1164d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 116538c387b5SJ. Bruce Fields } 116638c387b5SJ. Bruce Fields 116738c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 116838c387b5SJ. Bruce Fields { 11692c41beb0SJeff Layton LIST_HEAD(reaplist); 11702c41beb0SJeff Layton 11712c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1172d83017f9SJeff Layton unhash_open_stateid(stp, &reaplist); 11732c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 11742c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 11752c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 11762283963fSJ. Bruce Fields } 11772283963fSJ. Bruce Fields 11787ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1179f1d110caSJ. Bruce Fields { 1180d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 11817ffb5880STrond Myklebust 1182d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 11837ffb5880STrond Myklebust 11848f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 11858f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1186f1d110caSJ. Bruce Fields } 1187f1d110caSJ. Bruce Fields 1188f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1189f7a4d872SJ. Bruce Fields { 1190217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1191217526e7SJeff Layton nfsd_net_id); 1192217526e7SJeff Layton struct nfs4_ol_stateid *s; 1193f7a4d872SJ. Bruce Fields 1194217526e7SJeff Layton spin_lock(&nn->client_lock); 1195217526e7SJeff Layton s = oo->oo_last_closed_stid; 1196f7a4d872SJ. Bruce Fields if (s) { 1197d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1198f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1199f7a4d872SJ. Bruce Fields } 1200217526e7SJeff Layton spin_unlock(&nn->client_lock); 1201217526e7SJeff Layton if (s) 1202217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1203f7a4d872SJ. Bruce Fields } 1204f7a4d872SJ. Bruce Fields 12052c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 12068f4b54c5SJeff Layton { 12078f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1208d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 12092c41beb0SJeff Layton struct list_head reaplist; 12107ffb5880STrond Myklebust 12112c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 12127ffb5880STrond Myklebust 1213d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 12147ffb5880STrond Myklebust unhash_openowner_locked(oo); 12152c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 12162c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 12172c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1218d83017f9SJeff Layton unhash_open_stateid(stp, &reaplist); 12192c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 12202c41beb0SJeff Layton } 1221d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 12222c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1223f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 12246b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1225f1d110caSJ. Bruce Fields } 1226f1d110caSJ. Bruce Fields 12275282fd72SMarc Eshel static inline int 12285282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 12295282fd72SMarc Eshel { 12305282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 12315282fd72SMarc Eshel 12325282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 12335282fd72SMarc Eshel } 12345282fd72SMarc Eshel 1235135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 12365282fd72SMarc Eshel static inline void 12375282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 12385282fd72SMarc Eshel { 12395282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 12405282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 12415282fd72SMarc Eshel } 12428f199b82STrond Myklebust #else 12438f199b82STrond Myklebust static inline void 12448f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 12458f199b82STrond Myklebust { 12468f199b82STrond Myklebust } 12478f199b82STrond Myklebust #endif 12488f199b82STrond Myklebust 12499411b1d4SJ. Bruce Fields /* 12509411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 12519411b1d4SJ. Bruce Fields * won't be used for replay. 12529411b1d4SJ. Bruce Fields */ 12539411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 12549411b1d4SJ. Bruce Fields { 12559411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 12569411b1d4SJ. Bruce Fields 12579411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 12589411b1d4SJ. Bruce Fields return; 12599411b1d4SJ. Bruce Fields 12609411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 126158fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 12629411b1d4SJ. Bruce Fields return; 12639411b1d4SJ. Bruce Fields } 12649411b1d4SJ. Bruce Fields if (!so) 12659411b1d4SJ. Bruce Fields return; 12669411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 12679411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 12689411b1d4SJ. Bruce Fields so->so_seqid++; 12699411b1d4SJ. Bruce Fields return; 12709411b1d4SJ. Bruce Fields } 12715282fd72SMarc Eshel 1272ec6b5d7bSAndy Adamson static void 1273ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1274ec6b5d7bSAndy Adamson { 1275ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1276ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1277ec6b5d7bSAndy Adamson 1278ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1279ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1280ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1281ec6b5d7bSAndy Adamson sid->reserved = 0; 1282ec6b5d7bSAndy Adamson } 1283ec6b5d7bSAndy Adamson 1284ec6b5d7bSAndy Adamson /* 1285a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1286a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1287a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1288a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1289a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1290a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1291a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1292a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1293a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1294a649637cSAndy Adamson * for the SEQUENCE op response: 1295ec6b5d7bSAndy Adamson */ 1296a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1297a649637cSAndy Adamson 1298557ce264SAndy Adamson static void 1299557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1300557ce264SAndy Adamson { 1301557ce264SAndy Adamson int i; 1302557ce264SAndy Adamson 1303557ce264SAndy Adamson for (i = 0; i < ses->se_fchannel.maxreqs; i++) 1304557ce264SAndy Adamson kfree(ses->se_slots[i]); 1305557ce264SAndy Adamson } 1306557ce264SAndy Adamson 1307efe0cb6dSJ. Bruce Fields /* 1308efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1309efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1310efe0cb6dSJ. Bruce Fields */ 131155c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1312efe0cb6dSJ. Bruce Fields { 131355c760cfSJ. Bruce Fields u32 size; 1314efe0cb6dSJ. Bruce Fields 131555c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 131655c760cfSJ. Bruce Fields size = 0; 131755c760cfSJ. Bruce Fields else 131855c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 131955c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1320557ce264SAndy Adamson } 1321557ce264SAndy Adamson 13225b6feee9SJ. Bruce Fields /* 13235b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 13245b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 132542b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 13265b6feee9SJ. Bruce Fields */ 132755c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 13285b6feee9SJ. Bruce Fields { 132955c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 133055c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 13315b6feee9SJ. Bruce Fields int avail; 13325b6feee9SJ. Bruce Fields 13335b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 1334697ce9beSZhang Yanfei avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, 13355b6feee9SJ. Bruce Fields nfsd_drc_max_mem - nfsd_drc_mem_used); 13365b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 13375b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 13385b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 13395b6feee9SJ. Bruce Fields 13405b6feee9SJ. Bruce Fields return num; 13415b6feee9SJ. Bruce Fields } 13425b6feee9SJ. Bruce Fields 134355c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 13445b6feee9SJ. Bruce Fields { 134555c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 134655c760cfSJ. Bruce Fields 13475b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 134855c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 13495b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 13505b6feee9SJ. Bruce Fields } 13515b6feee9SJ. Bruce Fields 135260810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 135360810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 13545b6feee9SJ. Bruce Fields { 135560810e54SKinglong Mee int numslots = fattrs->maxreqs; 135660810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 13575b6feee9SJ. Bruce Fields struct nfsd4_session *new; 13585b6feee9SJ. Bruce Fields int mem, i; 1359ec6b5d7bSAndy Adamson 1360c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1361ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 13625b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1363ec6b5d7bSAndy Adamson 13645b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 13656c18ba9fSAlexandros Batsakis if (!new) 13665b6feee9SJ. Bruce Fields return NULL; 1367ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 13685b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 136955c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 13705b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1371ec6b5d7bSAndy Adamson goto out_free; 1372ec6b5d7bSAndy Adamson } 137360810e54SKinglong Mee 137460810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 137560810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 137660810e54SKinglong Mee 13775b6feee9SJ. Bruce Fields return new; 13785b6feee9SJ. Bruce Fields out_free: 13795b6feee9SJ. Bruce Fields while (i--) 13805b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 13815b6feee9SJ. Bruce Fields kfree(new); 13825b6feee9SJ. Bruce Fields return NULL; 13835b6feee9SJ. Bruce Fields } 13845b6feee9SJ. Bruce Fields 138519cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 138619cf5c02SJ. Bruce Fields { 138719cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 138819cf5c02SJ. Bruce Fields kfree(c); 138919cf5c02SJ. Bruce Fields } 139019cf5c02SJ. Bruce Fields 139119cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 139219cf5c02SJ. Bruce Fields { 139319cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 139419cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 139519cf5c02SJ. Bruce Fields 139619cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 139719cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 139819cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 139919cf5c02SJ. Bruce Fields free_conn(c); 140019cf5c02SJ. Bruce Fields } 1401eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 14022e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 140319cf5c02SJ. Bruce Fields } 140419cf5c02SJ. Bruce Fields 1405d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1406c7662518SJ. Bruce Fields { 1407c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1408c7662518SJ. Bruce Fields 1409c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1410c7662518SJ. Bruce Fields if (!conn) 1411db90681dSJ. Bruce Fields return NULL; 1412c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1413c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1414d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1415db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1416db90681dSJ. Bruce Fields return conn; 1417db90681dSJ. Bruce Fields } 1418db90681dSJ. Bruce Fields 1419328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1420328ead28SJ. Bruce Fields { 1421328ead28SJ. Bruce Fields conn->cn_session = ses; 1422328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1423328ead28SJ. Bruce Fields } 1424328ead28SJ. Bruce Fields 1425db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1426db90681dSJ. Bruce Fields { 1427db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1428c7662518SJ. Bruce Fields 1429c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1430328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1431c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1432db90681dSJ. Bruce Fields } 1433c7662518SJ. Bruce Fields 143421b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1435db90681dSJ. Bruce Fields { 143619cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 143721b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1438db90681dSJ. Bruce Fields } 1439db90681dSJ. Bruce Fields 1440e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1441db90681dSJ. Bruce Fields { 144221b75b01SJ. Bruce Fields int ret; 1443db90681dSJ. Bruce Fields 1444db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 144521b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 144621b75b01SJ. Bruce Fields if (ret) 144721b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 144821b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 144957a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 145057a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1451c7662518SJ. Bruce Fields } 1452c7662518SJ. Bruce Fields 1453e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 14541d1bc8f2SJ. Bruce Fields { 14551d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 14561d1bc8f2SJ. Bruce Fields 1457e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 14581d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1459e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 14601d1bc8f2SJ. Bruce Fields } 14611d1bc8f2SJ. Bruce Fields 14621d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 146319cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1464c7662518SJ. Bruce Fields { 146519cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 146619cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 146719cf5c02SJ. Bruce Fields 146819cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 146919cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 147019cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 147119cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 147219cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 147319cf5c02SJ. Bruce Fields 147419cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 147519cf5c02SJ. Bruce Fields free_conn(c); 147619cf5c02SJ. Bruce Fields 147719cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 147819cf5c02SJ. Bruce Fields } 147919cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1480c7662518SJ. Bruce Fields } 1481c7662518SJ. Bruce Fields 14821377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 14831377b69eSJ. Bruce Fields { 14841377b69eSJ. Bruce Fields free_session_slots(ses); 14851377b69eSJ. Bruce Fields kfree(ses); 14861377b69eSJ. Bruce Fields } 14871377b69eSJ. Bruce Fields 148866b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1489508dc6e1SBenny Halevy { 1490c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 149155c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1492c7662518SJ. Bruce Fields __free_session(ses); 1493a827bcb2SJ. Bruce Fields } 1494ec6b5d7bSAndy Adamson 1495135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1496a827bcb2SJ. Bruce Fields { 1497a827bcb2SJ. Bruce Fields int idx; 14981872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1499a827bcb2SJ. Bruce Fields 1500ec6b5d7bSAndy Adamson new->se_client = clp; 1501ec6b5d7bSAndy Adamson gen_sessionid(new); 1502ec6b5d7bSAndy Adamson 1503c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1504c7662518SJ. Bruce Fields 1505ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1506ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 15078b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1508c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 150966b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 15105b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 15111872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 15124c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1513ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 15144c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 151560810e54SKinglong Mee 1516b0d2e42cSChuck Lever { 1517edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1518dcbeaa68SJ. Bruce Fields /* 1519dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1520dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1521dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1522dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1523dcbeaa68SJ. Bruce Fields * future: 1524dcbeaa68SJ. Bruce Fields */ 1525edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1526edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1527edd76786SJ. Bruce Fields } 1528ec6b5d7bSAndy Adamson } 1529ec6b5d7bSAndy Adamson 15309089f1b4SBenny Halevy /* caller must hold client_lock */ 15315282fd72SMarc Eshel static struct nfsd4_session * 1532d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 15335282fd72SMarc Eshel { 15345282fd72SMarc Eshel struct nfsd4_session *elem; 15355282fd72SMarc Eshel int idx; 15361872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 15375282fd72SMarc Eshel 15380a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 15390a880a28STrond Myklebust 15405282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 15415282fd72SMarc Eshel idx = hash_sessionid(sessionid); 15425282fd72SMarc Eshel /* Search in the appropriate list */ 15431872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 15445282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 15455282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 15465282fd72SMarc Eshel return elem; 15475282fd72SMarc Eshel } 15485282fd72SMarc Eshel } 15495282fd72SMarc Eshel 15505282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 15515282fd72SMarc Eshel return NULL; 15525282fd72SMarc Eshel } 15535282fd72SMarc Eshel 1554d4e19e70STrond Myklebust static struct nfsd4_session * 1555d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1556d4e19e70STrond Myklebust __be32 *ret) 1557d4e19e70STrond Myklebust { 1558d4e19e70STrond Myklebust struct nfsd4_session *session; 1559d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1560d4e19e70STrond Myklebust 1561d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1562d4e19e70STrond Myklebust if (!session) 1563d4e19e70STrond Myklebust goto out; 1564d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1565d4e19e70STrond Myklebust if (status) 1566d4e19e70STrond Myklebust session = NULL; 1567d4e19e70STrond Myklebust out: 1568d4e19e70STrond Myklebust *ret = status; 1569d4e19e70STrond Myklebust return session; 1570d4e19e70STrond Myklebust } 1571d4e19e70STrond Myklebust 15729089f1b4SBenny Halevy /* caller must hold client_lock */ 15737116ed6bSAndy Adamson static void 15745282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 15757116ed6bSAndy Adamson { 15760a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 15770a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 15780a880a28STrond Myklebust 15790a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 15800a880a28STrond Myklebust 15817116ed6bSAndy Adamson list_del(&ses->se_hash); 15824c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 15837116ed6bSAndy Adamson list_del(&ses->se_perclnt); 15844c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 15855282fd72SMarc Eshel } 15865282fd72SMarc Eshel 15871da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 15881da177e4SLinus Torvalds static int 15892c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 15901da177e4SLinus Torvalds { 1591bbc7f33aSJ. Bruce Fields /* 1592bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 1593bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 1594bbc7f33aSJ. Bruce Fields * a safe assumption: 1595bbc7f33aSJ. Bruce Fields */ 1596bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 15971da177e4SLinus Torvalds return 0; 159860adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 15992c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 16001da177e4SLinus Torvalds return 1; 16011da177e4SLinus Torvalds } 16021da177e4SLinus Torvalds 16031da177e4SLinus Torvalds /* 16041da177e4SLinus Torvalds * XXX Should we use a slab cache ? 16051da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 16061da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 16071da177e4SLinus Torvalds */ 160835bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 16091da177e4SLinus Torvalds { 16101da177e4SLinus Torvalds struct nfs4_client *clp; 1611d4f0489fSTrond Myklebust int i; 16121da177e4SLinus Torvalds 161335bba9a3SJ. Bruce Fields clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); 161435bba9a3SJ. Bruce Fields if (clp == NULL) 161535bba9a3SJ. Bruce Fields return NULL; 161667114fe6SThomas Meyer clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); 1617d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1618d4f0489fSTrond Myklebust goto err_no_name; 1619d4f0489fSTrond Myklebust clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * 1620d4f0489fSTrond Myklebust OWNER_HASH_SIZE, GFP_KERNEL); 1621d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1622d4f0489fSTrond Myklebust goto err_no_hashtbl; 1623d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1624d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 16251da177e4SLinus Torvalds clp->cl_name.len = name.len; 16265694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 16275694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 16285694c93eSTrond Myklebust atomic_set(&clp->cl_refcount, 0); 16295694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 16305694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 16315694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 16325694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 16335694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 16345694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 16359cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 16369cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 16379cf514ccSChristoph Hellwig #endif 16385694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 16395694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 16401da177e4SLinus Torvalds return clp; 1641d4f0489fSTrond Myklebust err_no_hashtbl: 1642d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1643d4f0489fSTrond Myklebust err_no_name: 1644d4f0489fSTrond Myklebust kfree(clp); 1645d4f0489fSTrond Myklebust return NULL; 16461da177e4SLinus Torvalds } 16471da177e4SLinus Torvalds 16484dd86e15STrond Myklebust static void 16491da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 16501da177e4SLinus Torvalds { 1651792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1652792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1653792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1654792c95ddSJ. Bruce Fields se_perclnt); 1655792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 165666b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 165766b2b9b2SJ. Bruce Fields free_session(ses); 1658792c95ddSJ. Bruce Fields } 16594cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 166003a4e1f6SJ. Bruce Fields free_svc_cred(&clp->cl_cred); 1661d4f0489fSTrond Myklebust kfree(clp->cl_ownerstr_hashtbl); 16621da177e4SLinus Torvalds kfree(clp->cl_name.data); 16632d32b29aSmajianpeng idr_destroy(&clp->cl_stateids); 16641da177e4SLinus Torvalds kfree(clp); 16651da177e4SLinus Torvalds } 16661da177e4SLinus Torvalds 166784d38ac9SBenny Halevy /* must be called under the client_lock */ 16684beb345bSTrond Myklebust static void 166984d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 167084d38ac9SBenny Halevy { 16714beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1672792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1673792c95ddSJ. Bruce Fields 16740a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 16750a880a28STrond Myklebust 16764beb345bSTrond Myklebust /* Mark the client as expired! */ 16774beb345bSTrond Myklebust clp->cl_time = 0; 16784beb345bSTrond Myklebust /* Make it invisible */ 16794beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 16804beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 16814beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 16824beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 16834beb345bSTrond Myklebust else 16844beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 16854beb345bSTrond Myklebust } 16864beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 16874c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1688792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1689792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 16904c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 169184d38ac9SBenny Halevy } 169284d38ac9SBenny Halevy 16931da177e4SLinus Torvalds static void 16944beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 16954beb345bSTrond Myklebust { 16964beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 16974beb345bSTrond Myklebust 16984beb345bSTrond Myklebust spin_lock(&nn->client_lock); 16994beb345bSTrond Myklebust unhash_client_locked(clp); 17004beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 17014beb345bSTrond Myklebust } 17024beb345bSTrond Myklebust 170397403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 170497403d95SJeff Layton { 170597403d95SJeff Layton if (atomic_read(&clp->cl_refcount)) 170697403d95SJeff Layton return nfserr_jukebox; 170797403d95SJeff Layton unhash_client_locked(clp); 170897403d95SJeff Layton return nfs_ok; 170997403d95SJeff Layton } 171097403d95SJeff Layton 17114beb345bSTrond Myklebust static void 17124beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 17131da177e4SLinus Torvalds { 1714fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 17151da177e4SLinus Torvalds struct nfs4_delegation *dp; 17161da177e4SLinus Torvalds struct list_head reaplist; 17171da177e4SLinus Torvalds 17181da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 1719cdc97505SBenny Halevy spin_lock(&state_lock); 1720ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 1721ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 172242690676SJeff Layton unhash_delegation_locked(dp); 172342690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 17241da177e4SLinus Torvalds } 1725cdc97505SBenny Halevy spin_unlock(&state_lock); 17261da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 17271da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 172842690676SJeff Layton list_del_init(&dp->dl_recall_lru); 17298287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 1730afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 17316011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 17321da177e4SLinus Torvalds } 17332d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 1734c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 17352d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 17366011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 1737956c4feeSBenny Halevy } 1738ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 1739fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1740b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 1741fe0750e5SJ. Bruce Fields release_openowner(oo); 17421da177e4SLinus Torvalds } 17439cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 17446ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 17452bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 17462bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1747b12a05cbSJ. Bruce Fields free_client(clp); 17481da177e4SLinus Torvalds } 17491da177e4SLinus Torvalds 17504beb345bSTrond Myklebust static void 17514beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 17524beb345bSTrond Myklebust { 17534beb345bSTrond Myklebust unhash_client(clp); 17544beb345bSTrond Myklebust __destroy_client(clp); 17554beb345bSTrond Myklebust } 17564beb345bSTrond Myklebust 17570d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 17580d22f68fSJ. Bruce Fields { 17594beb345bSTrond Myklebust unhash_client(clp); 17600d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 17614beb345bSTrond Myklebust __destroy_client(clp); 17620d22f68fSJ. Bruce Fields } 17630d22f68fSJ. Bruce Fields 176435bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 176535bba9a3SJ. Bruce Fields { 176635bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 176735bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 17681da177e4SLinus Torvalds } 17691da177e4SLinus Torvalds 177035bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 177135bba9a3SJ. Bruce Fields { 17721da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 17731da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 17741da177e4SLinus Torvalds } 17751da177e4SLinus Torvalds 177603a4e1f6SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 177735bba9a3SJ. Bruce Fields { 177803a4e1f6SJ. Bruce Fields if (source->cr_principal) { 177903a4e1f6SJ. Bruce Fields target->cr_principal = 178003a4e1f6SJ. Bruce Fields kstrdup(source->cr_principal, GFP_KERNEL); 178103a4e1f6SJ. Bruce Fields if (target->cr_principal == NULL) 178203a4e1f6SJ. Bruce Fields return -ENOMEM; 178303a4e1f6SJ. Bruce Fields } else 178403a4e1f6SJ. Bruce Fields target->cr_principal = NULL; 1785d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 17861da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 17871da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 17881da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 17891da177e4SLinus Torvalds get_group_info(target->cr_group_info); 17900dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 17910dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 17920dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 179303a4e1f6SJ. Bruce Fields return 0; 17941da177e4SLinus Torvalds } 17951da177e4SLinus Torvalds 1796ef17af2aSRasmus Villemoes static int 1797ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 1798ac55fdc4SJeff Layton { 1799ef17af2aSRasmus Villemoes if (o1->len < o2->len) 1800ef17af2aSRasmus Villemoes return -1; 1801ef17af2aSRasmus Villemoes if (o1->len > o2->len) 1802ef17af2aSRasmus Villemoes return 1; 1803ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 1804ac55fdc4SJeff Layton } 1805ac55fdc4SJeff Layton 180635bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 1807599e0a22SJ. Bruce Fields { 1808a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds 18111da177e4SLinus Torvalds static int 1812599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 1813599e0a22SJ. Bruce Fields { 1814599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 18151da177e4SLinus Torvalds } 18161da177e4SLinus Torvalds 18171da177e4SLinus Torvalds static int 1818599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 1819599e0a22SJ. Bruce Fields { 1820599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 18211da177e4SLinus Torvalds } 18221da177e4SLinus Torvalds 18238fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 18248fbba96eSJ. Bruce Fields { 18258fbba96eSJ. Bruce Fields int i; 18268fbba96eSJ. Bruce Fields 18278fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 18288fbba96eSJ. Bruce Fields return false; 18298fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 18306fab8779SEric W. Biederman if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i))) 18318fbba96eSJ. Bruce Fields return false; 18328fbba96eSJ. Bruce Fields return true; 18338fbba96eSJ. Bruce Fields } 18348fbba96eSJ. Bruce Fields 183568eb3508SJ. Bruce Fields /* 183668eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 183768eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 183868eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 183968eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 184068eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 184168eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 184268eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 184368eb3508SJ. Bruce Fields */ 184468eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 184568eb3508SJ. Bruce Fields { 184668eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 184768eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 184868eb3508SJ. Bruce Fields } 184968eb3508SJ. Bruce Fields 185068eb3508SJ. Bruce Fields 18515559b50aSVivek Trivedi static bool 1852599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 1853599e0a22SJ. Bruce Fields { 185468eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 18556fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 18566fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 18578fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 18588fbba96eSJ. Bruce Fields return false; 18598fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 18608fbba96eSJ. Bruce Fields return true; 18618fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 18628fbba96eSJ. Bruce Fields return false; 18635559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 18641da177e4SLinus Torvalds } 18651da177e4SLinus Torvalds 186657266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 186757266a6eSJ. Bruce Fields { 186857266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 186957266a6eSJ. Bruce Fields u32 service; 187057266a6eSJ. Bruce Fields 1871c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 1872c4720591SJ. Bruce Fields return false; 187357266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 187457266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 187557266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 187657266a6eSJ. Bruce Fields } 187757266a6eSJ. Bruce Fields 187857266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 187957266a6eSJ. Bruce Fields { 188057266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 188157266a6eSJ. Bruce Fields 188257266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 188357266a6eSJ. Bruce Fields return true; 188457266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 188557266a6eSJ. Bruce Fields return false; 188657266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 188757266a6eSJ. Bruce Fields return false; 188857266a6eSJ. Bruce Fields if (!cr->cr_principal) 188957266a6eSJ. Bruce Fields return false; 189057266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 189157266a6eSJ. Bruce Fields } 189257266a6eSJ. Bruce Fields 1893294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 1894deda2faaSJ. Bruce Fields { 1895ab4684d1SChuck Lever __be32 verf[2]; 18961da177e4SLinus Torvalds 1897f419992cSJeff Layton /* 1898f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 1899f419992cSJeff Layton * __force to keep sparse happy 1900f419992cSJeff Layton */ 1901f419992cSJeff Layton verf[0] = (__force __be32)get_seconds(); 1902294ac32eSJeff Layton verf[1] = (__force __be32)nn->clientid_counter; 1903ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 19041da177e4SLinus Torvalds } 19051da177e4SLinus Torvalds 1906294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 1907294ac32eSJeff Layton { 1908294ac32eSJeff Layton clp->cl_clientid.cl_boot = nn->boot_time; 1909294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 1910294ac32eSJeff Layton gen_confirm(clp, nn); 1911294ac32eSJeff Layton } 1912294ac32eSJeff Layton 19134770d722SJeff Layton static struct nfs4_stid * 19144770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 19154581d140SJ. Bruce Fields { 19163abdb607SJ. Bruce Fields struct nfs4_stid *ret; 19173abdb607SJ. Bruce Fields 19183abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 19193abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 19203abdb607SJ. Bruce Fields return NULL; 19213abdb607SJ. Bruce Fields return ret; 19224581d140SJ. Bruce Fields } 19234d71ab87SJ. Bruce Fields 19244770d722SJeff Layton static struct nfs4_stid * 19254770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 1926f459e453SJ. Bruce Fields { 1927f459e453SJ. Bruce Fields struct nfs4_stid *s; 1928f459e453SJ. Bruce Fields 19294770d722SJeff Layton spin_lock(&cl->cl_lock); 19304770d722SJeff Layton s = find_stateid_locked(cl, t); 19312d3f9668STrond Myklebust if (s != NULL) { 19322d3f9668STrond Myklebust if (typemask & s->sc_type) 19332d3f9668STrond Myklebust atomic_inc(&s->sc_count); 19342d3f9668STrond Myklebust else 19354770d722SJeff Layton s = NULL; 19362d3f9668STrond Myklebust } 19374770d722SJeff Layton spin_unlock(&cl->cl_lock); 19384d71ab87SJ. Bruce Fields return s; 19394581d140SJ. Bruce Fields } 19404581d140SJ. Bruce Fields 19412216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 1942b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 1943b09333c4SRicardo Labiaga { 1944b09333c4SRicardo Labiaga struct nfs4_client *clp; 1945b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 194603a4e1f6SJ. Bruce Fields int ret; 1947c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 1948b09333c4SRicardo Labiaga 1949b09333c4SRicardo Labiaga clp = alloc_client(name); 1950b09333c4SRicardo Labiaga if (clp == NULL) 1951b09333c4SRicardo Labiaga return NULL; 1952b09333c4SRicardo Labiaga 195303a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 195403a4e1f6SJ. Bruce Fields if (ret) { 1955b09333c4SRicardo Labiaga free_client(clp); 1956b09333c4SRicardo Labiaga return NULL; 1957b09333c4SRicardo Labiaga } 19580162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 195907cd4909SBenny Halevy clp->cl_time = get_seconds(); 1960b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 1961b09333c4SRicardo Labiaga copy_verf(clp, verf); 1962b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 1963edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 1964c212cecfSStanislav Kinsbursky clp->net = net; 1965b09333c4SRicardo Labiaga return clp; 1966b09333c4SRicardo Labiaga } 1967b09333c4SRicardo Labiaga 1968fd39ca9aSNeilBrown static void 1969ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 1970ac55fdc4SJeff Layton { 1971ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 1972ac55fdc4SJeff Layton struct nfs4_client *clp; 1973ac55fdc4SJeff Layton 1974ac55fdc4SJeff Layton while (*new) { 1975ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 1976ac55fdc4SJeff Layton parent = *new; 1977ac55fdc4SJeff Layton 1978ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 1979ac55fdc4SJeff Layton new = &((*new)->rb_left); 1980ac55fdc4SJeff Layton else 1981ac55fdc4SJeff Layton new = &((*new)->rb_right); 1982ac55fdc4SJeff Layton } 1983ac55fdc4SJeff Layton 1984ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 1985ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 1986ac55fdc4SJeff Layton } 1987ac55fdc4SJeff Layton 1988ac55fdc4SJeff Layton static struct nfs4_client * 1989ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 1990ac55fdc4SJeff Layton { 1991ef17af2aSRasmus Villemoes int cmp; 1992ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 1993ac55fdc4SJeff Layton struct nfs4_client *clp; 1994ac55fdc4SJeff Layton 1995ac55fdc4SJeff Layton while (node) { 1996ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 1997ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 1998ac55fdc4SJeff Layton if (cmp > 0) 1999ac55fdc4SJeff Layton node = node->rb_left; 2000ac55fdc4SJeff Layton else if (cmp < 0) 2001ac55fdc4SJeff Layton node = node->rb_right; 2002ac55fdc4SJeff Layton else 2003ac55fdc4SJeff Layton return clp; 2004ac55fdc4SJeff Layton } 2005ac55fdc4SJeff Layton return NULL; 2006ac55fdc4SJeff Layton } 2007ac55fdc4SJeff Layton 2008ac55fdc4SJeff Layton static void 2009ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 20101da177e4SLinus Torvalds { 20111da177e4SLinus Torvalds unsigned int idhashval; 20120a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20131da177e4SLinus Torvalds 20140a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20150a880a28STrond Myklebust 2016ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2017a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 20181da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 20190a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 20203dbacee6STrond Myklebust renew_client_locked(clp); 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds 2023fd39ca9aSNeilBrown static void 20241da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 20251da177e4SLinus Torvalds { 20261da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 20278daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20281da177e4SLinus Torvalds 20290a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20300a880a28STrond Myklebust 20311da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 20328daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2033a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2034382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2035ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 20363dbacee6STrond Myklebust renew_client_locked(clp); 20371da177e4SLinus Torvalds } 20381da177e4SLinus Torvalds 20391da177e4SLinus Torvalds static struct nfs4_client * 2040bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 20411da177e4SLinus Torvalds { 20421da177e4SLinus Torvalds struct nfs4_client *clp; 20431da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 20441da177e4SLinus Torvalds 2045bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2046a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2047d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2048d15c077eSJ. Bruce Fields return NULL; 20493dbacee6STrond Myklebust renew_client_locked(clp); 20501da177e4SLinus Torvalds return clp; 20511da177e4SLinus Torvalds } 2052a50d2ad1SJ. Bruce Fields } 20531da177e4SLinus Torvalds return NULL; 20541da177e4SLinus Torvalds } 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds static struct nfs4_client * 2057bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2058bfa85e83SJ. Bruce Fields { 2059bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2060bfa85e83SJ. Bruce Fields 20610a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2062bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2063bfa85e83SJ. Bruce Fields } 2064bfa85e83SJ. Bruce Fields 2065bfa85e83SJ. Bruce Fields static struct nfs4_client * 20660a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 20671da177e4SLinus Torvalds { 2068bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 20691da177e4SLinus Torvalds 20700a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2071bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 20721da177e4SLinus Torvalds } 20731da177e4SLinus Torvalds 20746e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2075a1bcecd2SAndy Adamson { 20766e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2077a1bcecd2SAndy Adamson } 2078a1bcecd2SAndy Adamson 207928ce6054SNeilBrown static struct nfs4_client * 2080382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 208128ce6054SNeilBrown { 20820a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2083382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 208428ce6054SNeilBrown } 208528ce6054SNeilBrown 208628ce6054SNeilBrown static struct nfs4_client * 2087a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 208828ce6054SNeilBrown { 20890a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2090a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 209128ce6054SNeilBrown } 209228ce6054SNeilBrown 2093fd39ca9aSNeilBrown static void 20946f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 20951da177e4SLinus Torvalds { 209607263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 20976f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 20986f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 20997077ecbaSJeff Layton unsigned short expected_family; 21001da177e4SLinus Torvalds 21017077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 21027077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 21037077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 21047077ecbaSJeff Layton expected_family = AF_INET; 21057077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 21067077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 21077077ecbaSJeff Layton expected_family = AF_INET6; 21087077ecbaSJeff Layton else 21091da177e4SLinus Torvalds goto out_err; 21101da177e4SLinus Torvalds 2111c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2112aa9a4ec7SJeff Layton se->se_callback_addr_len, 211307263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 211407263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2115aa9a4ec7SJeff Layton 211607263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 21171da177e4SLinus Torvalds goto out_err; 2118aa9a4ec7SJeff Layton 211907263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 212007263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2121fbf4665fSJeff Layton 212207263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 212307263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2124849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 21251da177e4SLinus Torvalds return; 21261da177e4SLinus Torvalds out_err: 212707263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 212807263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 2129849823c5SNeil Brown dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " 21301da177e4SLinus Torvalds "will not receive delegations\n", 21311da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 21321da177e4SLinus Torvalds 21331da177e4SLinus Torvalds return; 21341da177e4SLinus Torvalds } 21351da177e4SLinus Torvalds 2136074fe897SAndy Adamson /* 2137067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2138074fe897SAndy Adamson */ 2139b607664eSTrond Myklebust static void 2140074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2141074fe897SAndy Adamson { 2142f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2143557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2144557ce264SAndy Adamson unsigned int base; 2145074fe897SAndy Adamson 2146557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2147074fe897SAndy Adamson 2148557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2149557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 2150bf864a31SAndy Adamson 2151bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2152bf864a31SAndy Adamson if (nfsd4_not_cached(resp)) { 2153557ce264SAndy Adamson slot->sl_datalen = 0; 2154bf864a31SAndy Adamson return; 2155bf864a31SAndy Adamson } 2156f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2157f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2158f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2159557ce264SAndy Adamson WARN("%s: sessions DRC could not cache compound\n", __func__); 2160557ce264SAndy Adamson return; 2161074fe897SAndy Adamson } 2162074fe897SAndy Adamson 2163074fe897SAndy Adamson /* 2164abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2165abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2166abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2167abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2168abfabf8cSAndy Adamson * 2169074fe897SAndy Adamson */ 2170abfabf8cSAndy Adamson static __be32 2171abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2172abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2173074fe897SAndy Adamson { 2174abfabf8cSAndy Adamson struct nfsd4_op *op; 2175abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2176074fe897SAndy Adamson 2177abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2178abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2179abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2180abfabf8cSAndy Adamson 2181abfabf8cSAndy Adamson /* Return nfserr_retry_uncached_rep in next operation. */ 218273e79482SJ. Bruce Fields if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { 2183abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2184abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2185abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2186074fe897SAndy Adamson } 2187abfabf8cSAndy Adamson return op->status; 2188074fe897SAndy Adamson } 2189074fe897SAndy Adamson 2190074fe897SAndy Adamson /* 2191557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2192557ce264SAndy Adamson * session values. 2193074fe897SAndy Adamson */ 21943ca2eb98SJ. Bruce Fields static __be32 2195bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2196bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2197074fe897SAndy Adamson { 2198557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2199f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2200f5236013SJ. Bruce Fields __be32 *p; 2201074fe897SAndy Adamson __be32 status; 2202074fe897SAndy Adamson 2203557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2204074fe897SAndy Adamson 2205abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 22060da7b19cSJ. Bruce Fields if (status) 2207abfabf8cSAndy Adamson return status; 2208074fe897SAndy Adamson 2209f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2210f5236013SJ. Bruce Fields if (!p) { 2211f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2212f5236013SJ. Bruce Fields return nfserr_serverfault; 2213f5236013SJ. Bruce Fields } 2214f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2215f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2216074fe897SAndy Adamson 2217557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2218f5236013SJ. Bruce Fields return slot->sl_status; 2219074fe897SAndy Adamson } 2220074fe897SAndy Adamson 22210733d213SAndy Adamson /* 22220733d213SAndy Adamson * Set the exchange_id flags returned by the server. 22230733d213SAndy Adamson */ 22240733d213SAndy Adamson static void 22250733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 22260733d213SAndy Adamson { 22279cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 22289cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 22299cf514ccSChristoph Hellwig #else 22300733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 22319cf514ccSChristoph Hellwig #endif 22320733d213SAndy Adamson 22330733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 22340733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 22350733d213SAndy Adamson 22360733d213SAndy Adamson /* set the wire flags to return to client. */ 22370733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 22380733d213SAndy Adamson } 22390733d213SAndy Adamson 2240631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 2241631fc9eaSJ. Bruce Fields { 2242631fc9eaSJ. Bruce Fields /* 2243631fc9eaSJ. Bruce Fields * Note clp->cl_openowners check isn't quite right: there's no 2244631fc9eaSJ. Bruce Fields * need to count owners without stateid's. 2245631fc9eaSJ. Bruce Fields * 2246631fc9eaSJ. Bruce Fields * Also note we should probably be using this in 4.0 case too. 2247631fc9eaSJ. Bruce Fields */ 22486eccece9SJ. Bruce Fields return !list_empty(&clp->cl_openowners) 224947e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 225047e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 225147e970beSKinglong Mee #endif 22526eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 22536eccece9SJ. Bruce Fields || !list_empty(&clp->cl_sessions); 2254631fc9eaSJ. Bruce Fields } 2255631fc9eaSJ. Bruce Fields 2256b37ad28bSAl Viro __be32 2257069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp, 2258069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2259069b6ad4SAndy Adamson struct nfsd4_exchange_id *exid) 2260069b6ad4SAndy Adamson { 22613dbacee6STrond Myklebust struct nfs4_client *conf, *new; 22623dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 226357b7b43bSJ. Bruce Fields __be32 status; 2264363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 22650733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 2266363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 226783e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 2268c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 22690733d213SAndy Adamson 2270363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 22710733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 2272363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 22730733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 2274363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 22750733d213SAndy Adamson 2276a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 22770733d213SAndy Adamson return nfserr_inval; 22780733d213SAndy Adamson 22790733d213SAndy Adamson switch (exid->spa_how) { 228057266a6eSJ. Bruce Fields case SP4_MACH_CRED: 228157266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 228257266a6eSJ. Bruce Fields return nfserr_inval; 22830733d213SAndy Adamson case SP4_NONE: 22840733d213SAndy Adamson break; 2285063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 2286063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 22870733d213SAndy Adamson case SP4_SSV: 2288dd30333cSJ. Bruce Fields return nfserr_encr_alg_unsupp; 22890733d213SAndy Adamson } 22900733d213SAndy Adamson 22915cc40fd7STrond Myklebust new = create_client(exid->clname, rqstp, &verf); 22925cc40fd7STrond Myklebust if (new == NULL) 22935cc40fd7STrond Myklebust return nfserr_jukebox; 22945cc40fd7STrond Myklebust 22952dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 22963dbacee6STrond Myklebust spin_lock(&nn->client_lock); 2297382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 22980733d213SAndy Adamson if (conf) { 229983e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 230083e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 230183e08fd4SJ. Bruce Fields 2302136e658dSJ. Bruce Fields if (update) { 2303136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 23042dbb269dSJ. Bruce Fields status = nfserr_inval; 2305e203d506SJ. Bruce Fields goto out; 2306e203d506SJ. Bruce Fields } 230757266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) { 230857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 230957266a6eSJ. Bruce Fields goto out; 231057266a6eSJ. Bruce Fields } 23112dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 23120733d213SAndy Adamson status = nfserr_perm; 23130733d213SAndy Adamson goto out; 23140733d213SAndy Adamson } 23152dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 23160733d213SAndy Adamson status = nfserr_not_same; 23170733d213SAndy Adamson goto out; 23180733d213SAndy Adamson } 2319136e658dSJ. Bruce Fields /* case 6 */ 23200733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 23210733d213SAndy Adamson goto out_copy; 23226ddbbbfeSMike Sager } 2323136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 2324631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 2325136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 2326136e658dSJ. Bruce Fields goto out; 2327136e658dSJ. Bruce Fields } 2328b9831b59SJ. Bruce Fields goto out_new; 2329631fc9eaSJ. Bruce Fields } 2330136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 23310f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 2332136e658dSJ. Bruce Fields goto out_copy; 2333136e658dSJ. Bruce Fields } 23342dbb269dSJ. Bruce Fields /* case 5, client reboot */ 23353dbacee6STrond Myklebust conf = NULL; 23360733d213SAndy Adamson goto out_new; 23370733d213SAndy Adamson } 23386ddbbbfeSMike Sager 23392dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 23400733d213SAndy Adamson status = nfserr_noent; 23410733d213SAndy Adamson goto out; 23420733d213SAndy Adamson } 23430733d213SAndy Adamson 2344a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 23452dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 23463dbacee6STrond Myklebust unhash_client_locked(unconf); 23470733d213SAndy Adamson 23482dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 23490733d213SAndy Adamson out_new: 2350fd699b8aSJeff Layton if (conf) { 2351fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 2352fd699b8aSJeff Layton if (status) 2353fd699b8aSJeff Layton goto out; 2354fd699b8aSJeff Layton } 23554f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 235657266a6eSJ. Bruce Fields new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); 23570733d213SAndy Adamson 2358c212cecfSStanislav Kinsbursky gen_clid(new, nn); 2359ac55fdc4SJeff Layton add_to_unconfirmed(new); 23603dbacee6STrond Myklebust swap(new, conf); 23610733d213SAndy Adamson out_copy: 23625cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 23635cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 23640733d213SAndy Adamson 23655cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 23665cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 23670733d213SAndy Adamson 23680733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 23695cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 23700733d213SAndy Adamson status = nfs_ok; 23710733d213SAndy Adamson 23720733d213SAndy Adamson out: 23733dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 23745cc40fd7STrond Myklebust if (new) 23753dbacee6STrond Myklebust expire_client(new); 23763dbacee6STrond Myklebust if (unconf) 23773dbacee6STrond Myklebust expire_client(unconf); 23780733d213SAndy Adamson return status; 2379069b6ad4SAndy Adamson } 2380069b6ad4SAndy Adamson 238157b7b43bSJ. Bruce Fields static __be32 238288e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 2383b85d4c01SBenny Halevy { 238488e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 238588e588d5SAndy Adamson slot_seqid); 2386b85d4c01SBenny Halevy 2387b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 238888e588d5SAndy Adamson if (slot_inuse) { 238988e588d5SAndy Adamson if (seqid == slot_seqid) 2390b85d4c01SBenny Halevy return nfserr_jukebox; 2391b85d4c01SBenny Halevy else 2392b85d4c01SBenny Halevy return nfserr_seq_misordered; 2393b85d4c01SBenny Halevy } 2394f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 239588e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 2396b85d4c01SBenny Halevy return nfs_ok; 239788e588d5SAndy Adamson if (seqid == slot_seqid) 2398b85d4c01SBenny Halevy return nfserr_replay_cache; 2399b85d4c01SBenny Halevy return nfserr_seq_misordered; 2400b85d4c01SBenny Halevy } 2401b85d4c01SBenny Halevy 240249557cc7SAndy Adamson /* 240349557cc7SAndy Adamson * Cache the create session result into the create session single DRC 240449557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 240549557cc7SAndy Adamson * Do this for solo or embedded create session operations. 240649557cc7SAndy Adamson */ 240749557cc7SAndy Adamson static void 240849557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 240957b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 241049557cc7SAndy Adamson { 241149557cc7SAndy Adamson slot->sl_status = nfserr; 241249557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 241349557cc7SAndy Adamson } 241449557cc7SAndy Adamson 241549557cc7SAndy Adamson static __be32 241649557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 241749557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 241849557cc7SAndy Adamson { 241949557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 242049557cc7SAndy Adamson return slot->sl_status; 242149557cc7SAndy Adamson } 242249557cc7SAndy Adamson 24231b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 24241b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 24251b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 24261b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 24271b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 24281b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 24291b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 24301b74c25bSMi Jinlong 24311b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 24321b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 24331b74c25bSMi Jinlong 1 + /* status */ \ 24341b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 24351b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 24361b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 24371b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 24381b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 24391b74c25bSMi Jinlong 244055c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 24411b74c25bSMi Jinlong { 244255c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 244355c760cfSJ. Bruce Fields 2444373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 2445373cd409SJ. Bruce Fields return nfserr_toosmall; 2446373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 2447373cd409SJ. Bruce Fields return nfserr_toosmall; 244855c760cfSJ. Bruce Fields ca->headerpadsz = 0; 244955c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 245055c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 245155c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 245255c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 245355c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 245455c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 245555c760cfSJ. Bruce Fields /* 245655c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 245755c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 245855c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 245955c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 246055c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 246155c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 246255c760cfSJ. Bruce Fields */ 246355c760cfSJ. Bruce Fields ca->maxreqs = nfsd4_get_drc_mem(ca); 246455c760cfSJ. Bruce Fields if (!ca->maxreqs) 246555c760cfSJ. Bruce Fields return nfserr_jukebox; 246655c760cfSJ. Bruce Fields 2467373cd409SJ. Bruce Fields return nfs_ok; 24681b74c25bSMi Jinlong } 24691b74c25bSMi Jinlong 24708a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 24718a891633SKinglong Mee RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32)) 24728a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 24738a891633SKinglong Mee RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32)) 24748a891633SKinglong Mee 247506b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 247606b332a5SJ. Bruce Fields { 247706b332a5SJ. Bruce Fields ca->headerpadsz = 0; 247806b332a5SJ. Bruce Fields 247906b332a5SJ. Bruce Fields /* 248006b332a5SJ. Bruce Fields * These RPC_MAX_HEADER macros are overkill, especially since we 248106b332a5SJ. Bruce Fields * don't even do gss on the backchannel yet. But this is still 248206b332a5SJ. Bruce Fields * less than 1k. Tighten up this estimate in the unlikely event 248306b332a5SJ. Bruce Fields * it turns out to be a problem for some client: 248406b332a5SJ. Bruce Fields */ 24858a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 248606b332a5SJ. Bruce Fields return nfserr_toosmall; 24878a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 248806b332a5SJ. Bruce Fields return nfserr_toosmall; 248906b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 249006b332a5SJ. Bruce Fields if (ca->maxops < 2) 249106b332a5SJ. Bruce Fields return nfserr_toosmall; 249206b332a5SJ. Bruce Fields 249306b332a5SJ. Bruce Fields return nfs_ok; 2494069b6ad4SAndy Adamson } 2495069b6ad4SAndy Adamson 2496b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 2497b78724b7SJ. Bruce Fields { 2498b78724b7SJ. Bruce Fields switch (cbs->flavor) { 2499b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 2500b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 2501b78724b7SJ. Bruce Fields return nfs_ok; 2502b78724b7SJ. Bruce Fields default: 2503b78724b7SJ. Bruce Fields /* 2504b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 2505b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 2506b78724b7SJ. Bruce Fields * GSS. 2507b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 2508b78724b7SJ. Bruce Fields * client might think it can already handle: 2509b78724b7SJ. Bruce Fields */ 2510b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 2511b78724b7SJ. Bruce Fields } 2512b78724b7SJ. Bruce Fields } 2513b78724b7SJ. Bruce Fields 2514069b6ad4SAndy Adamson __be32 2515069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 2516069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2517069b6ad4SAndy Adamson struct nfsd4_create_session *cr_ses) 2518069b6ad4SAndy Adamson { 2519363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 2520ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 2521d20c11d8SJeff Layton struct nfs4_client *old = NULL; 2522ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 252381f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 252449557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 252557b7b43bSJ. Bruce Fields __be32 status = 0; 25268daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2527ec6b5d7bSAndy Adamson 2528a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 2529a62573dcSMi Jinlong return nfserr_inval; 2530b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 2531b78724b7SJ. Bruce Fields if (status) 2532b78724b7SJ. Bruce Fields return status; 253355c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 2534373cd409SJ. Bruce Fields if (status) 2535373cd409SJ. Bruce Fields return status; 253606b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 253706b332a5SJ. Bruce Fields if (status) 2538f403e450SKinglong Mee goto out_release_drc_mem; 253981f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 254060810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 254155c760cfSJ. Bruce Fields if (!new) 254255c760cfSJ. Bruce Fields goto out_release_drc_mem; 254381f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 254481f0b2a4SJ. Bruce Fields if (!conn) 254581f0b2a4SJ. Bruce Fields goto out_free_session; 2546a62573dcSMi Jinlong 2547d20c11d8SJeff Layton spin_lock(&nn->client_lock); 25480a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 25498daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 255078389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2551ec6b5d7bSAndy Adamson 2552ec6b5d7bSAndy Adamson if (conf) { 255357266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 255457266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) 255557266a6eSJ. Bruce Fields goto out_free_conn; 255649557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 255749557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 255838eb76a5SAndy Adamson if (status == nfserr_replay_cache) { 255949557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 256081f0b2a4SJ. Bruce Fields goto out_free_conn; 256149557cc7SAndy Adamson } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { 2562ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 256381f0b2a4SJ. Bruce Fields goto out_free_conn; 2564ec6b5d7bSAndy Adamson } 2565ec6b5d7bSAndy Adamson } else if (unconf) { 2566ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 2567363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 2568ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 256981f0b2a4SJ. Bruce Fields goto out_free_conn; 2570ec6b5d7bSAndy Adamson } 257157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 257257266a6eSJ. Bruce Fields if (!mach_creds_match(unconf, rqstp)) 257357266a6eSJ. Bruce Fields goto out_free_conn; 257449557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 257549557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 257638eb76a5SAndy Adamson if (status) { 257738eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 2578ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 257981f0b2a4SJ. Bruce Fields goto out_free_conn; 2580ec6b5d7bSAndy Adamson } 2581382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 2582221a6876SJ. Bruce Fields if (old) { 2583d20c11d8SJeff Layton status = mark_client_expired_locked(old); 25847abea1e8SJeff Layton if (status) { 25857abea1e8SJeff Layton old = NULL; 2586221a6876SJ. Bruce Fields goto out_free_conn; 2587221a6876SJ. Bruce Fields } 25887abea1e8SJeff Layton } 25898f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 2590ec6b5d7bSAndy Adamson conf = unconf; 2591ec6b5d7bSAndy Adamson } else { 2592ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 259381f0b2a4SJ. Bruce Fields goto out_free_conn; 2594ec6b5d7bSAndy Adamson } 259581f0b2a4SJ. Bruce Fields status = nfs_ok; 25968323c3b2SJ. Bruce Fields /* 2597408b79bcSJ. Bruce Fields * We do not support RDMA or persistent sessions 2598408b79bcSJ. Bruce Fields */ 2599408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 2600408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 2601408b79bcSJ. Bruce Fields 260281f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 2603d20c11d8SJeff Layton nfsd4_get_session_locked(new); 260481f0b2a4SJ. Bruce Fields 2605ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 2606ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 260786c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 260849557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 2609ec6b5d7bSAndy Adamson 2610d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 261149557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 2612d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 2613d20c11d8SJeff Layton /* init connection and backchannel */ 2614d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 2615d20c11d8SJeff Layton nfsd4_put_session(new); 2616d20c11d8SJeff Layton if (old) 2617d20c11d8SJeff Layton expire_client(old); 2618ec6b5d7bSAndy Adamson return status; 261981f0b2a4SJ. Bruce Fields out_free_conn: 2620d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 262181f0b2a4SJ. Bruce Fields free_conn(conn); 2622d20c11d8SJeff Layton if (old) 2623d20c11d8SJeff Layton expire_client(old); 262481f0b2a4SJ. Bruce Fields out_free_session: 262581f0b2a4SJ. Bruce Fields __free_session(new); 262655c760cfSJ. Bruce Fields out_release_drc_mem: 262755c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 26281ca50792SJ. Bruce Fields return status; 2629069b6ad4SAndy Adamson } 2630069b6ad4SAndy Adamson 26311d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 26321d1bc8f2SJ. Bruce Fields { 26331d1bc8f2SJ. Bruce Fields switch (*dir) { 26341d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 26351d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 26361d1bc8f2SJ. Bruce Fields return nfs_ok; 26371d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 26381d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 26391d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 26401d1bc8f2SJ. Bruce Fields return nfs_ok; 26411d1bc8f2SJ. Bruce Fields }; 26421d1bc8f2SJ. Bruce Fields return nfserr_inval; 26431d1bc8f2SJ. Bruce Fields } 26441d1bc8f2SJ. Bruce Fields 2645cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) 2646cb73a9f4SJ. Bruce Fields { 2647cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 2648c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2649b78724b7SJ. Bruce Fields __be32 status; 2650cb73a9f4SJ. Bruce Fields 2651b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 2652b78724b7SJ. Bruce Fields if (status) 2653b78724b7SJ. Bruce Fields return status; 2654c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2655cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 2656cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 2657c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2658cb73a9f4SJ. Bruce Fields 2659cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 2660cb73a9f4SJ. Bruce Fields 2661cb73a9f4SJ. Bruce Fields return nfs_ok; 2662cb73a9f4SJ. Bruce Fields } 2663cb73a9f4SJ. Bruce Fields 26641d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 26651d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 26661d1bc8f2SJ. Bruce Fields struct nfsd4_bind_conn_to_session *bcts) 26671d1bc8f2SJ. Bruce Fields { 26681d1bc8f2SJ. Bruce Fields __be32 status; 26693ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 26704f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 2671d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2672d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 26731d1bc8f2SJ. Bruce Fields 26741d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 26751d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 2676c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2677d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 2678c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 26794f6e6c17SJ. Bruce Fields if (!session) 2680d4e19e70STrond Myklebust goto out_no_session; 268157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 268257266a6eSJ. Bruce Fields if (!mach_creds_match(session->se_client, rqstp)) 268357266a6eSJ. Bruce Fields goto out; 26841d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 26853ba63671SJ. Bruce Fields if (status) 26864f6e6c17SJ. Bruce Fields goto out; 26873ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 26884f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 26893ba63671SJ. Bruce Fields if (!conn) 26904f6e6c17SJ. Bruce Fields goto out; 26914f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 26924f6e6c17SJ. Bruce Fields status = nfs_ok; 26934f6e6c17SJ. Bruce Fields out: 2694d4e19e70STrond Myklebust nfsd4_put_session(session); 2695d4e19e70STrond Myklebust out_no_session: 26964f6e6c17SJ. Bruce Fields return status; 26971d1bc8f2SJ. Bruce Fields } 26981d1bc8f2SJ. Bruce Fields 26995d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) 27005d4cec2fSJ. Bruce Fields { 27015d4cec2fSJ. Bruce Fields if (!session) 27025d4cec2fSJ. Bruce Fields return 0; 27035d4cec2fSJ. Bruce Fields return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); 27045d4cec2fSJ. Bruce Fields } 27055d4cec2fSJ. Bruce Fields 2706069b6ad4SAndy Adamson __be32 2707069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r, 2708069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2709069b6ad4SAndy Adamson struct nfsd4_destroy_session *sessionid) 2710069b6ad4SAndy Adamson { 2711e10e0cfcSBenny Halevy struct nfsd4_session *ses; 2712abcdff09SJ. Bruce Fields __be32 status; 2713f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 2714d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 2715d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2716e10e0cfcSBenny Halevy 2717abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 27185d4cec2fSJ. Bruce Fields if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { 271957716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 2720abcdff09SJ. Bruce Fields goto out; 2721f0f51f5cSJ. Bruce Fields ref_held_by_me++; 272257716355SJ. Bruce Fields } 2723e10e0cfcSBenny Halevy dump_sessionid(__func__, &sessionid->sessionid); 2724c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2725d4e19e70STrond Myklebust ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status); 2726abcdff09SJ. Bruce Fields if (!ses) 2727abcdff09SJ. Bruce Fields goto out_client_lock; 272857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 272957266a6eSJ. Bruce Fields if (!mach_creds_match(ses->se_client, r)) 2730d4e19e70STrond Myklebust goto out_put_session; 2731f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 273266b2b9b2SJ. Bruce Fields if (status) 2733f0f51f5cSJ. Bruce Fields goto out_put_session; 2734e10e0cfcSBenny Halevy unhash_session(ses); 2735c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2736e10e0cfcSBenny Halevy 273784f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 273819cf5c02SJ. Bruce Fields 2739c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2740e10e0cfcSBenny Halevy status = nfs_ok; 2741f0f51f5cSJ. Bruce Fields out_put_session: 2742d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 2743abcdff09SJ. Bruce Fields out_client_lock: 2744abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 2745e10e0cfcSBenny Halevy out: 2746e10e0cfcSBenny Halevy return status; 2747069b6ad4SAndy Adamson } 2748069b6ad4SAndy Adamson 2749a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 2750328ead28SJ. Bruce Fields { 2751328ead28SJ. Bruce Fields struct nfsd4_conn *c; 2752328ead28SJ. Bruce Fields 2753328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 2754a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 2755328ead28SJ. Bruce Fields return c; 2756328ead28SJ. Bruce Fields } 2757328ead28SJ. Bruce Fields } 2758328ead28SJ. Bruce Fields return NULL; 2759328ead28SJ. Bruce Fields } 2760328ead28SJ. Bruce Fields 276157266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 2762328ead28SJ. Bruce Fields { 2763328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 2764a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 276557266a6eSJ. Bruce Fields __be32 status = nfs_ok; 276621b75b01SJ. Bruce Fields int ret; 2767328ead28SJ. Bruce Fields 2768328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 2769a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 277057266a6eSJ. Bruce Fields if (c) 277157266a6eSJ. Bruce Fields goto out_free; 277257266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 277357266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 277457266a6eSJ. Bruce Fields goto out_free; 2775328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 2776328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 277721b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 277821b75b01SJ. Bruce Fields if (ret) 277921b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 278021b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 278157266a6eSJ. Bruce Fields return nfs_ok; 278257266a6eSJ. Bruce Fields out_free: 278357266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 278457266a6eSJ. Bruce Fields free_conn(new); 278557266a6eSJ. Bruce Fields return status; 2786328ead28SJ. Bruce Fields } 2787328ead28SJ. Bruce Fields 2788868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 2789868b89c3SMi Jinlong { 2790868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 2791868b89c3SMi Jinlong 2792868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 2793868b89c3SMi Jinlong } 2794868b89c3SMi Jinlong 2795ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 2796ae82a8d0SMi Jinlong struct nfsd4_session *session) 2797ae82a8d0SMi Jinlong { 2798ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 2799ae82a8d0SMi Jinlong 2800ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 2801ae82a8d0SMi Jinlong } 2802ae82a8d0SMi Jinlong 2803069b6ad4SAndy Adamson __be32 2804b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp, 2805069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2806069b6ad4SAndy Adamson struct nfsd4_sequence *seq) 2807069b6ad4SAndy Adamson { 2808f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 280947ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2810b85d4c01SBenny Halevy struct nfsd4_session *session; 2811221a6876SJ. Bruce Fields struct nfs4_client *clp; 2812b85d4c01SBenny Halevy struct nfsd4_slot *slot; 2813a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 281457b7b43bSJ. Bruce Fields __be32 status; 281547ee5298SJ. Bruce Fields int buflen; 2816d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2817d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2818b85d4c01SBenny Halevy 2819f9bb94c4SAndy Adamson if (resp->opcnt != 1) 2820f9bb94c4SAndy Adamson return nfserr_sequence_pos; 2821f9bb94c4SAndy Adamson 2822a663bdd8SJ. Bruce Fields /* 2823a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 2824a663bdd8SJ. Bruce Fields * below. 2825a663bdd8SJ. Bruce Fields */ 2826a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 2827a663bdd8SJ. Bruce Fields if (!conn) 2828a663bdd8SJ. Bruce Fields return nfserr_jukebox; 2829a663bdd8SJ. Bruce Fields 2830c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2831d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 2832b85d4c01SBenny Halevy if (!session) 2833221a6876SJ. Bruce Fields goto out_no_session; 2834221a6876SJ. Bruce Fields clp = session->se_client; 2835b85d4c01SBenny Halevy 2836868b89c3SMi Jinlong status = nfserr_too_many_ops; 2837868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 283866b2b9b2SJ. Bruce Fields goto out_put_session; 2839868b89c3SMi Jinlong 2840ae82a8d0SMi Jinlong status = nfserr_req_too_big; 2841ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 284266b2b9b2SJ. Bruce Fields goto out_put_session; 2843ae82a8d0SMi Jinlong 2844b85d4c01SBenny Halevy status = nfserr_badslot; 28456c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 284666b2b9b2SJ. Bruce Fields goto out_put_session; 2847b85d4c01SBenny Halevy 2848557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 2849b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 2850b85d4c01SBenny Halevy 2851a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 2852a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 2853a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 2854a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 2855a8dfdaebSAndy Adamson 285673e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 285773e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 2858b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 2859bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 2860bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 286166b2b9b2SJ. Bruce Fields goto out_put_session; 2862b85d4c01SBenny Halevy cstate->slot = slot; 2863b85d4c01SBenny Halevy cstate->session = session; 28644b24ca7dSJeff Layton cstate->clp = clp; 2865da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 2866557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 2867bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 2868da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 2869aaf84eb9SBenny Halevy goto out; 2870b85d4c01SBenny Halevy } 2871b85d4c01SBenny Halevy if (status) 287266b2b9b2SJ. Bruce Fields goto out_put_session; 2873b85d4c01SBenny Halevy 287457266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 2875a663bdd8SJ. Bruce Fields conn = NULL; 287657266a6eSJ. Bruce Fields if (status) 287757266a6eSJ. Bruce Fields goto out_put_session; 2878328ead28SJ. Bruce Fields 287947ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 288047ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 288147ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 288247ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 288347ee5298SJ. Bruce Fields nfserr_rep_too_big; 2884a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 288547ee5298SJ. Bruce Fields goto out_put_session; 288632aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 288747ee5298SJ. Bruce Fields 288847ee5298SJ. Bruce Fields status = nfs_ok; 2889b85d4c01SBenny Halevy /* Success! bump slot seqid */ 2890b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 2891bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 289273e79482SJ. Bruce Fields if (seq->cachethis) 289373e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 2894bf5c43c8SJ. Bruce Fields else 2895bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 2896b85d4c01SBenny Halevy 2897b85d4c01SBenny Halevy cstate->slot = slot; 2898b85d4c01SBenny Halevy cstate->session = session; 28994b24ca7dSJeff Layton cstate->clp = clp; 2900b85d4c01SBenny Halevy 2901b85d4c01SBenny Halevy out: 29025423732aSBenny Halevy switch (clp->cl_cb_state) { 29035423732aSBenny Halevy case NFSD4_CB_DOWN: 2904fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 29055423732aSBenny Halevy break; 29065423732aSBenny Halevy case NFSD4_CB_FAULT: 2907fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 29085423732aSBenny Halevy break; 2909fc0c3dd1SBenny Halevy default: 2910fc0c3dd1SBenny Halevy seq->status_flags = 0; 29115423732aSBenny Halevy } 29123bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 29133bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 2914221a6876SJ. Bruce Fields out_no_session: 29153f42d2c4SKinglong Mee if (conn) 29163f42d2c4SKinglong Mee free_conn(conn); 2917c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2918b85d4c01SBenny Halevy return status; 291966b2b9b2SJ. Bruce Fields out_put_session: 2920d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 2921221a6876SJ. Bruce Fields goto out_no_session; 2922069b6ad4SAndy Adamson } 2923069b6ad4SAndy Adamson 2924b607664eSTrond Myklebust void 2925b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 2926b607664eSTrond Myklebust { 2927b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 2928b607664eSTrond Myklebust 2929b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 2930b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 2931b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 2932b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 2933b607664eSTrond Myklebust } 2934d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 2935b607664eSTrond Myklebust nfsd4_put_session(cs->session); 29364b24ca7dSJeff Layton } else if (cs->clp) 29374b24ca7dSJeff Layton put_client_renew(cs->clp); 2938b607664eSTrond Myklebust } 2939b607664eSTrond Myklebust 2940345c2842SMi Jinlong __be32 2941345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) 2942345c2842SMi Jinlong { 29436b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 29446b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 294557b7b43bSJ. Bruce Fields __be32 status = 0; 29468daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2947345c2842SMi Jinlong 29486b10ad19STrond Myklebust spin_lock(&nn->client_lock); 29490a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 29508daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 295178389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2952345c2842SMi Jinlong 2953345c2842SMi Jinlong if (conf) { 2954c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 2955345c2842SMi Jinlong status = nfserr_clientid_busy; 2956345c2842SMi Jinlong goto out; 2957345c2842SMi Jinlong } 2958fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 2959fd699b8aSJeff Layton if (status) 2960fd699b8aSJeff Layton goto out; 29616b10ad19STrond Myklebust clp = conf; 2962345c2842SMi Jinlong } else if (unconf) 2963345c2842SMi Jinlong clp = unconf; 2964345c2842SMi Jinlong else { 2965345c2842SMi Jinlong status = nfserr_stale_clientid; 2966345c2842SMi Jinlong goto out; 2967345c2842SMi Jinlong } 296857266a6eSJ. Bruce Fields if (!mach_creds_match(clp, rqstp)) { 29696b10ad19STrond Myklebust clp = NULL; 297057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 297157266a6eSJ. Bruce Fields goto out; 297257266a6eSJ. Bruce Fields } 29736b10ad19STrond Myklebust unhash_client_locked(clp); 2974345c2842SMi Jinlong out: 29756b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 29766b10ad19STrond Myklebust if (clp) 29776b10ad19STrond Myklebust expire_client(clp); 2978345c2842SMi Jinlong return status; 2979345c2842SMi Jinlong } 2980345c2842SMi Jinlong 2981069b6ad4SAndy Adamson __be32 29824dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) 29834dc6ec00SJ. Bruce Fields { 298457b7b43bSJ. Bruce Fields __be32 status = 0; 2985bcecf1ccSMi Jinlong 29864dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 29874dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 29884dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 29894dc6ec00SJ. Bruce Fields /* 29904dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 29914dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 29924dc6ec00SJ. Bruce Fields */ 29934dc6ec00SJ. Bruce Fields return nfs_ok; 29944dc6ec00SJ. Bruce Fields } 2995bcecf1ccSMi Jinlong 2996bcecf1ccSMi Jinlong status = nfserr_complete_already; 2997a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 2998a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 2999bcecf1ccSMi Jinlong goto out; 3000bcecf1ccSMi Jinlong 3001bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 3002bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 30034dc6ec00SJ. Bruce Fields /* 30044dc6ec00SJ. Bruce Fields * The following error isn't really legal. 30054dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 30064dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 30074dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 30084dc6ec00SJ. Bruce Fields * client. 30094dc6ec00SJ. Bruce Fields */ 3010bcecf1ccSMi Jinlong goto out; 3011bcecf1ccSMi Jinlong 3012bcecf1ccSMi Jinlong status = nfs_ok; 30132a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 3014bcecf1ccSMi Jinlong out: 3015bcecf1ccSMi Jinlong return status; 30164dc6ec00SJ. Bruce Fields } 30174dc6ec00SJ. Bruce Fields 30184dc6ec00SJ. Bruce Fields __be32 3019b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3020b591480bSJ.Bruce Fields struct nfsd4_setclientid *setclid) 30211da177e4SLinus Torvalds { 3022a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 30231da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 30243dbacee6STrond Myklebust struct nfs4_client *conf, *new; 30253dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 3026b37ad28bSAl Viro __be32 status; 3027c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3028a55370a3SNeilBrown 30295cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 30305cc40fd7STrond Myklebust if (new == NULL) 30315cc40fd7STrond Myklebust return nfserr_jukebox; 303263db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 30333dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3034382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 303528ce6054SNeilBrown if (conf) { 303663db4632SJ. Bruce Fields /* case 0: */ 30371da177e4SLinus Torvalds status = nfserr_clid_inuse; 3038e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 3039e203d506SJ. Bruce Fields goto out; 3040026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 3041363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 3042363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 3043363168b4SJeff Layton sizeof(addr_str)); 3044026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 3045363168b4SJeff Layton "at %s\n", addr_str); 30461da177e4SLinus Torvalds goto out; 30471da177e4SLinus Torvalds } 30481da177e4SLinus Torvalds } 3049a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 30501da177e4SLinus Torvalds if (unconf) 30513dbacee6STrond Myklebust unhash_client_locked(unconf); 305234b232bbSJ. Bruce Fields if (conf && same_verf(&conf->cl_verifier, &clverifier)) 305363db4632SJ. Bruce Fields /* case 1: probable callback update */ 30541da177e4SLinus Torvalds copy_clid(new, conf); 305534b232bbSJ. Bruce Fields else /* case 4 (new client) or cases 2, 3 (client reboot): */ 3056c212cecfSStanislav Kinsbursky gen_clid(new, nn); 30578323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 30586f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 3059ac55fdc4SJeff Layton add_to_unconfirmed(new); 30601da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 30611da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 30621da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 30635cc40fd7STrond Myklebust new = NULL; 30641da177e4SLinus Torvalds status = nfs_ok; 30651da177e4SLinus Torvalds out: 30663dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 30675cc40fd7STrond Myklebust if (new) 30685cc40fd7STrond Myklebust free_client(new); 30693dbacee6STrond Myklebust if (unconf) 30703dbacee6STrond Myklebust expire_client(unconf); 30711da177e4SLinus Torvalds return status; 30721da177e4SLinus Torvalds } 30731da177e4SLinus Torvalds 30741da177e4SLinus Torvalds 3075b37ad28bSAl Viro __be32 3076b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 3077b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 3078b591480bSJ.Bruce Fields struct nfsd4_setclientid_confirm *setclientid_confirm) 30791da177e4SLinus Torvalds { 308021ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 3081d20c11d8SJeff Layton struct nfs4_client *old = NULL; 30821da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 30831da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 3084b37ad28bSAl Viro __be32 status; 30857f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 30861da177e4SLinus Torvalds 30872c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 30881da177e4SLinus Torvalds return nfserr_stale_clientid; 308921ab45a4SNeilBrown 3090d20c11d8SJeff Layton spin_lock(&nn->client_lock); 30918daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 30920a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 3093a186e767SJ. Bruce Fields /* 30948695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 30958695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 30968695b90aSJ. Bruce Fields * there's a bug somewhere. Let's charitably assume it's our 30978695b90aSJ. Bruce Fields * bug. 3098a186e767SJ. Bruce Fields */ 30998695b90aSJ. Bruce Fields status = nfserr_serverfault; 31008695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 31018695b90aSJ. Bruce Fields goto out; 31028695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 31038695b90aSJ. Bruce Fields goto out; 310463db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 310590d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 310690d700b7SJ. Bruce Fields if (conf && !unconf) /* case 2: probable retransmit */ 310790d700b7SJ. Bruce Fields status = nfs_ok; 310890d700b7SJ. Bruce Fields else /* case 4: client hasn't noticed we rebooted yet? */ 310990d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 311090d700b7SJ. Bruce Fields goto out; 311190d700b7SJ. Bruce Fields } 311290d700b7SJ. Bruce Fields status = nfs_ok; 311390d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 3114d20c11d8SJeff Layton old = unconf; 3115d20c11d8SJeff Layton unhash_client_locked(old); 31165a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 311790d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 3118d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3119d20c11d8SJeff Layton if (old) { 3120d20c11d8SJeff Layton status = mark_client_expired_locked(old); 31217abea1e8SJeff Layton if (status) { 31227abea1e8SJeff Layton old = NULL; 3123221a6876SJ. Bruce Fields goto out; 3124221a6876SJ. Bruce Fields } 31257abea1e8SJeff Layton } 31261da177e4SLinus Torvalds move_to_confirmed(unconf); 3127d20c11d8SJeff Layton conf = unconf; 312808e8987cSNeilBrown } 3129d20c11d8SJeff Layton get_client_locked(conf); 3130d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3131d20c11d8SJeff Layton nfsd4_probe_callback(conf); 3132d20c11d8SJeff Layton spin_lock(&nn->client_lock); 3133d20c11d8SJeff Layton put_client_renew_locked(conf); 31341da177e4SLinus Torvalds out: 3135d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3136d20c11d8SJeff Layton if (old) 3137d20c11d8SJeff Layton expire_client(old); 31381da177e4SLinus Torvalds return status; 31391da177e4SLinus Torvalds } 31401da177e4SLinus Torvalds 314132513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 31421da177e4SLinus Torvalds { 314332513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 314432513b40SJ. Bruce Fields } 314532513b40SJ. Bruce Fields 314632513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 31475b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, 31485b095e99SJeff Layton struct nfs4_file *fp) 314932513b40SJ. Bruce Fields { 3150950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3151950e0118STrond Myklebust 31528b671b80SJ. Bruce Fields atomic_set(&fp->fi_ref, 1); 31531d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 31548beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 31558beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 31568287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 3157e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 31580c637be8SJeff Layton fp->fi_deleg_file = NULL; 315947f9940cSMeelap Shah fp->fi_had_conflict = false; 3160baeb4ff0SJeff Layton fp->fi_share_deny = 0; 3161f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 3162f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 31639cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 31649cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 3165c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 31669cf514ccSChristoph Hellwig #endif 31675b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 31681da177e4SLinus Torvalds } 31691da177e4SLinus Torvalds 3170e8ff2a84SJ. Bruce Fields void 3171e60d4398SNeilBrown nfsd4_free_slabs(void) 3172e60d4398SNeilBrown { 31738287f009SSachin Bhamare kmem_cache_destroy(odstate_slab); 3174abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3175abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3176abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3177abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3178abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 3179e60d4398SNeilBrown } 31801da177e4SLinus Torvalds 318172083396SBryan Schumaker int 31821da177e4SLinus Torvalds nfsd4_init_slabs(void) 31831da177e4SLinus Torvalds { 3184fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 3185fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 3186fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 3187abf1135bSChristoph Hellwig goto out; 3188fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 31893c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 3190fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 3191abf1135bSChristoph Hellwig goto out_free_openowner_slab; 3192e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 319320c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 3194e60d4398SNeilBrown if (file_slab == NULL) 3195abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 31965ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 3197dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 31985ac049acSNeilBrown if (stateid_slab == NULL) 3199abf1135bSChristoph Hellwig goto out_free_file_slab; 32005b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 320120c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 32025b2d21c1SNeilBrown if (deleg_slab == NULL) 3203abf1135bSChristoph Hellwig goto out_free_stateid_slab; 32048287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 32058287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 32068287f009SSachin Bhamare if (odstate_slab == NULL) 32078287f009SSachin Bhamare goto out_free_deleg_slab; 3208e60d4398SNeilBrown return 0; 3209abf1135bSChristoph Hellwig 32108287f009SSachin Bhamare out_free_deleg_slab: 32118287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 3212abf1135bSChristoph Hellwig out_free_stateid_slab: 3213abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3214abf1135bSChristoph Hellwig out_free_file_slab: 3215abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3216abf1135bSChristoph Hellwig out_free_lockowner_slab: 3217abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3218abf1135bSChristoph Hellwig out_free_openowner_slab: 3219abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3220abf1135bSChristoph Hellwig out: 32211da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 32221da177e4SLinus Torvalds return -ENOMEM; 32231da177e4SLinus Torvalds } 32241da177e4SLinus Torvalds 3225ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 3226ff194bd9SJ. Bruce Fields { 3227ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 3228ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 3229ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 323058fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 323158fb12e6SJeff Layton } 323258fb12e6SJeff Layton 323358fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 323458fb12e6SJeff Layton struct nfs4_stateowner *so) 323558fb12e6SJeff Layton { 323658fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 323758fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 3238b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 323958fb12e6SJeff Layton } 324058fb12e6SJeff Layton } 324158fb12e6SJeff Layton 324258fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 324358fb12e6SJeff Layton { 324458fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 324558fb12e6SJeff Layton 324658fb12e6SJeff Layton if (so != NULL) { 324758fb12e6SJeff Layton cstate->replay_owner = NULL; 324858fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 324958fb12e6SJeff Layton nfs4_put_stateowner(so); 325058fb12e6SJeff Layton } 3251ff194bd9SJ. Bruce Fields } 3252ff194bd9SJ. Bruce Fields 3253fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 32541da177e4SLinus Torvalds { 32551da177e4SLinus Torvalds struct nfs4_stateowner *sop; 32561da177e4SLinus Torvalds 3257fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 3258ff194bd9SJ. Bruce Fields if (!sop) 3259ff194bd9SJ. Bruce Fields return NULL; 3260ff194bd9SJ. Bruce Fields 3261ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 3262ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 3263fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 3264ff194bd9SJ. Bruce Fields return NULL; 3265ff194bd9SJ. Bruce Fields } 32661da177e4SLinus Torvalds sop->so_owner.len = owner->len; 3267ff194bd9SJ. Bruce Fields 3268ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 3269ff194bd9SJ. Bruce Fields sop->so_client = clp; 3270ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 32716b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 32721da177e4SLinus Torvalds return sop; 32731da177e4SLinus Torvalds } 3274ff194bd9SJ. Bruce Fields 3275fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 3276ff194bd9SJ. Bruce Fields { 3277d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 32789b531137SStanislav Kinsbursky 3279d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 3280d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 3281fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 32821da177e4SLinus Torvalds } 32831da177e4SLinus Torvalds 32848f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 32858f4b54c5SJeff Layton { 3286d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 32878f4b54c5SJeff Layton } 32888f4b54c5SJeff Layton 32896b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 32906b180f0bSJeff Layton { 32916b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 32926b180f0bSJeff Layton 32936b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 32946b180f0bSJeff Layton } 32956b180f0bSJeff Layton 32966b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 32978f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 32986b180f0bSJeff Layton .so_free = nfs4_free_openowner, 32996b180f0bSJeff Layton }; 33006b180f0bSJeff Layton 3301fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 330213d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 3303db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 3304db24b3b4SJeff Layton { 330513d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 33067ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 33071da177e4SLinus Torvalds 3308fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 3309fe0750e5SJ. Bruce Fields if (!oo) 33101da177e4SLinus Torvalds return NULL; 33116b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 3312fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 3313fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 3314d3134b10SJeff Layton oo->oo_flags = 0; 3315db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 3316db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 3317fe0750e5SJ. Bruce Fields oo->oo_time = 0; 331838c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 3319fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 3320d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 3321d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 33227ffb5880STrond Myklebust if (ret == NULL) { 3323fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 33247ffb5880STrond Myklebust ret = oo; 33257ffb5880STrond Myklebust } else 3326d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 3327d50ffdedSKinglong Mee 3328d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 3329c5952338SJeff Layton return ret; 33301da177e4SLinus Torvalds } 33311da177e4SLinus Torvalds 3332996e0938SJ. Bruce Fields static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { 3333fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 33341da177e4SLinus Torvalds 3335d6f2bc5dSTrond Myklebust atomic_inc(&stp->st_stid.sc_count); 33363abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 33373c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 3338b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 333913cd2184SNeilBrown get_nfs4_file(fp); 334011b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 33411da177e4SLinus Torvalds stp->st_access_bmap = 0; 33421da177e4SLinus Torvalds stp->st_deny_bmap = 0; 33434c4cd222SNeilBrown stp->st_openstp = NULL; 33441c755dc1SJeff Layton spin_lock(&oo->oo_owner.so_client->cl_lock); 33451c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 33461d31a253STrond Myklebust spin_lock(&fp->fi_lock); 33471d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 33481d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 33491c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 33501da177e4SLinus Torvalds } 33511da177e4SLinus Torvalds 3352d3134b10SJeff Layton /* 3353d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 3354d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 3355d3134b10SJeff Layton * them before returning however. 3356d3134b10SJeff Layton */ 33571da177e4SLinus Torvalds static void 3358d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 33591da177e4SLinus Torvalds { 3360217526e7SJeff Layton struct nfs4_ol_stateid *last; 3361d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 3362d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 3363d3134b10SJeff Layton nfsd_net_id); 336473758fedSStanislav Kinsbursky 3365fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 33661da177e4SLinus Torvalds 3367b401be22SJeff Layton /* 3368b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 3369b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 3370b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 3371b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 3372b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 3373b401be22SJeff Layton * there should be no danger of the refcount going back up again at 3374b401be22SJeff Layton * this point. 3375b401be22SJeff Layton */ 3376b401be22SJeff Layton wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2); 3377b401be22SJeff Layton 3378d3134b10SJeff Layton release_all_access(s); 3379d3134b10SJeff Layton if (s->st_stid.sc_file) { 3380d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 3381d3134b10SJeff Layton s->st_stid.sc_file = NULL; 3382d3134b10SJeff Layton } 3383217526e7SJeff Layton 3384217526e7SJeff Layton spin_lock(&nn->client_lock); 3385217526e7SJeff Layton last = oo->oo_last_closed_stid; 3386d3134b10SJeff Layton oo->oo_last_closed_stid = s; 338773758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 3388fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 3389217526e7SJeff Layton spin_unlock(&nn->client_lock); 3390217526e7SJeff Layton if (last) 3391217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 33921da177e4SLinus Torvalds } 33931da177e4SLinus Torvalds 33941da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 33951da177e4SLinus Torvalds static struct nfs4_file * 33965b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval) 33971da177e4SLinus Torvalds { 33981da177e4SLinus Torvalds struct nfs4_file *fp; 33991da177e4SLinus Torvalds 34005b095e99SJeff Layton hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { 34014d94c2efSChristoph Hellwig if (fh_match(&fp->fi_fhandle, fh)) { 34025b095e99SJeff Layton if (atomic_inc_not_zero(&fp->fi_ref)) 34031da177e4SLinus Torvalds return fp; 34041da177e4SLinus Torvalds } 340513cd2184SNeilBrown } 34061da177e4SLinus Torvalds return NULL; 34071da177e4SLinus Torvalds } 34081da177e4SLinus Torvalds 3409e6ba76e1SChristoph Hellwig struct nfs4_file * 3410ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 3411950e0118STrond Myklebust { 3412950e0118STrond Myklebust struct nfs4_file *fp; 34135b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 3414950e0118STrond Myklebust 34155b095e99SJeff Layton rcu_read_lock(); 34165b095e99SJeff Layton fp = find_file_locked(fh, hashval); 34175b095e99SJeff Layton rcu_read_unlock(); 3418950e0118STrond Myklebust return fp; 3419950e0118STrond Myklebust } 3420950e0118STrond Myklebust 3421950e0118STrond Myklebust static struct nfs4_file * 3422f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 3423950e0118STrond Myklebust { 3424950e0118STrond Myklebust struct nfs4_file *fp; 34255b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 34265b095e99SJeff Layton 34275b095e99SJeff Layton rcu_read_lock(); 34285b095e99SJeff Layton fp = find_file_locked(fh, hashval); 34295b095e99SJeff Layton rcu_read_unlock(); 34305b095e99SJeff Layton if (fp) 34315b095e99SJeff Layton return fp; 3432950e0118STrond Myklebust 3433950e0118STrond Myklebust spin_lock(&state_lock); 34345b095e99SJeff Layton fp = find_file_locked(fh, hashval); 34355b095e99SJeff Layton if (likely(fp == NULL)) { 34365b095e99SJeff Layton nfsd4_init_file(fh, hashval, new); 3437950e0118STrond Myklebust fp = new; 3438950e0118STrond Myklebust } 3439950e0118STrond Myklebust spin_unlock(&state_lock); 3440950e0118STrond Myklebust 3441950e0118STrond Myklebust return fp; 3442950e0118STrond Myklebust } 3443950e0118STrond Myklebust 34444f83aa30SJ. Bruce Fields /* 34451da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 34461da177e4SLinus Torvalds * WRITE with all zero or all one stateid 34471da177e4SLinus Torvalds */ 3448b37ad28bSAl Viro static __be32 34491da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 34501da177e4SLinus Torvalds { 34511da177e4SLinus Torvalds struct nfs4_file *fp; 3452baeb4ff0SJeff Layton __be32 ret = nfs_ok; 34531da177e4SLinus Torvalds 3454ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 345513cd2184SNeilBrown if (!fp) 3456baeb4ff0SJeff Layton return ret; 3457baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 34581d31a253STrond Myklebust spin_lock(&fp->fi_lock); 3459baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 3460baeb4ff0SJeff Layton ret = nfserr_locked; 34611d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 346213cd2184SNeilBrown put_nfs4_file(fp); 346313cd2184SNeilBrown return ret; 34641da177e4SLinus Torvalds } 34651da177e4SLinus Torvalds 34660162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 34671da177e4SLinus Torvalds { 34680162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 346911b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 347011b9164aSTrond Myklebust nfsd_net_id); 3471e8c69d17SJ. Bruce Fields 347211b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 3473f54fe962SJeff Layton 347402e1215fSJeff Layton /* 347502e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 3476f54fe962SJeff Layton * already holding inode->i_lock. 3477f54fe962SJeff Layton * 3478dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 3479dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 3480dff1399fSJeff Layton */ 3481f54fe962SJeff Layton spin_lock(&state_lock); 3482dff1399fSJeff Layton if (dp->dl_time == 0) { 34831da177e4SLinus Torvalds dp->dl_time = get_seconds(); 348402e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 348502e1215fSJeff Layton } 348602e1215fSJeff Layton spin_unlock(&state_lock); 3487dff1399fSJeff Layton } 34881da177e4SLinus Torvalds 34890162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 34900162ac2bSChristoph Hellwig struct rpc_task *task) 34910162ac2bSChristoph Hellwig { 34920162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 34930162ac2bSChristoph Hellwig 34940162ac2bSChristoph Hellwig switch (task->tk_status) { 34950162ac2bSChristoph Hellwig case 0: 34960162ac2bSChristoph Hellwig return 1; 34970162ac2bSChristoph Hellwig case -EBADHANDLE: 34980162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 34990162ac2bSChristoph Hellwig /* 35000162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 35010162ac2bSChristoph Hellwig * granting delegation. 35020162ac2bSChristoph Hellwig */ 35030162ac2bSChristoph Hellwig if (dp->dl_retries--) { 35040162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 35050162ac2bSChristoph Hellwig return 0; 35060162ac2bSChristoph Hellwig } 35070162ac2bSChristoph Hellwig /*FALLTHRU*/ 35080162ac2bSChristoph Hellwig default: 35090162ac2bSChristoph Hellwig return -1; 35100162ac2bSChristoph Hellwig } 35110162ac2bSChristoph Hellwig } 35120162ac2bSChristoph Hellwig 35130162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 35140162ac2bSChristoph Hellwig { 35150162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 35160162ac2bSChristoph Hellwig 35170162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 35180162ac2bSChristoph Hellwig } 35190162ac2bSChristoph Hellwig 35200162ac2bSChristoph Hellwig static struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 35210162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 35220162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 35230162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 35240162ac2bSChristoph Hellwig }; 35250162ac2bSChristoph Hellwig 352602e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 352702e1215fSJeff Layton { 352802e1215fSJeff Layton /* 352902e1215fSJeff Layton * We're assuming the state code never drops its reference 353002e1215fSJeff Layton * without first removing the lease. Since we're in this lease 353102e1215fSJeff Layton * callback (and since the lease code is serialized by the kernel 353202e1215fSJeff Layton * lock) we know the server hasn't removed the lease yet, we know 353302e1215fSJeff Layton * it's safe to take a reference. 353402e1215fSJeff Layton */ 353572c0b0fbSTrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 3536f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 35376b57d9c8SJ. Bruce Fields } 35386b57d9c8SJ. Bruce Fields 35391c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 35404d01b7f5SJeff Layton static bool 35414d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 35426b57d9c8SJ. Bruce Fields { 35434d01b7f5SJeff Layton bool ret = false; 3544acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 3545acfdf5c3SJ. Bruce Fields struct nfs4_delegation *dp; 35466b57d9c8SJ. Bruce Fields 35477fa10cd1SJ. Bruce Fields if (!fp) { 35487fa10cd1SJ. Bruce Fields WARN(1, "(%p)->fl_owner NULL\n", fl); 35494d01b7f5SJeff Layton return ret; 35507fa10cd1SJ. Bruce Fields } 35517fa10cd1SJ. Bruce Fields if (fp->fi_had_conflict) { 35527fa10cd1SJ. Bruce Fields WARN(1, "duplicate break on %p\n", fp); 35534d01b7f5SJeff Layton return ret; 35547fa10cd1SJ. Bruce Fields } 35550272e1fdSJ. Bruce Fields /* 35560272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 3557acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 35586b57d9c8SJ. Bruce Fields * in time: 35590272e1fdSJ. Bruce Fields */ 35600272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 35611da177e4SLinus Torvalds 356202e1215fSJeff Layton spin_lock(&fp->fi_lock); 3563417c6629SJeff Layton fp->fi_had_conflict = true; 3564417c6629SJeff Layton /* 35654d01b7f5SJeff Layton * If there are no delegations on the list, then return true 35664d01b7f5SJeff Layton * so that the lease code will go ahead and delete it. 3567417c6629SJeff Layton */ 3568417c6629SJeff Layton if (list_empty(&fp->fi_delegations)) 35694d01b7f5SJeff Layton ret = true; 3570417c6629SJeff Layton else 3571acfdf5c3SJ. Bruce Fields list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 35725d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 357302e1215fSJeff Layton spin_unlock(&fp->fi_lock); 35744d01b7f5SJeff Layton return ret; 35751da177e4SLinus Torvalds } 35761da177e4SLinus Torvalds 3577c45198edSJeff Layton static int 35787448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 35797448cc37SJeff Layton struct list_head *dispose) 35801da177e4SLinus Torvalds { 35811da177e4SLinus Torvalds if (arg & F_UNLCK) 3582c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 35831da177e4SLinus Torvalds else 35841da177e4SLinus Torvalds return -EAGAIN; 35851da177e4SLinus Torvalds } 35861da177e4SLinus Torvalds 35877b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 35888fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 35898fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 35901da177e4SLinus Torvalds }; 35911da177e4SLinus Torvalds 35927a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 35937a8711c9SJ. Bruce Fields { 35947a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 35957a8711c9SJ. Bruce Fields return nfs_ok; 35967a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 35977a8711c9SJ. Bruce Fields return nfserr_replay_me; 35987a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 35997a8711c9SJ. Bruce Fields return nfs_ok; 36007a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 36017a8711c9SJ. Bruce Fields } 36021da177e4SLinus Torvalds 36034b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 36044b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 36054b24ca7dSJeff Layton struct nfsd_net *nn) 36064b24ca7dSJeff Layton { 36074b24ca7dSJeff Layton struct nfs4_client *found; 36084b24ca7dSJeff Layton 36094b24ca7dSJeff Layton if (cstate->clp) { 36104b24ca7dSJeff Layton found = cstate->clp; 36114b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 36124b24ca7dSJeff Layton return nfserr_stale_clientid; 36134b24ca7dSJeff Layton return nfs_ok; 36144b24ca7dSJeff Layton } 36154b24ca7dSJeff Layton 36164b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 36174b24ca7dSJeff Layton return nfserr_stale_clientid; 36184b24ca7dSJeff Layton 36194b24ca7dSJeff Layton /* 36204b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 36214b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 36224b24ca7dSJeff Layton * will be false. 36234b24ca7dSJeff Layton */ 36244b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 36253e339f96STrond Myklebust spin_lock(&nn->client_lock); 36264b24ca7dSJeff Layton found = find_confirmed_client(clid, false, nn); 36273e339f96STrond Myklebust if (!found) { 36283e339f96STrond Myklebust spin_unlock(&nn->client_lock); 36294b24ca7dSJeff Layton return nfserr_expired; 36303e339f96STrond Myklebust } 36313e339f96STrond Myklebust atomic_inc(&found->cl_refcount); 36323e339f96STrond Myklebust spin_unlock(&nn->client_lock); 36334b24ca7dSJeff Layton 36344b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 36354b24ca7dSJeff Layton cstate->clp = found; 36364b24ca7dSJeff Layton return nfs_ok; 36374b24ca7dSJeff Layton } 36384b24ca7dSJeff Layton 3639b37ad28bSAl Viro __be32 36406668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 36413320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 36421da177e4SLinus Torvalds { 36431da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 36441da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 36451da177e4SLinus Torvalds unsigned int strhashval; 3646fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 36474cdc951bSJ. Bruce Fields __be32 status; 36481da177e4SLinus Torvalds 36492c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 36501da177e4SLinus Torvalds return nfserr_stale_clientid; 365132513b40SJ. Bruce Fields /* 365232513b40SJ. Bruce Fields * In case we need it later, after we've already created the 365332513b40SJ. Bruce Fields * file and don't want to risk a further failure: 365432513b40SJ. Bruce Fields */ 365532513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 365632513b40SJ. Bruce Fields if (open->op_file == NULL) 365732513b40SJ. Bruce Fields return nfserr_jukebox; 36581da177e4SLinus Torvalds 365913d6f66bSTrond Myklebust status = lookup_clientid(clientid, cstate, nn); 366013d6f66bSTrond Myklebust if (status) 366113d6f66bSTrond Myklebust return status; 366213d6f66bSTrond Myklebust clp = cstate->clp; 36632d91e895STrond Myklebust 3664d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 3665d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 36662d91e895STrond Myklebust open->op_openowner = oo; 36672d91e895STrond Myklebust if (!oo) { 3668bcf130f9SJ. Bruce Fields goto new_owner; 36690f442aa2SJ. Bruce Fields } 3670dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 36710f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 3672fe0750e5SJ. Bruce Fields release_openowner(oo); 3673fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 3674bcf130f9SJ. Bruce Fields goto new_owner; 36750f442aa2SJ. Bruce Fields } 36764cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 36774cdc951bSJ. Bruce Fields if (status) 36784cdc951bSJ. Bruce Fields return status; 36794cdc951bSJ. Bruce Fields goto alloc_stateid; 3680bcf130f9SJ. Bruce Fields new_owner: 368113d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 3682fe0750e5SJ. Bruce Fields if (oo == NULL) 36833e772463SJ. Bruce Fields return nfserr_jukebox; 3684fe0750e5SJ. Bruce Fields open->op_openowner = oo; 36854cdc951bSJ. Bruce Fields alloc_stateid: 3686b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 36874cdc951bSJ. Bruce Fields if (!open->op_stp) 36884cdc951bSJ. Bruce Fields return nfserr_jukebox; 36898287f009SSachin Bhamare 36908287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 36918287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 36928287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 36938287f009SSachin Bhamare if (!open->op_odstate) 36948287f009SSachin Bhamare return nfserr_jukebox; 36958287f009SSachin Bhamare } 36968287f009SSachin Bhamare 36970f442aa2SJ. Bruce Fields return nfs_ok; 36981da177e4SLinus Torvalds } 36991da177e4SLinus Torvalds 3700b37ad28bSAl Viro static inline __be32 37014a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 37024a6e43e6SNeilBrown { 37034a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 37044a6e43e6SNeilBrown return nfserr_openmode; 37054a6e43e6SNeilBrown else 37064a6e43e6SNeilBrown return nfs_ok; 37074a6e43e6SNeilBrown } 37084a6e43e6SNeilBrown 3709c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 371024a0111eSJ. Bruce Fields { 371124a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 371224a0111eSJ. Bruce Fields } 371324a0111eSJ. Bruce Fields 371438c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 3715f459e453SJ. Bruce Fields { 3716f459e453SJ. Bruce Fields struct nfs4_stid *ret; 3717f459e453SJ. Bruce Fields 371838c2f4b1SJ. Bruce Fields ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); 3719f459e453SJ. Bruce Fields if (!ret) 3720f459e453SJ. Bruce Fields return NULL; 3721f459e453SJ. Bruce Fields return delegstateid(ret); 3722f459e453SJ. Bruce Fields } 3723f459e453SJ. Bruce Fields 37248b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 37258b289b2cSJ. Bruce Fields { 37268b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 37278b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 37288b289b2cSJ. Bruce Fields } 37298b289b2cSJ. Bruce Fields 3730b37ad28bSAl Viro static __be32 373141d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 3732567d9829SNeilBrown struct nfs4_delegation **dp) 3733567d9829SNeilBrown { 3734567d9829SNeilBrown int flags; 3735b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 3736dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 3737567d9829SNeilBrown 3738dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 3739dcd94cc2STrond Myklebust if (deleg == NULL) 3740c44c5eebSNeilBrown goto out; 374124a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 3742dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 3743dcd94cc2STrond Myklebust if (status) { 3744dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 3745dcd94cc2STrond Myklebust goto out; 3746dcd94cc2STrond Myklebust } 3747dcd94cc2STrond Myklebust *dp = deleg; 3748c44c5eebSNeilBrown out: 37498b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 3750c44c5eebSNeilBrown return nfs_ok; 3751c44c5eebSNeilBrown if (status) 3752c44c5eebSNeilBrown return status; 3753dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 3754c44c5eebSNeilBrown return nfs_ok; 3755567d9829SNeilBrown } 3756567d9829SNeilBrown 3757a46cb7f2SJeff Layton static struct nfs4_ol_stateid * 3758a46cb7f2SJeff Layton nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 37591da177e4SLinus Torvalds { 3760a46cb7f2SJeff Layton struct nfs4_ol_stateid *local, *ret = NULL; 3761fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 37621da177e4SLinus Torvalds 37631d31a253STrond Myklebust spin_lock(&fp->fi_lock); 37648beefa24SNeilBrown list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 37651da177e4SLinus Torvalds /* ignore lock owners */ 37661da177e4SLinus Torvalds if (local->st_stateowner->so_is_open_owner == 0) 37671da177e4SLinus Torvalds continue; 3768baeb4ff0SJeff Layton if (local->st_stateowner == &oo->oo_owner) { 3769a46cb7f2SJeff Layton ret = local; 3770d6f2bc5dSTrond Myklebust atomic_inc(&ret->st_stid.sc_count); 3771baeb4ff0SJeff Layton break; 37721da177e4SLinus Torvalds } 37731d31a253STrond Myklebust } 37741d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 3775a46cb7f2SJeff Layton return ret; 37761da177e4SLinus Torvalds } 37771da177e4SLinus Torvalds 377821fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 377921fb4016SJ. Bruce Fields { 378021fb4016SJ. Bruce Fields int flags = 0; 378121fb4016SJ. Bruce Fields 378221fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 378321fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 378421fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 378521fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 378621fb4016SJ. Bruce Fields return flags; 378721fb4016SJ. Bruce Fields } 378821fb4016SJ. Bruce Fields 3789b37ad28bSAl Viro static inline __be32 37901da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 37911da177e4SLinus Torvalds struct nfsd4_open *open) 37921da177e4SLinus Torvalds { 37931da177e4SLinus Torvalds struct iattr iattr = { 37941da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 37951da177e4SLinus Torvalds .ia_size = 0, 37961da177e4SLinus Torvalds }; 37971da177e4SLinus Torvalds if (!open->op_truncate) 37981da177e4SLinus Torvalds return 0; 37991da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 38009246585aSAl Viro return nfserr_inval; 38011da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 38021da177e4SLinus Torvalds } 38031da177e4SLinus Torvalds 38047e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 38056eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 38066eb3a1d0SJeff Layton struct nfsd4_open *open) 38077e6a72e5SChristoph Hellwig { 3808de18643dSTrond Myklebust struct file *filp = NULL; 38097e6a72e5SChristoph Hellwig __be32 status; 38107e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 38117e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 3812baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 38137e6a72e5SChristoph Hellwig 3814de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3815baeb4ff0SJeff Layton 3816baeb4ff0SJeff Layton /* 3817baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 3818baeb4ff0SJeff Layton * current access? 3819baeb4ff0SJeff Layton */ 3820baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 3821baeb4ff0SJeff Layton if (status != nfs_ok) { 3822baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3823baeb4ff0SJeff Layton goto out; 3824baeb4ff0SJeff Layton } 3825baeb4ff0SJeff Layton 3826baeb4ff0SJeff Layton /* set access to the file */ 3827baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 3828baeb4ff0SJeff Layton if (status != nfs_ok) { 3829baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3830baeb4ff0SJeff Layton goto out; 3831baeb4ff0SJeff Layton } 3832baeb4ff0SJeff Layton 3833baeb4ff0SJeff Layton /* Set access bits in stateid */ 3834baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 3835baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 3836baeb4ff0SJeff Layton 3837baeb4ff0SJeff Layton /* Set new deny mask */ 3838baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 3839baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 3840baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 3841baeb4ff0SJeff Layton 38427e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 3843de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3844de18643dSTrond Myklebust status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); 38457e6a72e5SChristoph Hellwig if (status) 3846baeb4ff0SJeff Layton goto out_put_access; 3847de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3848de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 3849de18643dSTrond Myklebust fp->fi_fds[oflag] = filp; 3850de18643dSTrond Myklebust filp = NULL; 3851de18643dSTrond Myklebust } 38527e6a72e5SChristoph Hellwig } 3853de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3854de18643dSTrond Myklebust if (filp) 3855de18643dSTrond Myklebust fput(filp); 38567e6a72e5SChristoph Hellwig 38577e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 38587e6a72e5SChristoph Hellwig if (status) 38597e6a72e5SChristoph Hellwig goto out_put_access; 38607e6a72e5SChristoph Hellwig out: 38617e6a72e5SChristoph Hellwig return status; 3862baeb4ff0SJeff Layton out_put_access: 3863baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 3864baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 3865baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 3866baeb4ff0SJeff Layton goto out; 38677e6a72e5SChristoph Hellwig } 38687e6a72e5SChristoph Hellwig 3869b37ad28bSAl Viro static __be32 3870dcef0413SJ. 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) 38711da177e4SLinus Torvalds { 3872b37ad28bSAl Viro __be32 status; 38736ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 38741da177e4SLinus Torvalds 38756eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 3876baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 38777e6a72e5SChristoph Hellwig 3878baeb4ff0SJeff Layton /* test and set deny mode */ 3879baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 3880baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 3881baeb4ff0SJeff Layton if (status == nfs_ok) { 3882baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 3883baeb4ff0SJeff Layton fp->fi_share_deny |= 3884baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 38851da177e4SLinus Torvalds } 3886baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 38871da177e4SLinus Torvalds 3888baeb4ff0SJeff Layton if (status != nfs_ok) 3889baeb4ff0SJeff Layton return status; 3890baeb4ff0SJeff Layton 3891baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 3892baeb4ff0SJeff Layton if (status != nfs_ok) 3893baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 3894baeb4ff0SJeff Layton return status; 3895baeb4ff0SJeff Layton } 38961da177e4SLinus Torvalds 38971da177e4SLinus Torvalds static void 38981255a8f3SJ. Bruce Fields nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session) 38991da177e4SLinus Torvalds { 3900dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 39011da177e4SLinus Torvalds } 39021da177e4SLinus Torvalds 390314a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 390414a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 390514a24e99SJ. Bruce Fields { 390614a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 390714a24e99SJ. Bruce Fields return true; 390814a24e99SJ. Bruce Fields /* 390914a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 391014a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 391114a24e99SJ. Bruce Fields * until we hear otherwise: 391214a24e99SJ. Bruce Fields */ 391314a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 391414a24e99SJ. Bruce Fields } 391514a24e99SJ. Bruce Fields 3916d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag) 391722d38c4cSJ. Bruce Fields { 391822d38c4cSJ. Bruce Fields struct file_lock *fl; 391922d38c4cSJ. Bruce Fields 392022d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 392122d38c4cSJ. Bruce Fields if (!fl) 392222d38c4cSJ. Bruce Fields return NULL; 392322d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 3924617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 392522d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 392622d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 3927d564fbecSJeff Layton fl->fl_owner = (fl_owner_t)fp; 392822d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 392922d38c4cSJ. Bruce Fields return fl; 393022d38c4cSJ. Bruce Fields } 393122d38c4cSJ. Bruce Fields 393299c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp) 3933edab9782SJ. Bruce Fields { 393411b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 3935415b96c5SJeff Layton struct file_lock *fl, *ret; 3936417c6629SJeff Layton struct file *filp; 3937417c6629SJeff Layton int status = 0; 3938edab9782SJ. Bruce Fields 3939d564fbecSJeff Layton fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ); 3940edab9782SJ. Bruce Fields if (!fl) 3941edab9782SJ. Bruce Fields return -ENOMEM; 3942417c6629SJeff Layton filp = find_readable_file(fp); 3943417c6629SJeff Layton if (!filp) { 3944417c6629SJeff Layton /* We should always have a readable file here */ 3945417c6629SJeff Layton WARN_ON_ONCE(1); 3946af9dbaf4SKinglong Mee locks_free_lock(fl); 3947417c6629SJeff Layton return -EBADF; 3948417c6629SJeff Layton } 3949417c6629SJeff Layton fl->fl_file = filp; 3950415b96c5SJeff Layton ret = fl; 3951e6f5c789SJeff Layton status = vfs_setlease(filp, fl->fl_type, &fl, NULL); 39521c7dd2ffSJeff Layton if (fl) 3953417c6629SJeff Layton locks_free_lock(fl); 39541c7dd2ffSJeff Layton if (status) 3955417c6629SJeff Layton goto out_fput; 3956cdc97505SBenny Halevy spin_lock(&state_lock); 3957417c6629SJeff Layton spin_lock(&fp->fi_lock); 3958417c6629SJeff Layton /* Did the lease get broken before we took the lock? */ 3959417c6629SJeff Layton status = -EAGAIN; 3960417c6629SJeff Layton if (fp->fi_had_conflict) 3961417c6629SJeff Layton goto out_unlock; 3962417c6629SJeff Layton /* Race breaker */ 39630c637be8SJeff Layton if (fp->fi_deleg_file) { 3964417c6629SJeff Layton status = 0; 396567db1034SJeff Layton ++fp->fi_delegees; 3966931ee56cSBenny Halevy hash_delegation_locked(dp, fp); 3967417c6629SJeff Layton goto out_unlock; 3968417c6629SJeff Layton } 3969417c6629SJeff Layton fp->fi_deleg_file = filp; 397067db1034SJeff Layton fp->fi_delegees = 1; 3971417c6629SJeff Layton hash_delegation_locked(dp, fp); 3972417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3973cdc97505SBenny Halevy spin_unlock(&state_lock); 3974acfdf5c3SJ. Bruce Fields return 0; 3975417c6629SJeff Layton out_unlock: 3976417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3977417c6629SJeff Layton spin_unlock(&state_lock); 3978417c6629SJeff Layton out_fput: 3979417c6629SJeff Layton fput(filp); 3980e873088fSJ. Bruce Fields return status; 3981acfdf5c3SJ. Bruce Fields } 3982acfdf5c3SJ. Bruce Fields 39830b26693cSJeff Layton static struct nfs4_delegation * 39840b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 39858287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 3986acfdf5c3SJ. Bruce Fields { 39870b26693cSJeff Layton int status; 39880b26693cSJeff Layton struct nfs4_delegation *dp; 3989417c6629SJeff Layton 3990bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 39910b26693cSJeff Layton return ERR_PTR(-EAGAIN); 39920b26693cSJeff Layton 39938287f009SSachin Bhamare dp = alloc_init_deleg(clp, fh, odstate); 39940b26693cSJeff Layton if (!dp) 39950b26693cSJeff Layton return ERR_PTR(-ENOMEM); 39960b26693cSJeff Layton 3997bf7bd3e9SJ. Bruce Fields get_nfs4_file(fp); 3998cdc97505SBenny Halevy spin_lock(&state_lock); 3999417c6629SJeff Layton spin_lock(&fp->fi_lock); 400011b9164aSTrond Myklebust dp->dl_stid.sc_file = fp; 40010c637be8SJeff Layton if (!fp->fi_deleg_file) { 4002417c6629SJeff Layton spin_unlock(&fp->fi_lock); 4003417c6629SJeff Layton spin_unlock(&state_lock); 40040b26693cSJeff Layton status = nfs4_setlease(dp); 40050b26693cSJeff Layton goto out; 4006417c6629SJeff Layton } 4007acfdf5c3SJ. Bruce Fields if (fp->fi_had_conflict) { 4008417c6629SJeff Layton status = -EAGAIN; 4009417c6629SJeff Layton goto out_unlock; 4010acfdf5c3SJ. Bruce Fields } 401167db1034SJeff Layton ++fp->fi_delegees; 4012931ee56cSBenny Halevy hash_delegation_locked(dp, fp); 40130b26693cSJeff Layton status = 0; 4014417c6629SJeff Layton out_unlock: 4015417c6629SJeff Layton spin_unlock(&fp->fi_lock); 4016cdc97505SBenny Halevy spin_unlock(&state_lock); 40170b26693cSJeff Layton out: 40180b26693cSJeff Layton if (status) { 40198287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 40206011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 40210b26693cSJeff Layton return ERR_PTR(status); 40220b26693cSJeff Layton } 40230b26693cSJeff Layton return dp; 4024edab9782SJ. Bruce Fields } 4025edab9782SJ. Bruce Fields 40264aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 40274aa8913cSBenny Halevy { 40284aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 40294aa8913cSBenny Halevy if (status == -EAGAIN) 40304aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 40314aa8913cSBenny Halevy else { 40324aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 40334aa8913cSBenny Halevy switch (open->op_deleg_want) { 40344aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 40354aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 40364aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 40374aa8913cSBenny Halevy break; 40384aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 40394aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 40404aa8913cSBenny Halevy break; 40414aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 4042063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 40434aa8913cSBenny Halevy } 40444aa8913cSBenny Halevy } 40454aa8913cSBenny Halevy } 40464aa8913cSBenny Halevy 40471da177e4SLinus Torvalds /* 40481da177e4SLinus Torvalds * Attempt to hand out a delegation. 404999c41515SJ. Bruce Fields * 405099c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 405199c41515SJ. Bruce Fields * proper support for them. 40521da177e4SLinus Torvalds */ 40531da177e4SLinus Torvalds static void 40544cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 40554cf59221SJeff Layton struct nfs4_ol_stateid *stp) 40561da177e4SLinus Torvalds { 40571da177e4SLinus Torvalds struct nfs4_delegation *dp; 40584cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 40594cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 406014a24e99SJ. Bruce Fields int cb_up; 406199c41515SJ. Bruce Fields int status = 0; 40621da177e4SLinus Torvalds 4063fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 40647b190fecSNeilBrown open->op_recall = 0; 40657b190fecSNeilBrown switch (open->op_claim_type) { 40667b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 40672bf23875SJ. Bruce Fields if (!cb_up) 40687b190fecSNeilBrown open->op_recall = 1; 406999c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 407099c41515SJ. Bruce Fields goto out_no_deleg; 40717b190fecSNeilBrown break; 40727b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 4073ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 407499c41515SJ. Bruce Fields /* 407599c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 407699c41515SJ. Bruce Fields * had the chance to reclaim theirs.... 407799c41515SJ. Bruce Fields */ 40784cf59221SJeff Layton if (locks_in_grace(clp->net)) 407999c41515SJ. Bruce Fields goto out_no_deleg; 4080dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 408199c41515SJ. Bruce Fields goto out_no_deleg; 40829a0590aeSSteve Dickson /* 40839a0590aeSSteve Dickson * Also, if the file was opened for write or 40849a0590aeSSteve Dickson * create, there's a good chance the client's 40859a0590aeSSteve Dickson * about to write to it, resulting in an 40869a0590aeSSteve Dickson * immediate recall (since we don't support 40879a0590aeSSteve Dickson * write delegations): 40889a0590aeSSteve Dickson */ 40891da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 409099c41515SJ. Bruce Fields goto out_no_deleg; 409199c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 409299c41515SJ. Bruce Fields goto out_no_deleg; 40937b190fecSNeilBrown break; 40947b190fecSNeilBrown default: 409599c41515SJ. Bruce Fields goto out_no_deleg; 40967b190fecSNeilBrown } 40978287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 40980b26693cSJeff Layton if (IS_ERR(dp)) 4099dd239cc0SJ. Bruce Fields goto out_no_deleg; 41001da177e4SLinus Torvalds 4101d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 41021da177e4SLinus Torvalds 41038c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 4104d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 410599c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 410667cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4107dd239cc0SJ. Bruce Fields return; 4108dd239cc0SJ. Bruce Fields out_no_deleg: 410999c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 41107b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 4111d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 41121da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 4113d08d32e6SJ. Bruce Fields open->op_recall = 1; 4114d08d32e6SJ. Bruce Fields } 4115dd239cc0SJ. Bruce Fields 4116dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 4117dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 4118dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 4119dd239cc0SJ. Bruce Fields return; 41201da177e4SLinus Torvalds } 41211da177e4SLinus Torvalds 4122e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 4123e27f49c3SBenny Halevy struct nfs4_delegation *dp) 4124e27f49c3SBenny Halevy { 4125e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 4126e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4127e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4128e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 4129e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 4130e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4131e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4132e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 4133e27f49c3SBenny Halevy } 4134e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 4135e27f49c3SBenny Halevy * it already has, therefore we don't return 4136e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 4137e27f49c3SBenny Halevy */ 4138e27f49c3SBenny Halevy } 4139e27f49c3SBenny Halevy 4140b37ad28bSAl Viro __be32 41411da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 41421da177e4SLinus Torvalds { 41436668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 414438c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 41451da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 4146dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 4147567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 4148b37ad28bSAl Viro __be32 status; 41491da177e4SLinus Torvalds 41501da177e4SLinus Torvalds /* 41511da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 41521da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 41531da177e4SLinus Torvalds * If not found, create the nfs4_file struct 41541da177e4SLinus Torvalds */ 4155f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 4156950e0118STrond Myklebust if (fp != open->op_file) { 415741d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 4158c44c5eebSNeilBrown if (status) 4159c44c5eebSNeilBrown goto out; 4160a46cb7f2SJeff Layton stp = nfsd4_find_existing_open(fp, open); 41611da177e4SLinus Torvalds } else { 4162950e0118STrond Myklebust open->op_file = NULL; 4163c44c5eebSNeilBrown status = nfserr_bad_stateid; 41648b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 4165c44c5eebSNeilBrown goto out; 41661da177e4SLinus Torvalds } 41671da177e4SLinus Torvalds 41681da177e4SLinus Torvalds /* 41691da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 41701da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 41711da177e4SLinus Torvalds */ 41721da177e4SLinus Torvalds if (stp) { 41731da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 4174f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 41751da177e4SLinus Torvalds if (status) 41761da177e4SLinus Torvalds goto out; 41771da177e4SLinus Torvalds } else { 41784cdc951bSJ. Bruce Fields stp = open->op_stp; 41794cdc951bSJ. Bruce Fields open->op_stp = NULL; 4180996e0938SJ. Bruce Fields init_open_stateid(stp, fp, open); 41816eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 41826eb3a1d0SJeff Layton if (status) { 41836eb3a1d0SJeff Layton release_open_stateid(stp); 41846eb3a1d0SJeff Layton goto out; 41856eb3a1d0SJeff Layton } 41868287f009SSachin Bhamare 41878287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 41888287f009SSachin Bhamare open->op_odstate); 41898287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 41908287f009SSachin Bhamare open->op_odstate = NULL; 41911da177e4SLinus Torvalds } 4192dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4193dcef0413SJ. Bruce Fields memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 41941da177e4SLinus Torvalds 4195d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 4196d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 4197d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4198d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 4199d24433cdSBenny Halevy goto nodeleg; 4200d24433cdSBenny Halevy } 4201d24433cdSBenny Halevy } 4202d24433cdSBenny Halevy 42031da177e4SLinus Torvalds /* 42041da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 42051da177e4SLinus Torvalds * OPEN succeeds even if we fail. 42061da177e4SLinus Torvalds */ 42074cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 4208d24433cdSBenny Halevy nodeleg: 42091da177e4SLinus Torvalds status = nfs_ok; 42101da177e4SLinus Torvalds 42118c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 4212dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 42131da177e4SLinus Torvalds out: 4214d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 4215d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 4216e27f49c3SBenny Halevy open->op_deleg_want) 4217e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 4218d24433cdSBenny Halevy 421913cd2184SNeilBrown if (fp) 422013cd2184SNeilBrown put_nfs4_file(fp); 422137515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 42221255a8f3SJ. Bruce Fields nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate)); 42231da177e4SLinus Torvalds /* 42241da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 42251da177e4SLinus Torvalds */ 42261da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 4227dad1c067SJ. Bruce Fields if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) && 42286668958fSAndy Adamson !nfsd4_has_session(&resp->cstate)) 42291da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 4230dcd94cc2STrond Myklebust if (dp) 4231dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4232d6f2bc5dSTrond Myklebust if (stp) 4233d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 42341da177e4SLinus Torvalds 42351da177e4SLinus Torvalds return status; 42361da177e4SLinus Torvalds } 42371da177e4SLinus Torvalds 423858fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 423942297899SJeff Layton struct nfsd4_open *open) 4240d29b20cdSJ. Bruce Fields { 4241d29b20cdSJ. Bruce Fields if (open->op_openowner) { 4242d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 4243d29b20cdSJ. Bruce Fields 4244d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 4245d3134b10SJeff Layton nfs4_put_stateowner(so); 4246d29b20cdSJ. Bruce Fields } 424732513b40SJ. Bruce Fields if (open->op_file) 42485b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 42494cdc951bSJ. Bruce Fields if (open->op_stp) 42506011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 42518287f009SSachin Bhamare if (open->op_odstate) 42528287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 4253d29b20cdSJ. Bruce Fields } 4254d29b20cdSJ. Bruce Fields 4255b37ad28bSAl Viro __be32 4256b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4257b591480bSJ.Bruce Fields clientid_t *clid) 42581da177e4SLinus Torvalds { 42591da177e4SLinus Torvalds struct nfs4_client *clp; 4260b37ad28bSAl Viro __be32 status; 42617f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 42621da177e4SLinus Torvalds 42631da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 42641da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 42654b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 42669b2ef62bSJ. Bruce Fields if (status) 42671da177e4SLinus Torvalds goto out; 42684b24ca7dSJeff Layton clp = cstate->clp; 42691da177e4SLinus Torvalds status = nfserr_cb_path_down; 4270ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 427177a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 42721da177e4SLinus Torvalds goto out; 42731da177e4SLinus Torvalds status = nfs_ok; 42741da177e4SLinus Torvalds out: 42751da177e4SLinus Torvalds return status; 42761da177e4SLinus Torvalds } 42771da177e4SLinus Torvalds 42787f5ef2e9SJeff Layton void 427912760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 4280a76b4319SNeilBrown { 428133dcc481SJeff Layton /* do nothing if grace period already ended */ 4282a51c84edSStanislav Kinsbursky if (nn->grace_ended) 428333dcc481SJeff Layton return; 428433dcc481SJeff Layton 4285a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 4286a51c84edSStanislav Kinsbursky nn->grace_ended = true; 428770b28235SJ. Bruce Fields /* 428870b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 428970b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 429070b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 429170b28235SJ. Bruce Fields * 429270b28235SJ. Bruce Fields */ 4293919b8049SJeff Layton nfsd4_record_grace_done(nn); 429470b28235SJ. Bruce Fields /* 429570b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 429670b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 429770b28235SJ. Bruce Fields * of luck on the next boot. 429870b28235SJ. Bruce Fields * 429970b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 430070b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 430170b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 430270b28235SJ. Bruce Fields */ 43035e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 430470b28235SJ. Bruce Fields /* 430570b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 430670b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 430770b28235SJ. Bruce Fields * regular locking can resume. 430870b28235SJ. Bruce Fields */ 4309a76b4319SNeilBrown } 4310a76b4319SNeilBrown 4311fd39ca9aSNeilBrown static time_t 431209121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 43131da177e4SLinus Torvalds { 43141da177e4SLinus Torvalds struct nfs4_client *clp; 4315fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 43161da177e4SLinus Torvalds struct nfs4_delegation *dp; 4317217526e7SJeff Layton struct nfs4_ol_stateid *stp; 43181da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 43193d733711SStanislav Kinsbursky time_t cutoff = get_seconds() - nn->nfsd4_lease; 4320a832e7aeSJeff Layton time_t t, new_timeo = nn->nfsd4_lease; 43211da177e4SLinus Torvalds 43221da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 432312760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 432436acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 4325c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 43265ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 43271da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 43281da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 43291da177e4SLinus Torvalds t = clp->cl_time - cutoff; 4330a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 43311da177e4SLinus Torvalds break; 43321da177e4SLinus Torvalds } 4333221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 4334d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 4335d7682988SBenny Halevy clp->cl_clientid.cl_id); 4336d7682988SBenny Halevy continue; 4337d7682988SBenny Halevy } 43384864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 433936acb66bSBenny Halevy } 4340c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 434136acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 434236acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 43431da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 43441da177e4SLinus Torvalds clp->cl_clientid.cl_id); 43454864af97STrond Myklebust list_del_init(&clp->cl_lru); 43461da177e4SLinus Torvalds expire_client(clp); 43471da177e4SLinus Torvalds } 4348cdc97505SBenny Halevy spin_lock(&state_lock); 4349e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 43501da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 43514e37a7c2SStanislav Kinsbursky if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) 43524e37a7c2SStanislav Kinsbursky continue; 43531da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 4354a832e7aeSJeff Layton t = dp->dl_time - cutoff; 4355a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 43561da177e4SLinus Torvalds break; 43571da177e4SLinus Torvalds } 435842690676SJeff Layton unhash_delegation_locked(dp); 435942690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 43601da177e4SLinus Torvalds } 4361cdc97505SBenny Halevy spin_unlock(&state_lock); 43622d4a532dSJeff Layton while (!list_empty(&reaplist)) { 43632d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 43642d4a532dSJeff Layton dl_recall_lru); 43652d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 43663bd64a5bSJ. Bruce Fields revoke_delegation(dp); 43671da177e4SLinus Torvalds } 4368217526e7SJeff Layton 4369217526e7SJeff Layton spin_lock(&nn->client_lock); 4370217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 4371217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 4372217526e7SJeff Layton oo_close_lru); 4373217526e7SJeff Layton if (time_after((unsigned long)oo->oo_time, 4374217526e7SJeff Layton (unsigned long)cutoff)) { 4375a832e7aeSJeff Layton t = oo->oo_time - cutoff; 4376a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 43771da177e4SLinus Torvalds break; 43781da177e4SLinus Torvalds } 4379217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 4380217526e7SJeff Layton stp = oo->oo_last_closed_stid; 4381217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 4382217526e7SJeff Layton spin_unlock(&nn->client_lock); 4383217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 4384217526e7SJeff Layton spin_lock(&nn->client_lock); 43851da177e4SLinus Torvalds } 4386217526e7SJeff Layton spin_unlock(&nn->client_lock); 4387217526e7SJeff Layton 4388a832e7aeSJeff Layton new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 4389a832e7aeSJeff Layton return new_timeo; 43901da177e4SLinus Torvalds } 43911da177e4SLinus Torvalds 4392a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 4393a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 4394a254b246SHarvey Harrison 4395a254b246SHarvey Harrison static void 439609121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 43971da177e4SLinus Torvalds { 43981da177e4SLinus Torvalds time_t t; 439909121281SStanislav Kinsbursky struct delayed_work *dwork = container_of(laundry, struct delayed_work, 440009121281SStanislav Kinsbursky work); 440109121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 440209121281SStanislav Kinsbursky laundromat_work); 44031da177e4SLinus Torvalds 440409121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 44051da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 440609121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 44071da177e4SLinus Torvalds } 44081da177e4SLinus Torvalds 4409f7a4d872SJ. Bruce Fields static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) 4410f8816512SNeilBrown { 44114d94c2efSChristoph Hellwig if (!fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle)) 4412f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4413f7a4d872SJ. Bruce Fields return nfs_ok; 44141da177e4SLinus Torvalds } 44151da177e4SLinus Torvalds 44161da177e4SLinus Torvalds static inline int 441782c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 44181da177e4SLinus Torvalds { 441982c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 442082c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 442182c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 44221da177e4SLinus Torvalds } 44231da177e4SLinus Torvalds 44241da177e4SLinus Torvalds static inline int 442582c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 44261da177e4SLinus Torvalds { 442782c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 442882c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 44291da177e4SLinus Torvalds } 44301da177e4SLinus Torvalds 44311da177e4SLinus Torvalds static 4432dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 44331da177e4SLinus Torvalds { 4434b37ad28bSAl Viro __be32 status = nfserr_openmode; 44351da177e4SLinus Torvalds 443602921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 443702921914SJ. Bruce Fields if (stp->st_openstp) 443802921914SJ. Bruce Fields stp = stp->st_openstp; 443982c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 44401da177e4SLinus Torvalds goto out; 444182c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 44421da177e4SLinus Torvalds goto out; 44431da177e4SLinus Torvalds status = nfs_ok; 44441da177e4SLinus Torvalds out: 44451da177e4SLinus Torvalds return status; 44461da177e4SLinus Torvalds } 44471da177e4SLinus Torvalds 4448b37ad28bSAl Viro static inline __be32 44495ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 44501da177e4SLinus Torvalds { 4451203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 44521da177e4SLinus Torvalds return nfs_ok; 44535ccb0066SStanislav Kinsbursky else if (locks_in_grace(net)) { 445425985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 44551da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 44561da177e4SLinus Torvalds return nfserr_grace; 44571da177e4SLinus Torvalds } else if (flags & WR_STATE) 44581da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 44591da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 44601da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 44611da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 44621da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 44631da177e4SLinus Torvalds } 44641da177e4SLinus Torvalds 44651da177e4SLinus Torvalds /* 44661da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 44671da177e4SLinus Torvalds * that are not able to provide mandatory locking. 44681da177e4SLinus Torvalds */ 44691da177e4SLinus Torvalds static inline int 44705ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 44711da177e4SLinus Torvalds { 44725ccb0066SStanislav Kinsbursky return locks_in_grace(net) && mandatory_lock(inode); 44731da177e4SLinus Torvalds } 44741da177e4SLinus Torvalds 447581b82965SJ. Bruce Fields /* Returns true iff a is later than b: */ 447681b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b) 447781b82965SJ. Bruce Fields { 44781a9357f4SJim Rees return (s32)(a->si_generation - b->si_generation) > 0; 447981b82965SJ. Bruce Fields } 448081b82965SJ. Bruce Fields 448157b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 44820836f587SJ. Bruce Fields { 44836668958fSAndy Adamson /* 44846668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 44856668958fSAndy Adamson * when it is zero. 44866668958fSAndy Adamson */ 448728dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 448881b82965SJ. Bruce Fields return nfs_ok; 448981b82965SJ. Bruce Fields 449081b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 449181b82965SJ. Bruce Fields return nfs_ok; 44926668958fSAndy Adamson 44930836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 449481b82965SJ. Bruce Fields if (stateid_generation_after(in, ref)) 44950836f587SJ. Bruce Fields return nfserr_bad_stateid; 44960836f587SJ. Bruce Fields /* 449781b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 449881b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 449981b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 450081b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 450181b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 450281b82965SJ. Bruce Fields * but better performance may result in retrying IO that 450381b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 450481b82965SJ. Bruce Fields * reordered in flight: 45050836f587SJ. Bruce Fields */ 45060836f587SJ. Bruce Fields return nfserr_old_stateid; 45070836f587SJ. Bruce Fields } 45080836f587SJ. Bruce Fields 4509ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 4510ebe9cb3bSChristoph Hellwig { 4511ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 4512ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 4513ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 4514ebe9cb3bSChristoph Hellwig return nfs_ok; 4515ebe9cb3bSChristoph Hellwig } 4516ebe9cb3bSChristoph Hellwig 45177df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 451817456804SBryan Schumaker { 451997b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 45201af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 452117456804SBryan Schumaker 45227df302f7SChuck Lever if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 45231af71cc8SJeff Layton return status; 45247df302f7SChuck Lever /* Client debugging aid. */ 45257df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 45267df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 45277df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 45287df302f7SChuck Lever sizeof(addr_str)); 45297df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 45307df302f7SChuck Lever "with incorrect client ID\n", addr_str); 45311af71cc8SJeff Layton return status; 45327df302f7SChuck Lever } 45331af71cc8SJeff Layton spin_lock(&cl->cl_lock); 45341af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 453597b7e3b6SJ. Bruce Fields if (!s) 45361af71cc8SJeff Layton goto out_unlock; 453736279ac1SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, 1); 453817456804SBryan Schumaker if (status) 45391af71cc8SJeff Layton goto out_unlock; 454023340032SJ. Bruce Fields switch (s->sc_type) { 454123340032SJ. Bruce Fields case NFS4_DELEG_STID: 45421af71cc8SJeff Layton status = nfs_ok; 45431af71cc8SJeff Layton break; 45443bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 45451af71cc8SJeff Layton status = nfserr_deleg_revoked; 45461af71cc8SJeff Layton break; 454723340032SJ. Bruce Fields case NFS4_OPEN_STID: 454823340032SJ. Bruce Fields case NFS4_LOCK_STID: 4549ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 45501af71cc8SJeff Layton break; 455123340032SJ. Bruce Fields default: 455223340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 4553b0fc29d6STrond Myklebust /* Fallthrough */ 455423340032SJ. Bruce Fields case NFS4_CLOSED_STID: 4555b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 45561af71cc8SJeff Layton status = nfserr_bad_stateid; 455723340032SJ. Bruce Fields } 45581af71cc8SJeff Layton out_unlock: 45591af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 45601af71cc8SJeff Layton return status; 456117456804SBryan Schumaker } 456217456804SBryan Schumaker 4563cd61c522SChristoph Hellwig __be32 45642dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 45652dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 45662dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 456738c2f4b1SJ. Bruce Fields { 45680eb6f20aSJ. Bruce Fields __be32 status; 456938c2f4b1SJ. Bruce Fields 457038c2f4b1SJ. Bruce Fields if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 457138c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 45724b24ca7dSJeff Layton status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn); 4573a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 45744b24ca7dSJeff Layton if (cstate->session) 4575a8a7c677STrond Myklebust return nfserr_bad_stateid; 457638c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 4577a8a7c677STrond Myklebust } 45780eb6f20aSJ. Bruce Fields if (status) 45790eb6f20aSJ. Bruce Fields return status; 45804b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 458138c2f4b1SJ. Bruce Fields if (!*s) 458238c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 458338c2f4b1SJ. Bruce Fields return nfs_ok; 458438c2f4b1SJ. Bruce Fields } 458538c2f4b1SJ. Bruce Fields 4586a0649b2dSChristoph Hellwig static struct file * 4587a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 4588a0649b2dSChristoph Hellwig { 4589af90f707SChristoph Hellwig if (!s) 4590af90f707SChristoph Hellwig return NULL; 4591af90f707SChristoph Hellwig 4592a0649b2dSChristoph Hellwig switch (s->sc_type) { 4593a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 4594a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 4595a0649b2dSChristoph Hellwig return NULL; 4596a0649b2dSChristoph Hellwig return get_file(s->sc_file->fi_deleg_file); 4597a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 4598a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 4599a0649b2dSChristoph Hellwig if (flags & RD_STATE) 4600a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 4601a0649b2dSChristoph Hellwig else 4602a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 4603a0649b2dSChristoph Hellwig break; 4604a0649b2dSChristoph Hellwig } 4605a0649b2dSChristoph Hellwig 4606a0649b2dSChristoph Hellwig return NULL; 4607a0649b2dSChristoph Hellwig } 4608a0649b2dSChristoph Hellwig 4609a0649b2dSChristoph Hellwig static __be32 4610a0649b2dSChristoph Hellwig nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags) 4611a0649b2dSChristoph Hellwig { 4612a0649b2dSChristoph Hellwig __be32 status; 4613a0649b2dSChristoph Hellwig 4614a0649b2dSChristoph Hellwig status = nfs4_check_fh(fhp, ols); 4615a0649b2dSChristoph Hellwig if (status) 4616a0649b2dSChristoph Hellwig return status; 4617a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 4618a0649b2dSChristoph Hellwig if (status) 4619a0649b2dSChristoph Hellwig return status; 4620a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 4621a0649b2dSChristoph Hellwig } 4622a0649b2dSChristoph Hellwig 4623af90f707SChristoph Hellwig static __be32 4624af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 4625af90f707SChristoph Hellwig struct file **filpp, bool *tmp_file, int flags) 4626af90f707SChristoph Hellwig { 4627af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 4628af90f707SChristoph Hellwig struct file *file; 4629af90f707SChristoph Hellwig __be32 status; 4630af90f707SChristoph Hellwig 4631af90f707SChristoph Hellwig file = nfs4_find_file(s, flags); 4632af90f707SChristoph Hellwig if (file) { 4633af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 4634af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 4635af90f707SChristoph Hellwig if (status) { 4636af90f707SChristoph Hellwig fput(file); 4637af90f707SChristoph Hellwig return status; 4638af90f707SChristoph Hellwig } 4639af90f707SChristoph Hellwig 4640af90f707SChristoph Hellwig *filpp = file; 4641af90f707SChristoph Hellwig } else { 4642af90f707SChristoph Hellwig status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp); 4643af90f707SChristoph Hellwig if (status) 4644af90f707SChristoph Hellwig return status; 4645af90f707SChristoph Hellwig 4646af90f707SChristoph Hellwig if (tmp_file) 4647af90f707SChristoph Hellwig *tmp_file = true; 4648af90f707SChristoph Hellwig } 4649af90f707SChristoph Hellwig 4650af90f707SChristoph Hellwig return 0; 4651af90f707SChristoph Hellwig } 4652af90f707SChristoph Hellwig 46531da177e4SLinus Torvalds /* 46541da177e4SLinus Torvalds * Checks for stateid operations 46551da177e4SLinus Torvalds */ 4656b37ad28bSAl Viro __be32 4657af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 4658af90f707SChristoph Hellwig struct nfsd4_compound_state *cstate, stateid_t *stateid, 4659af90f707SChristoph Hellwig int flags, struct file **filpp, bool *tmp_file) 46601da177e4SLinus Torvalds { 4661a0649b2dSChristoph Hellwig struct svc_fh *fhp = &cstate->current_fh; 4662a0649b2dSChristoph Hellwig struct inode *ino = d_inode(fhp->fh_dentry); 4663af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 46643320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 4665af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 4666b37ad28bSAl Viro __be32 status; 46671da177e4SLinus Torvalds 46681da177e4SLinus Torvalds if (filpp) 46691da177e4SLinus Torvalds *filpp = NULL; 4670af90f707SChristoph Hellwig if (tmp_file) 4671af90f707SChristoph Hellwig *tmp_file = false; 46721da177e4SLinus Torvalds 46735ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 46741da177e4SLinus Torvalds return nfserr_grace; 46751da177e4SLinus Torvalds 4676af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 4677af90f707SChristoph Hellwig status = check_special_stateids(net, fhp, stateid, flags); 4678af90f707SChristoph Hellwig goto done; 4679af90f707SChristoph Hellwig } 46801da177e4SLinus Torvalds 46812dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 4682db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 46832dd6e458STrond Myklebust &s, nn); 468438c2f4b1SJ. Bruce Fields if (status) 4685c2d1d6a8STrond Myklebust return status; 4686a0649b2dSChristoph Hellwig status = check_stateid_generation(stateid, &s->sc_stateid, 4687a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 46880c2a498fSJ. Bruce Fields if (status) 46890c2a498fSJ. Bruce Fields goto out; 4690a0649b2dSChristoph Hellwig 4691f7a4d872SJ. Bruce Fields switch (s->sc_type) { 4692f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 4693a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 4694f7a4d872SJ. Bruce Fields break; 4695f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 4696f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 4697a0649b2dSChristoph Hellwig status = nfs4_check_olstateid(fhp, openlockstateid(s), flags); 4698f7a4d872SJ. Bruce Fields break; 4699f7a4d872SJ. Bruce Fields default: 470014bcab1aSTrond Myklebust status = nfserr_bad_stateid; 4701a0649b2dSChristoph Hellwig break; 47021da177e4SLinus Torvalds } 4703a0649b2dSChristoph Hellwig 4704af90f707SChristoph Hellwig done: 4705af90f707SChristoph Hellwig if (!status && filpp) 4706af90f707SChristoph Hellwig status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags); 47071da177e4SLinus Torvalds out: 4708af90f707SChristoph Hellwig if (s) 4709fd911011STrond Myklebust nfs4_put_stid(s); 47101da177e4SLinus Torvalds return status; 47111da177e4SLinus Torvalds } 47121da177e4SLinus Torvalds 4713e1ca12dfSBryan Schumaker /* 471417456804SBryan Schumaker * Test if the stateid is valid 471517456804SBryan Schumaker */ 471617456804SBryan Schumaker __be32 471717456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 471817456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 471917456804SBryan Schumaker { 472003cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 472103cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 472203cfb420SBryan Schumaker 472303cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 47247df302f7SChuck Lever stateid->ts_id_status = 47257df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 472603cfb420SBryan Schumaker 472717456804SBryan Schumaker return nfs_ok; 472817456804SBryan Schumaker } 472917456804SBryan Schumaker 4730e1ca12dfSBryan Schumaker __be32 4731e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4732e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 4733e1ca12dfSBryan Schumaker { 4734e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 47352da1cec7SJ. Bruce Fields struct nfs4_stid *s; 47363bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 4737fc5a96c3SJeff Layton struct nfs4_ol_stateid *stp; 473838c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 47392da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 4740e1ca12dfSBryan Schumaker 47411af71cc8SJeff Layton spin_lock(&cl->cl_lock); 47421af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 47432da1cec7SJ. Bruce Fields if (!s) 47441af71cc8SJeff Layton goto out_unlock; 47452da1cec7SJ. Bruce Fields switch (s->sc_type) { 47462da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 4747e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 47481af71cc8SJeff Layton break; 47492da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 47501af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 47511af71cc8SJeff Layton if (ret) 47521af71cc8SJeff Layton break; 47531af71cc8SJeff Layton ret = nfserr_locks_held; 47541af71cc8SJeff Layton break; 47552da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 47562da1cec7SJ. Bruce Fields ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 47572da1cec7SJ. Bruce Fields if (ret) 4758f7a4d872SJ. Bruce Fields break; 4759fc5a96c3SJeff Layton stp = openlockstateid(s); 4760fc5a96c3SJeff Layton ret = nfserr_locks_held; 4761fc5a96c3SJeff Layton if (check_for_locks(stp->st_stid.sc_file, 4762fc5a96c3SJeff Layton lockowner(stp->st_stateowner))) 4763fc5a96c3SJeff Layton break; 4764fc5a96c3SJeff Layton unhash_lock_stateid(stp); 47651af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 4766fc5a96c3SJeff Layton nfs4_put_stid(s); 4767fc5a96c3SJeff Layton ret = nfs_ok; 47681af71cc8SJeff Layton goto out; 47693bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 47703bd64a5bSJ. Bruce Fields dp = delegstateid(s); 47712d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 47722d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 47736011695dSTrond Myklebust nfs4_put_stid(s); 47743bd64a5bSJ. Bruce Fields ret = nfs_ok; 47751af71cc8SJeff Layton goto out; 47761af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 4777e1ca12dfSBryan Schumaker } 47781af71cc8SJeff Layton out_unlock: 47791af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 4780e1ca12dfSBryan Schumaker out: 4781e1ca12dfSBryan Schumaker return ret; 4782e1ca12dfSBryan Schumaker } 4783e1ca12dfSBryan Schumaker 47844c4cd222SNeilBrown static inline int 47854c4cd222SNeilBrown setlkflg (int type) 47864c4cd222SNeilBrown { 47874c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 47884c4cd222SNeilBrown RD_STATE : WR_STATE; 47894c4cd222SNeilBrown } 47901da177e4SLinus Torvalds 4791dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 4792c0a5d93eSJ. Bruce Fields { 4793c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 4794c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 4795c0a5d93eSJ. Bruce Fields __be32 status; 4796c0a5d93eSJ. Bruce Fields 4797c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 4798c0a5d93eSJ. Bruce Fields if (status) 4799c0a5d93eSJ. Bruce Fields return status; 48003bd64a5bSJ. Bruce Fields if (stp->st_stid.sc_type == NFS4_CLOSED_STID 48013bd64a5bSJ. Bruce Fields || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4802f7a4d872SJ. Bruce Fields /* 4803f7a4d872SJ. Bruce Fields * "Closed" stateid's exist *only* to return 48043bd64a5bSJ. Bruce Fields * nfserr_replay_me from the previous step, and 48053bd64a5bSJ. Bruce Fields * revoked delegations are kept only for free_stateid. 4806f7a4d872SJ. Bruce Fields */ 4807f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4808f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 4809f7a4d872SJ. Bruce Fields if (status) 4810f7a4d872SJ. Bruce Fields return status; 4811f7a4d872SJ. Bruce Fields return nfs4_check_fh(current_fh, stp); 4812c0a5d93eSJ. Bruce Fields } 4813c0a5d93eSJ. Bruce Fields 48141da177e4SLinus Torvalds /* 48151da177e4SLinus Torvalds * Checks for sequence id mutating operations. 48161da177e4SLinus Torvalds */ 4817b37ad28bSAl Viro static __be32 4818dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 48192288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 48203320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 48213320fef1SStanislav Kinsbursky struct nfsd_net *nn) 48221da177e4SLinus Torvalds { 48230836f587SJ. Bruce Fields __be32 status; 482438c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 4825e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 48261da177e4SLinus Torvalds 48278c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 48288c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 48291da177e4SLinus Torvalds 48301da177e4SLinus Torvalds *stpp = NULL; 48312dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 4832c0a5d93eSJ. Bruce Fields if (status) 4833c0a5d93eSJ. Bruce Fields return status; 4834e17f99b7STrond Myklebust stp = openlockstateid(s); 483558fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 48361da177e4SLinus Torvalds 4837e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 4838fd911011STrond Myklebust if (!status) 4839e17f99b7STrond Myklebust *stpp = stp; 4840fd911011STrond Myklebust else 4841fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 4842e17f99b7STrond Myklebust return status; 48431da177e4SLinus Torvalds } 48441da177e4SLinus Torvalds 48453320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 48463320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 4847c0a5d93eSJ. Bruce Fields { 4848c0a5d93eSJ. Bruce Fields __be32 status; 4849c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 48504cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 48511da177e4SLinus Torvalds 4852c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 48534cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 48540836f587SJ. Bruce Fields if (status) 48550836f587SJ. Bruce Fields return status; 48564cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 48574cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 48584cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 4859c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 48604cbfc9f7STrond Myklebust } 48614cbfc9f7STrond Myklebust *stpp = stp; 48623a4f98bbSNeilBrown return nfs_ok; 48631da177e4SLinus Torvalds } 48641da177e4SLinus Torvalds 4865b37ad28bSAl Viro __be32 4866ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4867a4f1706aSJ.Bruce Fields struct nfsd4_open_confirm *oc) 48681da177e4SLinus Torvalds { 4869b37ad28bSAl Viro __be32 status; 4870fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 4871dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 48723320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 48731da177e4SLinus Torvalds 4874a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 4875a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 48761da177e4SLinus Torvalds 4877ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 4878a8cddc5dSJ. Bruce Fields if (status) 4879a8cddc5dSJ. Bruce Fields return status; 48801da177e4SLinus Torvalds 48819072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 4882ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 48833320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 48849072d5c6SJ. Bruce Fields if (status) 48851da177e4SLinus Torvalds goto out; 4886fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 488768b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 4888dad1c067SJ. Bruce Fields if (oo->oo_flags & NFS4_OO_CONFIRMED) 48892585fc79STrond Myklebust goto put_stateid; 4890dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 4891dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4892dcef0413SJ. Bruce Fields memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 48938c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 4894dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 4895c7b9a459SNeilBrown 48962a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 489768b66e82SJ. Bruce Fields status = nfs_ok; 48982585fc79STrond Myklebust put_stateid: 48992585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 49001da177e4SLinus Torvalds out: 49019411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 49021da177e4SLinus Torvalds return status; 49031da177e4SLinus Torvalds } 49041da177e4SLinus Torvalds 49056409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 49061da177e4SLinus Torvalds { 490782c5ff1bSJeff Layton if (!test_access(access, stp)) 49086409a5a6SJ. Bruce Fields return; 490911b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 491082c5ff1bSJeff Layton clear_access(access, stp); 4911f197c271SJ. Bruce Fields } 49126409a5a6SJ. Bruce Fields 49136409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 49146409a5a6SJ. Bruce Fields { 49156409a5a6SJ. Bruce Fields switch (to_access) { 49166409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 49176409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 49186409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 49196409a5a6SJ. Bruce Fields break; 49206409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 49216409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 49226409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 49236409a5a6SJ. Bruce Fields break; 49246409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 49256409a5a6SJ. Bruce Fields break; 49266409a5a6SJ. Bruce Fields default: 4927063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 49281da177e4SLinus Torvalds } 49291da177e4SLinus Torvalds } 49301da177e4SLinus Torvalds 4931b37ad28bSAl Viro __be32 4932ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 4933ca364317SJ.Bruce Fields struct nfsd4_compound_state *cstate, 4934a4f1706aSJ.Bruce Fields struct nfsd4_open_downgrade *od) 49351da177e4SLinus Torvalds { 4936b37ad28bSAl Viro __be32 status; 4937dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 49383320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 49391da177e4SLinus Torvalds 4940a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 4941a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 49421da177e4SLinus Torvalds 4943c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 49442c8bd7e0SBenny Halevy if (od->od_deleg_want) 49452c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 49462c8bd7e0SBenny Halevy od->od_deleg_want); 49471da177e4SLinus Torvalds 4948c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 49493320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 49509072d5c6SJ. Bruce Fields if (status) 49511da177e4SLinus Torvalds goto out; 49521da177e4SLinus Torvalds status = nfserr_inval; 495382c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 4954c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 49551da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 49560667b1e9STrond Myklebust goto put_stateid; 49571da177e4SLinus Torvalds } 4958ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 4959c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 49601da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 49610667b1e9STrond Myklebust goto put_stateid; 49621da177e4SLinus Torvalds } 49636409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 49641da177e4SLinus Torvalds 4965ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 49661da177e4SLinus Torvalds 4967dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4968dcef0413SJ. Bruce Fields memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 49691da177e4SLinus Torvalds status = nfs_ok; 49700667b1e9STrond Myklebust put_stateid: 49710667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 49721da177e4SLinus Torvalds out: 49739411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 49741da177e4SLinus Torvalds return status; 49751da177e4SLinus Torvalds } 49761da177e4SLinus Torvalds 4977f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 4978f7a4d872SJ. Bruce Fields { 4979acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 4980d83017f9SJeff Layton LIST_HEAD(reaplist); 4981acf9295bSTrond Myklebust 4982f7a4d872SJ. Bruce Fields s->st_stid.sc_type = NFS4_CLOSED_STID; 49832c41beb0SJeff Layton spin_lock(&clp->cl_lock); 4984d83017f9SJeff Layton unhash_open_stateid(s, &reaplist); 4985acf9295bSTrond Myklebust 4986d83017f9SJeff Layton if (clp->cl_minorversion) { 4987d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 4988d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 4989d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 4990d83017f9SJeff Layton } else { 4991d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 4992d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 4993d3134b10SJeff Layton move_to_close_lru(s, clp->net); 499438c387b5SJ. Bruce Fields } 4995d83017f9SJeff Layton } 499638c387b5SJ. Bruce Fields 49971da177e4SLinus Torvalds /* 49981da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 49991da177e4SLinus Torvalds */ 5000b37ad28bSAl Viro __be32 5001ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5002a4f1706aSJ.Bruce Fields struct nfsd4_close *close) 50031da177e4SLinus Torvalds { 5004b37ad28bSAl Viro __be32 status; 5005dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 50063320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 50073320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 50081da177e4SLinus Torvalds 5009a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 5010a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 50111da177e4SLinus Torvalds 5012f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 5013f7a4d872SJ. Bruce Fields &close->cl_stateid, 5014f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 50153320fef1SStanislav Kinsbursky &stp, nn); 50169411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 50179072d5c6SJ. Bruce Fields if (status) 50181da177e4SLinus Torvalds goto out; 5019dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 5020dcef0413SJ. Bruce Fields memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 50211da177e4SLinus Torvalds 5022f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 50238a0b589dSTrond Myklebust 50248a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 50258a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 50261da177e4SLinus Torvalds out: 50271da177e4SLinus Torvalds return status; 50281da177e4SLinus Torvalds } 50291da177e4SLinus Torvalds 5030b37ad28bSAl Viro __be32 5031ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5032ca364317SJ.Bruce Fields struct nfsd4_delegreturn *dr) 50331da177e4SLinus Torvalds { 5034203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 5035203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 503638c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 5037b37ad28bSAl Viro __be32 status; 50383320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 50391da177e4SLinus Torvalds 5040ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 5041203a8c8eSJ. Bruce Fields return status; 50421da177e4SLinus Torvalds 50432dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 504438c2f4b1SJ. Bruce Fields if (status) 5045203a8c8eSJ. Bruce Fields goto out; 504638c2f4b1SJ. Bruce Fields dp = delegstateid(s); 5047d5477a8dSJ. Bruce Fields status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); 5048203a8c8eSJ. Bruce Fields if (status) 5049fd911011STrond Myklebust goto put_stateid; 5050203a8c8eSJ. Bruce Fields 50513bd64a5bSJ. Bruce Fields destroy_delegation(dp); 5052fd911011STrond Myklebust put_stateid: 5053fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 50541da177e4SLinus Torvalds out: 50551da177e4SLinus Torvalds return status; 50561da177e4SLinus Torvalds } 50571da177e4SLinus Torvalds 50581da177e4SLinus Torvalds 50591da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) 50601da177e4SLinus Torvalds 506187df4de8SBenny Halevy static inline u64 506287df4de8SBenny Halevy end_offset(u64 start, u64 len) 506387df4de8SBenny Halevy { 506487df4de8SBenny Halevy u64 end; 506587df4de8SBenny Halevy 506687df4de8SBenny Halevy end = start + len; 506787df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 506887df4de8SBenny Halevy } 506987df4de8SBenny Halevy 507087df4de8SBenny Halevy /* last octet in a range */ 507187df4de8SBenny Halevy static inline u64 507287df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 507387df4de8SBenny Halevy { 507487df4de8SBenny Halevy u64 end; 507587df4de8SBenny Halevy 5076063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 507787df4de8SBenny Halevy end = start + len; 507887df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 507987df4de8SBenny Halevy } 508087df4de8SBenny Halevy 50811da177e4SLinus Torvalds /* 50821da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 50831da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 50841da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 50851da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 50861da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 50871da177e4SLinus Torvalds * the VFS, but this is a very deep change! 50881da177e4SLinus Torvalds */ 50891da177e4SLinus Torvalds static inline void 50901da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 50911da177e4SLinus Torvalds { 50921da177e4SLinus Torvalds if (lock->fl_start < 0) 50931da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 50941da177e4SLinus Torvalds if (lock->fl_end < 0) 50951da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 50961da177e4SLinus Torvalds } 50971da177e4SLinus Torvalds 5098cae80b30SJeff Layton static fl_owner_t 5099cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner) 5100aef9583bSKinglong Mee { 5101cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5102cae80b30SJeff Layton 5103cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 5104cae80b30SJeff Layton return owner; 5105aef9583bSKinglong Mee } 5106aef9583bSKinglong Mee 5107cae80b30SJeff Layton static void 5108cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner) 5109aef9583bSKinglong Mee { 5110cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5111aef9583bSKinglong Mee 5112cae80b30SJeff Layton if (lo) 5113aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 5114aef9583bSKinglong Mee } 5115aef9583bSKinglong Mee 51167b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 5117aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 5118aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 5119d5b9026aSNeilBrown }; 51201da177e4SLinus Torvalds 51211da177e4SLinus Torvalds static inline void 51221da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 51231da177e4SLinus Torvalds { 5124fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 51251da177e4SLinus Torvalds 5126d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 5127fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 5128fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 5129fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 51307c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 51317c13f344SJ. Bruce Fields /* We just don't care that much */ 51327c13f344SJ. Bruce Fields goto nevermind; 5133fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 5134fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 5135d5b9026aSNeilBrown } else { 51367c13f344SJ. Bruce Fields nevermind: 51377c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 51387c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 5139d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 5140d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 51411da177e4SLinus Torvalds } 51421da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 514387df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 514487df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 51451da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 51461da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 51471da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 51481da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 51491da177e4SLinus Torvalds } 51501da177e4SLinus Torvalds 5151fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5152c58c6610STrond Myklebust find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner, 5153d4f0489fSTrond Myklebust struct nfs4_client *clp) 51541da177e4SLinus Torvalds { 5155d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 5156b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 51571da177e4SLinus Torvalds 51580a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 51590a880a28STrond Myklebust 5160d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 5161d4f0489fSTrond Myklebust so_strhash) { 5162b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 5163b3c32bcdSTrond Myklebust continue; 5164b5971afaSKinglong Mee if (same_owner_str(so, owner)) 5165b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 51661da177e4SLinus Torvalds } 51671da177e4SLinus Torvalds return NULL; 51681da177e4SLinus Torvalds } 51691da177e4SLinus Torvalds 5170c58c6610STrond Myklebust static struct nfs4_lockowner * 5171c58c6610STrond Myklebust find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner, 5172d4f0489fSTrond Myklebust struct nfs4_client *clp) 5173c58c6610STrond Myklebust { 5174c58c6610STrond Myklebust struct nfs4_lockowner *lo; 5175c58c6610STrond Myklebust 5176d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5177d4f0489fSTrond Myklebust lo = find_lockowner_str_locked(clid, owner, clp); 5178d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5179c58c6610STrond Myklebust return lo; 5180c58c6610STrond Myklebust } 5181c58c6610STrond Myklebust 51828f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 51838f4b54c5SJeff Layton { 5184c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 51858f4b54c5SJeff Layton } 51868f4b54c5SJeff Layton 51876b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 51886b180f0bSJeff Layton { 51896b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 51906b180f0bSJeff Layton 51916b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 51926b180f0bSJeff Layton } 51936b180f0bSJeff Layton 51946b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 51958f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 51966b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 51976b180f0bSJeff Layton }; 51986b180f0bSJeff Layton 51991da177e4SLinus Torvalds /* 52001da177e4SLinus Torvalds * Alloc a lock owner structure. 52011da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 520225985edcSLucas De Marchi * occurred. 52031da177e4SLinus Torvalds * 520416bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 52051da177e4SLinus Torvalds */ 5206fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5207c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 5208c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 5209c58c6610STrond Myklebust struct nfsd4_lock *lock) 5210c58c6610STrond Myklebust { 5211c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 52121da177e4SLinus Torvalds 5213fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 5214fe0750e5SJ. Bruce Fields if (!lo) 52151da177e4SLinus Torvalds return NULL; 5216fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 5217fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 52185db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 52196b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 5220d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5221c58c6610STrond Myklebust ret = find_lockowner_str_locked(&clp->cl_clientid, 5222d4f0489fSTrond Myklebust &lock->lk_new_owner, clp); 5223c58c6610STrond Myklebust if (ret == NULL) { 5224c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 5225d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 5226c58c6610STrond Myklebust ret = lo; 5227c58c6610STrond Myklebust } else 5228d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 5229d50ffdedSKinglong Mee 5230d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5231340f0ba1SJ. Bruce Fields return ret; 52321da177e4SLinus Torvalds } 52331da177e4SLinus Torvalds 5234356a95ecSJeff Layton static void 5235356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 5236356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 5237f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 52381da177e4SLinus Torvalds { 5239d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 52401da177e4SLinus Torvalds 5241356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 5242356a95ecSJeff Layton 52433d0fabd5STrond Myklebust atomic_inc(&stp->st_stid.sc_count); 52443abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 5245b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 524613cd2184SNeilBrown get_nfs4_file(fp); 524711b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 5248b49e084dSJeff Layton stp->st_stid.sc_free = nfs4_free_lock_stateid; 52490997b173SJ. Bruce Fields stp->st_access_bmap = 0; 52501da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 52514c4cd222SNeilBrown stp->st_openstp = open_stp; 52523c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 52531c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 52541d31a253STrond Myklebust spin_lock(&fp->fi_lock); 52551d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 52561d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 52571da177e4SLinus Torvalds } 52581da177e4SLinus Torvalds 5259c53530daSJeff Layton static struct nfs4_ol_stateid * 5260c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) 5261c53530daSJeff Layton { 5262c53530daSJeff Layton struct nfs4_ol_stateid *lst; 5263356a95ecSJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 5264356a95ecSJeff Layton 5265356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 5266c53530daSJeff Layton 5267c53530daSJeff Layton list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { 52683d0fabd5STrond Myklebust if (lst->st_stid.sc_file == fp) { 52693d0fabd5STrond Myklebust atomic_inc(&lst->st_stid.sc_count); 5270c53530daSJeff Layton return lst; 5271c53530daSJeff Layton } 52723d0fabd5STrond Myklebust } 5273c53530daSJeff Layton return NULL; 5274c53530daSJeff Layton } 5275c53530daSJeff Layton 5276356a95ecSJeff Layton static struct nfs4_ol_stateid * 5277356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 5278356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 5279356a95ecSJeff Layton bool *new) 5280356a95ecSJeff Layton { 5281356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 5282356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 5283356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 5284356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 5285356a95ecSJeff Layton 5286356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5287356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5288356a95ecSJeff Layton if (lst == NULL) { 5289356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5290356a95ecSJeff Layton ns = nfs4_alloc_stid(clp, stateid_slab); 5291356a95ecSJeff Layton if (ns == NULL) 5292356a95ecSJeff Layton return NULL; 5293356a95ecSJeff Layton 5294356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5295356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5296356a95ecSJeff Layton if (likely(!lst)) { 5297356a95ecSJeff Layton lst = openlockstateid(ns); 5298356a95ecSJeff Layton init_lock_stateid(lst, lo, fi, inode, ost); 5299356a95ecSJeff Layton ns = NULL; 5300356a95ecSJeff Layton *new = true; 5301356a95ecSJeff Layton } 5302356a95ecSJeff Layton } 5303356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5304356a95ecSJeff Layton if (ns) 5305356a95ecSJeff Layton nfs4_put_stid(ns); 5306356a95ecSJeff Layton return lst; 5307356a95ecSJeff Layton } 5308c53530daSJeff Layton 5309fd39ca9aSNeilBrown static int 53101da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 53111da177e4SLinus Torvalds { 531287df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 53131da177e4SLinus Torvalds LOFF_OVERFLOW(offset, length))); 53141da177e4SLinus Torvalds } 53151da177e4SLinus Torvalds 5316dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 53170997b173SJ. Bruce Fields { 531811b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 53190997b173SJ. Bruce Fields 53207214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 53217214e860SJeff Layton 532282c5ff1bSJeff Layton if (test_access(access, lock_stp)) 53230997b173SJ. Bruce Fields return; 532412659651SJeff Layton __nfs4_file_get_access(fp, access); 532582c5ff1bSJeff Layton set_access(access, lock_stp); 53260997b173SJ. Bruce Fields } 53270997b173SJ. Bruce Fields 5328356a95ecSJeff Layton static __be32 5329356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 5330356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 5331356a95ecSJeff Layton struct nfsd4_lock *lock, 5332356a95ecSJeff Layton struct nfs4_ol_stateid **lst, bool *new) 533364a284d0SJ. Bruce Fields { 53345db1c03fSJeff Layton __be32 status; 533511b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 533664a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 533764a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 53382b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 533964a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 534064a284d0SJ. Bruce Fields unsigned int strhashval; 534164a284d0SJ. Bruce Fields 5342d4f0489fSTrond Myklebust lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, cl); 5343c53530daSJeff Layton if (!lo) { 5344d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&lock->v.new.owner); 534564a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 534664a284d0SJ. Bruce Fields if (lo == NULL) 534764a284d0SJ. Bruce Fields return nfserr_jukebox; 5348c53530daSJeff Layton } else { 5349c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 53505db1c03fSJeff Layton status = nfserr_bad_seqid; 5351c53530daSJeff Layton if (!cstate->minorversion && 5352c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 53535db1c03fSJeff Layton goto out; 5354c53530daSJeff Layton } 5355c53530daSJeff Layton 5356356a95ecSJeff Layton *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 535764a284d0SJ. Bruce Fields if (*lst == NULL) { 53585db1c03fSJeff Layton status = nfserr_jukebox; 53595db1c03fSJeff Layton goto out; 536064a284d0SJ. Bruce Fields } 53615db1c03fSJeff Layton status = nfs_ok; 53625db1c03fSJeff Layton out: 53635db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 53645db1c03fSJeff Layton return status; 536564a284d0SJ. Bruce Fields } 536664a284d0SJ. Bruce Fields 53671da177e4SLinus Torvalds /* 53681da177e4SLinus Torvalds * LOCK operation 53691da177e4SLinus Torvalds */ 5370b37ad28bSAl Viro __be32 5371ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5372a4f1706aSJ.Bruce Fields struct nfsd4_lock *lock) 53731da177e4SLinus Torvalds { 5374fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 5375fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 53763d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 53770667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 53787214e860SJeff Layton struct nfs4_file *fp; 53797d947842SJ. Bruce Fields struct file *filp = NULL; 538021179d81SJeff Layton struct file_lock *file_lock = NULL; 538121179d81SJeff Layton struct file_lock *conflock = NULL; 5382b37ad28bSAl Viro __be32 status = 0; 5383b34f27aaSJ. Bruce Fields int lkflg; 5384b8dd7b9aSAl Viro int err; 53855db1c03fSJeff Layton bool new = false; 53863320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 53873320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 53881da177e4SLinus Torvalds 53891da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 53901da177e4SLinus Torvalds (long long) lock->lk_offset, 53911da177e4SLinus Torvalds (long long) lock->lk_length); 53921da177e4SLinus Torvalds 53931da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 53941da177e4SLinus Torvalds return nfserr_inval; 53951da177e4SLinus Torvalds 5396ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 53978837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 5398a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 5399a6f6ef2fSAndy Adamson return status; 5400a6f6ef2fSAndy Adamson } 5401a6f6ef2fSAndy Adamson 54021da177e4SLinus Torvalds if (lock->lk_is_new) { 5403684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 5404684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 5405684e5638SJ. Bruce Fields memcpy(&lock->v.new.clientid, 5406684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 5407684e5638SJ. Bruce Fields sizeof(clientid_t)); 5408684e5638SJ. Bruce Fields 54091da177e4SLinus Torvalds status = nfserr_stale_clientid; 54102c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 54111da177e4SLinus Torvalds goto out; 54121da177e4SLinus Torvalds 54131da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 5414c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 54151da177e4SLinus Torvalds lock->lk_new_open_seqid, 54161da177e4SLinus Torvalds &lock->lk_new_open_stateid, 54173320fef1SStanislav Kinsbursky &open_stp, nn); 541837515177SNeilBrown if (status) 54191da177e4SLinus Torvalds goto out; 5420fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 5421b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 5422684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 5423b34f27aaSJ. Bruce Fields &lock->v.new.clientid)) 5424b34f27aaSJ. Bruce Fields goto out; 542564a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 54265db1c03fSJeff Layton &lock_stp, &new); 54273d0fabd5STrond Myklebust } else { 5428dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 54291da177e4SLinus Torvalds lock->lk_old_lock_seqid, 54301da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 54313320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 54323d0fabd5STrond Myklebust } 54331da177e4SLinus Torvalds if (status) 54341da177e4SLinus Torvalds goto out; 5435fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 54361da177e4SLinus Torvalds 5437b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 5438b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 5439b34f27aaSJ. Bruce Fields if (status) 5440b34f27aaSJ. Bruce Fields goto out; 5441b34f27aaSJ. Bruce Fields 54420dd395dcSNeilBrown status = nfserr_grace; 54433320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 54440dd395dcSNeilBrown goto out; 54450dd395dcSNeilBrown status = nfserr_no_grace; 54463320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 54470dd395dcSNeilBrown goto out; 54480dd395dcSNeilBrown 544921179d81SJeff Layton file_lock = locks_alloc_lock(); 545021179d81SJeff Layton if (!file_lock) { 545121179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 545221179d81SJeff Layton status = nfserr_jukebox; 545321179d81SJeff Layton goto out; 545421179d81SJeff Layton } 545521179d81SJeff Layton 545611b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 54571da177e4SLinus Torvalds switch (lock->lk_type) { 54581da177e4SLinus Torvalds case NFS4_READ_LT: 54591da177e4SLinus Torvalds case NFS4_READW_LT: 54607214e860SJeff Layton spin_lock(&fp->fi_lock); 54617214e860SJeff Layton filp = find_readable_file_locked(fp); 54620997b173SJ. Bruce Fields if (filp) 54630997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 54647214e860SJeff Layton spin_unlock(&fp->fi_lock); 546521179d81SJeff Layton file_lock->fl_type = F_RDLCK; 54661da177e4SLinus Torvalds break; 54671da177e4SLinus Torvalds case NFS4_WRITE_LT: 54681da177e4SLinus Torvalds case NFS4_WRITEW_LT: 54697214e860SJeff Layton spin_lock(&fp->fi_lock); 54707214e860SJeff Layton filp = find_writeable_file_locked(fp); 54710997b173SJ. Bruce Fields if (filp) 54720997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 54737214e860SJeff Layton spin_unlock(&fp->fi_lock); 547421179d81SJeff Layton file_lock->fl_type = F_WRLCK; 54751da177e4SLinus Torvalds break; 54761da177e4SLinus Torvalds default: 54771da177e4SLinus Torvalds status = nfserr_inval; 54781da177e4SLinus Torvalds goto out; 54791da177e4SLinus Torvalds } 5480f9d7562fSJ. Bruce Fields if (!filp) { 5481f9d7562fSJ. Bruce Fields status = nfserr_openmode; 5482f9d7562fSJ. Bruce Fields goto out; 5483f9d7562fSJ. Bruce Fields } 5484aef9583bSKinglong Mee 5485aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 548621179d81SJeff Layton file_lock->fl_pid = current->tgid; 548721179d81SJeff Layton file_lock->fl_file = filp; 548821179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 548921179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 549021179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 549121179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 549221179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 54931da177e4SLinus Torvalds 549421179d81SJeff Layton conflock = locks_alloc_lock(); 549521179d81SJeff Layton if (!conflock) { 549621179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 549721179d81SJeff Layton status = nfserr_jukebox; 549821179d81SJeff Layton goto out; 549921179d81SJeff Layton } 55001da177e4SLinus Torvalds 550121179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); 5502b8dd7b9aSAl Viro switch (-err) { 55031da177e4SLinus Torvalds case 0: /* success! */ 5504dcef0413SJ. Bruce Fields update_stateid(&lock_stp->st_stid.sc_stateid); 5505dcef0413SJ. Bruce Fields memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, 55061da177e4SLinus Torvalds sizeof(stateid_t)); 5507b8dd7b9aSAl Viro status = 0; 5508eb76b3fdSAndy Adamson break; 5509eb76b3fdSAndy Adamson case (EAGAIN): /* conflock holds conflicting lock */ 5510eb76b3fdSAndy Adamson status = nfserr_denied; 5511eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 551221179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 5513eb76b3fdSAndy Adamson break; 55141da177e4SLinus Torvalds case (EDEADLK): 55151da177e4SLinus Torvalds status = nfserr_deadlock; 5516eb76b3fdSAndy Adamson break; 55171da177e4SLinus Torvalds default: 5518fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 55193e772463SJ. Bruce Fields status = nfserrno(err); 5520eb76b3fdSAndy Adamson break; 55211da177e4SLinus Torvalds } 55221da177e4SLinus Torvalds out: 5523de18643dSTrond Myklebust if (filp) 5524de18643dSTrond Myklebust fput(filp); 55255db1c03fSJeff Layton if (lock_stp) { 55265db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 55275db1c03fSJeff Layton if (cstate->replay_owner && 55285db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 55295db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 55305db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 55315db1c03fSJeff Layton 55325db1c03fSJeff Layton /* 55335db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 55345db1c03fSJeff Layton * returning an error, then just go ahead and release it. 55355db1c03fSJeff Layton */ 55365db1c03fSJeff Layton if (status && new) 55375db1c03fSJeff Layton release_lock_stateid(lock_stp); 55385db1c03fSJeff Layton 55393d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 55405db1c03fSJeff Layton } 55410667b1e9STrond Myklebust if (open_stp) 55420667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 55439411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 554421179d81SJeff Layton if (file_lock) 554521179d81SJeff Layton locks_free_lock(file_lock); 554621179d81SJeff Layton if (conflock) 554721179d81SJeff Layton locks_free_lock(conflock); 55481da177e4SLinus Torvalds return status; 55491da177e4SLinus Torvalds } 55501da177e4SLinus Torvalds 55511da177e4SLinus Torvalds /* 555255ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 555355ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 555455ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 555555ef1274SJ. Bruce Fields * inode operation.) 555655ef1274SJ. Bruce Fields */ 555704da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 555855ef1274SJ. Bruce Fields { 555955ef1274SJ. Bruce Fields struct file *file; 556004da6e9dSAl Viro __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 556104da6e9dSAl Viro if (!err) { 556204da6e9dSAl Viro err = nfserrno(vfs_test_lock(file, lock)); 5563fd891454SChristoph Hellwig fput(file); 556404da6e9dSAl Viro } 556555ef1274SJ. Bruce Fields return err; 556655ef1274SJ. Bruce Fields } 556755ef1274SJ. Bruce Fields 556855ef1274SJ. Bruce Fields /* 55691da177e4SLinus Torvalds * LOCKT operation 55701da177e4SLinus Torvalds */ 5571b37ad28bSAl Viro __be32 5572ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5573ca364317SJ.Bruce Fields struct nfsd4_lockt *lockt) 55741da177e4SLinus Torvalds { 557521179d81SJeff Layton struct file_lock *file_lock = NULL; 55765db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 5577b37ad28bSAl Viro __be32 status; 55787f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 55791da177e4SLinus Torvalds 55805ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 55811da177e4SLinus Torvalds return nfserr_grace; 55821da177e4SLinus Torvalds 55831da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 55841da177e4SLinus Torvalds return nfserr_inval; 55851da177e4SLinus Torvalds 55869b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 55874b24ca7dSJeff Layton status = lookup_clientid(&lockt->lt_clientid, cstate, nn); 55889b2ef62bSJ. Bruce Fields if (status) 55891da177e4SLinus Torvalds goto out; 55909b2ef62bSJ. Bruce Fields } 55911da177e4SLinus Torvalds 559275c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 55931da177e4SLinus Torvalds goto out; 55941da177e4SLinus Torvalds 559521179d81SJeff Layton file_lock = locks_alloc_lock(); 559621179d81SJeff Layton if (!file_lock) { 559721179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 559821179d81SJeff Layton status = nfserr_jukebox; 559921179d81SJeff Layton goto out; 560021179d81SJeff Layton } 56016cd90662SKinglong Mee 56021da177e4SLinus Torvalds switch (lockt->lt_type) { 56031da177e4SLinus Torvalds case NFS4_READ_LT: 56041da177e4SLinus Torvalds case NFS4_READW_LT: 560521179d81SJeff Layton file_lock->fl_type = F_RDLCK; 56061da177e4SLinus Torvalds break; 56071da177e4SLinus Torvalds case NFS4_WRITE_LT: 56081da177e4SLinus Torvalds case NFS4_WRITEW_LT: 560921179d81SJeff Layton file_lock->fl_type = F_WRLCK; 56101da177e4SLinus Torvalds break; 56111da177e4SLinus Torvalds default: 56122fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 56131da177e4SLinus Torvalds status = nfserr_inval; 56141da177e4SLinus Torvalds goto out; 56151da177e4SLinus Torvalds } 56161da177e4SLinus Torvalds 5617d4f0489fSTrond Myklebust lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner, 5618d4f0489fSTrond Myklebust cstate->clp); 5619fe0750e5SJ. Bruce Fields if (lo) 562021179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 562121179d81SJeff Layton file_lock->fl_pid = current->tgid; 562221179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 56231da177e4SLinus Torvalds 562421179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 562521179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 56261da177e4SLinus Torvalds 562721179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 56281da177e4SLinus Torvalds 562921179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 563004da6e9dSAl Viro if (status) 5631fd85b817SMarc Eshel goto out; 563204da6e9dSAl Viro 563321179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 56341da177e4SLinus Torvalds status = nfserr_denied; 563521179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 56361da177e4SLinus Torvalds } 56371da177e4SLinus Torvalds out: 56385db1c03fSJeff Layton if (lo) 56395db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 564021179d81SJeff Layton if (file_lock) 564121179d81SJeff Layton locks_free_lock(file_lock); 56421da177e4SLinus Torvalds return status; 56431da177e4SLinus Torvalds } 56441da177e4SLinus Torvalds 5645b37ad28bSAl Viro __be32 5646ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5647a4f1706aSJ.Bruce Fields struct nfsd4_locku *locku) 56481da177e4SLinus Torvalds { 5649dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 56501da177e4SLinus Torvalds struct file *filp = NULL; 565121179d81SJeff Layton struct file_lock *file_lock = NULL; 5652b37ad28bSAl Viro __be32 status; 5653b8dd7b9aSAl Viro int err; 56543320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 56551da177e4SLinus Torvalds 56561da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 56571da177e4SLinus Torvalds (long long) locku->lu_offset, 56581da177e4SLinus Torvalds (long long) locku->lu_length); 56591da177e4SLinus Torvalds 56601da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 56611da177e4SLinus Torvalds return nfserr_inval; 56621da177e4SLinus Torvalds 56639072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 56643320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 56653320fef1SStanislav Kinsbursky &stp, nn); 56669072d5c6SJ. Bruce Fields if (status) 56671da177e4SLinus Torvalds goto out; 566811b9164aSTrond Myklebust filp = find_any_file(stp->st_stid.sc_file); 5669f9d7562fSJ. Bruce Fields if (!filp) { 5670f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 5671858cc573STrond Myklebust goto put_stateid; 5672f9d7562fSJ. Bruce Fields } 567321179d81SJeff Layton file_lock = locks_alloc_lock(); 567421179d81SJeff Layton if (!file_lock) { 567521179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 567621179d81SJeff Layton status = nfserr_jukebox; 5677de18643dSTrond Myklebust goto fput; 567821179d81SJeff Layton } 56796cd90662SKinglong Mee 568021179d81SJeff Layton file_lock->fl_type = F_UNLCK; 5681aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 568221179d81SJeff Layton file_lock->fl_pid = current->tgid; 568321179d81SJeff Layton file_lock->fl_file = filp; 568421179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 568521179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 568621179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 56871da177e4SLinus Torvalds 568821179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 568921179d81SJeff Layton locku->lu_length); 569021179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 56911da177e4SLinus Torvalds 569221179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); 5693b8dd7b9aSAl Viro if (err) { 5694fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 56951da177e4SLinus Torvalds goto out_nfserr; 56961da177e4SLinus Torvalds } 5697dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 5698dcef0413SJ. Bruce Fields memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 5699de18643dSTrond Myklebust fput: 5700de18643dSTrond Myklebust fput(filp); 5701858cc573STrond Myklebust put_stateid: 5702858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 57031da177e4SLinus Torvalds out: 57049411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 570521179d81SJeff Layton if (file_lock) 570621179d81SJeff Layton locks_free_lock(file_lock); 57071da177e4SLinus Torvalds return status; 57081da177e4SLinus Torvalds 57091da177e4SLinus Torvalds out_nfserr: 5710b8dd7b9aSAl Viro status = nfserrno(err); 5711de18643dSTrond Myklebust goto fput; 57121da177e4SLinus Torvalds } 57131da177e4SLinus Torvalds 57141da177e4SLinus Torvalds /* 57151da177e4SLinus Torvalds * returns 5716f9c00c3aSJeff Layton * true: locks held by lockowner 5717f9c00c3aSJeff Layton * false: no locks held by lockowner 57181da177e4SLinus Torvalds */ 5719f9c00c3aSJeff Layton static bool 5720f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 57211da177e4SLinus Torvalds { 5722bd61e0a9SJeff Layton struct file_lock *fl; 5723f9c00c3aSJeff Layton int status = false; 5724f9c00c3aSJeff Layton struct file *filp = find_any_file(fp); 5725f9c00c3aSJeff Layton struct inode *inode; 5726bd61e0a9SJeff Layton struct file_lock_context *flctx; 5727f9c00c3aSJeff Layton 5728f9c00c3aSJeff Layton if (!filp) { 5729f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 5730f9c00c3aSJeff Layton WARN_ON_ONCE(1); 5731f9c00c3aSJeff Layton return status; 5732f9c00c3aSJeff Layton } 5733f9c00c3aSJeff Layton 5734f9c00c3aSJeff Layton inode = file_inode(filp); 5735bd61e0a9SJeff Layton flctx = inode->i_flctx; 57361da177e4SLinus Torvalds 5737bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 57386109c850SJeff Layton spin_lock(&flctx->flc_lock); 5739bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 5740bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 5741f9c00c3aSJeff Layton status = true; 5742f9c00c3aSJeff Layton break; 57431da177e4SLinus Torvalds } 5744796dadfdSJ. Bruce Fields } 57456109c850SJeff Layton spin_unlock(&flctx->flc_lock); 5746bd61e0a9SJeff Layton } 5747f9c00c3aSJeff Layton fput(filp); 57481da177e4SLinus Torvalds return status; 57491da177e4SLinus Torvalds } 57501da177e4SLinus Torvalds 5751b37ad28bSAl Viro __be32 5752b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 5753b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 5754b591480bSJ.Bruce Fields struct nfsd4_release_lockowner *rlockowner) 57551da177e4SLinus Torvalds { 57561da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 5757882e9d25SJeff Layton struct nfs4_stateowner *sop; 5758882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 5759dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 57601da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 5761d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 5762b37ad28bSAl Viro __be32 status; 57637f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5764c58c6610STrond Myklebust struct nfs4_client *clp; 57651da177e4SLinus Torvalds 57661da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 57671da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 57681da177e4SLinus Torvalds 57694b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 57709b2ef62bSJ. Bruce Fields if (status) 577151f5e783STrond Myklebust return status; 57729b2ef62bSJ. Bruce Fields 5773d4f0489fSTrond Myklebust clp = cstate->clp; 5774fd44907cSJeff Layton /* Find the matching lock stateowner */ 5775d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5776882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 5777d4f0489fSTrond Myklebust so_strhash) { 5778882e9d25SJeff Layton 5779882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 578016bfdaafSJ. Bruce Fields continue; 5781882e9d25SJeff Layton 5782882e9d25SJeff Layton /* see if there are still any locks associated with it */ 5783882e9d25SJeff Layton lo = lockowner(sop); 5784882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 5785882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 5786882e9d25SJeff Layton status = nfserr_locks_held; 5787882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 578851f5e783STrond Myklebust return status; 5789882e9d25SJeff Layton } 5790882e9d25SJeff Layton } 5791882e9d25SJeff Layton 5792b5971afaSKinglong Mee nfs4_get_stateowner(sop); 5793fd44907cSJeff Layton break; 5794fd44907cSJeff Layton } 5795d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5796882e9d25SJeff Layton if (lo) 5797fe0750e5SJ. Bruce Fields release_lockowner(lo); 57981da177e4SLinus Torvalds return status; 57991da177e4SLinus Torvalds } 58001da177e4SLinus Torvalds 58011da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 5802a55370a3SNeilBrown alloc_reclaim(void) 58031da177e4SLinus Torvalds { 5804a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 58051da177e4SLinus Torvalds } 58061da177e4SLinus Torvalds 58070ce0c2b5SJeff Layton bool 580852e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 5809c7b9a459SNeilBrown { 58100ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 5811c7b9a459SNeilBrown 581252e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 58130ce0c2b5SJeff Layton return (crp && crp->cr_clp); 5814c7b9a459SNeilBrown } 5815c7b9a459SNeilBrown 58161da177e4SLinus Torvalds /* 58171da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 58181da177e4SLinus Torvalds */ 5819772a9bbbSJeff Layton struct nfs4_client_reclaim * 582052e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 58211da177e4SLinus Torvalds { 58221da177e4SLinus Torvalds unsigned int strhashval; 5823772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 58241da177e4SLinus Torvalds 5825a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 5826a55370a3SNeilBrown crp = alloc_reclaim(); 5827772a9bbbSJeff Layton if (crp) { 5828a55370a3SNeilBrown strhashval = clientstr_hashval(name); 58291da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 583052e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 5831a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 58320ce0c2b5SJeff Layton crp->cr_clp = NULL; 583352e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 5834772a9bbbSJeff Layton } 5835772a9bbbSJeff Layton return crp; 58361da177e4SLinus Torvalds } 58371da177e4SLinus Torvalds 58382a4317c5SJeff Layton void 583952e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 5840ce30e539SJeff Layton { 5841ce30e539SJeff Layton list_del(&crp->cr_strhash); 5842ce30e539SJeff Layton kfree(crp); 584352e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 5844ce30e539SJeff Layton } 5845ce30e539SJeff Layton 5846ce30e539SJeff Layton void 584752e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 58481da177e4SLinus Torvalds { 58491da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 58501da177e4SLinus Torvalds int i; 58511da177e4SLinus Torvalds 58521da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 585352e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 585452e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 58551da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 585652e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 58571da177e4SLinus Torvalds } 58581da177e4SLinus Torvalds } 5859063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 58601da177e4SLinus Torvalds } 58611da177e4SLinus Torvalds 58621da177e4SLinus Torvalds /* 58631da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 58642a4317c5SJeff Layton struct nfs4_client_reclaim * 586552e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 58661da177e4SLinus Torvalds { 58671da177e4SLinus Torvalds unsigned int strhashval; 58681da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 58691da177e4SLinus Torvalds 5870278c931cSJeff Layton dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 58711da177e4SLinus Torvalds 5872278c931cSJeff Layton strhashval = clientstr_hashval(recdir); 587352e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 5874278c931cSJeff Layton if (same_name(crp->cr_recdir, recdir)) { 58751da177e4SLinus Torvalds return crp; 58761da177e4SLinus Torvalds } 58771da177e4SLinus Torvalds } 58781da177e4SLinus Torvalds return NULL; 58791da177e4SLinus Torvalds } 58801da177e4SLinus Torvalds 58811da177e4SLinus Torvalds /* 58821da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 58831da177e4SLinus Torvalds */ 5884b37ad28bSAl Viro __be32 58850fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 58860fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 58870fe492dbSTrond Myklebust struct nfsd_net *nn) 58881da177e4SLinus Torvalds { 58890fe492dbSTrond Myklebust __be32 status; 5890a52d726bSJeff Layton 5891a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 58920fe492dbSTrond Myklebust status = lookup_clientid(clid, cstate, nn); 58930fe492dbSTrond Myklebust if (status) 5894a52d726bSJeff Layton return nfserr_reclaim_bad; 5895a52d726bSJeff Layton 58963b3e7b72SJeff Layton if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) 58973b3e7b72SJeff Layton return nfserr_no_grace; 58983b3e7b72SJeff Layton 58990fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 59000fe492dbSTrond Myklebust return nfserr_reclaim_bad; 59010fe492dbSTrond Myklebust 59020fe492dbSTrond Myklebust return nfs_ok; 59031da177e4SLinus Torvalds } 59041da177e4SLinus Torvalds 590565178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 5906016200c3SJeff Layton static inline void 5907016200c3SJeff Layton put_client(struct nfs4_client *clp) 5908016200c3SJeff Layton { 5909016200c3SJeff Layton atomic_dec(&clp->cl_refcount); 5910016200c3SJeff Layton } 5911016200c3SJeff Layton 5912285abdeeSJeff Layton static struct nfs4_client * 5913285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 5914285abdeeSJeff Layton { 5915285abdeeSJeff Layton struct nfs4_client *clp; 5916285abdeeSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5917285abdeeSJeff Layton nfsd_net_id); 5918285abdeeSJeff Layton 5919285abdeeSJeff Layton if (!nfsd_netns_ready(nn)) 5920285abdeeSJeff Layton return NULL; 5921285abdeeSJeff Layton 5922285abdeeSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 5923285abdeeSJeff Layton if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 5924285abdeeSJeff Layton return clp; 5925285abdeeSJeff Layton } 5926285abdeeSJeff Layton return NULL; 5927285abdeeSJeff Layton } 5928285abdeeSJeff Layton 59297ec0e36fSJeff Layton u64 5930285abdeeSJeff Layton nfsd_inject_print_clients(void) 59317ec0e36fSJeff Layton { 59327ec0e36fSJeff Layton struct nfs4_client *clp; 59337ec0e36fSJeff Layton u64 count = 0; 59347ec0e36fSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 59357ec0e36fSJeff Layton nfsd_net_id); 59367ec0e36fSJeff Layton char buf[INET6_ADDRSTRLEN]; 59377ec0e36fSJeff Layton 59387ec0e36fSJeff Layton if (!nfsd_netns_ready(nn)) 59397ec0e36fSJeff Layton return 0; 59407ec0e36fSJeff Layton 59417ec0e36fSJeff Layton spin_lock(&nn->client_lock); 59427ec0e36fSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 59437ec0e36fSJeff Layton rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 59447ec0e36fSJeff Layton pr_info("NFS Client: %s\n", buf); 59457ec0e36fSJeff Layton ++count; 59467ec0e36fSJeff Layton } 59477ec0e36fSJeff Layton spin_unlock(&nn->client_lock); 59487ec0e36fSJeff Layton 59497ec0e36fSJeff Layton return count; 59507ec0e36fSJeff Layton } 595165178db4SBryan Schumaker 5952a0926d15SJeff Layton u64 5953285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) 5954a0926d15SJeff Layton { 5955a0926d15SJeff Layton u64 count = 0; 5956a0926d15SJeff Layton struct nfs4_client *clp; 5957a0926d15SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 5958a0926d15SJeff Layton nfsd_net_id); 5959a0926d15SJeff Layton 5960a0926d15SJeff Layton if (!nfsd_netns_ready(nn)) 5961a0926d15SJeff Layton return count; 5962a0926d15SJeff Layton 5963a0926d15SJeff Layton spin_lock(&nn->client_lock); 5964a0926d15SJeff Layton clp = nfsd_find_client(addr, addr_size); 5965a0926d15SJeff Layton if (clp) { 5966a0926d15SJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) 5967a0926d15SJeff Layton ++count; 5968a0926d15SJeff Layton else 5969a0926d15SJeff Layton clp = NULL; 5970a0926d15SJeff Layton } 5971a0926d15SJeff Layton spin_unlock(&nn->client_lock); 5972a0926d15SJeff Layton 5973a0926d15SJeff Layton if (clp) 5974a0926d15SJeff Layton expire_client(clp); 5975a0926d15SJeff Layton 5976a0926d15SJeff Layton return count; 5977a0926d15SJeff Layton } 5978a0926d15SJeff Layton 597969fc9edfSJeff Layton u64 5980285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max) 598169fc9edfSJeff Layton { 598269fc9edfSJeff Layton u64 count = 0; 598369fc9edfSJeff Layton struct nfs4_client *clp, *next; 598469fc9edfSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 598569fc9edfSJeff Layton nfsd_net_id); 598669fc9edfSJeff Layton LIST_HEAD(reaplist); 598769fc9edfSJeff Layton 598869fc9edfSJeff Layton if (!nfsd_netns_ready(nn)) 598969fc9edfSJeff Layton return count; 599069fc9edfSJeff Layton 599169fc9edfSJeff Layton spin_lock(&nn->client_lock); 599269fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 599369fc9edfSJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) { 599469fc9edfSJeff Layton list_add(&clp->cl_lru, &reaplist); 599569fc9edfSJeff Layton if (max != 0 && ++count >= max) 599669fc9edfSJeff Layton break; 599769fc9edfSJeff Layton } 599869fc9edfSJeff Layton } 599969fc9edfSJeff Layton spin_unlock(&nn->client_lock); 600069fc9edfSJeff Layton 600169fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &reaplist, cl_lru) 600269fc9edfSJeff Layton expire_client(clp); 600369fc9edfSJeff Layton 600469fc9edfSJeff Layton return count; 600569fc9edfSJeff Layton } 600669fc9edfSJeff Layton 6007184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 6008184c1847SBryan Schumaker const char *type) 6009184c1847SBryan Schumaker { 6010184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 60110a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 6012184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 6013184c1847SBryan Schumaker } 6014184c1847SBryan Schumaker 6015016200c3SJeff Layton static void 6016016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, 6017016200c3SJeff Layton struct list_head *collect) 6018016200c3SJeff Layton { 6019016200c3SJeff Layton struct nfs4_client *clp = lst->st_stid.sc_client; 6020016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6021016200c3SJeff Layton nfsd_net_id); 6022016200c3SJeff Layton 6023016200c3SJeff Layton if (!collect) 6024016200c3SJeff Layton return; 6025016200c3SJeff Layton 6026016200c3SJeff Layton lockdep_assert_held(&nn->client_lock); 6027016200c3SJeff Layton atomic_inc(&clp->cl_refcount); 6028016200c3SJeff Layton list_add(&lst->st_locks, collect); 6029016200c3SJeff Layton } 6030016200c3SJeff Layton 60313c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 60323738d50eSJeff Layton struct list_head *collect, 60333c87b9b7STrond Myklebust void (*func)(struct nfs4_ol_stateid *)) 6034fc29171fSBryan Schumaker { 6035fc29171fSBryan Schumaker struct nfs4_openowner *oop; 6036fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 60373c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 6038fc29171fSBryan Schumaker u64 count = 0; 6039fc29171fSBryan Schumaker 6040016200c3SJeff Layton spin_lock(&clp->cl_lock); 6041fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 60423c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 60433c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 60443c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 60453c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 60463738d50eSJeff Layton if (func) { 60473c87b9b7STrond Myklebust func(lst); 6048016200c3SJeff Layton nfsd_inject_add_lock_to_list(lst, 60493738d50eSJeff Layton collect); 60503738d50eSJeff Layton } 6051016200c3SJeff Layton ++count; 6052016200c3SJeff Layton /* 6053016200c3SJeff Layton * Despite the fact that these functions deal 6054016200c3SJeff Layton * with 64-bit integers for "count", we must 6055016200c3SJeff Layton * ensure that it doesn't blow up the 6056016200c3SJeff Layton * clp->cl_refcount. Throw a warning if we 6057016200c3SJeff Layton * start to approach INT_MAX here. 6058016200c3SJeff Layton */ 6059016200c3SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 6060016200c3SJeff Layton if (count == max) 6061016200c3SJeff Layton goto out; 6062fc29171fSBryan Schumaker } 6063fc29171fSBryan Schumaker } 6064fc29171fSBryan Schumaker } 6065016200c3SJeff Layton out: 6066016200c3SJeff Layton spin_unlock(&clp->cl_lock); 6067fc29171fSBryan Schumaker 6068fc29171fSBryan Schumaker return count; 6069fc29171fSBryan Schumaker } 6070fc29171fSBryan Schumaker 6071016200c3SJeff Layton static u64 6072016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, 6073016200c3SJeff Layton u64 max) 6074fc29171fSBryan Schumaker { 6075016200c3SJeff Layton return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); 6076fc29171fSBryan Schumaker } 6077fc29171fSBryan Schumaker 6078016200c3SJeff Layton static u64 6079016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp) 6080184c1847SBryan Schumaker { 6081016200c3SJeff Layton u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); 6082184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 6083184c1847SBryan Schumaker return count; 6084184c1847SBryan Schumaker } 6085184c1847SBryan Schumaker 6086016200c3SJeff Layton u64 6087285abdeeSJeff Layton nfsd_inject_print_locks(void) 6088016200c3SJeff Layton { 6089016200c3SJeff Layton struct nfs4_client *clp; 6090016200c3SJeff Layton u64 count = 0; 6091016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6092016200c3SJeff Layton nfsd_net_id); 6093016200c3SJeff Layton 6094016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6095016200c3SJeff Layton return 0; 6096016200c3SJeff Layton 6097016200c3SJeff Layton spin_lock(&nn->client_lock); 6098016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 6099016200c3SJeff Layton count += nfsd_print_client_locks(clp); 6100016200c3SJeff Layton spin_unlock(&nn->client_lock); 6101016200c3SJeff Layton 6102016200c3SJeff Layton return count; 6103016200c3SJeff Layton } 6104016200c3SJeff Layton 6105016200c3SJeff Layton static void 6106016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist) 6107016200c3SJeff Layton { 6108016200c3SJeff Layton struct nfs4_client *clp; 6109016200c3SJeff Layton struct nfs4_ol_stateid *stp, *next; 6110016200c3SJeff Layton 6111016200c3SJeff Layton list_for_each_entry_safe(stp, next, reaplist, st_locks) { 6112016200c3SJeff Layton list_del_init(&stp->st_locks); 6113016200c3SJeff Layton clp = stp->st_stid.sc_client; 6114016200c3SJeff Layton nfs4_put_stid(&stp->st_stid); 6115016200c3SJeff Layton put_client(clp); 6116016200c3SJeff Layton } 6117016200c3SJeff Layton } 6118016200c3SJeff Layton 6119016200c3SJeff Layton u64 6120285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) 6121016200c3SJeff Layton { 6122016200c3SJeff Layton unsigned int count = 0; 6123016200c3SJeff Layton struct nfs4_client *clp; 6124016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6125016200c3SJeff Layton nfsd_net_id); 6126016200c3SJeff Layton LIST_HEAD(reaplist); 6127016200c3SJeff Layton 6128016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6129016200c3SJeff Layton return count; 6130016200c3SJeff Layton 6131016200c3SJeff Layton spin_lock(&nn->client_lock); 6132016200c3SJeff Layton clp = nfsd_find_client(addr, addr_size); 6133016200c3SJeff Layton if (clp) 6134016200c3SJeff Layton count = nfsd_collect_client_locks(clp, &reaplist, 0); 6135016200c3SJeff Layton spin_unlock(&nn->client_lock); 6136016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6137016200c3SJeff Layton return count; 6138016200c3SJeff Layton } 6139016200c3SJeff Layton 6140016200c3SJeff Layton u64 6141285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max) 6142016200c3SJeff Layton { 6143016200c3SJeff Layton u64 count = 0; 6144016200c3SJeff Layton struct nfs4_client *clp; 6145016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6146016200c3SJeff Layton nfsd_net_id); 6147016200c3SJeff Layton LIST_HEAD(reaplist); 6148016200c3SJeff Layton 6149016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6150016200c3SJeff Layton return count; 6151016200c3SJeff Layton 6152016200c3SJeff Layton spin_lock(&nn->client_lock); 6153016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 6154016200c3SJeff Layton count += nfsd_collect_client_locks(clp, &reaplist, max - count); 6155016200c3SJeff Layton if (max != 0 && count >= max) 6156016200c3SJeff Layton break; 6157016200c3SJeff Layton } 6158016200c3SJeff Layton spin_unlock(&nn->client_lock); 6159016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6160016200c3SJeff Layton return count; 6161016200c3SJeff Layton } 6162016200c3SJeff Layton 616382e05efaSJeff Layton static u64 616482e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, 616582e05efaSJeff Layton struct list_head *collect, 616682e05efaSJeff Layton void (*func)(struct nfs4_openowner *)) 61674dbdbda8SBryan Schumaker { 61684dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 616982e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 617082e05efaSJeff Layton nfsd_net_id); 61714dbdbda8SBryan Schumaker u64 count = 0; 61724dbdbda8SBryan Schumaker 617382e05efaSJeff Layton lockdep_assert_held(&nn->client_lock); 617482e05efaSJeff Layton 617582e05efaSJeff Layton spin_lock(&clp->cl_lock); 61764dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 617782e05efaSJeff Layton if (func) { 61784dbdbda8SBryan Schumaker func(oop); 617982e05efaSJeff Layton if (collect) { 618082e05efaSJeff Layton atomic_inc(&clp->cl_refcount); 618182e05efaSJeff Layton list_add(&oop->oo_perclient, collect); 618282e05efaSJeff Layton } 618382e05efaSJeff Layton } 618482e05efaSJeff Layton ++count; 618582e05efaSJeff Layton /* 618682e05efaSJeff Layton * Despite the fact that these functions deal with 618782e05efaSJeff Layton * 64-bit integers for "count", we must ensure that 618882e05efaSJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 618982e05efaSJeff Layton * warning if we start to approach INT_MAX here. 619082e05efaSJeff Layton */ 619182e05efaSJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 619282e05efaSJeff Layton if (count == max) 61934dbdbda8SBryan Schumaker break; 61944dbdbda8SBryan Schumaker } 619582e05efaSJeff Layton spin_unlock(&clp->cl_lock); 61964dbdbda8SBryan Schumaker 61974dbdbda8SBryan Schumaker return count; 61984dbdbda8SBryan Schumaker } 61994dbdbda8SBryan Schumaker 620082e05efaSJeff Layton static u64 620182e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp) 62024dbdbda8SBryan Schumaker { 620382e05efaSJeff Layton u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); 620482e05efaSJeff Layton 620582e05efaSJeff Layton nfsd_print_count(clp, count, "openowners"); 620682e05efaSJeff Layton return count; 62074dbdbda8SBryan Schumaker } 62084dbdbda8SBryan Schumaker 620982e05efaSJeff Layton static u64 621082e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp, 621182e05efaSJeff Layton struct list_head *collect, u64 max) 6212184c1847SBryan Schumaker { 621382e05efaSJeff Layton return nfsd_foreach_client_openowner(clp, max, collect, 621482e05efaSJeff Layton unhash_openowner_locked); 621582e05efaSJeff Layton } 621682e05efaSJeff Layton 621782e05efaSJeff Layton u64 6218285abdeeSJeff Layton nfsd_inject_print_openowners(void) 621982e05efaSJeff Layton { 622082e05efaSJeff Layton struct nfs4_client *clp; 622182e05efaSJeff Layton u64 count = 0; 622282e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 622382e05efaSJeff Layton nfsd_net_id); 622482e05efaSJeff Layton 622582e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 622682e05efaSJeff Layton return 0; 622782e05efaSJeff Layton 622882e05efaSJeff Layton spin_lock(&nn->client_lock); 622982e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 623082e05efaSJeff Layton count += nfsd_print_client_openowners(clp); 623182e05efaSJeff Layton spin_unlock(&nn->client_lock); 623282e05efaSJeff Layton 623382e05efaSJeff Layton return count; 623482e05efaSJeff Layton } 623582e05efaSJeff Layton 623682e05efaSJeff Layton static void 623782e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist) 623882e05efaSJeff Layton { 623982e05efaSJeff Layton struct nfs4_client *clp; 624082e05efaSJeff Layton struct nfs4_openowner *oop, *next; 624182e05efaSJeff Layton 624282e05efaSJeff Layton list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { 624382e05efaSJeff Layton list_del_init(&oop->oo_perclient); 624482e05efaSJeff Layton clp = oop->oo_owner.so_client; 624582e05efaSJeff Layton release_openowner(oop); 624682e05efaSJeff Layton put_client(clp); 624782e05efaSJeff Layton } 624882e05efaSJeff Layton } 624982e05efaSJeff Layton 625082e05efaSJeff Layton u64 6251285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, 6252285abdeeSJeff Layton size_t addr_size) 625382e05efaSJeff Layton { 625482e05efaSJeff Layton unsigned int count = 0; 625582e05efaSJeff Layton struct nfs4_client *clp; 625682e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 625782e05efaSJeff Layton nfsd_net_id); 625882e05efaSJeff Layton LIST_HEAD(reaplist); 625982e05efaSJeff Layton 626082e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 626182e05efaSJeff Layton return count; 626282e05efaSJeff Layton 626382e05efaSJeff Layton spin_lock(&nn->client_lock); 626482e05efaSJeff Layton clp = nfsd_find_client(addr, addr_size); 626582e05efaSJeff Layton if (clp) 626682e05efaSJeff Layton count = nfsd_collect_client_openowners(clp, &reaplist, 0); 626782e05efaSJeff Layton spin_unlock(&nn->client_lock); 626882e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 626982e05efaSJeff Layton return count; 627082e05efaSJeff Layton } 627182e05efaSJeff Layton 627282e05efaSJeff Layton u64 6273285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max) 627482e05efaSJeff Layton { 627582e05efaSJeff Layton u64 count = 0; 627682e05efaSJeff Layton struct nfs4_client *clp; 627782e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 627882e05efaSJeff Layton nfsd_net_id); 627982e05efaSJeff Layton LIST_HEAD(reaplist); 628082e05efaSJeff Layton 628182e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 628282e05efaSJeff Layton return count; 628382e05efaSJeff Layton 628482e05efaSJeff Layton spin_lock(&nn->client_lock); 628582e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 628682e05efaSJeff Layton count += nfsd_collect_client_openowners(clp, &reaplist, 628782e05efaSJeff Layton max - count); 628882e05efaSJeff Layton if (max != 0 && count >= max) 628982e05efaSJeff Layton break; 629082e05efaSJeff Layton } 629182e05efaSJeff Layton spin_unlock(&nn->client_lock); 629282e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 6293184c1847SBryan Schumaker return count; 6294184c1847SBryan Schumaker } 6295184c1847SBryan Schumaker 6296269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 6297269de30fSBryan Schumaker struct list_head *victims) 6298269de30fSBryan Schumaker { 6299269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 630098d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 630198d5c7c5SJeff Layton nfsd_net_id); 6302269de30fSBryan Schumaker u64 count = 0; 6303269de30fSBryan Schumaker 630498d5c7c5SJeff Layton lockdep_assert_held(&nn->client_lock); 630598d5c7c5SJeff Layton 630698d5c7c5SJeff Layton spin_lock(&state_lock); 6307269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 6308dff1399fSJeff Layton if (victims) { 6309dff1399fSJeff Layton /* 6310dff1399fSJeff Layton * It's not safe to mess with delegations that have a 6311dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 6312dff1399fSJeff Layton * and could be processed by the laundromat outside of 6313dff1399fSJeff Layton * the state_lock. Just leave them be. 6314dff1399fSJeff Layton */ 6315dff1399fSJeff Layton if (dp->dl_time != 0) 6316dff1399fSJeff Layton continue; 6317dff1399fSJeff Layton 631898d5c7c5SJeff Layton atomic_inc(&clp->cl_refcount); 631942690676SJeff Layton unhash_delegation_locked(dp); 632042690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 6321dff1399fSJeff Layton } 632298d5c7c5SJeff Layton ++count; 632398d5c7c5SJeff Layton /* 632498d5c7c5SJeff Layton * Despite the fact that these functions deal with 632598d5c7c5SJeff Layton * 64-bit integers for "count", we must ensure that 632698d5c7c5SJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 632798d5c7c5SJeff Layton * warning if we start to approach INT_MAX here. 632898d5c7c5SJeff Layton */ 632998d5c7c5SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 633098d5c7c5SJeff Layton if (count == max) 6331269de30fSBryan Schumaker break; 6332269de30fSBryan Schumaker } 633398d5c7c5SJeff Layton spin_unlock(&state_lock); 6334269de30fSBryan Schumaker return count; 6335269de30fSBryan Schumaker } 6336269de30fSBryan Schumaker 633798d5c7c5SJeff Layton static u64 633898d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp) 6339269de30fSBryan Schumaker { 634098d5c7c5SJeff Layton u64 count = nfsd_find_all_delegations(clp, 0, NULL); 6341184c1847SBryan Schumaker 6342184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 6343184c1847SBryan Schumaker return count; 6344184c1847SBryan Schumaker } 6345184c1847SBryan Schumaker 634698d5c7c5SJeff Layton u64 6347285abdeeSJeff Layton nfsd_inject_print_delegations(void) 634898d5c7c5SJeff Layton { 634998d5c7c5SJeff Layton struct nfs4_client *clp; 635098d5c7c5SJeff Layton u64 count = 0; 635198d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 635298d5c7c5SJeff Layton nfsd_net_id); 635398d5c7c5SJeff Layton 635498d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 635598d5c7c5SJeff Layton return 0; 635698d5c7c5SJeff Layton 635798d5c7c5SJeff Layton spin_lock(&nn->client_lock); 635898d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 635998d5c7c5SJeff Layton count += nfsd_print_client_delegations(clp); 636098d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 636198d5c7c5SJeff Layton 636298d5c7c5SJeff Layton return count; 636398d5c7c5SJeff Layton } 636498d5c7c5SJeff Layton 636598d5c7c5SJeff Layton static void 636698d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist) 636798d5c7c5SJeff Layton { 636898d5c7c5SJeff Layton struct nfs4_client *clp; 636998d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 637098d5c7c5SJeff Layton 637198d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 637298d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 637398d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 637498d5c7c5SJeff Layton revoke_delegation(dp); 637598d5c7c5SJeff Layton put_client(clp); 637698d5c7c5SJeff Layton } 637798d5c7c5SJeff Layton } 637898d5c7c5SJeff Layton 637998d5c7c5SJeff Layton u64 6380285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, 6381285abdeeSJeff Layton size_t addr_size) 638298d5c7c5SJeff Layton { 638398d5c7c5SJeff Layton u64 count = 0; 638498d5c7c5SJeff Layton struct nfs4_client *clp; 638598d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 638698d5c7c5SJeff Layton nfsd_net_id); 638798d5c7c5SJeff Layton LIST_HEAD(reaplist); 638898d5c7c5SJeff Layton 638998d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 639098d5c7c5SJeff Layton return count; 639198d5c7c5SJeff Layton 639298d5c7c5SJeff Layton spin_lock(&nn->client_lock); 639398d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 639498d5c7c5SJeff Layton if (clp) 639598d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 639698d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 639798d5c7c5SJeff Layton 639898d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 639998d5c7c5SJeff Layton return count; 640098d5c7c5SJeff Layton } 640198d5c7c5SJeff Layton 640298d5c7c5SJeff Layton u64 6403285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max) 640498d5c7c5SJeff Layton { 640598d5c7c5SJeff Layton u64 count = 0; 640698d5c7c5SJeff Layton struct nfs4_client *clp; 640798d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 640898d5c7c5SJeff Layton nfsd_net_id); 640998d5c7c5SJeff Layton LIST_HEAD(reaplist); 641098d5c7c5SJeff Layton 641198d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 641298d5c7c5SJeff Layton return count; 641398d5c7c5SJeff Layton 641498d5c7c5SJeff Layton spin_lock(&nn->client_lock); 641598d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 641698d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 641798d5c7c5SJeff Layton if (max != 0 && count >= max) 641898d5c7c5SJeff Layton break; 641998d5c7c5SJeff Layton } 642098d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 642198d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 642298d5c7c5SJeff Layton return count; 642398d5c7c5SJeff Layton } 642498d5c7c5SJeff Layton 642598d5c7c5SJeff Layton static void 642698d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist) 642798d5c7c5SJeff Layton { 642898d5c7c5SJeff Layton struct nfs4_client *clp; 642998d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 643098d5c7c5SJeff Layton 643198d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 643298d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 643398d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 643498d5c7c5SJeff Layton /* 643598d5c7c5SJeff Layton * We skipped all entries that had a zero dl_time before, 643698d5c7c5SJeff Layton * so we can now reset the dl_time back to 0. If a delegation 643798d5c7c5SJeff Layton * break comes in now, then it won't make any difference since 643898d5c7c5SJeff Layton * we're recalling it either way. 643998d5c7c5SJeff Layton */ 644098d5c7c5SJeff Layton spin_lock(&state_lock); 644198d5c7c5SJeff Layton dp->dl_time = 0; 644298d5c7c5SJeff Layton spin_unlock(&state_lock); 644398d5c7c5SJeff Layton nfsd_break_one_deleg(dp); 644498d5c7c5SJeff Layton put_client(clp); 644598d5c7c5SJeff Layton } 644698d5c7c5SJeff Layton } 644798d5c7c5SJeff Layton 644898d5c7c5SJeff Layton u64 6449285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, 645098d5c7c5SJeff Layton size_t addr_size) 645198d5c7c5SJeff Layton { 645298d5c7c5SJeff Layton u64 count = 0; 645398d5c7c5SJeff Layton struct nfs4_client *clp; 645498d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 645598d5c7c5SJeff Layton nfsd_net_id); 645698d5c7c5SJeff Layton LIST_HEAD(reaplist); 645798d5c7c5SJeff Layton 645898d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 645998d5c7c5SJeff Layton return count; 646098d5c7c5SJeff Layton 646198d5c7c5SJeff Layton spin_lock(&nn->client_lock); 646298d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 646398d5c7c5SJeff Layton if (clp) 646498d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 646598d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 646698d5c7c5SJeff Layton 646798d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 646898d5c7c5SJeff Layton return count; 646998d5c7c5SJeff Layton } 647098d5c7c5SJeff Layton 647198d5c7c5SJeff Layton u64 6472285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max) 647398d5c7c5SJeff Layton { 647498d5c7c5SJeff Layton u64 count = 0; 647598d5c7c5SJeff Layton struct nfs4_client *clp, *next; 647698d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 647798d5c7c5SJeff Layton nfsd_net_id); 647898d5c7c5SJeff Layton LIST_HEAD(reaplist); 647998d5c7c5SJeff Layton 648098d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 648198d5c7c5SJeff Layton return count; 648298d5c7c5SJeff Layton 648398d5c7c5SJeff Layton spin_lock(&nn->client_lock); 648498d5c7c5SJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 648598d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 648698d5c7c5SJeff Layton if (max != 0 && ++count >= max) 648798d5c7c5SJeff Layton break; 648898d5c7c5SJeff Layton } 648998d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 649098d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 649198d5c7c5SJeff Layton return count; 649298d5c7c5SJeff Layton } 649365178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 649465178db4SBryan Schumaker 6495c2f1a551SMeelap Shah /* 6496c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 6497c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 6498c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 6499c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 6500c2f1a551SMeelap Shah * 6501c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 6502c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 6503c2f1a551SMeelap Shah */ 6504c2f1a551SMeelap Shah static void 6505c2f1a551SMeelap Shah set_max_delegations(void) 6506c2f1a551SMeelap Shah { 6507c2f1a551SMeelap Shah /* 6508c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 6509c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 6510c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 6511c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 6512c2f1a551SMeelap Shah */ 6513c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 6514c2f1a551SMeelap Shah } 6515c2f1a551SMeelap Shah 6516d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 65178daae4dcSStanislav Kinsbursky { 65188daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 65198daae4dcSStanislav Kinsbursky int i; 65208daae4dcSStanislav Kinsbursky 65218daae4dcSStanislav Kinsbursky nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * 65228daae4dcSStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 65238daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 6524382a62e7SStanislav Kinsbursky goto err; 65250a7ec377SStanislav Kinsbursky nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * 65260a7ec377SStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 65270a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 65280a7ec377SStanislav Kinsbursky goto err_unconf_id; 65291872de0eSStanislav Kinsbursky nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * 65301872de0eSStanislav Kinsbursky SESSION_HASH_SIZE, GFP_KERNEL); 65311872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 65321872de0eSStanislav Kinsbursky goto err_sessionid; 65338daae4dcSStanislav Kinsbursky 6534382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 65358daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 65360a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 6537382a62e7SStanislav Kinsbursky } 65381872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 65391872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 6540382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 6541a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 65425ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 654373758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 6544e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 6545c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 65468daae4dcSStanislav Kinsbursky 654709121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 6548d85ed443SStanislav Kinsbursky get_net(net); 654909121281SStanislav Kinsbursky 65508daae4dcSStanislav Kinsbursky return 0; 6551382a62e7SStanislav Kinsbursky 65521872de0eSStanislav Kinsbursky err_sessionid: 65539b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 65540a7ec377SStanislav Kinsbursky err_unconf_id: 65550a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 6556382a62e7SStanislav Kinsbursky err: 6557382a62e7SStanislav Kinsbursky return -ENOMEM; 65588daae4dcSStanislav Kinsbursky } 65598daae4dcSStanislav Kinsbursky 65608daae4dcSStanislav Kinsbursky static void 65614dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 65628daae4dcSStanislav Kinsbursky { 65638daae4dcSStanislav Kinsbursky int i; 65648daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 65658daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 65668daae4dcSStanislav Kinsbursky 65678daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 65688daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 65698daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 65708daae4dcSStanislav Kinsbursky destroy_client(clp); 65718daae4dcSStanislav Kinsbursky } 65728daae4dcSStanislav Kinsbursky } 6573a99454aaSStanislav Kinsbursky 65742b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 65752b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 65762b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 6577a99454aaSStanislav Kinsbursky destroy_client(clp); 6578a99454aaSStanislav Kinsbursky } 65792b905635SKinglong Mee } 6580a99454aaSStanislav Kinsbursky 65811872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 65820a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 65838daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 65844dce0ac9SStanislav Kinsbursky put_net(net); 65858daae4dcSStanislav Kinsbursky } 65868daae4dcSStanislav Kinsbursky 6587f252bc68SStanislav Kinsbursky int 6588d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 6589ac4d8ff2SNeilBrown { 65905e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 6591b5a1a81eSJ. Bruce Fields int ret; 6592b5a1a81eSJ. Bruce Fields 6593d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 65948daae4dcSStanislav Kinsbursky if (ret) 65958daae4dcSStanislav Kinsbursky return ret; 65962c142baaSStanislav Kinsbursky nn->boot_time = get_seconds(); 6597a51c84edSStanislav Kinsbursky nn->grace_ended = false; 6598d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 6599d4318acdSJeff Layton nfsd4_client_tracking_init(net); 6600d85ed443SStanislav Kinsbursky printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", 66015284b44eSStanislav Kinsbursky nn->nfsd4_grace, net); 66025284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 6603d85ed443SStanislav Kinsbursky return 0; 6604a6d6b781SJeff Layton } 6605d85ed443SStanislav Kinsbursky 6606d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 6607d85ed443SStanislav Kinsbursky 6608d85ed443SStanislav Kinsbursky int 6609d85ed443SStanislav Kinsbursky nfs4_state_start(void) 6610d85ed443SStanislav Kinsbursky { 6611d85ed443SStanislav Kinsbursky int ret; 6612d85ed443SStanislav Kinsbursky 6613d85ed443SStanislav Kinsbursky ret = set_callback_cred(); 6614d85ed443SStanislav Kinsbursky if (ret) 6615d85ed443SStanislav Kinsbursky return -ENOMEM; 661658da282bSNeilBrown laundry_wq = create_singlethread_workqueue("nfsd4"); 6617a6d6b781SJeff Layton if (laundry_wq == NULL) { 6618a6d6b781SJeff Layton ret = -ENOMEM; 6619a6d6b781SJeff Layton goto out_recovery; 6620a6d6b781SJeff Layton } 6621b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 6622b5a1a81eSJ. Bruce Fields if (ret) 6623b5a1a81eSJ. Bruce Fields goto out_free_laundry; 662409121281SStanislav Kinsbursky 6625c2f1a551SMeelap Shah set_max_delegations(); 6626d85ed443SStanislav Kinsbursky 6627b5a1a81eSJ. Bruce Fields return 0; 6628d85ed443SStanislav Kinsbursky 6629b5a1a81eSJ. Bruce Fields out_free_laundry: 6630b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 6631a6d6b781SJeff Layton out_recovery: 6632b5a1a81eSJ. Bruce Fields return ret; 66331da177e4SLinus Torvalds } 66341da177e4SLinus Torvalds 6635f252bc68SStanislav Kinsbursky void 66364dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 66371da177e4SLinus Torvalds { 66381da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 66391da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 66404dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 66411da177e4SLinus Torvalds 66424dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 66434dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 6644ac55fdc4SJeff Layton 66451da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 6646cdc97505SBenny Halevy spin_lock(&state_lock); 6647e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 66481da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 664942690676SJeff Layton unhash_delegation_locked(dp); 665042690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 66511da177e4SLinus Torvalds } 6652cdc97505SBenny Halevy spin_unlock(&state_lock); 66531da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 66541da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 665542690676SJeff Layton list_del_init(&dp->dl_recall_lru); 66568287f009SSachin Bhamare put_clnt_odstate(dp->dl_clnt_odstate); 6657afbda402SJeff Layton nfs4_put_deleg_lease(dp->dl_stid.sc_file); 66586011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 66591da177e4SLinus Torvalds } 66601da177e4SLinus Torvalds 66613320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 66624dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 66631da177e4SLinus Torvalds } 66641da177e4SLinus Torvalds 66651da177e4SLinus Torvalds void 66661da177e4SLinus Torvalds nfs4_state_shutdown(void) 66671da177e4SLinus Torvalds { 66685e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 6669c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 66701da177e4SLinus Torvalds } 66718b70484cSTigran Mkrtchyan 66728b70484cSTigran Mkrtchyan static void 66738b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 66748b70484cSTigran Mkrtchyan { 667537c593c5STigran Mkrtchyan if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) 667637c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 66778b70484cSTigran Mkrtchyan } 66788b70484cSTigran Mkrtchyan 66798b70484cSTigran Mkrtchyan static void 66808b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 66818b70484cSTigran Mkrtchyan { 668237c593c5STigran Mkrtchyan if (cstate->minorversion) { 668337c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 668437c593c5STigran Mkrtchyan SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 668537c593c5STigran Mkrtchyan } 668637c593c5STigran Mkrtchyan } 668737c593c5STigran Mkrtchyan 668837c593c5STigran Mkrtchyan void 668937c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 669037c593c5STigran Mkrtchyan { 669137c593c5STigran Mkrtchyan CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 66928b70484cSTigran Mkrtchyan } 66938b70484cSTigran Mkrtchyan 669462cd4a59STigran Mkrtchyan /* 669562cd4a59STigran Mkrtchyan * functions to set current state id 669662cd4a59STigran Mkrtchyan */ 66978b70484cSTigran Mkrtchyan void 66989428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 66999428fe1aSTigran Mkrtchyan { 67009428fe1aSTigran Mkrtchyan put_stateid(cstate, &odp->od_stateid); 67019428fe1aSTigran Mkrtchyan } 67029428fe1aSTigran Mkrtchyan 67039428fe1aSTigran Mkrtchyan void 67048b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open) 67058b70484cSTigran Mkrtchyan { 67068b70484cSTigran Mkrtchyan put_stateid(cstate, &open->op_stateid); 67078b70484cSTigran Mkrtchyan } 67088b70484cSTigran Mkrtchyan 67098b70484cSTigran Mkrtchyan void 671062cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 671162cd4a59STigran Mkrtchyan { 671262cd4a59STigran Mkrtchyan put_stateid(cstate, &close->cl_stateid); 671362cd4a59STigran Mkrtchyan } 671462cd4a59STigran Mkrtchyan 671562cd4a59STigran Mkrtchyan void 671662cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock) 671762cd4a59STigran Mkrtchyan { 671862cd4a59STigran Mkrtchyan put_stateid(cstate, &lock->lk_resp_stateid); 671962cd4a59STigran Mkrtchyan } 672062cd4a59STigran Mkrtchyan 672162cd4a59STigran Mkrtchyan /* 672262cd4a59STigran Mkrtchyan * functions to consume current state id 672362cd4a59STigran Mkrtchyan */ 67241e97b519STigran Mkrtchyan 67251e97b519STigran Mkrtchyan void 67269428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 67279428fe1aSTigran Mkrtchyan { 67289428fe1aSTigran Mkrtchyan get_stateid(cstate, &odp->od_stateid); 67299428fe1aSTigran Mkrtchyan } 67309428fe1aSTigran Mkrtchyan 67319428fe1aSTigran Mkrtchyan void 67329428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp) 67339428fe1aSTigran Mkrtchyan { 67349428fe1aSTigran Mkrtchyan get_stateid(cstate, &drp->dr_stateid); 67359428fe1aSTigran Mkrtchyan } 67369428fe1aSTigran Mkrtchyan 67379428fe1aSTigran Mkrtchyan void 67381e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp) 67391e97b519STigran Mkrtchyan { 67401e97b519STigran Mkrtchyan get_stateid(cstate, &fsp->fr_stateid); 67411e97b519STigran Mkrtchyan } 67421e97b519STigran Mkrtchyan 67431e97b519STigran Mkrtchyan void 67441e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) 67451e97b519STigran Mkrtchyan { 67461e97b519STigran Mkrtchyan get_stateid(cstate, &setattr->sa_stateid); 67471e97b519STigran Mkrtchyan } 67481e97b519STigran Mkrtchyan 674962cd4a59STigran Mkrtchyan void 67508b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 67518b70484cSTigran Mkrtchyan { 67528b70484cSTigran Mkrtchyan get_stateid(cstate, &close->cl_stateid); 67538b70484cSTigran Mkrtchyan } 67548b70484cSTigran Mkrtchyan 67558b70484cSTigran Mkrtchyan void 675662cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku) 67578b70484cSTigran Mkrtchyan { 675862cd4a59STigran Mkrtchyan get_stateid(cstate, &locku->lu_stateid); 67598b70484cSTigran Mkrtchyan } 676030813e27STigran Mkrtchyan 676130813e27STigran Mkrtchyan void 676230813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read) 676330813e27STigran Mkrtchyan { 676430813e27STigran Mkrtchyan get_stateid(cstate, &read->rd_stateid); 676530813e27STigran Mkrtchyan } 676630813e27STigran Mkrtchyan 676730813e27STigran Mkrtchyan void 676830813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write) 676930813e27STigran Mkrtchyan { 677030813e27STigran Mkrtchyan get_stateid(cstate, &write->wr_stateid); 677130813e27STigran Mkrtchyan } 6772