11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2001 The Regents of the University of Michigan. 31da177e4SLinus Torvalds * All rights reserved. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Kendrick Smith <kmsmith@umich.edu> 61da177e4SLinus Torvalds * Andy Adamson <kandros@umich.edu> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 91da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 101da177e4SLinus Torvalds * are met: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 131da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer. 141da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 151da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer in the 161da177e4SLinus Torvalds * documentation and/or other materials provided with the distribution. 171da177e4SLinus Torvalds * 3. Neither the name of the University nor the names of its 181da177e4SLinus Torvalds * contributors may be used to endorse or promote products derived 191da177e4SLinus Torvalds * from this software without specific prior written permission. 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 221da177e4SLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 231da177e4SLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 241da177e4SLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251da177e4SLinus Torvalds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 261da177e4SLinus Torvalds * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 271da177e4SLinus Torvalds * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 281da177e4SLinus Torvalds * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 291da177e4SLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 301da177e4SLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 311da177e4SLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds 35aceaf78dSDave Hansen #include <linux/file.h> 36b89f4321SArnd Bergmann #include <linux/fs.h> 375a0e3ad6STejun Heo #include <linux/slab.h> 380964a3d3SNeilBrown #include <linux/namei.h> 39c2f1a551SMeelap Shah #include <linux/swap.h> 4017456804SBryan Schumaker #include <linux/pagemap.h> 417df302f7SChuck Lever #include <linux/ratelimit.h> 4268e76ad0SOlga Kornievskaia #include <linux/sunrpc/svcauth_gss.h> 435976687aSJeff Layton #include <linux/sunrpc/addr.h> 446282cd56SNeilBrown #include <linux/hash.h> 459a74af21SBoaz Harrosh #include "xdr4.h" 4606b332a5SJ. Bruce Fields #include "xdr4cb.h" 470a3adadeSJ. Bruce Fields #include "vfs.h" 48bfa4b365SJ. Bruce Fields #include "current_stateid.h" 491da177e4SLinus Torvalds 505e1533c7SStanislav Kinsbursky #include "netns.h" 515e1533c7SStanislav Kinsbursky 521da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 531da177e4SLinus Torvalds 54f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 55f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 56f32f3c2dSJ. Bruce Fields .si_generation = ~0, 57f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 58f32f3c2dSJ. Bruce Fields }; 59f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 60f32f3c2dSJ. Bruce Fields /* all fields zero */ 61f32f3c2dSJ. Bruce Fields }; 6219ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 6319ff0f28STigran Mkrtchyan .si_generation = 1, 6419ff0f28STigran Mkrtchyan }; 65f32f3c2dSJ. Bruce Fields 66ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 67fd39ca9aSNeilBrown 68f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 69f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 7019ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds /* forward declarations */ 73f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 746011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 751da177e4SLinus Torvalds 768b671b80SJ. Bruce Fields /* Locking: */ 778b671b80SJ. Bruce Fields 788b671b80SJ. Bruce Fields /* Currently used for almost all code touching nfsv4 state: */ 79353ab6e9SIngo Molnar static DEFINE_MUTEX(client_mutex); 801da177e4SLinus Torvalds 818b671b80SJ. Bruce Fields /* 828b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 838b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 848b671b80SJ. Bruce Fields * eventually cover more: 858b671b80SJ. Bruce Fields */ 86cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 878b671b80SJ. Bruce Fields 88abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 89abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 90abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 91abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 92abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 93e60d4398SNeilBrown 941da177e4SLinus Torvalds void 951da177e4SLinus Torvalds nfs4_lock_state(void) 961da177e4SLinus Torvalds { 97353ab6e9SIngo Molnar mutex_lock(&client_mutex); 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 10066b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 101508dc6e1SBenny Halevy 10266b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 103508dc6e1SBenny Halevy { 10466b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 10566b2b9b2SJ. Bruce Fields } 10666b2b9b2SJ. Bruce Fields 107f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 108f0f51f5cSJ. Bruce Fields { 109f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 11066b2b9b2SJ. Bruce Fields return nfserr_jukebox; 11166b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 11266b2b9b2SJ. Bruce Fields return nfs_ok; 11366b2b9b2SJ. Bruce Fields } 11466b2b9b2SJ. Bruce Fields 1151da177e4SLinus Torvalds void 1161da177e4SLinus Torvalds nfs4_unlock_state(void) 1171da177e4SLinus Torvalds { 118353ab6e9SIngo Molnar mutex_unlock(&client_mutex); 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 121221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 122221a6876SJ. Bruce Fields { 123221a6876SJ. Bruce Fields return clp->cl_time == 0; 124221a6876SJ. Bruce Fields } 125221a6876SJ. Bruce Fields 126221a6876SJ. Bruce Fields static __be32 mark_client_expired_locked(struct nfs4_client *clp) 127221a6876SJ. Bruce Fields { 128221a6876SJ. Bruce Fields if (atomic_read(&clp->cl_refcount)) 129221a6876SJ. Bruce Fields return nfserr_jukebox; 130221a6876SJ. Bruce Fields clp->cl_time = 0; 131221a6876SJ. Bruce Fields return nfs_ok; 132221a6876SJ. Bruce Fields } 133221a6876SJ. Bruce Fields 134221a6876SJ. Bruce Fields static __be32 mark_client_expired(struct nfs4_client *clp) 135221a6876SJ. Bruce Fields { 136221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 137221a6876SJ. Bruce Fields __be32 ret; 138221a6876SJ. Bruce Fields 139221a6876SJ. Bruce Fields spin_lock(&nn->client_lock); 140221a6876SJ. Bruce Fields ret = mark_client_expired_locked(clp); 141221a6876SJ. Bruce Fields spin_unlock(&nn->client_lock); 142221a6876SJ. Bruce Fields return ret; 143221a6876SJ. Bruce Fields } 144221a6876SJ. Bruce Fields 145221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 146221a6876SJ. Bruce Fields { 147221a6876SJ. Bruce Fields if (is_client_expired(clp)) 148221a6876SJ. Bruce Fields return nfserr_expired; 149221a6876SJ. Bruce Fields atomic_inc(&clp->cl_refcount); 150221a6876SJ. Bruce Fields return nfs_ok; 151221a6876SJ. Bruce Fields } 152221a6876SJ. Bruce Fields 153221a6876SJ. Bruce Fields /* must be called under the client_lock */ 154221a6876SJ. Bruce Fields static inline void 155221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 156221a6876SJ. Bruce Fields { 157221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 158221a6876SJ. Bruce Fields 159221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 160221a6876SJ. Bruce Fields WARN_ON(1); 161221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 162221a6876SJ. Bruce Fields __func__, 163221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 164221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 165221a6876SJ. Bruce Fields return; 166221a6876SJ. Bruce Fields } 167221a6876SJ. Bruce Fields 168221a6876SJ. Bruce Fields dprintk("renewing client (clientid %08x/%08x)\n", 169221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 170221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 171221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 172221a6876SJ. Bruce Fields clp->cl_time = get_seconds(); 173221a6876SJ. Bruce Fields } 174221a6876SJ. Bruce Fields 175221a6876SJ. Bruce Fields static inline void 176221a6876SJ. Bruce Fields renew_client(struct nfs4_client *clp) 177221a6876SJ. Bruce Fields { 178221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 179221a6876SJ. Bruce Fields 180221a6876SJ. Bruce Fields spin_lock(&nn->client_lock); 181221a6876SJ. Bruce Fields renew_client_locked(clp); 182221a6876SJ. Bruce Fields spin_unlock(&nn->client_lock); 183221a6876SJ. Bruce Fields } 184221a6876SJ. Bruce Fields 185ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 186221a6876SJ. Bruce Fields { 187221a6876SJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_refcount)) 188221a6876SJ. Bruce Fields return; 189221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 190221a6876SJ. Bruce Fields renew_client_locked(clp); 191221a6876SJ. Bruce Fields } 192221a6876SJ. Bruce Fields 1934b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 1944b24ca7dSJeff Layton { 1954b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1964b24ca7dSJeff Layton 197d6c249b4SJeff Layton if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) 198d6c249b4SJeff Layton return; 199d6c249b4SJeff Layton if (!is_client_expired(clp)) 200d6c249b4SJeff Layton renew_client_locked(clp); 2014b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 2024b24ca7dSJeff Layton } 2034b24ca7dSJeff Layton 204d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 205d4e19e70STrond Myklebust { 206d4e19e70STrond Myklebust __be32 status; 207d4e19e70STrond Myklebust 208d4e19e70STrond Myklebust if (is_session_dead(ses)) 209d4e19e70STrond Myklebust return nfserr_badsession; 210d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 211d4e19e70STrond Myklebust if (status) 212d4e19e70STrond Myklebust return status; 213d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 214d4e19e70STrond Myklebust return nfs_ok; 215d4e19e70STrond Myklebust } 216d4e19e70STrond Myklebust 217d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 218d4e19e70STrond Myklebust { 219d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 220d4e19e70STrond Myklebust 221d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 222d4e19e70STrond Myklebust free_session(ses); 223d4e19e70STrond Myklebust put_client_renew_locked(clp); 224d4e19e70STrond Myklebust } 225d4e19e70STrond Myklebust 226d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 227d4e19e70STrond Myklebust { 228d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 229d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 230d4e19e70STrond Myklebust 231d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 232d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 233d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 234d4e19e70STrond Myklebust } 235d4e19e70STrond Myklebust 236d4e19e70STrond Myklebust 2371da177e4SLinus Torvalds static inline u32 2381da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 2391da177e4SLinus Torvalds { 2401da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds u32 x = 0; 2431da177e4SLinus Torvalds while (nbytes--) { 2441da177e4SLinus Torvalds x *= 37; 2451da177e4SLinus Torvalds x += *cptr++; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds return x; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds 25032513b40SJ. Bruce Fields static void nfsd4_free_file(struct nfs4_file *f) 25132513b40SJ. Bruce Fields { 25232513b40SJ. Bruce Fields kmem_cache_free(file_slab, f); 25332513b40SJ. Bruce Fields } 25432513b40SJ. Bruce Fields 25513cd2184SNeilBrown static inline void 25613cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 25713cd2184SNeilBrown { 25802e1215fSJeff Layton might_lock(&state_lock); 25902e1215fSJeff Layton 260cdc97505SBenny Halevy if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { 26189876f8cSJeff Layton hlist_del(&fi->fi_hash); 262cdc97505SBenny Halevy spin_unlock(&state_lock); 26332513b40SJ. Bruce Fields nfsd4_free_file(fi); 2648b671b80SJ. Bruce Fields } 26513cd2184SNeilBrown } 26613cd2184SNeilBrown 26713cd2184SNeilBrown static inline void 26813cd2184SNeilBrown get_nfs4_file(struct nfs4_file *fi) 26913cd2184SNeilBrown { 2708b671b80SJ. Bruce Fields atomic_inc(&fi->fi_ref); 27113cd2184SNeilBrown } 27213cd2184SNeilBrown 273de18643dSTrond Myklebust static struct file * 274de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag) 275de18643dSTrond Myklebust { 276de18643dSTrond Myklebust if (f->fi_fds[oflag]) 277de18643dSTrond Myklebust return get_file(f->fi_fds[oflag]); 278de18643dSTrond Myklebust return NULL; 279de18643dSTrond Myklebust } 280de18643dSTrond Myklebust 281de18643dSTrond Myklebust static struct file * 282de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f) 283de18643dSTrond Myklebust { 284de18643dSTrond Myklebust struct file *ret; 285de18643dSTrond Myklebust 286de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 287de18643dSTrond Myklebust 288de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 289de18643dSTrond Myklebust if (!ret) 290de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 291de18643dSTrond Myklebust return ret; 292de18643dSTrond Myklebust } 293de18643dSTrond Myklebust 294de18643dSTrond Myklebust static struct file * 295de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 296de18643dSTrond Myklebust { 297de18643dSTrond Myklebust struct file *ret; 298de18643dSTrond Myklebust 299de18643dSTrond Myklebust spin_lock(&f->fi_lock); 300de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 301de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 302de18643dSTrond Myklebust 303de18643dSTrond Myklebust return ret; 304de18643dSTrond Myklebust } 305de18643dSTrond Myklebust 306de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f) 307de18643dSTrond Myklebust { 308de18643dSTrond Myklebust struct file *ret; 309de18643dSTrond Myklebust 310de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 311de18643dSTrond Myklebust 312de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 313de18643dSTrond Myklebust if (!ret) 314de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 315de18643dSTrond Myklebust return ret; 316de18643dSTrond Myklebust } 317de18643dSTrond Myklebust 318de18643dSTrond Myklebust static struct file * 319de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 320de18643dSTrond Myklebust { 321de18643dSTrond Myklebust struct file *ret; 322de18643dSTrond Myklebust 323de18643dSTrond Myklebust spin_lock(&f->fi_lock); 324de18643dSTrond Myklebust ret = find_readable_file_locked(f); 325de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 326de18643dSTrond Myklebust 327de18643dSTrond Myklebust return ret; 328de18643dSTrond Myklebust } 329de18643dSTrond Myklebust 330de18643dSTrond Myklebust static struct file * 331de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 332de18643dSTrond Myklebust { 333de18643dSTrond Myklebust struct file *ret; 334de18643dSTrond Myklebust 335de18643dSTrond Myklebust spin_lock(&f->fi_lock); 336de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 337de18643dSTrond Myklebust if (!ret) { 338de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 339de18643dSTrond Myklebust if (!ret) 340de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 341de18643dSTrond Myklebust } 342de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 343de18643dSTrond Myklebust return ret; 344de18643dSTrond Myklebust } 345de18643dSTrond Myklebust 34602a3508dSTrond Myklebust static atomic_long_t num_delegations; 347697ce9beSZhang Yanfei unsigned long max_delegations; 348ef0f3390SNeilBrown 349ef0f3390SNeilBrown /* 350ef0f3390SNeilBrown * Open owner state (share locks) 351ef0f3390SNeilBrown */ 352ef0f3390SNeilBrown 35316bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 35416bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 35516bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 35616bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 357ef0f3390SNeilBrown 35816bfdaafSJ. Bruce Fields static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) 359ddc04c41SJ. Bruce Fields { 360ddc04c41SJ. Bruce Fields unsigned int ret; 361ddc04c41SJ. Bruce Fields 362ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 363ddc04c41SJ. Bruce Fields ret += clientid; 36416bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 365ddc04c41SJ. Bruce Fields } 366ef0f3390SNeilBrown 367ef0f3390SNeilBrown /* hash table for nfs4_file */ 368ef0f3390SNeilBrown #define FILE_HASH_BITS 8 369ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 37035079582SShan Wei 371ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) 372ddc04c41SJ. Bruce Fields { 373ca943217STrond Myklebust return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); 374ca943217STrond Myklebust } 375ca943217STrond Myklebust 376ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh) 377ca943217STrond Myklebust { 378ca943217STrond Myklebust return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); 379ca943217STrond Myklebust } 380ca943217STrond Myklebust 381ca943217STrond Myklebust static bool nfsd_fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) 382ca943217STrond Myklebust { 383ca943217STrond Myklebust return fh1->fh_size == fh2->fh_size && 384ca943217STrond Myklebust !memcmp(fh1->fh_base.fh_pad, 385ca943217STrond Myklebust fh2->fh_base.fh_pad, 386ca943217STrond Myklebust fh1->fh_size); 387ddc04c41SJ. Bruce Fields } 388ddc04c41SJ. Bruce Fields 38989876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 390ef0f3390SNeilBrown 39112659651SJeff Layton static void 39212659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 3933477565eSJ. Bruce Fields { 3947214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 3957214e860SJeff Layton 39612659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 39712659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 39812659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 39912659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 4003477565eSJ. Bruce Fields } 4013477565eSJ. Bruce Fields 40212659651SJeff Layton static __be32 40312659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 404998db52cSJ. Bruce Fields { 4057214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 4067214e860SJeff Layton 40712659651SJeff Layton /* Does this access mode make sense? */ 40812659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 40912659651SJeff Layton return nfserr_inval; 41012659651SJeff Layton 411baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 412baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 413baeb4ff0SJeff Layton return nfserr_share_denied; 414baeb4ff0SJeff Layton 41512659651SJeff Layton __nfs4_file_get_access(fp, access); 41612659651SJeff Layton return nfs_ok; 417998db52cSJ. Bruce Fields } 418998db52cSJ. Bruce Fields 419baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 420baeb4ff0SJeff Layton { 421baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 422baeb4ff0SJeff Layton if (deny) { 423baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 424baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 425baeb4ff0SJeff Layton return nfserr_inval; 426baeb4ff0SJeff Layton 427baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 428baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 429baeb4ff0SJeff Layton return nfserr_share_denied; 430baeb4ff0SJeff Layton 431baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 432baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 433baeb4ff0SJeff Layton return nfserr_share_denied; 434baeb4ff0SJeff Layton } 435baeb4ff0SJeff Layton return nfs_ok; 436baeb4ff0SJeff Layton } 437baeb4ff0SJeff Layton 438998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 439f9d7562fSJ. Bruce Fields { 440de18643dSTrond Myklebust might_lock(&fp->fi_lock); 441de18643dSTrond Myklebust 442de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 443de18643dSTrond Myklebust struct file *f1 = NULL; 444de18643dSTrond Myklebust struct file *f2 = NULL; 445de18643dSTrond Myklebust 4466d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 4470c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 4486d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 449de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 450de18643dSTrond Myklebust if (f1) 451de18643dSTrond Myklebust fput(f1); 452de18643dSTrond Myklebust if (f2) 453de18643dSTrond Myklebust fput(f2); 454f9d7562fSJ. Bruce Fields } 455f9d7562fSJ. Bruce Fields } 456f9d7562fSJ. Bruce Fields 45712659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 458998db52cSJ. Bruce Fields { 45912659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 46012659651SJeff Layton 46112659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 462998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 46312659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 46412659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 465998db52cSJ. Bruce Fields } 466998db52cSJ. Bruce Fields 4676011695dSTrond Myklebust static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 4686011695dSTrond Myklebust struct kmem_cache *slab) 469996e0938SJ. Bruce Fields { 4703abdb607SJ. Bruce Fields struct nfs4_stid *stid; 4713abdb607SJ. Bruce Fields int new_id; 4723abdb607SJ. Bruce Fields 473f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 4743abdb607SJ. Bruce Fields if (!stid) 4753abdb607SJ. Bruce Fields return NULL; 476996e0938SJ. Bruce Fields 4774770d722SJeff Layton idr_preload(GFP_KERNEL); 4784770d722SJeff Layton spin_lock(&cl->cl_lock); 4794770d722SJeff Layton new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT); 4804770d722SJeff Layton spin_unlock(&cl->cl_lock); 4814770d722SJeff Layton idr_preload_end(); 482ebd6c707STejun Heo if (new_id < 0) 4833abdb607SJ. Bruce Fields goto out_free; 4843abdb607SJ. Bruce Fields stid->sc_client = cl; 4853abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 4863abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 4873abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 48872c0b0fbSTrond Myklebust atomic_set(&stid->sc_count, 1); 4893abdb607SJ. Bruce Fields 490996e0938SJ. Bruce Fields /* 4913abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 4923abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 4933abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 4943abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 4953abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 4963abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 4973abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 498996e0938SJ. Bruce Fields */ 4993abdb607SJ. Bruce Fields return stid; 5003abdb607SJ. Bruce Fields out_free: 5012c44a234SWei Yongjun kmem_cache_free(slab, stid); 5023abdb607SJ. Bruce Fields return NULL; 5032a74aba7SJ. Bruce Fields } 5042a74aba7SJ. Bruce Fields 505b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 5064cdc951bSJ. Bruce Fields { 5076011695dSTrond Myklebust struct nfs4_stid *stid; 5086011695dSTrond Myklebust struct nfs4_ol_stateid *stp; 5096011695dSTrond Myklebust 5106011695dSTrond Myklebust stid = nfs4_alloc_stid(clp, stateid_slab); 5116011695dSTrond Myklebust if (!stid) 5126011695dSTrond Myklebust return NULL; 5136011695dSTrond Myklebust 5146011695dSTrond Myklebust stp = openlockstateid(stid); 5156011695dSTrond Myklebust stp->st_stid.sc_free = nfs4_free_ol_stateid; 5166011695dSTrond Myklebust return stp; 5176011695dSTrond Myklebust } 5186011695dSTrond Myklebust 5196011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 5206011695dSTrond Myklebust { 5216011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 5226011695dSTrond Myklebust atomic_long_dec(&num_delegations); 5234cdc951bSJ. Bruce Fields } 5244cdc951bSJ. Bruce Fields 5256282cd56SNeilBrown /* 5266282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 5276282cd56SNeilBrown * out again straight away. 5286282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 5296282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 5306282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 5316282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 5326282cd56SNeilBrown * filter. 5336282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 5346282cd56SNeilBrown * unless both are empty of course. 5356282cd56SNeilBrown * 5366282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 5376282cd56SNeilBrown * low 3 bytes as hash-table indices. 5386282cd56SNeilBrown * 539f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 5406282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 5416282cd56SNeilBrown * except when swapping the two filters. 5426282cd56SNeilBrown */ 543f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 5446282cd56SNeilBrown static struct bloom_pair { 5456282cd56SNeilBrown int entries, old_entries; 5466282cd56SNeilBrown time_t swap_time; 5476282cd56SNeilBrown int new; /* index into 'set' */ 5486282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 5496282cd56SNeilBrown } blocked_delegations; 5506282cd56SNeilBrown 5516282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 5526282cd56SNeilBrown { 5536282cd56SNeilBrown u32 hash; 5546282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 5556282cd56SNeilBrown 5566282cd56SNeilBrown if (bd->entries == 0) 5576282cd56SNeilBrown return 0; 5586282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 559f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 5606282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 5616282cd56SNeilBrown bd->entries -= bd->old_entries; 5626282cd56SNeilBrown bd->old_entries = bd->entries; 5636282cd56SNeilBrown memset(bd->set[bd->new], 0, 5646282cd56SNeilBrown sizeof(bd->set[0])); 5656282cd56SNeilBrown bd->new = 1-bd->new; 5666282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 5676282cd56SNeilBrown } 568f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 5696282cd56SNeilBrown } 5706282cd56SNeilBrown hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0); 5716282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 5726282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 5736282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 5746282cd56SNeilBrown return 1; 5756282cd56SNeilBrown 5766282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 5776282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 5786282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 5796282cd56SNeilBrown return 1; 5806282cd56SNeilBrown 5816282cd56SNeilBrown return 0; 5826282cd56SNeilBrown } 5836282cd56SNeilBrown 5846282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 5856282cd56SNeilBrown { 5866282cd56SNeilBrown u32 hash; 5876282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 5886282cd56SNeilBrown 5896282cd56SNeilBrown hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0); 5906282cd56SNeilBrown 591f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 5926282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 5936282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 5946282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 5956282cd56SNeilBrown if (bd->entries == 0) 5966282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 5976282cd56SNeilBrown bd->entries += 1; 598f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 5996282cd56SNeilBrown } 6006282cd56SNeilBrown 6011da177e4SLinus Torvalds static struct nfs4_delegation * 602f9416e28SJeff Layton alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) 6031da177e4SLinus Torvalds { 6041da177e4SLinus Torvalds struct nfs4_delegation *dp; 60502a3508dSTrond Myklebust long n; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 60802a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 60902a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 61002a3508dSTrond Myklebust goto out_dec; 6116282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 61202a3508dSTrond Myklebust goto out_dec; 613996e0938SJ. Bruce Fields dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); 6145b2d21c1SNeilBrown if (dp == NULL) 61502a3508dSTrond Myklebust goto out_dec; 6166011695dSTrond Myklebust 6176011695dSTrond Myklebust dp->dl_stid.sc_free = nfs4_free_deleg; 6182a74aba7SJ. Bruce Fields /* 6192a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 6206136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 6216136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 6222a74aba7SJ. Bruce Fields */ 6232a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 624ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 625ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 6261da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 62799c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 62802e1215fSJeff Layton INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall); 6291da177e4SLinus Torvalds return dp; 63002a3508dSTrond Myklebust out_dec: 63102a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 63202a3508dSTrond Myklebust return NULL; 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds void 6366011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 6371da177e4SLinus Torvalds { 63811b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 6396011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 6406011695dSTrond Myklebust 6414770d722SJeff Layton might_lock(&clp->cl_lock); 6424770d722SJeff Layton 6434770d722SJeff Layton if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) 6446011695dSTrond Myklebust return; 6456011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 6464770d722SJeff Layton spin_unlock(&clp->cl_lock); 6476011695dSTrond Myklebust s->sc_free(s); 64811b9164aSTrond Myklebust if (fp) 64911b9164aSTrond Myklebust put_nfs4_file(fp); 6501da177e4SLinus Torvalds } 6511da177e4SLinus Torvalds 652acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp) 6531da177e4SLinus Torvalds { 654417c6629SJeff Layton lockdep_assert_held(&state_lock); 655417c6629SJeff Layton 656cbf7a75bSJ. Bruce Fields if (!fp->fi_lease) 657cbf7a75bSJ. Bruce Fields return; 658acfdf5c3SJ. Bruce Fields if (atomic_dec_and_test(&fp->fi_delegees)) { 659acfdf5c3SJ. Bruce Fields vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); 660acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 6614ee63624SJ. Bruce Fields fput(fp->fi_deleg_file); 662acfdf5c3SJ. Bruce Fields fp->fi_deleg_file = NULL; 663acfdf5c3SJ. Bruce Fields } 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6666136d2b4SJ. Bruce Fields static void unhash_stid(struct nfs4_stid *s) 6676136d2b4SJ. Bruce Fields { 6683abdb607SJ. Bruce Fields s->sc_type = 0; 6696136d2b4SJ. Bruce Fields } 6706136d2b4SJ. Bruce Fields 671931ee56cSBenny Halevy static void 672931ee56cSBenny Halevy hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 673931ee56cSBenny Halevy { 674cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 675417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 676931ee56cSBenny Halevy 67767cb1279STrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 6783fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 679931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 680931ee56cSBenny Halevy list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); 681931ee56cSBenny Halevy } 682931ee56cSBenny Halevy 6831da177e4SLinus Torvalds static void 68442690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 6851da177e4SLinus Torvalds { 68611b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 68702e1215fSJeff Layton 68842690676SJeff Layton lockdep_assert_held(&state_lock); 68942690676SJeff Layton 690b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 691d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 692d55a166cSJeff Layton ++dp->dl_time; 693417c6629SJeff Layton spin_lock(&fp->fi_lock); 694931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 6951da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 69602e1215fSJeff Layton list_del_init(&dp->dl_perfile); 69702e1215fSJeff Layton spin_unlock(&fp->fi_lock); 698417c6629SJeff Layton if (fp) 699f8338834STrond Myklebust nfs4_put_deleg_lease(fp); 700cbf7a75bSJ. Bruce Fields } 7013bd64a5bSJ. Bruce Fields 7023bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 7033bd64a5bSJ. Bruce Fields { 70442690676SJeff Layton spin_lock(&state_lock); 70542690676SJeff Layton unhash_delegation_locked(dp); 70642690676SJeff Layton spin_unlock(&state_lock); 7076011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 7083bd64a5bSJ. Bruce Fields } 7093bd64a5bSJ. Bruce Fields 7103bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 7113bd64a5bSJ. Bruce Fields { 7123bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 7133bd64a5bSJ. Bruce Fields 7142d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 7152d4a532dSJeff Layton 7163bd64a5bSJ. Bruce Fields if (clp->cl_minorversion == 0) 7176011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 7183bd64a5bSJ. Bruce Fields else { 7193bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 7202d4a532dSJeff Layton spin_lock(&clp->cl_lock); 7212d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 7222d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 7233bd64a5bSJ. Bruce Fields } 7243bd64a5bSJ. Bruce Fields } 7253bd64a5bSJ. Bruce Fields 7261da177e4SLinus Torvalds /* 7271da177e4SLinus Torvalds * SETCLIENTID state 7281da177e4SLinus Torvalds */ 7291da177e4SLinus Torvalds 730ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 731ddc04c41SJ. Bruce Fields { 732ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 733ddc04c41SJ. Bruce Fields } 734ddc04c41SJ. Bruce Fields 735ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 736ddc04c41SJ. Bruce Fields { 737ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 738ddc04c41SJ. Bruce Fields } 739ddc04c41SJ. Bruce Fields 7401da177e4SLinus Torvalds /* 741f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 742f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 743f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 744f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 745f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 746f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 747f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 748f9d7562fSJ. Bruce Fields * 749f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 750f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 751f9d7562fSJ. Bruce Fields * 752f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 753f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 754f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 755f9d7562fSJ. Bruce Fields * 756f9d7562fSJ. Bruce Fields * which we should reject. 757f9d7562fSJ. Bruce Fields */ 7585ae037e5SJeff Layton static unsigned int 7595ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 760f9d7562fSJ. Bruce Fields int i; 7615ae037e5SJeff Layton unsigned int access = 0; 762f9d7562fSJ. Bruce Fields 763f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 764f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 7655ae037e5SJeff Layton access |= i; 766f9d7562fSJ. Bruce Fields } 7675ae037e5SJeff Layton return access; 768f9d7562fSJ. Bruce Fields } 769f9d7562fSJ. Bruce Fields 77082c5ff1bSJeff Layton /* set share access for a given stateid */ 77182c5ff1bSJeff Layton static inline void 77282c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 77382c5ff1bSJeff Layton { 774c11c591fSJeff Layton unsigned char mask = 1 << access; 775c11c591fSJeff Layton 776c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 777c11c591fSJeff Layton stp->st_access_bmap |= mask; 77882c5ff1bSJeff Layton } 77982c5ff1bSJeff Layton 78082c5ff1bSJeff Layton /* clear share access for a given stateid */ 78182c5ff1bSJeff Layton static inline void 78282c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 78382c5ff1bSJeff Layton { 784c11c591fSJeff Layton unsigned char mask = 1 << access; 785c11c591fSJeff Layton 786c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 787c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 78882c5ff1bSJeff Layton } 78982c5ff1bSJeff Layton 79082c5ff1bSJeff Layton /* test whether a given stateid has access */ 79182c5ff1bSJeff Layton static inline bool 79282c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 79382c5ff1bSJeff Layton { 794c11c591fSJeff Layton unsigned char mask = 1 << access; 795c11c591fSJeff Layton 796c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 79782c5ff1bSJeff Layton } 79882c5ff1bSJeff Layton 799ce0fc43cSJeff Layton /* set share deny for a given stateid */ 800ce0fc43cSJeff Layton static inline void 801c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 802ce0fc43cSJeff Layton { 803c11c591fSJeff Layton unsigned char mask = 1 << deny; 804c11c591fSJeff Layton 805c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 806c11c591fSJeff Layton stp->st_deny_bmap |= mask; 807ce0fc43cSJeff Layton } 808ce0fc43cSJeff Layton 809ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 810ce0fc43cSJeff Layton static inline void 811c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 812ce0fc43cSJeff Layton { 813c11c591fSJeff Layton unsigned char mask = 1 << deny; 814c11c591fSJeff Layton 815c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 816c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 817ce0fc43cSJeff Layton } 818ce0fc43cSJeff Layton 819ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 820ce0fc43cSJeff Layton static inline bool 821c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 822ce0fc43cSJeff Layton { 823c11c591fSJeff Layton unsigned char mask = 1 << deny; 824c11c591fSJeff Layton 825c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 826f9d7562fSJ. Bruce Fields } 827f9d7562fSJ. Bruce Fields 828f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 829f9d7562fSJ. Bruce Fields { 8308f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 831f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 832f9d7562fSJ. Bruce Fields return O_RDONLY; 833f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 834f9d7562fSJ. Bruce Fields return O_WRONLY; 835f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 836f9d7562fSJ. Bruce Fields return O_RDWR; 837f9d7562fSJ. Bruce Fields } 838063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 839063b0fb9SJ. Bruce Fields return O_RDONLY; 840f9d7562fSJ. Bruce Fields } 841f9d7562fSJ. Bruce Fields 842baeb4ff0SJeff Layton /* 843baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 844baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 845baeb4ff0SJeff Layton */ 846baeb4ff0SJeff Layton static void 847baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 848baeb4ff0SJeff Layton { 849baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 850baeb4ff0SJeff Layton 851baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 852baeb4ff0SJeff Layton fp->fi_share_deny = 0; 853baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 854baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 855baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 856baeb4ff0SJeff Layton } 857baeb4ff0SJeff Layton 858baeb4ff0SJeff Layton static void 859baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 860baeb4ff0SJeff Layton { 861baeb4ff0SJeff Layton int i; 862baeb4ff0SJeff Layton bool change = false; 863baeb4ff0SJeff Layton 864baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 865baeb4ff0SJeff Layton if ((i & deny) != i) { 866baeb4ff0SJeff Layton change = true; 867baeb4ff0SJeff Layton clear_deny(i, stp); 868baeb4ff0SJeff Layton } 869baeb4ff0SJeff Layton } 870baeb4ff0SJeff Layton 871baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 872baeb4ff0SJeff Layton if (change) 87311b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 874baeb4ff0SJeff Layton } 875baeb4ff0SJeff Layton 87682c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 87782c5ff1bSJeff Layton static void 87882c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 87982c5ff1bSJeff Layton { 88082c5ff1bSJeff Layton int i; 88111b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 882baeb4ff0SJeff Layton 883baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 884baeb4ff0SJeff Layton recalculate_deny_mode(fp); 88582c5ff1bSJeff Layton 88682c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 88782c5ff1bSJeff Layton if (test_access(i, stp)) 88811b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 88982c5ff1bSJeff Layton clear_access(i, stp); 89082c5ff1bSJeff Layton } 89182c5ff1bSJeff Layton } 89282c5ff1bSJeff Layton 8936b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 8946b180f0bSJeff Layton { 8956b180f0bSJeff Layton if (!atomic_dec_and_test(&sop->so_count)) 8966b180f0bSJeff Layton return; 8978f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 8986b180f0bSJeff Layton kfree(sop->so_owner.data); 8996b180f0bSJeff Layton sop->so_ops->so_free(sop); 9006b180f0bSJeff Layton } 9016b180f0bSJeff Layton 902dcef0413SJ. Bruce Fields static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) 903529d7b2aSJ. Bruce Fields { 90411b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 9051d31a253STrond Myklebust 9061c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 9071c755dc1SJeff Layton 9081d31a253STrond Myklebust spin_lock(&fp->fi_lock); 909529d7b2aSJ. Bruce Fields list_del(&stp->st_perfile); 9101d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 911529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 912529d7b2aSJ. Bruce Fields } 913529d7b2aSJ. Bruce Fields 9146011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 915529d7b2aSJ. Bruce Fields { 9166011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 9174665e2baSJ. Bruce Fields 9186011695dSTrond Myklebust release_all_access(stp); 9196011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 920529d7b2aSJ. Bruce Fields } 921529d7b2aSJ. Bruce Fields 922b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 923529d7b2aSJ. Bruce Fields { 924b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 925b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 926529d7b2aSJ. Bruce Fields struct file *file; 927529d7b2aSJ. Bruce Fields 928b49e084dSJeff Layton file = find_any_file(stp->st_stid.sc_file); 929b49e084dSJeff Layton if (file) 930b49e084dSJeff Layton filp_close(file, (fl_owner_t)lo); 931e4f1dd7fSTrond Myklebust if (stp->st_stateowner) 932e4f1dd7fSTrond Myklebust nfs4_put_stateowner(stp->st_stateowner); 933b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 934b49e084dSJeff Layton } 935b49e084dSJeff Layton 936b49e084dSJeff Layton static void __release_lock_stateid(struct nfs4_ol_stateid *stp) 937b49e084dSJeff Layton { 9381c755dc1SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 9391c755dc1SJeff Layton 9401c755dc1SJeff Layton spin_lock(&oo->oo_owner.so_client->cl_lock); 9413c87b9b7STrond Myklebust list_del(&stp->st_locks); 942529d7b2aSJ. Bruce Fields unhash_generic_stateid(stp); 9436136d2b4SJ. Bruce Fields unhash_stid(&stp->st_stid); 9441c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 9456011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 946529d7b2aSJ. Bruce Fields } 947529d7b2aSJ. Bruce Fields 948fe0750e5SJ. Bruce Fields static void unhash_lockowner(struct nfs4_lockowner *lo) 949529d7b2aSJ. Bruce Fields { 9508f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 9518f4b54c5SJeff Layton } 9528f4b54c5SJeff Layton 9538f4b54c5SJeff Layton static void release_lockowner_stateids(struct nfs4_lockowner *lo) 9548f4b54c5SJeff Layton { 955dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 956529d7b2aSJ. Bruce Fields 957fe0750e5SJ. Bruce Fields while (!list_empty(&lo->lo_owner.so_stateids)) { 958fe0750e5SJ. Bruce Fields stp = list_first_entry(&lo->lo_owner.so_stateids, 959dcef0413SJ. Bruce Fields struct nfs4_ol_stateid, st_perstateowner); 9603c87b9b7STrond Myklebust __release_lock_stateid(stp); 961529d7b2aSJ. Bruce Fields } 962529d7b2aSJ. Bruce Fields } 963529d7b2aSJ. Bruce Fields 964fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo) 965529d7b2aSJ. Bruce Fields { 966fe0750e5SJ. Bruce Fields unhash_lockowner(lo); 9678f4b54c5SJeff Layton release_lockowner_stateids(lo); 9686b180f0bSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 969529d7b2aSJ. Bruce Fields } 970529d7b2aSJ. Bruce Fields 9713c87b9b7STrond Myklebust static void release_lockowner_if_empty(struct nfs4_lockowner *lo) 9723c87b9b7STrond Myklebust { 9733c87b9b7STrond Myklebust if (list_empty(&lo->lo_owner.so_stateids)) 9743c87b9b7STrond Myklebust release_lockowner(lo); 9753c87b9b7STrond Myklebust } 9763c87b9b7STrond Myklebust 9773c87b9b7STrond Myklebust static void release_lock_stateid(struct nfs4_ol_stateid *stp) 978529d7b2aSJ. Bruce Fields { 979fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 980529d7b2aSJ. Bruce Fields 9813c87b9b7STrond Myklebust lo = lockowner(stp->st_stateowner); 9823c87b9b7STrond Myklebust __release_lock_stateid(stp); 9833c87b9b7STrond Myklebust release_lockowner_if_empty(lo); 9843c87b9b7STrond Myklebust } 9853c87b9b7STrond Myklebust 9863c87b9b7STrond Myklebust static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp) 9871c755dc1SJeff Layton __releases(&open_stp->st_stateowner->so_client->cl_lock) 9881c755dc1SJeff Layton __acquires(&open_stp->st_stateowner->so_client->cl_lock) 9893c87b9b7STrond Myklebust { 9903c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 9913c87b9b7STrond Myklebust 9923c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 9933c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 9943c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 9951c755dc1SJeff Layton spin_unlock(&open_stp->st_stateowner->so_client->cl_lock); 9963c87b9b7STrond Myklebust release_lock_stateid(stp); 9971c755dc1SJeff Layton spin_lock(&open_stp->st_stateowner->so_client->cl_lock); 998529d7b2aSJ. Bruce Fields } 999529d7b2aSJ. Bruce Fields } 1000529d7b2aSJ. Bruce Fields 100138c387b5SJ. Bruce Fields static void unhash_open_stateid(struct nfs4_ol_stateid *stp) 10022283963fSJ. Bruce Fields { 10031c755dc1SJeff Layton spin_lock(&stp->st_stateowner->so_client->cl_lock); 10042283963fSJ. Bruce Fields unhash_generic_stateid(stp); 10053c87b9b7STrond Myklebust release_open_stateid_locks(stp); 10061c755dc1SJeff Layton spin_unlock(&stp->st_stateowner->so_client->cl_lock); 100738c387b5SJ. Bruce Fields } 100838c387b5SJ. Bruce Fields 100938c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 101038c387b5SJ. Bruce Fields { 101138c387b5SJ. Bruce Fields unhash_open_stateid(stp); 10126011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 10132283963fSJ. Bruce Fields } 10142283963fSJ. Bruce Fields 1015fe0750e5SJ. Bruce Fields static void unhash_openowner(struct nfs4_openowner *oo) 1016f1d110caSJ. Bruce Fields { 10178f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 10188f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1019f1d110caSJ. Bruce Fields } 1020f1d110caSJ. Bruce Fields 1021f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1022f7a4d872SJ. Bruce Fields { 1023f7a4d872SJ. Bruce Fields struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; 1024f7a4d872SJ. Bruce Fields 1025f7a4d872SJ. Bruce Fields if (s) { 10266011695dSTrond Myklebust nfs4_put_stid(&s->st_stid); 1027f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1028f7a4d872SJ. Bruce Fields } 1029f7a4d872SJ. Bruce Fields } 1030f7a4d872SJ. Bruce Fields 10318f4b54c5SJeff Layton static void release_openowner_stateids(struct nfs4_openowner *oo) 10328f4b54c5SJeff Layton { 10338f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 10348f4b54c5SJeff Layton 10358f4b54c5SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 10368f4b54c5SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 10378f4b54c5SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 10388f4b54c5SJeff Layton release_open_stateid(stp); 10398f4b54c5SJeff Layton } 10408f4b54c5SJeff Layton } 10418f4b54c5SJeff Layton 1042fe0750e5SJ. Bruce Fields static void release_openowner(struct nfs4_openowner *oo) 1043f1d110caSJ. Bruce Fields { 1044fe0750e5SJ. Bruce Fields unhash_openowner(oo); 10458f4b54c5SJeff Layton release_openowner_stateids(oo); 1046fe0750e5SJ. Bruce Fields list_del(&oo->oo_close_lru); 1047f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 10486b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1049f1d110caSJ. Bruce Fields } 1050f1d110caSJ. Bruce Fields 10515282fd72SMarc Eshel static inline int 10525282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 10535282fd72SMarc Eshel { 10545282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 10555282fd72SMarc Eshel 10565282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 10575282fd72SMarc Eshel } 10585282fd72SMarc Eshel 10598f199b82STrond Myklebust #ifdef NFSD_DEBUG 10605282fd72SMarc Eshel static inline void 10615282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 10625282fd72SMarc Eshel { 10635282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 10645282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 10655282fd72SMarc Eshel } 10668f199b82STrond Myklebust #else 10678f199b82STrond Myklebust static inline void 10688f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 10698f199b82STrond Myklebust { 10708f199b82STrond Myklebust } 10718f199b82STrond Myklebust #endif 10728f199b82STrond Myklebust 10739411b1d4SJ. Bruce Fields /* 10749411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 10759411b1d4SJ. Bruce Fields * won't be used for replay. 10769411b1d4SJ. Bruce Fields */ 10779411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 10789411b1d4SJ. Bruce Fields { 10799411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 10809411b1d4SJ. Bruce Fields 10819411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 10829411b1d4SJ. Bruce Fields return; 10839411b1d4SJ. Bruce Fields 10849411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 108558fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 10869411b1d4SJ. Bruce Fields return; 10879411b1d4SJ. Bruce Fields } 10889411b1d4SJ. Bruce Fields if (!so) 10899411b1d4SJ. Bruce Fields return; 10909411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 10919411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 10929411b1d4SJ. Bruce Fields so->so_seqid++; 10939411b1d4SJ. Bruce Fields return; 10949411b1d4SJ. Bruce Fields } 10955282fd72SMarc Eshel 1096ec6b5d7bSAndy Adamson static void 1097ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1098ec6b5d7bSAndy Adamson { 1099ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1100ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1101ec6b5d7bSAndy Adamson 1102ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1103ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1104ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1105ec6b5d7bSAndy Adamson sid->reserved = 0; 1106ec6b5d7bSAndy Adamson } 1107ec6b5d7bSAndy Adamson 1108ec6b5d7bSAndy Adamson /* 1109a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1110a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1111a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1112a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1113a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1114a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1115a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1116a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1117a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1118a649637cSAndy Adamson * for the SEQUENCE op response: 1119ec6b5d7bSAndy Adamson */ 1120a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1121a649637cSAndy Adamson 1122557ce264SAndy Adamson static void 1123557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1124557ce264SAndy Adamson { 1125557ce264SAndy Adamson int i; 1126557ce264SAndy Adamson 1127557ce264SAndy Adamson for (i = 0; i < ses->se_fchannel.maxreqs; i++) 1128557ce264SAndy Adamson kfree(ses->se_slots[i]); 1129557ce264SAndy Adamson } 1130557ce264SAndy Adamson 1131efe0cb6dSJ. Bruce Fields /* 1132efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1133efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1134efe0cb6dSJ. Bruce Fields */ 113555c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1136efe0cb6dSJ. Bruce Fields { 113755c760cfSJ. Bruce Fields u32 size; 1138efe0cb6dSJ. Bruce Fields 113955c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 114055c760cfSJ. Bruce Fields size = 0; 114155c760cfSJ. Bruce Fields else 114255c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 114355c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1144557ce264SAndy Adamson } 1145557ce264SAndy Adamson 11465b6feee9SJ. Bruce Fields /* 11475b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 11485b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 114942b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 11505b6feee9SJ. Bruce Fields */ 115155c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 11525b6feee9SJ. Bruce Fields { 115355c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 115455c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 11555b6feee9SJ. Bruce Fields int avail; 11565b6feee9SJ. Bruce Fields 11575b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 1158697ce9beSZhang Yanfei avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, 11595b6feee9SJ. Bruce Fields nfsd_drc_max_mem - nfsd_drc_mem_used); 11605b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 11615b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 11625b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 11635b6feee9SJ. Bruce Fields 11645b6feee9SJ. Bruce Fields return num; 11655b6feee9SJ. Bruce Fields } 11665b6feee9SJ. Bruce Fields 116755c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 11685b6feee9SJ. Bruce Fields { 116955c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 117055c760cfSJ. Bruce Fields 11715b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 117255c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 11735b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 11745b6feee9SJ. Bruce Fields } 11755b6feee9SJ. Bruce Fields 117660810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 117760810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 11785b6feee9SJ. Bruce Fields { 117960810e54SKinglong Mee int numslots = fattrs->maxreqs; 118060810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 11815b6feee9SJ. Bruce Fields struct nfsd4_session *new; 11825b6feee9SJ. Bruce Fields int mem, i; 1183ec6b5d7bSAndy Adamson 1184c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1185ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 11865b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1187ec6b5d7bSAndy Adamson 11885b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 11896c18ba9fSAlexandros Batsakis if (!new) 11905b6feee9SJ. Bruce Fields return NULL; 1191ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 11925b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 119355c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 11945b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1195ec6b5d7bSAndy Adamson goto out_free; 1196ec6b5d7bSAndy Adamson } 119760810e54SKinglong Mee 119860810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 119960810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 120060810e54SKinglong Mee 12015b6feee9SJ. Bruce Fields return new; 12025b6feee9SJ. Bruce Fields out_free: 12035b6feee9SJ. Bruce Fields while (i--) 12045b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 12055b6feee9SJ. Bruce Fields kfree(new); 12065b6feee9SJ. Bruce Fields return NULL; 12075b6feee9SJ. Bruce Fields } 12085b6feee9SJ. Bruce Fields 120919cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 121019cf5c02SJ. Bruce Fields { 121119cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 121219cf5c02SJ. Bruce Fields kfree(c); 121319cf5c02SJ. Bruce Fields } 121419cf5c02SJ. Bruce Fields 121519cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 121619cf5c02SJ. Bruce Fields { 121719cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 121819cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 121919cf5c02SJ. Bruce Fields 122019cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 122119cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 122219cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 122319cf5c02SJ. Bruce Fields free_conn(c); 122419cf5c02SJ. Bruce Fields } 1225eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 12262e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 122719cf5c02SJ. Bruce Fields } 122819cf5c02SJ. Bruce Fields 1229d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1230c7662518SJ. Bruce Fields { 1231c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1232c7662518SJ. Bruce Fields 1233c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1234c7662518SJ. Bruce Fields if (!conn) 1235db90681dSJ. Bruce Fields return NULL; 1236c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1237c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1238d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1239db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1240db90681dSJ. Bruce Fields return conn; 1241db90681dSJ. Bruce Fields } 1242db90681dSJ. Bruce Fields 1243328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1244328ead28SJ. Bruce Fields { 1245328ead28SJ. Bruce Fields conn->cn_session = ses; 1246328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1247328ead28SJ. Bruce Fields } 1248328ead28SJ. Bruce Fields 1249db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1250db90681dSJ. Bruce Fields { 1251db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1252c7662518SJ. Bruce Fields 1253c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1254328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1255c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1256db90681dSJ. Bruce Fields } 1257c7662518SJ. Bruce Fields 125821b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1259db90681dSJ. Bruce Fields { 126019cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 126121b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1262db90681dSJ. Bruce Fields } 1263db90681dSJ. Bruce Fields 1264e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1265db90681dSJ. Bruce Fields { 126621b75b01SJ. Bruce Fields int ret; 1267db90681dSJ. Bruce Fields 1268db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 126921b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 127021b75b01SJ. Bruce Fields if (ret) 127121b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 127221b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 127357a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 127457a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1275c7662518SJ. Bruce Fields } 1276c7662518SJ. Bruce Fields 1277e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 12781d1bc8f2SJ. Bruce Fields { 12791d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 12801d1bc8f2SJ. Bruce Fields 1281e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 12821d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1283e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 12841d1bc8f2SJ. Bruce Fields } 12851d1bc8f2SJ. Bruce Fields 12861d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 128719cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1288c7662518SJ. Bruce Fields { 128919cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 129019cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 129119cf5c02SJ. Bruce Fields 129219cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 129319cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 129419cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 129519cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 129619cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 129719cf5c02SJ. Bruce Fields 129819cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 129919cf5c02SJ. Bruce Fields free_conn(c); 130019cf5c02SJ. Bruce Fields 130119cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 130219cf5c02SJ. Bruce Fields } 130319cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1304c7662518SJ. Bruce Fields } 1305c7662518SJ. Bruce Fields 13061377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 13071377b69eSJ. Bruce Fields { 13081377b69eSJ. Bruce Fields free_session_slots(ses); 13091377b69eSJ. Bruce Fields kfree(ses); 13101377b69eSJ. Bruce Fields } 13111377b69eSJ. Bruce Fields 131266b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1313508dc6e1SBenny Halevy { 1314c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id); 1315c9a49628SStanislav Kinsbursky 1316c7662518SJ. Bruce Fields lockdep_assert_held(&nn->client_lock); 1317c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 131855c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1319c7662518SJ. Bruce Fields __free_session(ses); 1320a827bcb2SJ. Bruce Fields } 1321ec6b5d7bSAndy Adamson 1322135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1323a827bcb2SJ. Bruce Fields { 1324a827bcb2SJ. Bruce Fields int idx; 13251872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1326a827bcb2SJ. Bruce Fields 1327ec6b5d7bSAndy Adamson new->se_client = clp; 1328ec6b5d7bSAndy Adamson gen_sessionid(new); 1329ec6b5d7bSAndy Adamson 1330c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1331c7662518SJ. Bruce Fields 1332ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1333ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 13348b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1335c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 133666b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 13375b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 1338c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 13391872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 13404c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1341ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 13424c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1343c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 134460810e54SKinglong Mee 1345dcbeaa68SJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) { 1346edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1347dcbeaa68SJ. Bruce Fields /* 1348dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1349dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1350dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1351dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1352dcbeaa68SJ. Bruce Fields * future: 1353dcbeaa68SJ. Bruce Fields */ 1354edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1355edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1356edd76786SJ. Bruce Fields } 1357ec6b5d7bSAndy Adamson } 1358ec6b5d7bSAndy Adamson 13599089f1b4SBenny Halevy /* caller must hold client_lock */ 13605282fd72SMarc Eshel static struct nfsd4_session * 1361d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 13625282fd72SMarc Eshel { 13635282fd72SMarc Eshel struct nfsd4_session *elem; 13645282fd72SMarc Eshel int idx; 13651872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 13665282fd72SMarc Eshel 13675282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 13685282fd72SMarc Eshel idx = hash_sessionid(sessionid); 13695282fd72SMarc Eshel /* Search in the appropriate list */ 13701872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 13715282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 13725282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 13735282fd72SMarc Eshel return elem; 13745282fd72SMarc Eshel } 13755282fd72SMarc Eshel } 13765282fd72SMarc Eshel 13775282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 13785282fd72SMarc Eshel return NULL; 13795282fd72SMarc Eshel } 13805282fd72SMarc Eshel 1381d4e19e70STrond Myklebust static struct nfsd4_session * 1382d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1383d4e19e70STrond Myklebust __be32 *ret) 1384d4e19e70STrond Myklebust { 1385d4e19e70STrond Myklebust struct nfsd4_session *session; 1386d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1387d4e19e70STrond Myklebust 1388d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1389d4e19e70STrond Myklebust if (!session) 1390d4e19e70STrond Myklebust goto out; 1391d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1392d4e19e70STrond Myklebust if (status) 1393d4e19e70STrond Myklebust session = NULL; 1394d4e19e70STrond Myklebust out: 1395d4e19e70STrond Myklebust *ret = status; 1396d4e19e70STrond Myklebust return session; 1397d4e19e70STrond Myklebust } 1398d4e19e70STrond Myklebust 13999089f1b4SBenny Halevy /* caller must hold client_lock */ 14007116ed6bSAndy Adamson static void 14015282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 14027116ed6bSAndy Adamson { 14037116ed6bSAndy Adamson list_del(&ses->se_hash); 14044c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 14057116ed6bSAndy Adamson list_del(&ses->se_perclnt); 14064c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 14075282fd72SMarc Eshel } 14085282fd72SMarc Eshel 14091da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 14101da177e4SLinus Torvalds static int 14112c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 14121da177e4SLinus Torvalds { 14132c142baaSStanislav Kinsbursky if (clid->cl_boot == nn->boot_time) 14141da177e4SLinus Torvalds return 0; 141560adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 14162c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 14171da177e4SLinus Torvalds return 1; 14181da177e4SLinus Torvalds } 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds /* 14211da177e4SLinus Torvalds * XXX Should we use a slab cache ? 14221da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 14231da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 14241da177e4SLinus Torvalds */ 142535bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 14261da177e4SLinus Torvalds { 14271da177e4SLinus Torvalds struct nfs4_client *clp; 14281da177e4SLinus Torvalds 142935bba9a3SJ. Bruce Fields clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); 143035bba9a3SJ. Bruce Fields if (clp == NULL) 143135bba9a3SJ. Bruce Fields return NULL; 143267114fe6SThomas Meyer clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); 143335bba9a3SJ. Bruce Fields if (clp->cl_name.data == NULL) { 143435bba9a3SJ. Bruce Fields kfree(clp); 143535bba9a3SJ. Bruce Fields return NULL; 143635bba9a3SJ. Bruce Fields } 14371da177e4SLinus Torvalds clp->cl_name.len = name.len; 14385694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 14395694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 14405694c93eSTrond Myklebust atomic_set(&clp->cl_refcount, 0); 14415694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 14425694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 14435694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 14445694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 14455694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 14465694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_callbacks); 14475694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 14485694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 14495694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 14501da177e4SLinus Torvalds return clp; 14511da177e4SLinus Torvalds } 14521da177e4SLinus Torvalds 14534dd86e15STrond Myklebust static void 14541da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 14551da177e4SLinus Torvalds { 1456bca0ec65SStanislav Kinsbursky struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id); 1457c9a49628SStanislav Kinsbursky 1458c9a49628SStanislav Kinsbursky lockdep_assert_held(&nn->client_lock); 1459792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1460792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1461792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1462792c95ddSJ. Bruce Fields se_perclnt); 1463792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 146466b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 146566b2b9b2SJ. Bruce Fields free_session(ses); 1466792c95ddSJ. Bruce Fields } 14674cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 146803a4e1f6SJ. Bruce Fields free_svc_cred(&clp->cl_cred); 14691da177e4SLinus Torvalds kfree(clp->cl_name.data); 14702d32b29aSmajianpeng idr_destroy(&clp->cl_stateids); 14711da177e4SLinus Torvalds kfree(clp); 14721da177e4SLinus Torvalds } 14731da177e4SLinus Torvalds 147484d38ac9SBenny Halevy /* must be called under the client_lock */ 147584d38ac9SBenny Halevy static inline void 147684d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 147784d38ac9SBenny Halevy { 1478792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1479792c95ddSJ. Bruce Fields 148084d38ac9SBenny Halevy list_del(&clp->cl_lru); 14814c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1482792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1483792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 14844c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 148584d38ac9SBenny Halevy } 148684d38ac9SBenny Halevy 14871da177e4SLinus Torvalds static void 14880d22f68fSJ. Bruce Fields destroy_client(struct nfs4_client *clp) 14891da177e4SLinus Torvalds { 1490fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 14911da177e4SLinus Torvalds struct nfs4_delegation *dp; 14921da177e4SLinus Torvalds struct list_head reaplist; 1493382a62e7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 1496cdc97505SBenny Halevy spin_lock(&state_lock); 1497ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 1498ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 149942690676SJeff Layton unhash_delegation_locked(dp); 150042690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 15011da177e4SLinus Torvalds } 1502cdc97505SBenny Halevy spin_unlock(&state_lock); 15031da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 15041da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 150542690676SJeff Layton list_del_init(&dp->dl_recall_lru); 15066011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 15071da177e4SLinus Torvalds } 15082d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 1509956c4feeSBenny Halevy dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 15102d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 15116011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 1512956c4feeSBenny Halevy } 1513ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 1514fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1515fe0750e5SJ. Bruce Fields release_openowner(oo); 15161da177e4SLinus Torvalds } 15176ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 15182bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 15192bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 152084d38ac9SBenny Halevy list_del(&clp->cl_idhash); 1521ac55fdc4SJeff Layton if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 1522382a62e7SStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 1523ac55fdc4SJeff Layton else 1524a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 1525c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 152684d38ac9SBenny Halevy unhash_client_locked(clp); 1527221a6876SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&clp->cl_refcount)); 1528b12a05cbSJ. Bruce Fields free_client(clp); 1529c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 15301da177e4SLinus Torvalds } 15311da177e4SLinus Torvalds 15320d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 15330d22f68fSJ. Bruce Fields { 15340d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 15350d22f68fSJ. Bruce Fields destroy_client(clp); 15360d22f68fSJ. Bruce Fields } 15370d22f68fSJ. Bruce Fields 153835bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 153935bba9a3SJ. Bruce Fields { 154035bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 154135bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 15421da177e4SLinus Torvalds } 15431da177e4SLinus Torvalds 154435bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 154535bba9a3SJ. Bruce Fields { 15461da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 15471da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 15481da177e4SLinus Torvalds } 15491da177e4SLinus Torvalds 155003a4e1f6SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 155135bba9a3SJ. Bruce Fields { 155203a4e1f6SJ. Bruce Fields if (source->cr_principal) { 155303a4e1f6SJ. Bruce Fields target->cr_principal = 155403a4e1f6SJ. Bruce Fields kstrdup(source->cr_principal, GFP_KERNEL); 155503a4e1f6SJ. Bruce Fields if (target->cr_principal == NULL) 155603a4e1f6SJ. Bruce Fields return -ENOMEM; 155703a4e1f6SJ. Bruce Fields } else 155803a4e1f6SJ. Bruce Fields target->cr_principal = NULL; 1559d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 15601da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 15611da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 15621da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 15631da177e4SLinus Torvalds get_group_info(target->cr_group_info); 15640dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 15650dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 15660dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 156703a4e1f6SJ. Bruce Fields return 0; 15681da177e4SLinus Torvalds } 15691da177e4SLinus Torvalds 1570ac55fdc4SJeff Layton static long long 1571ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 1572ac55fdc4SJeff Layton { 1573ac55fdc4SJeff Layton long long res; 1574ac55fdc4SJeff Layton 1575ac55fdc4SJeff Layton res = o1->len - o2->len; 1576ac55fdc4SJeff Layton if (res) 1577ac55fdc4SJeff Layton return res; 1578ac55fdc4SJeff Layton return (long long)memcmp(o1->data, o2->data, o1->len); 1579ac55fdc4SJeff Layton } 1580ac55fdc4SJeff Layton 158135bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 1582599e0a22SJ. Bruce Fields { 1583a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 15841da177e4SLinus Torvalds } 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds static int 1587599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 1588599e0a22SJ. Bruce Fields { 1589599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 15901da177e4SLinus Torvalds } 15911da177e4SLinus Torvalds 15921da177e4SLinus Torvalds static int 1593599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 1594599e0a22SJ. Bruce Fields { 1595599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 15961da177e4SLinus Torvalds } 15971da177e4SLinus Torvalds 15988fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 15998fbba96eSJ. Bruce Fields { 16008fbba96eSJ. Bruce Fields int i; 16018fbba96eSJ. Bruce Fields 16028fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 16038fbba96eSJ. Bruce Fields return false; 16048fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 16056fab8779SEric W. Biederman if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i))) 16068fbba96eSJ. Bruce Fields return false; 16078fbba96eSJ. Bruce Fields return true; 16088fbba96eSJ. Bruce Fields } 16098fbba96eSJ. Bruce Fields 161068eb3508SJ. Bruce Fields /* 161168eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 161268eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 161368eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 161468eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 161568eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 161668eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 161768eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 161868eb3508SJ. Bruce Fields */ 161968eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 162068eb3508SJ. Bruce Fields { 162168eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 162268eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 162368eb3508SJ. Bruce Fields } 162468eb3508SJ. Bruce Fields 162568eb3508SJ. Bruce Fields 16265559b50aSVivek Trivedi static bool 1627599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 1628599e0a22SJ. Bruce Fields { 162968eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 16306fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 16316fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 16328fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 16338fbba96eSJ. Bruce Fields return false; 16348fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 16358fbba96eSJ. Bruce Fields return true; 16368fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 16378fbba96eSJ. Bruce Fields return false; 16385559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 16391da177e4SLinus Torvalds } 16401da177e4SLinus Torvalds 164157266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 164257266a6eSJ. Bruce Fields { 164357266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 164457266a6eSJ. Bruce Fields u32 service; 164557266a6eSJ. Bruce Fields 1646c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 1647c4720591SJ. Bruce Fields return false; 164857266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 164957266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 165057266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 165157266a6eSJ. Bruce Fields } 165257266a6eSJ. Bruce Fields 165357266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 165457266a6eSJ. Bruce Fields { 165557266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 165657266a6eSJ. Bruce Fields 165757266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 165857266a6eSJ. Bruce Fields return true; 165957266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 166057266a6eSJ. Bruce Fields return false; 166157266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 166257266a6eSJ. Bruce Fields return false; 166357266a6eSJ. Bruce Fields if (!cr->cr_principal) 166457266a6eSJ. Bruce Fields return false; 166557266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 166657266a6eSJ. Bruce Fields } 166757266a6eSJ. Bruce Fields 1668c212cecfSStanislav Kinsbursky static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 16695ec7b46cSJ. Bruce Fields { 16705ec7b46cSJ. Bruce Fields static u32 current_clientid = 1; 16715ec7b46cSJ. Bruce Fields 16722c142baaSStanislav Kinsbursky clp->cl_clientid.cl_boot = nn->boot_time; 16731da177e4SLinus Torvalds clp->cl_clientid.cl_id = current_clientid++; 16741da177e4SLinus Torvalds } 16751da177e4SLinus Torvalds 1676deda2faaSJ. Bruce Fields static void gen_confirm(struct nfs4_client *clp) 1677deda2faaSJ. Bruce Fields { 1678ab4684d1SChuck Lever __be32 verf[2]; 1679deda2faaSJ. Bruce Fields static u32 i; 16801da177e4SLinus Torvalds 1681f419992cSJeff Layton /* 1682f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 1683f419992cSJeff Layton * __force to keep sparse happy 1684f419992cSJeff Layton */ 1685f419992cSJeff Layton verf[0] = (__force __be32)get_seconds(); 1686f419992cSJeff Layton verf[1] = (__force __be32)i++; 1687ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 16881da177e4SLinus Torvalds } 16891da177e4SLinus Torvalds 16904770d722SJeff Layton static struct nfs4_stid * 16914770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 16924581d140SJ. Bruce Fields { 16933abdb607SJ. Bruce Fields struct nfs4_stid *ret; 16943abdb607SJ. Bruce Fields 16953abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 16963abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 16973abdb607SJ. Bruce Fields return NULL; 16983abdb607SJ. Bruce Fields return ret; 16994581d140SJ. Bruce Fields } 17004d71ab87SJ. Bruce Fields 17014770d722SJeff Layton static struct nfs4_stid * 17024770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 1703f459e453SJ. Bruce Fields { 1704f459e453SJ. Bruce Fields struct nfs4_stid *s; 1705f459e453SJ. Bruce Fields 17064770d722SJeff Layton spin_lock(&cl->cl_lock); 17074770d722SJeff Layton s = find_stateid_locked(cl, t); 17082d3f9668STrond Myklebust if (s != NULL) { 17092d3f9668STrond Myklebust if (typemask & s->sc_type) 17102d3f9668STrond Myklebust atomic_inc(&s->sc_count); 17112d3f9668STrond Myklebust else 17124770d722SJeff Layton s = NULL; 17132d3f9668STrond Myklebust } 17144770d722SJeff Layton spin_unlock(&cl->cl_lock); 17154d71ab87SJ. Bruce Fields return s; 17164581d140SJ. Bruce Fields } 17174581d140SJ. Bruce Fields 17182216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 1719b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 1720b09333c4SRicardo Labiaga { 1721b09333c4SRicardo Labiaga struct nfs4_client *clp; 1722b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 172303a4e1f6SJ. Bruce Fields int ret; 1724c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 1725c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 1726b09333c4SRicardo Labiaga 1727b09333c4SRicardo Labiaga clp = alloc_client(name); 1728b09333c4SRicardo Labiaga if (clp == NULL) 1729b09333c4SRicardo Labiaga return NULL; 1730b09333c4SRicardo Labiaga 173103a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 173203a4e1f6SJ. Bruce Fields if (ret) { 1733c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 1734b09333c4SRicardo Labiaga free_client(clp); 1735c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 1736b09333c4SRicardo Labiaga return NULL; 1737b09333c4SRicardo Labiaga } 173802e1215fSJeff Layton INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null); 173907cd4909SBenny Halevy clp->cl_time = get_seconds(); 1740b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 1741b09333c4SRicardo Labiaga copy_verf(clp, verf); 1742b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 1743b09333c4SRicardo Labiaga gen_confirm(clp); 1744edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 1745c212cecfSStanislav Kinsbursky clp->net = net; 1746b09333c4SRicardo Labiaga return clp; 1747b09333c4SRicardo Labiaga } 1748b09333c4SRicardo Labiaga 1749fd39ca9aSNeilBrown static void 1750ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 1751ac55fdc4SJeff Layton { 1752ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 1753ac55fdc4SJeff Layton struct nfs4_client *clp; 1754ac55fdc4SJeff Layton 1755ac55fdc4SJeff Layton while (*new) { 1756ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 1757ac55fdc4SJeff Layton parent = *new; 1758ac55fdc4SJeff Layton 1759ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 1760ac55fdc4SJeff Layton new = &((*new)->rb_left); 1761ac55fdc4SJeff Layton else 1762ac55fdc4SJeff Layton new = &((*new)->rb_right); 1763ac55fdc4SJeff Layton } 1764ac55fdc4SJeff Layton 1765ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 1766ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 1767ac55fdc4SJeff Layton } 1768ac55fdc4SJeff Layton 1769ac55fdc4SJeff Layton static struct nfs4_client * 1770ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 1771ac55fdc4SJeff Layton { 1772ac55fdc4SJeff Layton long long cmp; 1773ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 1774ac55fdc4SJeff Layton struct nfs4_client *clp; 1775ac55fdc4SJeff Layton 1776ac55fdc4SJeff Layton while (node) { 1777ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 1778ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 1779ac55fdc4SJeff Layton if (cmp > 0) 1780ac55fdc4SJeff Layton node = node->rb_left; 1781ac55fdc4SJeff Layton else if (cmp < 0) 1782ac55fdc4SJeff Layton node = node->rb_right; 1783ac55fdc4SJeff Layton else 1784ac55fdc4SJeff Layton return clp; 1785ac55fdc4SJeff Layton } 1786ac55fdc4SJeff Layton return NULL; 1787ac55fdc4SJeff Layton } 1788ac55fdc4SJeff Layton 1789ac55fdc4SJeff Layton static void 1790ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 17911da177e4SLinus Torvalds { 17921da177e4SLinus Torvalds unsigned int idhashval; 17930a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 17941da177e4SLinus Torvalds 1795ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 1796a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 17971da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 17980a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 179936acb66bSBenny Halevy renew_client(clp); 18001da177e4SLinus Torvalds } 18011da177e4SLinus Torvalds 1802fd39ca9aSNeilBrown static void 18031da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 18041da177e4SLinus Torvalds { 18051da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 18068daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 18071da177e4SLinus Torvalds 18081da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 18098daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 1810a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 1811382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 1812ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 18131da177e4SLinus Torvalds renew_client(clp); 18141da177e4SLinus Torvalds } 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds static struct nfs4_client * 1817bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 18181da177e4SLinus Torvalds { 18191da177e4SLinus Torvalds struct nfs4_client *clp; 18201da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 18211da177e4SLinus Torvalds 1822bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 1823a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 1824d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 1825d15c077eSJ. Bruce Fields return NULL; 1826a50d2ad1SJ. Bruce Fields renew_client(clp); 18271da177e4SLinus Torvalds return clp; 18281da177e4SLinus Torvalds } 1829a50d2ad1SJ. Bruce Fields } 18301da177e4SLinus Torvalds return NULL; 18311da177e4SLinus Torvalds } 18321da177e4SLinus Torvalds 18331da177e4SLinus Torvalds static struct nfs4_client * 1834bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 1835bfa85e83SJ. Bruce Fields { 1836bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 1837bfa85e83SJ. Bruce Fields 1838bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 1839bfa85e83SJ. Bruce Fields } 1840bfa85e83SJ. Bruce Fields 1841bfa85e83SJ. Bruce Fields static struct nfs4_client * 18420a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 18431da177e4SLinus Torvalds { 1844bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 18451da177e4SLinus Torvalds 1846bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds 18496e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 1850a1bcecd2SAndy Adamson { 18516e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 1852a1bcecd2SAndy Adamson } 1853a1bcecd2SAndy Adamson 185428ce6054SNeilBrown static struct nfs4_client * 1855382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 185628ce6054SNeilBrown { 1857382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 185828ce6054SNeilBrown } 185928ce6054SNeilBrown 186028ce6054SNeilBrown static struct nfs4_client * 1861a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 186228ce6054SNeilBrown { 1863a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 186428ce6054SNeilBrown } 186528ce6054SNeilBrown 1866fd39ca9aSNeilBrown static void 18676f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 18681da177e4SLinus Torvalds { 186907263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 18706f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 18716f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 18727077ecbaSJeff Layton unsigned short expected_family; 18731da177e4SLinus Torvalds 18747077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 18757077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 18767077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 18777077ecbaSJeff Layton expected_family = AF_INET; 18787077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 18797077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 18807077ecbaSJeff Layton expected_family = AF_INET6; 18817077ecbaSJeff Layton else 18821da177e4SLinus Torvalds goto out_err; 18831da177e4SLinus Torvalds 1884c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 1885aa9a4ec7SJeff Layton se->se_callback_addr_len, 188607263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 188707263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 1888aa9a4ec7SJeff Layton 188907263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 18901da177e4SLinus Torvalds goto out_err; 1891aa9a4ec7SJeff Layton 189207263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 189307263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 1894fbf4665fSJeff Layton 189507263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 189607263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 1897849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 18981da177e4SLinus Torvalds return; 18991da177e4SLinus Torvalds out_err: 190007263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 190107263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 1902849823c5SNeil Brown dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " 19031da177e4SLinus Torvalds "will not receive delegations\n", 19041da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds return; 19071da177e4SLinus Torvalds } 19081da177e4SLinus Torvalds 1909074fe897SAndy Adamson /* 1910067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 1911074fe897SAndy Adamson */ 1912b607664eSTrond Myklebust static void 1913074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 1914074fe897SAndy Adamson { 1915f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 1916557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1917557ce264SAndy Adamson unsigned int base; 1918074fe897SAndy Adamson 1919557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 1920074fe897SAndy Adamson 1921557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 1922557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 1923bf864a31SAndy Adamson 1924bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 1925bf864a31SAndy Adamson if (nfsd4_not_cached(resp)) { 1926557ce264SAndy Adamson slot->sl_datalen = 0; 1927bf864a31SAndy Adamson return; 1928bf864a31SAndy Adamson } 1929f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 1930f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 1931f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 1932557ce264SAndy Adamson WARN("%s: sessions DRC could not cache compound\n", __func__); 1933557ce264SAndy Adamson return; 1934074fe897SAndy Adamson } 1935074fe897SAndy Adamson 1936074fe897SAndy Adamson /* 1937abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 1938abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 1939abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 1940abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 1941abfabf8cSAndy Adamson * 1942074fe897SAndy Adamson */ 1943abfabf8cSAndy Adamson static __be32 1944abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 1945abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 1946074fe897SAndy Adamson { 1947abfabf8cSAndy Adamson struct nfsd4_op *op; 1948abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1949074fe897SAndy Adamson 1950abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 1951abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 1952abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 1953abfabf8cSAndy Adamson 1954abfabf8cSAndy Adamson /* Return nfserr_retry_uncached_rep in next operation. */ 195573e79482SJ. Bruce Fields if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { 1956abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 1957abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 1958abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 1959074fe897SAndy Adamson } 1960abfabf8cSAndy Adamson return op->status; 1961074fe897SAndy Adamson } 1962074fe897SAndy Adamson 1963074fe897SAndy Adamson /* 1964557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 1965557ce264SAndy Adamson * session values. 1966074fe897SAndy Adamson */ 19673ca2eb98SJ. Bruce Fields static __be32 1968bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 1969bf864a31SAndy Adamson struct nfsd4_sequence *seq) 1970074fe897SAndy Adamson { 1971557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1972f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 1973f5236013SJ. Bruce Fields __be32 *p; 1974074fe897SAndy Adamson __be32 status; 1975074fe897SAndy Adamson 1976557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 1977074fe897SAndy Adamson 1978abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 19790da7b19cSJ. Bruce Fields if (status) 1980abfabf8cSAndy Adamson return status; 1981074fe897SAndy Adamson 1982f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 1983f5236013SJ. Bruce Fields if (!p) { 1984f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 1985f5236013SJ. Bruce Fields return nfserr_serverfault; 1986f5236013SJ. Bruce Fields } 1987f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 1988f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 1989074fe897SAndy Adamson 1990557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 1991f5236013SJ. Bruce Fields return slot->sl_status; 1992074fe897SAndy Adamson } 1993074fe897SAndy Adamson 19940733d213SAndy Adamson /* 19950733d213SAndy Adamson * Set the exchange_id flags returned by the server. 19960733d213SAndy Adamson */ 19970733d213SAndy Adamson static void 19980733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 19990733d213SAndy Adamson { 20000733d213SAndy Adamson /* pNFS is not supported */ 20010733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 20020733d213SAndy Adamson 20030733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 20040733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 20050733d213SAndy Adamson 20060733d213SAndy Adamson /* set the wire flags to return to client. */ 20070733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 20080733d213SAndy Adamson } 20090733d213SAndy Adamson 2010631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 2011631fc9eaSJ. Bruce Fields { 2012631fc9eaSJ. Bruce Fields /* 2013631fc9eaSJ. Bruce Fields * Note clp->cl_openowners check isn't quite right: there's no 2014631fc9eaSJ. Bruce Fields * need to count owners without stateid's. 2015631fc9eaSJ. Bruce Fields * 2016631fc9eaSJ. Bruce Fields * Also note we should probably be using this in 4.0 case too. 2017631fc9eaSJ. Bruce Fields */ 20186eccece9SJ. Bruce Fields return !list_empty(&clp->cl_openowners) 20196eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 20206eccece9SJ. Bruce Fields || !list_empty(&clp->cl_sessions); 2021631fc9eaSJ. Bruce Fields } 2022631fc9eaSJ. Bruce Fields 2023b37ad28bSAl Viro __be32 2024069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp, 2025069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2026069b6ad4SAndy Adamson struct nfsd4_exchange_id *exid) 2027069b6ad4SAndy Adamson { 20280733d213SAndy Adamson struct nfs4_client *unconf, *conf, *new; 202957b7b43bSJ. Bruce Fields __be32 status; 2030363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 20310733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 2032363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 203383e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 2034c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 20350733d213SAndy Adamson 2036363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 20370733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 2038363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 20390733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 2040363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 20410733d213SAndy Adamson 2042a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 20430733d213SAndy Adamson return nfserr_inval; 20440733d213SAndy Adamson 20450733d213SAndy Adamson switch (exid->spa_how) { 204657266a6eSJ. Bruce Fields case SP4_MACH_CRED: 204757266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 204857266a6eSJ. Bruce Fields return nfserr_inval; 20490733d213SAndy Adamson case SP4_NONE: 20500733d213SAndy Adamson break; 2051063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 2052063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 20530733d213SAndy Adamson case SP4_SSV: 2054dd30333cSJ. Bruce Fields return nfserr_encr_alg_unsupp; 20550733d213SAndy Adamson } 20560733d213SAndy Adamson 20572dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 20580733d213SAndy Adamson nfs4_lock_state(); 2059382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 20600733d213SAndy Adamson if (conf) { 206183e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 206283e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 206383e08fd4SJ. Bruce Fields 2064136e658dSJ. Bruce Fields if (update) { 2065136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 20662dbb269dSJ. Bruce Fields status = nfserr_inval; 2067e203d506SJ. Bruce Fields goto out; 2068e203d506SJ. Bruce Fields } 206957266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) { 207057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 207157266a6eSJ. Bruce Fields goto out; 207257266a6eSJ. Bruce Fields } 20732dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 20740733d213SAndy Adamson status = nfserr_perm; 20750733d213SAndy Adamson goto out; 20760733d213SAndy Adamson } 20772dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 20780733d213SAndy Adamson status = nfserr_not_same; 20790733d213SAndy Adamson goto out; 20800733d213SAndy Adamson } 2081136e658dSJ. Bruce Fields /* case 6 */ 20820733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 20830733d213SAndy Adamson new = conf; 20840733d213SAndy Adamson goto out_copy; 20856ddbbbfeSMike Sager } 2086136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 2087631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 2088136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 2089136e658dSJ. Bruce Fields goto out; 2090136e658dSJ. Bruce Fields } 2091b9831b59SJ. Bruce Fields expire_client(conf); 2092b9831b59SJ. Bruce Fields goto out_new; 2093631fc9eaSJ. Bruce Fields } 2094136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 20950f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 2096136e658dSJ. Bruce Fields new = conf; 2097136e658dSJ. Bruce Fields goto out_copy; 2098136e658dSJ. Bruce Fields } 20992dbb269dSJ. Bruce Fields /* case 5, client reboot */ 21000733d213SAndy Adamson goto out_new; 21010733d213SAndy Adamson } 21026ddbbbfeSMike Sager 21032dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 21040733d213SAndy Adamson status = nfserr_noent; 21050733d213SAndy Adamson goto out; 21060733d213SAndy Adamson } 21070733d213SAndy Adamson 2108a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 21092dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 21100733d213SAndy Adamson expire_client(unconf); 21110733d213SAndy Adamson 21122dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 21130733d213SAndy Adamson out_new: 21142216d449SJeff Layton new = create_client(exid->clname, rqstp, &verf); 21150733d213SAndy Adamson if (new == NULL) { 21164731030dSJ. Bruce Fields status = nfserr_jukebox; 21170733d213SAndy Adamson goto out; 21180733d213SAndy Adamson } 21194f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 212057266a6eSJ. Bruce Fields new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); 21210733d213SAndy Adamson 2122c212cecfSStanislav Kinsbursky gen_clid(new, nn); 2123ac55fdc4SJeff Layton add_to_unconfirmed(new); 21240733d213SAndy Adamson out_copy: 21250733d213SAndy Adamson exid->clientid.cl_boot = new->cl_clientid.cl_boot; 21260733d213SAndy Adamson exid->clientid.cl_id = new->cl_clientid.cl_id; 21270733d213SAndy Adamson 2128778df3f0SJ. Bruce Fields exid->seqid = new->cl_cs_slot.sl_seqid + 1; 21290733d213SAndy Adamson nfsd4_set_ex_flags(new, exid); 21300733d213SAndy Adamson 21310733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 213249557cc7SAndy Adamson new->cl_cs_slot.sl_seqid, new->cl_exchange_flags); 21330733d213SAndy Adamson status = nfs_ok; 21340733d213SAndy Adamson 21350733d213SAndy Adamson out: 21360733d213SAndy Adamson nfs4_unlock_state(); 21370733d213SAndy Adamson return status; 2138069b6ad4SAndy Adamson } 2139069b6ad4SAndy Adamson 214057b7b43bSJ. Bruce Fields static __be32 214188e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 2142b85d4c01SBenny Halevy { 214388e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 214488e588d5SAndy Adamson slot_seqid); 2145b85d4c01SBenny Halevy 2146b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 214788e588d5SAndy Adamson if (slot_inuse) { 214888e588d5SAndy Adamson if (seqid == slot_seqid) 2149b85d4c01SBenny Halevy return nfserr_jukebox; 2150b85d4c01SBenny Halevy else 2151b85d4c01SBenny Halevy return nfserr_seq_misordered; 2152b85d4c01SBenny Halevy } 2153f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 215488e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 2155b85d4c01SBenny Halevy return nfs_ok; 215688e588d5SAndy Adamson if (seqid == slot_seqid) 2157b85d4c01SBenny Halevy return nfserr_replay_cache; 2158b85d4c01SBenny Halevy return nfserr_seq_misordered; 2159b85d4c01SBenny Halevy } 2160b85d4c01SBenny Halevy 216149557cc7SAndy Adamson /* 216249557cc7SAndy Adamson * Cache the create session result into the create session single DRC 216349557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 216449557cc7SAndy Adamson * Do this for solo or embedded create session operations. 216549557cc7SAndy Adamson */ 216649557cc7SAndy Adamson static void 216749557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 216857b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 216949557cc7SAndy Adamson { 217049557cc7SAndy Adamson slot->sl_status = nfserr; 217149557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 217249557cc7SAndy Adamson } 217349557cc7SAndy Adamson 217449557cc7SAndy Adamson static __be32 217549557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 217649557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 217749557cc7SAndy Adamson { 217849557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 217949557cc7SAndy Adamson return slot->sl_status; 218049557cc7SAndy Adamson } 218149557cc7SAndy Adamson 21821b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 21831b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 21841b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 21851b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 21861b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 21871b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 21881b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 21891b74c25bSMi Jinlong 21901b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 21911b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 21921b74c25bSMi Jinlong 1 + /* status */ \ 21931b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 21941b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 21951b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 21961b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 21971b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 21981b74c25bSMi Jinlong 219955c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 22001b74c25bSMi Jinlong { 220155c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 220255c760cfSJ. Bruce Fields 2203373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 2204373cd409SJ. Bruce Fields return nfserr_toosmall; 2205373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 2206373cd409SJ. Bruce Fields return nfserr_toosmall; 220755c760cfSJ. Bruce Fields ca->headerpadsz = 0; 220855c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 220955c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 221055c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 221155c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 221255c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 221355c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 221455c760cfSJ. Bruce Fields /* 221555c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 221655c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 221755c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 221855c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 221955c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 222055c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 222155c760cfSJ. Bruce Fields */ 222255c760cfSJ. Bruce Fields ca->maxreqs = nfsd4_get_drc_mem(ca); 222355c760cfSJ. Bruce Fields if (!ca->maxreqs) 222455c760cfSJ. Bruce Fields return nfserr_jukebox; 222555c760cfSJ. Bruce Fields 2226373cd409SJ. Bruce Fields return nfs_ok; 22271b74c25bSMi Jinlong } 22281b74c25bSMi Jinlong 22298a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 22308a891633SKinglong Mee RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32)) 22318a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 22328a891633SKinglong Mee RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32)) 22338a891633SKinglong Mee 223406b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 223506b332a5SJ. Bruce Fields { 223606b332a5SJ. Bruce Fields ca->headerpadsz = 0; 223706b332a5SJ. Bruce Fields 223806b332a5SJ. Bruce Fields /* 223906b332a5SJ. Bruce Fields * These RPC_MAX_HEADER macros are overkill, especially since we 224006b332a5SJ. Bruce Fields * don't even do gss on the backchannel yet. But this is still 224106b332a5SJ. Bruce Fields * less than 1k. Tighten up this estimate in the unlikely event 224206b332a5SJ. Bruce Fields * it turns out to be a problem for some client: 224306b332a5SJ. Bruce Fields */ 22448a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 224506b332a5SJ. Bruce Fields return nfserr_toosmall; 22468a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 224706b332a5SJ. Bruce Fields return nfserr_toosmall; 224806b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 224906b332a5SJ. Bruce Fields if (ca->maxops < 2) 225006b332a5SJ. Bruce Fields return nfserr_toosmall; 225106b332a5SJ. Bruce Fields 225206b332a5SJ. Bruce Fields return nfs_ok; 2253069b6ad4SAndy Adamson } 2254069b6ad4SAndy Adamson 2255b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 2256b78724b7SJ. Bruce Fields { 2257b78724b7SJ. Bruce Fields switch (cbs->flavor) { 2258b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 2259b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 2260b78724b7SJ. Bruce Fields return nfs_ok; 2261b78724b7SJ. Bruce Fields default: 2262b78724b7SJ. Bruce Fields /* 2263b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 2264b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 2265b78724b7SJ. Bruce Fields * GSS. 2266b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 2267b78724b7SJ. Bruce Fields * client might think it can already handle: 2268b78724b7SJ. Bruce Fields */ 2269b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 2270b78724b7SJ. Bruce Fields } 2271b78724b7SJ. Bruce Fields } 2272b78724b7SJ. Bruce Fields 2273069b6ad4SAndy Adamson __be32 2274069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 2275069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2276069b6ad4SAndy Adamson struct nfsd4_create_session *cr_ses) 2277069b6ad4SAndy Adamson { 2278363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 2279ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 2280ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 228181f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 228249557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 228357b7b43bSJ. Bruce Fields __be32 status = 0; 22848daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2285ec6b5d7bSAndy Adamson 2286a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 2287a62573dcSMi Jinlong return nfserr_inval; 2288b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 2289b78724b7SJ. Bruce Fields if (status) 2290b78724b7SJ. Bruce Fields return status; 229155c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 2292373cd409SJ. Bruce Fields if (status) 2293373cd409SJ. Bruce Fields return status; 229406b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 229506b332a5SJ. Bruce Fields if (status) 2296f403e450SKinglong Mee goto out_release_drc_mem; 229781f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 229860810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 229955c760cfSJ. Bruce Fields if (!new) 230055c760cfSJ. Bruce Fields goto out_release_drc_mem; 230181f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 230281f0b2a4SJ. Bruce Fields if (!conn) 230381f0b2a4SJ. Bruce Fields goto out_free_session; 2304a62573dcSMi Jinlong 2305ec6b5d7bSAndy Adamson nfs4_lock_state(); 23060a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 23078daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 230878389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2309ec6b5d7bSAndy Adamson 2310ec6b5d7bSAndy Adamson if (conf) { 231157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 231257266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) 231357266a6eSJ. Bruce Fields goto out_free_conn; 231449557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 231549557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 231638eb76a5SAndy Adamson if (status == nfserr_replay_cache) { 231749557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 231881f0b2a4SJ. Bruce Fields goto out_free_conn; 231949557cc7SAndy Adamson } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { 2320ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 232181f0b2a4SJ. Bruce Fields goto out_free_conn; 2322ec6b5d7bSAndy Adamson } 2323ec6b5d7bSAndy Adamson } else if (unconf) { 23248f9d3d3bSJ. Bruce Fields struct nfs4_client *old; 2325ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 2326363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 2327ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 232881f0b2a4SJ. Bruce Fields goto out_free_conn; 2329ec6b5d7bSAndy Adamson } 233057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 233157266a6eSJ. Bruce Fields if (!mach_creds_match(unconf, rqstp)) 233257266a6eSJ. Bruce Fields goto out_free_conn; 233349557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 233449557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 233538eb76a5SAndy Adamson if (status) { 233638eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 2337ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 233881f0b2a4SJ. Bruce Fields goto out_free_conn; 2339ec6b5d7bSAndy Adamson } 2340382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 2341221a6876SJ. Bruce Fields if (old) { 2342221a6876SJ. Bruce Fields status = mark_client_expired(old); 2343221a6876SJ. Bruce Fields if (status) 2344221a6876SJ. Bruce Fields goto out_free_conn; 23458f9d3d3bSJ. Bruce Fields expire_client(old); 2346221a6876SJ. Bruce Fields } 23478f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 2348ec6b5d7bSAndy Adamson conf = unconf; 2349ec6b5d7bSAndy Adamson } else { 2350ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 235181f0b2a4SJ. Bruce Fields goto out_free_conn; 2352ec6b5d7bSAndy Adamson } 235381f0b2a4SJ. Bruce Fields status = nfs_ok; 23548323c3b2SJ. Bruce Fields /* 2355408b79bcSJ. Bruce Fields * We do not support RDMA or persistent sessions 2356408b79bcSJ. Bruce Fields */ 2357408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 2358408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 2359408b79bcSJ. Bruce Fields 236081f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 236181f0b2a4SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, new); 236281f0b2a4SJ. Bruce Fields 2363ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 2364ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 236586c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 236649557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 2367ec6b5d7bSAndy Adamson 236849557cc7SAndy Adamson /* cache solo and embedded create sessions under the state lock */ 236949557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 2370ec6b5d7bSAndy Adamson nfs4_unlock_state(); 2371ec6b5d7bSAndy Adamson return status; 237281f0b2a4SJ. Bruce Fields out_free_conn: 2373266533c6SYanchuan Nian nfs4_unlock_state(); 237481f0b2a4SJ. Bruce Fields free_conn(conn); 237581f0b2a4SJ. Bruce Fields out_free_session: 237681f0b2a4SJ. Bruce Fields __free_session(new); 237755c760cfSJ. Bruce Fields out_release_drc_mem: 237855c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 23791ca50792SJ. Bruce Fields return status; 2380069b6ad4SAndy Adamson } 2381069b6ad4SAndy Adamson 23821d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 23831d1bc8f2SJ. Bruce Fields { 23841d1bc8f2SJ. Bruce Fields switch (*dir) { 23851d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 23861d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 23871d1bc8f2SJ. Bruce Fields return nfs_ok; 23881d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 23891d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 23901d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 23911d1bc8f2SJ. Bruce Fields return nfs_ok; 23921d1bc8f2SJ. Bruce Fields }; 23931d1bc8f2SJ. Bruce Fields return nfserr_inval; 23941d1bc8f2SJ. Bruce Fields } 23951d1bc8f2SJ. Bruce Fields 2396cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) 2397cb73a9f4SJ. Bruce Fields { 2398cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 2399c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2400b78724b7SJ. Bruce Fields __be32 status; 2401cb73a9f4SJ. Bruce Fields 2402b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 2403b78724b7SJ. Bruce Fields if (status) 2404b78724b7SJ. Bruce Fields return status; 2405c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2406cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 2407cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 2408c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2409cb73a9f4SJ. Bruce Fields 2410cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 2411cb73a9f4SJ. Bruce Fields 2412cb73a9f4SJ. Bruce Fields return nfs_ok; 2413cb73a9f4SJ. Bruce Fields } 2414cb73a9f4SJ. Bruce Fields 24151d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 24161d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 24171d1bc8f2SJ. Bruce Fields struct nfsd4_bind_conn_to_session *bcts) 24181d1bc8f2SJ. Bruce Fields { 24191d1bc8f2SJ. Bruce Fields __be32 status; 24203ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 24214f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 2422d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2423d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 24241d1bc8f2SJ. Bruce Fields 24251d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 24261d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 24274f6e6c17SJ. Bruce Fields nfs4_lock_state(); 2428c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2429d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 2430c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 24314f6e6c17SJ. Bruce Fields if (!session) 2432d4e19e70STrond Myklebust goto out_no_session; 243357266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 243457266a6eSJ. Bruce Fields if (!mach_creds_match(session->se_client, rqstp)) 243557266a6eSJ. Bruce Fields goto out; 24361d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 24373ba63671SJ. Bruce Fields if (status) 24384f6e6c17SJ. Bruce Fields goto out; 24393ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 24404f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 24413ba63671SJ. Bruce Fields if (!conn) 24424f6e6c17SJ. Bruce Fields goto out; 24434f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 24444f6e6c17SJ. Bruce Fields status = nfs_ok; 24454f6e6c17SJ. Bruce Fields out: 2446d4e19e70STrond Myklebust nfsd4_put_session(session); 2447d4e19e70STrond Myklebust out_no_session: 24484f6e6c17SJ. Bruce Fields nfs4_unlock_state(); 24494f6e6c17SJ. Bruce Fields return status; 24501d1bc8f2SJ. Bruce Fields } 24511d1bc8f2SJ. Bruce Fields 24525d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) 24535d4cec2fSJ. Bruce Fields { 24545d4cec2fSJ. Bruce Fields if (!session) 24555d4cec2fSJ. Bruce Fields return 0; 24565d4cec2fSJ. Bruce Fields return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); 24575d4cec2fSJ. Bruce Fields } 24585d4cec2fSJ. Bruce Fields 2459069b6ad4SAndy Adamson __be32 2460069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r, 2461069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2462069b6ad4SAndy Adamson struct nfsd4_destroy_session *sessionid) 2463069b6ad4SAndy Adamson { 2464e10e0cfcSBenny Halevy struct nfsd4_session *ses; 2465abcdff09SJ. Bruce Fields __be32 status; 2466f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 2467d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 2468d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2469e10e0cfcSBenny Halevy 2470abcdff09SJ. Bruce Fields nfs4_lock_state(); 2471abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 24725d4cec2fSJ. Bruce Fields if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { 247357716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 2474abcdff09SJ. Bruce Fields goto out; 2475f0f51f5cSJ. Bruce Fields ref_held_by_me++; 247657716355SJ. Bruce Fields } 2477e10e0cfcSBenny Halevy dump_sessionid(__func__, &sessionid->sessionid); 2478c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2479d4e19e70STrond Myklebust ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status); 2480abcdff09SJ. Bruce Fields if (!ses) 2481abcdff09SJ. Bruce Fields goto out_client_lock; 248257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 248357266a6eSJ. Bruce Fields if (!mach_creds_match(ses->se_client, r)) 2484d4e19e70STrond Myklebust goto out_put_session; 2485f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 248666b2b9b2SJ. Bruce Fields if (status) 2487f0f51f5cSJ. Bruce Fields goto out_put_session; 2488e10e0cfcSBenny Halevy unhash_session(ses); 2489c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2490e10e0cfcSBenny Halevy 249184f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 249219cf5c02SJ. Bruce Fields 2493c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2494e10e0cfcSBenny Halevy status = nfs_ok; 2495f0f51f5cSJ. Bruce Fields out_put_session: 2496d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 2497abcdff09SJ. Bruce Fields out_client_lock: 2498abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 2499e10e0cfcSBenny Halevy out: 2500abcdff09SJ. Bruce Fields nfs4_unlock_state(); 2501e10e0cfcSBenny Halevy return status; 2502069b6ad4SAndy Adamson } 2503069b6ad4SAndy Adamson 2504a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 2505328ead28SJ. Bruce Fields { 2506328ead28SJ. Bruce Fields struct nfsd4_conn *c; 2507328ead28SJ. Bruce Fields 2508328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 2509a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 2510328ead28SJ. Bruce Fields return c; 2511328ead28SJ. Bruce Fields } 2512328ead28SJ. Bruce Fields } 2513328ead28SJ. Bruce Fields return NULL; 2514328ead28SJ. Bruce Fields } 2515328ead28SJ. Bruce Fields 251657266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 2517328ead28SJ. Bruce Fields { 2518328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 2519a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 252057266a6eSJ. Bruce Fields __be32 status = nfs_ok; 252121b75b01SJ. Bruce Fields int ret; 2522328ead28SJ. Bruce Fields 2523328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 2524a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 252557266a6eSJ. Bruce Fields if (c) 252657266a6eSJ. Bruce Fields goto out_free; 252757266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 252857266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 252957266a6eSJ. Bruce Fields goto out_free; 2530328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 2531328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 253221b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 253321b75b01SJ. Bruce Fields if (ret) 253421b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 253521b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 253657266a6eSJ. Bruce Fields return nfs_ok; 253757266a6eSJ. Bruce Fields out_free: 253857266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 253957266a6eSJ. Bruce Fields free_conn(new); 254057266a6eSJ. Bruce Fields return status; 2541328ead28SJ. Bruce Fields } 2542328ead28SJ. Bruce Fields 2543868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 2544868b89c3SMi Jinlong { 2545868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 2546868b89c3SMi Jinlong 2547868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 2548868b89c3SMi Jinlong } 2549868b89c3SMi Jinlong 2550ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 2551ae82a8d0SMi Jinlong struct nfsd4_session *session) 2552ae82a8d0SMi Jinlong { 2553ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 2554ae82a8d0SMi Jinlong 2555ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 2556ae82a8d0SMi Jinlong } 2557ae82a8d0SMi Jinlong 2558069b6ad4SAndy Adamson __be32 2559b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp, 2560069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2561069b6ad4SAndy Adamson struct nfsd4_sequence *seq) 2562069b6ad4SAndy Adamson { 2563f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 256447ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2565b85d4c01SBenny Halevy struct nfsd4_session *session; 2566221a6876SJ. Bruce Fields struct nfs4_client *clp; 2567b85d4c01SBenny Halevy struct nfsd4_slot *slot; 2568a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 256957b7b43bSJ. Bruce Fields __be32 status; 257047ee5298SJ. Bruce Fields int buflen; 2571d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2572d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2573b85d4c01SBenny Halevy 2574f9bb94c4SAndy Adamson if (resp->opcnt != 1) 2575f9bb94c4SAndy Adamson return nfserr_sequence_pos; 2576f9bb94c4SAndy Adamson 2577a663bdd8SJ. Bruce Fields /* 2578a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 2579a663bdd8SJ. Bruce Fields * below. 2580a663bdd8SJ. Bruce Fields */ 2581a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 2582a663bdd8SJ. Bruce Fields if (!conn) 2583a663bdd8SJ. Bruce Fields return nfserr_jukebox; 2584a663bdd8SJ. Bruce Fields 2585c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2586d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 2587b85d4c01SBenny Halevy if (!session) 2588221a6876SJ. Bruce Fields goto out_no_session; 2589221a6876SJ. Bruce Fields clp = session->se_client; 2590b85d4c01SBenny Halevy 2591868b89c3SMi Jinlong status = nfserr_too_many_ops; 2592868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 259366b2b9b2SJ. Bruce Fields goto out_put_session; 2594868b89c3SMi Jinlong 2595ae82a8d0SMi Jinlong status = nfserr_req_too_big; 2596ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 259766b2b9b2SJ. Bruce Fields goto out_put_session; 2598ae82a8d0SMi Jinlong 2599b85d4c01SBenny Halevy status = nfserr_badslot; 26006c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 260166b2b9b2SJ. Bruce Fields goto out_put_session; 2602b85d4c01SBenny Halevy 2603557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 2604b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 2605b85d4c01SBenny Halevy 2606a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 2607a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 2608a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 2609a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 2610a8dfdaebSAndy Adamson 261173e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 261273e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 2613b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 2614bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 2615bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 261666b2b9b2SJ. Bruce Fields goto out_put_session; 2617b85d4c01SBenny Halevy cstate->slot = slot; 2618b85d4c01SBenny Halevy cstate->session = session; 26194b24ca7dSJeff Layton cstate->clp = clp; 2620da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 2621557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 2622bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 2623da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 2624aaf84eb9SBenny Halevy goto out; 2625b85d4c01SBenny Halevy } 2626b85d4c01SBenny Halevy if (status) 262766b2b9b2SJ. Bruce Fields goto out_put_session; 2628b85d4c01SBenny Halevy 262957266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 2630a663bdd8SJ. Bruce Fields conn = NULL; 263157266a6eSJ. Bruce Fields if (status) 263257266a6eSJ. Bruce Fields goto out_put_session; 2633328ead28SJ. Bruce Fields 263447ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 263547ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 263647ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 263747ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 263847ee5298SJ. Bruce Fields nfserr_rep_too_big; 2639a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 264047ee5298SJ. Bruce Fields goto out_put_session; 264132aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 264247ee5298SJ. Bruce Fields 264347ee5298SJ. Bruce Fields status = nfs_ok; 2644b85d4c01SBenny Halevy /* Success! bump slot seqid */ 2645b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 2646bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 264773e79482SJ. Bruce Fields if (seq->cachethis) 264873e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 2649bf5c43c8SJ. Bruce Fields else 2650bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 2651b85d4c01SBenny Halevy 2652b85d4c01SBenny Halevy cstate->slot = slot; 2653b85d4c01SBenny Halevy cstate->session = session; 26544b24ca7dSJeff Layton cstate->clp = clp; 2655b85d4c01SBenny Halevy 2656b85d4c01SBenny Halevy out: 26575423732aSBenny Halevy switch (clp->cl_cb_state) { 26585423732aSBenny Halevy case NFSD4_CB_DOWN: 2659fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 26605423732aSBenny Halevy break; 26615423732aSBenny Halevy case NFSD4_CB_FAULT: 2662fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 26635423732aSBenny Halevy break; 2664fc0c3dd1SBenny Halevy default: 2665fc0c3dd1SBenny Halevy seq->status_flags = 0; 26665423732aSBenny Halevy } 26673bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 26683bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 2669221a6876SJ. Bruce Fields out_no_session: 26703f42d2c4SKinglong Mee if (conn) 26713f42d2c4SKinglong Mee free_conn(conn); 2672c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2673b85d4c01SBenny Halevy return status; 267466b2b9b2SJ. Bruce Fields out_put_session: 2675d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 2676221a6876SJ. Bruce Fields goto out_no_session; 2677069b6ad4SAndy Adamson } 2678069b6ad4SAndy Adamson 2679b607664eSTrond Myklebust void 2680b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 2681b607664eSTrond Myklebust { 2682b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 2683b607664eSTrond Myklebust 2684b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 2685b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 2686b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 2687b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 2688b607664eSTrond Myklebust } 2689d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 2690b607664eSTrond Myklebust nfsd4_put_session(cs->session); 26914b24ca7dSJeff Layton } else if (cs->clp) 26924b24ca7dSJeff Layton put_client_renew(cs->clp); 2693b607664eSTrond Myklebust } 2694b607664eSTrond Myklebust 2695345c2842SMi Jinlong __be32 2696345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) 2697345c2842SMi Jinlong { 2698345c2842SMi Jinlong struct nfs4_client *conf, *unconf, *clp; 269957b7b43bSJ. Bruce Fields __be32 status = 0; 27008daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2701345c2842SMi Jinlong 2702345c2842SMi Jinlong nfs4_lock_state(); 27030a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 27048daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 270578389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2706345c2842SMi Jinlong 2707345c2842SMi Jinlong if (conf) { 2708345c2842SMi Jinlong clp = conf; 2709345c2842SMi Jinlong 2710c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 2711345c2842SMi Jinlong status = nfserr_clientid_busy; 2712345c2842SMi Jinlong goto out; 2713345c2842SMi Jinlong } 2714345c2842SMi Jinlong } else if (unconf) 2715345c2842SMi Jinlong clp = unconf; 2716345c2842SMi Jinlong else { 2717345c2842SMi Jinlong status = nfserr_stale_clientid; 2718345c2842SMi Jinlong goto out; 2719345c2842SMi Jinlong } 272057266a6eSJ. Bruce Fields if (!mach_creds_match(clp, rqstp)) { 272157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 272257266a6eSJ. Bruce Fields goto out; 272357266a6eSJ. Bruce Fields } 2724345c2842SMi Jinlong expire_client(clp); 2725345c2842SMi Jinlong out: 2726345c2842SMi Jinlong nfs4_unlock_state(); 2727345c2842SMi Jinlong return status; 2728345c2842SMi Jinlong } 2729345c2842SMi Jinlong 2730069b6ad4SAndy Adamson __be32 27314dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) 27324dc6ec00SJ. Bruce Fields { 273357b7b43bSJ. Bruce Fields __be32 status = 0; 2734bcecf1ccSMi Jinlong 27354dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 27364dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 27374dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 27384dc6ec00SJ. Bruce Fields /* 27394dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 27404dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 27414dc6ec00SJ. Bruce Fields */ 27424dc6ec00SJ. Bruce Fields return nfs_ok; 27434dc6ec00SJ. Bruce Fields } 2744bcecf1ccSMi Jinlong 27454dc6ec00SJ. Bruce Fields nfs4_lock_state(); 2746bcecf1ccSMi Jinlong status = nfserr_complete_already; 2747a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 2748a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 2749bcecf1ccSMi Jinlong goto out; 2750bcecf1ccSMi Jinlong 2751bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 2752bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 27534dc6ec00SJ. Bruce Fields /* 27544dc6ec00SJ. Bruce Fields * The following error isn't really legal. 27554dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 27564dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 27574dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 27584dc6ec00SJ. Bruce Fields * client. 27594dc6ec00SJ. Bruce Fields */ 2760bcecf1ccSMi Jinlong goto out; 2761bcecf1ccSMi Jinlong 2762bcecf1ccSMi Jinlong status = nfs_ok; 27632a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 2764bcecf1ccSMi Jinlong out: 27654dc6ec00SJ. Bruce Fields nfs4_unlock_state(); 2766bcecf1ccSMi Jinlong return status; 27674dc6ec00SJ. Bruce Fields } 27684dc6ec00SJ. Bruce Fields 27694dc6ec00SJ. Bruce Fields __be32 2770b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 2771b591480bSJ.Bruce Fields struct nfsd4_setclientid *setclid) 27721da177e4SLinus Torvalds { 2773a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 27741da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 277528ce6054SNeilBrown struct nfs4_client *conf, *unconf, *new; 2776b37ad28bSAl Viro __be32 status; 2777c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2778a55370a3SNeilBrown 277963db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 27801da177e4SLinus Torvalds nfs4_lock_state(); 2781382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 278228ce6054SNeilBrown if (conf) { 278363db4632SJ. Bruce Fields /* case 0: */ 27841da177e4SLinus Torvalds status = nfserr_clid_inuse; 2785e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 2786e203d506SJ. Bruce Fields goto out; 2787026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 2788363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 2789363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 2790363168b4SJeff Layton sizeof(addr_str)); 2791026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 2792363168b4SJeff Layton "at %s\n", addr_str); 27931da177e4SLinus Torvalds goto out; 27941da177e4SLinus Torvalds } 27951da177e4SLinus Torvalds } 2796a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 27971da177e4SLinus Torvalds if (unconf) 27981da177e4SLinus Torvalds expire_client(unconf); 27998f930711SJ. Bruce Fields status = nfserr_jukebox; 28002216d449SJeff Layton new = create_client(clname, rqstp, &clverifier); 2801a55370a3SNeilBrown if (new == NULL) 28021da177e4SLinus Torvalds goto out; 280334b232bbSJ. Bruce Fields if (conf && same_verf(&conf->cl_verifier, &clverifier)) 280463db4632SJ. Bruce Fields /* case 1: probable callback update */ 28051da177e4SLinus Torvalds copy_clid(new, conf); 280634b232bbSJ. Bruce Fields else /* case 4 (new client) or cases 2, 3 (client reboot): */ 2807c212cecfSStanislav Kinsbursky gen_clid(new, nn); 28088323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 28096f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 2810ac55fdc4SJeff Layton add_to_unconfirmed(new); 28111da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 28121da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 28131da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 28141da177e4SLinus Torvalds status = nfs_ok; 28151da177e4SLinus Torvalds out: 28161da177e4SLinus Torvalds nfs4_unlock_state(); 28171da177e4SLinus Torvalds return status; 28181da177e4SLinus Torvalds } 28191da177e4SLinus Torvalds 28201da177e4SLinus Torvalds 2821b37ad28bSAl Viro __be32 2822b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 2823b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 2824b591480bSJ.Bruce Fields struct nfsd4_setclientid_confirm *setclientid_confirm) 28251da177e4SLinus Torvalds { 282621ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 28271da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 28281da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 2829b37ad28bSAl Viro __be32 status; 28307f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 28311da177e4SLinus Torvalds 28322c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 28331da177e4SLinus Torvalds return nfserr_stale_clientid; 28341da177e4SLinus Torvalds nfs4_lock_state(); 283521ab45a4SNeilBrown 28368daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 28370a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 2838a186e767SJ. Bruce Fields /* 28398695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 28408695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 28418695b90aSJ. Bruce Fields * there's a bug somewhere. Let's charitably assume it's our 28428695b90aSJ. Bruce Fields * bug. 2843a186e767SJ. Bruce Fields */ 28448695b90aSJ. Bruce Fields status = nfserr_serverfault; 28458695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 28468695b90aSJ. Bruce Fields goto out; 28478695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 28488695b90aSJ. Bruce Fields goto out; 284963db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 285090d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 285190d700b7SJ. Bruce Fields if (conf && !unconf) /* case 2: probable retransmit */ 285290d700b7SJ. Bruce Fields status = nfs_ok; 285390d700b7SJ. Bruce Fields else /* case 4: client hasn't noticed we rebooted yet? */ 285490d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 285590d700b7SJ. Bruce Fields goto out; 285690d700b7SJ. Bruce Fields } 285790d700b7SJ. Bruce Fields status = nfs_ok; 285890d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 28595a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 28605a3c9d71SJ. Bruce Fields nfsd4_probe_callback(conf); 28611a69c179SNeilBrown expire_client(unconf); 286290d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 2863382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&unconf->cl_name, nn); 2864221a6876SJ. Bruce Fields if (conf) { 2865221a6876SJ. Bruce Fields status = mark_client_expired(conf); 2866221a6876SJ. Bruce Fields if (status) 2867221a6876SJ. Bruce Fields goto out; 28681a69c179SNeilBrown expire_client(conf); 2869221a6876SJ. Bruce Fields } 28701da177e4SLinus Torvalds move_to_confirmed(unconf); 2871f3d03b92SJ. Bruce Fields nfsd4_probe_callback(unconf); 287208e8987cSNeilBrown } 28731da177e4SLinus Torvalds out: 28741da177e4SLinus Torvalds nfs4_unlock_state(); 28751da177e4SLinus Torvalds return status; 28761da177e4SLinus Torvalds } 28771da177e4SLinus Torvalds 287832513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 28791da177e4SLinus Torvalds { 288032513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 288132513b40SJ. Bruce Fields } 288232513b40SJ. Bruce Fields 288332513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 2884f9c00c3aSJeff Layton static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh) 288532513b40SJ. Bruce Fields { 2886ca943217STrond Myklebust unsigned int hashval = file_hashval(fh); 28871da177e4SLinus Torvalds 2888950e0118STrond Myklebust lockdep_assert_held(&state_lock); 2889950e0118STrond Myklebust 28908b671b80SJ. Bruce Fields atomic_set(&fp->fi_ref, 1); 28911d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 28928beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 28938beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 2894e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 289547f9940cSMeelap Shah fp->fi_had_conflict = false; 2896acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 2897baeb4ff0SJeff Layton fp->fi_share_deny = 0; 2898f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 2899f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 290089876f8cSJeff Layton hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]); 29011da177e4SLinus Torvalds } 29021da177e4SLinus Torvalds 2903e8ff2a84SJ. Bruce Fields void 2904e60d4398SNeilBrown nfsd4_free_slabs(void) 2905e60d4398SNeilBrown { 2906abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 2907abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 2908abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 2909abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 2910abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 2911e60d4398SNeilBrown } 29121da177e4SLinus Torvalds 291372083396SBryan Schumaker int 29141da177e4SLinus Torvalds nfsd4_init_slabs(void) 29151da177e4SLinus Torvalds { 2916fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 2917fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 2918fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 2919abf1135bSChristoph Hellwig goto out; 2920fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 29213c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 2922fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 2923abf1135bSChristoph Hellwig goto out_free_openowner_slab; 2924e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 292520c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 2926e60d4398SNeilBrown if (file_slab == NULL) 2927abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 29285ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 2929dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 29305ac049acSNeilBrown if (stateid_slab == NULL) 2931abf1135bSChristoph Hellwig goto out_free_file_slab; 29325b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 293320c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 29345b2d21c1SNeilBrown if (deleg_slab == NULL) 2935abf1135bSChristoph Hellwig goto out_free_stateid_slab; 2936e60d4398SNeilBrown return 0; 2937abf1135bSChristoph Hellwig 2938abf1135bSChristoph Hellwig out_free_stateid_slab: 2939abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 2940abf1135bSChristoph Hellwig out_free_file_slab: 2941abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 2942abf1135bSChristoph Hellwig out_free_lockowner_slab: 2943abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 2944abf1135bSChristoph Hellwig out_free_openowner_slab: 2945abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 2946abf1135bSChristoph Hellwig out: 29471da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 29481da177e4SLinus Torvalds return -ENOMEM; 29491da177e4SLinus Torvalds } 29501da177e4SLinus Torvalds 2951ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 2952ff194bd9SJ. Bruce Fields { 2953ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 2954ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 2955ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 295658fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 295758fb12e6SJeff Layton } 295858fb12e6SJeff Layton 295958fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 296058fb12e6SJeff Layton struct nfs4_stateowner *so) 296158fb12e6SJeff Layton { 296258fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 296358fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 296458fb12e6SJeff Layton cstate->replay_owner = so; 296558fb12e6SJeff Layton atomic_inc(&so->so_count); 296658fb12e6SJeff Layton } 296758fb12e6SJeff Layton } 296858fb12e6SJeff Layton 296958fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 297058fb12e6SJeff Layton { 297158fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 297258fb12e6SJeff Layton 297358fb12e6SJeff Layton if (so != NULL) { 297458fb12e6SJeff Layton cstate->replay_owner = NULL; 297558fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 297658fb12e6SJeff Layton nfs4_put_stateowner(so); 297758fb12e6SJeff Layton } 2978ff194bd9SJ. Bruce Fields } 2979ff194bd9SJ. Bruce Fields 2980fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 29811da177e4SLinus Torvalds { 29821da177e4SLinus Torvalds struct nfs4_stateowner *sop; 29831da177e4SLinus Torvalds 2984fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 2985ff194bd9SJ. Bruce Fields if (!sop) 2986ff194bd9SJ. Bruce Fields return NULL; 2987ff194bd9SJ. Bruce Fields 2988ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 2989ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 2990fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 2991ff194bd9SJ. Bruce Fields return NULL; 2992ff194bd9SJ. Bruce Fields } 29931da177e4SLinus Torvalds sop->so_owner.len = owner->len; 2994ff194bd9SJ. Bruce Fields 2995ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 2996ff194bd9SJ. Bruce Fields sop->so_client = clp; 2997ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 29986b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 29991da177e4SLinus Torvalds return sop; 30001da177e4SLinus Torvalds } 3001ff194bd9SJ. Bruce Fields 3002fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 3003ff194bd9SJ. Bruce Fields { 30049b531137SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 30059b531137SStanislav Kinsbursky 30069b531137SStanislav Kinsbursky list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); 3007fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 30081da177e4SLinus Torvalds } 30091da177e4SLinus Torvalds 30108f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 30118f4b54c5SJeff Layton { 30128f4b54c5SJeff Layton struct nfs4_openowner *oo = openowner(so); 30138f4b54c5SJeff Layton 30148f4b54c5SJeff Layton unhash_openowner(oo); 30158f4b54c5SJeff Layton } 30168f4b54c5SJeff Layton 30176b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 30186b180f0bSJeff Layton { 30196b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 30206b180f0bSJeff Layton 30216b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 30226b180f0bSJeff Layton } 30236b180f0bSJeff Layton 30246b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 30258f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 30266b180f0bSJeff Layton .so_free = nfs4_free_openowner, 30276b180f0bSJeff Layton }; 30286b180f0bSJeff Layton 3029fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 303013d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 3031db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 3032db24b3b4SJeff Layton { 303313d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 3034fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 30351da177e4SLinus Torvalds 3036fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 3037fe0750e5SJ. Bruce Fields if (!oo) 30381da177e4SLinus Torvalds return NULL; 30396b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 3040fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 3041fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 3042d29b20cdSJ. Bruce Fields oo->oo_flags = NFS4_OO_NEW; 3043db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 3044db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 3045fe0750e5SJ. Bruce Fields oo->oo_time = 0; 304638c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 3047fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 3048fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 3049fe0750e5SJ. Bruce Fields return oo; 30501da177e4SLinus Torvalds } 30511da177e4SLinus Torvalds 3052996e0938SJ. Bruce Fields static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { 3053fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 30541da177e4SLinus Torvalds 3055d6f2bc5dSTrond Myklebust atomic_inc(&stp->st_stid.sc_count); 30563abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 30573c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 3058fe0750e5SJ. Bruce Fields stp->st_stateowner = &oo->oo_owner; 305913cd2184SNeilBrown get_nfs4_file(fp); 306011b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 30611da177e4SLinus Torvalds stp->st_access_bmap = 0; 30621da177e4SLinus Torvalds stp->st_deny_bmap = 0; 30634c4cd222SNeilBrown stp->st_openstp = NULL; 30641c755dc1SJeff Layton spin_lock(&oo->oo_owner.so_client->cl_lock); 30651c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 30661d31a253STrond Myklebust spin_lock(&fp->fi_lock); 30671d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 30681d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 30691c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 30701da177e4SLinus Torvalds } 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds static void 307373758fedSStanislav Kinsbursky move_to_close_lru(struct nfs4_openowner *oo, struct net *net) 30741da177e4SLinus Torvalds { 307573758fedSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 307673758fedSStanislav Kinsbursky 3077fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 30781da177e4SLinus Torvalds 307973758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 3080fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 30811da177e4SLinus Torvalds } 30821da177e4SLinus Torvalds 30831da177e4SLinus Torvalds static int 3084599e0a22SJ. Bruce Fields same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, 3085599e0a22SJ. Bruce Fields clientid_t *clid) 3086599e0a22SJ. Bruce Fields { 3087599e0a22SJ. Bruce Fields return (sop->so_owner.len == owner->len) && 3088599e0a22SJ. Bruce Fields 0 == memcmp(sop->so_owner.data, owner->data, owner->len) && 3089599e0a22SJ. Bruce Fields (sop->so_client->cl_clientid.cl_id == clid->cl_id); 30901da177e4SLinus Torvalds } 30911da177e4SLinus Torvalds 3092fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 30939b531137SStanislav Kinsbursky find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 30949b531137SStanislav Kinsbursky bool sessions, struct nfsd_net *nn) 30951da177e4SLinus Torvalds { 3096a50d2ad1SJ. Bruce Fields struct nfs4_stateowner *so; 3097a50d2ad1SJ. Bruce Fields struct nfs4_openowner *oo; 3098d15c077eSJ. Bruce Fields struct nfs4_client *clp; 30991da177e4SLinus Torvalds 31009b531137SStanislav Kinsbursky list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) { 310116bfdaafSJ. Bruce Fields if (!so->so_is_open_owner) 310216bfdaafSJ. Bruce Fields continue; 3103a50d2ad1SJ. Bruce Fields if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { 3104a50d2ad1SJ. Bruce Fields oo = openowner(so); 3105d15c077eSJ. Bruce Fields clp = oo->oo_owner.so_client; 3106d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 3107d15c077eSJ. Bruce Fields return NULL; 3108a50d2ad1SJ. Bruce Fields renew_client(oo->oo_owner.so_client); 3109a50d2ad1SJ. Bruce Fields return oo; 3110a50d2ad1SJ. Bruce Fields } 31111da177e4SLinus Torvalds } 31121da177e4SLinus Torvalds return NULL; 31131da177e4SLinus Torvalds } 31141da177e4SLinus Torvalds 31151da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 31161da177e4SLinus Torvalds static struct nfs4_file * 3117ca943217STrond Myklebust find_file_locked(struct knfsd_fh *fh) 31181da177e4SLinus Torvalds { 3119ca943217STrond Myklebust unsigned int hashval = file_hashval(fh); 31201da177e4SLinus Torvalds struct nfs4_file *fp; 31211da177e4SLinus Torvalds 3122950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3123950e0118STrond Myklebust 312489876f8cSJeff Layton hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { 3125ca943217STrond Myklebust if (nfsd_fh_match(&fp->fi_fhandle, fh)) { 312613cd2184SNeilBrown get_nfs4_file(fp); 31271da177e4SLinus Torvalds return fp; 31281da177e4SLinus Torvalds } 312913cd2184SNeilBrown } 31301da177e4SLinus Torvalds return NULL; 31311da177e4SLinus Torvalds } 31321da177e4SLinus Torvalds 3133950e0118STrond Myklebust static struct nfs4_file * 3134ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 3135950e0118STrond Myklebust { 3136950e0118STrond Myklebust struct nfs4_file *fp; 3137950e0118STrond Myklebust 3138950e0118STrond Myklebust spin_lock(&state_lock); 3139ca943217STrond Myklebust fp = find_file_locked(fh); 3140950e0118STrond Myklebust spin_unlock(&state_lock); 3141950e0118STrond Myklebust return fp; 3142950e0118STrond Myklebust } 3143950e0118STrond Myklebust 3144950e0118STrond Myklebust static struct nfs4_file * 3145f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 3146950e0118STrond Myklebust { 3147950e0118STrond Myklebust struct nfs4_file *fp; 3148950e0118STrond Myklebust 3149950e0118STrond Myklebust spin_lock(&state_lock); 3150ca943217STrond Myklebust fp = find_file_locked(fh); 3151950e0118STrond Myklebust if (fp == NULL) { 3152f9c00c3aSJeff Layton nfsd4_init_file(new, fh); 3153950e0118STrond Myklebust fp = new; 3154950e0118STrond Myklebust } 3155950e0118STrond Myklebust spin_unlock(&state_lock); 3156950e0118STrond Myklebust 3157950e0118STrond Myklebust return fp; 3158950e0118STrond Myklebust } 3159950e0118STrond Myklebust 31604f83aa30SJ. Bruce Fields /* 31611da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 31621da177e4SLinus Torvalds * WRITE with all zero or all one stateid 31631da177e4SLinus Torvalds */ 3164b37ad28bSAl Viro static __be32 31651da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 31661da177e4SLinus Torvalds { 31671da177e4SLinus Torvalds struct nfs4_file *fp; 3168baeb4ff0SJeff Layton __be32 ret = nfs_ok; 31691da177e4SLinus Torvalds 3170ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 317113cd2184SNeilBrown if (!fp) 3172baeb4ff0SJeff Layton return ret; 3173baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 31741d31a253STrond Myklebust spin_lock(&fp->fi_lock); 3175baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 3176baeb4ff0SJeff Layton ret = nfserr_locked; 31771d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 317813cd2184SNeilBrown put_nfs4_file(fp); 317913cd2184SNeilBrown return ret; 31801da177e4SLinus Torvalds } 31811da177e4SLinus Torvalds 318202e1215fSJeff Layton void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) 31831da177e4SLinus Torvalds { 318411b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 318511b9164aSTrond Myklebust nfsd_net_id); 3186e8c69d17SJ. Bruce Fields 318711b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 3188f54fe962SJeff Layton 318902e1215fSJeff Layton /* 319002e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 3191f54fe962SJeff Layton * already holding inode->i_lock. 3192f54fe962SJeff Layton * 3193dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 3194dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 3195dff1399fSJeff Layton */ 3196f54fe962SJeff Layton spin_lock(&state_lock); 3197dff1399fSJeff Layton if (dp->dl_time == 0) { 31981da177e4SLinus Torvalds dp->dl_time = get_seconds(); 319902e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 320002e1215fSJeff Layton } 320102e1215fSJeff Layton spin_unlock(&state_lock); 3202dff1399fSJeff Layton } 32031da177e4SLinus Torvalds 320402e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 320502e1215fSJeff Layton { 320602e1215fSJeff Layton /* 320702e1215fSJeff Layton * We're assuming the state code never drops its reference 320802e1215fSJeff Layton * without first removing the lease. Since we're in this lease 320902e1215fSJeff Layton * callback (and since the lease code is serialized by the kernel 321002e1215fSJeff Layton * lock) we know the server hasn't removed the lease yet, we know 321102e1215fSJeff Layton * it's safe to take a reference. 321202e1215fSJeff Layton */ 321372c0b0fbSTrond Myklebust atomic_inc(&dp->dl_stid.sc_count); 32146b57d9c8SJ. Bruce Fields nfsd4_cb_recall(dp); 32156b57d9c8SJ. Bruce Fields } 32166b57d9c8SJ. Bruce Fields 32171c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 32186b57d9c8SJ. Bruce Fields static void nfsd_break_deleg_cb(struct file_lock *fl) 32196b57d9c8SJ. Bruce Fields { 3220acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 3221acfdf5c3SJ. Bruce Fields struct nfs4_delegation *dp; 32226b57d9c8SJ. Bruce Fields 32237fa10cd1SJ. Bruce Fields if (!fp) { 32247fa10cd1SJ. Bruce Fields WARN(1, "(%p)->fl_owner NULL\n", fl); 32257fa10cd1SJ. Bruce Fields return; 32267fa10cd1SJ. Bruce Fields } 32277fa10cd1SJ. Bruce Fields if (fp->fi_had_conflict) { 32287fa10cd1SJ. Bruce Fields WARN(1, "duplicate break on %p\n", fp); 32297fa10cd1SJ. Bruce Fields return; 32307fa10cd1SJ. Bruce Fields } 32310272e1fdSJ. Bruce Fields /* 32320272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 3233acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 32346b57d9c8SJ. Bruce Fields * in time: 32350272e1fdSJ. Bruce Fields */ 32360272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 32371da177e4SLinus Torvalds 323802e1215fSJeff Layton spin_lock(&fp->fi_lock); 3239417c6629SJeff Layton fp->fi_had_conflict = true; 3240417c6629SJeff Layton /* 3241417c6629SJeff Layton * If there are no delegations on the list, then we can't count on this 3242417c6629SJeff Layton * lease ever being cleaned up. Set the fl_break_time to jiffies so that 3243417c6629SJeff Layton * time_out_leases will do it ASAP. The fact that fi_had_conflict is now 3244417c6629SJeff Layton * true should keep any new delegations from being hashed. 3245417c6629SJeff Layton */ 3246417c6629SJeff Layton if (list_empty(&fp->fi_delegations)) 3247417c6629SJeff Layton fl->fl_break_time = jiffies; 3248417c6629SJeff Layton else 3249acfdf5c3SJ. Bruce Fields list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 32505d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 325102e1215fSJeff Layton spin_unlock(&fp->fi_lock); 32521da177e4SLinus Torvalds } 32531da177e4SLinus Torvalds 32541da177e4SLinus Torvalds static 32551da177e4SLinus Torvalds int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) 32561da177e4SLinus Torvalds { 32571da177e4SLinus Torvalds if (arg & F_UNLCK) 32581da177e4SLinus Torvalds return lease_modify(onlist, arg); 32591da177e4SLinus Torvalds else 32601da177e4SLinus Torvalds return -EAGAIN; 32611da177e4SLinus Torvalds } 32621da177e4SLinus Torvalds 32637b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 32648fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 32658fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 32661da177e4SLinus Torvalds }; 32671da177e4SLinus Torvalds 32687a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 32697a8711c9SJ. Bruce Fields { 32707a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 32717a8711c9SJ. Bruce Fields return nfs_ok; 32727a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 32737a8711c9SJ. Bruce Fields return nfserr_replay_me; 32747a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 32757a8711c9SJ. Bruce Fields return nfs_ok; 32767a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 32777a8711c9SJ. Bruce Fields } 32781da177e4SLinus Torvalds 32794b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 32804b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 32814b24ca7dSJeff Layton struct nfsd_net *nn) 32824b24ca7dSJeff Layton { 32834b24ca7dSJeff Layton struct nfs4_client *found; 32844b24ca7dSJeff Layton 32854b24ca7dSJeff Layton if (cstate->clp) { 32864b24ca7dSJeff Layton found = cstate->clp; 32874b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 32884b24ca7dSJeff Layton return nfserr_stale_clientid; 32894b24ca7dSJeff Layton return nfs_ok; 32904b24ca7dSJeff Layton } 32914b24ca7dSJeff Layton 32924b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 32934b24ca7dSJeff Layton return nfserr_stale_clientid; 32944b24ca7dSJeff Layton 32954b24ca7dSJeff Layton /* 32964b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 32974b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 32984b24ca7dSJeff Layton * will be false. 32994b24ca7dSJeff Layton */ 33004b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 33014b24ca7dSJeff Layton found = find_confirmed_client(clid, false, nn); 33024b24ca7dSJeff Layton if (!found) 33034b24ca7dSJeff Layton return nfserr_expired; 33044b24ca7dSJeff Layton 33054b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 33064b24ca7dSJeff Layton cstate->clp = found; 33074b24ca7dSJeff Layton atomic_inc(&found->cl_refcount); 33084b24ca7dSJeff Layton return nfs_ok; 33094b24ca7dSJeff Layton } 33104b24ca7dSJeff Layton 3311b37ad28bSAl Viro __be32 33126668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 33133320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 33141da177e4SLinus Torvalds { 33151da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 33161da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 33171da177e4SLinus Torvalds unsigned int strhashval; 3318fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 33194cdc951bSJ. Bruce Fields __be32 status; 33201da177e4SLinus Torvalds 33212c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 33221da177e4SLinus Torvalds return nfserr_stale_clientid; 332332513b40SJ. Bruce Fields /* 332432513b40SJ. Bruce Fields * In case we need it later, after we've already created the 332532513b40SJ. Bruce Fields * file and don't want to risk a further failure: 332632513b40SJ. Bruce Fields */ 332732513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 332832513b40SJ. Bruce Fields if (open->op_file == NULL) 332932513b40SJ. Bruce Fields return nfserr_jukebox; 33301da177e4SLinus Torvalds 333113d6f66bSTrond Myklebust status = lookup_clientid(clientid, cstate, nn); 333213d6f66bSTrond Myklebust if (status) 333313d6f66bSTrond Myklebust return status; 333413d6f66bSTrond Myklebust clp = cstate->clp; 33352d91e895STrond Myklebust 33362d91e895STrond Myklebust strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); 33372d91e895STrond Myklebust oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn); 33382d91e895STrond Myklebust open->op_openowner = oo; 33392d91e895STrond Myklebust if (!oo) { 3340bcf130f9SJ. Bruce Fields goto new_owner; 33410f442aa2SJ. Bruce Fields } 3342dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 33430f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 3344fe0750e5SJ. Bruce Fields release_openowner(oo); 3345fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 3346bcf130f9SJ. Bruce Fields goto new_owner; 33470f442aa2SJ. Bruce Fields } 33484cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 33494cdc951bSJ. Bruce Fields if (status) 33504cdc951bSJ. Bruce Fields return status; 33514cdc951bSJ. Bruce Fields goto alloc_stateid; 3352bcf130f9SJ. Bruce Fields new_owner: 335313d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 3354fe0750e5SJ. Bruce Fields if (oo == NULL) 33553e772463SJ. Bruce Fields return nfserr_jukebox; 3356fe0750e5SJ. Bruce Fields open->op_openowner = oo; 33574cdc951bSJ. Bruce Fields alloc_stateid: 3358b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 33594cdc951bSJ. Bruce Fields if (!open->op_stp) 33604cdc951bSJ. Bruce Fields return nfserr_jukebox; 33610f442aa2SJ. Bruce Fields return nfs_ok; 33621da177e4SLinus Torvalds } 33631da177e4SLinus Torvalds 3364b37ad28bSAl Viro static inline __be32 33654a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 33664a6e43e6SNeilBrown { 33674a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 33684a6e43e6SNeilBrown return nfserr_openmode; 33694a6e43e6SNeilBrown else 33704a6e43e6SNeilBrown return nfs_ok; 33714a6e43e6SNeilBrown } 33724a6e43e6SNeilBrown 3373c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 337424a0111eSJ. Bruce Fields { 337524a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 337624a0111eSJ. Bruce Fields } 337724a0111eSJ. Bruce Fields 337838c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 3379f459e453SJ. Bruce Fields { 3380f459e453SJ. Bruce Fields struct nfs4_stid *ret; 3381f459e453SJ. Bruce Fields 338238c2f4b1SJ. Bruce Fields ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); 3383f459e453SJ. Bruce Fields if (!ret) 3384f459e453SJ. Bruce Fields return NULL; 3385f459e453SJ. Bruce Fields return delegstateid(ret); 3386f459e453SJ. Bruce Fields } 3387f459e453SJ. Bruce Fields 33888b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 33898b289b2cSJ. Bruce Fields { 33908b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 33918b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 33928b289b2cSJ. Bruce Fields } 33938b289b2cSJ. Bruce Fields 3394b37ad28bSAl Viro static __be32 339541d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 3396567d9829SNeilBrown struct nfs4_delegation **dp) 3397567d9829SNeilBrown { 3398567d9829SNeilBrown int flags; 3399b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 3400dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 3401567d9829SNeilBrown 3402dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 3403dcd94cc2STrond Myklebust if (deleg == NULL) 3404c44c5eebSNeilBrown goto out; 340524a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 3406dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 3407dcd94cc2STrond Myklebust if (status) { 3408dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 3409dcd94cc2STrond Myklebust goto out; 3410dcd94cc2STrond Myklebust } 3411dcd94cc2STrond Myklebust *dp = deleg; 3412c44c5eebSNeilBrown out: 34138b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 3414c44c5eebSNeilBrown return nfs_ok; 3415c44c5eebSNeilBrown if (status) 3416c44c5eebSNeilBrown return status; 3417dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 3418c44c5eebSNeilBrown return nfs_ok; 3419567d9829SNeilBrown } 3420567d9829SNeilBrown 3421a46cb7f2SJeff Layton static struct nfs4_ol_stateid * 3422a46cb7f2SJeff Layton nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 34231da177e4SLinus Torvalds { 3424a46cb7f2SJeff Layton struct nfs4_ol_stateid *local, *ret = NULL; 3425fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 34261da177e4SLinus Torvalds 34271d31a253STrond Myklebust spin_lock(&fp->fi_lock); 34288beefa24SNeilBrown list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 34291da177e4SLinus Torvalds /* ignore lock owners */ 34301da177e4SLinus Torvalds if (local->st_stateowner->so_is_open_owner == 0) 34311da177e4SLinus Torvalds continue; 3432baeb4ff0SJeff Layton if (local->st_stateowner == &oo->oo_owner) { 3433a46cb7f2SJeff Layton ret = local; 3434d6f2bc5dSTrond Myklebust atomic_inc(&ret->st_stid.sc_count); 3435baeb4ff0SJeff Layton break; 34361da177e4SLinus Torvalds } 34371d31a253STrond Myklebust } 34381d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 3439a46cb7f2SJeff Layton return ret; 34401da177e4SLinus Torvalds } 34411da177e4SLinus Torvalds 344221fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 344321fb4016SJ. Bruce Fields { 344421fb4016SJ. Bruce Fields int flags = 0; 344521fb4016SJ. Bruce Fields 344621fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 344721fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 344821fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 344921fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 345021fb4016SJ. Bruce Fields return flags; 345121fb4016SJ. Bruce Fields } 345221fb4016SJ. Bruce Fields 3453b37ad28bSAl Viro static inline __be32 34541da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 34551da177e4SLinus Torvalds struct nfsd4_open *open) 34561da177e4SLinus Torvalds { 34571da177e4SLinus Torvalds struct iattr iattr = { 34581da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 34591da177e4SLinus Torvalds .ia_size = 0, 34601da177e4SLinus Torvalds }; 34611da177e4SLinus Torvalds if (!open->op_truncate) 34621da177e4SLinus Torvalds return 0; 34631da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 34649246585aSAl Viro return nfserr_inval; 34651da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 34661da177e4SLinus Torvalds } 34671da177e4SLinus Torvalds 34687e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 34696eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 34706eb3a1d0SJeff Layton struct nfsd4_open *open) 34717e6a72e5SChristoph Hellwig { 3472de18643dSTrond Myklebust struct file *filp = NULL; 34737e6a72e5SChristoph Hellwig __be32 status; 34747e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 34757e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 3476baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 34777e6a72e5SChristoph Hellwig 3478de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3479baeb4ff0SJeff Layton 3480baeb4ff0SJeff Layton /* 3481baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 3482baeb4ff0SJeff Layton * current access? 3483baeb4ff0SJeff Layton */ 3484baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 3485baeb4ff0SJeff Layton if (status != nfs_ok) { 3486baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3487baeb4ff0SJeff Layton goto out; 3488baeb4ff0SJeff Layton } 3489baeb4ff0SJeff Layton 3490baeb4ff0SJeff Layton /* set access to the file */ 3491baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 3492baeb4ff0SJeff Layton if (status != nfs_ok) { 3493baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 3494baeb4ff0SJeff Layton goto out; 3495baeb4ff0SJeff Layton } 3496baeb4ff0SJeff Layton 3497baeb4ff0SJeff Layton /* Set access bits in stateid */ 3498baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 3499baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 3500baeb4ff0SJeff Layton 3501baeb4ff0SJeff Layton /* Set new deny mask */ 3502baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 3503baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 3504baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 3505baeb4ff0SJeff Layton 35067e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 3507de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3508de18643dSTrond Myklebust status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); 35097e6a72e5SChristoph Hellwig if (status) 3510baeb4ff0SJeff Layton goto out_put_access; 3511de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 3512de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 3513de18643dSTrond Myklebust fp->fi_fds[oflag] = filp; 3514de18643dSTrond Myklebust filp = NULL; 3515de18643dSTrond Myklebust } 35167e6a72e5SChristoph Hellwig } 3517de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 3518de18643dSTrond Myklebust if (filp) 3519de18643dSTrond Myklebust fput(filp); 35207e6a72e5SChristoph Hellwig 35217e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 35227e6a72e5SChristoph Hellwig if (status) 35237e6a72e5SChristoph Hellwig goto out_put_access; 35247e6a72e5SChristoph Hellwig out: 35257e6a72e5SChristoph Hellwig return status; 3526baeb4ff0SJeff Layton out_put_access: 3527baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 3528baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 3529baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 3530baeb4ff0SJeff Layton goto out; 35317e6a72e5SChristoph Hellwig } 35327e6a72e5SChristoph Hellwig 3533b37ad28bSAl Viro static __be32 3534dcef0413SJ. 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) 35351da177e4SLinus Torvalds { 3536b37ad28bSAl Viro __be32 status; 3537baeb4ff0SJeff Layton unsigned char old_deny_bmap; 35381da177e4SLinus Torvalds 35396eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 3540baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 35417e6a72e5SChristoph Hellwig 3542baeb4ff0SJeff Layton /* test and set deny mode */ 3543baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 3544baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 3545baeb4ff0SJeff Layton if (status == nfs_ok) { 3546baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 3547baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 3548baeb4ff0SJeff Layton fp->fi_share_deny |= 3549baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 35501da177e4SLinus Torvalds } 3551baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 35521da177e4SLinus Torvalds 3553baeb4ff0SJeff Layton if (status != nfs_ok) 3554baeb4ff0SJeff Layton return status; 3555baeb4ff0SJeff Layton 3556baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 3557baeb4ff0SJeff Layton if (status != nfs_ok) 3558baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 3559baeb4ff0SJeff Layton return status; 3560baeb4ff0SJeff Layton } 35611da177e4SLinus Torvalds 35621da177e4SLinus Torvalds static void 35631255a8f3SJ. Bruce Fields nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session) 35641da177e4SLinus Torvalds { 3565dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 35661da177e4SLinus Torvalds } 35671da177e4SLinus Torvalds 356814a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 356914a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 357014a24e99SJ. Bruce Fields { 357114a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 357214a24e99SJ. Bruce Fields return true; 357314a24e99SJ. Bruce Fields /* 357414a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 357514a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 357614a24e99SJ. Bruce Fields * until we hear otherwise: 357714a24e99SJ. Bruce Fields */ 357814a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 357914a24e99SJ. Bruce Fields } 358014a24e99SJ. Bruce Fields 3581d564fbecSJeff Layton static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag) 358222d38c4cSJ. Bruce Fields { 358322d38c4cSJ. Bruce Fields struct file_lock *fl; 358422d38c4cSJ. Bruce Fields 358522d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 358622d38c4cSJ. Bruce Fields if (!fl) 358722d38c4cSJ. Bruce Fields return NULL; 358822d38c4cSJ. Bruce Fields locks_init_lock(fl); 358922d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 3590617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 359122d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 359222d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 3593d564fbecSJeff Layton fl->fl_owner = (fl_owner_t)fp; 359422d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 359522d38c4cSJ. Bruce Fields return fl; 359622d38c4cSJ. Bruce Fields } 359722d38c4cSJ. Bruce Fields 359899c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp) 3599edab9782SJ. Bruce Fields { 360011b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 3601edab9782SJ. Bruce Fields struct file_lock *fl; 3602417c6629SJeff Layton struct file *filp; 3603417c6629SJeff Layton int status = 0; 3604edab9782SJ. Bruce Fields 3605d564fbecSJeff Layton fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ); 3606edab9782SJ. Bruce Fields if (!fl) 3607edab9782SJ. Bruce Fields return -ENOMEM; 3608417c6629SJeff Layton filp = find_readable_file(fp); 3609417c6629SJeff Layton if (!filp) { 3610417c6629SJeff Layton /* We should always have a readable file here */ 3611417c6629SJeff Layton WARN_ON_ONCE(1); 3612417c6629SJeff Layton return -EBADF; 3613417c6629SJeff Layton } 3614417c6629SJeff Layton fl->fl_file = filp; 3615417c6629SJeff Layton status = vfs_setlease(filp, fl->fl_type, &fl); 3616417c6629SJeff Layton if (status) { 3617417c6629SJeff Layton locks_free_lock(fl); 3618417c6629SJeff Layton goto out_fput; 3619417c6629SJeff Layton } 3620cdc97505SBenny Halevy spin_lock(&state_lock); 3621417c6629SJeff Layton spin_lock(&fp->fi_lock); 3622417c6629SJeff Layton /* Did the lease get broken before we took the lock? */ 3623417c6629SJeff Layton status = -EAGAIN; 3624417c6629SJeff Layton if (fp->fi_had_conflict) 3625417c6629SJeff Layton goto out_unlock; 3626417c6629SJeff Layton /* Race breaker */ 3627417c6629SJeff Layton if (fp->fi_lease) { 3628417c6629SJeff Layton status = 0; 3629417c6629SJeff Layton atomic_inc(&fp->fi_delegees); 3630931ee56cSBenny Halevy hash_delegation_locked(dp, fp); 3631417c6629SJeff Layton goto out_unlock; 3632417c6629SJeff Layton } 3633417c6629SJeff Layton fp->fi_lease = fl; 3634417c6629SJeff Layton fp->fi_deleg_file = filp; 3635417c6629SJeff Layton atomic_set(&fp->fi_delegees, 1); 3636417c6629SJeff Layton hash_delegation_locked(dp, fp); 3637417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3638cdc97505SBenny Halevy spin_unlock(&state_lock); 3639acfdf5c3SJ. Bruce Fields return 0; 3640417c6629SJeff Layton out_unlock: 3641417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3642417c6629SJeff Layton spin_unlock(&state_lock); 3643417c6629SJeff Layton out_fput: 3644417c6629SJeff Layton fput(filp); 3645e873088fSJ. Bruce Fields return status; 3646acfdf5c3SJ. Bruce Fields } 3647acfdf5c3SJ. Bruce Fields 36480b26693cSJeff Layton static struct nfs4_delegation * 36490b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 36500b26693cSJeff Layton struct nfs4_file *fp) 3651acfdf5c3SJ. Bruce Fields { 36520b26693cSJeff Layton int status; 36530b26693cSJeff Layton struct nfs4_delegation *dp; 3654417c6629SJeff Layton 3655bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 36560b26693cSJeff Layton return ERR_PTR(-EAGAIN); 36570b26693cSJeff Layton 36580b26693cSJeff Layton dp = alloc_init_deleg(clp, fh); 36590b26693cSJeff Layton if (!dp) 36600b26693cSJeff Layton return ERR_PTR(-ENOMEM); 36610b26693cSJeff Layton 3662bf7bd3e9SJ. Bruce Fields get_nfs4_file(fp); 3663cdc97505SBenny Halevy spin_lock(&state_lock); 3664417c6629SJeff Layton spin_lock(&fp->fi_lock); 366511b9164aSTrond Myklebust dp->dl_stid.sc_file = fp; 3666417c6629SJeff Layton if (!fp->fi_lease) { 3667417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3668417c6629SJeff Layton spin_unlock(&state_lock); 36690b26693cSJeff Layton status = nfs4_setlease(dp); 36700b26693cSJeff Layton goto out; 3671417c6629SJeff Layton } 3672cbf7a75bSJ. Bruce Fields atomic_inc(&fp->fi_delegees); 3673acfdf5c3SJ. Bruce Fields if (fp->fi_had_conflict) { 3674417c6629SJeff Layton status = -EAGAIN; 3675417c6629SJeff Layton goto out_unlock; 3676acfdf5c3SJ. Bruce Fields } 3677931ee56cSBenny Halevy hash_delegation_locked(dp, fp); 36780b26693cSJeff Layton status = 0; 3679417c6629SJeff Layton out_unlock: 3680417c6629SJeff Layton spin_unlock(&fp->fi_lock); 3681cdc97505SBenny Halevy spin_unlock(&state_lock); 36820b26693cSJeff Layton out: 36830b26693cSJeff Layton if (status) { 36846011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 36850b26693cSJeff Layton return ERR_PTR(status); 36860b26693cSJeff Layton } 36870b26693cSJeff Layton return dp; 3688edab9782SJ. Bruce Fields } 3689edab9782SJ. Bruce Fields 36904aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 36914aa8913cSBenny Halevy { 36924aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 36934aa8913cSBenny Halevy if (status == -EAGAIN) 36944aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 36954aa8913cSBenny Halevy else { 36964aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 36974aa8913cSBenny Halevy switch (open->op_deleg_want) { 36984aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 36994aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 37004aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 37014aa8913cSBenny Halevy break; 37024aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 37034aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 37044aa8913cSBenny Halevy break; 37054aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 3706063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 37074aa8913cSBenny Halevy } 37084aa8913cSBenny Halevy } 37094aa8913cSBenny Halevy } 37104aa8913cSBenny Halevy 37111da177e4SLinus Torvalds /* 37121da177e4SLinus Torvalds * Attempt to hand out a delegation. 371399c41515SJ. Bruce Fields * 371499c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 371599c41515SJ. Bruce Fields * proper support for them. 37161da177e4SLinus Torvalds */ 37171da177e4SLinus Torvalds static void 37184cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 37194cf59221SJeff Layton struct nfs4_ol_stateid *stp) 37201da177e4SLinus Torvalds { 37211da177e4SLinus Torvalds struct nfs4_delegation *dp; 37224cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 37234cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 372414a24e99SJ. Bruce Fields int cb_up; 372599c41515SJ. Bruce Fields int status = 0; 37261da177e4SLinus Torvalds 3727fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 37287b190fecSNeilBrown open->op_recall = 0; 37297b190fecSNeilBrown switch (open->op_claim_type) { 37307b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 37312bf23875SJ. Bruce Fields if (!cb_up) 37327b190fecSNeilBrown open->op_recall = 1; 373399c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 373499c41515SJ. Bruce Fields goto out_no_deleg; 37357b190fecSNeilBrown break; 37367b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 3737ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 373899c41515SJ. Bruce Fields /* 373999c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 374099c41515SJ. Bruce Fields * had the chance to reclaim theirs.... 374199c41515SJ. Bruce Fields */ 37424cf59221SJeff Layton if (locks_in_grace(clp->net)) 374399c41515SJ. Bruce Fields goto out_no_deleg; 3744dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 374599c41515SJ. Bruce Fields goto out_no_deleg; 37469a0590aeSSteve Dickson /* 37479a0590aeSSteve Dickson * Also, if the file was opened for write or 37489a0590aeSSteve Dickson * create, there's a good chance the client's 37499a0590aeSSteve Dickson * about to write to it, resulting in an 37509a0590aeSSteve Dickson * immediate recall (since we don't support 37519a0590aeSSteve Dickson * write delegations): 37529a0590aeSSteve Dickson */ 37531da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 375499c41515SJ. Bruce Fields goto out_no_deleg; 375599c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 375699c41515SJ. Bruce Fields goto out_no_deleg; 37577b190fecSNeilBrown break; 37587b190fecSNeilBrown default: 375999c41515SJ. Bruce Fields goto out_no_deleg; 37607b190fecSNeilBrown } 376111b9164aSTrond Myklebust dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file); 37620b26693cSJeff Layton if (IS_ERR(dp)) 3763dd239cc0SJ. Bruce Fields goto out_no_deleg; 37641da177e4SLinus Torvalds 3765d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 37661da177e4SLinus Torvalds 37678c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 3768d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 376999c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 377067cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 3771dd239cc0SJ. Bruce Fields return; 3772dd239cc0SJ. Bruce Fields out_no_deleg: 377399c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 37747b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 3775d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 37761da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 3777d08d32e6SJ. Bruce Fields open->op_recall = 1; 3778d08d32e6SJ. Bruce Fields } 3779dd239cc0SJ. Bruce Fields 3780dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 3781dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 3782dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 3783dd239cc0SJ. Bruce Fields return; 37841da177e4SLinus Torvalds } 37851da177e4SLinus Torvalds 3786e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 3787e27f49c3SBenny Halevy struct nfs4_delegation *dp) 3788e27f49c3SBenny Halevy { 3789e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 3790e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 3791e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3792e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 3793e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 3794e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 3795e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3796e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 3797e27f49c3SBenny Halevy } 3798e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 3799e27f49c3SBenny Halevy * it already has, therefore we don't return 3800e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 3801e27f49c3SBenny Halevy */ 3802e27f49c3SBenny Halevy } 3803e27f49c3SBenny Halevy 38041da177e4SLinus Torvalds /* 38051da177e4SLinus Torvalds * called with nfs4_lock_state() held. 38061da177e4SLinus Torvalds */ 3807b37ad28bSAl Viro __be32 38081da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 38091da177e4SLinus Torvalds { 38106668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 381138c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 38121da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 3813dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 3814567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 3815b37ad28bSAl Viro __be32 status; 38161da177e4SLinus Torvalds 38171da177e4SLinus Torvalds /* 38181da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 38191da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 38201da177e4SLinus Torvalds * If not found, create the nfs4_file struct 38211da177e4SLinus Torvalds */ 3822f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 3823950e0118STrond Myklebust if (fp != open->op_file) { 382441d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 3825c44c5eebSNeilBrown if (status) 3826c44c5eebSNeilBrown goto out; 3827a46cb7f2SJeff Layton stp = nfsd4_find_existing_open(fp, open); 38281da177e4SLinus Torvalds } else { 3829950e0118STrond Myklebust open->op_file = NULL; 3830c44c5eebSNeilBrown status = nfserr_bad_stateid; 38318b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 3832c44c5eebSNeilBrown goto out; 38333e772463SJ. Bruce Fields status = nfserr_jukebox; 38341da177e4SLinus Torvalds } 38351da177e4SLinus Torvalds 38361da177e4SLinus Torvalds /* 38371da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 38381da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 38391da177e4SLinus Torvalds */ 38401da177e4SLinus Torvalds if (stp) { 38411da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 3842f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 38431da177e4SLinus Torvalds if (status) 38441da177e4SLinus Torvalds goto out; 38451da177e4SLinus Torvalds } else { 38464cdc951bSJ. Bruce Fields stp = open->op_stp; 38474cdc951bSJ. Bruce Fields open->op_stp = NULL; 3848996e0938SJ. Bruce Fields init_open_stateid(stp, fp, open); 38496eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 38506eb3a1d0SJeff Layton if (status) { 38516eb3a1d0SJeff Layton release_open_stateid(stp); 38526eb3a1d0SJeff Layton goto out; 38536eb3a1d0SJeff Layton } 38541da177e4SLinus Torvalds } 3855dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 3856dcef0413SJ. Bruce Fields memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 38571da177e4SLinus Torvalds 3858d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 3859d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 3860d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3861d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 3862d24433cdSBenny Halevy goto nodeleg; 3863d24433cdSBenny Halevy } 3864d24433cdSBenny Halevy } 3865d24433cdSBenny Halevy 38661da177e4SLinus Torvalds /* 38671da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 38681da177e4SLinus Torvalds * OPEN succeeds even if we fail. 38691da177e4SLinus Torvalds */ 38704cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 3871d24433cdSBenny Halevy nodeleg: 38721da177e4SLinus Torvalds status = nfs_ok; 38731da177e4SLinus Torvalds 38748c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 3875dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 38761da177e4SLinus Torvalds out: 3877d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 3878d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 3879e27f49c3SBenny Halevy open->op_deleg_want) 3880e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 3881d24433cdSBenny Halevy 388213cd2184SNeilBrown if (fp) 388313cd2184SNeilBrown put_nfs4_file(fp); 388437515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 38851255a8f3SJ. Bruce Fields nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate)); 38861da177e4SLinus Torvalds /* 38871da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 38881da177e4SLinus Torvalds */ 38891da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 3890dad1c067SJ. Bruce Fields if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) && 38916668958fSAndy Adamson !nfsd4_has_session(&resp->cstate)) 38921da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 3893dcd94cc2STrond Myklebust if (dp) 3894dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 3895d6f2bc5dSTrond Myklebust if (stp) 3896d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 38971da177e4SLinus Torvalds 38981da177e4SLinus Torvalds return status; 38991da177e4SLinus Torvalds } 39001da177e4SLinus Torvalds 390158fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 390258fb12e6SJeff Layton struct nfsd4_open *open, __be32 status) 3903d29b20cdSJ. Bruce Fields { 3904d29b20cdSJ. Bruce Fields if (open->op_openowner) { 3905d29b20cdSJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 3906d29b20cdSJ. Bruce Fields 3907d29b20cdSJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 3908d29b20cdSJ. Bruce Fields list_del_init(&oo->oo_close_lru); 3909d29b20cdSJ. Bruce Fields if (oo->oo_flags & NFS4_OO_NEW) { 3910d29b20cdSJ. Bruce Fields if (status) { 3911d29b20cdSJ. Bruce Fields release_openowner(oo); 3912d29b20cdSJ. Bruce Fields open->op_openowner = NULL; 3913d29b20cdSJ. Bruce Fields } else 3914d29b20cdSJ. Bruce Fields oo->oo_flags &= ~NFS4_OO_NEW; 3915d29b20cdSJ. Bruce Fields } 391658fb12e6SJeff Layton if (open->op_openowner) 391758fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, &oo->oo_owner); 3918d29b20cdSJ. Bruce Fields } 391932513b40SJ. Bruce Fields if (open->op_file) 392032513b40SJ. Bruce Fields nfsd4_free_file(open->op_file); 39214cdc951bSJ. Bruce Fields if (open->op_stp) 39226011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 3923d29b20cdSJ. Bruce Fields } 3924d29b20cdSJ. Bruce Fields 3925b37ad28bSAl Viro __be32 3926b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3927b591480bSJ.Bruce Fields clientid_t *clid) 39281da177e4SLinus Torvalds { 39291da177e4SLinus Torvalds struct nfs4_client *clp; 3930b37ad28bSAl Viro __be32 status; 39317f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 39321da177e4SLinus Torvalds 39331da177e4SLinus Torvalds nfs4_lock_state(); 39341da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 39351da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 39364b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 39379b2ef62bSJ. Bruce Fields if (status) 39381da177e4SLinus Torvalds goto out; 39394b24ca7dSJeff Layton clp = cstate->clp; 39401da177e4SLinus Torvalds status = nfserr_cb_path_down; 3941ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 394277a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 39431da177e4SLinus Torvalds goto out; 39441da177e4SLinus Torvalds status = nfs_ok; 39451da177e4SLinus Torvalds out: 39461da177e4SLinus Torvalds nfs4_unlock_state(); 39471da177e4SLinus Torvalds return status; 39481da177e4SLinus Torvalds } 39491da177e4SLinus Torvalds 3950a76b4319SNeilBrown static void 395112760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 3952a76b4319SNeilBrown { 395333dcc481SJeff Layton /* do nothing if grace period already ended */ 3954a51c84edSStanislav Kinsbursky if (nn->grace_ended) 395533dcc481SJeff Layton return; 395633dcc481SJeff Layton 3957a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 3958a51c84edSStanislav Kinsbursky nn->grace_ended = true; 395912760c66SStanislav Kinsbursky nfsd4_record_grace_done(nn, nn->boot_time); 39605e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 3961e46b498cSJ. Bruce Fields /* 3962e46b498cSJ. Bruce Fields * Now that every NFSv4 client has had the chance to recover and 3963e46b498cSJ. Bruce Fields * to see the (possibly new, possibly shorter) lease time, we 3964e46b498cSJ. Bruce Fields * can safely set the next grace time to the current lease time: 3965e46b498cSJ. Bruce Fields */ 39665284b44eSStanislav Kinsbursky nn->nfsd4_grace = nn->nfsd4_lease; 3967a76b4319SNeilBrown } 3968a76b4319SNeilBrown 3969fd39ca9aSNeilBrown static time_t 397009121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 39711da177e4SLinus Torvalds { 39721da177e4SLinus Torvalds struct nfs4_client *clp; 3973fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 39741da177e4SLinus Torvalds struct nfs4_delegation *dp; 39751da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 39763d733711SStanislav Kinsbursky time_t cutoff = get_seconds() - nn->nfsd4_lease; 3977a832e7aeSJeff Layton time_t t, new_timeo = nn->nfsd4_lease; 39781da177e4SLinus Torvalds 39791da177e4SLinus Torvalds nfs4_lock_state(); 39801da177e4SLinus Torvalds 39811da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 398212760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 398336acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 3984c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 39855ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 39861da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 39871da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 39881da177e4SLinus Torvalds t = clp->cl_time - cutoff; 3989a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 39901da177e4SLinus Torvalds break; 39911da177e4SLinus Torvalds } 3992221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 3993d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 3994d7682988SBenny Halevy clp->cl_clientid.cl_id); 3995d7682988SBenny Halevy continue; 3996d7682988SBenny Halevy } 3997221a6876SJ. Bruce Fields list_move(&clp->cl_lru, &reaplist); 399836acb66bSBenny Halevy } 3999c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 400036acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 400136acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 40021da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 40031da177e4SLinus Torvalds clp->cl_clientid.cl_id); 40041da177e4SLinus Torvalds expire_client(clp); 40051da177e4SLinus Torvalds } 4006cdc97505SBenny Halevy spin_lock(&state_lock); 4007e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 40081da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 40094e37a7c2SStanislav Kinsbursky if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) 40104e37a7c2SStanislav Kinsbursky continue; 40111da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 4012a832e7aeSJeff Layton t = dp->dl_time - cutoff; 4013a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 40141da177e4SLinus Torvalds break; 40151da177e4SLinus Torvalds } 401642690676SJeff Layton unhash_delegation_locked(dp); 401742690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 40181da177e4SLinus Torvalds } 4019cdc97505SBenny Halevy spin_unlock(&state_lock); 40202d4a532dSJeff Layton while (!list_empty(&reaplist)) { 40212d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 40222d4a532dSJeff Layton dl_recall_lru); 40232d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 40243bd64a5bSJ. Bruce Fields revoke_delegation(dp); 40251da177e4SLinus Torvalds } 402673758fedSStanislav Kinsbursky list_for_each_safe(pos, next, &nn->close_lru) { 4027fe0750e5SJ. Bruce Fields oo = container_of(pos, struct nfs4_openowner, oo_close_lru); 4028fe0750e5SJ. Bruce Fields if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { 4029a832e7aeSJeff Layton t = oo->oo_time - cutoff; 4030a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 40311da177e4SLinus Torvalds break; 40321da177e4SLinus Torvalds } 4033fe0750e5SJ. Bruce Fields release_openowner(oo); 40341da177e4SLinus Torvalds } 4035a832e7aeSJeff Layton new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 40361da177e4SLinus Torvalds nfs4_unlock_state(); 4037a832e7aeSJeff Layton return new_timeo; 40381da177e4SLinus Torvalds } 40391da177e4SLinus Torvalds 4040a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 4041a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 4042a254b246SHarvey Harrison 4043a254b246SHarvey Harrison static void 404409121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 40451da177e4SLinus Torvalds { 40461da177e4SLinus Torvalds time_t t; 404709121281SStanislav Kinsbursky struct delayed_work *dwork = container_of(laundry, struct delayed_work, 404809121281SStanislav Kinsbursky work); 404909121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 405009121281SStanislav Kinsbursky laundromat_work); 40511da177e4SLinus Torvalds 405209121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 40531da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 405409121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 40551da177e4SLinus Torvalds } 40561da177e4SLinus Torvalds 4057f7a4d872SJ. Bruce Fields static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) 4058f8816512SNeilBrown { 405911b9164aSTrond Myklebust if (!nfsd_fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle)) 4060f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4061f7a4d872SJ. Bruce Fields return nfs_ok; 40621da177e4SLinus Torvalds } 40631da177e4SLinus Torvalds 40641da177e4SLinus Torvalds static inline int 406582c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 40661da177e4SLinus Torvalds { 406782c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 406882c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 406982c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 40701da177e4SLinus Torvalds } 40711da177e4SLinus Torvalds 40721da177e4SLinus Torvalds static inline int 407382c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 40741da177e4SLinus Torvalds { 407582c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 407682c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 40771da177e4SLinus Torvalds } 40781da177e4SLinus Torvalds 40791da177e4SLinus Torvalds static 4080dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 40811da177e4SLinus Torvalds { 4082b37ad28bSAl Viro __be32 status = nfserr_openmode; 40831da177e4SLinus Torvalds 408402921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 408502921914SJ. Bruce Fields if (stp->st_openstp) 408602921914SJ. Bruce Fields stp = stp->st_openstp; 408782c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 40881da177e4SLinus Torvalds goto out; 408982c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 40901da177e4SLinus Torvalds goto out; 40911da177e4SLinus Torvalds status = nfs_ok; 40921da177e4SLinus Torvalds out: 40931da177e4SLinus Torvalds return status; 40941da177e4SLinus Torvalds } 40951da177e4SLinus Torvalds 4096b37ad28bSAl Viro static inline __be32 40975ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 40981da177e4SLinus Torvalds { 4099203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 41001da177e4SLinus Torvalds return nfs_ok; 41015ccb0066SStanislav Kinsbursky else if (locks_in_grace(net)) { 410225985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 41031da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 41041da177e4SLinus Torvalds return nfserr_grace; 41051da177e4SLinus Torvalds } else if (flags & WR_STATE) 41061da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 41071da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 41081da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 41091da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 41101da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 41111da177e4SLinus Torvalds } 41121da177e4SLinus Torvalds 41131da177e4SLinus Torvalds /* 41141da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 41151da177e4SLinus Torvalds * that are not able to provide mandatory locking. 41161da177e4SLinus Torvalds */ 41171da177e4SLinus Torvalds static inline int 41185ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 41191da177e4SLinus Torvalds { 41205ccb0066SStanislav Kinsbursky return locks_in_grace(net) && mandatory_lock(inode); 41211da177e4SLinus Torvalds } 41221da177e4SLinus Torvalds 412381b82965SJ. Bruce Fields /* Returns true iff a is later than b: */ 412481b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b) 412581b82965SJ. Bruce Fields { 41261a9357f4SJim Rees return (s32)(a->si_generation - b->si_generation) > 0; 412781b82965SJ. Bruce Fields } 412881b82965SJ. Bruce Fields 412957b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 41300836f587SJ. Bruce Fields { 41316668958fSAndy Adamson /* 41326668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 41336668958fSAndy Adamson * when it is zero. 41346668958fSAndy Adamson */ 413528dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 413681b82965SJ. Bruce Fields return nfs_ok; 413781b82965SJ. Bruce Fields 413881b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 413981b82965SJ. Bruce Fields return nfs_ok; 41406668958fSAndy Adamson 41410836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 414281b82965SJ. Bruce Fields if (stateid_generation_after(in, ref)) 41430836f587SJ. Bruce Fields return nfserr_bad_stateid; 41440836f587SJ. Bruce Fields /* 414581b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 414681b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 414781b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 414881b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 414981b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 415081b82965SJ. Bruce Fields * but better performance may result in retrying IO that 415181b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 415281b82965SJ. Bruce Fields * reordered in flight: 41530836f587SJ. Bruce Fields */ 41540836f587SJ. Bruce Fields return nfserr_old_stateid; 41550836f587SJ. Bruce Fields } 41560836f587SJ. Bruce Fields 41577df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 415817456804SBryan Schumaker { 415997b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 416097b7e3b6SJ. Bruce Fields struct nfs4_ol_stateid *ols; 41611af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 416217456804SBryan Schumaker 41637df302f7SChuck Lever if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 41641af71cc8SJeff Layton return status; 41657df302f7SChuck Lever /* Client debugging aid. */ 41667df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 41677df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 41687df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 41697df302f7SChuck Lever sizeof(addr_str)); 41707df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 41717df302f7SChuck Lever "with incorrect client ID\n", addr_str); 41721af71cc8SJeff Layton return status; 41737df302f7SChuck Lever } 41741af71cc8SJeff Layton spin_lock(&cl->cl_lock); 41751af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 417697b7e3b6SJ. Bruce Fields if (!s) 41771af71cc8SJeff Layton goto out_unlock; 417836279ac1SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, 1); 417917456804SBryan Schumaker if (status) 41801af71cc8SJeff Layton goto out_unlock; 418123340032SJ. Bruce Fields switch (s->sc_type) { 418223340032SJ. Bruce Fields case NFS4_DELEG_STID: 41831af71cc8SJeff Layton status = nfs_ok; 41841af71cc8SJeff Layton break; 41853bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 41861af71cc8SJeff Layton status = nfserr_deleg_revoked; 41871af71cc8SJeff Layton break; 418823340032SJ. Bruce Fields case NFS4_OPEN_STID: 418923340032SJ. Bruce Fields case NFS4_LOCK_STID: 419097b7e3b6SJ. Bruce Fields ols = openlockstateid(s); 419197b7e3b6SJ. Bruce Fields if (ols->st_stateowner->so_is_open_owner 419223340032SJ. Bruce Fields && !(openowner(ols->st_stateowner)->oo_flags 419323340032SJ. Bruce Fields & NFS4_OO_CONFIRMED)) 41941af71cc8SJeff Layton status = nfserr_bad_stateid; 41951af71cc8SJeff Layton else 41961af71cc8SJeff Layton status = nfs_ok; 41971af71cc8SJeff Layton break; 419823340032SJ. Bruce Fields default: 419923340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 4200b0fc29d6STrond Myklebust /* Fallthrough */ 420123340032SJ. Bruce Fields case NFS4_CLOSED_STID: 4202b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 42031af71cc8SJeff Layton status = nfserr_bad_stateid; 420423340032SJ. Bruce Fields } 42051af71cc8SJeff Layton out_unlock: 42061af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 42071af71cc8SJeff Layton return status; 420817456804SBryan Schumaker } 420917456804SBryan Schumaker 42102dd6e458STrond Myklebust static __be32 42112dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 42122dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 42132dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 421438c2f4b1SJ. Bruce Fields { 42150eb6f20aSJ. Bruce Fields __be32 status; 421638c2f4b1SJ. Bruce Fields 421738c2f4b1SJ. Bruce Fields if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 421838c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 42194b24ca7dSJeff Layton status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn); 4220a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 42214b24ca7dSJeff Layton if (cstate->session) 4222a8a7c677STrond Myklebust return nfserr_bad_stateid; 422338c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 4224a8a7c677STrond Myklebust } 42250eb6f20aSJ. Bruce Fields if (status) 42260eb6f20aSJ. Bruce Fields return status; 42274b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 422838c2f4b1SJ. Bruce Fields if (!*s) 422938c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 423038c2f4b1SJ. Bruce Fields return nfs_ok; 423138c2f4b1SJ. Bruce Fields } 423238c2f4b1SJ. Bruce Fields 42331da177e4SLinus Torvalds /* 42341da177e4SLinus Torvalds * Checks for stateid operations 42351da177e4SLinus Torvalds */ 4236b37ad28bSAl Viro __be32 42375ccb0066SStanislav Kinsbursky nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, 4238dd453dfdSBenny Halevy stateid_t *stateid, int flags, struct file **filpp) 42391da177e4SLinus Torvalds { 424069064a27SJ. Bruce Fields struct nfs4_stid *s; 4241dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 42421da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 4243dd453dfdSBenny Halevy struct svc_fh *current_fh = &cstate->current_fh; 42441da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 42453320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 424614bcab1aSTrond Myklebust struct file *file = NULL; 4247b37ad28bSAl Viro __be32 status; 42481da177e4SLinus Torvalds 42491da177e4SLinus Torvalds if (filpp) 42501da177e4SLinus Torvalds *filpp = NULL; 42511da177e4SLinus Torvalds 42525ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 42531da177e4SLinus Torvalds return nfserr_grace; 42541da177e4SLinus Torvalds 42551da177e4SLinus Torvalds if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 42565ccb0066SStanislav Kinsbursky return check_special_stateids(net, current_fh, stateid, flags); 42571da177e4SLinus Torvalds 425814bcab1aSTrond Myklebust nfs4_lock_state(); 425914bcab1aSTrond Myklebust 42602dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 4261db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 42622dd6e458STrond Myklebust &s, nn); 426338c2f4b1SJ. Bruce Fields if (status) 4264fd911011STrond Myklebust goto unlock_state; 426569064a27SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); 42660c2a498fSJ. Bruce Fields if (status) 42670c2a498fSJ. Bruce Fields goto out; 4268f7a4d872SJ. Bruce Fields switch (s->sc_type) { 4269f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 427069064a27SJ. Bruce Fields dp = delegstateid(s); 4271dc9bf700SJ. Bruce Fields status = nfs4_check_delegmode(dp, flags); 4272dc9bf700SJ. Bruce Fields if (status) 4273dc9bf700SJ. Bruce Fields goto out; 427443b0178eSDan Carpenter if (filpp) { 427511b9164aSTrond Myklebust file = dp->dl_stid.sc_file->fi_deleg_file; 427614bcab1aSTrond Myklebust if (!file) { 4277063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 4278063b0fb9SJ. Bruce Fields status = nfserr_serverfault; 4279063b0fb9SJ. Bruce Fields goto out; 4280063b0fb9SJ. Bruce Fields } 4281de18643dSTrond Myklebust get_file(file); 428243b0178eSDan Carpenter } 4283f7a4d872SJ. Bruce Fields break; 4284f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 4285f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 428669064a27SJ. Bruce Fields stp = openlockstateid(s); 4287f7a4d872SJ. Bruce Fields status = nfs4_check_fh(current_fh, stp); 4288f7a4d872SJ. Bruce Fields if (status) 42891da177e4SLinus Torvalds goto out; 4290fe0750e5SJ. Bruce Fields if (stp->st_stateowner->so_is_open_owner 4291dad1c067SJ. Bruce Fields && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 42921da177e4SLinus Torvalds goto out; 4293a4455be0SJ. Bruce Fields status = nfs4_check_openmode(stp, flags); 4294a4455be0SJ. Bruce Fields if (status) 42951da177e4SLinus Torvalds goto out; 4296f9d7562fSJ. Bruce Fields if (filpp) { 429711b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 429811b9164aSTrond Myklebust 4299f9d7562fSJ. Bruce Fields if (flags & RD_STATE) 430011b9164aSTrond Myklebust file = find_readable_file(fp); 4301f9d7562fSJ. Bruce Fields else 430211b9164aSTrond Myklebust file = find_writeable_file(fp); 4303f9d7562fSJ. Bruce Fields } 4304f7a4d872SJ. Bruce Fields break; 4305f7a4d872SJ. Bruce Fields default: 430614bcab1aSTrond Myklebust status = nfserr_bad_stateid; 430714bcab1aSTrond Myklebust goto out; 43081da177e4SLinus Torvalds } 43091da177e4SLinus Torvalds status = nfs_ok; 431014bcab1aSTrond Myklebust if (file) 4311de18643dSTrond Myklebust *filpp = file; 43121da177e4SLinus Torvalds out: 4313fd911011STrond Myklebust nfs4_put_stid(s); 4314fd911011STrond Myklebust unlock_state: 431514bcab1aSTrond Myklebust nfs4_unlock_state(); 43161da177e4SLinus Torvalds return status; 43171da177e4SLinus Torvalds } 43181da177e4SLinus Torvalds 4319e1ca12dfSBryan Schumaker static __be32 4320dcef0413SJ. Bruce Fields nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp) 4321e1ca12dfSBryan Schumaker { 4322a1b8ff4cSJ. Bruce Fields struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 4323a1b8ff4cSJ. Bruce Fields 432411b9164aSTrond Myklebust if (check_for_locks(stp->st_stid.sc_file, lo)) 4325e1ca12dfSBryan Schumaker return nfserr_locks_held; 4326c53530daSJeff Layton release_lockowner_if_empty(lo); 4327e1ca12dfSBryan Schumaker return nfs_ok; 4328e1ca12dfSBryan Schumaker } 4329e1ca12dfSBryan Schumaker 4330e1ca12dfSBryan Schumaker /* 433117456804SBryan Schumaker * Test if the stateid is valid 433217456804SBryan Schumaker */ 433317456804SBryan Schumaker __be32 433417456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 433517456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 433617456804SBryan Schumaker { 433703cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 433803cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 433903cfb420SBryan Schumaker 434003cfb420SBryan Schumaker nfs4_lock_state(); 434103cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 43427df302f7SChuck Lever stateid->ts_id_status = 43437df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 434403cfb420SBryan Schumaker nfs4_unlock_state(); 434503cfb420SBryan Schumaker 434617456804SBryan Schumaker return nfs_ok; 434717456804SBryan Schumaker } 434817456804SBryan Schumaker 4349e1ca12dfSBryan Schumaker __be32 4350e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4351e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 4352e1ca12dfSBryan Schumaker { 4353e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 43542da1cec7SJ. Bruce Fields struct nfs4_stid *s; 43553bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 435638c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 43572da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 4358e1ca12dfSBryan Schumaker 4359e1ca12dfSBryan Schumaker nfs4_lock_state(); 43601af71cc8SJeff Layton spin_lock(&cl->cl_lock); 43611af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 43622da1cec7SJ. Bruce Fields if (!s) 43631af71cc8SJeff Layton goto out_unlock; 43642da1cec7SJ. Bruce Fields switch (s->sc_type) { 43652da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 4366e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 43671af71cc8SJeff Layton break; 43682da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 43691af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 43701af71cc8SJeff Layton if (ret) 43711af71cc8SJeff Layton break; 43721af71cc8SJeff Layton ret = nfserr_locks_held; 43731af71cc8SJeff Layton break; 43742da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 43752da1cec7SJ. Bruce Fields ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 43762da1cec7SJ. Bruce Fields if (ret) 4377f7a4d872SJ. Bruce Fields break; 43781af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 43791af71cc8SJeff Layton ret = nfsd4_free_lock_stateid(openlockstateid(s)); 43801af71cc8SJeff Layton goto out; 43813bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 43823bd64a5bSJ. Bruce Fields dp = delegstateid(s); 43832d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 43842d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 43856011695dSTrond Myklebust nfs4_put_stid(s); 43863bd64a5bSJ. Bruce Fields ret = nfs_ok; 43871af71cc8SJeff Layton goto out; 43881af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 4389e1ca12dfSBryan Schumaker } 43901af71cc8SJeff Layton out_unlock: 43911af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 4392e1ca12dfSBryan Schumaker out: 4393e1ca12dfSBryan Schumaker nfs4_unlock_state(); 4394e1ca12dfSBryan Schumaker return ret; 4395e1ca12dfSBryan Schumaker } 4396e1ca12dfSBryan Schumaker 43974c4cd222SNeilBrown static inline int 43984c4cd222SNeilBrown setlkflg (int type) 43994c4cd222SNeilBrown { 44004c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 44014c4cd222SNeilBrown RD_STATE : WR_STATE; 44024c4cd222SNeilBrown } 44031da177e4SLinus Torvalds 4404dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 4405c0a5d93eSJ. Bruce Fields { 4406c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 4407c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 4408c0a5d93eSJ. Bruce Fields __be32 status; 4409c0a5d93eSJ. Bruce Fields 4410c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 4411c0a5d93eSJ. Bruce Fields if (status) 4412c0a5d93eSJ. Bruce Fields return status; 44133bd64a5bSJ. Bruce Fields if (stp->st_stid.sc_type == NFS4_CLOSED_STID 44143bd64a5bSJ. Bruce Fields || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4415f7a4d872SJ. Bruce Fields /* 4416f7a4d872SJ. Bruce Fields * "Closed" stateid's exist *only* to return 44173bd64a5bSJ. Bruce Fields * nfserr_replay_me from the previous step, and 44183bd64a5bSJ. Bruce Fields * revoked delegations are kept only for free_stateid. 4419f7a4d872SJ. Bruce Fields */ 4420f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4421f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 4422f7a4d872SJ. Bruce Fields if (status) 4423f7a4d872SJ. Bruce Fields return status; 4424f7a4d872SJ. Bruce Fields return nfs4_check_fh(current_fh, stp); 4425c0a5d93eSJ. Bruce Fields } 4426c0a5d93eSJ. Bruce Fields 44271da177e4SLinus Torvalds /* 44281da177e4SLinus Torvalds * Checks for sequence id mutating operations. 44291da177e4SLinus Torvalds */ 4430b37ad28bSAl Viro static __be32 4431dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 44322288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 44333320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 44343320fef1SStanislav Kinsbursky struct nfsd_net *nn) 44351da177e4SLinus Torvalds { 44360836f587SJ. Bruce Fields __be32 status; 443738c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 4438e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 44391da177e4SLinus Torvalds 44408c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 44418c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 44421da177e4SLinus Torvalds 44431da177e4SLinus Torvalds *stpp = NULL; 44442dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 4445c0a5d93eSJ. Bruce Fields if (status) 4446c0a5d93eSJ. Bruce Fields return status; 4447e17f99b7STrond Myklebust stp = openlockstateid(s); 444858fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 44491da177e4SLinus Torvalds 4450e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 4451fd911011STrond Myklebust if (!status) 4452e17f99b7STrond Myklebust *stpp = stp; 4453fd911011STrond Myklebust else 4454fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 4455e17f99b7STrond Myklebust return status; 44561da177e4SLinus Torvalds } 44571da177e4SLinus Torvalds 44583320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 44593320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 4460c0a5d93eSJ. Bruce Fields { 4461c0a5d93eSJ. Bruce Fields __be32 status; 4462c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 44634cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 44641da177e4SLinus Torvalds 4465c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 44664cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 44670836f587SJ. Bruce Fields if (status) 44680836f587SJ. Bruce Fields return status; 44694cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 44704cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 44714cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 4472c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 44734cbfc9f7STrond Myklebust } 44744cbfc9f7STrond Myklebust *stpp = stp; 44753a4f98bbSNeilBrown return nfs_ok; 44761da177e4SLinus Torvalds } 44771da177e4SLinus Torvalds 4478b37ad28bSAl Viro __be32 4479ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4480a4f1706aSJ.Bruce Fields struct nfsd4_open_confirm *oc) 44811da177e4SLinus Torvalds { 4482b37ad28bSAl Viro __be32 status; 4483fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 4484dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 44853320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 44861da177e4SLinus Torvalds 4487a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 4488a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 44891da177e4SLinus Torvalds 4490ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 4491a8cddc5dSJ. Bruce Fields if (status) 4492a8cddc5dSJ. Bruce Fields return status; 44931da177e4SLinus Torvalds 44941da177e4SLinus Torvalds nfs4_lock_state(); 44951da177e4SLinus Torvalds 44969072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 4497ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 44983320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 44999072d5c6SJ. Bruce Fields if (status) 45001da177e4SLinus Torvalds goto out; 4501fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 450268b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 4503dad1c067SJ. Bruce Fields if (oo->oo_flags & NFS4_OO_CONFIRMED) 45042585fc79STrond Myklebust goto put_stateid; 4505dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 4506dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4507dcef0413SJ. Bruce Fields memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 45088c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 4509dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 4510c7b9a459SNeilBrown 45112a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 451268b66e82SJ. Bruce Fields status = nfs_ok; 45132585fc79STrond Myklebust put_stateid: 45142585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 45151da177e4SLinus Torvalds out: 45169411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 45171da177e4SLinus Torvalds nfs4_unlock_state(); 45181da177e4SLinus Torvalds return status; 45191da177e4SLinus Torvalds } 45201da177e4SLinus Torvalds 45216409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 45221da177e4SLinus Torvalds { 452382c5ff1bSJeff Layton if (!test_access(access, stp)) 45246409a5a6SJ. Bruce Fields return; 452511b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 452682c5ff1bSJeff Layton clear_access(access, stp); 4527f197c271SJ. Bruce Fields } 45286409a5a6SJ. Bruce Fields 45296409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 45306409a5a6SJ. Bruce Fields { 45316409a5a6SJ. Bruce Fields switch (to_access) { 45326409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 45336409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 45346409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 45356409a5a6SJ. Bruce Fields break; 45366409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 45376409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 45386409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 45396409a5a6SJ. Bruce Fields break; 45406409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 45416409a5a6SJ. Bruce Fields break; 45426409a5a6SJ. Bruce Fields default: 4543063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 45441da177e4SLinus Torvalds } 45451da177e4SLinus Torvalds } 45461da177e4SLinus Torvalds 4547b37ad28bSAl Viro __be32 4548ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 4549ca364317SJ.Bruce Fields struct nfsd4_compound_state *cstate, 4550a4f1706aSJ.Bruce Fields struct nfsd4_open_downgrade *od) 45511da177e4SLinus Torvalds { 4552b37ad28bSAl Viro __be32 status; 4553dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 45543320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 45551da177e4SLinus Torvalds 4556a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 4557a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 45581da177e4SLinus Torvalds 4559c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 45602c8bd7e0SBenny Halevy if (od->od_deleg_want) 45612c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 45622c8bd7e0SBenny Halevy od->od_deleg_want); 45631da177e4SLinus Torvalds 45641da177e4SLinus Torvalds nfs4_lock_state(); 4565c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 45663320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 45679072d5c6SJ. Bruce Fields if (status) 45681da177e4SLinus Torvalds goto out; 45691da177e4SLinus Torvalds status = nfserr_inval; 457082c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 4571c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 45721da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 45730667b1e9STrond Myklebust goto put_stateid; 45741da177e4SLinus Torvalds } 4575ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 4576c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 45771da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 45780667b1e9STrond Myklebust goto put_stateid; 45791da177e4SLinus Torvalds } 45806409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 45811da177e4SLinus Torvalds 4582ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 45831da177e4SLinus Torvalds 4584dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4585dcef0413SJ. Bruce Fields memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 45861da177e4SLinus Torvalds status = nfs_ok; 45870667b1e9STrond Myklebust put_stateid: 45880667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 45891da177e4SLinus Torvalds out: 45909411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 45911da177e4SLinus Torvalds nfs4_unlock_state(); 45921da177e4SLinus Torvalds return status; 45931da177e4SLinus Torvalds } 45941da177e4SLinus Torvalds 4595f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 4596f7a4d872SJ. Bruce Fields { 4597acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 4598acf9295bSTrond Myklebust struct nfs4_openowner *oo = openowner(s->st_stateowner); 4599acf9295bSTrond Myklebust 4600f7a4d872SJ. Bruce Fields s->st_stid.sc_type = NFS4_CLOSED_STID; 4601acf9295bSTrond Myklebust unhash_open_stateid(s); 4602acf9295bSTrond Myklebust 4603acf9295bSTrond Myklebust if (clp->cl_minorversion) { 4604acf9295bSTrond Myklebust if (list_empty(&oo->oo_owner.so_stateids)) 4605acf9295bSTrond Myklebust release_openowner(oo); 46066011695dSTrond Myklebust nfs4_put_stid(&s->st_stid); 4607acf9295bSTrond Myklebust } else { 46086011695dSTrond Myklebust /* 46096011695dSTrond Myklebust * In the 4.0 case we need to keep the owners around a 46106011695dSTrond Myklebust * little while to handle CLOSE replay. We still do need 46116011695dSTrond Myklebust * to release any file access that is held by them 46126011695dSTrond Myklebust * before returning however. 46136011695dSTrond Myklebust */ 46146011695dSTrond Myklebust release_all_access(s); 461511b9164aSTrond Myklebust if (s->st_stid.sc_file) { 461611b9164aSTrond Myklebust put_nfs4_file(s->st_stid.sc_file); 461711b9164aSTrond Myklebust s->st_stid.sc_file = NULL; 4618f8338834STrond Myklebust } 4619acf9295bSTrond Myklebust oo->oo_last_closed_stid = s; 4620acf9295bSTrond Myklebust if (list_empty(&oo->oo_owner.so_stateids)) 4621acf9295bSTrond Myklebust move_to_close_lru(oo, clp->net); 4622acf9295bSTrond Myklebust } 462338c387b5SJ. Bruce Fields } 462438c387b5SJ. Bruce Fields 46251da177e4SLinus Torvalds /* 46261da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 46271da177e4SLinus Torvalds */ 4628b37ad28bSAl Viro __be32 4629ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4630a4f1706aSJ.Bruce Fields struct nfsd4_close *close) 46311da177e4SLinus Torvalds { 4632b37ad28bSAl Viro __be32 status; 4633dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 46343320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 46353320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 46361da177e4SLinus Torvalds 4637a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 4638a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 46391da177e4SLinus Torvalds 46401da177e4SLinus Torvalds nfs4_lock_state(); 4641f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 4642f7a4d872SJ. Bruce Fields &close->cl_stateid, 4643f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 46443320fef1SStanislav Kinsbursky &stp, nn); 46459411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 46469072d5c6SJ. Bruce Fields if (status) 46471da177e4SLinus Torvalds goto out; 4648dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4649dcef0413SJ. Bruce Fields memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 46501da177e4SLinus Torvalds 4651f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 46528a0b589dSTrond Myklebust 46538a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 46548a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 46551da177e4SLinus Torvalds out: 46561da177e4SLinus Torvalds nfs4_unlock_state(); 46571da177e4SLinus Torvalds return status; 46581da177e4SLinus Torvalds } 46591da177e4SLinus Torvalds 4660b37ad28bSAl Viro __be32 4661ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4662ca364317SJ.Bruce Fields struct nfsd4_delegreturn *dr) 46631da177e4SLinus Torvalds { 4664203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 4665203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 466638c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 4667b37ad28bSAl Viro __be32 status; 46683320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 46691da177e4SLinus Torvalds 4670ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 4671203a8c8eSJ. Bruce Fields return status; 46721da177e4SLinus Torvalds 46731da177e4SLinus Torvalds nfs4_lock_state(); 46742dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 467538c2f4b1SJ. Bruce Fields if (status) 4676203a8c8eSJ. Bruce Fields goto out; 467738c2f4b1SJ. Bruce Fields dp = delegstateid(s); 4678d5477a8dSJ. Bruce Fields status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); 4679203a8c8eSJ. Bruce Fields if (status) 4680fd911011STrond Myklebust goto put_stateid; 4681203a8c8eSJ. Bruce Fields 46823bd64a5bSJ. Bruce Fields destroy_delegation(dp); 4683fd911011STrond Myklebust put_stateid: 4684fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 46851da177e4SLinus Torvalds out: 4686203a8c8eSJ. Bruce Fields nfs4_unlock_state(); 4687203a8c8eSJ. Bruce Fields 46881da177e4SLinus Torvalds return status; 46891da177e4SLinus Torvalds } 46901da177e4SLinus Torvalds 46911da177e4SLinus Torvalds 46921da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) 46931da177e4SLinus Torvalds 469487df4de8SBenny Halevy static inline u64 469587df4de8SBenny Halevy end_offset(u64 start, u64 len) 469687df4de8SBenny Halevy { 469787df4de8SBenny Halevy u64 end; 469887df4de8SBenny Halevy 469987df4de8SBenny Halevy end = start + len; 470087df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 470187df4de8SBenny Halevy } 470287df4de8SBenny Halevy 470387df4de8SBenny Halevy /* last octet in a range */ 470487df4de8SBenny Halevy static inline u64 470587df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 470687df4de8SBenny Halevy { 470787df4de8SBenny Halevy u64 end; 470887df4de8SBenny Halevy 4709063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 471087df4de8SBenny Halevy end = start + len; 471187df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 471287df4de8SBenny Halevy } 471387df4de8SBenny Halevy 47141da177e4SLinus Torvalds /* 47151da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 47161da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 47171da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 47181da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 47191da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 47201da177e4SLinus Torvalds * the VFS, but this is a very deep change! 47211da177e4SLinus Torvalds */ 47221da177e4SLinus Torvalds static inline void 47231da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 47241da177e4SLinus Torvalds { 47251da177e4SLinus Torvalds if (lock->fl_start < 0) 47261da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 47271da177e4SLinus Torvalds if (lock->fl_end < 0) 47281da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 47291da177e4SLinus Torvalds } 47301da177e4SLinus Torvalds 4731d5b9026aSNeilBrown /* Hack!: For now, we're defining this just so we can use a pointer to it 4732d5b9026aSNeilBrown * as a unique cookie to identify our (NFSv4's) posix locks. */ 47337b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 4734d5b9026aSNeilBrown }; 47351da177e4SLinus Torvalds 47361da177e4SLinus Torvalds static inline void 47371da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 47381da177e4SLinus Torvalds { 4739fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 47401da177e4SLinus Torvalds 4741d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 4742fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 4743fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 4744fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 47457c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 47467c13f344SJ. Bruce Fields /* We just don't care that much */ 47477c13f344SJ. Bruce Fields goto nevermind; 4748fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 4749fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 4750d5b9026aSNeilBrown } else { 47517c13f344SJ. Bruce Fields nevermind: 47527c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 47537c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 4754d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 4755d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 47561da177e4SLinus Torvalds } 47571da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 475887df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 475987df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 47601da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 47611da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 47621da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 47631da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 47641da177e4SLinus Torvalds } 47651da177e4SLinus Torvalds 4766fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 4767b3c32bcdSTrond Myklebust find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner, 4768b3c32bcdSTrond Myklebust struct nfsd_net *nn) 47691da177e4SLinus Torvalds { 4770b3c32bcdSTrond Myklebust unsigned int strhashval = ownerstr_hashval(clid->cl_id, owner); 4771b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 47721da177e4SLinus Torvalds 4773b3c32bcdSTrond Myklebust list_for_each_entry(so, &nn->ownerstr_hashtbl[strhashval], so_strhash) { 4774b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 4775b3c32bcdSTrond Myklebust continue; 4776b3c32bcdSTrond Myklebust if (!same_owner_str(so, owner, clid)) 4777b3c32bcdSTrond Myklebust continue; 47785db1c03fSJeff Layton atomic_inc(&so->so_count); 4779b3c32bcdSTrond Myklebust return lockowner(so); 47801da177e4SLinus Torvalds } 47811da177e4SLinus Torvalds return NULL; 47821da177e4SLinus Torvalds } 47831da177e4SLinus Torvalds 47848f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 47858f4b54c5SJeff Layton { 47868f4b54c5SJeff Layton unhash_lockowner(lockowner(sop)); 47878f4b54c5SJeff Layton } 47888f4b54c5SJeff Layton 47896b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 47906b180f0bSJeff Layton { 47916b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 47926b180f0bSJeff Layton 47936b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 47946b180f0bSJeff Layton } 47956b180f0bSJeff Layton 47966b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 47978f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 47986b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 47996b180f0bSJeff Layton }; 48006b180f0bSJeff Layton 48011da177e4SLinus Torvalds /* 48021da177e4SLinus Torvalds * Alloc a lock owner structure. 48031da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 480425985edcSLucas De Marchi * occurred. 48051da177e4SLinus Torvalds * 480616bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 48071da177e4SLinus Torvalds */ 4808fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 4809dcef0413SJ. Bruce Fields alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) { 4810fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 4811b3c32bcdSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 48121da177e4SLinus Torvalds 4813fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 4814fe0750e5SJ. Bruce Fields if (!lo) 48151da177e4SLinus Torvalds return NULL; 4816fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 4817fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 48185db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 48196b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 4820b3c32bcdSTrond Myklebust list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); 4821fe0750e5SJ. Bruce Fields return lo; 48221da177e4SLinus Torvalds } 48231da177e4SLinus Torvalds 4824356a95ecSJeff Layton static void 4825356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 4826356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 4827f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 48281da177e4SLinus Torvalds { 4829d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 48301da177e4SLinus Torvalds 4831356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 4832356a95ecSJeff Layton 48333d0fabd5STrond Myklebust atomic_inc(&stp->st_stid.sc_count); 48343abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 4835fe0750e5SJ. Bruce Fields stp->st_stateowner = &lo->lo_owner; 4836e4f1dd7fSTrond Myklebust atomic_inc(&lo->lo_owner.so_count); 483713cd2184SNeilBrown get_nfs4_file(fp); 483811b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 4839b49e084dSJeff Layton stp->st_stid.sc_free = nfs4_free_lock_stateid; 48400997b173SJ. Bruce Fields stp->st_access_bmap = 0; 48411da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 48424c4cd222SNeilBrown stp->st_openstp = open_stp; 48433c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 48441c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 48451d31a253STrond Myklebust spin_lock(&fp->fi_lock); 48461d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 48471d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 48481da177e4SLinus Torvalds } 48491da177e4SLinus Torvalds 4850c53530daSJeff Layton static struct nfs4_ol_stateid * 4851c53530daSJeff Layton find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) 4852c53530daSJeff Layton { 4853c53530daSJeff Layton struct nfs4_ol_stateid *lst; 4854356a95ecSJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 4855356a95ecSJeff Layton 4856356a95ecSJeff Layton lockdep_assert_held(&clp->cl_lock); 4857c53530daSJeff Layton 4858c53530daSJeff Layton list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { 48593d0fabd5STrond Myklebust if (lst->st_stid.sc_file == fp) { 48603d0fabd5STrond Myklebust atomic_inc(&lst->st_stid.sc_count); 4861c53530daSJeff Layton return lst; 4862c53530daSJeff Layton } 48633d0fabd5STrond Myklebust } 4864c53530daSJeff Layton return NULL; 4865c53530daSJeff Layton } 4866c53530daSJeff Layton 4867356a95ecSJeff Layton static struct nfs4_ol_stateid * 4868356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 4869356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 4870356a95ecSJeff Layton bool *new) 4871356a95ecSJeff Layton { 4872356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 4873356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 4874356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 4875356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 4876356a95ecSJeff Layton 4877356a95ecSJeff Layton spin_lock(&clp->cl_lock); 4878356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 4879356a95ecSJeff Layton if (lst == NULL) { 4880356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 4881356a95ecSJeff Layton ns = nfs4_alloc_stid(clp, stateid_slab); 4882356a95ecSJeff Layton if (ns == NULL) 4883356a95ecSJeff Layton return NULL; 4884356a95ecSJeff Layton 4885356a95ecSJeff Layton spin_lock(&clp->cl_lock); 4886356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 4887356a95ecSJeff Layton if (likely(!lst)) { 4888356a95ecSJeff Layton lst = openlockstateid(ns); 4889356a95ecSJeff Layton init_lock_stateid(lst, lo, fi, inode, ost); 4890356a95ecSJeff Layton ns = NULL; 4891356a95ecSJeff Layton *new = true; 4892356a95ecSJeff Layton } 4893356a95ecSJeff Layton } 4894356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 4895356a95ecSJeff Layton if (ns) 4896356a95ecSJeff Layton nfs4_put_stid(ns); 4897356a95ecSJeff Layton return lst; 4898356a95ecSJeff Layton } 4899c53530daSJeff Layton 4900fd39ca9aSNeilBrown static int 49011da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 49021da177e4SLinus Torvalds { 490387df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 49041da177e4SLinus Torvalds LOFF_OVERFLOW(offset, length))); 49051da177e4SLinus Torvalds } 49061da177e4SLinus Torvalds 4907dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 49080997b173SJ. Bruce Fields { 490911b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 49100997b173SJ. Bruce Fields 49117214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 49127214e860SJeff Layton 491382c5ff1bSJeff Layton if (test_access(access, lock_stp)) 49140997b173SJ. Bruce Fields return; 491512659651SJeff Layton __nfs4_file_get_access(fp, access); 491682c5ff1bSJeff Layton set_access(access, lock_stp); 49170997b173SJ. Bruce Fields } 49180997b173SJ. Bruce Fields 4919356a95ecSJeff Layton static __be32 4920356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 4921356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 4922356a95ecSJeff Layton struct nfsd4_lock *lock, 4923356a95ecSJeff Layton struct nfs4_ol_stateid **lst, bool *new) 492464a284d0SJ. Bruce Fields { 49255db1c03fSJeff Layton __be32 status; 492611b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 492764a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 492864a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 4929f9c00c3aSJeff Layton struct inode *inode = cstate->current_fh.fh_dentry->d_inode; 493064a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 493164a284d0SJ. Bruce Fields unsigned int strhashval; 493220e9e2bcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id); 493364a284d0SJ. Bruce Fields 4934b3c32bcdSTrond Myklebust lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, nn); 4935c53530daSJeff Layton if (!lo) { 493616bfdaafSJ. Bruce Fields strhashval = ownerstr_hashval(cl->cl_clientid.cl_id, 493764a284d0SJ. Bruce Fields &lock->v.new.owner); 493864a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 493964a284d0SJ. Bruce Fields if (lo == NULL) 494064a284d0SJ. Bruce Fields return nfserr_jukebox; 49415db1c03fSJeff Layton /* FIXME: extra reference for new lockowners for the client */ 49425db1c03fSJeff Layton atomic_inc(&lo->lo_owner.so_count); 4943c53530daSJeff Layton } else { 4944c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 49455db1c03fSJeff Layton status = nfserr_bad_seqid; 4946c53530daSJeff Layton if (!cstate->minorversion && 4947c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 49485db1c03fSJeff Layton goto out; 4949c53530daSJeff Layton } 4950c53530daSJeff Layton 4951356a95ecSJeff Layton *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 495264a284d0SJ. Bruce Fields if (*lst == NULL) { 4953c53530daSJeff Layton release_lockowner_if_empty(lo); 49545db1c03fSJeff Layton status = nfserr_jukebox; 49555db1c03fSJeff Layton goto out; 495664a284d0SJ. Bruce Fields } 49575db1c03fSJeff Layton status = nfs_ok; 49585db1c03fSJeff Layton out: 49595db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 49605db1c03fSJeff Layton return status; 496164a284d0SJ. Bruce Fields } 496264a284d0SJ. Bruce Fields 49631da177e4SLinus Torvalds /* 49641da177e4SLinus Torvalds * LOCK operation 49651da177e4SLinus Torvalds */ 4966b37ad28bSAl Viro __be32 4967ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4968a4f1706aSJ.Bruce Fields struct nfsd4_lock *lock) 49691da177e4SLinus Torvalds { 4970fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 4971fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 49723d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 49730667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 49747214e860SJeff Layton struct nfs4_file *fp; 49757d947842SJ. Bruce Fields struct file *filp = NULL; 497621179d81SJeff Layton struct file_lock *file_lock = NULL; 497721179d81SJeff Layton struct file_lock *conflock = NULL; 4978b37ad28bSAl Viro __be32 status = 0; 4979b34f27aaSJ. Bruce Fields int lkflg; 4980b8dd7b9aSAl Viro int err; 49815db1c03fSJeff Layton bool new = false; 49823320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 49833320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 49841da177e4SLinus Torvalds 49851da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 49861da177e4SLinus Torvalds (long long) lock->lk_offset, 49871da177e4SLinus Torvalds (long long) lock->lk_length); 49881da177e4SLinus Torvalds 49891da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 49901da177e4SLinus Torvalds return nfserr_inval; 49911da177e4SLinus Torvalds 4992ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 49938837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 4994a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 4995a6f6ef2fSAndy Adamson return status; 4996a6f6ef2fSAndy Adamson } 4997a6f6ef2fSAndy Adamson 49981da177e4SLinus Torvalds nfs4_lock_state(); 49991da177e4SLinus Torvalds 50001da177e4SLinus Torvalds if (lock->lk_is_new) { 5001684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 5002684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 5003684e5638SJ. Bruce Fields memcpy(&lock->v.new.clientid, 5004684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 5005684e5638SJ. Bruce Fields sizeof(clientid_t)); 5006684e5638SJ. Bruce Fields 50071da177e4SLinus Torvalds status = nfserr_stale_clientid; 50082c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 50091da177e4SLinus Torvalds goto out; 50101da177e4SLinus Torvalds 50111da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 5012c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 50131da177e4SLinus Torvalds lock->lk_new_open_seqid, 50141da177e4SLinus Torvalds &lock->lk_new_open_stateid, 50153320fef1SStanislav Kinsbursky &open_stp, nn); 501637515177SNeilBrown if (status) 50171da177e4SLinus Torvalds goto out; 5018fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 5019b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 5020684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 5021b34f27aaSJ. Bruce Fields &lock->v.new.clientid)) 5022b34f27aaSJ. Bruce Fields goto out; 502364a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 50245db1c03fSJeff Layton &lock_stp, &new); 50253d0fabd5STrond Myklebust } else { 5026dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 50271da177e4SLinus Torvalds lock->lk_old_lock_seqid, 50281da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 50293320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 50303d0fabd5STrond Myklebust } 50311da177e4SLinus Torvalds if (status) 50321da177e4SLinus Torvalds goto out; 5033fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 50341da177e4SLinus Torvalds 5035b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 5036b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 5037b34f27aaSJ. Bruce Fields if (status) 5038b34f27aaSJ. Bruce Fields goto out; 5039b34f27aaSJ. Bruce Fields 50400dd395dcSNeilBrown status = nfserr_grace; 50413320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 50420dd395dcSNeilBrown goto out; 50430dd395dcSNeilBrown status = nfserr_no_grace; 50443320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 50450dd395dcSNeilBrown goto out; 50460dd395dcSNeilBrown 504721179d81SJeff Layton file_lock = locks_alloc_lock(); 504821179d81SJeff Layton if (!file_lock) { 504921179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 505021179d81SJeff Layton status = nfserr_jukebox; 505121179d81SJeff Layton goto out; 505221179d81SJeff Layton } 505321179d81SJeff Layton 505411b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 505521179d81SJeff Layton locks_init_lock(file_lock); 50561da177e4SLinus Torvalds switch (lock->lk_type) { 50571da177e4SLinus Torvalds case NFS4_READ_LT: 50581da177e4SLinus Torvalds case NFS4_READW_LT: 50597214e860SJeff Layton spin_lock(&fp->fi_lock); 50607214e860SJeff Layton filp = find_readable_file_locked(fp); 50610997b173SJ. Bruce Fields if (filp) 50620997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 50637214e860SJeff Layton spin_unlock(&fp->fi_lock); 506421179d81SJeff Layton file_lock->fl_type = F_RDLCK; 50651da177e4SLinus Torvalds break; 50661da177e4SLinus Torvalds case NFS4_WRITE_LT: 50671da177e4SLinus Torvalds case NFS4_WRITEW_LT: 50687214e860SJeff Layton spin_lock(&fp->fi_lock); 50697214e860SJeff Layton filp = find_writeable_file_locked(fp); 50700997b173SJ. Bruce Fields if (filp) 50710997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 50727214e860SJeff Layton spin_unlock(&fp->fi_lock); 507321179d81SJeff Layton file_lock->fl_type = F_WRLCK; 50741da177e4SLinus Torvalds break; 50751da177e4SLinus Torvalds default: 50761da177e4SLinus Torvalds status = nfserr_inval; 50771da177e4SLinus Torvalds goto out; 50781da177e4SLinus Torvalds } 5079f9d7562fSJ. Bruce Fields if (!filp) { 5080f9d7562fSJ. Bruce Fields status = nfserr_openmode; 5081f9d7562fSJ. Bruce Fields goto out; 5082f9d7562fSJ. Bruce Fields } 508321179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lock_sop; 508421179d81SJeff Layton file_lock->fl_pid = current->tgid; 508521179d81SJeff Layton file_lock->fl_file = filp; 508621179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 508721179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 508821179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 508921179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 509021179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 50911da177e4SLinus Torvalds 509221179d81SJeff Layton conflock = locks_alloc_lock(); 509321179d81SJeff Layton if (!conflock) { 509421179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 509521179d81SJeff Layton status = nfserr_jukebox; 509621179d81SJeff Layton goto out; 509721179d81SJeff Layton } 50981da177e4SLinus Torvalds 509921179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); 5100b8dd7b9aSAl Viro switch (-err) { 51011da177e4SLinus Torvalds case 0: /* success! */ 5102dcef0413SJ. Bruce Fields update_stateid(&lock_stp->st_stid.sc_stateid); 5103dcef0413SJ. Bruce Fields memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, 51041da177e4SLinus Torvalds sizeof(stateid_t)); 5105b8dd7b9aSAl Viro status = 0; 5106eb76b3fdSAndy Adamson break; 5107eb76b3fdSAndy Adamson case (EAGAIN): /* conflock holds conflicting lock */ 5108eb76b3fdSAndy Adamson status = nfserr_denied; 5109eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 511021179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 5111eb76b3fdSAndy Adamson break; 51121da177e4SLinus Torvalds case (EDEADLK): 51131da177e4SLinus Torvalds status = nfserr_deadlock; 5114eb76b3fdSAndy Adamson break; 51151da177e4SLinus Torvalds default: 5116fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 51173e772463SJ. Bruce Fields status = nfserrno(err); 5118eb76b3fdSAndy Adamson break; 51191da177e4SLinus Torvalds } 51201da177e4SLinus Torvalds out: 5121de18643dSTrond Myklebust if (filp) 5122de18643dSTrond Myklebust fput(filp); 51235db1c03fSJeff Layton if (lock_stp) { 51245db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 51255db1c03fSJeff Layton if (cstate->replay_owner && 51265db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 51275db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 51285db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 51295db1c03fSJeff Layton 51305db1c03fSJeff Layton /* 51315db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 51325db1c03fSJeff Layton * returning an error, then just go ahead and release it. 51335db1c03fSJeff Layton */ 51345db1c03fSJeff Layton if (status && new) 51355db1c03fSJeff Layton release_lock_stateid(lock_stp); 51365db1c03fSJeff Layton 51373d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 51385db1c03fSJeff Layton } 51390667b1e9STrond Myklebust if (open_stp) 51400667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 51419411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 51421da177e4SLinus Torvalds nfs4_unlock_state(); 514321179d81SJeff Layton if (file_lock) 514421179d81SJeff Layton locks_free_lock(file_lock); 514521179d81SJeff Layton if (conflock) 514621179d81SJeff Layton locks_free_lock(conflock); 51471da177e4SLinus Torvalds return status; 51481da177e4SLinus Torvalds } 51491da177e4SLinus Torvalds 51501da177e4SLinus Torvalds /* 515155ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 515255ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 515355ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 515455ef1274SJ. Bruce Fields * inode operation.) 515555ef1274SJ. Bruce Fields */ 515604da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 515755ef1274SJ. Bruce Fields { 515855ef1274SJ. Bruce Fields struct file *file; 515904da6e9dSAl Viro __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 516004da6e9dSAl Viro if (!err) { 516104da6e9dSAl Viro err = nfserrno(vfs_test_lock(file, lock)); 516255ef1274SJ. Bruce Fields nfsd_close(file); 516304da6e9dSAl Viro } 516455ef1274SJ. Bruce Fields return err; 516555ef1274SJ. Bruce Fields } 516655ef1274SJ. Bruce Fields 516755ef1274SJ. Bruce Fields /* 51681da177e4SLinus Torvalds * LOCKT operation 51691da177e4SLinus Torvalds */ 5170b37ad28bSAl Viro __be32 5171ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5172ca364317SJ.Bruce Fields struct nfsd4_lockt *lockt) 51731da177e4SLinus Torvalds { 517421179d81SJeff Layton struct file_lock *file_lock = NULL; 51755db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 5176b37ad28bSAl Viro __be32 status; 51777f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 51781da177e4SLinus Torvalds 51795ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 51801da177e4SLinus Torvalds return nfserr_grace; 51811da177e4SLinus Torvalds 51821da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 51831da177e4SLinus Torvalds return nfserr_inval; 51841da177e4SLinus Torvalds 51851da177e4SLinus Torvalds nfs4_lock_state(); 51861da177e4SLinus Torvalds 51879b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 51884b24ca7dSJeff Layton status = lookup_clientid(&lockt->lt_clientid, cstate, nn); 51899b2ef62bSJ. Bruce Fields if (status) 51901da177e4SLinus Torvalds goto out; 51919b2ef62bSJ. Bruce Fields } 51921da177e4SLinus Torvalds 519375c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 51941da177e4SLinus Torvalds goto out; 51951da177e4SLinus Torvalds 519621179d81SJeff Layton file_lock = locks_alloc_lock(); 519721179d81SJeff Layton if (!file_lock) { 519821179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 519921179d81SJeff Layton status = nfserr_jukebox; 520021179d81SJeff Layton goto out; 520121179d81SJeff Layton } 520221179d81SJeff Layton locks_init_lock(file_lock); 52031da177e4SLinus Torvalds switch (lockt->lt_type) { 52041da177e4SLinus Torvalds case NFS4_READ_LT: 52051da177e4SLinus Torvalds case NFS4_READW_LT: 520621179d81SJeff Layton file_lock->fl_type = F_RDLCK; 52071da177e4SLinus Torvalds break; 52081da177e4SLinus Torvalds case NFS4_WRITE_LT: 52091da177e4SLinus Torvalds case NFS4_WRITEW_LT: 521021179d81SJeff Layton file_lock->fl_type = F_WRLCK; 52111da177e4SLinus Torvalds break; 52121da177e4SLinus Torvalds default: 52132fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 52141da177e4SLinus Torvalds status = nfserr_inval; 52151da177e4SLinus Torvalds goto out; 52161da177e4SLinus Torvalds } 52171da177e4SLinus Torvalds 5218b3c32bcdSTrond Myklebust lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner, nn); 5219fe0750e5SJ. Bruce Fields if (lo) 522021179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 522121179d81SJeff Layton file_lock->fl_pid = current->tgid; 522221179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 52231da177e4SLinus Torvalds 522421179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 522521179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 52261da177e4SLinus Torvalds 522721179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 52281da177e4SLinus Torvalds 522921179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 523004da6e9dSAl Viro if (status) 5231fd85b817SMarc Eshel goto out; 523204da6e9dSAl Viro 523321179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 52341da177e4SLinus Torvalds status = nfserr_denied; 523521179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 52361da177e4SLinus Torvalds } 52371da177e4SLinus Torvalds out: 52385db1c03fSJeff Layton if (lo) 52395db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 52401da177e4SLinus Torvalds nfs4_unlock_state(); 524121179d81SJeff Layton if (file_lock) 524221179d81SJeff Layton locks_free_lock(file_lock); 52431da177e4SLinus Torvalds return status; 52441da177e4SLinus Torvalds } 52451da177e4SLinus Torvalds 5246b37ad28bSAl Viro __be32 5247ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5248a4f1706aSJ.Bruce Fields struct nfsd4_locku *locku) 52491da177e4SLinus Torvalds { 5250dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 52511da177e4SLinus Torvalds struct file *filp = NULL; 525221179d81SJeff Layton struct file_lock *file_lock = NULL; 5253b37ad28bSAl Viro __be32 status; 5254b8dd7b9aSAl Viro int err; 52553320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 52561da177e4SLinus Torvalds 52571da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 52581da177e4SLinus Torvalds (long long) locku->lu_offset, 52591da177e4SLinus Torvalds (long long) locku->lu_length); 52601da177e4SLinus Torvalds 52611da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 52621da177e4SLinus Torvalds return nfserr_inval; 52631da177e4SLinus Torvalds 52641da177e4SLinus Torvalds nfs4_lock_state(); 52651da177e4SLinus Torvalds 52669072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 52673320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 52683320fef1SStanislav Kinsbursky &stp, nn); 52699072d5c6SJ. Bruce Fields if (status) 52701da177e4SLinus Torvalds goto out; 527111b9164aSTrond Myklebust filp = find_any_file(stp->st_stid.sc_file); 5272f9d7562fSJ. Bruce Fields if (!filp) { 5273f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 5274858cc573STrond Myklebust goto put_stateid; 5275f9d7562fSJ. Bruce Fields } 527621179d81SJeff Layton file_lock = locks_alloc_lock(); 527721179d81SJeff Layton if (!file_lock) { 527821179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 527921179d81SJeff Layton status = nfserr_jukebox; 5280de18643dSTrond Myklebust goto fput; 528121179d81SJeff Layton } 528221179d81SJeff Layton locks_init_lock(file_lock); 528321179d81SJeff Layton file_lock->fl_type = F_UNLCK; 52840a262ffbSJ. Bruce Fields file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); 528521179d81SJeff Layton file_lock->fl_pid = current->tgid; 528621179d81SJeff Layton file_lock->fl_file = filp; 528721179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 528821179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 528921179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 52901da177e4SLinus Torvalds 529121179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 529221179d81SJeff Layton locku->lu_length); 529321179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 52941da177e4SLinus Torvalds 529521179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); 5296b8dd7b9aSAl Viro if (err) { 5297fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 52981da177e4SLinus Torvalds goto out_nfserr; 52991da177e4SLinus Torvalds } 5300dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 5301dcef0413SJ. Bruce Fields memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 5302de18643dSTrond Myklebust fput: 5303de18643dSTrond Myklebust fput(filp); 5304858cc573STrond Myklebust put_stateid: 5305858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 53061da177e4SLinus Torvalds out: 53079411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 53081da177e4SLinus Torvalds nfs4_unlock_state(); 530921179d81SJeff Layton if (file_lock) 531021179d81SJeff Layton locks_free_lock(file_lock); 53111da177e4SLinus Torvalds return status; 53121da177e4SLinus Torvalds 53131da177e4SLinus Torvalds out_nfserr: 5314b8dd7b9aSAl Viro status = nfserrno(err); 5315de18643dSTrond Myklebust goto fput; 53161da177e4SLinus Torvalds } 53171da177e4SLinus Torvalds 53181da177e4SLinus Torvalds /* 53191da177e4SLinus Torvalds * returns 5320f9c00c3aSJeff Layton * true: locks held by lockowner 5321f9c00c3aSJeff Layton * false: no locks held by lockowner 53221da177e4SLinus Torvalds */ 5323f9c00c3aSJeff Layton static bool 5324f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 53251da177e4SLinus Torvalds { 53261da177e4SLinus Torvalds struct file_lock **flpp; 5327f9c00c3aSJeff Layton int status = false; 5328f9c00c3aSJeff Layton struct file *filp = find_any_file(fp); 5329f9c00c3aSJeff Layton struct inode *inode; 5330f9c00c3aSJeff Layton 5331f9c00c3aSJeff Layton if (!filp) { 5332f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 5333f9c00c3aSJeff Layton WARN_ON_ONCE(1); 5334f9c00c3aSJeff Layton return status; 5335f9c00c3aSJeff Layton } 5336f9c00c3aSJeff Layton 5337f9c00c3aSJeff Layton inode = file_inode(filp); 53381da177e4SLinus Torvalds 53391c8c601aSJeff Layton spin_lock(&inode->i_lock); 53401da177e4SLinus Torvalds for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { 5341796dadfdSJ. Bruce Fields if ((*flpp)->fl_owner == (fl_owner_t)lowner) { 5342f9c00c3aSJeff Layton status = true; 5343f9c00c3aSJeff Layton break; 53441da177e4SLinus Torvalds } 5345796dadfdSJ. Bruce Fields } 53461c8c601aSJeff Layton spin_unlock(&inode->i_lock); 5347f9c00c3aSJeff Layton fput(filp); 53481da177e4SLinus Torvalds return status; 53491da177e4SLinus Torvalds } 53501da177e4SLinus Torvalds 5351b37ad28bSAl Viro __be32 5352b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 5353b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 5354b591480bSJ.Bruce Fields struct nfsd4_release_lockowner *rlockowner) 53551da177e4SLinus Torvalds { 53561da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 5357fd44907cSJeff Layton struct nfs4_stateowner *sop = NULL, *tmp; 5358fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 5359dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 53601da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 536116bfdaafSJ. Bruce Fields unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); 5362b37ad28bSAl Viro __be32 status; 53637f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 53641da177e4SLinus Torvalds 53651da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 53661da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 53671da177e4SLinus Torvalds 53681da177e4SLinus Torvalds nfs4_lock_state(); 53691da177e4SLinus Torvalds 53704b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 53719b2ef62bSJ. Bruce Fields if (status) 53729b2ef62bSJ. Bruce Fields goto out; 53739b2ef62bSJ. Bruce Fields 53741da177e4SLinus Torvalds status = nfserr_locks_held; 537506f1f864SJ. Bruce Fields 5376fd44907cSJeff Layton /* Find the matching lock stateowner */ 5377fd44907cSJeff Layton list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) { 5378fd44907cSJeff Layton if (tmp->so_is_open_owner) 537916bfdaafSJ. Bruce Fields continue; 5380fd44907cSJeff Layton if (same_owner_str(tmp, owner, clid)) { 5381fd44907cSJeff Layton sop = tmp; 5382fd44907cSJeff Layton break; 5383fd44907cSJeff Layton } 5384fd44907cSJeff Layton } 5385fd44907cSJeff Layton 5386fd44907cSJeff Layton /* No matching owner found, maybe a replay? Just declare victory... */ 5387fd44907cSJeff Layton if (!sop) { 5388fd44907cSJeff Layton status = nfs_ok; 5389fd44907cSJeff Layton goto out; 5390fd44907cSJeff Layton } 5391fd44907cSJeff Layton 5392fe0750e5SJ. Bruce Fields lo = lockowner(sop); 5393fd44907cSJeff Layton /* see if there are still any locks associated with it */ 5394fd44907cSJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 539511b9164aSTrond Myklebust if (check_for_locks(stp->st_stid.sc_file, lo)) 53961da177e4SLinus Torvalds goto out; 53971da177e4SLinus Torvalds } 5398fd44907cSJeff Layton 53991da177e4SLinus Torvalds status = nfs_ok; 5400fe0750e5SJ. Bruce Fields release_lockowner(lo); 54011da177e4SLinus Torvalds out: 54021da177e4SLinus Torvalds nfs4_unlock_state(); 54031da177e4SLinus Torvalds return status; 54041da177e4SLinus Torvalds } 54051da177e4SLinus Torvalds 54061da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 5407a55370a3SNeilBrown alloc_reclaim(void) 54081da177e4SLinus Torvalds { 5409a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 54101da177e4SLinus Torvalds } 54111da177e4SLinus Torvalds 54120ce0c2b5SJeff Layton bool 541352e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 5414c7b9a459SNeilBrown { 54150ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 5416c7b9a459SNeilBrown 541752e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 54180ce0c2b5SJeff Layton return (crp && crp->cr_clp); 5419c7b9a459SNeilBrown } 5420c7b9a459SNeilBrown 54211da177e4SLinus Torvalds /* 54221da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 54231da177e4SLinus Torvalds */ 5424772a9bbbSJeff Layton struct nfs4_client_reclaim * 542552e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 54261da177e4SLinus Torvalds { 54271da177e4SLinus Torvalds unsigned int strhashval; 5428772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 54291da177e4SLinus Torvalds 5430a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 5431a55370a3SNeilBrown crp = alloc_reclaim(); 5432772a9bbbSJeff Layton if (crp) { 5433a55370a3SNeilBrown strhashval = clientstr_hashval(name); 54341da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 543552e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 5436a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 54370ce0c2b5SJeff Layton crp->cr_clp = NULL; 543852e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 5439772a9bbbSJeff Layton } 5440772a9bbbSJeff Layton return crp; 54411da177e4SLinus Torvalds } 54421da177e4SLinus Torvalds 54432a4317c5SJeff Layton void 544452e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 5445ce30e539SJeff Layton { 5446ce30e539SJeff Layton list_del(&crp->cr_strhash); 5447ce30e539SJeff Layton kfree(crp); 544852e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 5449ce30e539SJeff Layton } 5450ce30e539SJeff Layton 5451ce30e539SJeff Layton void 545252e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 54531da177e4SLinus Torvalds { 54541da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 54551da177e4SLinus Torvalds int i; 54561da177e4SLinus Torvalds 54571da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 545852e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 545952e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 54601da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 546152e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 54621da177e4SLinus Torvalds } 54631da177e4SLinus Torvalds } 5464063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 54651da177e4SLinus Torvalds } 54661da177e4SLinus Torvalds 54671da177e4SLinus Torvalds /* 54681da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 54692a4317c5SJeff Layton struct nfs4_client_reclaim * 547052e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 54711da177e4SLinus Torvalds { 54721da177e4SLinus Torvalds unsigned int strhashval; 54731da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 54741da177e4SLinus Torvalds 5475278c931cSJeff Layton dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 54761da177e4SLinus Torvalds 5477278c931cSJeff Layton strhashval = clientstr_hashval(recdir); 547852e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 5479278c931cSJeff Layton if (same_name(crp->cr_recdir, recdir)) { 54801da177e4SLinus Torvalds return crp; 54811da177e4SLinus Torvalds } 54821da177e4SLinus Torvalds } 54831da177e4SLinus Torvalds return NULL; 54841da177e4SLinus Torvalds } 54851da177e4SLinus Torvalds 54861da177e4SLinus Torvalds /* 54871da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 54881da177e4SLinus Torvalds */ 5489b37ad28bSAl Viro __be32 54900fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 54910fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 54920fe492dbSTrond Myklebust struct nfsd_net *nn) 54931da177e4SLinus Torvalds { 54940fe492dbSTrond Myklebust __be32 status; 5495a52d726bSJeff Layton 5496a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 54970fe492dbSTrond Myklebust status = lookup_clientid(clid, cstate, nn); 54980fe492dbSTrond Myklebust if (status) 5499a52d726bSJeff Layton return nfserr_reclaim_bad; 5500a52d726bSJeff Layton 55010fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 55020fe492dbSTrond Myklebust return nfserr_reclaim_bad; 55030fe492dbSTrond Myklebust 55040fe492dbSTrond Myklebust return nfs_ok; 55051da177e4SLinus Torvalds } 55061da177e4SLinus Torvalds 550765178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 550865178db4SBryan Schumaker 550944e34da6SBryan Schumaker u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) 551044e34da6SBryan Schumaker { 5511221a6876SJ. Bruce Fields if (mark_client_expired(clp)) 5512221a6876SJ. Bruce Fields return 0; 551344e34da6SBryan Schumaker expire_client(clp); 551444e34da6SBryan Schumaker return 1; 551544e34da6SBryan Schumaker } 551644e34da6SBryan Schumaker 5517184c1847SBryan Schumaker u64 nfsd_print_client(struct nfs4_client *clp, u64 num) 5518184c1847SBryan Schumaker { 5519184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 55200a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 5521184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s\n", buf); 5522184c1847SBryan Schumaker return 1; 5523184c1847SBryan Schumaker } 5524184c1847SBryan Schumaker 5525184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 5526184c1847SBryan Schumaker const char *type) 5527184c1847SBryan Schumaker { 5528184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 55290a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 5530184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 5531184c1847SBryan Schumaker } 5532184c1847SBryan Schumaker 55333c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 55343c87b9b7STrond Myklebust void (*func)(struct nfs4_ol_stateid *)) 5535fc29171fSBryan Schumaker { 5536fc29171fSBryan Schumaker struct nfs4_openowner *oop; 5537fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 55383c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 5539fc29171fSBryan Schumaker u64 count = 0; 5540fc29171fSBryan Schumaker 5541fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 55423c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 55433c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 55443c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 55453c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 5546fc29171fSBryan Schumaker if (func) 55473c87b9b7STrond Myklebust func(lst); 5548fc29171fSBryan Schumaker if (++count == max) 5549fc29171fSBryan Schumaker return count; 5550fc29171fSBryan Schumaker } 5551fc29171fSBryan Schumaker } 5552fc29171fSBryan Schumaker } 5553fc29171fSBryan Schumaker 5554fc29171fSBryan Schumaker return count; 5555fc29171fSBryan Schumaker } 5556fc29171fSBryan Schumaker 5557fc29171fSBryan Schumaker u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) 5558fc29171fSBryan Schumaker { 55593c87b9b7STrond Myklebust return nfsd_foreach_client_lock(clp, max, release_lock_stateid); 5560fc29171fSBryan Schumaker } 5561fc29171fSBryan Schumaker 5562184c1847SBryan Schumaker u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) 5563184c1847SBryan Schumaker { 5564184c1847SBryan Schumaker u64 count = nfsd_foreach_client_lock(clp, max, NULL); 5565184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 5566184c1847SBryan Schumaker return count; 5567184c1847SBryan Schumaker } 5568184c1847SBryan Schumaker 55694dbdbda8SBryan Schumaker static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) 55704dbdbda8SBryan Schumaker { 55714dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 55724dbdbda8SBryan Schumaker u64 count = 0; 55734dbdbda8SBryan Schumaker 55744dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 55754dbdbda8SBryan Schumaker if (func) 55764dbdbda8SBryan Schumaker func(oop); 55774dbdbda8SBryan Schumaker if (++count == max) 55784dbdbda8SBryan Schumaker break; 55794dbdbda8SBryan Schumaker } 55804dbdbda8SBryan Schumaker 55814dbdbda8SBryan Schumaker return count; 55824dbdbda8SBryan Schumaker } 55834dbdbda8SBryan Schumaker 55844dbdbda8SBryan Schumaker u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) 55854dbdbda8SBryan Schumaker { 55864dbdbda8SBryan Schumaker return nfsd_foreach_client_open(clp, max, release_openowner); 55874dbdbda8SBryan Schumaker } 55884dbdbda8SBryan Schumaker 5589184c1847SBryan Schumaker u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) 5590184c1847SBryan Schumaker { 5591184c1847SBryan Schumaker u64 count = nfsd_foreach_client_open(clp, max, NULL); 5592184c1847SBryan Schumaker nfsd_print_count(clp, count, "open files"); 5593184c1847SBryan Schumaker return count; 5594184c1847SBryan Schumaker } 5595184c1847SBryan Schumaker 5596269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 5597269de30fSBryan Schumaker struct list_head *victims) 5598269de30fSBryan Schumaker { 5599269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 5600269de30fSBryan Schumaker u64 count = 0; 5601269de30fSBryan Schumaker 5602cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 5603269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 5604dff1399fSJeff Layton if (victims) { 5605dff1399fSJeff Layton /* 5606dff1399fSJeff Layton * It's not safe to mess with delegations that have a 5607dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 5608dff1399fSJeff Layton * and could be processed by the laundromat outside of 5609dff1399fSJeff Layton * the state_lock. Just leave them be. 5610dff1399fSJeff Layton */ 5611dff1399fSJeff Layton if (dp->dl_time != 0) 5612dff1399fSJeff Layton continue; 5613dff1399fSJeff Layton 561442690676SJeff Layton unhash_delegation_locked(dp); 561542690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 5616dff1399fSJeff Layton } 5617269de30fSBryan Schumaker if (++count == max) 5618269de30fSBryan Schumaker break; 5619269de30fSBryan Schumaker } 5620269de30fSBryan Schumaker return count; 5621269de30fSBryan Schumaker } 5622269de30fSBryan Schumaker 5623269de30fSBryan Schumaker u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) 5624269de30fSBryan Schumaker { 5625269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 5626269de30fSBryan Schumaker LIST_HEAD(victims); 5627269de30fSBryan Schumaker u64 count; 5628269de30fSBryan Schumaker 5629cdc97505SBenny Halevy spin_lock(&state_lock); 5630269de30fSBryan Schumaker count = nfsd_find_all_delegations(clp, max, &victims); 5631cdc97505SBenny Halevy spin_unlock(&state_lock); 5632269de30fSBryan Schumaker 56332d4a532dSJeff Layton list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) { 56342d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 56353bd64a5bSJ. Bruce Fields revoke_delegation(dp); 56362d4a532dSJeff Layton } 5637269de30fSBryan Schumaker 5638269de30fSBryan Schumaker return count; 5639269de30fSBryan Schumaker } 5640269de30fSBryan Schumaker 5641269de30fSBryan Schumaker u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) 5642269de30fSBryan Schumaker { 5643dff1399fSJeff Layton struct nfs4_delegation *dp; 5644269de30fSBryan Schumaker LIST_HEAD(victims); 5645269de30fSBryan Schumaker u64 count; 5646269de30fSBryan Schumaker 5647cdc97505SBenny Halevy spin_lock(&state_lock); 5648269de30fSBryan Schumaker count = nfsd_find_all_delegations(clp, max, &victims); 5649dff1399fSJeff Layton while (!list_empty(&victims)) { 5650dff1399fSJeff Layton dp = list_first_entry(&victims, struct nfs4_delegation, 5651dff1399fSJeff Layton dl_recall_lru); 5652dff1399fSJeff Layton list_del_init(&dp->dl_recall_lru); 5653dff1399fSJeff Layton dp->dl_time = 0; 5654269de30fSBryan Schumaker nfsd_break_one_deleg(dp); 5655dff1399fSJeff Layton } 5656cdc97505SBenny Halevy spin_unlock(&state_lock); 5657269de30fSBryan Schumaker 5658269de30fSBryan Schumaker return count; 5659269de30fSBryan Schumaker } 5660269de30fSBryan Schumaker 5661184c1847SBryan Schumaker u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) 5662184c1847SBryan Schumaker { 5663184c1847SBryan Schumaker u64 count = 0; 5664184c1847SBryan Schumaker 5665cdc97505SBenny Halevy spin_lock(&state_lock); 5666184c1847SBryan Schumaker count = nfsd_find_all_delegations(clp, max, NULL); 5667cdc97505SBenny Halevy spin_unlock(&state_lock); 5668184c1847SBryan Schumaker 5669184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 5670184c1847SBryan Schumaker return count; 5671184c1847SBryan Schumaker } 5672184c1847SBryan Schumaker 567344e34da6SBryan Schumaker u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) 567465178db4SBryan Schumaker { 567565178db4SBryan Schumaker struct nfs4_client *clp, *next; 567644e34da6SBryan Schumaker u64 count = 0; 56773320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); 567865178db4SBryan Schumaker 567944e34da6SBryan Schumaker if (!nfsd_netns_ready(nn)) 568044e34da6SBryan Schumaker return 0; 568144e34da6SBryan Schumaker 56825ed58bb2SStanislav Kinsbursky list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 568344e34da6SBryan Schumaker count += func(clp, max - count); 568444e34da6SBryan Schumaker if ((max != 0) && (count >= max)) 568565178db4SBryan Schumaker break; 568665178db4SBryan Schumaker } 568765178db4SBryan Schumaker 568844e34da6SBryan Schumaker return count; 568944e34da6SBryan Schumaker } 569044e34da6SBryan Schumaker 56916c1e82a4SBryan Schumaker struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 56926c1e82a4SBryan Schumaker { 56936c1e82a4SBryan Schumaker struct nfs4_client *clp; 56946c1e82a4SBryan Schumaker struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); 56956c1e82a4SBryan Schumaker 56966c1e82a4SBryan Schumaker if (!nfsd_netns_ready(nn)) 56976c1e82a4SBryan Schumaker return NULL; 56986c1e82a4SBryan Schumaker 56996c1e82a4SBryan Schumaker list_for_each_entry(clp, &nn->client_lru, cl_lru) { 57006c1e82a4SBryan Schumaker if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 57016c1e82a4SBryan Schumaker return clp; 57026c1e82a4SBryan Schumaker } 57036c1e82a4SBryan Schumaker return NULL; 57046c1e82a4SBryan Schumaker } 57056c1e82a4SBryan Schumaker 570665178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 570765178db4SBryan Schumaker 5708c2f1a551SMeelap Shah /* 5709c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 5710c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 5711c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 5712c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 5713c2f1a551SMeelap Shah * 5714c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 5715c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 5716c2f1a551SMeelap Shah */ 5717c2f1a551SMeelap Shah static void 5718c2f1a551SMeelap Shah set_max_delegations(void) 5719c2f1a551SMeelap Shah { 5720c2f1a551SMeelap Shah /* 5721c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 5722c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 5723c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 5724c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 5725c2f1a551SMeelap Shah */ 5726c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 5727c2f1a551SMeelap Shah } 5728c2f1a551SMeelap Shah 5729d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 57308daae4dcSStanislav Kinsbursky { 57318daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 57328daae4dcSStanislav Kinsbursky int i; 57338daae4dcSStanislav Kinsbursky 57348daae4dcSStanislav Kinsbursky nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * 57358daae4dcSStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 57368daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 5737382a62e7SStanislav Kinsbursky goto err; 57380a7ec377SStanislav Kinsbursky nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * 57390a7ec377SStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 57400a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 57410a7ec377SStanislav Kinsbursky goto err_unconf_id; 57429b531137SStanislav Kinsbursky nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * 57439b531137SStanislav Kinsbursky OWNER_HASH_SIZE, GFP_KERNEL); 57449b531137SStanislav Kinsbursky if (!nn->ownerstr_hashtbl) 57459b531137SStanislav Kinsbursky goto err_ownerstr; 57461872de0eSStanislav Kinsbursky nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * 57471872de0eSStanislav Kinsbursky SESSION_HASH_SIZE, GFP_KERNEL); 57481872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 57491872de0eSStanislav Kinsbursky goto err_sessionid; 57508daae4dcSStanislav Kinsbursky 5751382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 57528daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 57530a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 5754382a62e7SStanislav Kinsbursky } 57559b531137SStanislav Kinsbursky for (i = 0; i < OWNER_HASH_SIZE; i++) 57569b531137SStanislav Kinsbursky INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); 57571872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 57581872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 5759382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 5760a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 57615ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 576273758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 5763e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 5764c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 57658daae4dcSStanislav Kinsbursky 576609121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 5767d85ed443SStanislav Kinsbursky get_net(net); 576809121281SStanislav Kinsbursky 57698daae4dcSStanislav Kinsbursky return 0; 5770382a62e7SStanislav Kinsbursky 57711872de0eSStanislav Kinsbursky err_sessionid: 577220e9e2bcSStanislav Kinsbursky kfree(nn->ownerstr_hashtbl); 57739b531137SStanislav Kinsbursky err_ownerstr: 57749b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 57750a7ec377SStanislav Kinsbursky err_unconf_id: 57760a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 5777382a62e7SStanislav Kinsbursky err: 5778382a62e7SStanislav Kinsbursky return -ENOMEM; 57798daae4dcSStanislav Kinsbursky } 57808daae4dcSStanislav Kinsbursky 57818daae4dcSStanislav Kinsbursky static void 57824dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 57838daae4dcSStanislav Kinsbursky { 57848daae4dcSStanislav Kinsbursky int i; 57858daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 57868daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 57878daae4dcSStanislav Kinsbursky 57888daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 57898daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 57908daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 57918daae4dcSStanislav Kinsbursky destroy_client(clp); 57928daae4dcSStanislav Kinsbursky } 57938daae4dcSStanislav Kinsbursky } 5794a99454aaSStanislav Kinsbursky 57952b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 57962b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 57972b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 5798a99454aaSStanislav Kinsbursky destroy_client(clp); 5799a99454aaSStanislav Kinsbursky } 58002b905635SKinglong Mee } 5801a99454aaSStanislav Kinsbursky 58021872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 58039b531137SStanislav Kinsbursky kfree(nn->ownerstr_hashtbl); 58040a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 58058daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 58064dce0ac9SStanislav Kinsbursky put_net(net); 58078daae4dcSStanislav Kinsbursky } 58088daae4dcSStanislav Kinsbursky 5809f252bc68SStanislav Kinsbursky int 5810d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 5811ac4d8ff2SNeilBrown { 58125e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5813b5a1a81eSJ. Bruce Fields int ret; 5814b5a1a81eSJ. Bruce Fields 5815d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 58168daae4dcSStanislav Kinsbursky if (ret) 58178daae4dcSStanislav Kinsbursky return ret; 58185e1533c7SStanislav Kinsbursky nfsd4_client_tracking_init(net); 58192c142baaSStanislav Kinsbursky nn->boot_time = get_seconds(); 58205ccb0066SStanislav Kinsbursky locks_start_grace(net, &nn->nfsd4_manager); 5821a51c84edSStanislav Kinsbursky nn->grace_ended = false; 5822d85ed443SStanislav Kinsbursky printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", 58235284b44eSStanislav Kinsbursky nn->nfsd4_grace, net); 58245284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 5825d85ed443SStanislav Kinsbursky return 0; 5826a6d6b781SJeff Layton } 5827d85ed443SStanislav Kinsbursky 5828d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 5829d85ed443SStanislav Kinsbursky 5830d85ed443SStanislav Kinsbursky int 5831d85ed443SStanislav Kinsbursky nfs4_state_start(void) 5832d85ed443SStanislav Kinsbursky { 5833d85ed443SStanislav Kinsbursky int ret; 5834d85ed443SStanislav Kinsbursky 5835d85ed443SStanislav Kinsbursky ret = set_callback_cred(); 5836d85ed443SStanislav Kinsbursky if (ret) 5837d85ed443SStanislav Kinsbursky return -ENOMEM; 583858da282bSNeilBrown laundry_wq = create_singlethread_workqueue("nfsd4"); 5839a6d6b781SJeff Layton if (laundry_wq == NULL) { 5840a6d6b781SJeff Layton ret = -ENOMEM; 5841a6d6b781SJeff Layton goto out_recovery; 5842a6d6b781SJeff Layton } 5843b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 5844b5a1a81eSJ. Bruce Fields if (ret) 5845b5a1a81eSJ. Bruce Fields goto out_free_laundry; 584609121281SStanislav Kinsbursky 5847c2f1a551SMeelap Shah set_max_delegations(); 5848d85ed443SStanislav Kinsbursky 5849b5a1a81eSJ. Bruce Fields return 0; 5850d85ed443SStanislav Kinsbursky 5851b5a1a81eSJ. Bruce Fields out_free_laundry: 5852b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 5853a6d6b781SJeff Layton out_recovery: 5854b5a1a81eSJ. Bruce Fields return ret; 58551da177e4SLinus Torvalds } 58561da177e4SLinus Torvalds 5857f252bc68SStanislav Kinsbursky void 58584dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 58591da177e4SLinus Torvalds { 58601da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 58611da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 58624dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 58631da177e4SLinus Torvalds 58644dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 58654dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 5866ac55fdc4SJeff Layton 5867e50a26dcSJ. Bruce Fields nfs4_lock_state(); 58681da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 5869cdc97505SBenny Halevy spin_lock(&state_lock); 5870e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 58711da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 587242690676SJeff Layton unhash_delegation_locked(dp); 587342690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 58741da177e4SLinus Torvalds } 5875cdc97505SBenny Halevy spin_unlock(&state_lock); 58761da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 58771da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 587842690676SJeff Layton list_del_init(&dp->dl_recall_lru); 58796011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 58801da177e4SLinus Torvalds } 58811da177e4SLinus Torvalds 58823320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 58834dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 5884e50a26dcSJ. Bruce Fields nfs4_unlock_state(); 58851da177e4SLinus Torvalds } 58861da177e4SLinus Torvalds 58871da177e4SLinus Torvalds void 58881da177e4SLinus Torvalds nfs4_state_shutdown(void) 58891da177e4SLinus Torvalds { 58905e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 5891c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 58921da177e4SLinus Torvalds } 58938b70484cSTigran Mkrtchyan 58948b70484cSTigran Mkrtchyan static void 58958b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 58968b70484cSTigran Mkrtchyan { 589737c593c5STigran Mkrtchyan if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) 589837c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 58998b70484cSTigran Mkrtchyan } 59008b70484cSTigran Mkrtchyan 59018b70484cSTigran Mkrtchyan static void 59028b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 59038b70484cSTigran Mkrtchyan { 590437c593c5STigran Mkrtchyan if (cstate->minorversion) { 590537c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 590637c593c5STigran Mkrtchyan SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 590737c593c5STigran Mkrtchyan } 590837c593c5STigran Mkrtchyan } 590937c593c5STigran Mkrtchyan 591037c593c5STigran Mkrtchyan void 591137c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 591237c593c5STigran Mkrtchyan { 591337c593c5STigran Mkrtchyan CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 59148b70484cSTigran Mkrtchyan } 59158b70484cSTigran Mkrtchyan 591662cd4a59STigran Mkrtchyan /* 591762cd4a59STigran Mkrtchyan * functions to set current state id 591862cd4a59STigran Mkrtchyan */ 59198b70484cSTigran Mkrtchyan void 59209428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 59219428fe1aSTigran Mkrtchyan { 59229428fe1aSTigran Mkrtchyan put_stateid(cstate, &odp->od_stateid); 59239428fe1aSTigran Mkrtchyan } 59249428fe1aSTigran Mkrtchyan 59259428fe1aSTigran Mkrtchyan void 59268b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open) 59278b70484cSTigran Mkrtchyan { 59288b70484cSTigran Mkrtchyan put_stateid(cstate, &open->op_stateid); 59298b70484cSTigran Mkrtchyan } 59308b70484cSTigran Mkrtchyan 59318b70484cSTigran Mkrtchyan void 593262cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 593362cd4a59STigran Mkrtchyan { 593462cd4a59STigran Mkrtchyan put_stateid(cstate, &close->cl_stateid); 593562cd4a59STigran Mkrtchyan } 593662cd4a59STigran Mkrtchyan 593762cd4a59STigran Mkrtchyan void 593862cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock) 593962cd4a59STigran Mkrtchyan { 594062cd4a59STigran Mkrtchyan put_stateid(cstate, &lock->lk_resp_stateid); 594162cd4a59STigran Mkrtchyan } 594262cd4a59STigran Mkrtchyan 594362cd4a59STigran Mkrtchyan /* 594462cd4a59STigran Mkrtchyan * functions to consume current state id 594562cd4a59STigran Mkrtchyan */ 59461e97b519STigran Mkrtchyan 59471e97b519STigran Mkrtchyan void 59489428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 59499428fe1aSTigran Mkrtchyan { 59509428fe1aSTigran Mkrtchyan get_stateid(cstate, &odp->od_stateid); 59519428fe1aSTigran Mkrtchyan } 59529428fe1aSTigran Mkrtchyan 59539428fe1aSTigran Mkrtchyan void 59549428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp) 59559428fe1aSTigran Mkrtchyan { 59569428fe1aSTigran Mkrtchyan get_stateid(cstate, &drp->dr_stateid); 59579428fe1aSTigran Mkrtchyan } 59589428fe1aSTigran Mkrtchyan 59599428fe1aSTigran Mkrtchyan void 59601e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp) 59611e97b519STigran Mkrtchyan { 59621e97b519STigran Mkrtchyan get_stateid(cstate, &fsp->fr_stateid); 59631e97b519STigran Mkrtchyan } 59641e97b519STigran Mkrtchyan 59651e97b519STigran Mkrtchyan void 59661e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) 59671e97b519STigran Mkrtchyan { 59681e97b519STigran Mkrtchyan get_stateid(cstate, &setattr->sa_stateid); 59691e97b519STigran Mkrtchyan } 59701e97b519STigran Mkrtchyan 597162cd4a59STigran Mkrtchyan void 59728b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 59738b70484cSTigran Mkrtchyan { 59748b70484cSTigran Mkrtchyan get_stateid(cstate, &close->cl_stateid); 59758b70484cSTigran Mkrtchyan } 59768b70484cSTigran Mkrtchyan 59778b70484cSTigran Mkrtchyan void 597862cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku) 59798b70484cSTigran Mkrtchyan { 598062cd4a59STigran Mkrtchyan get_stateid(cstate, &locku->lu_stateid); 59818b70484cSTigran Mkrtchyan } 598230813e27STigran Mkrtchyan 598330813e27STigran Mkrtchyan void 598430813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read) 598530813e27STigran Mkrtchyan { 598630813e27STigran Mkrtchyan get_stateid(cstate, &read->rd_stateid); 598730813e27STigran Mkrtchyan } 598830813e27STigran Mkrtchyan 598930813e27STigran Mkrtchyan void 599030813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write) 599130813e27STigran Mkrtchyan { 599230813e27STigran Mkrtchyan get_stateid(cstate, &write->wr_stateid); 599330813e27STigran Mkrtchyan } 5994