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> 449a74af21SBoaz Harrosh #include "xdr4.h" 4506b332a5SJ. Bruce Fields #include "xdr4cb.h" 460a3adadeSJ. Bruce Fields #include "vfs.h" 47bfa4b365SJ. Bruce Fields #include "current_stateid.h" 481da177e4SLinus Torvalds 495e1533c7SStanislav Kinsbursky #include "netns.h" 505e1533c7SStanislav Kinsbursky 511da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 521da177e4SLinus Torvalds 53f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 54f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 55f32f3c2dSJ. Bruce Fields .si_generation = ~0, 56f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 57f32f3c2dSJ. Bruce Fields }; 58f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 59f32f3c2dSJ. Bruce Fields /* all fields zero */ 60f32f3c2dSJ. Bruce Fields }; 6119ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 6219ff0f28STigran Mkrtchyan .si_generation = 1, 6319ff0f28STigran Mkrtchyan }; 64f32f3c2dSJ. Bruce Fields 65ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 66fd39ca9aSNeilBrown 67f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 68f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 6919ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds /* forward declarations */ 72fe0750e5SJ. Bruce Fields static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); 731da177e4SLinus Torvalds 748b671b80SJ. Bruce Fields /* Locking: */ 758b671b80SJ. Bruce Fields 768b671b80SJ. Bruce Fields /* Currently used for almost all code touching nfsv4 state: */ 77353ab6e9SIngo Molnar static DEFINE_MUTEX(client_mutex); 781da177e4SLinus Torvalds 798b671b80SJ. Bruce Fields /* 808b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 818b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 828b671b80SJ. Bruce Fields * eventually cover more: 838b671b80SJ. Bruce Fields */ 848b671b80SJ. Bruce Fields static DEFINE_SPINLOCK(recall_lock); 858b671b80SJ. Bruce Fields 86fe0750e5SJ. Bruce Fields static struct kmem_cache *openowner_slab = NULL; 87fe0750e5SJ. Bruce Fields static struct kmem_cache *lockowner_slab = NULL; 88e18b890bSChristoph Lameter static struct kmem_cache *file_slab = NULL; 89e18b890bSChristoph Lameter static struct kmem_cache *stateid_slab = NULL; 90e18b890bSChristoph Lameter static struct kmem_cache *deleg_slab = NULL; 91e60d4398SNeilBrown 921da177e4SLinus Torvalds void 931da177e4SLinus Torvalds nfs4_lock_state(void) 941da177e4SLinus Torvalds { 95353ab6e9SIngo Molnar mutex_lock(&client_mutex); 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 9866b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 99508dc6e1SBenny Halevy 10066b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 101508dc6e1SBenny Halevy { 10266b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 10366b2b9b2SJ. Bruce Fields } 10466b2b9b2SJ. Bruce Fields 105f0f51f5cSJ. Bruce Fields void nfsd4_put_session(struct nfsd4_session *ses) 10666b2b9b2SJ. Bruce Fields { 107f0f51f5cSJ. Bruce Fields if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 108f0f51f5cSJ. Bruce Fields free_session(ses); 109f0f51f5cSJ. Bruce Fields } 110f0f51f5cSJ. Bruce Fields 111f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 112f0f51f5cSJ. Bruce Fields { 113f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 11466b2b9b2SJ. Bruce Fields return nfserr_jukebox; 11566b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 11666b2b9b2SJ. Bruce Fields return nfs_ok; 11766b2b9b2SJ. Bruce Fields } 11866b2b9b2SJ. Bruce Fields 11966b2b9b2SJ. Bruce Fields static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 12066b2b9b2SJ. Bruce Fields { 12166b2b9b2SJ. Bruce Fields if (is_session_dead(ses)) 12266b2b9b2SJ. Bruce Fields return nfserr_badsession; 12366b2b9b2SJ. Bruce Fields atomic_inc(&ses->se_ref); 12466b2b9b2SJ. Bruce Fields return nfs_ok; 125508dc6e1SBenny Halevy } 126508dc6e1SBenny Halevy 1271da177e4SLinus Torvalds void 1281da177e4SLinus Torvalds nfs4_unlock_state(void) 1291da177e4SLinus Torvalds { 130353ab6e9SIngo Molnar mutex_unlock(&client_mutex); 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 133221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 134221a6876SJ. Bruce Fields { 135221a6876SJ. Bruce Fields return clp->cl_time == 0; 136221a6876SJ. Bruce Fields } 137221a6876SJ. Bruce Fields 138221a6876SJ. Bruce Fields static __be32 mark_client_expired_locked(struct nfs4_client *clp) 139221a6876SJ. Bruce Fields { 140221a6876SJ. Bruce Fields if (atomic_read(&clp->cl_refcount)) 141221a6876SJ. Bruce Fields return nfserr_jukebox; 142221a6876SJ. Bruce Fields clp->cl_time = 0; 143221a6876SJ. Bruce Fields return nfs_ok; 144221a6876SJ. Bruce Fields } 145221a6876SJ. Bruce Fields 146221a6876SJ. Bruce Fields static __be32 mark_client_expired(struct nfs4_client *clp) 147221a6876SJ. Bruce Fields { 148221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 149221a6876SJ. Bruce Fields __be32 ret; 150221a6876SJ. Bruce Fields 151221a6876SJ. Bruce Fields spin_lock(&nn->client_lock); 152221a6876SJ. Bruce Fields ret = mark_client_expired_locked(clp); 153221a6876SJ. Bruce Fields spin_unlock(&nn->client_lock); 154221a6876SJ. Bruce Fields return ret; 155221a6876SJ. Bruce Fields } 156221a6876SJ. Bruce Fields 157221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 158221a6876SJ. Bruce Fields { 159221a6876SJ. Bruce Fields if (is_client_expired(clp)) 160221a6876SJ. Bruce Fields return nfserr_expired; 161221a6876SJ. Bruce Fields atomic_inc(&clp->cl_refcount); 162221a6876SJ. Bruce Fields return nfs_ok; 163221a6876SJ. Bruce Fields } 164221a6876SJ. Bruce Fields 165221a6876SJ. Bruce Fields /* must be called under the client_lock */ 166221a6876SJ. Bruce Fields static inline void 167221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 168221a6876SJ. Bruce Fields { 169221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 170221a6876SJ. Bruce Fields 171221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 172221a6876SJ. Bruce Fields WARN_ON(1); 173221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 174221a6876SJ. Bruce Fields __func__, 175221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 176221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 177221a6876SJ. Bruce Fields return; 178221a6876SJ. Bruce Fields } 179221a6876SJ. Bruce Fields 180221a6876SJ. Bruce Fields dprintk("renewing client (clientid %08x/%08x)\n", 181221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 182221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 183221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 184221a6876SJ. Bruce Fields clp->cl_time = get_seconds(); 185221a6876SJ. Bruce Fields } 186221a6876SJ. Bruce Fields 187221a6876SJ. Bruce Fields static inline void 188221a6876SJ. Bruce Fields renew_client(struct nfs4_client *clp) 189221a6876SJ. Bruce Fields { 190221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 191221a6876SJ. Bruce Fields 192221a6876SJ. Bruce Fields spin_lock(&nn->client_lock); 193221a6876SJ. Bruce Fields renew_client_locked(clp); 194221a6876SJ. Bruce Fields spin_unlock(&nn->client_lock); 195221a6876SJ. Bruce Fields } 196221a6876SJ. Bruce Fields 197ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 198221a6876SJ. Bruce Fields { 199221a6876SJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_refcount)) 200221a6876SJ. Bruce Fields return; 201221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 202221a6876SJ. Bruce Fields renew_client_locked(clp); 203221a6876SJ. Bruce Fields } 204221a6876SJ. Bruce Fields 205221a6876SJ. Bruce Fields void put_client_renew(struct nfs4_client *clp) 206221a6876SJ. Bruce Fields { 207221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 208221a6876SJ. Bruce Fields 209221a6876SJ. Bruce Fields if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) 210221a6876SJ. Bruce Fields return; 211221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 212221a6876SJ. Bruce Fields renew_client_locked(clp); 213221a6876SJ. Bruce Fields spin_unlock(&nn->client_lock); 214221a6876SJ. Bruce Fields } 215221a6876SJ. Bruce Fields 216221a6876SJ. Bruce Fields 2171da177e4SLinus Torvalds static inline u32 2181da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds u32 x = 0; 2231da177e4SLinus Torvalds while (nbytes--) { 2241da177e4SLinus Torvalds x *= 37; 2251da177e4SLinus Torvalds x += *cptr++; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds return x; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 23032513b40SJ. Bruce Fields static void nfsd4_free_file(struct nfs4_file *f) 23132513b40SJ. Bruce Fields { 23232513b40SJ. Bruce Fields kmem_cache_free(file_slab, f); 23332513b40SJ. Bruce Fields } 23432513b40SJ. Bruce Fields 23513cd2184SNeilBrown static inline void 23613cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 23713cd2184SNeilBrown { 2388b671b80SJ. Bruce Fields if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) { 23989876f8cSJeff Layton hlist_del(&fi->fi_hash); 2408b671b80SJ. Bruce Fields spin_unlock(&recall_lock); 2418b671b80SJ. Bruce Fields iput(fi->fi_inode); 24232513b40SJ. Bruce Fields nfsd4_free_file(fi); 2438b671b80SJ. Bruce Fields } 24413cd2184SNeilBrown } 24513cd2184SNeilBrown 24613cd2184SNeilBrown static inline void 24713cd2184SNeilBrown get_nfs4_file(struct nfs4_file *fi) 24813cd2184SNeilBrown { 2498b671b80SJ. Bruce Fields atomic_inc(&fi->fi_ref); 25013cd2184SNeilBrown } 25113cd2184SNeilBrown 252ef0f3390SNeilBrown static int num_delegations; 253697ce9beSZhang Yanfei unsigned long max_delegations; 254ef0f3390SNeilBrown 255ef0f3390SNeilBrown /* 256ef0f3390SNeilBrown * Open owner state (share locks) 257ef0f3390SNeilBrown */ 258ef0f3390SNeilBrown 25916bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 26016bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 26116bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 26216bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 263ef0f3390SNeilBrown 26416bfdaafSJ. Bruce Fields static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) 265ddc04c41SJ. Bruce Fields { 266ddc04c41SJ. Bruce Fields unsigned int ret; 267ddc04c41SJ. Bruce Fields 268ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 269ddc04c41SJ. Bruce Fields ret += clientid; 27016bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 271ddc04c41SJ. Bruce Fields } 272ef0f3390SNeilBrown 273ef0f3390SNeilBrown /* hash table for nfs4_file */ 274ef0f3390SNeilBrown #define FILE_HASH_BITS 8 275ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 27635079582SShan Wei 277ddc04c41SJ. Bruce Fields static unsigned int file_hashval(struct inode *ino) 278ddc04c41SJ. Bruce Fields { 279ddc04c41SJ. Bruce Fields /* XXX: why are we hashing on inode pointer, anyway? */ 280ddc04c41SJ. Bruce Fields return hash_ptr(ino, FILE_HASH_BITS); 281ddc04c41SJ. Bruce Fields } 282ddc04c41SJ. Bruce Fields 28389876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 284ef0f3390SNeilBrown 2853477565eSJ. Bruce Fields static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) 2863477565eSJ. Bruce Fields { 2873477565eSJ. Bruce Fields WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); 2883477565eSJ. Bruce Fields atomic_inc(&fp->fi_access[oflag]); 2893477565eSJ. Bruce Fields } 2903477565eSJ. Bruce Fields 291998db52cSJ. Bruce Fields static void nfs4_file_get_access(struct nfs4_file *fp, int oflag) 292998db52cSJ. Bruce Fields { 293998db52cSJ. Bruce Fields if (oflag == O_RDWR) { 2943477565eSJ. Bruce Fields __nfs4_file_get_access(fp, O_RDONLY); 2953477565eSJ. Bruce Fields __nfs4_file_get_access(fp, O_WRONLY); 296998db52cSJ. Bruce Fields } else 2973477565eSJ. Bruce Fields __nfs4_file_get_access(fp, oflag); 298998db52cSJ. Bruce Fields } 299998db52cSJ. Bruce Fields 300998db52cSJ. Bruce Fields static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) 301f9d7562fSJ. Bruce Fields { 302f9d7562fSJ. Bruce Fields if (fp->fi_fds[oflag]) { 303f9d7562fSJ. Bruce Fields fput(fp->fi_fds[oflag]); 304f9d7562fSJ. Bruce Fields fp->fi_fds[oflag] = NULL; 305f9d7562fSJ. Bruce Fields } 306f9d7562fSJ. Bruce Fields } 307f9d7562fSJ. Bruce Fields 308998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 309f9d7562fSJ. Bruce Fields { 310f9d7562fSJ. Bruce Fields if (atomic_dec_and_test(&fp->fi_access[oflag])) { 311f9d7562fSJ. Bruce Fields nfs4_file_put_fd(fp, oflag); 3120c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 3133d02fa29SJ. Bruce Fields nfs4_file_put_fd(fp, O_RDWR); 314f9d7562fSJ. Bruce Fields } 315f9d7562fSJ. Bruce Fields } 316f9d7562fSJ. Bruce Fields 317998db52cSJ. Bruce Fields static void nfs4_file_put_access(struct nfs4_file *fp, int oflag) 318998db52cSJ. Bruce Fields { 319998db52cSJ. Bruce Fields if (oflag == O_RDWR) { 320998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_RDONLY); 321998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 322998db52cSJ. Bruce Fields } else 323998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, oflag); 324998db52cSJ. Bruce Fields } 325998db52cSJ. Bruce Fields 3263abdb607SJ. Bruce Fields static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct 3273abdb607SJ. Bruce Fields kmem_cache *slab) 328996e0938SJ. Bruce Fields { 329996e0938SJ. Bruce Fields struct idr *stateids = &cl->cl_stateids; 3303abdb607SJ. Bruce Fields struct nfs4_stid *stid; 3313abdb607SJ. Bruce Fields int new_id; 3323abdb607SJ. Bruce Fields 3333abdb607SJ. Bruce Fields stid = kmem_cache_alloc(slab, GFP_KERNEL); 3343abdb607SJ. Bruce Fields if (!stid) 3353abdb607SJ. Bruce Fields return NULL; 336996e0938SJ. Bruce Fields 337398c33aaSJeff Layton new_id = idr_alloc_cyclic(stateids, stid, 0, 0, GFP_KERNEL); 338ebd6c707STejun Heo if (new_id < 0) 3393abdb607SJ. Bruce Fields goto out_free; 3403abdb607SJ. Bruce Fields stid->sc_client = cl; 3413abdb607SJ. Bruce Fields stid->sc_type = 0; 3423abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 3433abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 3443abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 3453abdb607SJ. Bruce Fields stid->sc_stateid.si_generation = 0; 3463abdb607SJ. Bruce Fields 347996e0938SJ. Bruce Fields /* 3483abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 3493abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 3503abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 3513abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 3523abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 3533abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 3543abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 355996e0938SJ. Bruce Fields */ 3563abdb607SJ. Bruce Fields return stid; 3573abdb607SJ. Bruce Fields out_free: 3582c44a234SWei Yongjun kmem_cache_free(slab, stid); 3593abdb607SJ. Bruce Fields return NULL; 3602a74aba7SJ. Bruce Fields } 3612a74aba7SJ. Bruce Fields 3624cdc951bSJ. Bruce Fields static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) 3634cdc951bSJ. Bruce Fields { 3644cdc951bSJ. Bruce Fields return openlockstateid(nfs4_alloc_stid(clp, stateid_slab)); 3654cdc951bSJ. Bruce Fields } 3664cdc951bSJ. Bruce Fields 3671da177e4SLinus Torvalds static struct nfs4_delegation * 36899c41515SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) 3691da177e4SLinus Torvalds { 3701da177e4SLinus Torvalds struct nfs4_delegation *dp; 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 373c2f1a551SMeelap Shah if (num_delegations > max_delegations) 374ef0f3390SNeilBrown return NULL; 375996e0938SJ. Bruce Fields dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); 3765b2d21c1SNeilBrown if (dp == NULL) 3771da177e4SLinus Torvalds return dp; 3783abdb607SJ. Bruce Fields dp->dl_stid.sc_type = NFS4_DELEG_STID; 3792a74aba7SJ. Bruce Fields /* 3802a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 3816136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 3826136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 3832a74aba7SJ. Bruce Fields */ 3842a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 385ef0f3390SNeilBrown num_delegations++; 386ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 387ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 3881da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 389bf7bd3e9SJ. Bruce Fields dp->dl_file = NULL; 39099c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 3916c02eaa1SJ. Bruce Fields fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); 3921da177e4SLinus Torvalds dp->dl_time = 0; 3931da177e4SLinus Torvalds atomic_set(&dp->dl_count, 1); 39457725155SJ. Bruce Fields nfsd4_init_callback(&dp->dl_recall); 3951da177e4SLinus Torvalds return dp; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds 39868a33961SJ. Bruce Fields static void remove_stid(struct nfs4_stid *s) 3993abdb607SJ. Bruce Fields { 4003abdb607SJ. Bruce Fields struct idr *stateids = &s->sc_client->cl_stateids; 4013abdb607SJ. Bruce Fields 4023abdb607SJ. Bruce Fields idr_remove(stateids, s->sc_stateid.si_opaque.so_id); 4033abdb607SJ. Bruce Fields } 4043abdb607SJ. Bruce Fields 4051da177e4SLinus Torvalds void 4061da177e4SLinus Torvalds nfs4_put_delegation(struct nfs4_delegation *dp) 4071da177e4SLinus Torvalds { 4081da177e4SLinus Torvalds if (atomic_dec_and_test(&dp->dl_count)) { 40968a33961SJ. Bruce Fields kmem_cache_free(deleg_slab, dp); 410ef0f3390SNeilBrown num_delegations--; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 414acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp) 4151da177e4SLinus Torvalds { 416acfdf5c3SJ. Bruce Fields if (atomic_dec_and_test(&fp->fi_delegees)) { 417acfdf5c3SJ. Bruce Fields vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); 418acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 4194ee63624SJ. Bruce Fields fput(fp->fi_deleg_file); 420acfdf5c3SJ. Bruce Fields fp->fi_deleg_file = NULL; 421acfdf5c3SJ. Bruce Fields } 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 4246136d2b4SJ. Bruce Fields static void unhash_stid(struct nfs4_stid *s) 4256136d2b4SJ. Bruce Fields { 4263abdb607SJ. Bruce Fields s->sc_type = 0; 4276136d2b4SJ. Bruce Fields } 4286136d2b4SJ. Bruce Fields 4291da177e4SLinus Torvalds /* Called under the state lock. */ 4301da177e4SLinus Torvalds static void 4311da177e4SLinus Torvalds unhash_delegation(struct nfs4_delegation *dp) 4321da177e4SLinus Torvalds { 433ea1da636SNeilBrown list_del_init(&dp->dl_perclnt); 4341da177e4SLinus Torvalds spin_lock(&recall_lock); 4355d926e8cSJ. Bruce Fields list_del_init(&dp->dl_perfile); 4361da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 4371da177e4SLinus Torvalds spin_unlock(&recall_lock); 438acfdf5c3SJ. Bruce Fields nfs4_put_deleg_lease(dp->dl_file); 43968a33961SJ. Bruce Fields put_nfs4_file(dp->dl_file); 44068a33961SJ. Bruce Fields dp->dl_file = NULL; 4413bd64a5bSJ. Bruce Fields } 4423bd64a5bSJ. Bruce Fields 4433bd64a5bSJ. Bruce Fields 4443bd64a5bSJ. Bruce Fields 4453bd64a5bSJ. Bruce Fields static void destroy_revoked_delegation(struct nfs4_delegation *dp) 4463bd64a5bSJ. Bruce Fields { 4473bd64a5bSJ. Bruce Fields list_del_init(&dp->dl_recall_lru); 44868a33961SJ. Bruce Fields remove_stid(&dp->dl_stid); 4491da177e4SLinus Torvalds nfs4_put_delegation(dp); 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds 4523bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 4533bd64a5bSJ. Bruce Fields { 4543bd64a5bSJ. Bruce Fields unhash_delegation(dp); 4553bd64a5bSJ. Bruce Fields remove_stid(&dp->dl_stid); 4563bd64a5bSJ. Bruce Fields nfs4_put_delegation(dp); 4573bd64a5bSJ. Bruce Fields } 4583bd64a5bSJ. Bruce Fields 4593bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 4603bd64a5bSJ. Bruce Fields { 4613bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 4623bd64a5bSJ. Bruce Fields 4633bd64a5bSJ. Bruce Fields if (clp->cl_minorversion == 0) 4643bd64a5bSJ. Bruce Fields destroy_delegation(dp); 4653bd64a5bSJ. Bruce Fields else { 4663bd64a5bSJ. Bruce Fields unhash_delegation(dp); 4673bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 4683bd64a5bSJ. Bruce Fields list_add(&dp->dl_recall_lru, &clp->cl_revoked); 4693bd64a5bSJ. Bruce Fields } 4703bd64a5bSJ. Bruce Fields } 4713bd64a5bSJ. Bruce Fields 4721da177e4SLinus Torvalds /* 4731da177e4SLinus Torvalds * SETCLIENTID state 4741da177e4SLinus Torvalds */ 4751da177e4SLinus Torvalds 476ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 477ddc04c41SJ. Bruce Fields { 478ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 479ddc04c41SJ. Bruce Fields } 480ddc04c41SJ. Bruce Fields 481ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 482ddc04c41SJ. Bruce Fields { 483ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 484ddc04c41SJ. Bruce Fields } 485ddc04c41SJ. Bruce Fields 4861da177e4SLinus Torvalds /* 487f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 488f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 489f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 490f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 491f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 492f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 493f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 494f9d7562fSJ. Bruce Fields * 495f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 496f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 497f9d7562fSJ. Bruce Fields * 498f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 499f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 500f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 501f9d7562fSJ. Bruce Fields * 502f9d7562fSJ. Bruce Fields * which we should reject. 503f9d7562fSJ. Bruce Fields */ 5045ae037e5SJeff Layton static unsigned int 5055ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 506f9d7562fSJ. Bruce Fields int i; 5075ae037e5SJeff Layton unsigned int access = 0; 508f9d7562fSJ. Bruce Fields 509f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 510f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 5115ae037e5SJeff Layton access |= i; 512f9d7562fSJ. Bruce Fields } 5135ae037e5SJeff Layton return access; 514f9d7562fSJ. Bruce Fields } 515f9d7562fSJ. Bruce Fields 5163a328614SJeff Layton static bool 517dcef0413SJ. Bruce Fields test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { 518f9d7562fSJ. Bruce Fields unsigned int access, deny; 519f9d7562fSJ. Bruce Fields 5205ae037e5SJeff Layton access = bmap_to_share_mode(stp->st_access_bmap); 5215ae037e5SJeff Layton deny = bmap_to_share_mode(stp->st_deny_bmap); 522f9d7562fSJ. Bruce Fields if ((access & open->op_share_deny) || (deny & open->op_share_access)) 5233a328614SJeff Layton return false; 5243a328614SJeff Layton return true; 525f9d7562fSJ. Bruce Fields } 526f9d7562fSJ. Bruce Fields 52782c5ff1bSJeff Layton /* set share access for a given stateid */ 52882c5ff1bSJeff Layton static inline void 52982c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 53082c5ff1bSJeff Layton { 53182c5ff1bSJeff Layton __set_bit(access, &stp->st_access_bmap); 53282c5ff1bSJeff Layton } 53382c5ff1bSJeff Layton 53482c5ff1bSJeff Layton /* clear share access for a given stateid */ 53582c5ff1bSJeff Layton static inline void 53682c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 53782c5ff1bSJeff Layton { 53882c5ff1bSJeff Layton __clear_bit(access, &stp->st_access_bmap); 53982c5ff1bSJeff Layton } 54082c5ff1bSJeff Layton 54182c5ff1bSJeff Layton /* test whether a given stateid has access */ 54282c5ff1bSJeff Layton static inline bool 54382c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 54482c5ff1bSJeff Layton { 54582c5ff1bSJeff Layton return test_bit(access, &stp->st_access_bmap); 54682c5ff1bSJeff Layton } 54782c5ff1bSJeff Layton 548ce0fc43cSJeff Layton /* set share deny for a given stateid */ 549ce0fc43cSJeff Layton static inline void 550ce0fc43cSJeff Layton set_deny(u32 access, struct nfs4_ol_stateid *stp) 551ce0fc43cSJeff Layton { 552ce0fc43cSJeff Layton __set_bit(access, &stp->st_deny_bmap); 553ce0fc43cSJeff Layton } 554ce0fc43cSJeff Layton 555ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 556ce0fc43cSJeff Layton static inline void 557ce0fc43cSJeff Layton clear_deny(u32 access, struct nfs4_ol_stateid *stp) 558ce0fc43cSJeff Layton { 559ce0fc43cSJeff Layton __clear_bit(access, &stp->st_deny_bmap); 560ce0fc43cSJeff Layton } 561ce0fc43cSJeff Layton 562ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 563ce0fc43cSJeff Layton static inline bool 564ce0fc43cSJeff Layton test_deny(u32 access, struct nfs4_ol_stateid *stp) 565ce0fc43cSJeff Layton { 566ce0fc43cSJeff Layton return test_bit(access, &stp->st_deny_bmap); 567f9d7562fSJ. Bruce Fields } 568f9d7562fSJ. Bruce Fields 569f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 570f9d7562fSJ. Bruce Fields { 5718f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 572f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 573f9d7562fSJ. Bruce Fields return O_RDONLY; 574f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 575f9d7562fSJ. Bruce Fields return O_WRONLY; 576f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 577f9d7562fSJ. Bruce Fields return O_RDWR; 578f9d7562fSJ. Bruce Fields } 579063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 580063b0fb9SJ. Bruce Fields return O_RDONLY; 581f9d7562fSJ. Bruce Fields } 582f9d7562fSJ. Bruce Fields 58382c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 58482c5ff1bSJeff Layton static void 58582c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 58682c5ff1bSJeff Layton { 58782c5ff1bSJeff Layton int i; 58882c5ff1bSJeff Layton 58982c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 59082c5ff1bSJeff Layton if (test_access(i, stp)) 59182c5ff1bSJeff Layton nfs4_file_put_access(stp->st_file, 59282c5ff1bSJeff Layton nfs4_access_to_omode(i)); 59382c5ff1bSJeff Layton clear_access(i, stp); 59482c5ff1bSJeff Layton } 59582c5ff1bSJeff Layton } 59682c5ff1bSJeff Layton 597dcef0413SJ. Bruce Fields static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) 598529d7b2aSJ. Bruce Fields { 599529d7b2aSJ. Bruce Fields list_del(&stp->st_perfile); 600529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 601529d7b2aSJ. Bruce Fields } 602529d7b2aSJ. Bruce Fields 603dcef0413SJ. Bruce Fields static void close_generic_stateid(struct nfs4_ol_stateid *stp) 604529d7b2aSJ. Bruce Fields { 60582c5ff1bSJeff Layton release_all_access(stp); 606a96e5b90SOGAWA Hirofumi put_nfs4_file(stp->st_file); 6074665e2baSJ. Bruce Fields stp->st_file = NULL; 6084665e2baSJ. Bruce Fields } 6094665e2baSJ. Bruce Fields 610dcef0413SJ. Bruce Fields static void free_generic_stateid(struct nfs4_ol_stateid *stp) 6114665e2baSJ. Bruce Fields { 61268a33961SJ. Bruce Fields remove_stid(&stp->st_stid); 61368a33961SJ. Bruce Fields kmem_cache_free(stateid_slab, stp); 614529d7b2aSJ. Bruce Fields } 615529d7b2aSJ. Bruce Fields 616dcef0413SJ. Bruce Fields static void release_lock_stateid(struct nfs4_ol_stateid *stp) 617529d7b2aSJ. Bruce Fields { 618529d7b2aSJ. Bruce Fields struct file *file; 619529d7b2aSJ. Bruce Fields 620529d7b2aSJ. Bruce Fields unhash_generic_stateid(stp); 6216136d2b4SJ. Bruce Fields unhash_stid(&stp->st_stid); 622529d7b2aSJ. Bruce Fields file = find_any_file(stp->st_file); 623529d7b2aSJ. Bruce Fields if (file) 624fe0750e5SJ. Bruce Fields locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); 62538c387b5SJ. Bruce Fields close_generic_stateid(stp); 626529d7b2aSJ. Bruce Fields free_generic_stateid(stp); 627529d7b2aSJ. Bruce Fields } 628529d7b2aSJ. Bruce Fields 629fe0750e5SJ. Bruce Fields static void unhash_lockowner(struct nfs4_lockowner *lo) 630529d7b2aSJ. Bruce Fields { 631dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 632529d7b2aSJ. Bruce Fields 633fe0750e5SJ. Bruce Fields list_del(&lo->lo_owner.so_strhash); 634fe0750e5SJ. Bruce Fields list_del(&lo->lo_perstateid); 635009673b4SJ. Bruce Fields list_del(&lo->lo_owner_ino_hash); 636fe0750e5SJ. Bruce Fields while (!list_empty(&lo->lo_owner.so_stateids)) { 637fe0750e5SJ. Bruce Fields stp = list_first_entry(&lo->lo_owner.so_stateids, 638dcef0413SJ. Bruce Fields struct nfs4_ol_stateid, st_perstateowner); 639529d7b2aSJ. Bruce Fields release_lock_stateid(stp); 640529d7b2aSJ. Bruce Fields } 641529d7b2aSJ. Bruce Fields } 642529d7b2aSJ. Bruce Fields 643fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo) 644529d7b2aSJ. Bruce Fields { 645fe0750e5SJ. Bruce Fields unhash_lockowner(lo); 646fe0750e5SJ. Bruce Fields nfs4_free_lockowner(lo); 647529d7b2aSJ. Bruce Fields } 648529d7b2aSJ. Bruce Fields 649529d7b2aSJ. Bruce Fields static void 650dcef0413SJ. Bruce Fields release_stateid_lockowners(struct nfs4_ol_stateid *open_stp) 651529d7b2aSJ. Bruce Fields { 652fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 653529d7b2aSJ. Bruce Fields 654529d7b2aSJ. Bruce Fields while (!list_empty(&open_stp->st_lockowners)) { 655fe0750e5SJ. Bruce Fields lo = list_entry(open_stp->st_lockowners.next, 656fe0750e5SJ. Bruce Fields struct nfs4_lockowner, lo_perstateid); 657fe0750e5SJ. Bruce Fields release_lockowner(lo); 658529d7b2aSJ. Bruce Fields } 659529d7b2aSJ. Bruce Fields } 660529d7b2aSJ. Bruce Fields 66138c387b5SJ. Bruce Fields static void unhash_open_stateid(struct nfs4_ol_stateid *stp) 6622283963fSJ. Bruce Fields { 6632283963fSJ. Bruce Fields unhash_generic_stateid(stp); 6642283963fSJ. Bruce Fields release_stateid_lockowners(stp); 66538c387b5SJ. Bruce Fields close_generic_stateid(stp); 66638c387b5SJ. Bruce Fields } 66738c387b5SJ. Bruce Fields 66838c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 66938c387b5SJ. Bruce Fields { 67038c387b5SJ. Bruce Fields unhash_open_stateid(stp); 6716136d2b4SJ. Bruce Fields unhash_stid(&stp->st_stid); 6722283963fSJ. Bruce Fields free_generic_stateid(stp); 6732283963fSJ. Bruce Fields } 6742283963fSJ. Bruce Fields 675fe0750e5SJ. Bruce Fields static void unhash_openowner(struct nfs4_openowner *oo) 676f1d110caSJ. Bruce Fields { 677dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 678f1d110caSJ. Bruce Fields 679fe0750e5SJ. Bruce Fields list_del(&oo->oo_owner.so_strhash); 680fe0750e5SJ. Bruce Fields list_del(&oo->oo_perclient); 681fe0750e5SJ. Bruce Fields while (!list_empty(&oo->oo_owner.so_stateids)) { 682fe0750e5SJ. Bruce Fields stp = list_first_entry(&oo->oo_owner.so_stateids, 683dcef0413SJ. Bruce Fields struct nfs4_ol_stateid, st_perstateowner); 684f1d110caSJ. Bruce Fields release_open_stateid(stp); 685f1d110caSJ. Bruce Fields } 686f1d110caSJ. Bruce Fields } 687f1d110caSJ. Bruce Fields 688f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 689f7a4d872SJ. Bruce Fields { 690f7a4d872SJ. Bruce Fields struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; 691f7a4d872SJ. Bruce Fields 692f7a4d872SJ. Bruce Fields if (s) { 6936136d2b4SJ. Bruce Fields unhash_stid(&s->st_stid); 694f7a4d872SJ. Bruce Fields free_generic_stateid(s); 695f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 696f7a4d872SJ. Bruce Fields } 697f7a4d872SJ. Bruce Fields } 698f7a4d872SJ. Bruce Fields 699fe0750e5SJ. Bruce Fields static void release_openowner(struct nfs4_openowner *oo) 700f1d110caSJ. Bruce Fields { 701fe0750e5SJ. Bruce Fields unhash_openowner(oo); 702fe0750e5SJ. Bruce Fields list_del(&oo->oo_close_lru); 703f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 704fe0750e5SJ. Bruce Fields nfs4_free_openowner(oo); 705f1d110caSJ. Bruce Fields } 706f1d110caSJ. Bruce Fields 7075282fd72SMarc Eshel static inline int 7085282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 7095282fd72SMarc Eshel { 7105282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 7115282fd72SMarc Eshel 7125282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 7135282fd72SMarc Eshel } 7145282fd72SMarc Eshel 7158f199b82STrond Myklebust #ifdef NFSD_DEBUG 7165282fd72SMarc Eshel static inline void 7175282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 7185282fd72SMarc Eshel { 7195282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 7205282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 7215282fd72SMarc Eshel } 7228f199b82STrond Myklebust #else 7238f199b82STrond Myklebust static inline void 7248f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 7258f199b82STrond Myklebust { 7268f199b82STrond Myklebust } 7278f199b82STrond Myklebust #endif 7288f199b82STrond Myklebust 7299411b1d4SJ. Bruce Fields /* 7309411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 7319411b1d4SJ. Bruce Fields * won't be used for replay. 7329411b1d4SJ. Bruce Fields */ 7339411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 7349411b1d4SJ. Bruce Fields { 7359411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 7369411b1d4SJ. Bruce Fields 7379411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 7389411b1d4SJ. Bruce Fields return; 7399411b1d4SJ. Bruce Fields 7409411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 7419411b1d4SJ. Bruce Fields cstate->replay_owner = NULL; 7429411b1d4SJ. Bruce Fields return; 7439411b1d4SJ. Bruce Fields } 7449411b1d4SJ. Bruce Fields if (!so) 7459411b1d4SJ. Bruce Fields return; 7469411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 7479411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 7489411b1d4SJ. Bruce Fields so->so_seqid++; 7499411b1d4SJ. Bruce Fields return; 7509411b1d4SJ. Bruce Fields } 7515282fd72SMarc Eshel 752ec6b5d7bSAndy Adamson static void 753ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 754ec6b5d7bSAndy Adamson { 755ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 756ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 757ec6b5d7bSAndy Adamson 758ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 759ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 760ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 761ec6b5d7bSAndy Adamson sid->reserved = 0; 762ec6b5d7bSAndy Adamson } 763ec6b5d7bSAndy Adamson 764ec6b5d7bSAndy Adamson /* 765a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 766a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 767a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 768a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 769a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 770a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 771a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 772a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 773a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 774a649637cSAndy Adamson * for the SEQUENCE op response: 775ec6b5d7bSAndy Adamson */ 776a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 777a649637cSAndy Adamson 778557ce264SAndy Adamson static void 779557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 780557ce264SAndy Adamson { 781557ce264SAndy Adamson int i; 782557ce264SAndy Adamson 783557ce264SAndy Adamson for (i = 0; i < ses->se_fchannel.maxreqs; i++) 784557ce264SAndy Adamson kfree(ses->se_slots[i]); 785557ce264SAndy Adamson } 786557ce264SAndy Adamson 787efe0cb6dSJ. Bruce Fields /* 788efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 789efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 790efe0cb6dSJ. Bruce Fields */ 79155c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 792efe0cb6dSJ. Bruce Fields { 79355c760cfSJ. Bruce Fields u32 size; 794efe0cb6dSJ. Bruce Fields 79555c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 79655c760cfSJ. Bruce Fields size = 0; 79755c760cfSJ. Bruce Fields else 79855c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 79955c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 800557ce264SAndy Adamson } 801557ce264SAndy Adamson 8025b6feee9SJ. Bruce Fields /* 8035b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 8045b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 80542b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 8065b6feee9SJ. Bruce Fields */ 80755c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 8085b6feee9SJ. Bruce Fields { 80955c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 81055c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 8115b6feee9SJ. Bruce Fields int avail; 8125b6feee9SJ. Bruce Fields 8135b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 814697ce9beSZhang Yanfei avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, 8155b6feee9SJ. Bruce Fields nfsd_drc_max_mem - nfsd_drc_mem_used); 8165b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 8175b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 8185b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 8195b6feee9SJ. Bruce Fields 8205b6feee9SJ. Bruce Fields return num; 8215b6feee9SJ. Bruce Fields } 8225b6feee9SJ. Bruce Fields 82355c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 8245b6feee9SJ. Bruce Fields { 82555c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 82655c760cfSJ. Bruce Fields 8275b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 82855c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 8295b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 8305b6feee9SJ. Bruce Fields } 8315b6feee9SJ. Bruce Fields 83255c760cfSJ. Bruce Fields static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs) 8335b6feee9SJ. Bruce Fields { 83455c760cfSJ. Bruce Fields int numslots = attrs->maxreqs; 83555c760cfSJ. Bruce Fields int slotsize = slot_bytes(attrs); 8365b6feee9SJ. Bruce Fields struct nfsd4_session *new; 8375b6feee9SJ. Bruce Fields int mem, i; 838ec6b5d7bSAndy Adamson 839c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 840ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 8415b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 842ec6b5d7bSAndy Adamson 8435b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 8446c18ba9fSAlexandros Batsakis if (!new) 8455b6feee9SJ. Bruce Fields return NULL; 846ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 8475b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 84855c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 8495b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 850ec6b5d7bSAndy Adamson goto out_free; 851ec6b5d7bSAndy Adamson } 8525b6feee9SJ. Bruce Fields return new; 8535b6feee9SJ. Bruce Fields out_free: 8545b6feee9SJ. Bruce Fields while (i--) 8555b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 8565b6feee9SJ. Bruce Fields kfree(new); 8575b6feee9SJ. Bruce Fields return NULL; 8585b6feee9SJ. Bruce Fields } 8595b6feee9SJ. Bruce Fields 86019cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 86119cf5c02SJ. Bruce Fields { 86219cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 86319cf5c02SJ. Bruce Fields kfree(c); 86419cf5c02SJ. Bruce Fields } 86519cf5c02SJ. Bruce Fields 86619cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 86719cf5c02SJ. Bruce Fields { 86819cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 86919cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 87019cf5c02SJ. Bruce Fields 87119cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 87219cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 87319cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 87419cf5c02SJ. Bruce Fields free_conn(c); 87519cf5c02SJ. Bruce Fields } 876eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 8772e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 87819cf5c02SJ. Bruce Fields } 87919cf5c02SJ. Bruce Fields 880d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 881c7662518SJ. Bruce Fields { 882c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 883c7662518SJ. Bruce Fields 884c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 885c7662518SJ. Bruce Fields if (!conn) 886db90681dSJ. Bruce Fields return NULL; 887c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 888c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 889d29c374cSJ. Bruce Fields conn->cn_flags = flags; 890db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 891db90681dSJ. Bruce Fields return conn; 892db90681dSJ. Bruce Fields } 893db90681dSJ. Bruce Fields 894328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 895328ead28SJ. Bruce Fields { 896328ead28SJ. Bruce Fields conn->cn_session = ses; 897328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 898328ead28SJ. Bruce Fields } 899328ead28SJ. Bruce Fields 900db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 901db90681dSJ. Bruce Fields { 902db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 903c7662518SJ. Bruce Fields 904c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 905328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 906c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 907db90681dSJ. Bruce Fields } 908c7662518SJ. Bruce Fields 90921b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 910db90681dSJ. Bruce Fields { 91119cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 91221b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 913db90681dSJ. Bruce Fields } 914db90681dSJ. Bruce Fields 915e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 916db90681dSJ. Bruce Fields { 91721b75b01SJ. Bruce Fields int ret; 918db90681dSJ. Bruce Fields 919db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 92021b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 92121b75b01SJ. Bruce Fields if (ret) 92221b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 92321b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 9246a3b1563SJ. Bruce Fields if (conn->cn_flags & NFS4_CDFC4_BACK) { 92524119673SWeston Andros Adamson /* callback channel may be back up */ 92624119673SWeston Andros Adamson nfsd4_probe_callback(ses->se_client); 92724119673SWeston Andros Adamson } 928c7662518SJ. Bruce Fields } 929c7662518SJ. Bruce Fields 930e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 9311d1bc8f2SJ. Bruce Fields { 9321d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 9331d1bc8f2SJ. Bruce Fields 934e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 9351d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 936e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 9371d1bc8f2SJ. Bruce Fields } 9381d1bc8f2SJ. Bruce Fields 9391d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 94019cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 941c7662518SJ. Bruce Fields { 94219cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 94319cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 94419cf5c02SJ. Bruce Fields 94519cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 94619cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 94719cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 94819cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 94919cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 95019cf5c02SJ. Bruce Fields 95119cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 95219cf5c02SJ. Bruce Fields free_conn(c); 95319cf5c02SJ. Bruce Fields 95419cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 95519cf5c02SJ. Bruce Fields } 95619cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 957c7662518SJ. Bruce Fields } 958c7662518SJ. Bruce Fields 9591377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 9601377b69eSJ. Bruce Fields { 9611377b69eSJ. Bruce Fields free_session_slots(ses); 9621377b69eSJ. Bruce Fields kfree(ses); 9631377b69eSJ. Bruce Fields } 9641377b69eSJ. Bruce Fields 96566b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 966508dc6e1SBenny Halevy { 967c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id); 968c9a49628SStanislav Kinsbursky 969c7662518SJ. Bruce Fields lockdep_assert_held(&nn->client_lock); 970c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 97155c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 972c7662518SJ. Bruce Fields __free_session(ses); 973a827bcb2SJ. Bruce Fields } 974ec6b5d7bSAndy Adamson 975135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 976a827bcb2SJ. Bruce Fields { 977a827bcb2SJ. Bruce Fields int idx; 9781872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 979a827bcb2SJ. Bruce Fields 980ec6b5d7bSAndy Adamson new->se_client = clp; 981ec6b5d7bSAndy Adamson gen_sessionid(new); 982ec6b5d7bSAndy Adamson 983c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 984c7662518SJ. Bruce Fields 985ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 986ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 9878b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 988c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 98966b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 9905b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 991c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 9921872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 9934c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 994ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 9954c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 996c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 99755c760cfSJ. Bruce Fields memcpy(&new->se_fchannel, &cses->fore_channel, 99855c760cfSJ. Bruce Fields sizeof(struct nfsd4_channel_attrs)); 999dcbeaa68SJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) { 1000edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1001dcbeaa68SJ. Bruce Fields /* 1002dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1003dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1004dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1005dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1006dcbeaa68SJ. Bruce Fields * future: 1007dcbeaa68SJ. Bruce Fields */ 1008edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1009edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1010edd76786SJ. Bruce Fields } 1011ec6b5d7bSAndy Adamson } 1012ec6b5d7bSAndy Adamson 10139089f1b4SBenny Halevy /* caller must hold client_lock */ 10145282fd72SMarc Eshel static struct nfsd4_session * 10151872de0eSStanislav Kinsbursky find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 10165282fd72SMarc Eshel { 10175282fd72SMarc Eshel struct nfsd4_session *elem; 10185282fd72SMarc Eshel int idx; 10191872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 10205282fd72SMarc Eshel 10215282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 10225282fd72SMarc Eshel idx = hash_sessionid(sessionid); 10235282fd72SMarc Eshel /* Search in the appropriate list */ 10241872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 10255282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 10265282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 10275282fd72SMarc Eshel return elem; 10285282fd72SMarc Eshel } 10295282fd72SMarc Eshel } 10305282fd72SMarc Eshel 10315282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 10325282fd72SMarc Eshel return NULL; 10335282fd72SMarc Eshel } 10345282fd72SMarc Eshel 10359089f1b4SBenny Halevy /* caller must hold client_lock */ 10367116ed6bSAndy Adamson static void 10375282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 10387116ed6bSAndy Adamson { 10397116ed6bSAndy Adamson list_del(&ses->se_hash); 10404c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 10417116ed6bSAndy Adamson list_del(&ses->se_perclnt); 10424c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 10435282fd72SMarc Eshel } 10445282fd72SMarc Eshel 10451da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 10461da177e4SLinus Torvalds static int 10472c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 10481da177e4SLinus Torvalds { 10492c142baaSStanislav Kinsbursky if (clid->cl_boot == nn->boot_time) 10501da177e4SLinus Torvalds return 0; 105160adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 10522c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 10531da177e4SLinus Torvalds return 1; 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds /* 10571da177e4SLinus Torvalds * XXX Should we use a slab cache ? 10581da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 10591da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 10601da177e4SLinus Torvalds */ 106135bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 10621da177e4SLinus Torvalds { 10631da177e4SLinus Torvalds struct nfs4_client *clp; 10641da177e4SLinus Torvalds 106535bba9a3SJ. Bruce Fields clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); 106635bba9a3SJ. Bruce Fields if (clp == NULL) 106735bba9a3SJ. Bruce Fields return NULL; 106867114fe6SThomas Meyer clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); 106935bba9a3SJ. Bruce Fields if (clp->cl_name.data == NULL) { 107035bba9a3SJ. Bruce Fields kfree(clp); 107135bba9a3SJ. Bruce Fields return NULL; 107235bba9a3SJ. Bruce Fields } 10731da177e4SLinus Torvalds clp->cl_name.len = name.len; 10741da177e4SLinus Torvalds return clp; 10751da177e4SLinus Torvalds } 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds static inline void 10781da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 10791da177e4SLinus Torvalds { 1080bca0ec65SStanislav Kinsbursky struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id); 1081c9a49628SStanislav Kinsbursky 1082c9a49628SStanislav Kinsbursky lockdep_assert_held(&nn->client_lock); 1083792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1084792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1085792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1086792c95ddSJ. Bruce Fields se_perclnt); 1087792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 108866b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 108966b2b9b2SJ. Bruce Fields free_session(ses); 1090792c95ddSJ. Bruce Fields } 109103a4e1f6SJ. Bruce Fields free_svc_cred(&clp->cl_cred); 10921da177e4SLinus Torvalds kfree(clp->cl_name.data); 10932d32b29aSmajianpeng idr_destroy(&clp->cl_stateids); 10941da177e4SLinus Torvalds kfree(clp); 10951da177e4SLinus Torvalds } 10961da177e4SLinus Torvalds 109784d38ac9SBenny Halevy /* must be called under the client_lock */ 109884d38ac9SBenny Halevy static inline void 109984d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 110084d38ac9SBenny Halevy { 1101792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1102792c95ddSJ. Bruce Fields 110384d38ac9SBenny Halevy list_del(&clp->cl_lru); 11044c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1105792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1106792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 11074c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 110884d38ac9SBenny Halevy } 110984d38ac9SBenny Halevy 11101da177e4SLinus Torvalds static void 11110d22f68fSJ. Bruce Fields destroy_client(struct nfs4_client *clp) 11121da177e4SLinus Torvalds { 1113fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 11141da177e4SLinus Torvalds struct nfs4_delegation *dp; 11151da177e4SLinus Torvalds struct list_head reaplist; 1116382a62e7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 11191da177e4SLinus Torvalds spin_lock(&recall_lock); 1120ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 1121ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 1122ea1da636SNeilBrown list_del_init(&dp->dl_perclnt); 11231da177e4SLinus Torvalds list_move(&dp->dl_recall_lru, &reaplist); 11241da177e4SLinus Torvalds } 11251da177e4SLinus Torvalds spin_unlock(&recall_lock); 11261da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 11271da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 11283bd64a5bSJ. Bruce Fields destroy_delegation(dp); 11291da177e4SLinus Torvalds } 1130ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 1131fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1132fe0750e5SJ. Bruce Fields release_openowner(oo); 11331da177e4SLinus Torvalds } 11346ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 11352bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 11362bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 113784d38ac9SBenny Halevy list_del(&clp->cl_idhash); 1138ac55fdc4SJeff Layton if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 1139382a62e7SStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 1140ac55fdc4SJeff Layton else 1141a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 1142c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 114384d38ac9SBenny Halevy unhash_client_locked(clp); 1144221a6876SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&clp->cl_refcount)); 1145b12a05cbSJ. Bruce Fields free_client(clp); 1146c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 11471da177e4SLinus Torvalds } 11481da177e4SLinus Torvalds 11490d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 11500d22f68fSJ. Bruce Fields { 11510d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 11520d22f68fSJ. Bruce Fields destroy_client(clp); 11530d22f68fSJ. Bruce Fields } 11540d22f68fSJ. Bruce Fields 115535bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 115635bba9a3SJ. Bruce Fields { 115735bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 115835bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds 116135bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 116235bba9a3SJ. Bruce Fields { 11631da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 11641da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds 116703a4e1f6SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 116835bba9a3SJ. Bruce Fields { 116903a4e1f6SJ. Bruce Fields if (source->cr_principal) { 117003a4e1f6SJ. Bruce Fields target->cr_principal = 117103a4e1f6SJ. Bruce Fields kstrdup(source->cr_principal, GFP_KERNEL); 117203a4e1f6SJ. Bruce Fields if (target->cr_principal == NULL) 117303a4e1f6SJ. Bruce Fields return -ENOMEM; 117403a4e1f6SJ. Bruce Fields } else 117503a4e1f6SJ. Bruce Fields target->cr_principal = NULL; 1176d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 11771da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 11781da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 11791da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 11801da177e4SLinus Torvalds get_group_info(target->cr_group_info); 11810dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 11820dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 11830dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 118403a4e1f6SJ. Bruce Fields return 0; 11851da177e4SLinus Torvalds } 11861da177e4SLinus Torvalds 1187ac55fdc4SJeff Layton static long long 1188ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 1189ac55fdc4SJeff Layton { 1190ac55fdc4SJeff Layton long long res; 1191ac55fdc4SJeff Layton 1192ac55fdc4SJeff Layton res = o1->len - o2->len; 1193ac55fdc4SJeff Layton if (res) 1194ac55fdc4SJeff Layton return res; 1195ac55fdc4SJeff Layton return (long long)memcmp(o1->data, o2->data, o1->len); 1196ac55fdc4SJeff Layton } 1197ac55fdc4SJeff Layton 119835bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 1199599e0a22SJ. Bruce Fields { 1200a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds static int 1204599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 1205599e0a22SJ. Bruce Fields { 1206599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 12071da177e4SLinus Torvalds } 12081da177e4SLinus Torvalds 12091da177e4SLinus Torvalds static int 1210599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 1211599e0a22SJ. Bruce Fields { 1212599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 12131da177e4SLinus Torvalds } 12141da177e4SLinus Torvalds 12158fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 12168fbba96eSJ. Bruce Fields { 12178fbba96eSJ. Bruce Fields int i; 12188fbba96eSJ. Bruce Fields 12198fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 12208fbba96eSJ. Bruce Fields return false; 12218fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 12226fab8779SEric W. Biederman if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i))) 12238fbba96eSJ. Bruce Fields return false; 12248fbba96eSJ. Bruce Fields return true; 12258fbba96eSJ. Bruce Fields } 12268fbba96eSJ. Bruce Fields 122768eb3508SJ. Bruce Fields /* 122868eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 122968eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 123068eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 123168eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 123268eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 123368eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 123468eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 123568eb3508SJ. Bruce Fields */ 123668eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 123768eb3508SJ. Bruce Fields { 123868eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 123968eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 124068eb3508SJ. Bruce Fields } 124168eb3508SJ. Bruce Fields 124268eb3508SJ. Bruce Fields 12435559b50aSVivek Trivedi static bool 1244599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 1245599e0a22SJ. Bruce Fields { 124668eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 12476fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 12486fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 12498fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 12508fbba96eSJ. Bruce Fields return false; 12518fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 12528fbba96eSJ. Bruce Fields return true; 12538fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 12548fbba96eSJ. Bruce Fields return false; 12555559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds 125857266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 125957266a6eSJ. Bruce Fields { 126057266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 126157266a6eSJ. Bruce Fields u32 service; 126257266a6eSJ. Bruce Fields 1263c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 1264c4720591SJ. Bruce Fields return false; 126557266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 126657266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 126757266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 126857266a6eSJ. Bruce Fields } 126957266a6eSJ. Bruce Fields 127057266a6eSJ. Bruce Fields static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 127157266a6eSJ. Bruce Fields { 127257266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 127357266a6eSJ. Bruce Fields 127457266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 127557266a6eSJ. Bruce Fields return true; 127657266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 127757266a6eSJ. Bruce Fields return false; 127857266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 127957266a6eSJ. Bruce Fields return false; 128057266a6eSJ. Bruce Fields if (!cr->cr_principal) 128157266a6eSJ. Bruce Fields return false; 128257266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 128357266a6eSJ. Bruce Fields } 128457266a6eSJ. Bruce Fields 1285c212cecfSStanislav Kinsbursky static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 12865ec7b46cSJ. Bruce Fields { 12875ec7b46cSJ. Bruce Fields static u32 current_clientid = 1; 12885ec7b46cSJ. Bruce Fields 12892c142baaSStanislav Kinsbursky clp->cl_clientid.cl_boot = nn->boot_time; 12901da177e4SLinus Torvalds clp->cl_clientid.cl_id = current_clientid++; 12911da177e4SLinus Torvalds } 12921da177e4SLinus Torvalds 1293deda2faaSJ. Bruce Fields static void gen_confirm(struct nfs4_client *clp) 1294deda2faaSJ. Bruce Fields { 1295ab4684d1SChuck Lever __be32 verf[2]; 1296deda2faaSJ. Bruce Fields static u32 i; 12971da177e4SLinus Torvalds 1298ab4684d1SChuck Lever verf[0] = (__be32)get_seconds(); 1299ab4684d1SChuck Lever verf[1] = (__be32)i++; 1300ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 13011da177e4SLinus Torvalds } 13021da177e4SLinus Torvalds 130338c2f4b1SJ. Bruce Fields static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t) 13044581d140SJ. Bruce Fields { 13053abdb607SJ. Bruce Fields struct nfs4_stid *ret; 13063abdb607SJ. Bruce Fields 13073abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 13083abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 13093abdb607SJ. Bruce Fields return NULL; 13103abdb607SJ. Bruce Fields return ret; 13114581d140SJ. Bruce Fields } 13124d71ab87SJ. Bruce Fields 131338c2f4b1SJ. Bruce Fields static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 1314f459e453SJ. Bruce Fields { 1315f459e453SJ. Bruce Fields struct nfs4_stid *s; 1316f459e453SJ. Bruce Fields 131738c2f4b1SJ. Bruce Fields s = find_stateid(cl, t); 1318f459e453SJ. Bruce Fields if (!s) 1319f459e453SJ. Bruce Fields return NULL; 1320f459e453SJ. Bruce Fields if (typemask & s->sc_type) 13214d71ab87SJ. Bruce Fields return s; 13224581d140SJ. Bruce Fields return NULL; 13234581d140SJ. Bruce Fields } 13244581d140SJ. Bruce Fields 13252216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 1326b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 1327b09333c4SRicardo Labiaga { 1328b09333c4SRicardo Labiaga struct nfs4_client *clp; 1329b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 133003a4e1f6SJ. Bruce Fields int ret; 1331c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 1332c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 1333b09333c4SRicardo Labiaga 1334b09333c4SRicardo Labiaga clp = alloc_client(name); 1335b09333c4SRicardo Labiaga if (clp == NULL) 1336b09333c4SRicardo Labiaga return NULL; 1337b09333c4SRicardo Labiaga 1338792c95ddSJ. Bruce Fields INIT_LIST_HEAD(&clp->cl_sessions); 133903a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 134003a4e1f6SJ. Bruce Fields if (ret) { 1341c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 1342b09333c4SRicardo Labiaga free_client(clp); 1343c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 1344b09333c4SRicardo Labiaga return NULL; 1345b09333c4SRicardo Labiaga } 134638c2f4b1SJ. Bruce Fields idr_init(&clp->cl_stateids); 134746583e25SBenny Halevy atomic_set(&clp->cl_refcount, 0); 134877a3569dSJ. Bruce Fields clp->cl_cb_state = NFSD4_CB_UNKNOWN; 1349b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_idhash); 1350b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_openowners); 1351b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_delegations); 1352b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_lru); 13535ce8ba25SJ. Bruce Fields INIT_LIST_HEAD(&clp->cl_callbacks); 13543bd64a5bSJ. Bruce Fields INIT_LIST_HEAD(&clp->cl_revoked); 13556ff8da08SJ. Bruce Fields spin_lock_init(&clp->cl_lock); 135657725155SJ. Bruce Fields nfsd4_init_callback(&clp->cl_cb_null); 135707cd4909SBenny Halevy clp->cl_time = get_seconds(); 1358b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 1359b09333c4SRicardo Labiaga rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 1360b09333c4SRicardo Labiaga copy_verf(clp, verf); 1361b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 1362b09333c4SRicardo Labiaga gen_confirm(clp); 1363edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 1364c212cecfSStanislav Kinsbursky clp->net = net; 1365b09333c4SRicardo Labiaga return clp; 1366b09333c4SRicardo Labiaga } 1367b09333c4SRicardo Labiaga 1368fd39ca9aSNeilBrown static void 1369ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 1370ac55fdc4SJeff Layton { 1371ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 1372ac55fdc4SJeff Layton struct nfs4_client *clp; 1373ac55fdc4SJeff Layton 1374ac55fdc4SJeff Layton while (*new) { 1375ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 1376ac55fdc4SJeff Layton parent = *new; 1377ac55fdc4SJeff Layton 1378ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 1379ac55fdc4SJeff Layton new = &((*new)->rb_left); 1380ac55fdc4SJeff Layton else 1381ac55fdc4SJeff Layton new = &((*new)->rb_right); 1382ac55fdc4SJeff Layton } 1383ac55fdc4SJeff Layton 1384ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 1385ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 1386ac55fdc4SJeff Layton } 1387ac55fdc4SJeff Layton 1388ac55fdc4SJeff Layton static struct nfs4_client * 1389ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 1390ac55fdc4SJeff Layton { 1391ac55fdc4SJeff Layton long long cmp; 1392ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 1393ac55fdc4SJeff Layton struct nfs4_client *clp; 1394ac55fdc4SJeff Layton 1395ac55fdc4SJeff Layton while (node) { 1396ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 1397ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 1398ac55fdc4SJeff Layton if (cmp > 0) 1399ac55fdc4SJeff Layton node = node->rb_left; 1400ac55fdc4SJeff Layton else if (cmp < 0) 1401ac55fdc4SJeff Layton node = node->rb_right; 1402ac55fdc4SJeff Layton else 1403ac55fdc4SJeff Layton return clp; 1404ac55fdc4SJeff Layton } 1405ac55fdc4SJeff Layton return NULL; 1406ac55fdc4SJeff Layton } 1407ac55fdc4SJeff Layton 1408ac55fdc4SJeff Layton static void 1409ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 14101da177e4SLinus Torvalds { 14111da177e4SLinus Torvalds unsigned int idhashval; 14120a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 14131da177e4SLinus Torvalds 1414ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 1415a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 14161da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 14170a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 141836acb66bSBenny Halevy renew_client(clp); 14191da177e4SLinus Torvalds } 14201da177e4SLinus Torvalds 1421fd39ca9aSNeilBrown static void 14221da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 14231da177e4SLinus Torvalds { 14241da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 14258daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 14261da177e4SLinus Torvalds 14271da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 14288daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 1429a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 1430382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 1431ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 14321da177e4SLinus Torvalds renew_client(clp); 14331da177e4SLinus Torvalds } 14341da177e4SLinus Torvalds 14351da177e4SLinus Torvalds static struct nfs4_client * 1436bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 14371da177e4SLinus Torvalds { 14381da177e4SLinus Torvalds struct nfs4_client *clp; 14391da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 14401da177e4SLinus Torvalds 1441bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 1442a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 1443d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 1444d15c077eSJ. Bruce Fields return NULL; 1445a50d2ad1SJ. Bruce Fields renew_client(clp); 14461da177e4SLinus Torvalds return clp; 14471da177e4SLinus Torvalds } 1448a50d2ad1SJ. Bruce Fields } 14491da177e4SLinus Torvalds return NULL; 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds static struct nfs4_client * 1453bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 1454bfa85e83SJ. Bruce Fields { 1455bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 1456bfa85e83SJ. Bruce Fields 1457bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 1458bfa85e83SJ. Bruce Fields } 1459bfa85e83SJ. Bruce Fields 1460bfa85e83SJ. Bruce Fields static struct nfs4_client * 14610a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 14621da177e4SLinus Torvalds { 1463bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 14641da177e4SLinus Torvalds 1465bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 14661da177e4SLinus Torvalds } 14671da177e4SLinus Torvalds 14686e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 1469a1bcecd2SAndy Adamson { 14706e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 1471a1bcecd2SAndy Adamson } 1472a1bcecd2SAndy Adamson 147328ce6054SNeilBrown static struct nfs4_client * 1474382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 147528ce6054SNeilBrown { 1476382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 147728ce6054SNeilBrown } 147828ce6054SNeilBrown 147928ce6054SNeilBrown static struct nfs4_client * 1480a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 148128ce6054SNeilBrown { 1482a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 148328ce6054SNeilBrown } 148428ce6054SNeilBrown 1485fd39ca9aSNeilBrown static void 14866f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 14871da177e4SLinus Torvalds { 148807263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 14896f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 14906f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 14917077ecbaSJeff Layton unsigned short expected_family; 14921da177e4SLinus Torvalds 14937077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 14947077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 14957077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 14967077ecbaSJeff Layton expected_family = AF_INET; 14977077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 14987077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 14997077ecbaSJeff Layton expected_family = AF_INET6; 15007077ecbaSJeff Layton else 15011da177e4SLinus Torvalds goto out_err; 15021da177e4SLinus Torvalds 1503c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 1504aa9a4ec7SJeff Layton se->se_callback_addr_len, 150507263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 150607263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 1507aa9a4ec7SJeff Layton 150807263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 15091da177e4SLinus Torvalds goto out_err; 1510aa9a4ec7SJeff Layton 151107263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 151207263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 1513fbf4665fSJeff Layton 151407263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 151507263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 1516849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 15171da177e4SLinus Torvalds return; 15181da177e4SLinus Torvalds out_err: 151907263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 152007263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 1521849823c5SNeil Brown dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " 15221da177e4SLinus Torvalds "will not receive delegations\n", 15231da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 15241da177e4SLinus Torvalds 15251da177e4SLinus Torvalds return; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds 1528074fe897SAndy Adamson /* 1529557ce264SAndy Adamson * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size. 1530074fe897SAndy Adamson */ 1531074fe897SAndy Adamson void 1532074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 1533074fe897SAndy Adamson { 1534557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1535557ce264SAndy Adamson unsigned int base; 1536074fe897SAndy Adamson 1537557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 1538074fe897SAndy Adamson 1539557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 1540557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 1541bf864a31SAndy Adamson 1542bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 1543bf864a31SAndy Adamson if (nfsd4_not_cached(resp)) { 1544557ce264SAndy Adamson slot->sl_datalen = 0; 1545bf864a31SAndy Adamson return; 1546bf864a31SAndy Adamson } 1547557ce264SAndy Adamson slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap; 1548557ce264SAndy Adamson base = (char *)resp->cstate.datap - 1549557ce264SAndy Adamson (char *)resp->xbuf->head[0].iov_base; 1550557ce264SAndy Adamson if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data, 1551557ce264SAndy Adamson slot->sl_datalen)) 1552557ce264SAndy Adamson WARN("%s: sessions DRC could not cache compound\n", __func__); 1553557ce264SAndy Adamson return; 1554074fe897SAndy Adamson } 1555074fe897SAndy Adamson 1556074fe897SAndy Adamson /* 1557abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 1558abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 1559abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 1560abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 1561abfabf8cSAndy Adamson * 1562074fe897SAndy Adamson */ 1563abfabf8cSAndy Adamson static __be32 1564abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 1565abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 1566074fe897SAndy Adamson { 1567abfabf8cSAndy Adamson struct nfsd4_op *op; 1568abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1569074fe897SAndy Adamson 1570abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 1571abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 1572abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 1573abfabf8cSAndy Adamson 1574abfabf8cSAndy Adamson /* Return nfserr_retry_uncached_rep in next operation. */ 157573e79482SJ. Bruce Fields if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { 1576abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 1577abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 1578abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 1579074fe897SAndy Adamson } 1580abfabf8cSAndy Adamson return op->status; 1581074fe897SAndy Adamson } 1582074fe897SAndy Adamson 1583074fe897SAndy Adamson /* 1584557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 1585557ce264SAndy Adamson * session values. 1586074fe897SAndy Adamson */ 1587074fe897SAndy Adamson __be32 1588bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 1589bf864a31SAndy Adamson struct nfsd4_sequence *seq) 1590074fe897SAndy Adamson { 1591557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1592074fe897SAndy Adamson __be32 status; 1593074fe897SAndy Adamson 1594557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 1595074fe897SAndy Adamson 1596abfabf8cSAndy Adamson /* Either returns 0 or nfserr_retry_uncached */ 1597abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 1598abfabf8cSAndy Adamson if (status == nfserr_retry_uncached_rep) 1599abfabf8cSAndy Adamson return status; 1600074fe897SAndy Adamson 1601557ce264SAndy Adamson /* The sequence operation has been encoded, cstate->datap set. */ 1602557ce264SAndy Adamson memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen); 1603074fe897SAndy Adamson 1604557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 1605557ce264SAndy Adamson resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen); 1606557ce264SAndy Adamson status = slot->sl_status; 1607074fe897SAndy Adamson 1608074fe897SAndy Adamson return status; 1609074fe897SAndy Adamson } 1610074fe897SAndy Adamson 16110733d213SAndy Adamson /* 16120733d213SAndy Adamson * Set the exchange_id flags returned by the server. 16130733d213SAndy Adamson */ 16140733d213SAndy Adamson static void 16150733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 16160733d213SAndy Adamson { 16170733d213SAndy Adamson /* pNFS is not supported */ 16180733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 16190733d213SAndy Adamson 16200733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 16210733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 16220733d213SAndy Adamson 16230733d213SAndy Adamson /* set the wire flags to return to client. */ 16240733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 16250733d213SAndy Adamson } 16260733d213SAndy Adamson 1627631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 1628631fc9eaSJ. Bruce Fields { 1629631fc9eaSJ. Bruce Fields /* 1630631fc9eaSJ. Bruce Fields * Note clp->cl_openowners check isn't quite right: there's no 1631631fc9eaSJ. Bruce Fields * need to count owners without stateid's. 1632631fc9eaSJ. Bruce Fields * 1633631fc9eaSJ. Bruce Fields * Also note we should probably be using this in 4.0 case too. 1634631fc9eaSJ. Bruce Fields */ 16356eccece9SJ. Bruce Fields return !list_empty(&clp->cl_openowners) 16366eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 16376eccece9SJ. Bruce Fields || !list_empty(&clp->cl_sessions); 1638631fc9eaSJ. Bruce Fields } 1639631fc9eaSJ. Bruce Fields 1640b37ad28bSAl Viro __be32 1641069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp, 1642069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 1643069b6ad4SAndy Adamson struct nfsd4_exchange_id *exid) 1644069b6ad4SAndy Adamson { 16450733d213SAndy Adamson struct nfs4_client *unconf, *conf, *new; 164657b7b43bSJ. Bruce Fields __be32 status; 1647363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 16480733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 1649363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 165083e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 1651c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 16520733d213SAndy Adamson 1653363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 16540733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 1655363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 16560733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 1657363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 16580733d213SAndy Adamson 1659a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 16600733d213SAndy Adamson return nfserr_inval; 16610733d213SAndy Adamson 16620733d213SAndy Adamson switch (exid->spa_how) { 166357266a6eSJ. Bruce Fields case SP4_MACH_CRED: 166457266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 166557266a6eSJ. Bruce Fields return nfserr_inval; 16660733d213SAndy Adamson case SP4_NONE: 16670733d213SAndy Adamson break; 1668063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 1669063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 16700733d213SAndy Adamson case SP4_SSV: 1671dd30333cSJ. Bruce Fields return nfserr_encr_alg_unsupp; 16720733d213SAndy Adamson } 16730733d213SAndy Adamson 16742dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 16750733d213SAndy Adamson nfs4_lock_state(); 1676382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 16770733d213SAndy Adamson if (conf) { 167883e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 167983e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 168083e08fd4SJ. Bruce Fields 1681136e658dSJ. Bruce Fields if (update) { 1682136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 16832dbb269dSJ. Bruce Fields status = nfserr_inval; 1684e203d506SJ. Bruce Fields goto out; 1685e203d506SJ. Bruce Fields } 168657266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) { 168757266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 168857266a6eSJ. Bruce Fields goto out; 168957266a6eSJ. Bruce Fields } 16902dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 16910733d213SAndy Adamson status = nfserr_perm; 16920733d213SAndy Adamson goto out; 16930733d213SAndy Adamson } 16942dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 16950733d213SAndy Adamson status = nfserr_not_same; 16960733d213SAndy Adamson goto out; 16970733d213SAndy Adamson } 1698136e658dSJ. Bruce Fields /* case 6 */ 16990733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 17000733d213SAndy Adamson new = conf; 17010733d213SAndy Adamson goto out_copy; 17026ddbbbfeSMike Sager } 1703136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 1704631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 1705136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 1706136e658dSJ. Bruce Fields goto out; 1707136e658dSJ. Bruce Fields } 1708b9831b59SJ. Bruce Fields expire_client(conf); 1709b9831b59SJ. Bruce Fields goto out_new; 1710631fc9eaSJ. Bruce Fields } 1711136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 17120f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 1713136e658dSJ. Bruce Fields new = conf; 1714136e658dSJ. Bruce Fields goto out_copy; 1715136e658dSJ. Bruce Fields } 17162dbb269dSJ. Bruce Fields /* case 5, client reboot */ 17170733d213SAndy Adamson goto out_new; 17180733d213SAndy Adamson } 17196ddbbbfeSMike Sager 17202dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 17210733d213SAndy Adamson status = nfserr_noent; 17220733d213SAndy Adamson goto out; 17230733d213SAndy Adamson } 17240733d213SAndy Adamson 1725a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 17262dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 17270733d213SAndy Adamson expire_client(unconf); 17280733d213SAndy Adamson 17292dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 17300733d213SAndy Adamson out_new: 17312216d449SJeff Layton new = create_client(exid->clname, rqstp, &verf); 17320733d213SAndy Adamson if (new == NULL) { 17334731030dSJ. Bruce Fields status = nfserr_jukebox; 17340733d213SAndy Adamson goto out; 17350733d213SAndy Adamson } 17364f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 173757266a6eSJ. Bruce Fields new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); 17380733d213SAndy Adamson 1739c212cecfSStanislav Kinsbursky gen_clid(new, nn); 1740ac55fdc4SJeff Layton add_to_unconfirmed(new); 17410733d213SAndy Adamson out_copy: 17420733d213SAndy Adamson exid->clientid.cl_boot = new->cl_clientid.cl_boot; 17430733d213SAndy Adamson exid->clientid.cl_id = new->cl_clientid.cl_id; 17440733d213SAndy Adamson 1745778df3f0SJ. Bruce Fields exid->seqid = new->cl_cs_slot.sl_seqid + 1; 17460733d213SAndy Adamson nfsd4_set_ex_flags(new, exid); 17470733d213SAndy Adamson 17480733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 174949557cc7SAndy Adamson new->cl_cs_slot.sl_seqid, new->cl_exchange_flags); 17500733d213SAndy Adamson status = nfs_ok; 17510733d213SAndy Adamson 17520733d213SAndy Adamson out: 17530733d213SAndy Adamson nfs4_unlock_state(); 17540733d213SAndy Adamson return status; 1755069b6ad4SAndy Adamson } 1756069b6ad4SAndy Adamson 175757b7b43bSJ. Bruce Fields static __be32 175888e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 1759b85d4c01SBenny Halevy { 176088e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 176188e588d5SAndy Adamson slot_seqid); 1762b85d4c01SBenny Halevy 1763b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 176488e588d5SAndy Adamson if (slot_inuse) { 176588e588d5SAndy Adamson if (seqid == slot_seqid) 1766b85d4c01SBenny Halevy return nfserr_jukebox; 1767b85d4c01SBenny Halevy else 1768b85d4c01SBenny Halevy return nfserr_seq_misordered; 1769b85d4c01SBenny Halevy } 1770f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 177188e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 1772b85d4c01SBenny Halevy return nfs_ok; 177388e588d5SAndy Adamson if (seqid == slot_seqid) 1774b85d4c01SBenny Halevy return nfserr_replay_cache; 1775b85d4c01SBenny Halevy return nfserr_seq_misordered; 1776b85d4c01SBenny Halevy } 1777b85d4c01SBenny Halevy 177849557cc7SAndy Adamson /* 177949557cc7SAndy Adamson * Cache the create session result into the create session single DRC 178049557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 178149557cc7SAndy Adamson * Do this for solo or embedded create session operations. 178249557cc7SAndy Adamson */ 178349557cc7SAndy Adamson static void 178449557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 178557b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 178649557cc7SAndy Adamson { 178749557cc7SAndy Adamson slot->sl_status = nfserr; 178849557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 178949557cc7SAndy Adamson } 179049557cc7SAndy Adamson 179149557cc7SAndy Adamson static __be32 179249557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 179349557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 179449557cc7SAndy Adamson { 179549557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 179649557cc7SAndy Adamson return slot->sl_status; 179749557cc7SAndy Adamson } 179849557cc7SAndy Adamson 17991b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 18001b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 18011b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 18021b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 18031b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 18041b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 18051b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 18061b74c25bSMi Jinlong 18071b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 18081b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 18091b74c25bSMi Jinlong 1 + /* status */ \ 18101b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 18111b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 18121b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 18131b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 18141b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 18151b74c25bSMi Jinlong 181655c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 18171b74c25bSMi Jinlong { 181855c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 181955c760cfSJ. Bruce Fields 1820373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 1821373cd409SJ. Bruce Fields return nfserr_toosmall; 1822373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 1823373cd409SJ. Bruce Fields return nfserr_toosmall; 182455c760cfSJ. Bruce Fields ca->headerpadsz = 0; 182555c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 182655c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 182755c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 182855c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 182955c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 183055c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 183155c760cfSJ. Bruce Fields /* 183255c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 183355c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 183455c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 183555c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 183655c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 183755c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 183855c760cfSJ. Bruce Fields */ 183955c760cfSJ. Bruce Fields ca->maxreqs = nfsd4_get_drc_mem(ca); 184055c760cfSJ. Bruce Fields if (!ca->maxreqs) 184155c760cfSJ. Bruce Fields return nfserr_jukebox; 184255c760cfSJ. Bruce Fields 1843373cd409SJ. Bruce Fields return nfs_ok; 18441b74c25bSMi Jinlong } 18451b74c25bSMi Jinlong 184606b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 184706b332a5SJ. Bruce Fields { 184806b332a5SJ. Bruce Fields ca->headerpadsz = 0; 184906b332a5SJ. Bruce Fields 185006b332a5SJ. Bruce Fields /* 185106b332a5SJ. Bruce Fields * These RPC_MAX_HEADER macros are overkill, especially since we 185206b332a5SJ. Bruce Fields * don't even do gss on the backchannel yet. But this is still 185306b332a5SJ. Bruce Fields * less than 1k. Tighten up this estimate in the unlikely event 185406b332a5SJ. Bruce Fields * it turns out to be a problem for some client: 185506b332a5SJ. Bruce Fields */ 185606b332a5SJ. Bruce Fields if (ca->maxreq_sz < NFS4_enc_cb_recall_sz + RPC_MAX_HEADER_WITH_AUTH) 185706b332a5SJ. Bruce Fields return nfserr_toosmall; 185806b332a5SJ. Bruce Fields if (ca->maxresp_sz < NFS4_dec_cb_recall_sz + RPC_MAX_REPHEADER_WITH_AUTH) 185906b332a5SJ. Bruce Fields return nfserr_toosmall; 186006b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 186106b332a5SJ. Bruce Fields if (ca->maxops < 2) 186206b332a5SJ. Bruce Fields return nfserr_toosmall; 186306b332a5SJ. Bruce Fields 186406b332a5SJ. Bruce Fields return nfs_ok; 1865069b6ad4SAndy Adamson } 1866069b6ad4SAndy Adamson 1867b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 1868b78724b7SJ. Bruce Fields { 1869b78724b7SJ. Bruce Fields switch (cbs->flavor) { 1870b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 1871b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 1872b78724b7SJ. Bruce Fields return nfs_ok; 1873b78724b7SJ. Bruce Fields default: 1874b78724b7SJ. Bruce Fields /* 1875b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 1876b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 1877b78724b7SJ. Bruce Fields * GSS. 1878b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 1879b78724b7SJ. Bruce Fields * client might think it can already handle: 1880b78724b7SJ. Bruce Fields */ 1881b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 1882b78724b7SJ. Bruce Fields } 1883b78724b7SJ. Bruce Fields } 1884b78724b7SJ. Bruce Fields 1885069b6ad4SAndy Adamson __be32 1886069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 1887069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 1888069b6ad4SAndy Adamson struct nfsd4_create_session *cr_ses) 1889069b6ad4SAndy Adamson { 1890363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 1891ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 1892ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 189381f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 189449557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 189557b7b43bSJ. Bruce Fields __be32 status = 0; 18968daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1897ec6b5d7bSAndy Adamson 1898a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 1899a62573dcSMi Jinlong return nfserr_inval; 1900b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 1901b78724b7SJ. Bruce Fields if (status) 1902b78724b7SJ. Bruce Fields return status; 190355c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 1904373cd409SJ. Bruce Fields if (status) 1905373cd409SJ. Bruce Fields return status; 190606b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 190706b332a5SJ. Bruce Fields if (status) 190806b332a5SJ. Bruce Fields return status; 190981f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 191055c760cfSJ. Bruce Fields new = alloc_session(&cr_ses->fore_channel); 191155c760cfSJ. Bruce Fields if (!new) 191255c760cfSJ. Bruce Fields goto out_release_drc_mem; 191381f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 191481f0b2a4SJ. Bruce Fields if (!conn) 191581f0b2a4SJ. Bruce Fields goto out_free_session; 1916a62573dcSMi Jinlong 1917ec6b5d7bSAndy Adamson nfs4_lock_state(); 19180a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 19198daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 192078389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 1921ec6b5d7bSAndy Adamson 1922ec6b5d7bSAndy Adamson if (conf) { 192357266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 192457266a6eSJ. Bruce Fields if (!mach_creds_match(conf, rqstp)) 192557266a6eSJ. Bruce Fields goto out_free_conn; 192649557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 192749557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 192838eb76a5SAndy Adamson if (status == nfserr_replay_cache) { 192949557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 193081f0b2a4SJ. Bruce Fields goto out_free_conn; 193149557cc7SAndy Adamson } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { 1932ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 193381f0b2a4SJ. Bruce Fields goto out_free_conn; 1934ec6b5d7bSAndy Adamson } 1935ec6b5d7bSAndy Adamson } else if (unconf) { 19368f9d3d3bSJ. Bruce Fields struct nfs4_client *old; 1937ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 1938363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 1939ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 194081f0b2a4SJ. Bruce Fields goto out_free_conn; 1941ec6b5d7bSAndy Adamson } 194257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 194357266a6eSJ. Bruce Fields if (!mach_creds_match(unconf, rqstp)) 194457266a6eSJ. Bruce Fields goto out_free_conn; 194549557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 194649557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 194738eb76a5SAndy Adamson if (status) { 194838eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 1949ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 195081f0b2a4SJ. Bruce Fields goto out_free_conn; 1951ec6b5d7bSAndy Adamson } 1952382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 1953221a6876SJ. Bruce Fields if (old) { 1954221a6876SJ. Bruce Fields status = mark_client_expired(old); 1955221a6876SJ. Bruce Fields if (status) 1956221a6876SJ. Bruce Fields goto out_free_conn; 19578f9d3d3bSJ. Bruce Fields expire_client(old); 1958221a6876SJ. Bruce Fields } 19598f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 1960ec6b5d7bSAndy Adamson conf = unconf; 1961ec6b5d7bSAndy Adamson } else { 1962ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 196381f0b2a4SJ. Bruce Fields goto out_free_conn; 1964ec6b5d7bSAndy Adamson } 196581f0b2a4SJ. Bruce Fields status = nfs_ok; 19668323c3b2SJ. Bruce Fields /* 1967408b79bcSJ. Bruce Fields * We do not support RDMA or persistent sessions 1968408b79bcSJ. Bruce Fields */ 1969408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 1970408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 1971408b79bcSJ. Bruce Fields 197281f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 197381f0b2a4SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, new); 197481f0b2a4SJ. Bruce Fields 1975ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 1976ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 197786c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 197849557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 1979ec6b5d7bSAndy Adamson 198049557cc7SAndy Adamson /* cache solo and embedded create sessions under the state lock */ 198149557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 1982ec6b5d7bSAndy Adamson nfs4_unlock_state(); 1983ec6b5d7bSAndy Adamson return status; 198481f0b2a4SJ. Bruce Fields out_free_conn: 1985266533c6SYanchuan Nian nfs4_unlock_state(); 198681f0b2a4SJ. Bruce Fields free_conn(conn); 198781f0b2a4SJ. Bruce Fields out_free_session: 198881f0b2a4SJ. Bruce Fields __free_session(new); 198955c760cfSJ. Bruce Fields out_release_drc_mem: 199055c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 19911ca50792SJ. Bruce Fields return status; 1992069b6ad4SAndy Adamson } 1993069b6ad4SAndy Adamson 19941d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 19951d1bc8f2SJ. Bruce Fields { 19961d1bc8f2SJ. Bruce Fields switch (*dir) { 19971d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 19981d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 19991d1bc8f2SJ. Bruce Fields return nfs_ok; 20001d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 20011d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 20021d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 20031d1bc8f2SJ. Bruce Fields return nfs_ok; 20041d1bc8f2SJ. Bruce Fields }; 20051d1bc8f2SJ. Bruce Fields return nfserr_inval; 20061d1bc8f2SJ. Bruce Fields } 20071d1bc8f2SJ. Bruce Fields 2008cb73a9f4SJ. Bruce Fields __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) 2009cb73a9f4SJ. Bruce Fields { 2010cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 2011c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2012b78724b7SJ. Bruce Fields __be32 status; 2013cb73a9f4SJ. Bruce Fields 2014b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 2015b78724b7SJ. Bruce Fields if (status) 2016b78724b7SJ. Bruce Fields return status; 2017c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2018cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 2019cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 2020c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2021cb73a9f4SJ. Bruce Fields 2022cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 2023cb73a9f4SJ. Bruce Fields 2024cb73a9f4SJ. Bruce Fields return nfs_ok; 2025cb73a9f4SJ. Bruce Fields } 2026cb73a9f4SJ. Bruce Fields 20271d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 20281d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 20291d1bc8f2SJ. Bruce Fields struct nfsd4_bind_conn_to_session *bcts) 20301d1bc8f2SJ. Bruce Fields { 20311d1bc8f2SJ. Bruce Fields __be32 status; 20323ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 20334f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 2034c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 20351d1bc8f2SJ. Bruce Fields 20361d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 20371d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 20384f6e6c17SJ. Bruce Fields nfs4_lock_state(); 2039c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 20404f6e6c17SJ. Bruce Fields session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp)); 2041c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 20424f6e6c17SJ. Bruce Fields status = nfserr_badsession; 20434f6e6c17SJ. Bruce Fields if (!session) 20444f6e6c17SJ. Bruce Fields goto out; 204557266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 204657266a6eSJ. Bruce Fields if (!mach_creds_match(session->se_client, rqstp)) 204757266a6eSJ. Bruce Fields goto out; 20481d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 20493ba63671SJ. Bruce Fields if (status) 20504f6e6c17SJ. Bruce Fields goto out; 20513ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 20524f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 20533ba63671SJ. Bruce Fields if (!conn) 20544f6e6c17SJ. Bruce Fields goto out; 20554f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 20564f6e6c17SJ. Bruce Fields status = nfs_ok; 20574f6e6c17SJ. Bruce Fields out: 20584f6e6c17SJ. Bruce Fields nfs4_unlock_state(); 20594f6e6c17SJ. Bruce Fields return status; 20601d1bc8f2SJ. Bruce Fields } 20611d1bc8f2SJ. Bruce Fields 20625d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) 20635d4cec2fSJ. Bruce Fields { 20645d4cec2fSJ. Bruce Fields if (!session) 20655d4cec2fSJ. Bruce Fields return 0; 20665d4cec2fSJ. Bruce Fields return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); 20675d4cec2fSJ. Bruce Fields } 20685d4cec2fSJ. Bruce Fields 2069069b6ad4SAndy Adamson __be32 2070069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r, 2071069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2072069b6ad4SAndy Adamson struct nfsd4_destroy_session *sessionid) 2073069b6ad4SAndy Adamson { 2074e10e0cfcSBenny Halevy struct nfsd4_session *ses; 2075abcdff09SJ. Bruce Fields __be32 status; 2076f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 2077c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); 2078e10e0cfcSBenny Halevy 2079abcdff09SJ. Bruce Fields nfs4_lock_state(); 2080abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 20815d4cec2fSJ. Bruce Fields if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { 208257716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 2083abcdff09SJ. Bruce Fields goto out; 2084f0f51f5cSJ. Bruce Fields ref_held_by_me++; 208557716355SJ. Bruce Fields } 2086e10e0cfcSBenny Halevy dump_sessionid(__func__, &sessionid->sessionid); 2087c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 20881872de0eSStanislav Kinsbursky ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); 2089abcdff09SJ. Bruce Fields status = nfserr_badsession; 2090abcdff09SJ. Bruce Fields if (!ses) 2091abcdff09SJ. Bruce Fields goto out_client_lock; 209257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 209357266a6eSJ. Bruce Fields if (!mach_creds_match(ses->se_client, r)) 209466b2b9b2SJ. Bruce Fields goto out_client_lock; 2095f0f51f5cSJ. Bruce Fields nfsd4_get_session_locked(ses); 2096f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 2097e10e0cfcSBenny Halevy if (status) 2098f0f51f5cSJ. Bruce Fields goto out_put_session; 2099e10e0cfcSBenny Halevy unhash_session(ses); 2100c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2101e10e0cfcSBenny Halevy 210284f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 210319cf5c02SJ. Bruce Fields 2104c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2105e10e0cfcSBenny Halevy status = nfs_ok; 2106f0f51f5cSJ. Bruce Fields out_put_session: 2107f0f51f5cSJ. Bruce Fields nfsd4_put_session(ses); 2108abcdff09SJ. Bruce Fields out_client_lock: 2109abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 2110e10e0cfcSBenny Halevy out: 2111abcdff09SJ. Bruce Fields nfs4_unlock_state(); 2112e10e0cfcSBenny Halevy return status; 2113069b6ad4SAndy Adamson } 2114069b6ad4SAndy Adamson 2115a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 2116328ead28SJ. Bruce Fields { 2117328ead28SJ. Bruce Fields struct nfsd4_conn *c; 2118328ead28SJ. Bruce Fields 2119328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 2120a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 2121328ead28SJ. Bruce Fields return c; 2122328ead28SJ. Bruce Fields } 2123328ead28SJ. Bruce Fields } 2124328ead28SJ. Bruce Fields return NULL; 2125328ead28SJ. Bruce Fields } 2126328ead28SJ. Bruce Fields 212757266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 2128328ead28SJ. Bruce Fields { 2129328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 2130a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 213157266a6eSJ. Bruce Fields __be32 status = nfs_ok; 213221b75b01SJ. Bruce Fields int ret; 2133328ead28SJ. Bruce Fields 2134328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 2135a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 213657266a6eSJ. Bruce Fields if (c) 213757266a6eSJ. Bruce Fields goto out_free; 213857266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 213957266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 214057266a6eSJ. Bruce Fields goto out_free; 2141328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 2142328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 214321b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 214421b75b01SJ. Bruce Fields if (ret) 214521b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 214621b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 214757266a6eSJ. Bruce Fields return nfs_ok; 214857266a6eSJ. Bruce Fields out_free: 214957266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 215057266a6eSJ. Bruce Fields free_conn(new); 215157266a6eSJ. Bruce Fields return status; 2152328ead28SJ. Bruce Fields } 2153328ead28SJ. Bruce Fields 2154868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 2155868b89c3SMi Jinlong { 2156868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 2157868b89c3SMi Jinlong 2158868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 2159868b89c3SMi Jinlong } 2160868b89c3SMi Jinlong 2161ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 2162ae82a8d0SMi Jinlong struct nfsd4_session *session) 2163ae82a8d0SMi Jinlong { 2164ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 2165ae82a8d0SMi Jinlong 2166ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 2167ae82a8d0SMi Jinlong } 2168ae82a8d0SMi Jinlong 2169069b6ad4SAndy Adamson __be32 2170b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp, 2171069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 2172069b6ad4SAndy Adamson struct nfsd4_sequence *seq) 2173069b6ad4SAndy Adamson { 2174f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 2175b85d4c01SBenny Halevy struct nfsd4_session *session; 2176221a6876SJ. Bruce Fields struct nfs4_client *clp; 2177b85d4c01SBenny Halevy struct nfsd4_slot *slot; 2178a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 217957b7b43bSJ. Bruce Fields __be32 status; 2180c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2181b85d4c01SBenny Halevy 2182f9bb94c4SAndy Adamson if (resp->opcnt != 1) 2183f9bb94c4SAndy Adamson return nfserr_sequence_pos; 2184f9bb94c4SAndy Adamson 2185a663bdd8SJ. Bruce Fields /* 2186a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 2187a663bdd8SJ. Bruce Fields * below. 2188a663bdd8SJ. Bruce Fields */ 2189a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 2190a663bdd8SJ. Bruce Fields if (!conn) 2191a663bdd8SJ. Bruce Fields return nfserr_jukebox; 2192a663bdd8SJ. Bruce Fields 2193c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2194b85d4c01SBenny Halevy status = nfserr_badsession; 21951872de0eSStanislav Kinsbursky session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp)); 2196b85d4c01SBenny Halevy if (!session) 2197221a6876SJ. Bruce Fields goto out_no_session; 2198221a6876SJ. Bruce Fields clp = session->se_client; 2199221a6876SJ. Bruce Fields status = get_client_locked(clp); 2200221a6876SJ. Bruce Fields if (status) 2201221a6876SJ. Bruce Fields goto out_no_session; 220266b2b9b2SJ. Bruce Fields status = nfsd4_get_session_locked(session); 220366b2b9b2SJ. Bruce Fields if (status) 220466b2b9b2SJ. Bruce Fields goto out_put_client; 2205b85d4c01SBenny Halevy 2206868b89c3SMi Jinlong status = nfserr_too_many_ops; 2207868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 220866b2b9b2SJ. Bruce Fields goto out_put_session; 2209868b89c3SMi Jinlong 2210ae82a8d0SMi Jinlong status = nfserr_req_too_big; 2211ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 221266b2b9b2SJ. Bruce Fields goto out_put_session; 2213ae82a8d0SMi Jinlong 2214b85d4c01SBenny Halevy status = nfserr_badslot; 22156c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 221666b2b9b2SJ. Bruce Fields goto out_put_session; 2217b85d4c01SBenny Halevy 2218557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 2219b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 2220b85d4c01SBenny Halevy 2221a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 2222a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 2223a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 2224a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 2225a8dfdaebSAndy Adamson 222673e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 222773e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 2228b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 2229bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 2230bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 223166b2b9b2SJ. Bruce Fields goto out_put_session; 2232b85d4c01SBenny Halevy cstate->slot = slot; 2233b85d4c01SBenny Halevy cstate->session = session; 2234da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 2235557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 2236bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 2237da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 2238aaf84eb9SBenny Halevy goto out; 2239b85d4c01SBenny Halevy } 2240b85d4c01SBenny Halevy if (status) 224166b2b9b2SJ. Bruce Fields goto out_put_session; 2242b85d4c01SBenny Halevy 224357266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 2244a663bdd8SJ. Bruce Fields conn = NULL; 224557266a6eSJ. Bruce Fields if (status) 224657266a6eSJ. Bruce Fields goto out_put_session; 2247328ead28SJ. Bruce Fields 2248b85d4c01SBenny Halevy /* Success! bump slot seqid */ 2249b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 2250bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 225173e79482SJ. Bruce Fields if (seq->cachethis) 225273e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 2253bf5c43c8SJ. Bruce Fields else 2254bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 2255b85d4c01SBenny Halevy 2256b85d4c01SBenny Halevy cstate->slot = slot; 2257b85d4c01SBenny Halevy cstate->session = session; 2258b85d4c01SBenny Halevy 2259b85d4c01SBenny Halevy out: 22605423732aSBenny Halevy switch (clp->cl_cb_state) { 22615423732aSBenny Halevy case NFSD4_CB_DOWN: 2262fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 22635423732aSBenny Halevy break; 22645423732aSBenny Halevy case NFSD4_CB_FAULT: 2265fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 22665423732aSBenny Halevy break; 2267fc0c3dd1SBenny Halevy default: 2268fc0c3dd1SBenny Halevy seq->status_flags = 0; 22695423732aSBenny Halevy } 22703bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 22713bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 2272221a6876SJ. Bruce Fields out_no_session: 2273a663bdd8SJ. Bruce Fields kfree(conn); 2274c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2275b85d4c01SBenny Halevy return status; 227666b2b9b2SJ. Bruce Fields out_put_session: 227766b2b9b2SJ. Bruce Fields nfsd4_put_session(session); 2278221a6876SJ. Bruce Fields out_put_client: 2279221a6876SJ. Bruce Fields put_client_renew_locked(clp); 2280221a6876SJ. Bruce Fields goto out_no_session; 2281069b6ad4SAndy Adamson } 2282069b6ad4SAndy Adamson 2283345c2842SMi Jinlong __be32 2284345c2842SMi Jinlong nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) 2285345c2842SMi Jinlong { 2286345c2842SMi Jinlong struct nfs4_client *conf, *unconf, *clp; 228757b7b43bSJ. Bruce Fields __be32 status = 0; 22888daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2289345c2842SMi Jinlong 2290345c2842SMi Jinlong nfs4_lock_state(); 22910a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 22928daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 229378389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2294345c2842SMi Jinlong 2295345c2842SMi Jinlong if (conf) { 2296345c2842SMi Jinlong clp = conf; 2297345c2842SMi Jinlong 2298c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 2299345c2842SMi Jinlong status = nfserr_clientid_busy; 2300345c2842SMi Jinlong goto out; 2301345c2842SMi Jinlong } 2302345c2842SMi Jinlong } else if (unconf) 2303345c2842SMi Jinlong clp = unconf; 2304345c2842SMi Jinlong else { 2305345c2842SMi Jinlong status = nfserr_stale_clientid; 2306345c2842SMi Jinlong goto out; 2307345c2842SMi Jinlong } 230857266a6eSJ. Bruce Fields if (!mach_creds_match(clp, rqstp)) { 230957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 231057266a6eSJ. Bruce Fields goto out; 231157266a6eSJ. Bruce Fields } 2312345c2842SMi Jinlong expire_client(clp); 2313345c2842SMi Jinlong out: 2314345c2842SMi Jinlong nfs4_unlock_state(); 2315345c2842SMi Jinlong return status; 2316345c2842SMi Jinlong } 2317345c2842SMi Jinlong 2318069b6ad4SAndy Adamson __be32 23194dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) 23204dc6ec00SJ. Bruce Fields { 232157b7b43bSJ. Bruce Fields __be32 status = 0; 2322bcecf1ccSMi Jinlong 23234dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 23244dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 23254dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 23264dc6ec00SJ. Bruce Fields /* 23274dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 23284dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 23294dc6ec00SJ. Bruce Fields */ 23304dc6ec00SJ. Bruce Fields return nfs_ok; 23314dc6ec00SJ. Bruce Fields } 2332bcecf1ccSMi Jinlong 23334dc6ec00SJ. Bruce Fields nfs4_lock_state(); 2334bcecf1ccSMi Jinlong status = nfserr_complete_already; 2335a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 2336a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 2337bcecf1ccSMi Jinlong goto out; 2338bcecf1ccSMi Jinlong 2339bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 2340bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 23414dc6ec00SJ. Bruce Fields /* 23424dc6ec00SJ. Bruce Fields * The following error isn't really legal. 23434dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 23444dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 23454dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 23464dc6ec00SJ. Bruce Fields * client. 23474dc6ec00SJ. Bruce Fields */ 2348bcecf1ccSMi Jinlong goto out; 2349bcecf1ccSMi Jinlong 2350bcecf1ccSMi Jinlong status = nfs_ok; 23512a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 2352bcecf1ccSMi Jinlong out: 23534dc6ec00SJ. Bruce Fields nfs4_unlock_state(); 2354bcecf1ccSMi Jinlong return status; 23554dc6ec00SJ. Bruce Fields } 23564dc6ec00SJ. Bruce Fields 23574dc6ec00SJ. Bruce Fields __be32 2358b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 2359b591480bSJ.Bruce Fields struct nfsd4_setclientid *setclid) 23601da177e4SLinus Torvalds { 2361a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 23621da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 236328ce6054SNeilBrown struct nfs4_client *conf, *unconf, *new; 2364b37ad28bSAl Viro __be32 status; 2365c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2366a55370a3SNeilBrown 236763db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 23681da177e4SLinus Torvalds nfs4_lock_state(); 2369382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 237028ce6054SNeilBrown if (conf) { 237163db4632SJ. Bruce Fields /* case 0: */ 23721da177e4SLinus Torvalds status = nfserr_clid_inuse; 2373e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 2374e203d506SJ. Bruce Fields goto out; 2375026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 2376363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 2377363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 2378363168b4SJeff Layton sizeof(addr_str)); 2379026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 2380363168b4SJeff Layton "at %s\n", addr_str); 23811da177e4SLinus Torvalds goto out; 23821da177e4SLinus Torvalds } 23831da177e4SLinus Torvalds } 2384a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 23851da177e4SLinus Torvalds if (unconf) 23861da177e4SLinus Torvalds expire_client(unconf); 23878f930711SJ. Bruce Fields status = nfserr_jukebox; 23882216d449SJeff Layton new = create_client(clname, rqstp, &clverifier); 2389a55370a3SNeilBrown if (new == NULL) 23901da177e4SLinus Torvalds goto out; 239134b232bbSJ. Bruce Fields if (conf && same_verf(&conf->cl_verifier, &clverifier)) 239263db4632SJ. Bruce Fields /* case 1: probable callback update */ 23931da177e4SLinus Torvalds copy_clid(new, conf); 239434b232bbSJ. Bruce Fields else /* case 4 (new client) or cases 2, 3 (client reboot): */ 2395c212cecfSStanislav Kinsbursky gen_clid(new, nn); 23968323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 23976f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 2398ac55fdc4SJeff Layton add_to_unconfirmed(new); 23991da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 24001da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 24011da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 24021da177e4SLinus Torvalds status = nfs_ok; 24031da177e4SLinus Torvalds out: 24041da177e4SLinus Torvalds nfs4_unlock_state(); 24051da177e4SLinus Torvalds return status; 24061da177e4SLinus Torvalds } 24071da177e4SLinus Torvalds 24081da177e4SLinus Torvalds 2409b37ad28bSAl Viro __be32 2410b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 2411b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 2412b591480bSJ.Bruce Fields struct nfsd4_setclientid_confirm *setclientid_confirm) 24131da177e4SLinus Torvalds { 241421ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 24151da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 24161da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 2417b37ad28bSAl Viro __be32 status; 24187f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 24191da177e4SLinus Torvalds 24202c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 24211da177e4SLinus Torvalds return nfserr_stale_clientid; 24221da177e4SLinus Torvalds nfs4_lock_state(); 242321ab45a4SNeilBrown 24248daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 24250a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 2426a186e767SJ. Bruce Fields /* 24278695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 24288695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 24298695b90aSJ. Bruce Fields * there's a bug somewhere. Let's charitably assume it's our 24308695b90aSJ. Bruce Fields * bug. 2431a186e767SJ. Bruce Fields */ 24328695b90aSJ. Bruce Fields status = nfserr_serverfault; 24338695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 24348695b90aSJ. Bruce Fields goto out; 24358695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 24368695b90aSJ. Bruce Fields goto out; 243763db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 243890d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 243990d700b7SJ. Bruce Fields if (conf && !unconf) /* case 2: probable retransmit */ 244090d700b7SJ. Bruce Fields status = nfs_ok; 244190d700b7SJ. Bruce Fields else /* case 4: client hasn't noticed we rebooted yet? */ 244290d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 244390d700b7SJ. Bruce Fields goto out; 244490d700b7SJ. Bruce Fields } 244590d700b7SJ. Bruce Fields status = nfs_ok; 244690d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 24475a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 24485a3c9d71SJ. Bruce Fields nfsd4_probe_callback(conf); 24491a69c179SNeilBrown expire_client(unconf); 245090d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 2451382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&unconf->cl_name, nn); 2452221a6876SJ. Bruce Fields if (conf) { 2453221a6876SJ. Bruce Fields status = mark_client_expired(conf); 2454221a6876SJ. Bruce Fields if (status) 2455221a6876SJ. Bruce Fields goto out; 24561a69c179SNeilBrown expire_client(conf); 2457221a6876SJ. Bruce Fields } 24581da177e4SLinus Torvalds move_to_confirmed(unconf); 2459f3d03b92SJ. Bruce Fields nfsd4_probe_callback(unconf); 246008e8987cSNeilBrown } 24611da177e4SLinus Torvalds out: 24621da177e4SLinus Torvalds nfs4_unlock_state(); 24631da177e4SLinus Torvalds return status; 24641da177e4SLinus Torvalds } 24651da177e4SLinus Torvalds 246632513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 24671da177e4SLinus Torvalds { 246832513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 246932513b40SJ. Bruce Fields } 247032513b40SJ. Bruce Fields 247132513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 247232513b40SJ. Bruce Fields static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino) 247332513b40SJ. Bruce Fields { 24741da177e4SLinus Torvalds unsigned int hashval = file_hashval(ino); 24751da177e4SLinus Torvalds 24768b671b80SJ. Bruce Fields atomic_set(&fp->fi_ref, 1); 24778beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 24788beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 24791da177e4SLinus Torvalds fp->fi_inode = igrab(ino); 248047f9940cSMeelap Shah fp->fi_had_conflict = false; 2481acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 2482f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 2483f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 248447cee541SPavel Emelyanov spin_lock(&recall_lock); 248589876f8cSJeff Layton hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]); 248647cee541SPavel Emelyanov spin_unlock(&recall_lock); 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds static void 2490e18b890bSChristoph Lameter nfsd4_free_slab(struct kmem_cache **slab) 2491e60d4398SNeilBrown { 2492e60d4398SNeilBrown if (*slab == NULL) 2493e60d4398SNeilBrown return; 24941a1d92c1SAlexey Dobriyan kmem_cache_destroy(*slab); 2495e60d4398SNeilBrown *slab = NULL; 2496e60d4398SNeilBrown } 2497e60d4398SNeilBrown 2498e8ff2a84SJ. Bruce Fields void 2499e60d4398SNeilBrown nfsd4_free_slabs(void) 2500e60d4398SNeilBrown { 2501fe0750e5SJ. Bruce Fields nfsd4_free_slab(&openowner_slab); 2502fe0750e5SJ. Bruce Fields nfsd4_free_slab(&lockowner_slab); 2503e60d4398SNeilBrown nfsd4_free_slab(&file_slab); 25045ac049acSNeilBrown nfsd4_free_slab(&stateid_slab); 25055b2d21c1SNeilBrown nfsd4_free_slab(&deleg_slab); 2506e60d4398SNeilBrown } 25071da177e4SLinus Torvalds 250872083396SBryan Schumaker int 25091da177e4SLinus Torvalds nfsd4_init_slabs(void) 25101da177e4SLinus Torvalds { 2511fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 2512fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 2513fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 2514fe0750e5SJ. Bruce Fields goto out_nomem; 2515fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 25163c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 2517fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 2518e60d4398SNeilBrown goto out_nomem; 2519e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 252020c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 2521e60d4398SNeilBrown if (file_slab == NULL) 2522e60d4398SNeilBrown goto out_nomem; 25235ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 2524dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 25255ac049acSNeilBrown if (stateid_slab == NULL) 25265ac049acSNeilBrown goto out_nomem; 25275b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 252820c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 25295b2d21c1SNeilBrown if (deleg_slab == NULL) 25305b2d21c1SNeilBrown goto out_nomem; 2531e60d4398SNeilBrown return 0; 2532e60d4398SNeilBrown out_nomem: 2533e60d4398SNeilBrown nfsd4_free_slabs(); 25341da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 25351da177e4SLinus Torvalds return -ENOMEM; 25361da177e4SLinus Torvalds } 25371da177e4SLinus Torvalds 2538fe0750e5SJ. Bruce Fields void nfs4_free_openowner(struct nfs4_openowner *oo) 25391da177e4SLinus Torvalds { 2540fe0750e5SJ. Bruce Fields kfree(oo->oo_owner.so_owner.data); 2541fe0750e5SJ. Bruce Fields kmem_cache_free(openowner_slab, oo); 2542fe0750e5SJ. Bruce Fields } 2543fe0750e5SJ. Bruce Fields 2544fe0750e5SJ. Bruce Fields void nfs4_free_lockowner(struct nfs4_lockowner *lo) 2545fe0750e5SJ. Bruce Fields { 2546fe0750e5SJ. Bruce Fields kfree(lo->lo_owner.so_owner.data); 2547fe0750e5SJ. Bruce Fields kmem_cache_free(lockowner_slab, lo); 25481da177e4SLinus Torvalds } 25491da177e4SLinus Torvalds 2550ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 2551ff194bd9SJ. Bruce Fields { 2552ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 2553ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 2554ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 2555ff194bd9SJ. Bruce Fields } 2556ff194bd9SJ. Bruce Fields 2557fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 25581da177e4SLinus Torvalds { 25591da177e4SLinus Torvalds struct nfs4_stateowner *sop; 25601da177e4SLinus Torvalds 2561fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 2562ff194bd9SJ. Bruce Fields if (!sop) 2563ff194bd9SJ. Bruce Fields return NULL; 2564ff194bd9SJ. Bruce Fields 2565ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 2566ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 2567fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 2568ff194bd9SJ. Bruce Fields return NULL; 2569ff194bd9SJ. Bruce Fields } 25701da177e4SLinus Torvalds sop->so_owner.len = owner->len; 2571ff194bd9SJ. Bruce Fields 2572ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 2573ff194bd9SJ. Bruce Fields sop->so_client = clp; 2574ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 25751da177e4SLinus Torvalds return sop; 25761da177e4SLinus Torvalds } 2577ff194bd9SJ. Bruce Fields 2578fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 2579ff194bd9SJ. Bruce Fields { 25809b531137SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 25819b531137SStanislav Kinsbursky 25829b531137SStanislav Kinsbursky list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); 2583fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 25841da177e4SLinus Torvalds } 25851da177e4SLinus Torvalds 2586fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 25871da177e4SLinus Torvalds alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { 2588fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 25891da177e4SLinus Torvalds 2590fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 2591fe0750e5SJ. Bruce Fields if (!oo) 25921da177e4SLinus Torvalds return NULL; 2593fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 2594fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 2595d29b20cdSJ. Bruce Fields oo->oo_flags = NFS4_OO_NEW; 2596fe0750e5SJ. Bruce Fields oo->oo_time = 0; 259738c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 2598fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 2599fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 2600fe0750e5SJ. Bruce Fields return oo; 26011da177e4SLinus Torvalds } 26021da177e4SLinus Torvalds 2603996e0938SJ. Bruce Fields static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { 2604fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 26051da177e4SLinus Torvalds 26063abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 2607ea1da636SNeilBrown INIT_LIST_HEAD(&stp->st_lockowners); 2608fe0750e5SJ. Bruce Fields list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 26098beefa24SNeilBrown list_add(&stp->st_perfile, &fp->fi_stateids); 2610fe0750e5SJ. Bruce Fields stp->st_stateowner = &oo->oo_owner; 261113cd2184SNeilBrown get_nfs4_file(fp); 26121da177e4SLinus Torvalds stp->st_file = fp; 26131da177e4SLinus Torvalds stp->st_access_bmap = 0; 26141da177e4SLinus Torvalds stp->st_deny_bmap = 0; 261582c5ff1bSJeff Layton set_access(open->op_share_access, stp); 2616ce0fc43cSJeff Layton set_deny(open->op_share_deny, stp); 26174c4cd222SNeilBrown stp->st_openstp = NULL; 26181da177e4SLinus Torvalds } 26191da177e4SLinus Torvalds 26201da177e4SLinus Torvalds static void 262173758fedSStanislav Kinsbursky move_to_close_lru(struct nfs4_openowner *oo, struct net *net) 26221da177e4SLinus Torvalds { 262373758fedSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 262473758fedSStanislav Kinsbursky 2625fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 26261da177e4SLinus Torvalds 262773758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 2628fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 26291da177e4SLinus Torvalds } 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds static int 2632599e0a22SJ. Bruce Fields same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, 2633599e0a22SJ. Bruce Fields clientid_t *clid) 2634599e0a22SJ. Bruce Fields { 2635599e0a22SJ. Bruce Fields return (sop->so_owner.len == owner->len) && 2636599e0a22SJ. Bruce Fields 0 == memcmp(sop->so_owner.data, owner->data, owner->len) && 2637599e0a22SJ. Bruce Fields (sop->so_client->cl_clientid.cl_id == clid->cl_id); 26381da177e4SLinus Torvalds } 26391da177e4SLinus Torvalds 2640fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 26419b531137SStanislav Kinsbursky find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 26429b531137SStanislav Kinsbursky bool sessions, struct nfsd_net *nn) 26431da177e4SLinus Torvalds { 2644a50d2ad1SJ. Bruce Fields struct nfs4_stateowner *so; 2645a50d2ad1SJ. Bruce Fields struct nfs4_openowner *oo; 2646d15c077eSJ. Bruce Fields struct nfs4_client *clp; 26471da177e4SLinus Torvalds 26489b531137SStanislav Kinsbursky list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) { 264916bfdaafSJ. Bruce Fields if (!so->so_is_open_owner) 265016bfdaafSJ. Bruce Fields continue; 2651a50d2ad1SJ. Bruce Fields if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { 2652a50d2ad1SJ. Bruce Fields oo = openowner(so); 2653d15c077eSJ. Bruce Fields clp = oo->oo_owner.so_client; 2654d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2655d15c077eSJ. Bruce Fields return NULL; 2656a50d2ad1SJ. Bruce Fields renew_client(oo->oo_owner.so_client); 2657a50d2ad1SJ. Bruce Fields return oo; 2658a50d2ad1SJ. Bruce Fields } 26591da177e4SLinus Torvalds } 26601da177e4SLinus Torvalds return NULL; 26611da177e4SLinus Torvalds } 26621da177e4SLinus Torvalds 26631da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 26641da177e4SLinus Torvalds static struct nfs4_file * 26651da177e4SLinus Torvalds find_file(struct inode *ino) 26661da177e4SLinus Torvalds { 26671da177e4SLinus Torvalds unsigned int hashval = file_hashval(ino); 26681da177e4SLinus Torvalds struct nfs4_file *fp; 26691da177e4SLinus Torvalds 26708b671b80SJ. Bruce Fields spin_lock(&recall_lock); 267189876f8cSJeff Layton hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { 267213cd2184SNeilBrown if (fp->fi_inode == ino) { 267313cd2184SNeilBrown get_nfs4_file(fp); 26748b671b80SJ. Bruce Fields spin_unlock(&recall_lock); 26751da177e4SLinus Torvalds return fp; 26761da177e4SLinus Torvalds } 267713cd2184SNeilBrown } 26788b671b80SJ. Bruce Fields spin_unlock(&recall_lock); 26791da177e4SLinus Torvalds return NULL; 26801da177e4SLinus Torvalds } 26811da177e4SLinus Torvalds 26824f83aa30SJ. Bruce Fields /* 26831da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 26841da177e4SLinus Torvalds * WRITE with all zero or all one stateid 26851da177e4SLinus Torvalds */ 2686b37ad28bSAl Viro static __be32 26871da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 26881da177e4SLinus Torvalds { 26891da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 26901da177e4SLinus Torvalds struct nfs4_file *fp; 2691dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 2692b37ad28bSAl Viro __be32 ret; 26931da177e4SLinus Torvalds 26941da177e4SLinus Torvalds fp = find_file(ino); 269513cd2184SNeilBrown if (!fp) 269613cd2184SNeilBrown return nfs_ok; 2697b700949bSNeilBrown ret = nfserr_locked; 26981da177e4SLinus Torvalds /* Search for conflicting share reservations */ 26998beefa24SNeilBrown list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { 2700ce0fc43cSJeff Layton if (test_deny(deny_type, stp) || 2701ce0fc43cSJeff Layton test_deny(NFS4_SHARE_DENY_BOTH, stp)) 270213cd2184SNeilBrown goto out; 27031da177e4SLinus Torvalds } 270413cd2184SNeilBrown ret = nfs_ok; 270513cd2184SNeilBrown out: 270613cd2184SNeilBrown put_nfs4_file(fp); 270713cd2184SNeilBrown return ret; 27081da177e4SLinus Torvalds } 27091da177e4SLinus Torvalds 27106b57d9c8SJ. Bruce Fields static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 27111da177e4SLinus Torvalds { 2712e8c69d17SJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 2713e8c69d17SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2714e8c69d17SJ. Bruce Fields 27151da177e4SLinus Torvalds /* We're assuming the state code never drops its reference 27161da177e4SLinus Torvalds * without first removing the lease. Since we're in this lease 27171da177e4SLinus Torvalds * callback (and since the lease code is serialized by the kernel 27181da177e4SLinus Torvalds * lock) we know the server hasn't removed the lease yet, we know 27191da177e4SLinus Torvalds * it's safe to take a reference: */ 27201da177e4SLinus Torvalds atomic_inc(&dp->dl_count); 27211da177e4SLinus Torvalds 2722e8c69d17SJ. Bruce Fields list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 27231da177e4SLinus Torvalds 27241c8c601aSJeff Layton /* Only place dl_time is set; protected by i_lock: */ 27251da177e4SLinus Torvalds dp->dl_time = get_seconds(); 27261da177e4SLinus Torvalds 27276b57d9c8SJ. Bruce Fields nfsd4_cb_recall(dp); 27286b57d9c8SJ. Bruce Fields } 27296b57d9c8SJ. Bruce Fields 27301c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 27316b57d9c8SJ. Bruce Fields static void nfsd_break_deleg_cb(struct file_lock *fl) 27326b57d9c8SJ. Bruce Fields { 2733acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 2734acfdf5c3SJ. Bruce Fields struct nfs4_delegation *dp; 27356b57d9c8SJ. Bruce Fields 27367fa10cd1SJ. Bruce Fields if (!fp) { 27377fa10cd1SJ. Bruce Fields WARN(1, "(%p)->fl_owner NULL\n", fl); 27387fa10cd1SJ. Bruce Fields return; 27397fa10cd1SJ. Bruce Fields } 27407fa10cd1SJ. Bruce Fields if (fp->fi_had_conflict) { 27417fa10cd1SJ. Bruce Fields WARN(1, "duplicate break on %p\n", fp); 27427fa10cd1SJ. Bruce Fields return; 27437fa10cd1SJ. Bruce Fields } 27440272e1fdSJ. Bruce Fields /* 27450272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 2746acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 27476b57d9c8SJ. Bruce Fields * in time: 27480272e1fdSJ. Bruce Fields */ 27490272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 27501da177e4SLinus Torvalds 27515d926e8cSJ. Bruce Fields spin_lock(&recall_lock); 2752acfdf5c3SJ. Bruce Fields fp->fi_had_conflict = true; 2753acfdf5c3SJ. Bruce Fields list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 27545d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 27555d926e8cSJ. Bruce Fields spin_unlock(&recall_lock); 27561da177e4SLinus Torvalds } 27571da177e4SLinus Torvalds 27581da177e4SLinus Torvalds static 27591da177e4SLinus Torvalds int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) 27601da177e4SLinus Torvalds { 27611da177e4SLinus Torvalds if (arg & F_UNLCK) 27621da177e4SLinus Torvalds return lease_modify(onlist, arg); 27631da177e4SLinus Torvalds else 27641da177e4SLinus Torvalds return -EAGAIN; 27651da177e4SLinus Torvalds } 27661da177e4SLinus Torvalds 27677b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 27688fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 27698fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 27701da177e4SLinus Torvalds }; 27711da177e4SLinus Torvalds 27727a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 27737a8711c9SJ. Bruce Fields { 27747a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 27757a8711c9SJ. Bruce Fields return nfs_ok; 27767a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 27777a8711c9SJ. Bruce Fields return nfserr_replay_me; 27787a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 27797a8711c9SJ. Bruce Fields return nfs_ok; 27807a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 27817a8711c9SJ. Bruce Fields } 27821da177e4SLinus Torvalds 2783b37ad28bSAl Viro __be32 27846668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 27853320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 27861da177e4SLinus Torvalds { 27871da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 27881da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 27891da177e4SLinus Torvalds unsigned int strhashval; 2790fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 27914cdc951bSJ. Bruce Fields __be32 status; 27921da177e4SLinus Torvalds 27932c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 27941da177e4SLinus Torvalds return nfserr_stale_clientid; 279532513b40SJ. Bruce Fields /* 279632513b40SJ. Bruce Fields * In case we need it later, after we've already created the 279732513b40SJ. Bruce Fields * file and don't want to risk a further failure: 279832513b40SJ. Bruce Fields */ 279932513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 280032513b40SJ. Bruce Fields if (open->op_file == NULL) 280132513b40SJ. Bruce Fields return nfserr_jukebox; 28021da177e4SLinus Torvalds 280316bfdaafSJ. Bruce Fields strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); 28049b531137SStanislav Kinsbursky oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn); 2805fe0750e5SJ. Bruce Fields open->op_openowner = oo; 2806fe0750e5SJ. Bruce Fields if (!oo) { 28078daae4dcSStanislav Kinsbursky clp = find_confirmed_client(clientid, cstate->minorversion, 28088daae4dcSStanislav Kinsbursky nn); 28090f442aa2SJ. Bruce Fields if (clp == NULL) 28100f442aa2SJ. Bruce Fields return nfserr_expired; 2811bcf130f9SJ. Bruce Fields goto new_owner; 28120f442aa2SJ. Bruce Fields } 2813dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 28140f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 2815fe0750e5SJ. Bruce Fields clp = oo->oo_owner.so_client; 2816fe0750e5SJ. Bruce Fields release_openowner(oo); 2817fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 2818bcf130f9SJ. Bruce Fields goto new_owner; 28190f442aa2SJ. Bruce Fields } 28204cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 28214cdc951bSJ. Bruce Fields if (status) 28224cdc951bSJ. Bruce Fields return status; 28234cdc951bSJ. Bruce Fields clp = oo->oo_owner.so_client; 28244cdc951bSJ. Bruce Fields goto alloc_stateid; 2825bcf130f9SJ. Bruce Fields new_owner: 2826fe0750e5SJ. Bruce Fields oo = alloc_init_open_stateowner(strhashval, clp, open); 2827fe0750e5SJ. Bruce Fields if (oo == NULL) 28283e772463SJ. Bruce Fields return nfserr_jukebox; 2829fe0750e5SJ. Bruce Fields open->op_openowner = oo; 28304cdc951bSJ. Bruce Fields alloc_stateid: 28314cdc951bSJ. Bruce Fields open->op_stp = nfs4_alloc_stateid(clp); 28324cdc951bSJ. Bruce Fields if (!open->op_stp) 28334cdc951bSJ. Bruce Fields return nfserr_jukebox; 28340f442aa2SJ. Bruce Fields return nfs_ok; 28351da177e4SLinus Torvalds } 28361da177e4SLinus Torvalds 2837b37ad28bSAl Viro static inline __be32 28384a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 28394a6e43e6SNeilBrown { 28404a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 28414a6e43e6SNeilBrown return nfserr_openmode; 28424a6e43e6SNeilBrown else 28434a6e43e6SNeilBrown return nfs_ok; 28444a6e43e6SNeilBrown } 28454a6e43e6SNeilBrown 2846c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 284724a0111eSJ. Bruce Fields { 284824a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 284924a0111eSJ. Bruce Fields } 285024a0111eSJ. Bruce Fields 285138c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 2852f459e453SJ. Bruce Fields { 2853f459e453SJ. Bruce Fields struct nfs4_stid *ret; 2854f459e453SJ. Bruce Fields 285538c2f4b1SJ. Bruce Fields ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); 2856f459e453SJ. Bruce Fields if (!ret) 2857f459e453SJ. Bruce Fields return NULL; 2858f459e453SJ. Bruce Fields return delegstateid(ret); 2859f459e453SJ. Bruce Fields } 2860f459e453SJ. Bruce Fields 28618b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 28628b289b2cSJ. Bruce Fields { 28638b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 28648b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 28658b289b2cSJ. Bruce Fields } 28668b289b2cSJ. Bruce Fields 2867b37ad28bSAl Viro static __be32 286841d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 2869567d9829SNeilBrown struct nfs4_delegation **dp) 2870567d9829SNeilBrown { 2871567d9829SNeilBrown int flags; 2872b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 2873567d9829SNeilBrown 287438c2f4b1SJ. Bruce Fields *dp = find_deleg_stateid(cl, &open->op_delegate_stateid); 2875567d9829SNeilBrown if (*dp == NULL) 2876c44c5eebSNeilBrown goto out; 287724a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 2878567d9829SNeilBrown status = nfs4_check_delegmode(*dp, flags); 2879567d9829SNeilBrown if (status) 2880567d9829SNeilBrown *dp = NULL; 2881c44c5eebSNeilBrown out: 28828b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 2883c44c5eebSNeilBrown return nfs_ok; 2884c44c5eebSNeilBrown if (status) 2885c44c5eebSNeilBrown return status; 2886dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 2887c44c5eebSNeilBrown return nfs_ok; 2888567d9829SNeilBrown } 2889567d9829SNeilBrown 2890b37ad28bSAl Viro static __be32 2891dcef0413SJ. Bruce Fields nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp) 28921da177e4SLinus Torvalds { 2893dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *local; 2894fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 28951da177e4SLinus Torvalds 28968beefa24SNeilBrown list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 28971da177e4SLinus Torvalds /* ignore lock owners */ 28981da177e4SLinus Torvalds if (local->st_stateowner->so_is_open_owner == 0) 28991da177e4SLinus Torvalds continue; 29001da177e4SLinus Torvalds /* remember if we have seen this open owner */ 2901fe0750e5SJ. Bruce Fields if (local->st_stateowner == &oo->oo_owner) 29021da177e4SLinus Torvalds *stpp = local; 29031da177e4SLinus Torvalds /* check for conflicting share reservations */ 29041da177e4SLinus Torvalds if (!test_share(local, open)) 290577eaae8dSJ. Bruce Fields return nfserr_share_denied; 29061da177e4SLinus Torvalds } 290777eaae8dSJ. Bruce Fields return nfs_ok; 29081da177e4SLinus Torvalds } 29091da177e4SLinus Torvalds 291021fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 291121fb4016SJ. Bruce Fields { 291221fb4016SJ. Bruce Fields int flags = 0; 291321fb4016SJ. Bruce Fields 291421fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 291521fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 291621fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 291721fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 291821fb4016SJ. Bruce Fields return flags; 291921fb4016SJ. Bruce Fields } 292021fb4016SJ. Bruce Fields 29210c12eaffSCasey Bodley static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 29220c12eaffSCasey Bodley struct svc_fh *cur_fh, struct nfsd4_open *open) 2923f9d7562fSJ. Bruce Fields { 2924f9d7562fSJ. Bruce Fields __be32 status; 29250c12eaffSCasey Bodley int oflag = nfs4_access_to_omode(open->op_share_access); 29260c12eaffSCasey Bodley int access = nfs4_access_to_access(open->op_share_access); 29270c12eaffSCasey Bodley 2928f9d7562fSJ. Bruce Fields if (!fp->fi_fds[oflag]) { 2929f9d7562fSJ. Bruce Fields status = nfsd_open(rqstp, cur_fh, S_IFREG, access, 2930f9d7562fSJ. Bruce Fields &fp->fi_fds[oflag]); 2931f9d7562fSJ. Bruce Fields if (status) 2932f9d7562fSJ. Bruce Fields return status; 2933f9d7562fSJ. Bruce Fields } 2934f9d7562fSJ. Bruce Fields nfs4_file_get_access(fp, oflag); 2935f9d7562fSJ. Bruce Fields 2936f9d7562fSJ. Bruce Fields return nfs_ok; 2937f9d7562fSJ. Bruce Fields } 2938f9d7562fSJ. Bruce Fields 2939b37ad28bSAl Viro static inline __be32 29401da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 29411da177e4SLinus Torvalds struct nfsd4_open *open) 29421da177e4SLinus Torvalds { 29431da177e4SLinus Torvalds struct iattr iattr = { 29441da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 29451da177e4SLinus Torvalds .ia_size = 0, 29461da177e4SLinus Torvalds }; 29471da177e4SLinus Torvalds if (!open->op_truncate) 29481da177e4SLinus Torvalds return 0; 29491da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 29509246585aSAl Viro return nfserr_inval; 29511da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 29521da177e4SLinus Torvalds } 29531da177e4SLinus Torvalds 2954b37ad28bSAl Viro static __be32 2955dcef0413SJ. 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) 29561da177e4SLinus Torvalds { 2957b6d2f1caSJ. Bruce Fields u32 op_share_access = open->op_share_access; 29587d947842SJ. Bruce Fields bool new_access; 2959b37ad28bSAl Viro __be32 status; 29601da177e4SLinus Torvalds 296182c5ff1bSJeff Layton new_access = !test_access(op_share_access, stp); 2962f9d7562fSJ. Bruce Fields if (new_access) { 29630c12eaffSCasey Bodley status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); 2964f9d7562fSJ. Bruce Fields if (status) 2965f9d7562fSJ. Bruce Fields return status; 29666c26d08fSJ. Bruce Fields } 29671da177e4SLinus Torvalds status = nfsd4_truncate(rqstp, cur_fh, open); 29681da177e4SLinus Torvalds if (status) { 2969f9d7562fSJ. Bruce Fields if (new_access) { 2970f197c271SJ. Bruce Fields int oflag = nfs4_access_to_omode(op_share_access); 2971f9d7562fSJ. Bruce Fields nfs4_file_put_access(fp, oflag); 2972f9d7562fSJ. Bruce Fields } 29731da177e4SLinus Torvalds return status; 29741da177e4SLinus Torvalds } 29751da177e4SLinus Torvalds /* remember the open */ 297682c5ff1bSJeff Layton set_access(op_share_access, stp); 2977ce0fc43cSJeff Layton set_deny(open->op_share_deny, stp); 29781da177e4SLinus Torvalds 29791da177e4SLinus Torvalds return nfs_ok; 29801da177e4SLinus Torvalds } 29811da177e4SLinus Torvalds 29821da177e4SLinus Torvalds 29831da177e4SLinus Torvalds static void 29841255a8f3SJ. Bruce Fields nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session) 29851da177e4SLinus Torvalds { 2986dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 29871da177e4SLinus Torvalds } 29881da177e4SLinus Torvalds 298914a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 299014a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 299114a24e99SJ. Bruce Fields { 299214a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 299314a24e99SJ. Bruce Fields return true; 299414a24e99SJ. Bruce Fields /* 299514a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 299614a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 299714a24e99SJ. Bruce Fields * until we hear otherwise: 299814a24e99SJ. Bruce Fields */ 299914a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 300014a24e99SJ. Bruce Fields } 300114a24e99SJ. Bruce Fields 300222d38c4cSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag) 300322d38c4cSJ. Bruce Fields { 300422d38c4cSJ. Bruce Fields struct file_lock *fl; 300522d38c4cSJ. Bruce Fields 300622d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 300722d38c4cSJ. Bruce Fields if (!fl) 300822d38c4cSJ. Bruce Fields return NULL; 300922d38c4cSJ. Bruce Fields locks_init_lock(fl); 301022d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 301122d38c4cSJ. Bruce Fields fl->fl_flags = FL_LEASE; 301222d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 301322d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 3014acfdf5c3SJ. Bruce Fields fl->fl_owner = (fl_owner_t)(dp->dl_file); 301522d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 301622d38c4cSJ. Bruce Fields return fl; 301722d38c4cSJ. Bruce Fields } 301822d38c4cSJ. Bruce Fields 301999c41515SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp) 3020edab9782SJ. Bruce Fields { 3021acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = dp->dl_file; 3022edab9782SJ. Bruce Fields struct file_lock *fl; 3023edab9782SJ. Bruce Fields int status; 3024edab9782SJ. Bruce Fields 302599c41515SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 3026edab9782SJ. Bruce Fields if (!fl) 3027edab9782SJ. Bruce Fields return -ENOMEM; 3028acfdf5c3SJ. Bruce Fields fl->fl_file = find_readable_file(fp); 30292a74aba7SJ. Bruce Fields list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); 3030acfdf5c3SJ. Bruce Fields status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); 3031edab9782SJ. Bruce Fields if (status) { 3032acfdf5c3SJ. Bruce Fields list_del_init(&dp->dl_perclnt); 3033edab9782SJ. Bruce Fields locks_free_lock(fl); 3034b1948a64SJ. Bruce Fields return status; 3035edab9782SJ. Bruce Fields } 3036acfdf5c3SJ. Bruce Fields fp->fi_lease = fl; 3037cb0942b8SAl Viro fp->fi_deleg_file = get_file(fl->fl_file); 3038acfdf5c3SJ. Bruce Fields atomic_set(&fp->fi_delegees, 1); 3039acfdf5c3SJ. Bruce Fields list_add(&dp->dl_perfile, &fp->fi_delegations); 3040acfdf5c3SJ. Bruce Fields return 0; 3041acfdf5c3SJ. Bruce Fields } 3042acfdf5c3SJ. Bruce Fields 3043bf7bd3e9SJ. Bruce Fields static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp) 3044acfdf5c3SJ. Bruce Fields { 3045bf7bd3e9SJ. Bruce Fields int status; 3046acfdf5c3SJ. Bruce Fields 3047bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 3048bf7bd3e9SJ. Bruce Fields return -EAGAIN; 3049bf7bd3e9SJ. Bruce Fields get_nfs4_file(fp); 3050bf7bd3e9SJ. Bruce Fields dp->dl_file = fp; 3051bf7bd3e9SJ. Bruce Fields if (!fp->fi_lease) { 3052bf7bd3e9SJ. Bruce Fields status = nfs4_setlease(dp); 3053bf7bd3e9SJ. Bruce Fields if (status) 3054bf7bd3e9SJ. Bruce Fields goto out_free; 3055bf7bd3e9SJ. Bruce Fields return 0; 3056bf7bd3e9SJ. Bruce Fields } 3057acfdf5c3SJ. Bruce Fields spin_lock(&recall_lock); 3058acfdf5c3SJ. Bruce Fields if (fp->fi_had_conflict) { 3059acfdf5c3SJ. Bruce Fields spin_unlock(&recall_lock); 3060bf7bd3e9SJ. Bruce Fields status = -EAGAIN; 3061bf7bd3e9SJ. Bruce Fields goto out_free; 3062acfdf5c3SJ. Bruce Fields } 3063acfdf5c3SJ. Bruce Fields atomic_inc(&fp->fi_delegees); 3064acfdf5c3SJ. Bruce Fields list_add(&dp->dl_perfile, &fp->fi_delegations); 3065acfdf5c3SJ. Bruce Fields spin_unlock(&recall_lock); 30662a74aba7SJ. Bruce Fields list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); 3067edab9782SJ. Bruce Fields return 0; 3068bf7bd3e9SJ. Bruce Fields out_free: 3069bf7bd3e9SJ. Bruce Fields put_nfs4_file(fp); 3070bf7bd3e9SJ. Bruce Fields dp->dl_file = fp; 3071bf7bd3e9SJ. Bruce Fields return status; 3072edab9782SJ. Bruce Fields } 3073edab9782SJ. Bruce Fields 30744aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 30754aa8913cSBenny Halevy { 30764aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 30774aa8913cSBenny Halevy if (status == -EAGAIN) 30784aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 30794aa8913cSBenny Halevy else { 30804aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 30814aa8913cSBenny Halevy switch (open->op_deleg_want) { 30824aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 30834aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 30844aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 30854aa8913cSBenny Halevy break; 30864aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 30874aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 30884aa8913cSBenny Halevy break; 30894aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 3090063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 30914aa8913cSBenny Halevy } 30924aa8913cSBenny Halevy } 30934aa8913cSBenny Halevy } 30944aa8913cSBenny Halevy 30951da177e4SLinus Torvalds /* 30961da177e4SLinus Torvalds * Attempt to hand out a delegation. 309799c41515SJ. Bruce Fields * 309899c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 309999c41515SJ. Bruce Fields * proper support for them. 31001da177e4SLinus Torvalds */ 31011da177e4SLinus Torvalds static void 31025ccb0066SStanislav Kinsbursky nfs4_open_delegation(struct net *net, struct svc_fh *fh, 31035ccb0066SStanislav Kinsbursky struct nfsd4_open *open, struct nfs4_ol_stateid *stp) 31041da177e4SLinus Torvalds { 31051da177e4SLinus Torvalds struct nfs4_delegation *dp; 3106fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); 310714a24e99SJ. Bruce Fields int cb_up; 310899c41515SJ. Bruce Fields int status = 0; 31091da177e4SLinus Torvalds 3110fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 31117b190fecSNeilBrown open->op_recall = 0; 31127b190fecSNeilBrown switch (open->op_claim_type) { 31137b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 31142bf23875SJ. Bruce Fields if (!cb_up) 31157b190fecSNeilBrown open->op_recall = 1; 311699c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 311799c41515SJ. Bruce Fields goto out_no_deleg; 31187b190fecSNeilBrown break; 31197b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 312099c41515SJ. Bruce Fields /* 312199c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 312299c41515SJ. Bruce Fields * had the chance to reclaim theirs.... 312399c41515SJ. Bruce Fields */ 31245ccb0066SStanislav Kinsbursky if (locks_in_grace(net)) 312599c41515SJ. Bruce Fields goto out_no_deleg; 3126dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 312799c41515SJ. Bruce Fields goto out_no_deleg; 31289a0590aeSSteve Dickson /* 31299a0590aeSSteve Dickson * Also, if the file was opened for write or 31309a0590aeSSteve Dickson * create, there's a good chance the client's 31319a0590aeSSteve Dickson * about to write to it, resulting in an 31329a0590aeSSteve Dickson * immediate recall (since we don't support 31339a0590aeSSteve Dickson * write delegations): 31349a0590aeSSteve Dickson */ 31351da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 313699c41515SJ. Bruce Fields goto out_no_deleg; 313799c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 313899c41515SJ. Bruce Fields goto out_no_deleg; 31397b190fecSNeilBrown break; 31407b190fecSNeilBrown default: 314199c41515SJ. Bruce Fields goto out_no_deleg; 31427b190fecSNeilBrown } 314399c41515SJ. Bruce Fields dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh); 3144dd239cc0SJ. Bruce Fields if (dp == NULL) 3145dd239cc0SJ. Bruce Fields goto out_no_deleg; 3146bf7bd3e9SJ. Bruce Fields status = nfs4_set_delegation(dp, stp->st_file); 3147edab9782SJ. Bruce Fields if (status) 3148dd239cc0SJ. Bruce Fields goto out_free; 31491da177e4SLinus Torvalds 3150d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 31511da177e4SLinus Torvalds 31528c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 3153d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 315499c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 3155dd239cc0SJ. Bruce Fields return; 3156dd239cc0SJ. Bruce Fields out_free: 315724ffb938SJ. Bruce Fields unhash_stid(&dp->dl_stid); 3158acfdf5c3SJ. Bruce Fields nfs4_put_delegation(dp); 3159dd239cc0SJ. Bruce Fields out_no_deleg: 316099c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 31617b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 3162d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 31631da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 3164d08d32e6SJ. Bruce Fields open->op_recall = 1; 3165d08d32e6SJ. Bruce Fields } 3166dd239cc0SJ. Bruce Fields 3167dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 3168dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 3169dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 3170dd239cc0SJ. Bruce Fields return; 31711da177e4SLinus Torvalds } 31721da177e4SLinus Torvalds 3173e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 3174e27f49c3SBenny Halevy struct nfs4_delegation *dp) 3175e27f49c3SBenny Halevy { 3176e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 3177e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 3178e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3179e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 3180e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 3181e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 3182e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3183e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 3184e27f49c3SBenny Halevy } 3185e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 3186e27f49c3SBenny Halevy * it already has, therefore we don't return 3187e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 3188e27f49c3SBenny Halevy */ 3189e27f49c3SBenny Halevy } 3190e27f49c3SBenny Halevy 31911da177e4SLinus Torvalds /* 31921da177e4SLinus Torvalds * called with nfs4_lock_state() held. 31931da177e4SLinus Torvalds */ 3194b37ad28bSAl Viro __be32 31951da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 31961da177e4SLinus Torvalds { 31976668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 319838c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 31991da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 32001da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 3201dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 3202567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 3203b37ad28bSAl Viro __be32 status; 32041da177e4SLinus Torvalds 32051da177e4SLinus Torvalds /* 32061da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 32071da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 32081da177e4SLinus Torvalds * If not found, create the nfs4_file struct 32091da177e4SLinus Torvalds */ 32101da177e4SLinus Torvalds fp = find_file(ino); 32111da177e4SLinus Torvalds if (fp) { 32121da177e4SLinus Torvalds if ((status = nfs4_check_open(fp, open, &stp))) 32131da177e4SLinus Torvalds goto out; 321441d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 3215c44c5eebSNeilBrown if (status) 3216c44c5eebSNeilBrown goto out; 32171da177e4SLinus Torvalds } else { 3218c44c5eebSNeilBrown status = nfserr_bad_stateid; 32198b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 3220c44c5eebSNeilBrown goto out; 32213e772463SJ. Bruce Fields status = nfserr_jukebox; 322232513b40SJ. Bruce Fields fp = open->op_file; 322332513b40SJ. Bruce Fields open->op_file = NULL; 322432513b40SJ. Bruce Fields nfsd4_init_file(fp, ino); 32251da177e4SLinus Torvalds } 32261da177e4SLinus Torvalds 32271da177e4SLinus Torvalds /* 32281da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 32291da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 32301da177e4SLinus Torvalds */ 32311da177e4SLinus Torvalds if (stp) { 32321da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 3233f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 32341da177e4SLinus Torvalds if (status) 32351da177e4SLinus Torvalds goto out; 32361da177e4SLinus Torvalds } else { 32374cdc951bSJ. Bruce Fields status = nfs4_get_vfs_file(rqstp, fp, current_fh, open); 3238567d9829SNeilBrown if (status) 32391da177e4SLinus Torvalds goto out; 32404af82504SJ. Bruce Fields status = nfsd4_truncate(rqstp, current_fh, open); 32414af82504SJ. Bruce Fields if (status) 32424af82504SJ. Bruce Fields goto out; 32434cdc951bSJ. Bruce Fields stp = open->op_stp; 32444cdc951bSJ. Bruce Fields open->op_stp = NULL; 3245996e0938SJ. Bruce Fields init_open_stateid(stp, fp, open); 32461da177e4SLinus Torvalds } 3247dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 3248dcef0413SJ. Bruce Fields memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 32491da177e4SLinus Torvalds 3250d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 3251dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 32526668958fSAndy Adamson 3253d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 3254d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 3255d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 3256d24433cdSBenny Halevy goto nodeleg; 3257d24433cdSBenny Halevy } 3258d24433cdSBenny Halevy } 3259d24433cdSBenny Halevy 32601da177e4SLinus Torvalds /* 32611da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 32621da177e4SLinus Torvalds * OPEN succeeds even if we fail. 32631da177e4SLinus Torvalds */ 32645ccb0066SStanislav Kinsbursky nfs4_open_delegation(SVC_NET(rqstp), current_fh, open, stp); 3265d24433cdSBenny Halevy nodeleg: 32661da177e4SLinus Torvalds status = nfs_ok; 32671da177e4SLinus Torvalds 32688c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 3269dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 32701da177e4SLinus Torvalds out: 3271d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 3272d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 3273e27f49c3SBenny Halevy open->op_deleg_want) 3274e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 3275d24433cdSBenny Halevy 327613cd2184SNeilBrown if (fp) 327713cd2184SNeilBrown put_nfs4_file(fp); 327837515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 32791255a8f3SJ. Bruce Fields nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate)); 32801da177e4SLinus Torvalds /* 32811da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 32821da177e4SLinus Torvalds */ 32831da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 3284dad1c067SJ. Bruce Fields if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) && 32856668958fSAndy Adamson !nfsd4_has_session(&resp->cstate)) 32861da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 32871da177e4SLinus Torvalds 32881da177e4SLinus Torvalds return status; 32891da177e4SLinus Torvalds } 32901da177e4SLinus Torvalds 3291d29b20cdSJ. Bruce Fields void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) 3292d29b20cdSJ. Bruce Fields { 3293d29b20cdSJ. Bruce Fields if (open->op_openowner) { 3294d29b20cdSJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 3295d29b20cdSJ. Bruce Fields 3296d29b20cdSJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 3297d29b20cdSJ. Bruce Fields list_del_init(&oo->oo_close_lru); 3298d29b20cdSJ. Bruce Fields if (oo->oo_flags & NFS4_OO_NEW) { 3299d29b20cdSJ. Bruce Fields if (status) { 3300d29b20cdSJ. Bruce Fields release_openowner(oo); 3301d29b20cdSJ. Bruce Fields open->op_openowner = NULL; 3302d29b20cdSJ. Bruce Fields } else 3303d29b20cdSJ. Bruce Fields oo->oo_flags &= ~NFS4_OO_NEW; 3304d29b20cdSJ. Bruce Fields } 3305d29b20cdSJ. Bruce Fields } 330632513b40SJ. Bruce Fields if (open->op_file) 330732513b40SJ. Bruce Fields nfsd4_free_file(open->op_file); 33084cdc951bSJ. Bruce Fields if (open->op_stp) 3309ef79859eSJ. Bruce Fields free_generic_stateid(open->op_stp); 3310d29b20cdSJ. Bruce Fields } 3311d29b20cdSJ. Bruce Fields 33129b2ef62bSJ. Bruce Fields static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp) 33139b2ef62bSJ. Bruce Fields { 33149b2ef62bSJ. Bruce Fields struct nfs4_client *found; 33159b2ef62bSJ. Bruce Fields 33169b2ef62bSJ. Bruce Fields if (STALE_CLIENTID(clid, nn)) 33179b2ef62bSJ. Bruce Fields return nfserr_stale_clientid; 33189b2ef62bSJ. Bruce Fields found = find_confirmed_client(clid, session, nn); 33199b2ef62bSJ. Bruce Fields if (clp) 33209b2ef62bSJ. Bruce Fields *clp = found; 33219b2ef62bSJ. Bruce Fields return found ? nfs_ok : nfserr_expired; 33229b2ef62bSJ. Bruce Fields } 33239b2ef62bSJ. Bruce Fields 3324b37ad28bSAl Viro __be32 3325b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3326b591480bSJ.Bruce Fields clientid_t *clid) 33271da177e4SLinus Torvalds { 33281da177e4SLinus Torvalds struct nfs4_client *clp; 3329b37ad28bSAl Viro __be32 status; 33307f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 33311da177e4SLinus Torvalds 33321da177e4SLinus Torvalds nfs4_lock_state(); 33331da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 33341da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 33359b2ef62bSJ. Bruce Fields status = lookup_clientid(clid, cstate->minorversion, nn, &clp); 33369b2ef62bSJ. Bruce Fields if (status) 33371da177e4SLinus Torvalds goto out; 33381da177e4SLinus Torvalds status = nfserr_cb_path_down; 3339ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 334077a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 33411da177e4SLinus Torvalds goto out; 33421da177e4SLinus Torvalds status = nfs_ok; 33431da177e4SLinus Torvalds out: 33441da177e4SLinus Torvalds nfs4_unlock_state(); 33451da177e4SLinus Torvalds return status; 33461da177e4SLinus Torvalds } 33471da177e4SLinus Torvalds 3348a76b4319SNeilBrown static void 334912760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 3350a76b4319SNeilBrown { 335133dcc481SJeff Layton /* do nothing if grace period already ended */ 3352a51c84edSStanislav Kinsbursky if (nn->grace_ended) 335333dcc481SJeff Layton return; 335433dcc481SJeff Layton 3355a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 3356a51c84edSStanislav Kinsbursky nn->grace_ended = true; 335712760c66SStanislav Kinsbursky nfsd4_record_grace_done(nn, nn->boot_time); 33585e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 3359e46b498cSJ. Bruce Fields /* 3360e46b498cSJ. Bruce Fields * Now that every NFSv4 client has had the chance to recover and 3361e46b498cSJ. Bruce Fields * to see the (possibly new, possibly shorter) lease time, we 3362e46b498cSJ. Bruce Fields * can safely set the next grace time to the current lease time: 3363e46b498cSJ. Bruce Fields */ 33645284b44eSStanislav Kinsbursky nn->nfsd4_grace = nn->nfsd4_lease; 3365a76b4319SNeilBrown } 3366a76b4319SNeilBrown 3367fd39ca9aSNeilBrown static time_t 336809121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 33691da177e4SLinus Torvalds { 33701da177e4SLinus Torvalds struct nfs4_client *clp; 3371fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 33721da177e4SLinus Torvalds struct nfs4_delegation *dp; 33731da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 33743d733711SStanislav Kinsbursky time_t cutoff = get_seconds() - nn->nfsd4_lease; 33753d733711SStanislav Kinsbursky time_t t, clientid_val = nn->nfsd4_lease; 33763d733711SStanislav Kinsbursky time_t u, test_val = nn->nfsd4_lease; 33771da177e4SLinus Torvalds 33781da177e4SLinus Torvalds nfs4_lock_state(); 33791da177e4SLinus Torvalds 33801da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 338112760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 338236acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 3383c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 33845ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 33851da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 33861da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 33871da177e4SLinus Torvalds t = clp->cl_time - cutoff; 33881da177e4SLinus Torvalds if (clientid_val > t) 33891da177e4SLinus Torvalds clientid_val = t; 33901da177e4SLinus Torvalds break; 33911da177e4SLinus Torvalds } 3392221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 3393d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 3394d7682988SBenny Halevy clp->cl_clientid.cl_id); 3395d7682988SBenny Halevy continue; 3396d7682988SBenny Halevy } 3397221a6876SJ. Bruce Fields list_move(&clp->cl_lru, &reaplist); 339836acb66bSBenny Halevy } 3399c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 340036acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 340136acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 34021da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 34031da177e4SLinus Torvalds clp->cl_clientid.cl_id); 34041da177e4SLinus Torvalds expire_client(clp); 34051da177e4SLinus Torvalds } 34061da177e4SLinus Torvalds spin_lock(&recall_lock); 3407e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 34081da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 34094e37a7c2SStanislav Kinsbursky if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) 34104e37a7c2SStanislav Kinsbursky continue; 34111da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 34121da177e4SLinus Torvalds u = dp->dl_time - cutoff; 34131da177e4SLinus Torvalds if (test_val > u) 34141da177e4SLinus Torvalds test_val = u; 34151da177e4SLinus Torvalds break; 34161da177e4SLinus Torvalds } 34171da177e4SLinus Torvalds list_move(&dp->dl_recall_lru, &reaplist); 34181da177e4SLinus Torvalds } 34191da177e4SLinus Torvalds spin_unlock(&recall_lock); 34201da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 34211da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 34223bd64a5bSJ. Bruce Fields revoke_delegation(dp); 34231da177e4SLinus Torvalds } 34243d733711SStanislav Kinsbursky test_val = nn->nfsd4_lease; 342573758fedSStanislav Kinsbursky list_for_each_safe(pos, next, &nn->close_lru) { 3426fe0750e5SJ. Bruce Fields oo = container_of(pos, struct nfs4_openowner, oo_close_lru); 3427fe0750e5SJ. Bruce Fields if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { 3428fe0750e5SJ. Bruce Fields u = oo->oo_time - cutoff; 34291da177e4SLinus Torvalds if (test_val > u) 34301da177e4SLinus Torvalds test_val = u; 34311da177e4SLinus Torvalds break; 34321da177e4SLinus Torvalds } 3433fe0750e5SJ. Bruce Fields release_openowner(oo); 34341da177e4SLinus Torvalds } 34351da177e4SLinus Torvalds if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) 34361da177e4SLinus Torvalds clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; 34371da177e4SLinus Torvalds nfs4_unlock_state(); 34381da177e4SLinus Torvalds return clientid_val; 34391da177e4SLinus Torvalds } 34401da177e4SLinus Torvalds 3441a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 3442a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 3443a254b246SHarvey Harrison 3444a254b246SHarvey Harrison static void 344509121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 34461da177e4SLinus Torvalds { 34471da177e4SLinus Torvalds time_t t; 344809121281SStanislav Kinsbursky struct delayed_work *dwork = container_of(laundry, struct delayed_work, 344909121281SStanislav Kinsbursky work); 345009121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 345109121281SStanislav Kinsbursky laundromat_work); 34521da177e4SLinus Torvalds 345309121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 34541da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 345509121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 34561da177e4SLinus Torvalds } 34571da177e4SLinus Torvalds 3458f7a4d872SJ. Bruce Fields static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) 3459f8816512SNeilBrown { 3460f7a4d872SJ. Bruce Fields if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode) 3461f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 3462f7a4d872SJ. Bruce Fields return nfs_ok; 34631da177e4SLinus Torvalds } 34641da177e4SLinus Torvalds 34651da177e4SLinus Torvalds static inline int 346682c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 34671da177e4SLinus Torvalds { 346882c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 346982c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 347082c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 34711da177e4SLinus Torvalds } 34721da177e4SLinus Torvalds 34731da177e4SLinus Torvalds static inline int 347482c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 34751da177e4SLinus Torvalds { 347682c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 347782c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 34781da177e4SLinus Torvalds } 34791da177e4SLinus Torvalds 34801da177e4SLinus Torvalds static 3481dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 34821da177e4SLinus Torvalds { 3483b37ad28bSAl Viro __be32 status = nfserr_openmode; 34841da177e4SLinus Torvalds 348502921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 348602921914SJ. Bruce Fields if (stp->st_openstp) 348702921914SJ. Bruce Fields stp = stp->st_openstp; 348882c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 34891da177e4SLinus Torvalds goto out; 349082c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 34911da177e4SLinus Torvalds goto out; 34921da177e4SLinus Torvalds status = nfs_ok; 34931da177e4SLinus Torvalds out: 34941da177e4SLinus Torvalds return status; 34951da177e4SLinus Torvalds } 34961da177e4SLinus Torvalds 3497b37ad28bSAl Viro static inline __be32 34985ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 34991da177e4SLinus Torvalds { 3500203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 35011da177e4SLinus Torvalds return nfs_ok; 35025ccb0066SStanislav Kinsbursky else if (locks_in_grace(net)) { 350325985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 35041da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 35051da177e4SLinus Torvalds return nfserr_grace; 35061da177e4SLinus Torvalds } else if (flags & WR_STATE) 35071da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 35081da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 35091da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 35101da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 35111da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 35121da177e4SLinus Torvalds } 35131da177e4SLinus Torvalds 35141da177e4SLinus Torvalds /* 35151da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 35161da177e4SLinus Torvalds * that are not able to provide mandatory locking. 35171da177e4SLinus Torvalds */ 35181da177e4SLinus Torvalds static inline int 35195ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 35201da177e4SLinus Torvalds { 35215ccb0066SStanislav Kinsbursky return locks_in_grace(net) && mandatory_lock(inode); 35221da177e4SLinus Torvalds } 35231da177e4SLinus Torvalds 352481b82965SJ. Bruce Fields /* Returns true iff a is later than b: */ 352581b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b) 352681b82965SJ. Bruce Fields { 35271a9357f4SJim Rees return (s32)(a->si_generation - b->si_generation) > 0; 352881b82965SJ. Bruce Fields } 352981b82965SJ. Bruce Fields 353057b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 35310836f587SJ. Bruce Fields { 35326668958fSAndy Adamson /* 35336668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 35346668958fSAndy Adamson * when it is zero. 35356668958fSAndy Adamson */ 353628dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 353781b82965SJ. Bruce Fields return nfs_ok; 353881b82965SJ. Bruce Fields 353981b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 354081b82965SJ. Bruce Fields return nfs_ok; 35416668958fSAndy Adamson 35420836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 354381b82965SJ. Bruce Fields if (stateid_generation_after(in, ref)) 35440836f587SJ. Bruce Fields return nfserr_bad_stateid; 35450836f587SJ. Bruce Fields /* 354681b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 354781b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 354881b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 354981b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 355081b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 355181b82965SJ. Bruce Fields * but better performance may result in retrying IO that 355281b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 355381b82965SJ. Bruce Fields * reordered in flight: 35540836f587SJ. Bruce Fields */ 35550836f587SJ. Bruce Fields return nfserr_old_stateid; 35560836f587SJ. Bruce Fields } 35570836f587SJ. Bruce Fields 35587df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 355917456804SBryan Schumaker { 356097b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 356197b7e3b6SJ. Bruce Fields struct nfs4_ol_stateid *ols; 356297b7e3b6SJ. Bruce Fields __be32 status; 356317456804SBryan Schumaker 35647df302f7SChuck Lever if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 35657df302f7SChuck Lever return nfserr_bad_stateid; 35667df302f7SChuck Lever /* Client debugging aid. */ 35677df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 35687df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 35697df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 35707df302f7SChuck Lever sizeof(addr_str)); 35717df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 35727df302f7SChuck Lever "with incorrect client ID\n", addr_str); 35737df302f7SChuck Lever return nfserr_bad_stateid; 35747df302f7SChuck Lever } 357538c2f4b1SJ. Bruce Fields s = find_stateid(cl, stateid); 357697b7e3b6SJ. Bruce Fields if (!s) 35777df302f7SChuck Lever return nfserr_bad_stateid; 357836279ac1SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, 1); 357917456804SBryan Schumaker if (status) 358017456804SBryan Schumaker return status; 358123340032SJ. Bruce Fields switch (s->sc_type) { 358223340032SJ. Bruce Fields case NFS4_DELEG_STID: 358397b7e3b6SJ. Bruce Fields return nfs_ok; 35843bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 35853bd64a5bSJ. Bruce Fields return nfserr_deleg_revoked; 358623340032SJ. Bruce Fields case NFS4_OPEN_STID: 358723340032SJ. Bruce Fields case NFS4_LOCK_STID: 358897b7e3b6SJ. Bruce Fields ols = openlockstateid(s); 358997b7e3b6SJ. Bruce Fields if (ols->st_stateowner->so_is_open_owner 359023340032SJ. Bruce Fields && !(openowner(ols->st_stateowner)->oo_flags 359123340032SJ. Bruce Fields & NFS4_OO_CONFIRMED)) 359297b7e3b6SJ. Bruce Fields return nfserr_bad_stateid; 359397b7e3b6SJ. Bruce Fields return nfs_ok; 359423340032SJ. Bruce Fields default: 359523340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 359623340032SJ. Bruce Fields case NFS4_CLOSED_STID: 359723340032SJ. Bruce Fields return nfserr_bad_stateid; 359823340032SJ. Bruce Fields } 359917456804SBryan Schumaker } 360017456804SBryan Schumaker 36013320fef1SStanislav Kinsbursky static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, 36023320fef1SStanislav Kinsbursky struct nfs4_stid **s, bool sessions, 36033320fef1SStanislav Kinsbursky struct nfsd_net *nn) 360438c2f4b1SJ. Bruce Fields { 360538c2f4b1SJ. Bruce Fields struct nfs4_client *cl; 36060eb6f20aSJ. Bruce Fields __be32 status; 360738c2f4b1SJ. Bruce Fields 360838c2f4b1SJ. Bruce Fields if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 360938c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 36100eb6f20aSJ. Bruce Fields status = lookup_clientid(&stateid->si_opaque.so_clid, sessions, 36110eb6f20aSJ. Bruce Fields nn, &cl); 36120eb6f20aSJ. Bruce Fields if (status == nfserr_stale_clientid) 361338c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 36140eb6f20aSJ. Bruce Fields if (status) 36150eb6f20aSJ. Bruce Fields return status; 361638c2f4b1SJ. Bruce Fields *s = find_stateid_by_type(cl, stateid, typemask); 361738c2f4b1SJ. Bruce Fields if (!*s) 361838c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 361938c2f4b1SJ. Bruce Fields return nfs_ok; 362038c2f4b1SJ. Bruce Fields } 362138c2f4b1SJ. Bruce Fields 36221da177e4SLinus Torvalds /* 36231da177e4SLinus Torvalds * Checks for stateid operations 36241da177e4SLinus Torvalds */ 3625b37ad28bSAl Viro __be32 36265ccb0066SStanislav Kinsbursky nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, 3627dd453dfdSBenny Halevy stateid_t *stateid, int flags, struct file **filpp) 36281da177e4SLinus Torvalds { 362969064a27SJ. Bruce Fields struct nfs4_stid *s; 3630dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 36311da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 3632dd453dfdSBenny Halevy struct svc_fh *current_fh = &cstate->current_fh; 36331da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 36343320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3635b37ad28bSAl Viro __be32 status; 36361da177e4SLinus Torvalds 36371da177e4SLinus Torvalds if (filpp) 36381da177e4SLinus Torvalds *filpp = NULL; 36391da177e4SLinus Torvalds 36405ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 36411da177e4SLinus Torvalds return nfserr_grace; 36421da177e4SLinus Torvalds 36431da177e4SLinus Torvalds if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 36445ccb0066SStanislav Kinsbursky return check_special_stateids(net, current_fh, stateid, flags); 36451da177e4SLinus Torvalds 36463320fef1SStanislav Kinsbursky status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 36473320fef1SStanislav Kinsbursky &s, cstate->minorversion, nn); 364838c2f4b1SJ. Bruce Fields if (status) 364938c2f4b1SJ. Bruce Fields return status; 365069064a27SJ. Bruce Fields status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); 36510c2a498fSJ. Bruce Fields if (status) 36520c2a498fSJ. Bruce Fields goto out; 3653f7a4d872SJ. Bruce Fields switch (s->sc_type) { 3654f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 365569064a27SJ. Bruce Fields dp = delegstateid(s); 3656dc9bf700SJ. Bruce Fields status = nfs4_check_delegmode(dp, flags); 3657dc9bf700SJ. Bruce Fields if (status) 3658dc9bf700SJ. Bruce Fields goto out; 365943b0178eSDan Carpenter if (filpp) { 3660acfdf5c3SJ. Bruce Fields *filpp = dp->dl_file->fi_deleg_file; 3661063b0fb9SJ. Bruce Fields if (!*filpp) { 3662063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 3663063b0fb9SJ. Bruce Fields status = nfserr_serverfault; 3664063b0fb9SJ. Bruce Fields goto out; 3665063b0fb9SJ. Bruce Fields } 366643b0178eSDan Carpenter } 3667f7a4d872SJ. Bruce Fields break; 3668f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 3669f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 367069064a27SJ. Bruce Fields stp = openlockstateid(s); 3671f7a4d872SJ. Bruce Fields status = nfs4_check_fh(current_fh, stp); 3672f7a4d872SJ. Bruce Fields if (status) 36731da177e4SLinus Torvalds goto out; 3674fe0750e5SJ. Bruce Fields if (stp->st_stateowner->so_is_open_owner 3675dad1c067SJ. Bruce Fields && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 36761da177e4SLinus Torvalds goto out; 3677a4455be0SJ. Bruce Fields status = nfs4_check_openmode(stp, flags); 3678a4455be0SJ. Bruce Fields if (status) 36791da177e4SLinus Torvalds goto out; 3680f9d7562fSJ. Bruce Fields if (filpp) { 3681f9d7562fSJ. Bruce Fields if (flags & RD_STATE) 3682f9d7562fSJ. Bruce Fields *filpp = find_readable_file(stp->st_file); 3683f9d7562fSJ. Bruce Fields else 3684f9d7562fSJ. Bruce Fields *filpp = find_writeable_file(stp->st_file); 3685f9d7562fSJ. Bruce Fields } 3686f7a4d872SJ. Bruce Fields break; 3687f7a4d872SJ. Bruce Fields default: 3688f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 36891da177e4SLinus Torvalds } 36901da177e4SLinus Torvalds status = nfs_ok; 36911da177e4SLinus Torvalds out: 36921da177e4SLinus Torvalds return status; 36931da177e4SLinus Torvalds } 36941da177e4SLinus Torvalds 3695e1ca12dfSBryan Schumaker static __be32 3696dcef0413SJ. Bruce Fields nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp) 3697e1ca12dfSBryan Schumaker { 3698fe0750e5SJ. Bruce Fields if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner))) 3699e1ca12dfSBryan Schumaker return nfserr_locks_held; 3700e1ca12dfSBryan Schumaker release_lock_stateid(stp); 3701e1ca12dfSBryan Schumaker return nfs_ok; 3702e1ca12dfSBryan Schumaker } 3703e1ca12dfSBryan Schumaker 3704e1ca12dfSBryan Schumaker /* 370517456804SBryan Schumaker * Test if the stateid is valid 370617456804SBryan Schumaker */ 370717456804SBryan Schumaker __be32 370817456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 370917456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 371017456804SBryan Schumaker { 371103cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 371203cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 371303cfb420SBryan Schumaker 371403cfb420SBryan Schumaker nfs4_lock_state(); 371503cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 37167df302f7SChuck Lever stateid->ts_id_status = 37177df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 371803cfb420SBryan Schumaker nfs4_unlock_state(); 371903cfb420SBryan Schumaker 372017456804SBryan Schumaker return nfs_ok; 372117456804SBryan Schumaker } 372217456804SBryan Schumaker 3723e1ca12dfSBryan Schumaker __be32 3724e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3725e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 3726e1ca12dfSBryan Schumaker { 3727e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 37282da1cec7SJ. Bruce Fields struct nfs4_stid *s; 37293bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 373038c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 37312da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 3732e1ca12dfSBryan Schumaker 3733e1ca12dfSBryan Schumaker nfs4_lock_state(); 373438c2f4b1SJ. Bruce Fields s = find_stateid(cl, stateid); 37352da1cec7SJ. Bruce Fields if (!s) 3736e1ca12dfSBryan Schumaker goto out; 37372da1cec7SJ. Bruce Fields switch (s->sc_type) { 37382da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 3739e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 3740e1ca12dfSBryan Schumaker goto out; 37412da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 37422da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 37432da1cec7SJ. Bruce Fields ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 37442da1cec7SJ. Bruce Fields if (ret) 3745e1ca12dfSBryan Schumaker goto out; 37462da1cec7SJ. Bruce Fields if (s->sc_type == NFS4_LOCK_STID) 37472da1cec7SJ. Bruce Fields ret = nfsd4_free_lock_stateid(openlockstateid(s)); 37482da1cec7SJ. Bruce Fields else 37492da1cec7SJ. Bruce Fields ret = nfserr_locks_held; 3750f7a4d872SJ. Bruce Fields break; 37513bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 37523bd64a5bSJ. Bruce Fields dp = delegstateid(s); 37533bd64a5bSJ. Bruce Fields destroy_revoked_delegation(dp); 37543bd64a5bSJ. Bruce Fields ret = nfs_ok; 37553bd64a5bSJ. Bruce Fields break; 3756f7a4d872SJ. Bruce Fields default: 3757f7a4d872SJ. Bruce Fields ret = nfserr_bad_stateid; 3758e1ca12dfSBryan Schumaker } 3759e1ca12dfSBryan Schumaker out: 3760e1ca12dfSBryan Schumaker nfs4_unlock_state(); 3761e1ca12dfSBryan Schumaker return ret; 3762e1ca12dfSBryan Schumaker } 3763e1ca12dfSBryan Schumaker 37644c4cd222SNeilBrown static inline int 37654c4cd222SNeilBrown setlkflg (int type) 37664c4cd222SNeilBrown { 37674c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 37684c4cd222SNeilBrown RD_STATE : WR_STATE; 37694c4cd222SNeilBrown } 37701da177e4SLinus Torvalds 3771dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 3772c0a5d93eSJ. Bruce Fields { 3773c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 3774c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 3775c0a5d93eSJ. Bruce Fields __be32 status; 3776c0a5d93eSJ. Bruce Fields 3777c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 3778c0a5d93eSJ. Bruce Fields if (status) 3779c0a5d93eSJ. Bruce Fields return status; 37803bd64a5bSJ. Bruce Fields if (stp->st_stid.sc_type == NFS4_CLOSED_STID 37813bd64a5bSJ. Bruce Fields || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID) 3782f7a4d872SJ. Bruce Fields /* 3783f7a4d872SJ. Bruce Fields * "Closed" stateid's exist *only* to return 37843bd64a5bSJ. Bruce Fields * nfserr_replay_me from the previous step, and 37853bd64a5bSJ. Bruce Fields * revoked delegations are kept only for free_stateid. 3786f7a4d872SJ. Bruce Fields */ 3787f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 3788f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 3789f7a4d872SJ. Bruce Fields if (status) 3790f7a4d872SJ. Bruce Fields return status; 3791f7a4d872SJ. Bruce Fields return nfs4_check_fh(current_fh, stp); 3792c0a5d93eSJ. Bruce Fields } 3793c0a5d93eSJ. Bruce Fields 37941da177e4SLinus Torvalds /* 37951da177e4SLinus Torvalds * Checks for sequence id mutating operations. 37961da177e4SLinus Torvalds */ 3797b37ad28bSAl Viro static __be32 3798dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 37992288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 38003320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 38013320fef1SStanislav Kinsbursky struct nfsd_net *nn) 38021da177e4SLinus Torvalds { 38030836f587SJ. Bruce Fields __be32 status; 380438c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 38051da177e4SLinus Torvalds 38068c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 38078c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 38081da177e4SLinus Torvalds 38091da177e4SLinus Torvalds *stpp = NULL; 38103320fef1SStanislav Kinsbursky status = nfsd4_lookup_stateid(stateid, typemask, &s, 38113320fef1SStanislav Kinsbursky cstate->minorversion, nn); 3812c0a5d93eSJ. Bruce Fields if (status) 3813c0a5d93eSJ. Bruce Fields return status; 381438c2f4b1SJ. Bruce Fields *stpp = openlockstateid(s); 38153d74e6a5SJ. Bruce Fields if (!nfsd4_has_session(cstate)) 3816c0a5d93eSJ. Bruce Fields cstate->replay_owner = (*stpp)->st_stateowner; 38171da177e4SLinus Torvalds 3818c0a5d93eSJ. Bruce Fields return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); 38191da177e4SLinus Torvalds } 38201da177e4SLinus Torvalds 38213320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 38223320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 3823c0a5d93eSJ. Bruce Fields { 3824c0a5d93eSJ. Bruce Fields __be32 status; 3825c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 38261da177e4SLinus Torvalds 3827c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 38283320fef1SStanislav Kinsbursky NFS4_OPEN_STID, stpp, nn); 38290836f587SJ. Bruce Fields if (status) 38300836f587SJ. Bruce Fields return status; 3831c0a5d93eSJ. Bruce Fields oo = openowner((*stpp)->st_stateowner); 3832dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) 3833c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 38343a4f98bbSNeilBrown return nfs_ok; 38351da177e4SLinus Torvalds } 38361da177e4SLinus Torvalds 3837b37ad28bSAl Viro __be32 3838ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3839a4f1706aSJ.Bruce Fields struct nfsd4_open_confirm *oc) 38401da177e4SLinus Torvalds { 3841b37ad28bSAl Viro __be32 status; 3842fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 3843dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 38443320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 38451da177e4SLinus Torvalds 3846*a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 3847*a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 38481da177e4SLinus Torvalds 3849ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 3850a8cddc5dSJ. Bruce Fields if (status) 3851a8cddc5dSJ. Bruce Fields return status; 38521da177e4SLinus Torvalds 38531da177e4SLinus Torvalds nfs4_lock_state(); 38541da177e4SLinus Torvalds 38559072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 3856ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 38573320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 38589072d5c6SJ. Bruce Fields if (status) 38591da177e4SLinus Torvalds goto out; 3860fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 386168b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 3862dad1c067SJ. Bruce Fields if (oo->oo_flags & NFS4_OO_CONFIRMED) 386368b66e82SJ. Bruce Fields goto out; 3864dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 3865dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 3866dcef0413SJ. Bruce Fields memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 38678c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 3868dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 3869c7b9a459SNeilBrown 38702a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 387168b66e82SJ. Bruce Fields status = nfs_ok; 38721da177e4SLinus Torvalds out: 38739411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 38745ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 38751da177e4SLinus Torvalds nfs4_unlock_state(); 38761da177e4SLinus Torvalds return status; 38771da177e4SLinus Torvalds } 38781da177e4SLinus Torvalds 38796409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 38801da177e4SLinus Torvalds { 388182c5ff1bSJeff Layton if (!test_access(access, stp)) 38826409a5a6SJ. Bruce Fields return; 38836409a5a6SJ. Bruce Fields nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); 388482c5ff1bSJeff Layton clear_access(access, stp); 3885f197c271SJ. Bruce Fields } 38866409a5a6SJ. Bruce Fields 38876409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 38886409a5a6SJ. Bruce Fields { 38896409a5a6SJ. Bruce Fields switch (to_access) { 38906409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 38916409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 38926409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 38936409a5a6SJ. Bruce Fields break; 38946409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 38956409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 38966409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 38976409a5a6SJ. Bruce Fields break; 38986409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 38996409a5a6SJ. Bruce Fields break; 39006409a5a6SJ. Bruce Fields default: 3901063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 39021da177e4SLinus Torvalds } 39031da177e4SLinus Torvalds } 39041da177e4SLinus Torvalds 39051da177e4SLinus Torvalds static void 3906ce0fc43cSJeff Layton reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp) 39071da177e4SLinus Torvalds { 39081da177e4SLinus Torvalds int i; 39091da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 39101da177e4SLinus Torvalds if ((i & deny) != i) 3911ce0fc43cSJeff Layton clear_deny(i, stp); 39121da177e4SLinus Torvalds } 39131da177e4SLinus Torvalds } 39141da177e4SLinus Torvalds 3915b37ad28bSAl Viro __be32 3916ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 3917ca364317SJ.Bruce Fields struct nfsd4_compound_state *cstate, 3918a4f1706aSJ.Bruce Fields struct nfsd4_open_downgrade *od) 39191da177e4SLinus Torvalds { 3920b37ad28bSAl Viro __be32 status; 3921dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 39223320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 39231da177e4SLinus Torvalds 3924*a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 3925*a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 39261da177e4SLinus Torvalds 3927c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 39282c8bd7e0SBenny Halevy if (od->od_deleg_want) 39292c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 39302c8bd7e0SBenny Halevy od->od_deleg_want); 39311da177e4SLinus Torvalds 39321da177e4SLinus Torvalds nfs4_lock_state(); 3933c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 39343320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 39359072d5c6SJ. Bruce Fields if (status) 39361da177e4SLinus Torvalds goto out; 39371da177e4SLinus Torvalds status = nfserr_inval; 393882c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 39391da177e4SLinus Torvalds dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n", 39401da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 39411da177e4SLinus Torvalds goto out; 39421da177e4SLinus Torvalds } 3943ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 39441da177e4SLinus Torvalds dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", 39451da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 39461da177e4SLinus Torvalds goto out; 39471da177e4SLinus Torvalds } 39486409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 39491da177e4SLinus Torvalds 3950ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 39511da177e4SLinus Torvalds 3952dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 3953dcef0413SJ. Bruce Fields memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 39541da177e4SLinus Torvalds status = nfs_ok; 39551da177e4SLinus Torvalds out: 39569411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 39575ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 39581da177e4SLinus Torvalds nfs4_unlock_state(); 39591da177e4SLinus Torvalds return status; 39601da177e4SLinus Torvalds } 39611da177e4SLinus Torvalds 3962f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 3963f7a4d872SJ. Bruce Fields { 3964f7a4d872SJ. Bruce Fields unhash_open_stateid(s); 3965f7a4d872SJ. Bruce Fields s->st_stid.sc_type = NFS4_CLOSED_STID; 396638c387b5SJ. Bruce Fields } 396738c387b5SJ. Bruce Fields 39681da177e4SLinus Torvalds /* 39691da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 39701da177e4SLinus Torvalds */ 3971b37ad28bSAl Viro __be32 3972ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3973a4f1706aSJ.Bruce Fields struct nfsd4_close *close) 39741da177e4SLinus Torvalds { 3975b37ad28bSAl Viro __be32 status; 3976fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 3977dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 39783320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 39793320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 39801da177e4SLinus Torvalds 3981*a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 3982*a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 39831da177e4SLinus Torvalds 39841da177e4SLinus Torvalds nfs4_lock_state(); 3985f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 3986f7a4d872SJ. Bruce Fields &close->cl_stateid, 3987f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 39883320fef1SStanislav Kinsbursky &stp, nn); 39899411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 39909072d5c6SJ. Bruce Fields if (status) 39911da177e4SLinus Torvalds goto out; 3992fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 3993dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 3994dcef0413SJ. Bruce Fields memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 39951da177e4SLinus Torvalds 3996f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 39979411b1d4SJ. Bruce Fields 39989411b1d4SJ. Bruce Fields if (cstate->minorversion) { 39999411b1d4SJ. Bruce Fields unhash_stid(&stp->st_stid); 40009411b1d4SJ. Bruce Fields free_generic_stateid(stp); 40019411b1d4SJ. Bruce Fields } else 400238c387b5SJ. Bruce Fields oo->oo_last_closed_stid = stp; 400304ef5954SJ. Bruce Fields 400474dbafafSJ. Bruce Fields if (list_empty(&oo->oo_owner.so_stateids)) { 40053d74e6a5SJ. Bruce Fields if (cstate->minorversion) 400674dbafafSJ. Bruce Fields release_openowner(oo); 40073d74e6a5SJ. Bruce Fields else { 400874dbafafSJ. Bruce Fields /* 400974dbafafSJ. Bruce Fields * In the 4.0 case we need to keep the owners around a 401074dbafafSJ. Bruce Fields * little while to handle CLOSE replay. 401104ef5954SJ. Bruce Fields */ 401273758fedSStanislav Kinsbursky move_to_close_lru(oo, SVC_NET(rqstp)); 401374dbafafSJ. Bruce Fields } 401474dbafafSJ. Bruce Fields } 40151da177e4SLinus Torvalds out: 40165ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 40171da177e4SLinus Torvalds nfs4_unlock_state(); 40181da177e4SLinus Torvalds return status; 40191da177e4SLinus Torvalds } 40201da177e4SLinus Torvalds 4021b37ad28bSAl Viro __be32 4022ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4023ca364317SJ.Bruce Fields struct nfsd4_delegreturn *dr) 40241da177e4SLinus Torvalds { 4025203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 4026203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 402738c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 4028b37ad28bSAl Viro __be32 status; 40293320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 40301da177e4SLinus Torvalds 4031ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 4032203a8c8eSJ. Bruce Fields return status; 40331da177e4SLinus Torvalds 40341da177e4SLinus Torvalds nfs4_lock_state(); 40353320fef1SStanislav Kinsbursky status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, 40363320fef1SStanislav Kinsbursky cstate->minorversion, nn); 403738c2f4b1SJ. Bruce Fields if (status) 4038203a8c8eSJ. Bruce Fields goto out; 403938c2f4b1SJ. Bruce Fields dp = delegstateid(s); 4040d5477a8dSJ. Bruce Fields status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); 4041203a8c8eSJ. Bruce Fields if (status) 4042203a8c8eSJ. Bruce Fields goto out; 4043203a8c8eSJ. Bruce Fields 40443bd64a5bSJ. Bruce Fields destroy_delegation(dp); 40451da177e4SLinus Torvalds out: 4046203a8c8eSJ. Bruce Fields nfs4_unlock_state(); 4047203a8c8eSJ. Bruce Fields 40481da177e4SLinus Torvalds return status; 40491da177e4SLinus Torvalds } 40501da177e4SLinus Torvalds 40511da177e4SLinus Torvalds 40521da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) 40531da177e4SLinus Torvalds 4054009673b4SJ. Bruce Fields #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) 40551da177e4SLinus Torvalds 405687df4de8SBenny Halevy static inline u64 405787df4de8SBenny Halevy end_offset(u64 start, u64 len) 405887df4de8SBenny Halevy { 405987df4de8SBenny Halevy u64 end; 406087df4de8SBenny Halevy 406187df4de8SBenny Halevy end = start + len; 406287df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 406387df4de8SBenny Halevy } 406487df4de8SBenny Halevy 406587df4de8SBenny Halevy /* last octet in a range */ 406687df4de8SBenny Halevy static inline u64 406787df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 406887df4de8SBenny Halevy { 406987df4de8SBenny Halevy u64 end; 407087df4de8SBenny Halevy 4071063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 407287df4de8SBenny Halevy end = start + len; 407387df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 407487df4de8SBenny Halevy } 407587df4de8SBenny Halevy 4076009673b4SJ. Bruce Fields static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername) 40771da177e4SLinus Torvalds { 40781da177e4SLinus Torvalds return (file_hashval(inode) + cl_id 40791da177e4SLinus Torvalds + opaque_hashval(ownername->data, ownername->len)) 4080009673b4SJ. Bruce Fields & LOCKOWNER_INO_HASH_MASK; 40811da177e4SLinus Torvalds } 40821da177e4SLinus Torvalds 40831da177e4SLinus Torvalds /* 40841da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 40851da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 40861da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 40871da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 40881da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 40891da177e4SLinus Torvalds * the VFS, but this is a very deep change! 40901da177e4SLinus Torvalds */ 40911da177e4SLinus Torvalds static inline void 40921da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 40931da177e4SLinus Torvalds { 40941da177e4SLinus Torvalds if (lock->fl_start < 0) 40951da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 40961da177e4SLinus Torvalds if (lock->fl_end < 0) 40971da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 40981da177e4SLinus Torvalds } 40991da177e4SLinus Torvalds 4100d5b9026aSNeilBrown /* Hack!: For now, we're defining this just so we can use a pointer to it 4101d5b9026aSNeilBrown * as a unique cookie to identify our (NFSv4's) posix locks. */ 41027b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 4103d5b9026aSNeilBrown }; 41041da177e4SLinus Torvalds 41051da177e4SLinus Torvalds static inline void 41061da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 41071da177e4SLinus Torvalds { 4108fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 41091da177e4SLinus Torvalds 4110d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 4111fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 4112fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 4113fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 41147c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 41157c13f344SJ. Bruce Fields /* We just don't care that much */ 41167c13f344SJ. Bruce Fields goto nevermind; 4117fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 4118fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 4119d5b9026aSNeilBrown } else { 41207c13f344SJ. Bruce Fields nevermind: 41217c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 41227c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 4123d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 4124d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 41251da177e4SLinus Torvalds } 41261da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 412787df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 412887df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 41291da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 41301da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 41311da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 41321da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 41331da177e4SLinus Torvalds } 41341da177e4SLinus Torvalds 4135b93d87c1SJ. Bruce Fields static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner) 4136b93d87c1SJ. Bruce Fields { 4137b93d87c1SJ. Bruce Fields struct nfs4_ol_stateid *lst; 4138b93d87c1SJ. Bruce Fields 4139b93d87c1SJ. Bruce Fields if (!same_owner_str(&lo->lo_owner, owner, clid)) 4140b93d87c1SJ. Bruce Fields return false; 4141b93d87c1SJ. Bruce Fields lst = list_first_entry(&lo->lo_owner.so_stateids, 4142b93d87c1SJ. Bruce Fields struct nfs4_ol_stateid, st_perstateowner); 4143b93d87c1SJ. Bruce Fields return lst->st_file->fi_inode == inode; 4144b93d87c1SJ. Bruce Fields } 4145b93d87c1SJ. Bruce Fields 4146fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 4147fe0750e5SJ. Bruce Fields find_lockowner_str(struct inode *inode, clientid_t *clid, 414820e9e2bcSStanislav Kinsbursky struct xdr_netobj *owner, struct nfsd_net *nn) 41491da177e4SLinus Torvalds { 4150009673b4SJ. Bruce Fields unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); 4151b93d87c1SJ. Bruce Fields struct nfs4_lockowner *lo; 41521da177e4SLinus Torvalds 415320e9e2bcSStanislav Kinsbursky list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { 4154b93d87c1SJ. Bruce Fields if (same_lockowner_ino(lo, inode, clid, owner)) 4155b93d87c1SJ. Bruce Fields return lo; 41561da177e4SLinus Torvalds } 41571da177e4SLinus Torvalds return NULL; 41581da177e4SLinus Torvalds } 41591da177e4SLinus Torvalds 4160dcef0413SJ. Bruce Fields static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp) 4161ff194bd9SJ. Bruce Fields { 4162009673b4SJ. Bruce Fields struct inode *inode = open_stp->st_file->fi_inode; 4163009673b4SJ. Bruce Fields unsigned int inohash = lockowner_ino_hashval(inode, 4164009673b4SJ. Bruce Fields clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); 41659b531137SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 4166009673b4SJ. Bruce Fields 41679b531137SStanislav Kinsbursky list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); 416820e9e2bcSStanislav Kinsbursky list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]); 4169fe0750e5SJ. Bruce Fields list_add(&lo->lo_perstateid, &open_stp->st_lockowners); 4170ff194bd9SJ. Bruce Fields } 4171ff194bd9SJ. Bruce Fields 41721da177e4SLinus Torvalds /* 41731da177e4SLinus Torvalds * Alloc a lock owner structure. 41741da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 417525985edcSLucas De Marchi * occurred. 41761da177e4SLinus Torvalds * 417716bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 41781da177e4SLinus Torvalds */ 41791da177e4SLinus Torvalds 4180fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 4181dcef0413SJ. Bruce Fields alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) { 4182fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 41831da177e4SLinus Torvalds 4184fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 4185fe0750e5SJ. Bruce Fields if (!lo) 41861da177e4SLinus Torvalds return NULL; 4187fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 4188fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 4189b59e3c0eSNeil Brown /* It is the openowner seqid that will be incremented in encode in the 4190b59e3c0eSNeil Brown * case of new lockowners; so increment the lock seqid manually: */ 4191fe0750e5SJ. Bruce Fields lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1; 4192fe0750e5SJ. Bruce Fields hash_lockowner(lo, strhashval, clp, open_stp); 4193fe0750e5SJ. Bruce Fields return lo; 41941da177e4SLinus Torvalds } 41951da177e4SLinus Torvalds 4196dcef0413SJ. Bruce Fields static struct nfs4_ol_stateid * 4197dcef0413SJ. Bruce Fields alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp) 41981da177e4SLinus Torvalds { 4199dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 4200d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 42011da177e4SLinus Torvalds 4202996e0938SJ. Bruce Fields stp = nfs4_alloc_stateid(clp); 42035ac049acSNeilBrown if (stp == NULL) 42046136d2b4SJ. Bruce Fields return NULL; 42053abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 42068beefa24SNeilBrown list_add(&stp->st_perfile, &fp->fi_stateids); 4207fe0750e5SJ. Bruce Fields list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 4208fe0750e5SJ. Bruce Fields stp->st_stateowner = &lo->lo_owner; 420913cd2184SNeilBrown get_nfs4_file(fp); 42101da177e4SLinus Torvalds stp->st_file = fp; 42110997b173SJ. Bruce Fields stp->st_access_bmap = 0; 42121da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 42134c4cd222SNeilBrown stp->st_openstp = open_stp; 42141da177e4SLinus Torvalds return stp; 42151da177e4SLinus Torvalds } 42161da177e4SLinus Torvalds 4217fd39ca9aSNeilBrown static int 42181da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 42191da177e4SLinus Torvalds { 422087df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 42211da177e4SLinus Torvalds LOFF_OVERFLOW(offset, length))); 42221da177e4SLinus Torvalds } 42231da177e4SLinus Torvalds 4224dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 42250997b173SJ. Bruce Fields { 42260997b173SJ. Bruce Fields struct nfs4_file *fp = lock_stp->st_file; 42270997b173SJ. Bruce Fields int oflag = nfs4_access_to_omode(access); 42280997b173SJ. Bruce Fields 422982c5ff1bSJeff Layton if (test_access(access, lock_stp)) 42300997b173SJ. Bruce Fields return; 42310997b173SJ. Bruce Fields nfs4_file_get_access(fp, oflag); 423282c5ff1bSJeff Layton set_access(access, lock_stp); 42330997b173SJ. Bruce Fields } 42340997b173SJ. Bruce Fields 42352355c596SJ. Bruce Fields static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) 423664a284d0SJ. Bruce Fields { 423764a284d0SJ. Bruce Fields struct nfs4_file *fi = ost->st_file; 423864a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 423964a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 424064a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 424164a284d0SJ. Bruce Fields unsigned int strhashval; 424220e9e2bcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id); 424364a284d0SJ. Bruce Fields 424420e9e2bcSStanislav Kinsbursky lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, 424520e9e2bcSStanislav Kinsbursky &lock->v.new.owner, nn); 424664a284d0SJ. Bruce Fields if (lo) { 424764a284d0SJ. Bruce Fields if (!cstate->minorversion) 424864a284d0SJ. Bruce Fields return nfserr_bad_seqid; 424964a284d0SJ. Bruce Fields /* XXX: a lockowner always has exactly one stateid: */ 425064a284d0SJ. Bruce Fields *lst = list_first_entry(&lo->lo_owner.so_stateids, 425164a284d0SJ. Bruce Fields struct nfs4_ol_stateid, st_perstateowner); 425264a284d0SJ. Bruce Fields return nfs_ok; 425364a284d0SJ. Bruce Fields } 425416bfdaafSJ. Bruce Fields strhashval = ownerstr_hashval(cl->cl_clientid.cl_id, 425564a284d0SJ. Bruce Fields &lock->v.new.owner); 425664a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 425764a284d0SJ. Bruce Fields if (lo == NULL) 425864a284d0SJ. Bruce Fields return nfserr_jukebox; 425964a284d0SJ. Bruce Fields *lst = alloc_init_lock_stateid(lo, fi, ost); 426064a284d0SJ. Bruce Fields if (*lst == NULL) { 426164a284d0SJ. Bruce Fields release_lockowner(lo); 426264a284d0SJ. Bruce Fields return nfserr_jukebox; 426364a284d0SJ. Bruce Fields } 426464a284d0SJ. Bruce Fields *new = true; 426564a284d0SJ. Bruce Fields return nfs_ok; 426664a284d0SJ. Bruce Fields } 426764a284d0SJ. Bruce Fields 42681da177e4SLinus Torvalds /* 42691da177e4SLinus Torvalds * LOCK operation 42701da177e4SLinus Torvalds */ 4271b37ad28bSAl Viro __be32 4272ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4273a4f1706aSJ.Bruce Fields struct nfsd4_lock *lock) 42741da177e4SLinus Torvalds { 4275fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 4276fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 4277dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *lock_stp; 42787d947842SJ. Bruce Fields struct file *filp = NULL; 427921179d81SJeff Layton struct file_lock *file_lock = NULL; 428021179d81SJeff Layton struct file_lock *conflock = NULL; 4281b37ad28bSAl Viro __be32 status = 0; 428264a284d0SJ. Bruce Fields bool new_state = false; 4283b34f27aaSJ. Bruce Fields int lkflg; 4284b8dd7b9aSAl Viro int err; 42853320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 42863320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 42871da177e4SLinus Torvalds 42881da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 42891da177e4SLinus Torvalds (long long) lock->lk_offset, 42901da177e4SLinus Torvalds (long long) lock->lk_length); 42911da177e4SLinus Torvalds 42921da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 42931da177e4SLinus Torvalds return nfserr_inval; 42941da177e4SLinus Torvalds 4295ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 42968837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 4297a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 4298a6f6ef2fSAndy Adamson return status; 4299a6f6ef2fSAndy Adamson } 4300a6f6ef2fSAndy Adamson 43011da177e4SLinus Torvalds nfs4_lock_state(); 43021da177e4SLinus Torvalds 43031da177e4SLinus Torvalds if (lock->lk_is_new) { 4304dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *open_stp = NULL; 43051da177e4SLinus Torvalds 4306684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 4307684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 4308684e5638SJ. Bruce Fields memcpy(&lock->v.new.clientid, 4309684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 4310684e5638SJ. Bruce Fields sizeof(clientid_t)); 4311684e5638SJ. Bruce Fields 43121da177e4SLinus Torvalds status = nfserr_stale_clientid; 43132c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 43141da177e4SLinus Torvalds goto out; 43151da177e4SLinus Torvalds 43161da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 4317c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 43181da177e4SLinus Torvalds lock->lk_new_open_seqid, 43191da177e4SLinus Torvalds &lock->lk_new_open_stateid, 43203320fef1SStanislav Kinsbursky &open_stp, nn); 432137515177SNeilBrown if (status) 43221da177e4SLinus Torvalds goto out; 4323fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 4324b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 4325684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 4326b34f27aaSJ. Bruce Fields &lock->v.new.clientid)) 4327b34f27aaSJ. Bruce Fields goto out; 432864a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 432964a284d0SJ. Bruce Fields &lock_stp, &new_state); 4330e1aaa891SJ. Bruce Fields } else 4331dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 43321da177e4SLinus Torvalds lock->lk_old_lock_seqid, 43331da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 43343320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 43351da177e4SLinus Torvalds if (status) 43361da177e4SLinus Torvalds goto out; 4337fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 43381da177e4SLinus Torvalds 4339b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 4340b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 4341b34f27aaSJ. Bruce Fields if (status) 4342b34f27aaSJ. Bruce Fields goto out; 4343b34f27aaSJ. Bruce Fields 43440dd395dcSNeilBrown status = nfserr_grace; 43453320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 43460dd395dcSNeilBrown goto out; 43470dd395dcSNeilBrown status = nfserr_no_grace; 43483320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 43490dd395dcSNeilBrown goto out; 43500dd395dcSNeilBrown 435121179d81SJeff Layton file_lock = locks_alloc_lock(); 435221179d81SJeff Layton if (!file_lock) { 435321179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 435421179d81SJeff Layton status = nfserr_jukebox; 435521179d81SJeff Layton goto out; 435621179d81SJeff Layton } 435721179d81SJeff Layton 435821179d81SJeff Layton locks_init_lock(file_lock); 43591da177e4SLinus Torvalds switch (lock->lk_type) { 43601da177e4SLinus Torvalds case NFS4_READ_LT: 43611da177e4SLinus Torvalds case NFS4_READW_LT: 4362f9d7562fSJ. Bruce Fields filp = find_readable_file(lock_stp->st_file); 43630997b173SJ. Bruce Fields if (filp) 43640997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 436521179d81SJeff Layton file_lock->fl_type = F_RDLCK; 43661da177e4SLinus Torvalds break; 43671da177e4SLinus Torvalds case NFS4_WRITE_LT: 43681da177e4SLinus Torvalds case NFS4_WRITEW_LT: 4369f9d7562fSJ. Bruce Fields filp = find_writeable_file(lock_stp->st_file); 43700997b173SJ. Bruce Fields if (filp) 43710997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 437221179d81SJeff Layton file_lock->fl_type = F_WRLCK; 43731da177e4SLinus Torvalds break; 43741da177e4SLinus Torvalds default: 43751da177e4SLinus Torvalds status = nfserr_inval; 43761da177e4SLinus Torvalds goto out; 43771da177e4SLinus Torvalds } 4378f9d7562fSJ. Bruce Fields if (!filp) { 4379f9d7562fSJ. Bruce Fields status = nfserr_openmode; 4380f9d7562fSJ. Bruce Fields goto out; 4381f9d7562fSJ. Bruce Fields } 438221179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lock_sop; 438321179d81SJeff Layton file_lock->fl_pid = current->tgid; 438421179d81SJeff Layton file_lock->fl_file = filp; 438521179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 438621179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 438721179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 438821179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 438921179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 43901da177e4SLinus Torvalds 439121179d81SJeff Layton conflock = locks_alloc_lock(); 439221179d81SJeff Layton if (!conflock) { 439321179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 439421179d81SJeff Layton status = nfserr_jukebox; 439521179d81SJeff Layton goto out; 439621179d81SJeff Layton } 43971da177e4SLinus Torvalds 439821179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); 4399b8dd7b9aSAl Viro switch (-err) { 44001da177e4SLinus Torvalds case 0: /* success! */ 4401dcef0413SJ. Bruce Fields update_stateid(&lock_stp->st_stid.sc_stateid); 4402dcef0413SJ. Bruce Fields memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, 44031da177e4SLinus Torvalds sizeof(stateid_t)); 4404b8dd7b9aSAl Viro status = 0; 4405eb76b3fdSAndy Adamson break; 4406eb76b3fdSAndy Adamson case (EAGAIN): /* conflock holds conflicting lock */ 4407eb76b3fdSAndy Adamson status = nfserr_denied; 4408eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 440921179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 4410eb76b3fdSAndy Adamson break; 44111da177e4SLinus Torvalds case (EDEADLK): 44121da177e4SLinus Torvalds status = nfserr_deadlock; 4413eb76b3fdSAndy Adamson break; 44141da177e4SLinus Torvalds default: 4415fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 44163e772463SJ. Bruce Fields status = nfserrno(err); 4417eb76b3fdSAndy Adamson break; 44181da177e4SLinus Torvalds } 44191da177e4SLinus Torvalds out: 442064a284d0SJ. Bruce Fields if (status && new_state) 4421f044ff83SJ. Bruce Fields release_lockowner(lock_sop); 44229411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 44235ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 44241da177e4SLinus Torvalds nfs4_unlock_state(); 442521179d81SJeff Layton if (file_lock) 442621179d81SJeff Layton locks_free_lock(file_lock); 442721179d81SJeff Layton if (conflock) 442821179d81SJeff Layton locks_free_lock(conflock); 44291da177e4SLinus Torvalds return status; 44301da177e4SLinus Torvalds } 44311da177e4SLinus Torvalds 44321da177e4SLinus Torvalds /* 443355ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 443455ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 443555ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 443655ef1274SJ. Bruce Fields * inode operation.) 443755ef1274SJ. Bruce Fields */ 443804da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 443955ef1274SJ. Bruce Fields { 444055ef1274SJ. Bruce Fields struct file *file; 444104da6e9dSAl Viro __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 444204da6e9dSAl Viro if (!err) { 444304da6e9dSAl Viro err = nfserrno(vfs_test_lock(file, lock)); 444455ef1274SJ. Bruce Fields nfsd_close(file); 444504da6e9dSAl Viro } 444655ef1274SJ. Bruce Fields return err; 444755ef1274SJ. Bruce Fields } 444855ef1274SJ. Bruce Fields 444955ef1274SJ. Bruce Fields /* 44501da177e4SLinus Torvalds * LOCKT operation 44511da177e4SLinus Torvalds */ 4452b37ad28bSAl Viro __be32 4453ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4454ca364317SJ.Bruce Fields struct nfsd4_lockt *lockt) 44551da177e4SLinus Torvalds { 44561da177e4SLinus Torvalds struct inode *inode; 445721179d81SJeff Layton struct file_lock *file_lock = NULL; 4458fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 4459b37ad28bSAl Viro __be32 status; 44607f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 44611da177e4SLinus Torvalds 44625ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 44631da177e4SLinus Torvalds return nfserr_grace; 44641da177e4SLinus Torvalds 44651da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 44661da177e4SLinus Torvalds return nfserr_inval; 44671da177e4SLinus Torvalds 44681da177e4SLinus Torvalds nfs4_lock_state(); 44691da177e4SLinus Torvalds 44709b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 44719b2ef62bSJ. Bruce Fields status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL); 44729b2ef62bSJ. Bruce Fields if (status) 44731da177e4SLinus Torvalds goto out; 44749b2ef62bSJ. Bruce Fields } 44751da177e4SLinus Torvalds 447675c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 44771da177e4SLinus Torvalds goto out; 44781da177e4SLinus Torvalds 4479ca364317SJ.Bruce Fields inode = cstate->current_fh.fh_dentry->d_inode; 448021179d81SJeff Layton file_lock = locks_alloc_lock(); 448121179d81SJeff Layton if (!file_lock) { 448221179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 448321179d81SJeff Layton status = nfserr_jukebox; 448421179d81SJeff Layton goto out; 448521179d81SJeff Layton } 448621179d81SJeff Layton locks_init_lock(file_lock); 44871da177e4SLinus Torvalds switch (lockt->lt_type) { 44881da177e4SLinus Torvalds case NFS4_READ_LT: 44891da177e4SLinus Torvalds case NFS4_READW_LT: 449021179d81SJeff Layton file_lock->fl_type = F_RDLCK; 44911da177e4SLinus Torvalds break; 44921da177e4SLinus Torvalds case NFS4_WRITE_LT: 44931da177e4SLinus Torvalds case NFS4_WRITEW_LT: 449421179d81SJeff Layton file_lock->fl_type = F_WRLCK; 44951da177e4SLinus Torvalds break; 44961da177e4SLinus Torvalds default: 44972fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 44981da177e4SLinus Torvalds status = nfserr_inval; 44991da177e4SLinus Torvalds goto out; 45001da177e4SLinus Torvalds } 45011da177e4SLinus Torvalds 450220e9e2bcSStanislav Kinsbursky lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn); 4503fe0750e5SJ. Bruce Fields if (lo) 450421179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 450521179d81SJeff Layton file_lock->fl_pid = current->tgid; 450621179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 45071da177e4SLinus Torvalds 450821179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 450921179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 45101da177e4SLinus Torvalds 451121179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 45121da177e4SLinus Torvalds 451321179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 451404da6e9dSAl Viro if (status) 4515fd85b817SMarc Eshel goto out; 451604da6e9dSAl Viro 451721179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 45181da177e4SLinus Torvalds status = nfserr_denied; 451921179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 45201da177e4SLinus Torvalds } 45211da177e4SLinus Torvalds out: 45221da177e4SLinus Torvalds nfs4_unlock_state(); 452321179d81SJeff Layton if (file_lock) 452421179d81SJeff Layton locks_free_lock(file_lock); 45251da177e4SLinus Torvalds return status; 45261da177e4SLinus Torvalds } 45271da177e4SLinus Torvalds 4528b37ad28bSAl Viro __be32 4529ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4530a4f1706aSJ.Bruce Fields struct nfsd4_locku *locku) 45311da177e4SLinus Torvalds { 4532dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 45331da177e4SLinus Torvalds struct file *filp = NULL; 453421179d81SJeff Layton struct file_lock *file_lock = NULL; 4535b37ad28bSAl Viro __be32 status; 4536b8dd7b9aSAl Viro int err; 45373320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 45381da177e4SLinus Torvalds 45391da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 45401da177e4SLinus Torvalds (long long) locku->lu_offset, 45411da177e4SLinus Torvalds (long long) locku->lu_length); 45421da177e4SLinus Torvalds 45431da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 45441da177e4SLinus Torvalds return nfserr_inval; 45451da177e4SLinus Torvalds 45461da177e4SLinus Torvalds nfs4_lock_state(); 45471da177e4SLinus Torvalds 45489072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 45493320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 45503320fef1SStanislav Kinsbursky &stp, nn); 45519072d5c6SJ. Bruce Fields if (status) 45521da177e4SLinus Torvalds goto out; 4553f9d7562fSJ. Bruce Fields filp = find_any_file(stp->st_file); 4554f9d7562fSJ. Bruce Fields if (!filp) { 4555f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 4556f9d7562fSJ. Bruce Fields goto out; 4557f9d7562fSJ. Bruce Fields } 455821179d81SJeff Layton file_lock = locks_alloc_lock(); 455921179d81SJeff Layton if (!file_lock) { 456021179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 456121179d81SJeff Layton status = nfserr_jukebox; 456221179d81SJeff Layton goto out; 456321179d81SJeff Layton } 456421179d81SJeff Layton locks_init_lock(file_lock); 456521179d81SJeff Layton file_lock->fl_type = F_UNLCK; 45660a262ffbSJ. Bruce Fields file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); 456721179d81SJeff Layton file_lock->fl_pid = current->tgid; 456821179d81SJeff Layton file_lock->fl_file = filp; 456921179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 457021179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 457121179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 45721da177e4SLinus Torvalds 457321179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 457421179d81SJeff Layton locku->lu_length); 457521179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 45761da177e4SLinus Torvalds 457721179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); 4578b8dd7b9aSAl Viro if (err) { 4579fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 45801da177e4SLinus Torvalds goto out_nfserr; 45811da177e4SLinus Torvalds } 4582dcef0413SJ. Bruce Fields update_stateid(&stp->st_stid.sc_stateid); 4583dcef0413SJ. Bruce Fields memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 45841da177e4SLinus Torvalds 45851da177e4SLinus Torvalds out: 45869411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 458771c3bcd7SJ. Bruce Fields if (!cstate->replay_owner) 45881da177e4SLinus Torvalds nfs4_unlock_state(); 458921179d81SJeff Layton if (file_lock) 459021179d81SJeff Layton locks_free_lock(file_lock); 45911da177e4SLinus Torvalds return status; 45921da177e4SLinus Torvalds 45931da177e4SLinus Torvalds out_nfserr: 4594b8dd7b9aSAl Viro status = nfserrno(err); 45951da177e4SLinus Torvalds goto out; 45961da177e4SLinus Torvalds } 45971da177e4SLinus Torvalds 45981da177e4SLinus Torvalds /* 45991da177e4SLinus Torvalds * returns 46001da177e4SLinus Torvalds * 1: locks held by lockowner 46011da177e4SLinus Torvalds * 0: no locks held by lockowner 46021da177e4SLinus Torvalds */ 46031da177e4SLinus Torvalds static int 4604fe0750e5SJ. Bruce Fields check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) 46051da177e4SLinus Torvalds { 46061da177e4SLinus Torvalds struct file_lock **flpp; 4607f9d7562fSJ. Bruce Fields struct inode *inode = filp->fi_inode; 46081da177e4SLinus Torvalds int status = 0; 46091da177e4SLinus Torvalds 46101c8c601aSJeff Layton spin_lock(&inode->i_lock); 46111da177e4SLinus Torvalds for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { 4612796dadfdSJ. Bruce Fields if ((*flpp)->fl_owner == (fl_owner_t)lowner) { 46131da177e4SLinus Torvalds status = 1; 46141da177e4SLinus Torvalds goto out; 46151da177e4SLinus Torvalds } 4616796dadfdSJ. Bruce Fields } 46171da177e4SLinus Torvalds out: 46181c8c601aSJeff Layton spin_unlock(&inode->i_lock); 46191da177e4SLinus Torvalds return status; 46201da177e4SLinus Torvalds } 46211da177e4SLinus Torvalds 4622b37ad28bSAl Viro __be32 4623b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 4624b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 4625b591480bSJ.Bruce Fields struct nfsd4_release_lockowner *rlockowner) 46261da177e4SLinus Torvalds { 46271da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 46283e9e3dbeSNeilBrown struct nfs4_stateowner *sop; 4629fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 4630dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 46311da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 46323e9e3dbeSNeilBrown struct list_head matches; 463316bfdaafSJ. Bruce Fields unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); 4634b37ad28bSAl Viro __be32 status; 46357f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 46361da177e4SLinus Torvalds 46371da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 46381da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 46391da177e4SLinus Torvalds 46401da177e4SLinus Torvalds nfs4_lock_state(); 46411da177e4SLinus Torvalds 46429b2ef62bSJ. Bruce Fields status = lookup_clientid(clid, cstate->minorversion, nn, NULL); 46439b2ef62bSJ. Bruce Fields if (status) 46449b2ef62bSJ. Bruce Fields goto out; 46459b2ef62bSJ. Bruce Fields 46461da177e4SLinus Torvalds status = nfserr_locks_held; 46473e9e3dbeSNeilBrown INIT_LIST_HEAD(&matches); 464806f1f864SJ. Bruce Fields 46499b531137SStanislav Kinsbursky list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) { 465016bfdaafSJ. Bruce Fields if (sop->so_is_open_owner) 465116bfdaafSJ. Bruce Fields continue; 4652599e0a22SJ. Bruce Fields if (!same_owner_str(sop, owner, clid)) 46533e9e3dbeSNeilBrown continue; 46543e9e3dbeSNeilBrown list_for_each_entry(stp, &sop->so_stateids, 4655ea1da636SNeilBrown st_perstateowner) { 4656fe0750e5SJ. Bruce Fields lo = lockowner(sop); 4657fe0750e5SJ. Bruce Fields if (check_for_locks(stp->st_file, lo)) 46581da177e4SLinus Torvalds goto out; 4659fe0750e5SJ. Bruce Fields list_add(&lo->lo_list, &matches); 46601da177e4SLinus Torvalds } 46613e9e3dbeSNeilBrown } 46623e9e3dbeSNeilBrown /* Clients probably won't expect us to return with some (but not all) 46633e9e3dbeSNeilBrown * of the lockowner state released; so don't release any until all 46643e9e3dbeSNeilBrown * have been checked. */ 46651da177e4SLinus Torvalds status = nfs_ok; 46660fa822e4SNeilBrown while (!list_empty(&matches)) { 4667fe0750e5SJ. Bruce Fields lo = list_entry(matches.next, struct nfs4_lockowner, 4668fe0750e5SJ. Bruce Fields lo_list); 46690fa822e4SNeilBrown /* unhash_stateowner deletes so_perclient only 46700fa822e4SNeilBrown * for openowners. */ 4671fe0750e5SJ. Bruce Fields list_del(&lo->lo_list); 4672fe0750e5SJ. Bruce Fields release_lockowner(lo); 46731da177e4SLinus Torvalds } 46741da177e4SLinus Torvalds out: 46751da177e4SLinus Torvalds nfs4_unlock_state(); 46761da177e4SLinus Torvalds return status; 46771da177e4SLinus Torvalds } 46781da177e4SLinus Torvalds 46791da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 4680a55370a3SNeilBrown alloc_reclaim(void) 46811da177e4SLinus Torvalds { 4682a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 46831da177e4SLinus Torvalds } 46841da177e4SLinus Torvalds 46850ce0c2b5SJeff Layton bool 468652e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 4687c7b9a459SNeilBrown { 46880ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 4689c7b9a459SNeilBrown 469052e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 46910ce0c2b5SJeff Layton return (crp && crp->cr_clp); 4692c7b9a459SNeilBrown } 4693c7b9a459SNeilBrown 46941da177e4SLinus Torvalds /* 46951da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 46961da177e4SLinus Torvalds */ 4697772a9bbbSJeff Layton struct nfs4_client_reclaim * 469852e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 46991da177e4SLinus Torvalds { 47001da177e4SLinus Torvalds unsigned int strhashval; 4701772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 47021da177e4SLinus Torvalds 4703a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 4704a55370a3SNeilBrown crp = alloc_reclaim(); 4705772a9bbbSJeff Layton if (crp) { 4706a55370a3SNeilBrown strhashval = clientstr_hashval(name); 47071da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 470852e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 4709a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 47100ce0c2b5SJeff Layton crp->cr_clp = NULL; 471152e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 4712772a9bbbSJeff Layton } 4713772a9bbbSJeff Layton return crp; 47141da177e4SLinus Torvalds } 47151da177e4SLinus Torvalds 47162a4317c5SJeff Layton void 471752e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 4718ce30e539SJeff Layton { 4719ce30e539SJeff Layton list_del(&crp->cr_strhash); 4720ce30e539SJeff Layton kfree(crp); 472152e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 4722ce30e539SJeff Layton } 4723ce30e539SJeff Layton 4724ce30e539SJeff Layton void 472552e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 47261da177e4SLinus Torvalds { 47271da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 47281da177e4SLinus Torvalds int i; 47291da177e4SLinus Torvalds 47301da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 473152e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 473252e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 47331da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 473452e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 47351da177e4SLinus Torvalds } 47361da177e4SLinus Torvalds } 4737063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 47381da177e4SLinus Torvalds } 47391da177e4SLinus Torvalds 47401da177e4SLinus Torvalds /* 47411da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 47422a4317c5SJeff Layton struct nfs4_client_reclaim * 474352e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 47441da177e4SLinus Torvalds { 47451da177e4SLinus Torvalds unsigned int strhashval; 47461da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 47471da177e4SLinus Torvalds 4748278c931cSJeff Layton dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 47491da177e4SLinus Torvalds 4750278c931cSJeff Layton strhashval = clientstr_hashval(recdir); 475152e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 4752278c931cSJeff Layton if (same_name(crp->cr_recdir, recdir)) { 47531da177e4SLinus Torvalds return crp; 47541da177e4SLinus Torvalds } 47551da177e4SLinus Torvalds } 47561da177e4SLinus Torvalds return NULL; 47571da177e4SLinus Torvalds } 47581da177e4SLinus Torvalds 47591da177e4SLinus Torvalds /* 47601da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 47611da177e4SLinus Torvalds */ 4762b37ad28bSAl Viro __be32 47633320fef1SStanislav Kinsbursky nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn) 47641da177e4SLinus Torvalds { 4765a52d726bSJeff Layton struct nfs4_client *clp; 4766a52d726bSJeff Layton 4767a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 47688daae4dcSStanislav Kinsbursky clp = find_confirmed_client(clid, sessions, nn); 4769a52d726bSJeff Layton if (clp == NULL) 4770a52d726bSJeff Layton return nfserr_reclaim_bad; 4771a52d726bSJeff Layton 4772a52d726bSJeff Layton return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok; 47731da177e4SLinus Torvalds } 47741da177e4SLinus Torvalds 477565178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 477665178db4SBryan Schumaker 477744e34da6SBryan Schumaker u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) 477844e34da6SBryan Schumaker { 4779221a6876SJ. Bruce Fields if (mark_client_expired(clp)) 4780221a6876SJ. Bruce Fields return 0; 478144e34da6SBryan Schumaker expire_client(clp); 478244e34da6SBryan Schumaker return 1; 478344e34da6SBryan Schumaker } 478444e34da6SBryan Schumaker 4785184c1847SBryan Schumaker u64 nfsd_print_client(struct nfs4_client *clp, u64 num) 4786184c1847SBryan Schumaker { 4787184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 47880a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 4789184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s\n", buf); 4790184c1847SBryan Schumaker return 1; 4791184c1847SBryan Schumaker } 4792184c1847SBryan Schumaker 4793184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 4794184c1847SBryan Schumaker const char *type) 4795184c1847SBryan Schumaker { 4796184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 47970a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 4798184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 4799184c1847SBryan Schumaker } 4800184c1847SBryan Schumaker 4801fc29171fSBryan Schumaker static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *)) 4802fc29171fSBryan Schumaker { 4803fc29171fSBryan Schumaker struct nfs4_openowner *oop; 4804fc29171fSBryan Schumaker struct nfs4_lockowner *lop, *lo_next; 4805fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 4806fc29171fSBryan Schumaker u64 count = 0; 4807fc29171fSBryan Schumaker 4808fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 4809fc29171fSBryan Schumaker list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) { 4810fc29171fSBryan Schumaker list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) { 4811fc29171fSBryan Schumaker if (func) 4812fc29171fSBryan Schumaker func(lop); 4813fc29171fSBryan Schumaker if (++count == max) 4814fc29171fSBryan Schumaker return count; 4815fc29171fSBryan Schumaker } 4816fc29171fSBryan Schumaker } 4817fc29171fSBryan Schumaker } 4818fc29171fSBryan Schumaker 4819fc29171fSBryan Schumaker return count; 4820fc29171fSBryan Schumaker } 4821fc29171fSBryan Schumaker 4822fc29171fSBryan Schumaker u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) 4823fc29171fSBryan Schumaker { 4824fc29171fSBryan Schumaker return nfsd_foreach_client_lock(clp, max, release_lockowner); 4825fc29171fSBryan Schumaker } 4826fc29171fSBryan Schumaker 4827184c1847SBryan Schumaker u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) 4828184c1847SBryan Schumaker { 4829184c1847SBryan Schumaker u64 count = nfsd_foreach_client_lock(clp, max, NULL); 4830184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 4831184c1847SBryan Schumaker return count; 4832184c1847SBryan Schumaker } 4833184c1847SBryan Schumaker 48344dbdbda8SBryan Schumaker static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) 48354dbdbda8SBryan Schumaker { 48364dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 48374dbdbda8SBryan Schumaker u64 count = 0; 48384dbdbda8SBryan Schumaker 48394dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 48404dbdbda8SBryan Schumaker if (func) 48414dbdbda8SBryan Schumaker func(oop); 48424dbdbda8SBryan Schumaker if (++count == max) 48434dbdbda8SBryan Schumaker break; 48444dbdbda8SBryan Schumaker } 48454dbdbda8SBryan Schumaker 48464dbdbda8SBryan Schumaker return count; 48474dbdbda8SBryan Schumaker } 48484dbdbda8SBryan Schumaker 48494dbdbda8SBryan Schumaker u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) 48504dbdbda8SBryan Schumaker { 48514dbdbda8SBryan Schumaker return nfsd_foreach_client_open(clp, max, release_openowner); 48524dbdbda8SBryan Schumaker } 48534dbdbda8SBryan Schumaker 4854184c1847SBryan Schumaker u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) 4855184c1847SBryan Schumaker { 4856184c1847SBryan Schumaker u64 count = nfsd_foreach_client_open(clp, max, NULL); 4857184c1847SBryan Schumaker nfsd_print_count(clp, count, "open files"); 4858184c1847SBryan Schumaker return count; 4859184c1847SBryan Schumaker } 4860184c1847SBryan Schumaker 4861269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 4862269de30fSBryan Schumaker struct list_head *victims) 4863269de30fSBryan Schumaker { 4864269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 4865269de30fSBryan Schumaker u64 count = 0; 4866269de30fSBryan Schumaker 4867269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 4868269de30fSBryan Schumaker if (victims) 4869269de30fSBryan Schumaker list_move(&dp->dl_recall_lru, victims); 4870269de30fSBryan Schumaker if (++count == max) 4871269de30fSBryan Schumaker break; 4872269de30fSBryan Schumaker } 4873269de30fSBryan Schumaker return count; 4874269de30fSBryan Schumaker } 4875269de30fSBryan Schumaker 4876269de30fSBryan Schumaker u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) 4877269de30fSBryan Schumaker { 4878269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 4879269de30fSBryan Schumaker LIST_HEAD(victims); 4880269de30fSBryan Schumaker u64 count; 4881269de30fSBryan Schumaker 4882269de30fSBryan Schumaker spin_lock(&recall_lock); 4883269de30fSBryan Schumaker count = nfsd_find_all_delegations(clp, max, &victims); 4884269de30fSBryan Schumaker spin_unlock(&recall_lock); 4885269de30fSBryan Schumaker 4886269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) 48873bd64a5bSJ. Bruce Fields revoke_delegation(dp); 4888269de30fSBryan Schumaker 4889269de30fSBryan Schumaker return count; 4890269de30fSBryan Schumaker } 4891269de30fSBryan Schumaker 4892269de30fSBryan Schumaker u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) 4893269de30fSBryan Schumaker { 4894269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 4895269de30fSBryan Schumaker LIST_HEAD(victims); 4896269de30fSBryan Schumaker u64 count; 4897269de30fSBryan Schumaker 4898269de30fSBryan Schumaker spin_lock(&recall_lock); 4899269de30fSBryan Schumaker count = nfsd_find_all_delegations(clp, max, &victims); 4900269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) 4901269de30fSBryan Schumaker nfsd_break_one_deleg(dp); 4902269de30fSBryan Schumaker spin_unlock(&recall_lock); 4903269de30fSBryan Schumaker 4904269de30fSBryan Schumaker return count; 4905269de30fSBryan Schumaker } 4906269de30fSBryan Schumaker 4907184c1847SBryan Schumaker u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) 4908184c1847SBryan Schumaker { 4909184c1847SBryan Schumaker u64 count = 0; 4910184c1847SBryan Schumaker 4911184c1847SBryan Schumaker spin_lock(&recall_lock); 4912184c1847SBryan Schumaker count = nfsd_find_all_delegations(clp, max, NULL); 4913184c1847SBryan Schumaker spin_unlock(&recall_lock); 4914184c1847SBryan Schumaker 4915184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 4916184c1847SBryan Schumaker return count; 4917184c1847SBryan Schumaker } 4918184c1847SBryan Schumaker 491944e34da6SBryan Schumaker u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) 492065178db4SBryan Schumaker { 492165178db4SBryan Schumaker struct nfs4_client *clp, *next; 492244e34da6SBryan Schumaker u64 count = 0; 49233320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); 492465178db4SBryan Schumaker 492544e34da6SBryan Schumaker if (!nfsd_netns_ready(nn)) 492644e34da6SBryan Schumaker return 0; 492744e34da6SBryan Schumaker 49285ed58bb2SStanislav Kinsbursky list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 492944e34da6SBryan Schumaker count += func(clp, max - count); 493044e34da6SBryan Schumaker if ((max != 0) && (count >= max)) 493165178db4SBryan Schumaker break; 493265178db4SBryan Schumaker } 493365178db4SBryan Schumaker 493444e34da6SBryan Schumaker return count; 493544e34da6SBryan Schumaker } 493644e34da6SBryan Schumaker 49376c1e82a4SBryan Schumaker struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 49386c1e82a4SBryan Schumaker { 49396c1e82a4SBryan Schumaker struct nfs4_client *clp; 49406c1e82a4SBryan Schumaker struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); 49416c1e82a4SBryan Schumaker 49426c1e82a4SBryan Schumaker if (!nfsd_netns_ready(nn)) 49436c1e82a4SBryan Schumaker return NULL; 49446c1e82a4SBryan Schumaker 49456c1e82a4SBryan Schumaker list_for_each_entry(clp, &nn->client_lru, cl_lru) { 49466c1e82a4SBryan Schumaker if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 49476c1e82a4SBryan Schumaker return clp; 49486c1e82a4SBryan Schumaker } 49496c1e82a4SBryan Schumaker return NULL; 49506c1e82a4SBryan Schumaker } 49516c1e82a4SBryan Schumaker 495265178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 495365178db4SBryan Schumaker 4954ac4d8ff2SNeilBrown /* initialization to perform at module load time: */ 49551da177e4SLinus Torvalds 495672083396SBryan Schumaker void 4957ac4d8ff2SNeilBrown nfs4_state_init(void) 49581da177e4SLinus Torvalds { 4959ac4d8ff2SNeilBrown } 4960ac4d8ff2SNeilBrown 4961c2f1a551SMeelap Shah /* 4962c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 4963c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 4964c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 4965c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 4966c2f1a551SMeelap Shah * 4967c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 4968c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 4969c2f1a551SMeelap Shah */ 4970c2f1a551SMeelap Shah static void 4971c2f1a551SMeelap Shah set_max_delegations(void) 4972c2f1a551SMeelap Shah { 4973c2f1a551SMeelap Shah /* 4974c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 4975c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 4976c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 4977c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 4978c2f1a551SMeelap Shah */ 4979c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 4980c2f1a551SMeelap Shah } 4981c2f1a551SMeelap Shah 4982d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 49838daae4dcSStanislav Kinsbursky { 49848daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 49858daae4dcSStanislav Kinsbursky int i; 49868daae4dcSStanislav Kinsbursky 49878daae4dcSStanislav Kinsbursky nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * 49888daae4dcSStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 49898daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 4990382a62e7SStanislav Kinsbursky goto err; 49910a7ec377SStanislav Kinsbursky nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * 49920a7ec377SStanislav Kinsbursky CLIENT_HASH_SIZE, GFP_KERNEL); 49930a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 49940a7ec377SStanislav Kinsbursky goto err_unconf_id; 49959b531137SStanislav Kinsbursky nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * 49969b531137SStanislav Kinsbursky OWNER_HASH_SIZE, GFP_KERNEL); 49979b531137SStanislav Kinsbursky if (!nn->ownerstr_hashtbl) 49989b531137SStanislav Kinsbursky goto err_ownerstr; 499920e9e2bcSStanislav Kinsbursky nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) * 500020e9e2bcSStanislav Kinsbursky LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL); 500120e9e2bcSStanislav Kinsbursky if (!nn->lockowner_ino_hashtbl) 500220e9e2bcSStanislav Kinsbursky goto err_lockowner_ino; 50031872de0eSStanislav Kinsbursky nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * 50041872de0eSStanislav Kinsbursky SESSION_HASH_SIZE, GFP_KERNEL); 50051872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 50061872de0eSStanislav Kinsbursky goto err_sessionid; 50078daae4dcSStanislav Kinsbursky 5008382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 50098daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 50100a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 5011382a62e7SStanislav Kinsbursky } 50129b531137SStanislav Kinsbursky for (i = 0; i < OWNER_HASH_SIZE; i++) 50139b531137SStanislav Kinsbursky INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); 501420e9e2bcSStanislav Kinsbursky for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) 501520e9e2bcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]); 50161872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 50171872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 5018382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 5019a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 50205ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 502173758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 5022e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 5023c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 50248daae4dcSStanislav Kinsbursky 502509121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 5026d85ed443SStanislav Kinsbursky get_net(net); 502709121281SStanislav Kinsbursky 50288daae4dcSStanislav Kinsbursky return 0; 5029382a62e7SStanislav Kinsbursky 50301872de0eSStanislav Kinsbursky err_sessionid: 50311872de0eSStanislav Kinsbursky kfree(nn->lockowner_ino_hashtbl); 503220e9e2bcSStanislav Kinsbursky err_lockowner_ino: 503320e9e2bcSStanislav Kinsbursky kfree(nn->ownerstr_hashtbl); 50349b531137SStanislav Kinsbursky err_ownerstr: 50359b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 50360a7ec377SStanislav Kinsbursky err_unconf_id: 50370a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 5038382a62e7SStanislav Kinsbursky err: 5039382a62e7SStanislav Kinsbursky return -ENOMEM; 50408daae4dcSStanislav Kinsbursky } 50418daae4dcSStanislav Kinsbursky 50428daae4dcSStanislav Kinsbursky static void 50434dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 50448daae4dcSStanislav Kinsbursky { 50458daae4dcSStanislav Kinsbursky int i; 50468daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 50478daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5048a99454aaSStanislav Kinsbursky struct rb_node *node, *tmp; 50498daae4dcSStanislav Kinsbursky 50508daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 50518daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 50528daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 50538daae4dcSStanislav Kinsbursky destroy_client(clp); 50548daae4dcSStanislav Kinsbursky } 50558daae4dcSStanislav Kinsbursky } 5056a99454aaSStanislav Kinsbursky 5057a99454aaSStanislav Kinsbursky node = rb_first(&nn->unconf_name_tree); 5058a99454aaSStanislav Kinsbursky while (node != NULL) { 5059a99454aaSStanislav Kinsbursky tmp = node; 5060a99454aaSStanislav Kinsbursky node = rb_next(tmp); 5061a99454aaSStanislav Kinsbursky clp = rb_entry(tmp, struct nfs4_client, cl_namenode); 5062a99454aaSStanislav Kinsbursky rb_erase(tmp, &nn->unconf_name_tree); 5063a99454aaSStanislav Kinsbursky destroy_client(clp); 5064a99454aaSStanislav Kinsbursky } 5065a99454aaSStanislav Kinsbursky 50661872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 506720e9e2bcSStanislav Kinsbursky kfree(nn->lockowner_ino_hashtbl); 50689b531137SStanislav Kinsbursky kfree(nn->ownerstr_hashtbl); 50690a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 50708daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 50714dce0ac9SStanislav Kinsbursky put_net(net); 50728daae4dcSStanislav Kinsbursky } 50738daae4dcSStanislav Kinsbursky 5074f252bc68SStanislav Kinsbursky int 5075d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 5076ac4d8ff2SNeilBrown { 50775e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5078b5a1a81eSJ. Bruce Fields int ret; 5079b5a1a81eSJ. Bruce Fields 5080d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 50818daae4dcSStanislav Kinsbursky if (ret) 50828daae4dcSStanislav Kinsbursky return ret; 50835e1533c7SStanislav Kinsbursky nfsd4_client_tracking_init(net); 50842c142baaSStanislav Kinsbursky nn->boot_time = get_seconds(); 50855ccb0066SStanislav Kinsbursky locks_start_grace(net, &nn->nfsd4_manager); 5086a51c84edSStanislav Kinsbursky nn->grace_ended = false; 5087d85ed443SStanislav Kinsbursky printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", 50885284b44eSStanislav Kinsbursky nn->nfsd4_grace, net); 50895284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 5090d85ed443SStanislav Kinsbursky return 0; 5091a6d6b781SJeff Layton } 5092d85ed443SStanislav Kinsbursky 5093d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 5094d85ed443SStanislav Kinsbursky 5095d85ed443SStanislav Kinsbursky int 5096d85ed443SStanislav Kinsbursky nfs4_state_start(void) 5097d85ed443SStanislav Kinsbursky { 5098d85ed443SStanislav Kinsbursky int ret; 5099d85ed443SStanislav Kinsbursky 5100d85ed443SStanislav Kinsbursky ret = set_callback_cred(); 5101d85ed443SStanislav Kinsbursky if (ret) 5102d85ed443SStanislav Kinsbursky return -ENOMEM; 510358da282bSNeilBrown laundry_wq = create_singlethread_workqueue("nfsd4"); 5104a6d6b781SJeff Layton if (laundry_wq == NULL) { 5105a6d6b781SJeff Layton ret = -ENOMEM; 5106a6d6b781SJeff Layton goto out_recovery; 5107a6d6b781SJeff Layton } 5108b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 5109b5a1a81eSJ. Bruce Fields if (ret) 5110b5a1a81eSJ. Bruce Fields goto out_free_laundry; 511109121281SStanislav Kinsbursky 5112c2f1a551SMeelap Shah set_max_delegations(); 5113d85ed443SStanislav Kinsbursky 5114b5a1a81eSJ. Bruce Fields return 0; 5115d85ed443SStanislav Kinsbursky 5116b5a1a81eSJ. Bruce Fields out_free_laundry: 5117b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 5118a6d6b781SJeff Layton out_recovery: 5119b5a1a81eSJ. Bruce Fields return ret; 51201da177e4SLinus Torvalds } 51211da177e4SLinus Torvalds 5122ac55fdc4SJeff Layton /* should be called with the state lock held */ 5123f252bc68SStanislav Kinsbursky void 51244dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 51251da177e4SLinus Torvalds { 51261da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 51271da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 51284dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 51291da177e4SLinus Torvalds 51304dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 51314dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 5132ac55fdc4SJeff Layton 51331da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 51341da177e4SLinus Torvalds spin_lock(&recall_lock); 5135e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 51361da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 51371da177e4SLinus Torvalds list_move(&dp->dl_recall_lru, &reaplist); 51381da177e4SLinus Torvalds } 51391da177e4SLinus Torvalds spin_unlock(&recall_lock); 51401da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 51411da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 51423bd64a5bSJ. Bruce Fields destroy_delegation(dp); 51431da177e4SLinus Torvalds } 51441da177e4SLinus Torvalds 51453320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 51464dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 51471da177e4SLinus Torvalds } 51481da177e4SLinus Torvalds 51491da177e4SLinus Torvalds void 51501da177e4SLinus Torvalds nfs4_state_shutdown(void) 51511da177e4SLinus Torvalds { 51525e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 5153c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 51541da177e4SLinus Torvalds } 51558b70484cSTigran Mkrtchyan 51568b70484cSTigran Mkrtchyan static void 51578b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 51588b70484cSTigran Mkrtchyan { 515937c593c5STigran Mkrtchyan if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) 516037c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 51618b70484cSTigran Mkrtchyan } 51628b70484cSTigran Mkrtchyan 51638b70484cSTigran Mkrtchyan static void 51648b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 51658b70484cSTigran Mkrtchyan { 516637c593c5STigran Mkrtchyan if (cstate->minorversion) { 516737c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 516837c593c5STigran Mkrtchyan SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 516937c593c5STigran Mkrtchyan } 517037c593c5STigran Mkrtchyan } 517137c593c5STigran Mkrtchyan 517237c593c5STigran Mkrtchyan void 517337c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 517437c593c5STigran Mkrtchyan { 517537c593c5STigran Mkrtchyan CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 51768b70484cSTigran Mkrtchyan } 51778b70484cSTigran Mkrtchyan 517862cd4a59STigran Mkrtchyan /* 517962cd4a59STigran Mkrtchyan * functions to set current state id 518062cd4a59STigran Mkrtchyan */ 51818b70484cSTigran Mkrtchyan void 51829428fe1aSTigran Mkrtchyan nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 51839428fe1aSTigran Mkrtchyan { 51849428fe1aSTigran Mkrtchyan put_stateid(cstate, &odp->od_stateid); 51859428fe1aSTigran Mkrtchyan } 51869428fe1aSTigran Mkrtchyan 51879428fe1aSTigran Mkrtchyan void 51888b70484cSTigran Mkrtchyan nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open) 51898b70484cSTigran Mkrtchyan { 51908b70484cSTigran Mkrtchyan put_stateid(cstate, &open->op_stateid); 51918b70484cSTigran Mkrtchyan } 51928b70484cSTigran Mkrtchyan 51938b70484cSTigran Mkrtchyan void 519462cd4a59STigran Mkrtchyan nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 519562cd4a59STigran Mkrtchyan { 519662cd4a59STigran Mkrtchyan put_stateid(cstate, &close->cl_stateid); 519762cd4a59STigran Mkrtchyan } 519862cd4a59STigran Mkrtchyan 519962cd4a59STigran Mkrtchyan void 520062cd4a59STigran Mkrtchyan nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock) 520162cd4a59STigran Mkrtchyan { 520262cd4a59STigran Mkrtchyan put_stateid(cstate, &lock->lk_resp_stateid); 520362cd4a59STigran Mkrtchyan } 520462cd4a59STigran Mkrtchyan 520562cd4a59STigran Mkrtchyan /* 520662cd4a59STigran Mkrtchyan * functions to consume current state id 520762cd4a59STigran Mkrtchyan */ 52081e97b519STigran Mkrtchyan 52091e97b519STigran Mkrtchyan void 52109428fe1aSTigran Mkrtchyan nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) 52119428fe1aSTigran Mkrtchyan { 52129428fe1aSTigran Mkrtchyan get_stateid(cstate, &odp->od_stateid); 52139428fe1aSTigran Mkrtchyan } 52149428fe1aSTigran Mkrtchyan 52159428fe1aSTigran Mkrtchyan void 52169428fe1aSTigran Mkrtchyan nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp) 52179428fe1aSTigran Mkrtchyan { 52189428fe1aSTigran Mkrtchyan get_stateid(cstate, &drp->dr_stateid); 52199428fe1aSTigran Mkrtchyan } 52209428fe1aSTigran Mkrtchyan 52219428fe1aSTigran Mkrtchyan void 52221e97b519STigran Mkrtchyan nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp) 52231e97b519STigran Mkrtchyan { 52241e97b519STigran Mkrtchyan get_stateid(cstate, &fsp->fr_stateid); 52251e97b519STigran Mkrtchyan } 52261e97b519STigran Mkrtchyan 52271e97b519STigran Mkrtchyan void 52281e97b519STigran Mkrtchyan nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) 52291e97b519STigran Mkrtchyan { 52301e97b519STigran Mkrtchyan get_stateid(cstate, &setattr->sa_stateid); 52311e97b519STigran Mkrtchyan } 52321e97b519STigran Mkrtchyan 523362cd4a59STigran Mkrtchyan void 52348b70484cSTigran Mkrtchyan nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) 52358b70484cSTigran Mkrtchyan { 52368b70484cSTigran Mkrtchyan get_stateid(cstate, &close->cl_stateid); 52378b70484cSTigran Mkrtchyan } 52388b70484cSTigran Mkrtchyan 52398b70484cSTigran Mkrtchyan void 524062cd4a59STigran Mkrtchyan nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku) 52418b70484cSTigran Mkrtchyan { 524262cd4a59STigran Mkrtchyan get_stateid(cstate, &locku->lu_stateid); 52438b70484cSTigran Mkrtchyan } 524430813e27STigran Mkrtchyan 524530813e27STigran Mkrtchyan void 524630813e27STigran Mkrtchyan nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read) 524730813e27STigran Mkrtchyan { 524830813e27STigran Mkrtchyan get_stateid(cstate, &read->rd_stateid); 524930813e27STigran Mkrtchyan } 525030813e27STigran Mkrtchyan 525130813e27STigran Mkrtchyan void 525230813e27STigran Mkrtchyan nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write) 525330813e27STigran Mkrtchyan { 525430813e27STigran Mkrtchyan get_stateid(cstate, &write->wr_stateid); 525530813e27STigran Mkrtchyan } 5256