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> 4168e76ad0SOlga Kornievskaia #include <linux/sunrpc/svcauth_gss.h> 42363168b4SJeff Layton #include <linux/sunrpc/clnt.h> 439a74af21SBoaz Harrosh #include "xdr4.h" 440a3adadeSJ. Bruce Fields #include "vfs.h" 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* Globals */ 49cf07d2eaSJ. Bruce Fields time_t nfsd4_lease = 90; /* default lease time */ 50efc4bb4fSJ. Bruce Fields time_t nfsd4_grace = 90; 51fd39ca9aSNeilBrown static time_t boot_time; 521da177e4SLinus Torvalds static u32 current_ownerid = 1; 531da177e4SLinus Torvalds static u32 current_fileid = 1; 541da177e4SLinus Torvalds static u32 current_delegid = 1; 55fd39ca9aSNeilBrown static stateid_t zerostateid; /* bits all 0 */ 56fd39ca9aSNeilBrown static stateid_t onestateid; /* bits all 1 */ 57ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 58fd39ca9aSNeilBrown 59fd39ca9aSNeilBrown #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) 60fd39ca9aSNeilBrown #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds /* forward declarations */ 63e1ca12dfSBryan Schumaker static struct nfs4_delegation * search_for_delegation(stateid_t *stid); 641da177e4SLinus Torvalds static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); 65fe0750e5SJ. Bruce Fields static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); 661da177e4SLinus Torvalds 678b671b80SJ. Bruce Fields /* Locking: */ 688b671b80SJ. Bruce Fields 698b671b80SJ. Bruce Fields /* Currently used for almost all code touching nfsv4 state: */ 70353ab6e9SIngo Molnar static DEFINE_MUTEX(client_mutex); 711da177e4SLinus Torvalds 728b671b80SJ. Bruce Fields /* 738b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 748b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 758b671b80SJ. Bruce Fields * eventually cover more: 768b671b80SJ. Bruce Fields */ 778b671b80SJ. Bruce Fields static DEFINE_SPINLOCK(recall_lock); 788b671b80SJ. Bruce Fields 79fe0750e5SJ. Bruce Fields static struct kmem_cache *openowner_slab = NULL; 80fe0750e5SJ. Bruce Fields static struct kmem_cache *lockowner_slab = NULL; 81e18b890bSChristoph Lameter static struct kmem_cache *file_slab = NULL; 82e18b890bSChristoph Lameter static struct kmem_cache *stateid_slab = NULL; 83e18b890bSChristoph Lameter static struct kmem_cache *deleg_slab = NULL; 84e60d4398SNeilBrown 851da177e4SLinus Torvalds void 861da177e4SLinus Torvalds nfs4_lock_state(void) 871da177e4SLinus Torvalds { 88353ab6e9SIngo Molnar mutex_lock(&client_mutex); 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds void 921da177e4SLinus Torvalds nfs4_unlock_state(void) 931da177e4SLinus Torvalds { 94353ab6e9SIngo Molnar mutex_unlock(&client_mutex); 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static inline u32 981da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 991da177e4SLinus Torvalds { 1001da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds u32 x = 0; 1031da177e4SLinus Torvalds while (nbytes--) { 1041da177e4SLinus Torvalds x *= 37; 1051da177e4SLinus Torvalds x += *cptr++; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds return x; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static struct list_head del_recall_lru; 1111da177e4SLinus Torvalds 11213cd2184SNeilBrown static inline void 11313cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 11413cd2184SNeilBrown { 1158b671b80SJ. Bruce Fields if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) { 1168b671b80SJ. Bruce Fields list_del(&fi->fi_hash); 1178b671b80SJ. Bruce Fields spin_unlock(&recall_lock); 1188b671b80SJ. Bruce Fields iput(fi->fi_inode); 1198b671b80SJ. Bruce Fields kmem_cache_free(file_slab, fi); 1208b671b80SJ. Bruce Fields } 12113cd2184SNeilBrown } 12213cd2184SNeilBrown 12313cd2184SNeilBrown static inline void 12413cd2184SNeilBrown get_nfs4_file(struct nfs4_file *fi) 12513cd2184SNeilBrown { 1268b671b80SJ. Bruce Fields atomic_inc(&fi->fi_ref); 12713cd2184SNeilBrown } 12813cd2184SNeilBrown 129ef0f3390SNeilBrown static int num_delegations; 130c2f1a551SMeelap Shah unsigned int max_delegations; 131ef0f3390SNeilBrown 132ef0f3390SNeilBrown /* 133ef0f3390SNeilBrown * Open owner state (share locks) 134ef0f3390SNeilBrown */ 135ef0f3390SNeilBrown 136506f275fSJ. Bruce Fields /* hash tables for open owners */ 137506f275fSJ. Bruce Fields #define OPEN_OWNER_HASH_BITS 8 138506f275fSJ. Bruce Fields #define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS) 139506f275fSJ. Bruce Fields #define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1) 140ef0f3390SNeilBrown 141506f275fSJ. Bruce Fields static unsigned int open_ownerid_hashval(const u32 id) 142ddc04c41SJ. Bruce Fields { 143506f275fSJ. Bruce Fields return id & OPEN_OWNER_HASH_MASK; 144ddc04c41SJ. Bruce Fields } 145ddc04c41SJ. Bruce Fields 146506f275fSJ. Bruce Fields static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) 147ddc04c41SJ. Bruce Fields { 148ddc04c41SJ. Bruce Fields unsigned int ret; 149ddc04c41SJ. Bruce Fields 150ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 151ddc04c41SJ. Bruce Fields ret += clientid; 152506f275fSJ. Bruce Fields return ret & OPEN_OWNER_HASH_MASK; 153ddc04c41SJ. Bruce Fields } 154ef0f3390SNeilBrown 155506f275fSJ. Bruce Fields static struct list_head open_ownerid_hashtbl[OPEN_OWNER_HASH_SIZE]; 156506f275fSJ. Bruce Fields static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE]; 157ef0f3390SNeilBrown 158ef0f3390SNeilBrown /* hash table for nfs4_file */ 159ef0f3390SNeilBrown #define FILE_HASH_BITS 8 160ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 16135079582SShan Wei 162ef0f3390SNeilBrown /* hash table for (open)nfs4_stateid */ 163ef0f3390SNeilBrown #define STATEID_HASH_BITS 10 164ef0f3390SNeilBrown #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) 165ef0f3390SNeilBrown #define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1) 166ef0f3390SNeilBrown 167ddc04c41SJ. Bruce Fields static unsigned int file_hashval(struct inode *ino) 168ddc04c41SJ. Bruce Fields { 169ddc04c41SJ. Bruce Fields /* XXX: why are we hashing on inode pointer, anyway? */ 170ddc04c41SJ. Bruce Fields return hash_ptr(ino, FILE_HASH_BITS); 171ddc04c41SJ. Bruce Fields } 172ddc04c41SJ. Bruce Fields 173ddc04c41SJ. Bruce Fields static unsigned int stateid_hashval(u32 owner_id, u32 file_id) 174ddc04c41SJ. Bruce Fields { 175ddc04c41SJ. Bruce Fields return (owner_id + file_id) & STATEID_HASH_MASK; 176ddc04c41SJ. Bruce Fields } 177ef0f3390SNeilBrown 178ef0f3390SNeilBrown static struct list_head file_hashtbl[FILE_HASH_SIZE]; 179ef0f3390SNeilBrown static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; 180ef0f3390SNeilBrown 181998db52cSJ. Bruce Fields static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) 182f9d7562fSJ. Bruce Fields { 183f9d7562fSJ. Bruce Fields BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); 184f9d7562fSJ. Bruce Fields atomic_inc(&fp->fi_access[oflag]); 185f9d7562fSJ. Bruce Fields } 186f9d7562fSJ. Bruce Fields 187998db52cSJ. Bruce Fields static void nfs4_file_get_access(struct nfs4_file *fp, int oflag) 188998db52cSJ. Bruce Fields { 189998db52cSJ. Bruce Fields if (oflag == O_RDWR) { 190998db52cSJ. Bruce Fields __nfs4_file_get_access(fp, O_RDONLY); 191998db52cSJ. Bruce Fields __nfs4_file_get_access(fp, O_WRONLY); 192998db52cSJ. Bruce Fields } else 193998db52cSJ. Bruce Fields __nfs4_file_get_access(fp, oflag); 194998db52cSJ. Bruce Fields } 195998db52cSJ. Bruce Fields 196998db52cSJ. Bruce Fields static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) 197f9d7562fSJ. Bruce Fields { 198f9d7562fSJ. Bruce Fields if (fp->fi_fds[oflag]) { 199f9d7562fSJ. Bruce Fields fput(fp->fi_fds[oflag]); 200f9d7562fSJ. Bruce Fields fp->fi_fds[oflag] = NULL; 201f9d7562fSJ. Bruce Fields } 202f9d7562fSJ. Bruce Fields } 203f9d7562fSJ. Bruce Fields 204998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 205f9d7562fSJ. Bruce Fields { 206f9d7562fSJ. Bruce Fields if (atomic_dec_and_test(&fp->fi_access[oflag])) { 207f9d7562fSJ. Bruce Fields nfs4_file_put_fd(fp, O_RDWR); 208f9d7562fSJ. Bruce Fields nfs4_file_put_fd(fp, oflag); 209f9d7562fSJ. Bruce Fields } 210f9d7562fSJ. Bruce Fields } 211f9d7562fSJ. Bruce Fields 212998db52cSJ. Bruce Fields static void nfs4_file_put_access(struct nfs4_file *fp, int oflag) 213998db52cSJ. Bruce Fields { 214998db52cSJ. Bruce Fields if (oflag == O_RDWR) { 215998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_RDONLY); 216998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 217998db52cSJ. Bruce Fields } else 218998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, oflag); 219998db52cSJ. Bruce Fields } 220998db52cSJ. Bruce Fields 2211da177e4SLinus Torvalds static struct nfs4_delegation * 2221da177e4SLinus Torvalds alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) 2231da177e4SLinus Torvalds { 2241da177e4SLinus Torvalds struct nfs4_delegation *dp; 2251da177e4SLinus Torvalds struct nfs4_file *fp = stp->st_file; 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 228c3e48080SJ. Bruce Fields /* 229c3e48080SJ. Bruce Fields * Major work on the lease subsystem (for example, to support 230c3e48080SJ. Bruce Fields * calbacks on stat) will be required before we can support 231c3e48080SJ. Bruce Fields * write delegations properly. 232c3e48080SJ. Bruce Fields */ 233c3e48080SJ. Bruce Fields if (type != NFS4_OPEN_DELEGATE_READ) 234c3e48080SJ. Bruce Fields return NULL; 23547f9940cSMeelap Shah if (fp->fi_had_conflict) 23647f9940cSMeelap Shah return NULL; 237c2f1a551SMeelap Shah if (num_delegations > max_delegations) 238ef0f3390SNeilBrown return NULL; 2395b2d21c1SNeilBrown dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); 2405b2d21c1SNeilBrown if (dp == NULL) 2411da177e4SLinus Torvalds return dp; 242ef0f3390SNeilBrown num_delegations++; 243ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 244ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 2451da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 2461da177e4SLinus Torvalds dp->dl_client = clp; 24713cd2184SNeilBrown get_nfs4_file(fp); 2481da177e4SLinus Torvalds dp->dl_file = fp; 2491da177e4SLinus Torvalds dp->dl_type = type; 250e4e83ea4SJ. Bruce Fields dp->dl_stateid.si_boot = boot_time; 2511da177e4SLinus Torvalds dp->dl_stateid.si_stateownerid = current_delegid++; 2521da177e4SLinus Torvalds dp->dl_stateid.si_fileid = 0; 25373997dc4SJ. Bruce Fields dp->dl_stateid.si_generation = 1; 2546c02eaa1SJ. Bruce Fields fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); 2551da177e4SLinus Torvalds dp->dl_time = 0; 2561da177e4SLinus Torvalds atomic_set(&dp->dl_count, 1); 257b5a1a81eSJ. Bruce Fields INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); 2581da177e4SLinus Torvalds return dp; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds void 2621da177e4SLinus Torvalds nfs4_put_delegation(struct nfs4_delegation *dp) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds if (atomic_dec_and_test(&dp->dl_count)) { 2651da177e4SLinus Torvalds dprintk("NFSD: freeing dp %p\n",dp); 26613cd2184SNeilBrown put_nfs4_file(dp->dl_file); 2675b2d21c1SNeilBrown kmem_cache_free(deleg_slab, dp); 268ef0f3390SNeilBrown num_delegations--; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 272acfdf5c3SJ. Bruce Fields static void nfs4_put_deleg_lease(struct nfs4_file *fp) 2731da177e4SLinus Torvalds { 274acfdf5c3SJ. Bruce Fields if (atomic_dec_and_test(&fp->fi_delegees)) { 275acfdf5c3SJ. Bruce Fields vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); 276acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 2774ee63624SJ. Bruce Fields fput(fp->fi_deleg_file); 278acfdf5c3SJ. Bruce Fields fp->fi_deleg_file = NULL; 279acfdf5c3SJ. Bruce Fields } 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds /* Called under the state lock. */ 2831da177e4SLinus Torvalds static void 2841da177e4SLinus Torvalds unhash_delegation(struct nfs4_delegation *dp) 2851da177e4SLinus Torvalds { 286ea1da636SNeilBrown list_del_init(&dp->dl_perclnt); 2871da177e4SLinus Torvalds spin_lock(&recall_lock); 2885d926e8cSJ. Bruce Fields list_del_init(&dp->dl_perfile); 2891da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 2901da177e4SLinus Torvalds spin_unlock(&recall_lock); 291acfdf5c3SJ. Bruce Fields nfs4_put_deleg_lease(dp->dl_file); 2921da177e4SLinus Torvalds nfs4_put_delegation(dp); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* 2961da177e4SLinus Torvalds * SETCLIENTID state 2971da177e4SLinus Torvalds */ 2981da177e4SLinus Torvalds 29936acb66bSBenny Halevy /* client_lock protects the client lru list and session hash table */ 3009089f1b4SBenny Halevy static DEFINE_SPINLOCK(client_lock); 3019089f1b4SBenny Halevy 3021da177e4SLinus Torvalds /* Hash tables for nfs4_clientid state */ 3031da177e4SLinus Torvalds #define CLIENT_HASH_BITS 4 3041da177e4SLinus Torvalds #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) 3051da177e4SLinus Torvalds #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) 3061da177e4SLinus Torvalds 307ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 308ddc04c41SJ. Bruce Fields { 309ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 310ddc04c41SJ. Bruce Fields } 311ddc04c41SJ. Bruce Fields 312ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 313ddc04c41SJ. Bruce Fields { 314ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 315ddc04c41SJ. Bruce Fields } 316ddc04c41SJ. Bruce Fields 3171da177e4SLinus Torvalds /* 3181da177e4SLinus Torvalds * reclaim_str_hashtbl[] holds known client info from previous reset/reboot 3191da177e4SLinus Torvalds * used in reboot/reset lease grace period processing 3201da177e4SLinus Torvalds * 3211da177e4SLinus Torvalds * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed 3221da177e4SLinus Torvalds * setclientid_confirmed info. 3231da177e4SLinus Torvalds * 3241da177e4SLinus Torvalds * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed 3251da177e4SLinus Torvalds * setclientid info. 3261da177e4SLinus Torvalds * 3271da177e4SLinus Torvalds * client_lru holds client queue ordered by nfs4_client.cl_time 3281da177e4SLinus Torvalds * for lease renewal. 3291da177e4SLinus Torvalds * 3301da177e4SLinus Torvalds * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time 3311da177e4SLinus Torvalds * for last close replay. 3321da177e4SLinus Torvalds */ 3331da177e4SLinus Torvalds static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE]; 3341da177e4SLinus Torvalds static int reclaim_str_hashtbl_size = 0; 3351da177e4SLinus Torvalds static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; 3361da177e4SLinus Torvalds static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; 3371da177e4SLinus Torvalds static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; 3381da177e4SLinus Torvalds static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; 3391da177e4SLinus Torvalds static struct list_head client_lru; 3401da177e4SLinus Torvalds static struct list_head close_lru; 3411da177e4SLinus Torvalds 342f9d7562fSJ. Bruce Fields /* 343f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 344f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 345f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 346f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 347f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 348f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 349f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 350f9d7562fSJ. Bruce Fields * 351f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 352f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 353f9d7562fSJ. Bruce Fields * 354f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 355f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 356f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 357f9d7562fSJ. Bruce Fields * 358f9d7562fSJ. Bruce Fields * which we should reject. 359f9d7562fSJ. Bruce Fields */ 360f9d7562fSJ. Bruce Fields static void 361f9d7562fSJ. Bruce Fields set_access(unsigned int *access, unsigned long bmap) { 362f9d7562fSJ. Bruce Fields int i; 363f9d7562fSJ. Bruce Fields 364f9d7562fSJ. Bruce Fields *access = 0; 365f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 366f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 367f9d7562fSJ. Bruce Fields *access |= i; 368f9d7562fSJ. Bruce Fields } 369f9d7562fSJ. Bruce Fields } 370f9d7562fSJ. Bruce Fields 371f9d7562fSJ. Bruce Fields static void 372f9d7562fSJ. Bruce Fields set_deny(unsigned int *deny, unsigned long bmap) { 373f9d7562fSJ. Bruce Fields int i; 374f9d7562fSJ. Bruce Fields 375f9d7562fSJ. Bruce Fields *deny = 0; 376f9d7562fSJ. Bruce Fields for (i = 0; i < 4; i++) { 377f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 378f9d7562fSJ. Bruce Fields *deny |= i ; 379f9d7562fSJ. Bruce Fields } 380f9d7562fSJ. Bruce Fields } 381f9d7562fSJ. Bruce Fields 382f9d7562fSJ. Bruce Fields static int 383f9d7562fSJ. Bruce Fields test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { 384f9d7562fSJ. Bruce Fields unsigned int access, deny; 385f9d7562fSJ. Bruce Fields 386f9d7562fSJ. Bruce Fields set_access(&access, stp->st_access_bmap); 387f9d7562fSJ. Bruce Fields set_deny(&deny, stp->st_deny_bmap); 388f9d7562fSJ. Bruce Fields if ((access & open->op_share_deny) || (deny & open->op_share_access)) 389f9d7562fSJ. Bruce Fields return 0; 390f9d7562fSJ. Bruce Fields return 1; 391f9d7562fSJ. Bruce Fields } 392f9d7562fSJ. Bruce Fields 393f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 394f9d7562fSJ. Bruce Fields { 3958f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 396f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 397f9d7562fSJ. Bruce Fields return O_RDONLY; 398f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 399f9d7562fSJ. Bruce Fields return O_WRONLY; 400f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 401f9d7562fSJ. Bruce Fields return O_RDWR; 402f9d7562fSJ. Bruce Fields } 403f9d7562fSJ. Bruce Fields BUG(); 404f9d7562fSJ. Bruce Fields } 405f9d7562fSJ. Bruce Fields 406529d7b2aSJ. Bruce Fields static void unhash_generic_stateid(struct nfs4_stateid *stp) 407529d7b2aSJ. Bruce Fields { 408529d7b2aSJ. Bruce Fields list_del(&stp->st_hash); 409529d7b2aSJ. Bruce Fields list_del(&stp->st_perfile); 410529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 411529d7b2aSJ. Bruce Fields } 412529d7b2aSJ. Bruce Fields 4134665e2baSJ. Bruce Fields static void close_generic_stateid(struct nfs4_stateid *stp) 414529d7b2aSJ. Bruce Fields { 415499f3edcSJ. Bruce Fields int i; 4160997b173SJ. Bruce Fields 41723fcf2ecSJ. Bruce Fields if (stp->st_access_bmap) { 418499f3edcSJ. Bruce Fields for (i = 1; i < 4; i++) { 419499f3edcSJ. Bruce Fields if (test_bit(i, &stp->st_access_bmap)) 420499f3edcSJ. Bruce Fields nfs4_file_put_access(stp->st_file, 421499f3edcSJ. Bruce Fields nfs4_access_to_omode(i)); 4224665e2baSJ. Bruce Fields __clear_bit(i, &stp->st_access_bmap); 423499f3edcSJ. Bruce Fields } 42423fcf2ecSJ. Bruce Fields } 425a96e5b90SOGAWA Hirofumi put_nfs4_file(stp->st_file); 4264665e2baSJ. Bruce Fields stp->st_file = NULL; 4274665e2baSJ. Bruce Fields } 4284665e2baSJ. Bruce Fields 4294665e2baSJ. Bruce Fields static void free_generic_stateid(struct nfs4_stateid *stp) 4304665e2baSJ. Bruce Fields { 4314665e2baSJ. Bruce Fields close_generic_stateid(stp); 432529d7b2aSJ. Bruce Fields kmem_cache_free(stateid_slab, stp); 433529d7b2aSJ. Bruce Fields } 434529d7b2aSJ. Bruce Fields 435529d7b2aSJ. Bruce Fields static void release_lock_stateid(struct nfs4_stateid *stp) 436529d7b2aSJ. Bruce Fields { 437529d7b2aSJ. Bruce Fields struct file *file; 438529d7b2aSJ. Bruce Fields 439529d7b2aSJ. Bruce Fields unhash_generic_stateid(stp); 440529d7b2aSJ. Bruce Fields file = find_any_file(stp->st_file); 441529d7b2aSJ. Bruce Fields if (file) 442fe0750e5SJ. Bruce Fields locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); 443529d7b2aSJ. Bruce Fields free_generic_stateid(stp); 444529d7b2aSJ. Bruce Fields } 445529d7b2aSJ. Bruce Fields 446fe0750e5SJ. Bruce Fields static void unhash_lockowner(struct nfs4_lockowner *lo) 447529d7b2aSJ. Bruce Fields { 448529d7b2aSJ. Bruce Fields struct nfs4_stateid *stp; 449529d7b2aSJ. Bruce Fields 450fe0750e5SJ. Bruce Fields list_del(&lo->lo_owner.so_idhash); 451fe0750e5SJ. Bruce Fields list_del(&lo->lo_owner.so_strhash); 452fe0750e5SJ. Bruce Fields list_del(&lo->lo_perstateid); 453fe0750e5SJ. Bruce Fields while (!list_empty(&lo->lo_owner.so_stateids)) { 454fe0750e5SJ. Bruce Fields stp = list_first_entry(&lo->lo_owner.so_stateids, 455529d7b2aSJ. Bruce Fields struct nfs4_stateid, st_perstateowner); 456529d7b2aSJ. Bruce Fields release_lock_stateid(stp); 457529d7b2aSJ. Bruce Fields } 458529d7b2aSJ. Bruce Fields } 459529d7b2aSJ. Bruce Fields 460fe0750e5SJ. Bruce Fields static void release_lockowner(struct nfs4_lockowner *lo) 461529d7b2aSJ. Bruce Fields { 462fe0750e5SJ. Bruce Fields unhash_lockowner(lo); 463fe0750e5SJ. Bruce Fields nfs4_free_lockowner(lo); 464529d7b2aSJ. Bruce Fields } 465529d7b2aSJ. Bruce Fields 466529d7b2aSJ. Bruce Fields static void 467529d7b2aSJ. Bruce Fields release_stateid_lockowners(struct nfs4_stateid *open_stp) 468529d7b2aSJ. Bruce Fields { 469fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 470529d7b2aSJ. Bruce Fields 471529d7b2aSJ. Bruce Fields while (!list_empty(&open_stp->st_lockowners)) { 472fe0750e5SJ. Bruce Fields lo = list_entry(open_stp->st_lockowners.next, 473fe0750e5SJ. Bruce Fields struct nfs4_lockowner, lo_perstateid); 474fe0750e5SJ. Bruce Fields release_lockowner(lo); 475529d7b2aSJ. Bruce Fields } 476529d7b2aSJ. Bruce Fields } 477529d7b2aSJ. Bruce Fields 4782283963fSJ. Bruce Fields static void release_open_stateid(struct nfs4_stateid *stp) 4792283963fSJ. Bruce Fields { 4802283963fSJ. Bruce Fields unhash_generic_stateid(stp); 4812283963fSJ. Bruce Fields release_stateid_lockowners(stp); 4822283963fSJ. Bruce Fields free_generic_stateid(stp); 4832283963fSJ. Bruce Fields } 4842283963fSJ. Bruce Fields 485fe0750e5SJ. Bruce Fields static void unhash_openowner(struct nfs4_openowner *oo) 486f1d110caSJ. Bruce Fields { 487f1d110caSJ. Bruce Fields struct nfs4_stateid *stp; 488f1d110caSJ. Bruce Fields 489fe0750e5SJ. Bruce Fields list_del(&oo->oo_owner.so_idhash); 490fe0750e5SJ. Bruce Fields list_del(&oo->oo_owner.so_strhash); 491fe0750e5SJ. Bruce Fields list_del(&oo->oo_perclient); 492fe0750e5SJ. Bruce Fields while (!list_empty(&oo->oo_owner.so_stateids)) { 493fe0750e5SJ. Bruce Fields stp = list_first_entry(&oo->oo_owner.so_stateids, 494f1d110caSJ. Bruce Fields struct nfs4_stateid, st_perstateowner); 495f1d110caSJ. Bruce Fields release_open_stateid(stp); 496f1d110caSJ. Bruce Fields } 497f1d110caSJ. Bruce Fields } 498f1d110caSJ. Bruce Fields 499fe0750e5SJ. Bruce Fields static void release_openowner(struct nfs4_openowner *oo) 500f1d110caSJ. Bruce Fields { 501fe0750e5SJ. Bruce Fields unhash_openowner(oo); 502fe0750e5SJ. Bruce Fields list_del(&oo->oo_close_lru); 503fe0750e5SJ. Bruce Fields nfs4_free_openowner(oo); 504f1d110caSJ. Bruce Fields } 505f1d110caSJ. Bruce Fields 5065282fd72SMarc Eshel #define SESSION_HASH_SIZE 512 5075282fd72SMarc Eshel static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; 5085282fd72SMarc Eshel 5095282fd72SMarc Eshel static inline int 5105282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 5115282fd72SMarc Eshel { 5125282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 5135282fd72SMarc Eshel 5145282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 5155282fd72SMarc Eshel } 5165282fd72SMarc Eshel 5175282fd72SMarc Eshel static inline void 5185282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 5195282fd72SMarc Eshel { 5205282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 5215282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 5225282fd72SMarc Eshel } 5235282fd72SMarc Eshel 524ec6b5d7bSAndy Adamson static void 525ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 526ec6b5d7bSAndy Adamson { 527ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 528ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 529ec6b5d7bSAndy Adamson 530ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 531ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 532ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 533ec6b5d7bSAndy Adamson sid->reserved = 0; 534ec6b5d7bSAndy Adamson } 535ec6b5d7bSAndy Adamson 536ec6b5d7bSAndy Adamson /* 537a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 538a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 539a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 540a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 541a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 542a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 543a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 544a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 545a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 546a649637cSAndy Adamson * for the SEQUENCE op response: 547ec6b5d7bSAndy Adamson */ 548a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 549a649637cSAndy Adamson 550557ce264SAndy Adamson static void 551557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 552557ce264SAndy Adamson { 553557ce264SAndy Adamson int i; 554557ce264SAndy Adamson 555557ce264SAndy Adamson for (i = 0; i < ses->se_fchannel.maxreqs; i++) 556557ce264SAndy Adamson kfree(ses->se_slots[i]); 557557ce264SAndy Adamson } 558557ce264SAndy Adamson 559efe0cb6dSJ. Bruce Fields /* 560efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 561efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 562efe0cb6dSJ. Bruce Fields */ 563efe0cb6dSJ. Bruce Fields static inline int slot_bytes(struct nfsd4_channel_attrs *ca) 564efe0cb6dSJ. Bruce Fields { 565efe0cb6dSJ. Bruce Fields return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 566efe0cb6dSJ. Bruce Fields } 567efe0cb6dSJ. Bruce Fields 5685b6feee9SJ. Bruce Fields static int nfsd4_sanitize_slot_size(u32 size) 569ec6b5d7bSAndy Adamson { 5705b6feee9SJ. Bruce Fields size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */ 5715b6feee9SJ. Bruce Fields size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE); 572ec6b5d7bSAndy Adamson 5735b6feee9SJ. Bruce Fields return size; 574557ce264SAndy Adamson } 575557ce264SAndy Adamson 5765b6feee9SJ. Bruce Fields /* 5775b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 5785b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 5795b6feee9SJ. Bruce Fields * rooom for new connections. For now we just fail the create session. 5805b6feee9SJ. Bruce Fields */ 5815b6feee9SJ. Bruce Fields static int nfsd4_get_drc_mem(int slotsize, u32 num) 5825b6feee9SJ. Bruce Fields { 5835b6feee9SJ. Bruce Fields int avail; 5845b6feee9SJ. Bruce Fields 5855b6feee9SJ. Bruce Fields num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION); 5865b6feee9SJ. Bruce Fields 5875b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 5885b6feee9SJ. Bruce Fields avail = min_t(int, NFSD_MAX_MEM_PER_SESSION, 5895b6feee9SJ. Bruce Fields nfsd_drc_max_mem - nfsd_drc_mem_used); 5905b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 5915b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 5925b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 5935b6feee9SJ. Bruce Fields 5945b6feee9SJ. Bruce Fields return num; 5955b6feee9SJ. Bruce Fields } 5965b6feee9SJ. Bruce Fields 5975b6feee9SJ. Bruce Fields static void nfsd4_put_drc_mem(int slotsize, int num) 5985b6feee9SJ. Bruce Fields { 5995b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 6005b6feee9SJ. Bruce Fields nfsd_drc_mem_used -= slotsize * num; 6015b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 6025b6feee9SJ. Bruce Fields } 6035b6feee9SJ. Bruce Fields 6045b6feee9SJ. Bruce Fields static struct nfsd4_session *alloc_session(int slotsize, int numslots) 6055b6feee9SJ. Bruce Fields { 6065b6feee9SJ. Bruce Fields struct nfsd4_session *new; 6075b6feee9SJ. Bruce Fields int mem, i; 608ec6b5d7bSAndy Adamson 609c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 610ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 6115b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 612ec6b5d7bSAndy Adamson 6135b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 6146c18ba9fSAlexandros Batsakis if (!new) 6155b6feee9SJ. Bruce Fields return NULL; 616ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 6175b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 6185b6feee9SJ. Bruce Fields mem = sizeof(struct nfsd4_slot) + slotsize; 6195b6feee9SJ. Bruce Fields new->se_slots[i] = kzalloc(mem, GFP_KERNEL); 6205b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 621ec6b5d7bSAndy Adamson goto out_free; 622ec6b5d7bSAndy Adamson } 6235b6feee9SJ. Bruce Fields return new; 6245b6feee9SJ. Bruce Fields out_free: 6255b6feee9SJ. Bruce Fields while (i--) 6265b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 6275b6feee9SJ. Bruce Fields kfree(new); 6285b6feee9SJ. Bruce Fields return NULL; 6295b6feee9SJ. Bruce Fields } 6305b6feee9SJ. Bruce Fields 6315b6feee9SJ. Bruce Fields static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize) 6325b6feee9SJ. Bruce Fields { 6335b6feee9SJ. Bruce Fields u32 maxrpc = nfsd_serv->sv_max_mesg; 6345b6feee9SJ. Bruce Fields 6355b6feee9SJ. Bruce Fields new->maxreqs = numslots; 636d2b21743SMi Jinlong new->maxresp_cached = min_t(u32, req->maxresp_cached, 637d2b21743SMi Jinlong slotsize + NFSD_MIN_HDR_SEQ_SZ); 6385b6feee9SJ. Bruce Fields new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); 6395b6feee9SJ. Bruce Fields new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); 6405b6feee9SJ. Bruce Fields new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); 6415b6feee9SJ. Bruce Fields } 6425b6feee9SJ. Bruce Fields 64319cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 64419cf5c02SJ. Bruce Fields { 64519cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 64619cf5c02SJ. Bruce Fields kfree(c); 64719cf5c02SJ. Bruce Fields } 64819cf5c02SJ. Bruce Fields 64919cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 65019cf5c02SJ. Bruce Fields { 65119cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 65219cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 65319cf5c02SJ. Bruce Fields 65419cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 65519cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 65619cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 65719cf5c02SJ. Bruce Fields free_conn(c); 65819cf5c02SJ. Bruce Fields } 65919cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 660eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 66119cf5c02SJ. Bruce Fields } 66219cf5c02SJ. Bruce Fields 663d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 664c7662518SJ. Bruce Fields { 665c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 666c7662518SJ. Bruce Fields 667c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 668c7662518SJ. Bruce Fields if (!conn) 669db90681dSJ. Bruce Fields return NULL; 670c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 671c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 672d29c374cSJ. Bruce Fields conn->cn_flags = flags; 673db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 674db90681dSJ. Bruce Fields return conn; 675db90681dSJ. Bruce Fields } 676db90681dSJ. Bruce Fields 677328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 678328ead28SJ. Bruce Fields { 679328ead28SJ. Bruce Fields conn->cn_session = ses; 680328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 681328ead28SJ. Bruce Fields } 682328ead28SJ. Bruce Fields 683db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 684db90681dSJ. Bruce Fields { 685db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 686c7662518SJ. Bruce Fields 687c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 688328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 689c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 690db90681dSJ. Bruce Fields } 691c7662518SJ. Bruce Fields 69221b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 693db90681dSJ. Bruce Fields { 69419cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 69521b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 696db90681dSJ. Bruce Fields } 697db90681dSJ. Bruce Fields 6981d1bc8f2SJ. Bruce Fields static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) 699db90681dSJ. Bruce Fields { 700db90681dSJ. Bruce Fields struct nfsd4_conn *conn; 70121b75b01SJ. Bruce Fields int ret; 702db90681dSJ. Bruce Fields 7031d1bc8f2SJ. Bruce Fields conn = alloc_conn(rqstp, dir); 704db90681dSJ. Bruce Fields if (!conn) 705db90681dSJ. Bruce Fields return nfserr_jukebox; 706db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 70721b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 70821b75b01SJ. Bruce Fields if (ret) 70921b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 71021b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 711c7662518SJ. Bruce Fields return nfs_ok; 712c7662518SJ. Bruce Fields } 713c7662518SJ. Bruce Fields 7141d1bc8f2SJ. Bruce Fields static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) 7151d1bc8f2SJ. Bruce Fields { 7161d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 7171d1bc8f2SJ. Bruce Fields 7181d1bc8f2SJ. Bruce Fields if (ses->se_flags & SESSION4_BACK_CHAN) 7191d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 7201d1bc8f2SJ. Bruce Fields 7211d1bc8f2SJ. Bruce Fields return nfsd4_new_conn(rqstp, ses, dir); 7221d1bc8f2SJ. Bruce Fields } 7231d1bc8f2SJ. Bruce Fields 7241d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 72519cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 726c7662518SJ. Bruce Fields { 72719cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 72819cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 72919cf5c02SJ. Bruce Fields 73019cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 73119cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 73219cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 73319cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 73419cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 73519cf5c02SJ. Bruce Fields 73619cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 73719cf5c02SJ. Bruce Fields free_conn(c); 73819cf5c02SJ. Bruce Fields 73919cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 74019cf5c02SJ. Bruce Fields } 74119cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 742c7662518SJ. Bruce Fields } 743c7662518SJ. Bruce Fields 744c7662518SJ. Bruce Fields void free_session(struct kref *kref) 745c7662518SJ. Bruce Fields { 746c7662518SJ. Bruce Fields struct nfsd4_session *ses; 747c7662518SJ. Bruce Fields int mem; 748c7662518SJ. Bruce Fields 749c7662518SJ. Bruce Fields ses = container_of(kref, struct nfsd4_session, se_ref); 75019cf5c02SJ. Bruce Fields nfsd4_del_conns(ses); 751c7662518SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 752c7662518SJ. Bruce Fields mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); 753c7662518SJ. Bruce Fields nfsd_drc_mem_used -= mem; 754c7662518SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 755c7662518SJ. Bruce Fields free_session_slots(ses); 756c7662518SJ. Bruce Fields kfree(ses); 757c7662518SJ. Bruce Fields } 758c7662518SJ. Bruce Fields 759ac7c46f2SJ. Bruce Fields static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) 7605b6feee9SJ. Bruce Fields { 7615b6feee9SJ. Bruce Fields struct nfsd4_session *new; 7625b6feee9SJ. Bruce Fields struct nfsd4_channel_attrs *fchan = &cses->fore_channel; 7635b6feee9SJ. Bruce Fields int numslots, slotsize; 764c7662518SJ. Bruce Fields int status; 7655b6feee9SJ. Bruce Fields int idx; 7665b6feee9SJ. Bruce Fields 7675b6feee9SJ. Bruce Fields /* 7685b6feee9SJ. Bruce Fields * Note decreasing slot size below client's request may 7695b6feee9SJ. Bruce Fields * make it difficult for client to function correctly, whereas 7705b6feee9SJ. Bruce Fields * decreasing the number of slots will (just?) affect 7715b6feee9SJ. Bruce Fields * performance. When short on memory we therefore prefer to 7725b6feee9SJ. Bruce Fields * decrease number of slots instead of their size. 7735b6feee9SJ. Bruce Fields */ 7745b6feee9SJ. Bruce Fields slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); 7755b6feee9SJ. Bruce Fields numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); 776ced6dfe9SMi Jinlong if (numslots < 1) 777ced6dfe9SMi Jinlong return NULL; 7785b6feee9SJ. Bruce Fields 7795b6feee9SJ. Bruce Fields new = alloc_session(slotsize, numslots); 7805b6feee9SJ. Bruce Fields if (!new) { 7815b6feee9SJ. Bruce Fields nfsd4_put_drc_mem(slotsize, fchan->maxreqs); 782ac7c46f2SJ. Bruce Fields return NULL; 7835b6feee9SJ. Bruce Fields } 7845b6feee9SJ. Bruce Fields init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); 785ec6b5d7bSAndy Adamson 786ec6b5d7bSAndy Adamson new->se_client = clp; 787ec6b5d7bSAndy Adamson gen_sessionid(new); 788ec6b5d7bSAndy Adamson 789c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 790c7662518SJ. Bruce Fields 791ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 792ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 7938b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 794ec6b5d7bSAndy Adamson kref_init(&new->se_ref); 7955b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 7969089f1b4SBenny Halevy spin_lock(&client_lock); 797ec6b5d7bSAndy Adamson list_add(&new->se_hash, &sessionid_hashtbl[idx]); 7984c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 799ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 8004c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 8019089f1b4SBenny Halevy spin_unlock(&client_lock); 802ec6b5d7bSAndy Adamson 8031d1bc8f2SJ. Bruce Fields status = nfsd4_new_conn_from_crses(rqstp, new); 804ac7c46f2SJ. Bruce Fields /* whoops: benny points out, status is ignored! (err, or bogus) */ 805c7662518SJ. Bruce Fields if (status) { 806c7662518SJ. Bruce Fields free_session(&new->se_ref); 807ac7c46f2SJ. Bruce Fields return NULL; 808c7662518SJ. Bruce Fields } 809dcbeaa68SJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) { 810edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 811dcbeaa68SJ. Bruce Fields /* 812dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 813dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 814dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 815dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 816dcbeaa68SJ. Bruce Fields * future: 817dcbeaa68SJ. Bruce Fields */ 818edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 819edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 820edd76786SJ. Bruce Fields } 821dcbeaa68SJ. Bruce Fields nfsd4_probe_callback(clp); 822ac7c46f2SJ. Bruce Fields return new; 823ec6b5d7bSAndy Adamson } 824ec6b5d7bSAndy Adamson 8259089f1b4SBenny Halevy /* caller must hold client_lock */ 8265282fd72SMarc Eshel static struct nfsd4_session * 8275282fd72SMarc Eshel find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) 8285282fd72SMarc Eshel { 8295282fd72SMarc Eshel struct nfsd4_session *elem; 8305282fd72SMarc Eshel int idx; 8315282fd72SMarc Eshel 8325282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 8335282fd72SMarc Eshel idx = hash_sessionid(sessionid); 8345282fd72SMarc Eshel /* Search in the appropriate list */ 8355282fd72SMarc Eshel list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { 8365282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 8375282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 8385282fd72SMarc Eshel return elem; 8395282fd72SMarc Eshel } 8405282fd72SMarc Eshel } 8415282fd72SMarc Eshel 8425282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 8435282fd72SMarc Eshel return NULL; 8445282fd72SMarc Eshel } 8455282fd72SMarc Eshel 8469089f1b4SBenny Halevy /* caller must hold client_lock */ 8477116ed6bSAndy Adamson static void 8485282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 8497116ed6bSAndy Adamson { 8507116ed6bSAndy Adamson list_del(&ses->se_hash); 8514c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 8527116ed6bSAndy Adamson list_del(&ses->se_perclnt); 8534c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 8545282fd72SMarc Eshel } 8555282fd72SMarc Eshel 85636acb66bSBenny Halevy /* must be called under the client_lock */ 8571da177e4SLinus Torvalds static inline void 85836acb66bSBenny Halevy renew_client_locked(struct nfs4_client *clp) 8591da177e4SLinus Torvalds { 86007cd4909SBenny Halevy if (is_client_expired(clp)) { 86107cd4909SBenny Halevy dprintk("%s: client (clientid %08x/%08x) already expired\n", 86207cd4909SBenny Halevy __func__, 86307cd4909SBenny Halevy clp->cl_clientid.cl_boot, 86407cd4909SBenny Halevy clp->cl_clientid.cl_id); 86507cd4909SBenny Halevy return; 86607cd4909SBenny Halevy } 86707cd4909SBenny Halevy 8681da177e4SLinus Torvalds /* 8691da177e4SLinus Torvalds * Move client to the end to the LRU list. 8701da177e4SLinus Torvalds */ 8711da177e4SLinus Torvalds dprintk("renewing client (clientid %08x/%08x)\n", 8721da177e4SLinus Torvalds clp->cl_clientid.cl_boot, 8731da177e4SLinus Torvalds clp->cl_clientid.cl_id); 8741da177e4SLinus Torvalds list_move_tail(&clp->cl_lru, &client_lru); 8751da177e4SLinus Torvalds clp->cl_time = get_seconds(); 8761da177e4SLinus Torvalds } 8771da177e4SLinus Torvalds 87836acb66bSBenny Halevy static inline void 87936acb66bSBenny Halevy renew_client(struct nfs4_client *clp) 88036acb66bSBenny Halevy { 88136acb66bSBenny Halevy spin_lock(&client_lock); 88236acb66bSBenny Halevy renew_client_locked(clp); 88336acb66bSBenny Halevy spin_unlock(&client_lock); 88436acb66bSBenny Halevy } 88536acb66bSBenny Halevy 8861da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 8871da177e4SLinus Torvalds static int 8881da177e4SLinus Torvalds STALE_CLIENTID(clientid_t *clid) 8891da177e4SLinus Torvalds { 8901da177e4SLinus Torvalds if (clid->cl_boot == boot_time) 8911da177e4SLinus Torvalds return 0; 89260adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 89360adfc50SAndy Adamson clid->cl_boot, clid->cl_id, boot_time); 8941da177e4SLinus Torvalds return 1; 8951da177e4SLinus Torvalds } 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds /* 8981da177e4SLinus Torvalds * XXX Should we use a slab cache ? 8991da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 9001da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 9011da177e4SLinus Torvalds */ 90235bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 9031da177e4SLinus Torvalds { 9041da177e4SLinus Torvalds struct nfs4_client *clp; 9051da177e4SLinus Torvalds 90635bba9a3SJ. Bruce Fields clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); 90735bba9a3SJ. Bruce Fields if (clp == NULL) 90835bba9a3SJ. Bruce Fields return NULL; 90935bba9a3SJ. Bruce Fields clp->cl_name.data = kmalloc(name.len, GFP_KERNEL); 91035bba9a3SJ. Bruce Fields if (clp->cl_name.data == NULL) { 91135bba9a3SJ. Bruce Fields kfree(clp); 91235bba9a3SJ. Bruce Fields return NULL; 91335bba9a3SJ. Bruce Fields } 9141da177e4SLinus Torvalds memcpy(clp->cl_name.data, name.data, name.len); 9151da177e4SLinus Torvalds clp->cl_name.len = name.len; 9161da177e4SLinus Torvalds return clp; 9171da177e4SLinus Torvalds } 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds static inline void 9201da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 9211da177e4SLinus Torvalds { 922792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 923792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 924792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 925792c95ddSJ. Bruce Fields se_perclnt); 926792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 927792c95ddSJ. Bruce Fields nfsd4_put_session(ses); 928792c95ddSJ. Bruce Fields } 9291da177e4SLinus Torvalds if (clp->cl_cred.cr_group_info) 9301da177e4SLinus Torvalds put_group_info(clp->cl_cred.cr_group_info); 93168e76ad0SOlga Kornievskaia kfree(clp->cl_principal); 9321da177e4SLinus Torvalds kfree(clp->cl_name.data); 9331da177e4SLinus Torvalds kfree(clp); 9341da177e4SLinus Torvalds } 9351da177e4SLinus Torvalds 936d7682988SBenny Halevy void 937d7682988SBenny Halevy release_session_client(struct nfsd4_session *session) 938d7682988SBenny Halevy { 939d7682988SBenny Halevy struct nfs4_client *clp = session->se_client; 940d7682988SBenny Halevy 941d7682988SBenny Halevy if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) 942d7682988SBenny Halevy return; 943d7682988SBenny Halevy if (is_client_expired(clp)) { 944d7682988SBenny Halevy free_client(clp); 945d7682988SBenny Halevy session->se_client = NULL; 946d7682988SBenny Halevy } else 947d7682988SBenny Halevy renew_client_locked(clp); 948d7682988SBenny Halevy spin_unlock(&client_lock); 949d7682988SBenny Halevy } 950d7682988SBenny Halevy 95184d38ac9SBenny Halevy /* must be called under the client_lock */ 95284d38ac9SBenny Halevy static inline void 95384d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 95484d38ac9SBenny Halevy { 955792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 956792c95ddSJ. Bruce Fields 95707cd4909SBenny Halevy mark_client_expired(clp); 95884d38ac9SBenny Halevy list_del(&clp->cl_lru); 9594c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 960792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 961792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 9624c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 96384d38ac9SBenny Halevy } 96484d38ac9SBenny Halevy 9651da177e4SLinus Torvalds static void 9661da177e4SLinus Torvalds expire_client(struct nfs4_client *clp) 9671da177e4SLinus Torvalds { 968fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 9691da177e4SLinus Torvalds struct nfs4_delegation *dp; 9701da177e4SLinus Torvalds struct list_head reaplist; 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 9731da177e4SLinus Torvalds spin_lock(&recall_lock); 974ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 975ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 976ea1da636SNeilBrown list_del_init(&dp->dl_perclnt); 9771da177e4SLinus Torvalds list_move(&dp->dl_recall_lru, &reaplist); 9781da177e4SLinus Torvalds } 9791da177e4SLinus Torvalds spin_unlock(&recall_lock); 9801da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 9811da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 9821da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 9831da177e4SLinus Torvalds unhash_delegation(dp); 9841da177e4SLinus Torvalds } 985ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 986fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 987fe0750e5SJ. Bruce Fields release_openowner(oo); 9881da177e4SLinus Torvalds } 9896ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 9902bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 9912bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 99284d38ac9SBenny Halevy list_del(&clp->cl_idhash); 99384d38ac9SBenny Halevy list_del(&clp->cl_strhash); 99484d38ac9SBenny Halevy spin_lock(&client_lock); 99584d38ac9SBenny Halevy unhash_client_locked(clp); 99646583e25SBenny Halevy if (atomic_read(&clp->cl_refcount) == 0) 997b12a05cbSJ. Bruce Fields free_client(clp); 99846583e25SBenny Halevy spin_unlock(&client_lock); 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds 100135bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 100235bba9a3SJ. Bruce Fields { 100335bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 100435bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 10051da177e4SLinus Torvalds } 10061da177e4SLinus Torvalds 100735bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 100835bba9a3SJ. Bruce Fields { 10091da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 10101da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds 101335bba9a3SJ. Bruce Fields static void copy_cred(struct svc_cred *target, struct svc_cred *source) 101435bba9a3SJ. Bruce Fields { 10151da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 10161da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 10171da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 10181da177e4SLinus Torvalds get_group_info(target->cr_group_info); 10191da177e4SLinus Torvalds } 10201da177e4SLinus Torvalds 102135bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 1022599e0a22SJ. Bruce Fields { 1023a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 10241da177e4SLinus Torvalds } 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds static int 1027599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 1028599e0a22SJ. Bruce Fields { 1029599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds static int 1033599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 1034599e0a22SJ. Bruce Fields { 1035599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 10361da177e4SLinus Torvalds } 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds /* XXX what about NGROUP */ 10391da177e4SLinus Torvalds static int 1040599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 1041599e0a22SJ. Bruce Fields { 1042599e0a22SJ. Bruce Fields return cr1->cr_uid == cr2->cr_uid; 10431da177e4SLinus Torvalds } 10441da177e4SLinus Torvalds 10455ec7b46cSJ. Bruce Fields static void gen_clid(struct nfs4_client *clp) 10465ec7b46cSJ. Bruce Fields { 10475ec7b46cSJ. Bruce Fields static u32 current_clientid = 1; 10485ec7b46cSJ. Bruce Fields 10491da177e4SLinus Torvalds clp->cl_clientid.cl_boot = boot_time; 10501da177e4SLinus Torvalds clp->cl_clientid.cl_id = current_clientid++; 10511da177e4SLinus Torvalds } 10521da177e4SLinus Torvalds 1053deda2faaSJ. Bruce Fields static void gen_confirm(struct nfs4_client *clp) 1054deda2faaSJ. Bruce Fields { 1055deda2faaSJ. Bruce Fields static u32 i; 10561da177e4SLinus Torvalds u32 *p; 10571da177e4SLinus Torvalds 10581da177e4SLinus Torvalds p = (u32 *)clp->cl_confirm.data; 1059deda2faaSJ. Bruce Fields *p++ = get_seconds(); 1060deda2faaSJ. Bruce Fields *p++ = i++; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds 10634581d140SJ. Bruce Fields static int 10644581d140SJ. Bruce Fields same_stateid(stateid_t *id_one, stateid_t *id_two) 10654581d140SJ. Bruce Fields { 10664581d140SJ. Bruce Fields if (id_one->si_stateownerid != id_two->si_stateownerid) 10674581d140SJ. Bruce Fields return 0; 10684581d140SJ. Bruce Fields return id_one->si_fileid == id_two->si_fileid; 10694581d140SJ. Bruce Fields } 10704581d140SJ. Bruce Fields 10714d71ab87SJ. Bruce Fields static struct nfs4_stateid *find_stateid(stateid_t *t) 10724581d140SJ. Bruce Fields { 10734581d140SJ. Bruce Fields struct nfs4_stateid *s; 10744581d140SJ. Bruce Fields unsigned int hashval; 10754581d140SJ. Bruce Fields 10764581d140SJ. Bruce Fields hashval = stateid_hashval(t->si_stateownerid, t->si_fileid); 10774d71ab87SJ. Bruce Fields list_for_each_entry(s, &stateid_hashtbl[hashval], st_hash) 10784d71ab87SJ. Bruce Fields if (same_stateid(&s->st_stateid, t)) 10794581d140SJ. Bruce Fields return s; 10804d71ab87SJ. Bruce Fields return NULL; 10814581d140SJ. Bruce Fields } 10824d71ab87SJ. Bruce Fields 10832288d0e3SJ. Bruce Fields static struct nfs4_stateid *find_stateid_by_type(stateid_t *t, char typemask) 10844d71ab87SJ. Bruce Fields { 10854d71ab87SJ. Bruce Fields struct nfs4_stateid *s; 10864d71ab87SJ. Bruce Fields 10874d71ab87SJ. Bruce Fields s = find_stateid(t); 10884d71ab87SJ. Bruce Fields if (!s) 10894d71ab87SJ. Bruce Fields return NULL; 10902288d0e3SJ. Bruce Fields if (typemask & s->st_type) 10914d71ab87SJ. Bruce Fields return s; 10924581d140SJ. Bruce Fields return NULL; 10934581d140SJ. Bruce Fields } 10944581d140SJ. Bruce Fields 1095b09333c4SRicardo Labiaga static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, 1096b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 1097b09333c4SRicardo Labiaga { 1098b09333c4SRicardo Labiaga struct nfs4_client *clp; 1099b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 1100b09333c4SRicardo Labiaga char *princ; 1101b09333c4SRicardo Labiaga 1102b09333c4SRicardo Labiaga clp = alloc_client(name); 1103b09333c4SRicardo Labiaga if (clp == NULL) 1104b09333c4SRicardo Labiaga return NULL; 1105b09333c4SRicardo Labiaga 1106792c95ddSJ. Bruce Fields INIT_LIST_HEAD(&clp->cl_sessions); 1107792c95ddSJ. Bruce Fields 1108b09333c4SRicardo Labiaga princ = svc_gss_principal(rqstp); 1109b09333c4SRicardo Labiaga if (princ) { 1110b09333c4SRicardo Labiaga clp->cl_principal = kstrdup(princ, GFP_KERNEL); 1111b09333c4SRicardo Labiaga if (clp->cl_principal == NULL) { 1112b09333c4SRicardo Labiaga free_client(clp); 1113b09333c4SRicardo Labiaga return NULL; 1114b09333c4SRicardo Labiaga } 1115b09333c4SRicardo Labiaga } 1116b09333c4SRicardo Labiaga 1117b09333c4SRicardo Labiaga memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); 111846583e25SBenny Halevy atomic_set(&clp->cl_refcount, 0); 111977a3569dSJ. Bruce Fields clp->cl_cb_state = NFSD4_CB_UNKNOWN; 1120b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_idhash); 1121b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_strhash); 1122b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_openowners); 1123b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_delegations); 1124b09333c4SRicardo Labiaga INIT_LIST_HEAD(&clp->cl_lru); 11255ce8ba25SJ. Bruce Fields INIT_LIST_HEAD(&clp->cl_callbacks); 11266ff8da08SJ. Bruce Fields spin_lock_init(&clp->cl_lock); 1127cee277d9SJ. Bruce Fields INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); 112807cd4909SBenny Halevy clp->cl_time = get_seconds(); 1129b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 1130b09333c4SRicardo Labiaga rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 1131b09333c4SRicardo Labiaga copy_verf(clp, verf); 1132b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 1133b09333c4SRicardo Labiaga clp->cl_flavor = rqstp->rq_flavor; 1134b09333c4SRicardo Labiaga copy_cred(&clp->cl_cred, &rqstp->rq_cred); 1135b09333c4SRicardo Labiaga gen_confirm(clp); 1136edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 1137b09333c4SRicardo Labiaga return clp; 1138b09333c4SRicardo Labiaga } 1139b09333c4SRicardo Labiaga 114035bba9a3SJ. Bruce Fields static int check_name(struct xdr_netobj name) 114135bba9a3SJ. Bruce Fields { 11421da177e4SLinus Torvalds if (name.len == 0) 11431da177e4SLinus Torvalds return 0; 11441da177e4SLinus Torvalds if (name.len > NFS4_OPAQUE_LIMIT) { 11452fdada03SJ. Bruce Fields dprintk("NFSD: check_name: name too long(%d)!\n", name.len); 11461da177e4SLinus Torvalds return 0; 11471da177e4SLinus Torvalds } 11481da177e4SLinus Torvalds return 1; 11491da177e4SLinus Torvalds } 11501da177e4SLinus Torvalds 1151fd39ca9aSNeilBrown static void 11521da177e4SLinus Torvalds add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) 11531da177e4SLinus Torvalds { 11541da177e4SLinus Torvalds unsigned int idhashval; 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); 11571da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 11581da177e4SLinus Torvalds list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); 115936acb66bSBenny Halevy renew_client(clp); 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds 1162fd39ca9aSNeilBrown static void 11631da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 11641da177e4SLinus Torvalds { 11651da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 11661da177e4SLinus Torvalds unsigned int strhashval; 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 1169f116629dSAkinobu Mita list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); 1170a55370a3SNeilBrown strhashval = clientstr_hashval(clp->cl_recdir); 1171328efbabSBenny Halevy list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); 11721da177e4SLinus Torvalds renew_client(clp); 11731da177e4SLinus Torvalds } 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds static struct nfs4_client * 11761da177e4SLinus Torvalds find_confirmed_client(clientid_t *clid) 11771da177e4SLinus Torvalds { 11781da177e4SLinus Torvalds struct nfs4_client *clp; 11791da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { 1182599e0a22SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) 11831da177e4SLinus Torvalds return clp; 11841da177e4SLinus Torvalds } 11851da177e4SLinus Torvalds return NULL; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds static struct nfs4_client * 11891da177e4SLinus Torvalds find_unconfirmed_client(clientid_t *clid) 11901da177e4SLinus Torvalds { 11911da177e4SLinus Torvalds struct nfs4_client *clp; 11921da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { 1195599e0a22SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) 11961da177e4SLinus Torvalds return clp; 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds return NULL; 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds 12016e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 1202a1bcecd2SAndy Adamson { 12036e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 1204a1bcecd2SAndy Adamson } 1205a1bcecd2SAndy Adamson 120628ce6054SNeilBrown static struct nfs4_client * 1207e203d506SJ. Bruce Fields find_confirmed_client_by_str(const char *dname, unsigned int hashval) 120828ce6054SNeilBrown { 120928ce6054SNeilBrown struct nfs4_client *clp; 121028ce6054SNeilBrown 121128ce6054SNeilBrown list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { 1212e203d506SJ. Bruce Fields if (same_name(clp->cl_recdir, dname)) 121328ce6054SNeilBrown return clp; 121428ce6054SNeilBrown } 121528ce6054SNeilBrown return NULL; 121628ce6054SNeilBrown } 121728ce6054SNeilBrown 121828ce6054SNeilBrown static struct nfs4_client * 1219e203d506SJ. Bruce Fields find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) 122028ce6054SNeilBrown { 122128ce6054SNeilBrown struct nfs4_client *clp; 122228ce6054SNeilBrown 122328ce6054SNeilBrown list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { 1224e203d506SJ. Bruce Fields if (same_name(clp->cl_recdir, dname)) 122528ce6054SNeilBrown return clp; 122628ce6054SNeilBrown } 122728ce6054SNeilBrown return NULL; 122828ce6054SNeilBrown } 122928ce6054SNeilBrown 12306f3d772fSTakuma Umeya static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr) 12316f3d772fSTakuma Umeya { 12326f3d772fSTakuma Umeya switch (family) { 12336f3d772fSTakuma Umeya case AF_INET: 12346f3d772fSTakuma Umeya ((struct sockaddr_in *)sa)->sin_family = AF_INET; 12356f3d772fSTakuma Umeya ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr; 12366f3d772fSTakuma Umeya return; 12376f3d772fSTakuma Umeya case AF_INET6: 12386f3d772fSTakuma Umeya ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; 12396f3d772fSTakuma Umeya ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6; 12406f3d772fSTakuma Umeya return; 12416f3d772fSTakuma Umeya } 12426f3d772fSTakuma Umeya } 12436f3d772fSTakuma Umeya 1244fd39ca9aSNeilBrown static void 12456f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 12461da177e4SLinus Torvalds { 124707263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 12486f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 12496f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 12507077ecbaSJeff Layton unsigned short expected_family; 12511da177e4SLinus Torvalds 12527077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 12537077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 12547077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 12557077ecbaSJeff Layton expected_family = AF_INET; 12567077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 12577077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 12587077ecbaSJeff Layton expected_family = AF_INET6; 12597077ecbaSJeff Layton else 12601da177e4SLinus Torvalds goto out_err; 12611da177e4SLinus Torvalds 126207263f1eSJ. Bruce Fields conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, 1263aa9a4ec7SJeff Layton se->se_callback_addr_len, 126407263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 126507263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 1266aa9a4ec7SJeff Layton 126707263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 12681da177e4SLinus Torvalds goto out_err; 1269aa9a4ec7SJeff Layton 127007263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 127107263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 1272fbf4665fSJeff Layton 127307263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 127407263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 12756f3d772fSTakuma Umeya rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr); 12761da177e4SLinus Torvalds return; 12771da177e4SLinus Torvalds out_err: 127807263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 127907263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 1280849823c5SNeil Brown dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " 12811da177e4SLinus Torvalds "will not receive delegations\n", 12821da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 12831da177e4SLinus Torvalds 12841da177e4SLinus Torvalds return; 12851da177e4SLinus Torvalds } 12861da177e4SLinus Torvalds 1287074fe897SAndy Adamson /* 1288557ce264SAndy Adamson * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size. 1289074fe897SAndy Adamson */ 1290074fe897SAndy Adamson void 1291074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 1292074fe897SAndy Adamson { 1293557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1294557ce264SAndy Adamson unsigned int base; 1295074fe897SAndy Adamson 1296557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 1297074fe897SAndy Adamson 1298557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 1299557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 1300bf864a31SAndy Adamson 1301bf864a31SAndy Adamson if (nfsd4_not_cached(resp)) { 1302557ce264SAndy Adamson slot->sl_datalen = 0; 1303bf864a31SAndy Adamson return; 1304bf864a31SAndy Adamson } 1305557ce264SAndy Adamson slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap; 1306557ce264SAndy Adamson base = (char *)resp->cstate.datap - 1307557ce264SAndy Adamson (char *)resp->xbuf->head[0].iov_base; 1308557ce264SAndy Adamson if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data, 1309557ce264SAndy Adamson slot->sl_datalen)) 1310557ce264SAndy Adamson WARN("%s: sessions DRC could not cache compound\n", __func__); 1311557ce264SAndy Adamson return; 1312074fe897SAndy Adamson } 1313074fe897SAndy Adamson 1314074fe897SAndy Adamson /* 1315abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 1316abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 1317abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 1318abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 1319abfabf8cSAndy Adamson * 1320074fe897SAndy Adamson */ 1321abfabf8cSAndy Adamson static __be32 1322abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 1323abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 1324074fe897SAndy Adamson { 1325abfabf8cSAndy Adamson struct nfsd4_op *op; 1326abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1327074fe897SAndy Adamson 1328abfabf8cSAndy Adamson dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__, 1329557ce264SAndy Adamson resp->opcnt, resp->cstate.slot->sl_cachethis); 1330abfabf8cSAndy Adamson 1331abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 1332abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 1333abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 1334abfabf8cSAndy Adamson 1335abfabf8cSAndy Adamson /* Return nfserr_retry_uncached_rep in next operation. */ 1336557ce264SAndy Adamson if (args->opcnt > 1 && slot->sl_cachethis == 0) { 1337abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 1338abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 1339abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 1340074fe897SAndy Adamson } 1341abfabf8cSAndy Adamson return op->status; 1342074fe897SAndy Adamson } 1343074fe897SAndy Adamson 1344074fe897SAndy Adamson /* 1345557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 1346557ce264SAndy Adamson * session values. 1347074fe897SAndy Adamson */ 1348074fe897SAndy Adamson __be32 1349bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 1350bf864a31SAndy Adamson struct nfsd4_sequence *seq) 1351074fe897SAndy Adamson { 1352557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 1353074fe897SAndy Adamson __be32 status; 1354074fe897SAndy Adamson 1355557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 1356074fe897SAndy Adamson 1357abfabf8cSAndy Adamson /* Either returns 0 or nfserr_retry_uncached */ 1358abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 1359abfabf8cSAndy Adamson if (status == nfserr_retry_uncached_rep) 1360abfabf8cSAndy Adamson return status; 1361074fe897SAndy Adamson 1362557ce264SAndy Adamson /* The sequence operation has been encoded, cstate->datap set. */ 1363557ce264SAndy Adamson memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen); 1364074fe897SAndy Adamson 1365557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 1366557ce264SAndy Adamson resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen); 1367557ce264SAndy Adamson status = slot->sl_status; 1368074fe897SAndy Adamson 1369074fe897SAndy Adamson return status; 1370074fe897SAndy Adamson } 1371074fe897SAndy Adamson 13720733d213SAndy Adamson /* 13730733d213SAndy Adamson * Set the exchange_id flags returned by the server. 13740733d213SAndy Adamson */ 13750733d213SAndy Adamson static void 13760733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 13770733d213SAndy Adamson { 13780733d213SAndy Adamson /* pNFS is not supported */ 13790733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 13800733d213SAndy Adamson 13810733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 13820733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 13830733d213SAndy Adamson 13840733d213SAndy Adamson /* set the wire flags to return to client. */ 13850733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 13860733d213SAndy Adamson } 13870733d213SAndy Adamson 1388b37ad28bSAl Viro __be32 1389069b6ad4SAndy Adamson nfsd4_exchange_id(struct svc_rqst *rqstp, 1390069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 1391069b6ad4SAndy Adamson struct nfsd4_exchange_id *exid) 1392069b6ad4SAndy Adamson { 13930733d213SAndy Adamson struct nfs4_client *unconf, *conf, *new; 13940733d213SAndy Adamson int status; 13950733d213SAndy Adamson unsigned int strhashval; 13960733d213SAndy Adamson char dname[HEXDIR_LEN]; 1397363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 13980733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 1399363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 14000733d213SAndy Adamson 1401363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 14020733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 1403363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 14040733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 1405363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 14060733d213SAndy Adamson 14070733d213SAndy Adamson if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) 14080733d213SAndy Adamson return nfserr_inval; 14090733d213SAndy Adamson 14100733d213SAndy Adamson /* Currently only support SP4_NONE */ 14110733d213SAndy Adamson switch (exid->spa_how) { 14120733d213SAndy Adamson case SP4_NONE: 14130733d213SAndy Adamson break; 14140733d213SAndy Adamson case SP4_SSV: 1415044bc1d4SJ. Bruce Fields return nfserr_serverfault; 14160733d213SAndy Adamson default: 14170733d213SAndy Adamson BUG(); /* checked by xdr code */ 14180733d213SAndy Adamson case SP4_MACH_CRED: 14190733d213SAndy Adamson return nfserr_serverfault; /* no excuse :-/ */ 14200733d213SAndy Adamson } 14210733d213SAndy Adamson 14220733d213SAndy Adamson status = nfs4_make_rec_clidname(dname, &exid->clname); 14230733d213SAndy Adamson 14240733d213SAndy Adamson if (status) 14250733d213SAndy Adamson goto error; 14260733d213SAndy Adamson 14270733d213SAndy Adamson strhashval = clientstr_hashval(dname); 14280733d213SAndy Adamson 14290733d213SAndy Adamson nfs4_lock_state(); 14300733d213SAndy Adamson status = nfs_ok; 14310733d213SAndy Adamson 1432e203d506SJ. Bruce Fields conf = find_confirmed_client_by_str(dname, strhashval); 14330733d213SAndy Adamson if (conf) { 1434e203d506SJ. Bruce Fields if (!clp_used_exchangeid(conf)) { 1435e203d506SJ. Bruce Fields status = nfserr_clid_inuse; /* XXX: ? */ 1436e203d506SJ. Bruce Fields goto out; 1437e203d506SJ. Bruce Fields } 14380733d213SAndy Adamson if (!same_verf(&verf, &conf->cl_verifier)) { 14390733d213SAndy Adamson /* 18.35.4 case 8 */ 14400733d213SAndy Adamson if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { 14410733d213SAndy Adamson status = nfserr_not_same; 14420733d213SAndy Adamson goto out; 14430733d213SAndy Adamson } 14440733d213SAndy Adamson /* Client reboot: destroy old state */ 14450733d213SAndy Adamson expire_client(conf); 14460733d213SAndy Adamson goto out_new; 14470733d213SAndy Adamson } 14480733d213SAndy Adamson if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 14490733d213SAndy Adamson /* 18.35.4 case 9 */ 14500733d213SAndy Adamson if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { 14510733d213SAndy Adamson status = nfserr_perm; 14520733d213SAndy Adamson goto out; 14530733d213SAndy Adamson } 14540733d213SAndy Adamson expire_client(conf); 14550733d213SAndy Adamson goto out_new; 14560733d213SAndy Adamson } 14570733d213SAndy Adamson /* 14580733d213SAndy Adamson * Set bit when the owner id and verifier map to an already 14590733d213SAndy Adamson * confirmed client id (18.35.3). 14600733d213SAndy Adamson */ 14610733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 14620733d213SAndy Adamson 14630733d213SAndy Adamson /* 14640733d213SAndy Adamson * Falling into 18.35.4 case 2, possible router replay. 14650733d213SAndy Adamson * Leave confirmed record intact and return same result. 14660733d213SAndy Adamson */ 14670733d213SAndy Adamson copy_verf(conf, &verf); 14680733d213SAndy Adamson new = conf; 14690733d213SAndy Adamson goto out_copy; 14706ddbbbfeSMike Sager } 14716ddbbbfeSMike Sager 14720733d213SAndy Adamson /* 18.35.4 case 7 */ 14730733d213SAndy Adamson if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { 14740733d213SAndy Adamson status = nfserr_noent; 14750733d213SAndy Adamson goto out; 14760733d213SAndy Adamson } 14770733d213SAndy Adamson 1478e203d506SJ. Bruce Fields unconf = find_unconfirmed_client_by_str(dname, strhashval); 14790733d213SAndy Adamson if (unconf) { 14800733d213SAndy Adamson /* 14810733d213SAndy Adamson * Possible retry or client restart. Per 18.35.4 case 4, 14820733d213SAndy Adamson * a new unconfirmed record should be generated regardless 14830733d213SAndy Adamson * of whether any properties have changed. 14840733d213SAndy Adamson */ 14850733d213SAndy Adamson expire_client(unconf); 14860733d213SAndy Adamson } 14870733d213SAndy Adamson 14880733d213SAndy Adamson out_new: 14890733d213SAndy Adamson /* Normal case */ 1490b09333c4SRicardo Labiaga new = create_client(exid->clname, dname, rqstp, &verf); 14910733d213SAndy Adamson if (new == NULL) { 14924731030dSJ. Bruce Fields status = nfserr_jukebox; 14930733d213SAndy Adamson goto out; 14940733d213SAndy Adamson } 14950733d213SAndy Adamson 14960733d213SAndy Adamson gen_clid(new); 14970733d213SAndy Adamson add_to_unconfirmed(new, strhashval); 14980733d213SAndy Adamson out_copy: 14990733d213SAndy Adamson exid->clientid.cl_boot = new->cl_clientid.cl_boot; 15000733d213SAndy Adamson exid->clientid.cl_id = new->cl_clientid.cl_id; 15010733d213SAndy Adamson 150238eb76a5SAndy Adamson exid->seqid = 1; 15030733d213SAndy Adamson nfsd4_set_ex_flags(new, exid); 15040733d213SAndy Adamson 15050733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 150649557cc7SAndy Adamson new->cl_cs_slot.sl_seqid, new->cl_exchange_flags); 15070733d213SAndy Adamson status = nfs_ok; 15080733d213SAndy Adamson 15090733d213SAndy Adamson out: 15100733d213SAndy Adamson nfs4_unlock_state(); 15110733d213SAndy Adamson error: 15120733d213SAndy Adamson dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); 15130733d213SAndy Adamson return status; 1514069b6ad4SAndy Adamson } 1515069b6ad4SAndy Adamson 1516b85d4c01SBenny Halevy static int 151788e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 1518b85d4c01SBenny Halevy { 151988e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 152088e588d5SAndy Adamson slot_seqid); 1521b85d4c01SBenny Halevy 1522b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 152388e588d5SAndy Adamson if (slot_inuse) { 152488e588d5SAndy Adamson if (seqid == slot_seqid) 1525b85d4c01SBenny Halevy return nfserr_jukebox; 1526b85d4c01SBenny Halevy else 1527b85d4c01SBenny Halevy return nfserr_seq_misordered; 1528b85d4c01SBenny Halevy } 1529b85d4c01SBenny Halevy /* Normal */ 153088e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 1531b85d4c01SBenny Halevy return nfs_ok; 1532b85d4c01SBenny Halevy /* Replay */ 153388e588d5SAndy Adamson if (seqid == slot_seqid) 1534b85d4c01SBenny Halevy return nfserr_replay_cache; 1535b85d4c01SBenny Halevy /* Wraparound */ 153688e588d5SAndy Adamson if (seqid == 1 && (slot_seqid + 1) == 0) 1537b85d4c01SBenny Halevy return nfs_ok; 1538b85d4c01SBenny Halevy /* Misordered replay or misordered new request */ 1539b85d4c01SBenny Halevy return nfserr_seq_misordered; 1540b85d4c01SBenny Halevy } 1541b85d4c01SBenny Halevy 154249557cc7SAndy Adamson /* 154349557cc7SAndy Adamson * Cache the create session result into the create session single DRC 154449557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 154549557cc7SAndy Adamson * Do this for solo or embedded create session operations. 154649557cc7SAndy Adamson */ 154749557cc7SAndy Adamson static void 154849557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 154949557cc7SAndy Adamson struct nfsd4_clid_slot *slot, int nfserr) 155049557cc7SAndy Adamson { 155149557cc7SAndy Adamson slot->sl_status = nfserr; 155249557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 155349557cc7SAndy Adamson } 155449557cc7SAndy Adamson 155549557cc7SAndy Adamson static __be32 155649557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 155749557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 155849557cc7SAndy Adamson { 155949557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 156049557cc7SAndy Adamson return slot->sl_status; 156149557cc7SAndy Adamson } 156249557cc7SAndy Adamson 15631b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 15641b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 15651b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 15661b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 15671b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 15681b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 15691b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 15701b74c25bSMi Jinlong 15711b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 15721b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 15731b74c25bSMi Jinlong 1 + /* status */ \ 15741b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 15751b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 15761b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 15771b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 15781b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 15791b74c25bSMi Jinlong 15801b74c25bSMi Jinlong static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) 15811b74c25bSMi Jinlong { 15821b74c25bSMi Jinlong return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ 15831b74c25bSMi Jinlong || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; 15841b74c25bSMi Jinlong } 15851b74c25bSMi Jinlong 1586069b6ad4SAndy Adamson __be32 1587069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 1588069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 1589069b6ad4SAndy Adamson struct nfsd4_create_session *cr_ses) 1590069b6ad4SAndy Adamson { 1591363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 1592ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 1593ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 159449557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 159586c3e16cSJ. Bruce Fields bool confirm_me = false; 1596ec6b5d7bSAndy Adamson int status = 0; 1597ec6b5d7bSAndy Adamson 1598a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 1599a62573dcSMi Jinlong return nfserr_inval; 1600a62573dcSMi Jinlong 1601ec6b5d7bSAndy Adamson nfs4_lock_state(); 1602ec6b5d7bSAndy Adamson unconf = find_unconfirmed_client(&cr_ses->clientid); 1603ec6b5d7bSAndy Adamson conf = find_confirmed_client(&cr_ses->clientid); 1604ec6b5d7bSAndy Adamson 1605ec6b5d7bSAndy Adamson if (conf) { 160649557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 160749557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 160838eb76a5SAndy Adamson if (status == nfserr_replay_cache) { 1609ec6b5d7bSAndy Adamson dprintk("Got a create_session replay! seqid= %d\n", 161049557cc7SAndy Adamson cs_slot->sl_seqid); 161138eb76a5SAndy Adamson /* Return the cached reply status */ 161249557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 161338eb76a5SAndy Adamson goto out; 161449557cc7SAndy Adamson } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { 1615ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 1616ec6b5d7bSAndy Adamson dprintk("Sequence misordered!\n"); 1617ec6b5d7bSAndy Adamson dprintk("Expected seqid= %d but got seqid= %d\n", 161849557cc7SAndy Adamson cs_slot->sl_seqid, cr_ses->seqid); 1619ec6b5d7bSAndy Adamson goto out; 1620ec6b5d7bSAndy Adamson } 1621ec6b5d7bSAndy Adamson } else if (unconf) { 1622ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 1623363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 1624ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 1625ec6b5d7bSAndy Adamson goto out; 1626ec6b5d7bSAndy Adamson } 1627ec6b5d7bSAndy Adamson 162849557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 162949557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 163038eb76a5SAndy Adamson if (status) { 163138eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 1632ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 1633cd5b8144SJ. Bruce Fields goto out; 1634ec6b5d7bSAndy Adamson } 1635ec6b5d7bSAndy Adamson 163686c3e16cSJ. Bruce Fields confirm_me = true; 1637ec6b5d7bSAndy Adamson conf = unconf; 1638ec6b5d7bSAndy Adamson } else { 1639ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 1640ec6b5d7bSAndy Adamson goto out; 1641ec6b5d7bSAndy Adamson } 1642ec6b5d7bSAndy Adamson 1643408b79bcSJ. Bruce Fields /* 16448323c3b2SJ. Bruce Fields * XXX: we should probably set this at creation time, and check 16458323c3b2SJ. Bruce Fields * for consistent minorversion use throughout: 16468323c3b2SJ. Bruce Fields */ 16478323c3b2SJ. Bruce Fields conf->cl_minorversion = 1; 16488323c3b2SJ. Bruce Fields /* 1649408b79bcSJ. Bruce Fields * We do not support RDMA or persistent sessions 1650408b79bcSJ. Bruce Fields */ 1651408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 1652408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 1653408b79bcSJ. Bruce Fields 16541b74c25bSMi Jinlong status = nfserr_toosmall; 16551b74c25bSMi Jinlong if (check_forechannel_attrs(cr_ses->fore_channel)) 16561b74c25bSMi Jinlong goto out; 16571b74c25bSMi Jinlong 1658ac7c46f2SJ. Bruce Fields status = nfserr_jukebox; 1659ac7c46f2SJ. Bruce Fields new = alloc_init_session(rqstp, conf, cr_ses); 1660ac7c46f2SJ. Bruce Fields if (!new) 1661ec6b5d7bSAndy Adamson goto out; 1662ac7c46f2SJ. Bruce Fields status = nfs_ok; 1663ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 1664ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 166512050657SMi Jinlong memcpy(&cr_ses->fore_channel, &new->se_fchannel, 166612050657SMi Jinlong sizeof(struct nfsd4_channel_attrs)); 166786c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 166849557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 1669ec6b5d7bSAndy Adamson 167049557cc7SAndy Adamson /* cache solo and embedded create sessions under the state lock */ 167149557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 167286c3e16cSJ. Bruce Fields if (confirm_me) 167386c3e16cSJ. Bruce Fields move_to_confirmed(conf); 1674ec6b5d7bSAndy Adamson out: 1675ec6b5d7bSAndy Adamson nfs4_unlock_state(); 1676ec6b5d7bSAndy Adamson dprintk("%s returns %d\n", __func__, ntohl(status)); 1677ec6b5d7bSAndy Adamson return status; 1678069b6ad4SAndy Adamson } 1679069b6ad4SAndy Adamson 168057716355SJ. Bruce Fields static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) 168157716355SJ. Bruce Fields { 168257716355SJ. Bruce Fields struct nfsd4_compoundres *resp = rqstp->rq_resp; 168357716355SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 168457716355SJ. Bruce Fields 168557716355SJ. Bruce Fields return argp->opcnt == resp->opcnt; 168657716355SJ. Bruce Fields } 168757716355SJ. Bruce Fields 16881d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 16891d1bc8f2SJ. Bruce Fields { 16901d1bc8f2SJ. Bruce Fields switch (*dir) { 16911d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 16921d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 16931d1bc8f2SJ. Bruce Fields return nfs_ok; 16941d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 16951d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 16961d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 16971d1bc8f2SJ. Bruce Fields return nfs_ok; 16981d1bc8f2SJ. Bruce Fields }; 16991d1bc8f2SJ. Bruce Fields return nfserr_inval; 17001d1bc8f2SJ. Bruce Fields } 17011d1bc8f2SJ. Bruce Fields 17021d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 17031d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 17041d1bc8f2SJ. Bruce Fields struct nfsd4_bind_conn_to_session *bcts) 17051d1bc8f2SJ. Bruce Fields { 17061d1bc8f2SJ. Bruce Fields __be32 status; 17071d1bc8f2SJ. Bruce Fields 17081d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 17091d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 17101d1bc8f2SJ. Bruce Fields spin_lock(&client_lock); 17111d1bc8f2SJ. Bruce Fields cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); 17121d1bc8f2SJ. Bruce Fields /* Sorta weird: we only need the refcnt'ing because new_conn acquires 17131d1bc8f2SJ. Bruce Fields * client_lock iself: */ 17141d1bc8f2SJ. Bruce Fields if (cstate->session) { 17151d1bc8f2SJ. Bruce Fields nfsd4_get_session(cstate->session); 17161d1bc8f2SJ. Bruce Fields atomic_inc(&cstate->session->se_client->cl_refcount); 17171d1bc8f2SJ. Bruce Fields } 17181d1bc8f2SJ. Bruce Fields spin_unlock(&client_lock); 17191d1bc8f2SJ. Bruce Fields if (!cstate->session) 17201d1bc8f2SJ. Bruce Fields return nfserr_badsession; 17211d1bc8f2SJ. Bruce Fields 17221d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 17231db2b9ddSBryan Schumaker if (!status) 17241d1bc8f2SJ. Bruce Fields nfsd4_new_conn(rqstp, cstate->session, bcts->dir); 17251db2b9ddSBryan Schumaker return status; 17261d1bc8f2SJ. Bruce Fields } 17271d1bc8f2SJ. Bruce Fields 17285d4cec2fSJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) 17295d4cec2fSJ. Bruce Fields { 17305d4cec2fSJ. Bruce Fields if (!session) 17315d4cec2fSJ. Bruce Fields return 0; 17325d4cec2fSJ. Bruce Fields return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); 17335d4cec2fSJ. Bruce Fields } 17345d4cec2fSJ. Bruce Fields 1735069b6ad4SAndy Adamson __be32 1736069b6ad4SAndy Adamson nfsd4_destroy_session(struct svc_rqst *r, 1737069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 1738069b6ad4SAndy Adamson struct nfsd4_destroy_session *sessionid) 1739069b6ad4SAndy Adamson { 1740e10e0cfcSBenny Halevy struct nfsd4_session *ses; 1741e10e0cfcSBenny Halevy u32 status = nfserr_badsession; 1742e10e0cfcSBenny Halevy 1743e10e0cfcSBenny Halevy /* Notes: 1744e10e0cfcSBenny Halevy * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid 1745e10e0cfcSBenny Halevy * - Should we return nfserr_back_chan_busy if waiting for 1746e10e0cfcSBenny Halevy * callbacks on to-be-destroyed session? 1747e10e0cfcSBenny Halevy * - Do we need to clear any callback info from previous session? 1748e10e0cfcSBenny Halevy */ 1749e10e0cfcSBenny Halevy 17505d4cec2fSJ. Bruce Fields if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { 175157716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 175257716355SJ. Bruce Fields return nfserr_not_only_op; 175357716355SJ. Bruce Fields } 1754e10e0cfcSBenny Halevy dump_sessionid(__func__, &sessionid->sessionid); 17559089f1b4SBenny Halevy spin_lock(&client_lock); 1756e10e0cfcSBenny Halevy ses = find_in_sessionid_hashtbl(&sessionid->sessionid); 1757e10e0cfcSBenny Halevy if (!ses) { 17589089f1b4SBenny Halevy spin_unlock(&client_lock); 1759e10e0cfcSBenny Halevy goto out; 1760e10e0cfcSBenny Halevy } 1761e10e0cfcSBenny Halevy 1762e10e0cfcSBenny Halevy unhash_session(ses); 17639089f1b4SBenny Halevy spin_unlock(&client_lock); 1764e10e0cfcSBenny Halevy 1765ab707e15SBenny Halevy nfs4_lock_state(); 176684f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1767ab707e15SBenny Halevy nfs4_unlock_state(); 176819cf5c02SJ. Bruce Fields 176919cf5c02SJ. Bruce Fields nfsd4_del_conns(ses); 177019cf5c02SJ. Bruce Fields 1771e10e0cfcSBenny Halevy nfsd4_put_session(ses); 1772e10e0cfcSBenny Halevy status = nfs_ok; 1773e10e0cfcSBenny Halevy out: 1774e10e0cfcSBenny Halevy dprintk("%s returns %d\n", __func__, ntohl(status)); 1775e10e0cfcSBenny Halevy return status; 1776069b6ad4SAndy Adamson } 1777069b6ad4SAndy Adamson 1778a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 1779328ead28SJ. Bruce Fields { 1780328ead28SJ. Bruce Fields struct nfsd4_conn *c; 1781328ead28SJ. Bruce Fields 1782328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 1783a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 1784328ead28SJ. Bruce Fields return c; 1785328ead28SJ. Bruce Fields } 1786328ead28SJ. Bruce Fields } 1787328ead28SJ. Bruce Fields return NULL; 1788328ead28SJ. Bruce Fields } 1789328ead28SJ. Bruce Fields 1790a663bdd8SJ. Bruce Fields static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 1791328ead28SJ. Bruce Fields { 1792328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1793a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 179421b75b01SJ. Bruce Fields int ret; 1795328ead28SJ. Bruce Fields 1796328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 1797a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 1798328ead28SJ. Bruce Fields if (c) { 1799328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1800328ead28SJ. Bruce Fields free_conn(new); 1801328ead28SJ. Bruce Fields return; 1802328ead28SJ. Bruce Fields } 1803328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 1804328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 180521b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 180621b75b01SJ. Bruce Fields if (ret) 180721b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 180821b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 1809328ead28SJ. Bruce Fields return; 1810328ead28SJ. Bruce Fields } 1811328ead28SJ. Bruce Fields 1812868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 1813868b89c3SMi Jinlong { 1814868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 1815868b89c3SMi Jinlong 1816868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 1817868b89c3SMi Jinlong } 1818868b89c3SMi Jinlong 1819ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 1820ae82a8d0SMi Jinlong struct nfsd4_session *session) 1821ae82a8d0SMi Jinlong { 1822ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 1823ae82a8d0SMi Jinlong 1824ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 1825ae82a8d0SMi Jinlong } 1826ae82a8d0SMi Jinlong 1827069b6ad4SAndy Adamson __be32 1828b85d4c01SBenny Halevy nfsd4_sequence(struct svc_rqst *rqstp, 1829069b6ad4SAndy Adamson struct nfsd4_compound_state *cstate, 1830069b6ad4SAndy Adamson struct nfsd4_sequence *seq) 1831069b6ad4SAndy Adamson { 1832f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 1833b85d4c01SBenny Halevy struct nfsd4_session *session; 1834b85d4c01SBenny Halevy struct nfsd4_slot *slot; 1835a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 1836b85d4c01SBenny Halevy int status; 1837b85d4c01SBenny Halevy 1838f9bb94c4SAndy Adamson if (resp->opcnt != 1) 1839f9bb94c4SAndy Adamson return nfserr_sequence_pos; 1840f9bb94c4SAndy Adamson 1841a663bdd8SJ. Bruce Fields /* 1842a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 1843a663bdd8SJ. Bruce Fields * below. 1844a663bdd8SJ. Bruce Fields */ 1845a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 1846a663bdd8SJ. Bruce Fields if (!conn) 1847a663bdd8SJ. Bruce Fields return nfserr_jukebox; 1848a663bdd8SJ. Bruce Fields 18499089f1b4SBenny Halevy spin_lock(&client_lock); 1850b85d4c01SBenny Halevy status = nfserr_badsession; 1851b85d4c01SBenny Halevy session = find_in_sessionid_hashtbl(&seq->sessionid); 1852b85d4c01SBenny Halevy if (!session) 1853b85d4c01SBenny Halevy goto out; 1854b85d4c01SBenny Halevy 1855868b89c3SMi Jinlong status = nfserr_too_many_ops; 1856868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 1857868b89c3SMi Jinlong goto out; 1858868b89c3SMi Jinlong 1859ae82a8d0SMi Jinlong status = nfserr_req_too_big; 1860ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 1861ae82a8d0SMi Jinlong goto out; 1862ae82a8d0SMi Jinlong 1863b85d4c01SBenny Halevy status = nfserr_badslot; 18646c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 1865b85d4c01SBenny Halevy goto out; 1866b85d4c01SBenny Halevy 1867557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 1868b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 1869b85d4c01SBenny Halevy 1870a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 1871a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 1872a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 1873a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 1874a8dfdaebSAndy Adamson 187588e588d5SAndy Adamson status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse); 1876b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 1877b85d4c01SBenny Halevy cstate->slot = slot; 1878b85d4c01SBenny Halevy cstate->session = session; 1879da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 1880557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 1881bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 1882da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 1883aaf84eb9SBenny Halevy goto out; 1884b85d4c01SBenny Halevy } 1885b85d4c01SBenny Halevy if (status) 1886b85d4c01SBenny Halevy goto out; 1887b85d4c01SBenny Halevy 1888a663bdd8SJ. Bruce Fields nfsd4_sequence_check_conn(conn, session); 1889a663bdd8SJ. Bruce Fields conn = NULL; 1890328ead28SJ. Bruce Fields 1891b85d4c01SBenny Halevy /* Success! bump slot seqid */ 1892b85d4c01SBenny Halevy slot->sl_inuse = true; 1893b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 1894557ce264SAndy Adamson slot->sl_cachethis = seq->cachethis; 1895b85d4c01SBenny Halevy 1896b85d4c01SBenny Halevy cstate->slot = slot; 1897b85d4c01SBenny Halevy cstate->session = session; 1898b85d4c01SBenny Halevy 1899b85d4c01SBenny Halevy out: 190026c0c75eSJ. Bruce Fields /* Hold a session reference until done processing the compound. */ 1901aaf84eb9SBenny Halevy if (cstate->session) { 19020d7bb719SJ. Bruce Fields struct nfs4_client *clp = session->se_client; 19030d7bb719SJ. Bruce Fields 190436acb66bSBenny Halevy nfsd4_get_session(cstate->session); 19050d7bb719SJ. Bruce Fields atomic_inc(&clp->cl_refcount); 19060d7bb719SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_DOWN) 19070d7bb719SJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN; 1908aaf84eb9SBenny Halevy } 1909a663bdd8SJ. Bruce Fields kfree(conn); 191036acb66bSBenny Halevy spin_unlock(&client_lock); 1911b85d4c01SBenny Halevy dprintk("%s: return %d\n", __func__, ntohl(status)); 1912b85d4c01SBenny Halevy return status; 1913069b6ad4SAndy Adamson } 1914069b6ad4SAndy Adamson 1915069b6ad4SAndy Adamson __be32 19164dc6ec00SJ. Bruce Fields nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) 19174dc6ec00SJ. Bruce Fields { 1918bcecf1ccSMi Jinlong int status = 0; 1919bcecf1ccSMi Jinlong 19204dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 19214dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 19224dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 19234dc6ec00SJ. Bruce Fields /* 19244dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 19254dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 19264dc6ec00SJ. Bruce Fields */ 19274dc6ec00SJ. Bruce Fields return nfs_ok; 19284dc6ec00SJ. Bruce Fields } 1929bcecf1ccSMi Jinlong 19304dc6ec00SJ. Bruce Fields nfs4_lock_state(); 1931bcecf1ccSMi Jinlong status = nfserr_complete_already; 1932bcecf1ccSMi Jinlong if (cstate->session->se_client->cl_firststate) 1933bcecf1ccSMi Jinlong goto out; 1934bcecf1ccSMi Jinlong 1935bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 1936bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 19374dc6ec00SJ. Bruce Fields /* 19384dc6ec00SJ. Bruce Fields * The following error isn't really legal. 19394dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 19404dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 19414dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 19424dc6ec00SJ. Bruce Fields * client. 19434dc6ec00SJ. Bruce Fields */ 1944bcecf1ccSMi Jinlong goto out; 1945bcecf1ccSMi Jinlong 1946bcecf1ccSMi Jinlong status = nfs_ok; 19474dc6ec00SJ. Bruce Fields nfsd4_create_clid_dir(cstate->session->se_client); 1948bcecf1ccSMi Jinlong out: 19494dc6ec00SJ. Bruce Fields nfs4_unlock_state(); 1950bcecf1ccSMi Jinlong return status; 19514dc6ec00SJ. Bruce Fields } 19524dc6ec00SJ. Bruce Fields 19534dc6ec00SJ. Bruce Fields __be32 1954b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 1955b591480bSJ.Bruce Fields struct nfsd4_setclientid *setclid) 19561da177e4SLinus Torvalds { 19571da177e4SLinus Torvalds struct xdr_netobj clname = { 19581da177e4SLinus Torvalds .len = setclid->se_namelen, 19591da177e4SLinus Torvalds .data = setclid->se_name, 19601da177e4SLinus Torvalds }; 19611da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 19621da177e4SLinus Torvalds unsigned int strhashval; 196328ce6054SNeilBrown struct nfs4_client *conf, *unconf, *new; 1964b37ad28bSAl Viro __be32 status; 1965a55370a3SNeilBrown char dname[HEXDIR_LEN]; 19661da177e4SLinus Torvalds 19671da177e4SLinus Torvalds if (!check_name(clname)) 196873aea4ecSNeil Brown return nfserr_inval; 19691da177e4SLinus Torvalds 1970a55370a3SNeilBrown status = nfs4_make_rec_clidname(dname, &clname); 1971a55370a3SNeilBrown if (status) 197273aea4ecSNeil Brown return status; 1973a55370a3SNeilBrown 19741da177e4SLinus Torvalds /* 19751da177e4SLinus Torvalds * XXX The Duplicate Request Cache (DRC) has been checked (??) 19761da177e4SLinus Torvalds * We get here on a DRC miss. 19771da177e4SLinus Torvalds */ 19781da177e4SLinus Torvalds 1979a55370a3SNeilBrown strhashval = clientstr_hashval(dname); 19801da177e4SLinus Torvalds 19811da177e4SLinus Torvalds nfs4_lock_state(); 1982e203d506SJ. Bruce Fields conf = find_confirmed_client_by_str(dname, strhashval); 198328ce6054SNeilBrown if (conf) { 1984a186e767SJ. Bruce Fields /* RFC 3530 14.2.33 CASE 0: */ 19851da177e4SLinus Torvalds status = nfserr_clid_inuse; 1986e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 1987e203d506SJ. Bruce Fields goto out; 1988026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 1989363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 1990363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 1991363168b4SJeff Layton sizeof(addr_str)); 1992026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 1993363168b4SJeff Layton "at %s\n", addr_str); 19941da177e4SLinus Torvalds goto out; 19951da177e4SLinus Torvalds } 19961da177e4SLinus Torvalds } 1997a186e767SJ. Bruce Fields /* 1998a186e767SJ. Bruce Fields * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION") 1999a186e767SJ. Bruce Fields * has a description of SETCLIENTID request processing consisting 2000a186e767SJ. Bruce Fields * of 5 bullet points, labeled as CASE0 - CASE4 below. 2001a186e767SJ. Bruce Fields */ 2002e203d506SJ. Bruce Fields unconf = find_unconfirmed_client_by_str(dname, strhashval); 20033e772463SJ. Bruce Fields status = nfserr_jukebox; 20041da177e4SLinus Torvalds if (!conf) { 20051da177e4SLinus Torvalds /* 2006a186e767SJ. Bruce Fields * RFC 3530 14.2.33 CASE 4: 2007a186e767SJ. Bruce Fields * placed first, because it is the normal case 20081da177e4SLinus Torvalds */ 20091da177e4SLinus Torvalds if (unconf) 20101da177e4SLinus Torvalds expire_client(unconf); 2011b09333c4SRicardo Labiaga new = create_client(clname, dname, rqstp, &clverifier); 2012a55370a3SNeilBrown if (new == NULL) 20131da177e4SLinus Torvalds goto out; 20141da177e4SLinus Torvalds gen_clid(new); 2015599e0a22SJ. Bruce Fields } else if (same_verf(&conf->cl_verifier, &clverifier)) { 20161da177e4SLinus Torvalds /* 2017a186e767SJ. Bruce Fields * RFC 3530 14.2.33 CASE 1: 2018a186e767SJ. Bruce Fields * probable callback update 20191da177e4SLinus Torvalds */ 202031f4a6c1SNeilBrown if (unconf) { 202131f4a6c1SNeilBrown /* Note this is removing unconfirmed {*x***}, 202231f4a6c1SNeilBrown * which is stronger than RFC recommended {vxc**}. 202331f4a6c1SNeilBrown * This has the advantage that there is at most 202431f4a6c1SNeilBrown * one {*x***} in either list at any time. 202531f4a6c1SNeilBrown */ 20261da177e4SLinus Torvalds expire_client(unconf); 20271da177e4SLinus Torvalds } 2028b09333c4SRicardo Labiaga new = create_client(clname, dname, rqstp, &clverifier); 2029a55370a3SNeilBrown if (new == NULL) 20301da177e4SLinus Torvalds goto out; 20311da177e4SLinus Torvalds copy_clid(new, conf); 20321da177e4SLinus Torvalds } else if (!unconf) { 20331da177e4SLinus Torvalds /* 2034a186e767SJ. Bruce Fields * RFC 3530 14.2.33 CASE 2: 2035a186e767SJ. Bruce Fields * probable client reboot; state will be removed if 2036a186e767SJ. Bruce Fields * confirmed. 20371da177e4SLinus Torvalds */ 2038b09333c4SRicardo Labiaga new = create_client(clname, dname, rqstp, &clverifier); 2039a55370a3SNeilBrown if (new == NULL) 20401da177e4SLinus Torvalds goto out; 20411da177e4SLinus Torvalds gen_clid(new); 204249ba8781SJ. Bruce Fields } else { 20431da177e4SLinus Torvalds /* 2044a186e767SJ. Bruce Fields * RFC 3530 14.2.33 CASE 3: 2045a186e767SJ. Bruce Fields * probable client reboot; state will be removed if 2046a186e767SJ. Bruce Fields * confirmed. 20471da177e4SLinus Torvalds */ 20481da177e4SLinus Torvalds expire_client(unconf); 2049b09333c4SRicardo Labiaga new = create_client(clname, dname, rqstp, &clverifier); 2050a55370a3SNeilBrown if (new == NULL) 20511da177e4SLinus Torvalds goto out; 20521da177e4SLinus Torvalds gen_clid(new); 20531da177e4SLinus Torvalds } 20548323c3b2SJ. Bruce Fields /* 20558323c3b2SJ. Bruce Fields * XXX: we should probably set this at creation time, and check 20568323c3b2SJ. Bruce Fields * for consistent minorversion use throughout: 20578323c3b2SJ. Bruce Fields */ 20588323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 20596f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 2060c175b83cSJ. Bruce Fields add_to_unconfirmed(new, strhashval); 20611da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 20621da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 20631da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 20641da177e4SLinus Torvalds status = nfs_ok; 20651da177e4SLinus Torvalds out: 20661da177e4SLinus Torvalds nfs4_unlock_state(); 20671da177e4SLinus Torvalds return status; 20681da177e4SLinus Torvalds } 20691da177e4SLinus Torvalds 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds /* 2072a186e767SJ. Bruce Fields * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has 2073a186e767SJ. Bruce Fields * a description of SETCLIENTID_CONFIRM request processing consisting of 4 2074a186e767SJ. Bruce Fields * bullets, labeled as CASE1 - CASE4 below. 20751da177e4SLinus Torvalds */ 2076b37ad28bSAl Viro __be32 2077b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 2078b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 2079b591480bSJ.Bruce Fields struct nfsd4_setclientid_confirm *setclientid_confirm) 20801da177e4SLinus Torvalds { 2081363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 208221ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 20831da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 20841da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 2085b37ad28bSAl Viro __be32 status; 20861da177e4SLinus Torvalds 20871da177e4SLinus Torvalds if (STALE_CLIENTID(clid)) 20881da177e4SLinus Torvalds return nfserr_stale_clientid; 20891da177e4SLinus Torvalds /* 20901da177e4SLinus Torvalds * XXX The Duplicate Request Cache (DRC) has been checked (??) 20911da177e4SLinus Torvalds * We get here on a DRC miss. 20921da177e4SLinus Torvalds */ 20931da177e4SLinus Torvalds 20941da177e4SLinus Torvalds nfs4_lock_state(); 209521ab45a4SNeilBrown 209621ab45a4SNeilBrown conf = find_confirmed_client(clid); 209721ab45a4SNeilBrown unconf = find_unconfirmed_client(clid); 209821ab45a4SNeilBrown 209922de4d83SNeilBrown status = nfserr_clid_inuse; 2100363168b4SJeff Layton if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) 21011da177e4SLinus Torvalds goto out; 2102363168b4SJeff Layton if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) 21031da177e4SLinus Torvalds goto out; 210421ab45a4SNeilBrown 2105a186e767SJ. Bruce Fields /* 2106a186e767SJ. Bruce Fields * section 14.2.34 of RFC 3530 has a description of 2107a186e767SJ. Bruce Fields * SETCLIENTID_CONFIRM request processing consisting 2108a186e767SJ. Bruce Fields * of 4 bullet points, labeled as CASE1 - CASE4 below. 2109a186e767SJ. Bruce Fields */ 2110366e0c1dSJ. Bruce Fields if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) { 2111a186e767SJ. Bruce Fields /* 2112a186e767SJ. Bruce Fields * RFC 3530 14.2.34 CASE 1: 2113a186e767SJ. Bruce Fields * callback update 21147c79f737SNeilBrown */ 2115599e0a22SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) 21161da177e4SLinus Torvalds status = nfserr_clid_inuse; 21171da177e4SLinus Torvalds else { 21185a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 21195a3c9d71SJ. Bruce Fields nfsd4_probe_callback(conf); 21201a69c179SNeilBrown expire_client(unconf); 21211da177e4SLinus Torvalds status = nfs_ok; 21221a69c179SNeilBrown 21231da177e4SLinus Torvalds } 2124f3aba4e5SJ. Bruce Fields } else if (conf && !unconf) { 2125a186e767SJ. Bruce Fields /* 2126a186e767SJ. Bruce Fields * RFC 3530 14.2.34 CASE 2: 2127a186e767SJ. Bruce Fields * probable retransmitted request; play it safe and 2128a186e767SJ. Bruce Fields * do nothing. 21297c79f737SNeilBrown */ 2130599e0a22SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) 21311da177e4SLinus Torvalds status = nfserr_clid_inuse; 213221ab45a4SNeilBrown else 21331da177e4SLinus Torvalds status = nfs_ok; 21347c79f737SNeilBrown } else if (!conf && unconf 2135599e0a22SJ. Bruce Fields && same_verf(&unconf->cl_confirm, &confirm)) { 2136a186e767SJ. Bruce Fields /* 2137a186e767SJ. Bruce Fields * RFC 3530 14.2.34 CASE 3: 2138a186e767SJ. Bruce Fields * Normal case; new or rebooted client: 21391da177e4SLinus Torvalds */ 2140599e0a22SJ. Bruce Fields if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { 21411da177e4SLinus Torvalds status = nfserr_clid_inuse; 21421da177e4SLinus Torvalds } else { 21431a69c179SNeilBrown unsigned int hash = 21441a69c179SNeilBrown clientstr_hashval(unconf->cl_recdir); 21451a69c179SNeilBrown conf = find_confirmed_client_by_str(unconf->cl_recdir, 2146e203d506SJ. Bruce Fields hash); 21471a69c179SNeilBrown if (conf) { 2148c7b9a459SNeilBrown nfsd4_remove_clid_dir(conf); 21491a69c179SNeilBrown expire_client(conf); 21501a69c179SNeilBrown } 21511da177e4SLinus Torvalds move_to_confirmed(unconf); 215221ab45a4SNeilBrown conf = unconf; 21535a3c9d71SJ. Bruce Fields nfsd4_probe_callback(conf); 21541a69c179SNeilBrown status = nfs_ok; 21551da177e4SLinus Torvalds } 2156599e0a22SJ. Bruce Fields } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) 2157599e0a22SJ. Bruce Fields && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, 21587c79f737SNeilBrown &confirm)))) { 2159a186e767SJ. Bruce Fields /* 2160a186e767SJ. Bruce Fields * RFC 3530 14.2.34 CASE 4: 2161a186e767SJ. Bruce Fields * Client probably hasn't noticed that we rebooted yet. 21621da177e4SLinus Torvalds */ 21631da177e4SLinus Torvalds status = nfserr_stale_clientid; 21647c79f737SNeilBrown } else { 21651da177e4SLinus Torvalds /* check that we have hit one of the cases...*/ 216622de4d83SNeilBrown status = nfserr_clid_inuse; 216708e8987cSNeilBrown } 21681da177e4SLinus Torvalds out: 21691da177e4SLinus Torvalds nfs4_unlock_state(); 21701da177e4SLinus Torvalds return status; 21711da177e4SLinus Torvalds } 21721da177e4SLinus Torvalds 21731da177e4SLinus Torvalds /* OPEN Share state helper functions */ 21741da177e4SLinus Torvalds static inline struct nfs4_file * 21751da177e4SLinus Torvalds alloc_init_file(struct inode *ino) 21761da177e4SLinus Torvalds { 21771da177e4SLinus Torvalds struct nfs4_file *fp; 21781da177e4SLinus Torvalds unsigned int hashval = file_hashval(ino); 21791da177e4SLinus Torvalds 2180e60d4398SNeilBrown fp = kmem_cache_alloc(file_slab, GFP_KERNEL); 2181e60d4398SNeilBrown if (fp) { 21828b671b80SJ. Bruce Fields atomic_set(&fp->fi_ref, 1); 21831da177e4SLinus Torvalds INIT_LIST_HEAD(&fp->fi_hash); 21848beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 21858beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 21861da177e4SLinus Torvalds fp->fi_inode = igrab(ino); 21871da177e4SLinus Torvalds fp->fi_id = current_fileid++; 218847f9940cSMeelap Shah fp->fi_had_conflict = false; 2189acfdf5c3SJ. Bruce Fields fp->fi_lease = NULL; 2190f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 2191f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 219247cee541SPavel Emelyanov spin_lock(&recall_lock); 219347cee541SPavel Emelyanov list_add(&fp->fi_hash, &file_hashtbl[hashval]); 219447cee541SPavel Emelyanov spin_unlock(&recall_lock); 21951da177e4SLinus Torvalds return fp; 21961da177e4SLinus Torvalds } 21971da177e4SLinus Torvalds return NULL; 21981da177e4SLinus Torvalds } 21991da177e4SLinus Torvalds 22001da177e4SLinus Torvalds static void 2201e18b890bSChristoph Lameter nfsd4_free_slab(struct kmem_cache **slab) 2202e60d4398SNeilBrown { 2203e60d4398SNeilBrown if (*slab == NULL) 2204e60d4398SNeilBrown return; 22051a1d92c1SAlexey Dobriyan kmem_cache_destroy(*slab); 2206e60d4398SNeilBrown *slab = NULL; 2207e60d4398SNeilBrown } 2208e60d4398SNeilBrown 2209e8ff2a84SJ. Bruce Fields void 2210e60d4398SNeilBrown nfsd4_free_slabs(void) 2211e60d4398SNeilBrown { 2212fe0750e5SJ. Bruce Fields nfsd4_free_slab(&openowner_slab); 2213fe0750e5SJ. Bruce Fields nfsd4_free_slab(&lockowner_slab); 2214e60d4398SNeilBrown nfsd4_free_slab(&file_slab); 22155ac049acSNeilBrown nfsd4_free_slab(&stateid_slab); 22165b2d21c1SNeilBrown nfsd4_free_slab(&deleg_slab); 2217e60d4398SNeilBrown } 22181da177e4SLinus Torvalds 22191da177e4SLinus Torvalds static int 22201da177e4SLinus Torvalds nfsd4_init_slabs(void) 22211da177e4SLinus Torvalds { 2222fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 2223fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 2224fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 2225fe0750e5SJ. Bruce Fields goto out_nomem; 2226fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 2227fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 2228fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 2229e60d4398SNeilBrown goto out_nomem; 2230e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 223120c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 2232e60d4398SNeilBrown if (file_slab == NULL) 2233e60d4398SNeilBrown goto out_nomem; 22345ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 223520c2df83SPaul Mundt sizeof(struct nfs4_stateid), 0, 0, NULL); 22365ac049acSNeilBrown if (stateid_slab == NULL) 22375ac049acSNeilBrown goto out_nomem; 22385b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 223920c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 22405b2d21c1SNeilBrown if (deleg_slab == NULL) 22415b2d21c1SNeilBrown goto out_nomem; 2242e60d4398SNeilBrown return 0; 2243e60d4398SNeilBrown out_nomem: 2244e60d4398SNeilBrown nfsd4_free_slabs(); 22451da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 22461da177e4SLinus Torvalds return -ENOMEM; 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds 2249fe0750e5SJ. Bruce Fields void nfs4_free_openowner(struct nfs4_openowner *oo) 22501da177e4SLinus Torvalds { 2251fe0750e5SJ. Bruce Fields kfree(oo->oo_owner.so_owner.data); 2252fe0750e5SJ. Bruce Fields kmem_cache_free(openowner_slab, oo); 2253fe0750e5SJ. Bruce Fields } 2254fe0750e5SJ. Bruce Fields 2255fe0750e5SJ. Bruce Fields void nfs4_free_lockowner(struct nfs4_lockowner *lo) 2256fe0750e5SJ. Bruce Fields { 2257fe0750e5SJ. Bruce Fields kfree(lo->lo_owner.so_owner.data); 2258fe0750e5SJ. Bruce Fields kmem_cache_free(lockowner_slab, lo); 22591da177e4SLinus Torvalds } 22601da177e4SLinus Torvalds 2261ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 2262ff194bd9SJ. Bruce Fields { 2263ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 2264ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 2265ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 2266ff194bd9SJ. Bruce Fields } 2267ff194bd9SJ. Bruce Fields 2268fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 22691da177e4SLinus Torvalds { 22701da177e4SLinus Torvalds struct nfs4_stateowner *sop; 22711da177e4SLinus Torvalds 2272fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 2273ff194bd9SJ. Bruce Fields if (!sop) 2274ff194bd9SJ. Bruce Fields return NULL; 2275ff194bd9SJ. Bruce Fields 2276ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 2277ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 2278fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 2279ff194bd9SJ. Bruce Fields return NULL; 2280ff194bd9SJ. Bruce Fields } 22811da177e4SLinus Torvalds sop->so_owner.len = owner->len; 2282ff194bd9SJ. Bruce Fields 2283ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 2284ff194bd9SJ. Bruce Fields sop->so_id = current_ownerid++; 2285ff194bd9SJ. Bruce Fields sop->so_client = clp; 2286ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 22871da177e4SLinus Torvalds return sop; 22881da177e4SLinus Torvalds } 2289ff194bd9SJ. Bruce Fields 2290fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 2291ff194bd9SJ. Bruce Fields { 2292ff194bd9SJ. Bruce Fields unsigned int idhashval; 2293ff194bd9SJ. Bruce Fields 2294fe0750e5SJ. Bruce Fields idhashval = open_ownerid_hashval(oo->oo_owner.so_id); 2295fe0750e5SJ. Bruce Fields list_add(&oo->oo_owner.so_idhash, &open_ownerid_hashtbl[idhashval]); 2296fe0750e5SJ. Bruce Fields list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]); 2297fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 22981da177e4SLinus Torvalds } 22991da177e4SLinus Torvalds 2300fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 23011da177e4SLinus Torvalds alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { 2302fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 23031da177e4SLinus Torvalds 2304fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 2305fe0750e5SJ. Bruce Fields if (!oo) 23061da177e4SLinus Torvalds return NULL; 2307fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 2308fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 2309fe0750e5SJ. Bruce Fields oo->oo_confirmed = 0; 2310fe0750e5SJ. Bruce Fields oo->oo_time = 0; 2311fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 2312fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 2313fe0750e5SJ. Bruce Fields return oo; 23141da177e4SLinus Torvalds } 23151da177e4SLinus Torvalds 23161da177e4SLinus Torvalds static inline void 2317881ea2b1SJ. Bruce Fields init_open_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { 2318fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 2319fe0750e5SJ. Bruce Fields unsigned int hashval = stateid_hashval(oo->oo_owner.so_id, fp->fi_id); 23201da177e4SLinus Torvalds 23211da177e4SLinus Torvalds INIT_LIST_HEAD(&stp->st_hash); 2322ea1da636SNeilBrown INIT_LIST_HEAD(&stp->st_perstateowner); 2323ea1da636SNeilBrown INIT_LIST_HEAD(&stp->st_lockowners); 23241da177e4SLinus Torvalds INIT_LIST_HEAD(&stp->st_perfile); 23251da177e4SLinus Torvalds list_add(&stp->st_hash, &stateid_hashtbl[hashval]); 2326fe0750e5SJ. Bruce Fields list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 23278beefa24SNeilBrown list_add(&stp->st_perfile, &fp->fi_stateids); 23285fa0bbb4SJ. Bruce Fields stp->st_type = NFS4_OPEN_STID; 2329fe0750e5SJ. Bruce Fields stp->st_stateowner = &oo->oo_owner; 233013cd2184SNeilBrown get_nfs4_file(fp); 23311da177e4SLinus Torvalds stp->st_file = fp; 2332e4e83ea4SJ. Bruce Fields stp->st_stateid.si_boot = boot_time; 2333fe0750e5SJ. Bruce Fields stp->st_stateid.si_stateownerid = oo->oo_owner.so_id; 23341da177e4SLinus Torvalds stp->st_stateid.si_fileid = fp->fi_id; 233573997dc4SJ. Bruce Fields /* note will be incremented before first return to client: */ 23361da177e4SLinus Torvalds stp->st_stateid.si_generation = 0; 23371da177e4SLinus Torvalds stp->st_access_bmap = 0; 23381da177e4SLinus Torvalds stp->st_deny_bmap = 0; 233984459a11SAndy Adamson __set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK, 234084459a11SAndy Adamson &stp->st_access_bmap); 23411da177e4SLinus Torvalds __set_bit(open->op_share_deny, &stp->st_deny_bmap); 23424c4cd222SNeilBrown stp->st_openstp = NULL; 23431da177e4SLinus Torvalds } 23441da177e4SLinus Torvalds 23451da177e4SLinus Torvalds static void 2346fe0750e5SJ. Bruce Fields move_to_close_lru(struct nfs4_openowner *oo) 23471da177e4SLinus Torvalds { 2348fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 23491da177e4SLinus Torvalds 2350fe0750e5SJ. Bruce Fields list_move_tail(&oo->oo_close_lru, &close_lru); 2351fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 23521da177e4SLinus Torvalds } 23531da177e4SLinus Torvalds 23541da177e4SLinus Torvalds static int 2355599e0a22SJ. Bruce Fields same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, 2356599e0a22SJ. Bruce Fields clientid_t *clid) 2357599e0a22SJ. Bruce Fields { 2358599e0a22SJ. Bruce Fields return (sop->so_owner.len == owner->len) && 2359599e0a22SJ. Bruce Fields 0 == memcmp(sop->so_owner.data, owner->data, owner->len) && 2360599e0a22SJ. Bruce Fields (sop->so_client->cl_clientid.cl_id == clid->cl_id); 23611da177e4SLinus Torvalds } 23621da177e4SLinus Torvalds 2363fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 23641da177e4SLinus Torvalds find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) 23651da177e4SLinus Torvalds { 23661da177e4SLinus Torvalds struct nfs4_stateowner *so = NULL; 23671da177e4SLinus Torvalds 2368506f275fSJ. Bruce Fields list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) { 2369599e0a22SJ. Bruce Fields if (same_owner_str(so, &open->op_owner, &open->op_clientid)) 2370fe0750e5SJ. Bruce Fields return container_of(so, struct nfs4_openowner, oo_owner); 23711da177e4SLinus Torvalds } 23721da177e4SLinus Torvalds return NULL; 23731da177e4SLinus Torvalds } 23741da177e4SLinus Torvalds 23751da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 23761da177e4SLinus Torvalds static struct nfs4_file * 23771da177e4SLinus Torvalds find_file(struct inode *ino) 23781da177e4SLinus Torvalds { 23791da177e4SLinus Torvalds unsigned int hashval = file_hashval(ino); 23801da177e4SLinus Torvalds struct nfs4_file *fp; 23811da177e4SLinus Torvalds 23828b671b80SJ. Bruce Fields spin_lock(&recall_lock); 23831da177e4SLinus Torvalds list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { 238413cd2184SNeilBrown if (fp->fi_inode == ino) { 238513cd2184SNeilBrown get_nfs4_file(fp); 23868b671b80SJ. Bruce Fields spin_unlock(&recall_lock); 23871da177e4SLinus Torvalds return fp; 23881da177e4SLinus Torvalds } 238913cd2184SNeilBrown } 23908b671b80SJ. Bruce Fields spin_unlock(&recall_lock); 23911da177e4SLinus Torvalds return NULL; 23921da177e4SLinus Torvalds } 23931da177e4SLinus Torvalds 2394d87a8adeSAndy Adamson static inline int access_valid(u32 x, u32 minorversion) 2395ba5a6a19SJ. Bruce Fields { 2396d87a8adeSAndy Adamson if ((x & NFS4_SHARE_ACCESS_MASK) < NFS4_SHARE_ACCESS_READ) 23978838dc43SJ. Bruce Fields return 0; 2398d87a8adeSAndy Adamson if ((x & NFS4_SHARE_ACCESS_MASK) > NFS4_SHARE_ACCESS_BOTH) 2399d87a8adeSAndy Adamson return 0; 2400d87a8adeSAndy Adamson x &= ~NFS4_SHARE_ACCESS_MASK; 2401d87a8adeSAndy Adamson if (minorversion && x) { 2402d87a8adeSAndy Adamson if ((x & NFS4_SHARE_WANT_MASK) > NFS4_SHARE_WANT_CANCEL) 2403d87a8adeSAndy Adamson return 0; 2404d87a8adeSAndy Adamson if ((x & NFS4_SHARE_WHEN_MASK) > NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED) 2405d87a8adeSAndy Adamson return 0; 2406d87a8adeSAndy Adamson x &= ~(NFS4_SHARE_WANT_MASK | NFS4_SHARE_WHEN_MASK); 2407d87a8adeSAndy Adamson } 2408d87a8adeSAndy Adamson if (x) 24098838dc43SJ. Bruce Fields return 0; 24108838dc43SJ. Bruce Fields return 1; 2411ba5a6a19SJ. Bruce Fields } 2412ba5a6a19SJ. Bruce Fields 24138838dc43SJ. Bruce Fields static inline int deny_valid(u32 x) 2414ba5a6a19SJ. Bruce Fields { 24158838dc43SJ. Bruce Fields /* Note: unlike access bits, deny bits may be zero. */ 24168838dc43SJ. Bruce Fields return x <= NFS4_SHARE_DENY_BOTH; 2417ba5a6a19SJ. Bruce Fields } 24181da177e4SLinus Torvalds 24194f83aa30SJ. Bruce Fields /* 24201da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 24211da177e4SLinus Torvalds * WRITE with all zero or all one stateid 24221da177e4SLinus Torvalds */ 2423b37ad28bSAl Viro static __be32 24241da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 24251da177e4SLinus Torvalds { 24261da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 24271da177e4SLinus Torvalds struct nfs4_file *fp; 24281da177e4SLinus Torvalds struct nfs4_stateid *stp; 2429b37ad28bSAl Viro __be32 ret; 24301da177e4SLinus Torvalds 24311da177e4SLinus Torvalds dprintk("NFSD: nfs4_share_conflict\n"); 24321da177e4SLinus Torvalds 24331da177e4SLinus Torvalds fp = find_file(ino); 243413cd2184SNeilBrown if (!fp) 243513cd2184SNeilBrown return nfs_ok; 2436b700949bSNeilBrown ret = nfserr_locked; 24371da177e4SLinus Torvalds /* Search for conflicting share reservations */ 24388beefa24SNeilBrown list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { 24391da177e4SLinus Torvalds if (test_bit(deny_type, &stp->st_deny_bmap) || 24401da177e4SLinus Torvalds test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) 244113cd2184SNeilBrown goto out; 24421da177e4SLinus Torvalds } 244313cd2184SNeilBrown ret = nfs_ok; 244413cd2184SNeilBrown out: 244513cd2184SNeilBrown put_nfs4_file(fp); 244613cd2184SNeilBrown return ret; 24471da177e4SLinus Torvalds } 24481da177e4SLinus Torvalds 24496b57d9c8SJ. Bruce Fields static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 24501da177e4SLinus Torvalds { 24511da177e4SLinus Torvalds /* We're assuming the state code never drops its reference 24521da177e4SLinus Torvalds * without first removing the lease. Since we're in this lease 24531da177e4SLinus Torvalds * callback (and since the lease code is serialized by the kernel 24541da177e4SLinus Torvalds * lock) we know the server hasn't removed the lease yet, we know 24551da177e4SLinus Torvalds * it's safe to take a reference: */ 24561da177e4SLinus Torvalds atomic_inc(&dp->dl_count); 24571da177e4SLinus Torvalds 24581da177e4SLinus Torvalds list_add_tail(&dp->dl_recall_lru, &del_recall_lru); 24591da177e4SLinus Torvalds 2460460781b5SArnd Bergmann /* only place dl_time is set. protected by lock_flocks*/ 24611da177e4SLinus Torvalds dp->dl_time = get_seconds(); 24621da177e4SLinus Torvalds 24636b57d9c8SJ. Bruce Fields nfsd4_cb_recall(dp); 24646b57d9c8SJ. Bruce Fields } 24656b57d9c8SJ. Bruce Fields 2466acfdf5c3SJ. Bruce Fields /* Called from break_lease() with lock_flocks() held. */ 24676b57d9c8SJ. Bruce Fields static void nfsd_break_deleg_cb(struct file_lock *fl) 24686b57d9c8SJ. Bruce Fields { 2469acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 2470acfdf5c3SJ. Bruce Fields struct nfs4_delegation *dp; 24716b57d9c8SJ. Bruce Fields 2472acfdf5c3SJ. Bruce Fields BUG_ON(!fp); 2473acfdf5c3SJ. Bruce Fields /* We assume break_lease is only called once per lease: */ 2474acfdf5c3SJ. Bruce Fields BUG_ON(fp->fi_had_conflict); 24750272e1fdSJ. Bruce Fields /* 24760272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 2477acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 24786b57d9c8SJ. Bruce Fields * in time: 24790272e1fdSJ. Bruce Fields */ 24800272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 24811da177e4SLinus Torvalds 24825d926e8cSJ. Bruce Fields spin_lock(&recall_lock); 2483acfdf5c3SJ. Bruce Fields fp->fi_had_conflict = true; 2484acfdf5c3SJ. Bruce Fields list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 24855d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 24865d926e8cSJ. Bruce Fields spin_unlock(&recall_lock); 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds static 24901da177e4SLinus Torvalds int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) 24911da177e4SLinus Torvalds { 24921da177e4SLinus Torvalds if (arg & F_UNLCK) 24931da177e4SLinus Torvalds return lease_modify(onlist, arg); 24941da177e4SLinus Torvalds else 24951da177e4SLinus Torvalds return -EAGAIN; 24961da177e4SLinus Torvalds } 24971da177e4SLinus Torvalds 24987b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 24998fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 25008fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 25011da177e4SLinus Torvalds }; 25021da177e4SLinus Torvalds 25037a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 25047a8711c9SJ. Bruce Fields { 25057a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 25067a8711c9SJ. Bruce Fields return nfs_ok; 25077a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 25087a8711c9SJ. Bruce Fields return nfserr_replay_me; 25097a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 25107a8711c9SJ. Bruce Fields return nfs_ok; 25117a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 25127a8711c9SJ. Bruce Fields } 25131da177e4SLinus Torvalds 2514b37ad28bSAl Viro __be32 25156668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 25166668958fSAndy Adamson struct nfsd4_open *open) 25171da177e4SLinus Torvalds { 25181da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 25191da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 25201da177e4SLinus Torvalds unsigned int strhashval; 2521fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 25227a8711c9SJ. Bruce Fields __be32 status; 25231da177e4SLinus Torvalds 25241da177e4SLinus Torvalds if (!check_name(open->op_owner)) 25250f442aa2SJ. Bruce Fields return nfserr_inval; 25261da177e4SLinus Torvalds 25271da177e4SLinus Torvalds if (STALE_CLIENTID(&open->op_clientid)) 25281da177e4SLinus Torvalds return nfserr_stale_clientid; 25291da177e4SLinus Torvalds 2530506f275fSJ. Bruce Fields strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner); 2531fe0750e5SJ. Bruce Fields oo = find_openstateowner_str(strhashval, open); 2532fe0750e5SJ. Bruce Fields open->op_openowner = oo; 2533fe0750e5SJ. Bruce Fields if (!oo) { 25340f442aa2SJ. Bruce Fields /* Make sure the client's lease hasn't expired. */ 25350f442aa2SJ. Bruce Fields clp = find_confirmed_client(clientid); 25360f442aa2SJ. Bruce Fields if (clp == NULL) 25370f442aa2SJ. Bruce Fields return nfserr_expired; 25380f442aa2SJ. Bruce Fields goto renew; 25390f442aa2SJ. Bruce Fields } 2540fe0750e5SJ. Bruce Fields if (!oo->oo_confirmed) { 25410f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 2542fe0750e5SJ. Bruce Fields clp = oo->oo_owner.so_client; 2543fe0750e5SJ. Bruce Fields release_openowner(oo); 2544fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 2545ae8b6253SJ. Bruce Fields goto renew; 25460f442aa2SJ. Bruce Fields } 2547fe0750e5SJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 25487a8711c9SJ. Bruce Fields if (status) 25497a8711c9SJ. Bruce Fields return status; 25500f442aa2SJ. Bruce Fields renew: 2551fe0750e5SJ. Bruce Fields if (open->op_openowner == NULL) { 2552fe0750e5SJ. Bruce Fields oo = alloc_init_open_stateowner(strhashval, clp, open); 2553fe0750e5SJ. Bruce Fields if (oo == NULL) 25543e772463SJ. Bruce Fields return nfserr_jukebox; 2555fe0750e5SJ. Bruce Fields open->op_openowner = oo; 25560f442aa2SJ. Bruce Fields } 2557fe0750e5SJ. Bruce Fields list_del_init(&oo->oo_close_lru); 2558fe0750e5SJ. Bruce Fields renew_client(oo->oo_owner.so_client); 25590f442aa2SJ. Bruce Fields return nfs_ok; 25601da177e4SLinus Torvalds } 25611da177e4SLinus Torvalds 2562b37ad28bSAl Viro static inline __be32 25634a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 25644a6e43e6SNeilBrown { 25654a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 25664a6e43e6SNeilBrown return nfserr_openmode; 25674a6e43e6SNeilBrown else 25684a6e43e6SNeilBrown return nfs_ok; 25694a6e43e6SNeilBrown } 25704a6e43e6SNeilBrown 257152f4fb43SNeilBrown static struct nfs4_delegation * 257252f4fb43SNeilBrown find_delegation_file(struct nfs4_file *fp, stateid_t *stid) 257352f4fb43SNeilBrown { 257432b007b4SJ. Bruce Fields struct nfs4_delegation *dp; 257552f4fb43SNeilBrown 2576acfdf5c3SJ. Bruce Fields spin_lock(&recall_lock); 257732b007b4SJ. Bruce Fields list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 257832b007b4SJ. Bruce Fields if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) { 2579acfdf5c3SJ. Bruce Fields spin_unlock(&recall_lock); 2580acfdf5c3SJ. Bruce Fields return dp; 258152f4fb43SNeilBrown } 258232b007b4SJ. Bruce Fields spin_unlock(&recall_lock); 258332b007b4SJ. Bruce Fields return NULL; 258432b007b4SJ. Bruce Fields } 258552f4fb43SNeilBrown 2586c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 258724a0111eSJ. Bruce Fields { 258824a0111eSJ. Bruce Fields share_access &= ~NFS4_SHARE_WANT_MASK; 258924a0111eSJ. Bruce Fields 259024a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 259124a0111eSJ. Bruce Fields } 259224a0111eSJ. Bruce Fields 2593b37ad28bSAl Viro static __be32 2594567d9829SNeilBrown nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, 2595567d9829SNeilBrown struct nfs4_delegation **dp) 2596567d9829SNeilBrown { 2597567d9829SNeilBrown int flags; 2598b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 2599567d9829SNeilBrown 2600567d9829SNeilBrown *dp = find_delegation_file(fp, &open->op_delegate_stateid); 2601567d9829SNeilBrown if (*dp == NULL) 2602c44c5eebSNeilBrown goto out; 260324a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 2604567d9829SNeilBrown status = nfs4_check_delegmode(*dp, flags); 2605567d9829SNeilBrown if (status) 2606567d9829SNeilBrown *dp = NULL; 2607c44c5eebSNeilBrown out: 2608c44c5eebSNeilBrown if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR) 2609c44c5eebSNeilBrown return nfs_ok; 2610c44c5eebSNeilBrown if (status) 2611c44c5eebSNeilBrown return status; 2612fe0750e5SJ. Bruce Fields open->op_openowner->oo_confirmed = 1; 2613c44c5eebSNeilBrown return nfs_ok; 2614567d9829SNeilBrown } 2615567d9829SNeilBrown 2616b37ad28bSAl Viro static __be32 26171da177e4SLinus Torvalds nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) 26181da177e4SLinus Torvalds { 26191da177e4SLinus Torvalds struct nfs4_stateid *local; 2620fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = open->op_openowner; 26211da177e4SLinus Torvalds 26228beefa24SNeilBrown list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 26231da177e4SLinus Torvalds /* ignore lock owners */ 26241da177e4SLinus Torvalds if (local->st_stateowner->so_is_open_owner == 0) 26251da177e4SLinus Torvalds continue; 26261da177e4SLinus Torvalds /* remember if we have seen this open owner */ 2627fe0750e5SJ. Bruce Fields if (local->st_stateowner == &oo->oo_owner) 26281da177e4SLinus Torvalds *stpp = local; 26291da177e4SLinus Torvalds /* check for conflicting share reservations */ 26301da177e4SLinus Torvalds if (!test_share(local, open)) 263177eaae8dSJ. Bruce Fields return nfserr_share_denied; 26321da177e4SLinus Torvalds } 263377eaae8dSJ. Bruce Fields return nfs_ok; 26341da177e4SLinus Torvalds } 26351da177e4SLinus Torvalds 26365ac049acSNeilBrown static inline struct nfs4_stateid * 26375ac049acSNeilBrown nfs4_alloc_stateid(void) 26385ac049acSNeilBrown { 26395ac049acSNeilBrown return kmem_cache_alloc(stateid_slab, GFP_KERNEL); 26405ac049acSNeilBrown } 26415ac049acSNeilBrown 264221fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 264321fb4016SJ. Bruce Fields { 264421fb4016SJ. Bruce Fields int flags = 0; 264521fb4016SJ. Bruce Fields 264621fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 264721fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 264821fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 264921fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 265021fb4016SJ. Bruce Fields return flags; 265121fb4016SJ. Bruce Fields } 265221fb4016SJ. Bruce Fields 26530c12eaffSCasey Bodley static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 26540c12eaffSCasey Bodley struct svc_fh *cur_fh, struct nfsd4_open *open) 2655f9d7562fSJ. Bruce Fields { 2656f9d7562fSJ. Bruce Fields __be32 status; 26570c12eaffSCasey Bodley int oflag = nfs4_access_to_omode(open->op_share_access); 26580c12eaffSCasey Bodley int access = nfs4_access_to_access(open->op_share_access); 26590c12eaffSCasey Bodley 26600c12eaffSCasey Bodley /* CLAIM_DELEGATE_CUR is used in response to a broken lease; 26610c12eaffSCasey Bodley * allowing it to break the lease and return EAGAIN leaves the 26620c12eaffSCasey Bodley * client unable to make progress in returning the delegation */ 26630c12eaffSCasey Bodley if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) 26640c12eaffSCasey Bodley access |= NFSD_MAY_NOT_BREAK_LEASE; 2665f9d7562fSJ. Bruce Fields 2666f9d7562fSJ. Bruce Fields if (!fp->fi_fds[oflag]) { 2667f9d7562fSJ. Bruce Fields status = nfsd_open(rqstp, cur_fh, S_IFREG, access, 2668f9d7562fSJ. Bruce Fields &fp->fi_fds[oflag]); 2669f9d7562fSJ. Bruce Fields if (status) 2670f9d7562fSJ. Bruce Fields return status; 2671f9d7562fSJ. Bruce Fields } 2672f9d7562fSJ. Bruce Fields nfs4_file_get_access(fp, oflag); 2673f9d7562fSJ. Bruce Fields 2674f9d7562fSJ. Bruce Fields return nfs_ok; 2675f9d7562fSJ. Bruce Fields } 2676f9d7562fSJ. Bruce Fields 2677b37ad28bSAl Viro static __be32 26781da177e4SLinus Torvalds nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, 2679f9d7562fSJ. Bruce Fields struct nfs4_file *fp, struct svc_fh *cur_fh, 2680f9d7562fSJ. Bruce Fields struct nfsd4_open *open) 26811da177e4SLinus Torvalds { 26821da177e4SLinus Torvalds struct nfs4_stateid *stp; 2683f9d7562fSJ. Bruce Fields __be32 status; 26841da177e4SLinus Torvalds 26855ac049acSNeilBrown stp = nfs4_alloc_stateid(); 26861da177e4SLinus Torvalds if (stp == NULL) 26873e772463SJ. Bruce Fields return nfserr_jukebox; 26881da177e4SLinus Torvalds 26890c12eaffSCasey Bodley status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); 26901da177e4SLinus Torvalds if (status) { 26915ac049acSNeilBrown kmem_cache_free(stateid_slab, stp); 26921da177e4SLinus Torvalds return status; 26931da177e4SLinus Torvalds } 26941da177e4SLinus Torvalds *stpp = stp; 26951da177e4SLinus Torvalds return 0; 26961da177e4SLinus Torvalds } 26971da177e4SLinus Torvalds 2698b37ad28bSAl Viro static inline __be32 26991da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 27001da177e4SLinus Torvalds struct nfsd4_open *open) 27011da177e4SLinus Torvalds { 27021da177e4SLinus Torvalds struct iattr iattr = { 27031da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 27041da177e4SLinus Torvalds .ia_size = 0, 27051da177e4SLinus Torvalds }; 27061da177e4SLinus Torvalds if (!open->op_truncate) 27071da177e4SLinus Torvalds return 0; 27081da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 27099246585aSAl Viro return nfserr_inval; 27101da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 27111da177e4SLinus Torvalds } 27121da177e4SLinus Torvalds 2713b37ad28bSAl Viro static __be32 2714f9d7562fSJ. Bruce Fields nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) 27151da177e4SLinus Torvalds { 27167d947842SJ. Bruce Fields u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; 27177d947842SJ. Bruce Fields bool new_access; 2718b37ad28bSAl Viro __be32 status; 27191da177e4SLinus Torvalds 27207d947842SJ. Bruce Fields new_access = !test_bit(op_share_access, &stp->st_access_bmap); 2721f9d7562fSJ. Bruce Fields if (new_access) { 27220c12eaffSCasey Bodley status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); 2723f9d7562fSJ. Bruce Fields if (status) 2724f9d7562fSJ. Bruce Fields return status; 27256c26d08fSJ. Bruce Fields } 27261da177e4SLinus Torvalds status = nfsd4_truncate(rqstp, cur_fh, open); 27271da177e4SLinus Torvalds if (status) { 2728f9d7562fSJ. Bruce Fields if (new_access) { 2729f197c271SJ. Bruce Fields int oflag = nfs4_access_to_omode(op_share_access); 2730f9d7562fSJ. Bruce Fields nfs4_file_put_access(fp, oflag); 2731f9d7562fSJ. Bruce Fields } 27321da177e4SLinus Torvalds return status; 27331da177e4SLinus Torvalds } 27341da177e4SLinus Torvalds /* remember the open */ 273524a0111eSJ. Bruce Fields __set_bit(op_share_access, &stp->st_access_bmap); 2736b55e0ba1SJ. Bruce Fields __set_bit(open->op_share_deny, &stp->st_deny_bmap); 27371da177e4SLinus Torvalds 27381da177e4SLinus Torvalds return nfs_ok; 27391da177e4SLinus Torvalds } 27401da177e4SLinus Torvalds 27411da177e4SLinus Torvalds 27421da177e4SLinus Torvalds static void 274337515177SNeilBrown nfs4_set_claim_prev(struct nfsd4_open *open) 27441da177e4SLinus Torvalds { 2745fe0750e5SJ. Bruce Fields open->op_openowner->oo_confirmed = 1; 2746fe0750e5SJ. Bruce Fields open->op_openowner->oo_owner.so_client->cl_firststate = 1; 27471da177e4SLinus Torvalds } 27481da177e4SLinus Torvalds 274914a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 275014a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 275114a24e99SJ. Bruce Fields { 275214a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 275314a24e99SJ. Bruce Fields return true; 275414a24e99SJ. Bruce Fields /* 275514a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 275614a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 275714a24e99SJ. Bruce Fields * until we hear otherwise: 275814a24e99SJ. Bruce Fields */ 275914a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 276014a24e99SJ. Bruce Fields } 276114a24e99SJ. Bruce Fields 276222d38c4cSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag) 276322d38c4cSJ. Bruce Fields { 276422d38c4cSJ. Bruce Fields struct file_lock *fl; 276522d38c4cSJ. Bruce Fields 276622d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 276722d38c4cSJ. Bruce Fields if (!fl) 276822d38c4cSJ. Bruce Fields return NULL; 276922d38c4cSJ. Bruce Fields locks_init_lock(fl); 277022d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 277122d38c4cSJ. Bruce Fields fl->fl_flags = FL_LEASE; 277222d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 277322d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 2774acfdf5c3SJ. Bruce Fields fl->fl_owner = (fl_owner_t)(dp->dl_file); 277522d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 277622d38c4cSJ. Bruce Fields return fl; 277722d38c4cSJ. Bruce Fields } 277822d38c4cSJ. Bruce Fields 2779edab9782SJ. Bruce Fields static int nfs4_setlease(struct nfs4_delegation *dp, int flag) 2780edab9782SJ. Bruce Fields { 2781acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = dp->dl_file; 2782edab9782SJ. Bruce Fields struct file_lock *fl; 2783edab9782SJ. Bruce Fields int status; 2784edab9782SJ. Bruce Fields 2785edab9782SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, flag); 2786edab9782SJ. Bruce Fields if (!fl) 2787edab9782SJ. Bruce Fields return -ENOMEM; 2788acfdf5c3SJ. Bruce Fields fl->fl_file = find_readable_file(fp); 2789acfdf5c3SJ. Bruce Fields list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); 2790acfdf5c3SJ. Bruce Fields status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); 2791edab9782SJ. Bruce Fields if (status) { 2792acfdf5c3SJ. Bruce Fields list_del_init(&dp->dl_perclnt); 2793edab9782SJ. Bruce Fields locks_free_lock(fl); 2794edab9782SJ. Bruce Fields return -ENOMEM; 2795edab9782SJ. Bruce Fields } 2796acfdf5c3SJ. Bruce Fields fp->fi_lease = fl; 2797acfdf5c3SJ. Bruce Fields fp->fi_deleg_file = fl->fl_file; 2798acfdf5c3SJ. Bruce Fields get_file(fp->fi_deleg_file); 2799acfdf5c3SJ. Bruce Fields atomic_set(&fp->fi_delegees, 1); 2800acfdf5c3SJ. Bruce Fields list_add(&dp->dl_perfile, &fp->fi_delegations); 2801acfdf5c3SJ. Bruce Fields return 0; 2802acfdf5c3SJ. Bruce Fields } 2803acfdf5c3SJ. Bruce Fields 2804acfdf5c3SJ. Bruce Fields static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) 2805acfdf5c3SJ. Bruce Fields { 2806acfdf5c3SJ. Bruce Fields struct nfs4_file *fp = dp->dl_file; 2807acfdf5c3SJ. Bruce Fields 2808acfdf5c3SJ. Bruce Fields if (!fp->fi_lease) 2809acfdf5c3SJ. Bruce Fields return nfs4_setlease(dp, flag); 2810acfdf5c3SJ. Bruce Fields spin_lock(&recall_lock); 2811acfdf5c3SJ. Bruce Fields if (fp->fi_had_conflict) { 2812acfdf5c3SJ. Bruce Fields spin_unlock(&recall_lock); 2813acfdf5c3SJ. Bruce Fields return -EAGAIN; 2814acfdf5c3SJ. Bruce Fields } 2815acfdf5c3SJ. Bruce Fields atomic_inc(&fp->fi_delegees); 2816acfdf5c3SJ. Bruce Fields list_add(&dp->dl_perfile, &fp->fi_delegations); 2817acfdf5c3SJ. Bruce Fields spin_unlock(&recall_lock); 2818acfdf5c3SJ. Bruce Fields list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); 2819edab9782SJ. Bruce Fields return 0; 2820edab9782SJ. Bruce Fields } 2821edab9782SJ. Bruce Fields 28221da177e4SLinus Torvalds /* 28231da177e4SLinus Torvalds * Attempt to hand out a delegation. 28241da177e4SLinus Torvalds */ 28251da177e4SLinus Torvalds static void 28261da177e4SLinus Torvalds nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp) 28271da177e4SLinus Torvalds { 28281da177e4SLinus Torvalds struct nfs4_delegation *dp; 2829fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); 283014a24e99SJ. Bruce Fields int cb_up; 28311da177e4SLinus Torvalds int status, flag = 0; 28321da177e4SLinus Torvalds 2833fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 28341da177e4SLinus Torvalds flag = NFS4_OPEN_DELEGATE_NONE; 28357b190fecSNeilBrown open->op_recall = 0; 28367b190fecSNeilBrown switch (open->op_claim_type) { 28377b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 28382bf23875SJ. Bruce Fields if (!cb_up) 28397b190fecSNeilBrown open->op_recall = 1; 28407b190fecSNeilBrown flag = open->op_delegate_type; 28417b190fecSNeilBrown if (flag == NFS4_OPEN_DELEGATE_NONE) 28421da177e4SLinus Torvalds goto out; 28437b190fecSNeilBrown break; 28447b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 28457b190fecSNeilBrown /* Let's not give out any delegations till everyone's 28467b190fecSNeilBrown * had the chance to reclaim theirs.... */ 2847af558e33SJ. Bruce Fields if (locks_in_grace()) 28487b190fecSNeilBrown goto out; 2849fe0750e5SJ. Bruce Fields if (!cb_up || !oo->oo_confirmed) 28507b190fecSNeilBrown goto out; 28511da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 28521da177e4SLinus Torvalds flag = NFS4_OPEN_DELEGATE_WRITE; 28531da177e4SLinus Torvalds else 28541da177e4SLinus Torvalds flag = NFS4_OPEN_DELEGATE_READ; 28557b190fecSNeilBrown break; 28567b190fecSNeilBrown default: 28577b190fecSNeilBrown goto out; 28587b190fecSNeilBrown } 28591da177e4SLinus Torvalds 2860fe0750e5SJ. Bruce Fields dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag); 2861dd239cc0SJ. Bruce Fields if (dp == NULL) 2862dd239cc0SJ. Bruce Fields goto out_no_deleg; 2863acfdf5c3SJ. Bruce Fields status = nfs4_set_delegation(dp, flag); 2864edab9782SJ. Bruce Fields if (status) 2865dd239cc0SJ. Bruce Fields goto out_free; 28661da177e4SLinus Torvalds 28671da177e4SLinus Torvalds memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); 28681da177e4SLinus Torvalds 28698c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 28708c10cbdbSBenny Halevy STATEID_VAL(&dp->dl_stateid)); 28711da177e4SLinus Torvalds out: 28727b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS 28737b190fecSNeilBrown && flag == NFS4_OPEN_DELEGATE_NONE 28747b190fecSNeilBrown && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) 28752fdada03SJ. Bruce Fields dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 28761da177e4SLinus Torvalds open->op_delegate_type = flag; 2877dd239cc0SJ. Bruce Fields return; 2878dd239cc0SJ. Bruce Fields out_free: 2879acfdf5c3SJ. Bruce Fields nfs4_put_delegation(dp); 2880dd239cc0SJ. Bruce Fields out_no_deleg: 2881dd239cc0SJ. Bruce Fields flag = NFS4_OPEN_DELEGATE_NONE; 2882dd239cc0SJ. Bruce Fields goto out; 28831da177e4SLinus Torvalds } 28841da177e4SLinus Torvalds 28851da177e4SLinus Torvalds /* 28861da177e4SLinus Torvalds * called with nfs4_lock_state() held. 28871da177e4SLinus Torvalds */ 2888b37ad28bSAl Viro __be32 28891da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 28901da177e4SLinus Torvalds { 28916668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 28921da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 28931da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 28941da177e4SLinus Torvalds struct nfs4_stateid *stp = NULL; 2895567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 2896b37ad28bSAl Viro __be32 status; 28971da177e4SLinus Torvalds 28981da177e4SLinus Torvalds status = nfserr_inval; 2899d87a8adeSAndy Adamson if (!access_valid(open->op_share_access, resp->cstate.minorversion) 2900ba5a6a19SJ. Bruce Fields || !deny_valid(open->op_share_deny)) 29011da177e4SLinus Torvalds goto out; 29021da177e4SLinus Torvalds /* 29031da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 29041da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 29051da177e4SLinus Torvalds * If not found, create the nfs4_file struct 29061da177e4SLinus Torvalds */ 29071da177e4SLinus Torvalds fp = find_file(ino); 29081da177e4SLinus Torvalds if (fp) { 29091da177e4SLinus Torvalds if ((status = nfs4_check_open(fp, open, &stp))) 29101da177e4SLinus Torvalds goto out; 2911c44c5eebSNeilBrown status = nfs4_check_deleg(fp, open, &dp); 2912c44c5eebSNeilBrown if (status) 2913c44c5eebSNeilBrown goto out; 29141da177e4SLinus Torvalds } else { 2915c44c5eebSNeilBrown status = nfserr_bad_stateid; 2916c44c5eebSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) 2917c44c5eebSNeilBrown goto out; 29183e772463SJ. Bruce Fields status = nfserr_jukebox; 29191da177e4SLinus Torvalds fp = alloc_init_file(ino); 29201da177e4SLinus Torvalds if (fp == NULL) 29211da177e4SLinus Torvalds goto out; 29221da177e4SLinus Torvalds } 29231da177e4SLinus Torvalds 29241da177e4SLinus Torvalds /* 29251da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 29261da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 29271da177e4SLinus Torvalds */ 29281da177e4SLinus Torvalds if (stp) { 29291da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 2930f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 29311da177e4SLinus Torvalds if (status) 29321da177e4SLinus Torvalds goto out; 29331da177e4SLinus Torvalds } else { 2934f9d7562fSJ. Bruce Fields status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); 2935567d9829SNeilBrown if (status) 29361da177e4SLinus Torvalds goto out; 2937881ea2b1SJ. Bruce Fields init_open_stateid(stp, fp, open); 29381da177e4SLinus Torvalds status = nfsd4_truncate(rqstp, current_fh, open); 29391da177e4SLinus Torvalds if (status) { 29402283963fSJ. Bruce Fields release_open_stateid(stp); 29411da177e4SLinus Torvalds goto out; 29421da177e4SLinus Torvalds } 29431da177e4SLinus Torvalds } 294473997dc4SJ. Bruce Fields update_stateid(&stp->st_stateid); 29451da177e4SLinus Torvalds memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); 29461da177e4SLinus Torvalds 29474dc6ec00SJ. Bruce Fields if (nfsd4_has_session(&resp->cstate)) 2948fe0750e5SJ. Bruce Fields open->op_openowner->oo_confirmed = 1; 29496668958fSAndy Adamson 29501da177e4SLinus Torvalds /* 29511da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 29521da177e4SLinus Torvalds * OPEN succeeds even if we fail. 29531da177e4SLinus Torvalds */ 29541da177e4SLinus Torvalds nfs4_open_delegation(current_fh, open, stp); 29551da177e4SLinus Torvalds 29561da177e4SLinus Torvalds status = nfs_ok; 29571da177e4SLinus Torvalds 29588c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 29598c10cbdbSBenny Halevy STATEID_VAL(&stp->st_stateid)); 29601da177e4SLinus Torvalds out: 296113cd2184SNeilBrown if (fp) 296213cd2184SNeilBrown put_nfs4_file(fp); 296337515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 296437515177SNeilBrown nfs4_set_claim_prev(open); 29651da177e4SLinus Torvalds /* 29661da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 29671da177e4SLinus Torvalds */ 29681da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 2969fe0750e5SJ. Bruce Fields if (!open->op_openowner->oo_confirmed && 29706668958fSAndy Adamson !nfsd4_has_session(&resp->cstate)) 29711da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 29721da177e4SLinus Torvalds 29731da177e4SLinus Torvalds return status; 29741da177e4SLinus Torvalds } 29751da177e4SLinus Torvalds 2976b37ad28bSAl Viro __be32 2977b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 2978b591480bSJ.Bruce Fields clientid_t *clid) 29791da177e4SLinus Torvalds { 29801da177e4SLinus Torvalds struct nfs4_client *clp; 2981b37ad28bSAl Viro __be32 status; 29821da177e4SLinus Torvalds 29831da177e4SLinus Torvalds nfs4_lock_state(); 29841da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 29851da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 29861da177e4SLinus Torvalds status = nfserr_stale_clientid; 29871da177e4SLinus Torvalds if (STALE_CLIENTID(clid)) 29881da177e4SLinus Torvalds goto out; 29891da177e4SLinus Torvalds clp = find_confirmed_client(clid); 29901da177e4SLinus Torvalds status = nfserr_expired; 29911da177e4SLinus Torvalds if (clp == NULL) { 29921da177e4SLinus Torvalds /* We assume the client took too long to RENEW. */ 29931da177e4SLinus Torvalds dprintk("nfsd4_renew: clientid not found!\n"); 29941da177e4SLinus Torvalds goto out; 29951da177e4SLinus Torvalds } 29961da177e4SLinus Torvalds renew_client(clp); 29971da177e4SLinus Torvalds status = nfserr_cb_path_down; 2998ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 299977a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 30001da177e4SLinus Torvalds goto out; 30011da177e4SLinus Torvalds status = nfs_ok; 30021da177e4SLinus Torvalds out: 30031da177e4SLinus Torvalds nfs4_unlock_state(); 30041da177e4SLinus Torvalds return status; 30051da177e4SLinus Torvalds } 30061da177e4SLinus Torvalds 3007c47d832bSDaniel Mack static struct lock_manager nfsd4_manager = { 3008af558e33SJ. Bruce Fields }; 3009af558e33SJ. Bruce Fields 3010a76b4319SNeilBrown static void 3011af558e33SJ. Bruce Fields nfsd4_end_grace(void) 3012a76b4319SNeilBrown { 3013a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 3014c7b9a459SNeilBrown nfsd4_recdir_purge_old(); 3015af558e33SJ. Bruce Fields locks_end_grace(&nfsd4_manager); 3016e46b498cSJ. Bruce Fields /* 3017e46b498cSJ. Bruce Fields * Now that every NFSv4 client has had the chance to recover and 3018e46b498cSJ. Bruce Fields * to see the (possibly new, possibly shorter) lease time, we 3019e46b498cSJ. Bruce Fields * can safely set the next grace time to the current lease time: 3020e46b498cSJ. Bruce Fields */ 3021e46b498cSJ. Bruce Fields nfsd4_grace = nfsd4_lease; 3022a76b4319SNeilBrown } 3023a76b4319SNeilBrown 3024fd39ca9aSNeilBrown static time_t 30251da177e4SLinus Torvalds nfs4_laundromat(void) 30261da177e4SLinus Torvalds { 30271da177e4SLinus Torvalds struct nfs4_client *clp; 3028fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 30291da177e4SLinus Torvalds struct nfs4_delegation *dp; 30301da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 3031cf07d2eaSJ. Bruce Fields time_t cutoff = get_seconds() - nfsd4_lease; 3032cf07d2eaSJ. Bruce Fields time_t t, clientid_val = nfsd4_lease; 3033cf07d2eaSJ. Bruce Fields time_t u, test_val = nfsd4_lease; 30341da177e4SLinus Torvalds 30351da177e4SLinus Torvalds nfs4_lock_state(); 30361da177e4SLinus Torvalds 30371da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 3038af558e33SJ. Bruce Fields if (locks_in_grace()) 3039af558e33SJ. Bruce Fields nfsd4_end_grace(); 304036acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 304136acb66bSBenny Halevy spin_lock(&client_lock); 30421da177e4SLinus Torvalds list_for_each_safe(pos, next, &client_lru) { 30431da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 30441da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 30451da177e4SLinus Torvalds t = clp->cl_time - cutoff; 30461da177e4SLinus Torvalds if (clientid_val > t) 30471da177e4SLinus Torvalds clientid_val = t; 30481da177e4SLinus Torvalds break; 30491da177e4SLinus Torvalds } 3050d7682988SBenny Halevy if (atomic_read(&clp->cl_refcount)) { 3051d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 3052d7682988SBenny Halevy clp->cl_clientid.cl_id); 3053d7682988SBenny Halevy continue; 3054d7682988SBenny Halevy } 3055d7682988SBenny Halevy unhash_client_locked(clp); 3056d7682988SBenny Halevy list_add(&clp->cl_lru, &reaplist); 305736acb66bSBenny Halevy } 305836acb66bSBenny Halevy spin_unlock(&client_lock); 305936acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 306036acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 30611da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 30621da177e4SLinus Torvalds clp->cl_clientid.cl_id); 3063c7b9a459SNeilBrown nfsd4_remove_clid_dir(clp); 30641da177e4SLinus Torvalds expire_client(clp); 30651da177e4SLinus Torvalds } 30661da177e4SLinus Torvalds spin_lock(&recall_lock); 30671da177e4SLinus Torvalds list_for_each_safe(pos, next, &del_recall_lru) { 30681da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 30691da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 30701da177e4SLinus Torvalds u = dp->dl_time - cutoff; 30711da177e4SLinus Torvalds if (test_val > u) 30721da177e4SLinus Torvalds test_val = u; 30731da177e4SLinus Torvalds break; 30741da177e4SLinus Torvalds } 30751da177e4SLinus Torvalds list_move(&dp->dl_recall_lru, &reaplist); 30761da177e4SLinus Torvalds } 30771da177e4SLinus Torvalds spin_unlock(&recall_lock); 30781da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 30791da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 30801da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 30811da177e4SLinus Torvalds unhash_delegation(dp); 30821da177e4SLinus Torvalds } 3083cf07d2eaSJ. Bruce Fields test_val = nfsd4_lease; 30841da177e4SLinus Torvalds list_for_each_safe(pos, next, &close_lru) { 3085fe0750e5SJ. Bruce Fields oo = container_of(pos, struct nfs4_openowner, oo_close_lru); 3086fe0750e5SJ. Bruce Fields if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { 3087fe0750e5SJ. Bruce Fields u = oo->oo_time - cutoff; 30881da177e4SLinus Torvalds if (test_val > u) 30891da177e4SLinus Torvalds test_val = u; 30901da177e4SLinus Torvalds break; 30911da177e4SLinus Torvalds } 30921da177e4SLinus Torvalds dprintk("NFSD: purging unused open stateowner (so_id %d)\n", 3093fe0750e5SJ. Bruce Fields oo->oo_owner.so_id); 3094fe0750e5SJ. Bruce Fields release_openowner(oo); 30951da177e4SLinus Torvalds } 30961da177e4SLinus Torvalds if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) 30971da177e4SLinus Torvalds clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; 30981da177e4SLinus Torvalds nfs4_unlock_state(); 30991da177e4SLinus Torvalds return clientid_val; 31001da177e4SLinus Torvalds } 31011da177e4SLinus Torvalds 3102a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 3103a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 3104a254b246SHarvey Harrison static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); 3105a254b246SHarvey Harrison 3106a254b246SHarvey Harrison static void 3107c4028958SDavid Howells laundromat_main(struct work_struct *not_used) 31081da177e4SLinus Torvalds { 31091da177e4SLinus Torvalds time_t t; 31101da177e4SLinus Torvalds 31111da177e4SLinus Torvalds t = nfs4_laundromat(); 31121da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 311358da282bSNeilBrown queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); 31141da177e4SLinus Torvalds } 31151da177e4SLinus Torvalds 3116fe0750e5SJ. Bruce Fields static struct nfs4_openowner * search_close_lru(u32 st_id) 3117f8816512SNeilBrown { 3118fe0750e5SJ. Bruce Fields struct nfs4_openowner *local; 31191da177e4SLinus Torvalds 3120fe0750e5SJ. Bruce Fields list_for_each_entry(local, &close_lru, oo_close_lru) { 3121fe0750e5SJ. Bruce Fields if (local->oo_owner.so_id == st_id) 31221da177e4SLinus Torvalds return local; 31231da177e4SLinus Torvalds } 31241da177e4SLinus Torvalds return NULL; 31251da177e4SLinus Torvalds } 31261da177e4SLinus Torvalds 31271da177e4SLinus Torvalds static inline int 31281da177e4SLinus Torvalds nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) 31291da177e4SLinus Torvalds { 3130f9d7562fSJ. Bruce Fields return fhp->fh_dentry->d_inode != stp->st_file->fi_inode; 31311da177e4SLinus Torvalds } 31321da177e4SLinus Torvalds 31331da177e4SLinus Torvalds static int 31341da177e4SLinus Torvalds STALE_STATEID(stateid_t *stateid) 31351da177e4SLinus Torvalds { 3136e4e83ea4SJ. Bruce Fields if (stateid->si_boot == boot_time) 3137e4e83ea4SJ. Bruce Fields return 0; 31388c10cbdbSBenny Halevy dprintk("NFSD: stale stateid " STATEID_FMT "!\n", 31398c10cbdbSBenny Halevy STATEID_VAL(stateid)); 31401da177e4SLinus Torvalds return 1; 31411da177e4SLinus Torvalds } 31421da177e4SLinus Torvalds 31431da177e4SLinus Torvalds static inline int 31441da177e4SLinus Torvalds access_permit_read(unsigned long access_bmap) 31451da177e4SLinus Torvalds { 31461da177e4SLinus Torvalds return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || 31471da177e4SLinus Torvalds test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) || 31481da177e4SLinus Torvalds test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap); 31491da177e4SLinus Torvalds } 31501da177e4SLinus Torvalds 31511da177e4SLinus Torvalds static inline int 31521da177e4SLinus Torvalds access_permit_write(unsigned long access_bmap) 31531da177e4SLinus Torvalds { 31541da177e4SLinus Torvalds return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || 31551da177e4SLinus Torvalds test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); 31561da177e4SLinus Torvalds } 31571da177e4SLinus Torvalds 31581da177e4SLinus Torvalds static 3159b37ad28bSAl Viro __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) 31601da177e4SLinus Torvalds { 3161b37ad28bSAl Viro __be32 status = nfserr_openmode; 31621da177e4SLinus Torvalds 316302921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 316402921914SJ. Bruce Fields if (stp->st_openstp) 316502921914SJ. Bruce Fields stp = stp->st_openstp; 31661da177e4SLinus Torvalds if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) 31671da177e4SLinus Torvalds goto out; 31681da177e4SLinus Torvalds if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) 31691da177e4SLinus Torvalds goto out; 31701da177e4SLinus Torvalds status = nfs_ok; 31711da177e4SLinus Torvalds out: 31721da177e4SLinus Torvalds return status; 31731da177e4SLinus Torvalds } 31741da177e4SLinus Torvalds 3175b37ad28bSAl Viro static inline __be32 31761da177e4SLinus Torvalds check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) 31771da177e4SLinus Torvalds { 3178203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 31791da177e4SLinus Torvalds return nfs_ok; 3180af558e33SJ. Bruce Fields else if (locks_in_grace()) { 318125985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 31821da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 31831da177e4SLinus Torvalds return nfserr_grace; 31841da177e4SLinus Torvalds } else if (flags & WR_STATE) 31851da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 31861da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 31871da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 31881da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 31891da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 31901da177e4SLinus Torvalds } 31911da177e4SLinus Torvalds 31921da177e4SLinus Torvalds /* 31931da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 31941da177e4SLinus Torvalds * that are not able to provide mandatory locking. 31951da177e4SLinus Torvalds */ 31961da177e4SLinus Torvalds static inline int 319718f82731SJ. Bruce Fields grace_disallows_io(struct inode *inode) 31981da177e4SLinus Torvalds { 3199203a8c8eSJ. Bruce Fields return locks_in_grace() && mandatory_lock(inode); 32001da177e4SLinus Torvalds } 32011da177e4SLinus Torvalds 320281b82965SJ. Bruce Fields /* Returns true iff a is later than b: */ 320381b82965SJ. Bruce Fields static bool stateid_generation_after(stateid_t *a, stateid_t *b) 320481b82965SJ. Bruce Fields { 320581b82965SJ. Bruce Fields return (s32)a->si_generation - (s32)b->si_generation > 0; 320681b82965SJ. Bruce Fields } 320781b82965SJ. Bruce Fields 320828dde241SJ. Bruce Fields static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 32090836f587SJ. Bruce Fields { 32106668958fSAndy Adamson /* 32116668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 32126668958fSAndy Adamson * when it is zero. 32136668958fSAndy Adamson */ 321428dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 321581b82965SJ. Bruce Fields return nfs_ok; 321681b82965SJ. Bruce Fields 321781b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 321881b82965SJ. Bruce Fields return nfs_ok; 32196668958fSAndy Adamson 32200836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 322181b82965SJ. Bruce Fields if (stateid_generation_after(in, ref)) 32220836f587SJ. Bruce Fields return nfserr_bad_stateid; 32230836f587SJ. Bruce Fields /* 322481b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 322581b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 322681b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 322781b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 322881b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 322981b82965SJ. Bruce Fields * but better performance may result in retrying IO that 323081b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 323181b82965SJ. Bruce Fields * reordered in flight: 32320836f587SJ. Bruce Fields */ 32330836f587SJ. Bruce Fields return nfserr_old_stateid; 32340836f587SJ. Bruce Fields } 32350836f587SJ. Bruce Fields 32363e633079SJ. Bruce Fields static int is_delegation_stateid(stateid_t *stateid) 32373e633079SJ. Bruce Fields { 32383e633079SJ. Bruce Fields return stateid->si_fileid == 0; 32393e633079SJ. Bruce Fields } 32403e633079SJ. Bruce Fields 324128dde241SJ. Bruce Fields __be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session) 324217456804SBryan Schumaker { 324317456804SBryan Schumaker struct nfs4_stateid *stp = NULL; 324417456804SBryan Schumaker __be32 status = nfserr_stale_stateid; 324517456804SBryan Schumaker 324617456804SBryan Schumaker if (STALE_STATEID(stateid)) 324717456804SBryan Schumaker goto out; 324817456804SBryan Schumaker 324917456804SBryan Schumaker status = nfserr_expired; 32504d71ab87SJ. Bruce Fields stp = find_stateid(stateid); 325117456804SBryan Schumaker if (!stp) 325217456804SBryan Schumaker goto out; 325317456804SBryan Schumaker status = nfserr_bad_stateid; 3254fe0750e5SJ. Bruce Fields if (stp->st_stateowner->so_is_open_owner 3255fe0750e5SJ. Bruce Fields && !openowner(stp->st_stateowner)->oo_confirmed) 325617456804SBryan Schumaker goto out; 325717456804SBryan Schumaker 325828dde241SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stateid, has_session); 325917456804SBryan Schumaker if (status) 326017456804SBryan Schumaker goto out; 326117456804SBryan Schumaker 326217456804SBryan Schumaker status = nfs_ok; 326317456804SBryan Schumaker out: 326417456804SBryan Schumaker return status; 326517456804SBryan Schumaker } 326617456804SBryan Schumaker 32671da177e4SLinus Torvalds /* 32681da177e4SLinus Torvalds * Checks for stateid operations 32691da177e4SLinus Torvalds */ 3270b37ad28bSAl Viro __be32 3271dd453dfdSBenny Halevy nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, 3272dd453dfdSBenny Halevy stateid_t *stateid, int flags, struct file **filpp) 32731da177e4SLinus Torvalds { 32741da177e4SLinus Torvalds struct nfs4_stateid *stp = NULL; 32751da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 3276dd453dfdSBenny Halevy struct svc_fh *current_fh = &cstate->current_fh; 32771da177e4SLinus Torvalds struct inode *ino = current_fh->fh_dentry->d_inode; 3278b37ad28bSAl Viro __be32 status; 32791da177e4SLinus Torvalds 32801da177e4SLinus Torvalds if (filpp) 32811da177e4SLinus Torvalds *filpp = NULL; 32821da177e4SLinus Torvalds 328318f82731SJ. Bruce Fields if (grace_disallows_io(ino)) 32841da177e4SLinus Torvalds return nfserr_grace; 32851da177e4SLinus Torvalds 32861da177e4SLinus Torvalds if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 32871da177e4SLinus Torvalds return check_special_stateids(current_fh, stateid, flags); 32881da177e4SLinus Torvalds 32891da177e4SLinus Torvalds status = nfserr_stale_stateid; 32901da177e4SLinus Torvalds if (STALE_STATEID(stateid)) 32911da177e4SLinus Torvalds goto out; 32921da177e4SLinus Torvalds 329333515142SJ. Bruce Fields /* 329433515142SJ. Bruce Fields * We assume that any stateid that has the current boot time, 329533515142SJ. Bruce Fields * but that we can't find, is expired: 329633515142SJ. Bruce Fields */ 329733515142SJ. Bruce Fields status = nfserr_expired; 32983e633079SJ. Bruce Fields if (is_delegation_stateid(stateid)) { 3299a4455be0SJ. Bruce Fields dp = find_delegation_stateid(ino, stateid); 3300e4e83ea4SJ. Bruce Fields if (!dp) 33011da177e4SLinus Torvalds goto out; 330228dde241SJ. Bruce Fields status = check_stateid_generation(stateid, &dp->dl_stateid, nfsd4_has_session(cstate)); 33030c2a498fSJ. Bruce Fields if (status) 33040c2a498fSJ. Bruce Fields goto out; 3305dc9bf700SJ. Bruce Fields status = nfs4_check_delegmode(dp, flags); 3306dc9bf700SJ. Bruce Fields if (status) 3307dc9bf700SJ. Bruce Fields goto out; 3308dc9bf700SJ. Bruce Fields renew_client(dp->dl_client); 330943b0178eSDan Carpenter if (filpp) { 3310acfdf5c3SJ. Bruce Fields *filpp = dp->dl_file->fi_deleg_file; 3311f9d7562fSJ. Bruce Fields BUG_ON(!*filpp); 331243b0178eSDan Carpenter } 33131da177e4SLinus Torvalds } else { /* open or lock stateid */ 33144d71ab87SJ. Bruce Fields stp = find_stateid(stateid); 3315e4e83ea4SJ. Bruce Fields if (!stp) 33161da177e4SLinus Torvalds goto out; 331733515142SJ. Bruce Fields status = nfserr_bad_stateid; 33186150ef0dSJ. Bruce Fields if (nfs4_check_fh(current_fh, stp)) 33191da177e4SLinus Torvalds goto out; 3320fe0750e5SJ. Bruce Fields if (stp->st_stateowner->so_is_open_owner 3321fe0750e5SJ. Bruce Fields && !openowner(stp->st_stateowner)->oo_confirmed) 33221da177e4SLinus Torvalds goto out; 33236668958fSAndy Adamson status = check_stateid_generation(stateid, &stp->st_stateid, 332428dde241SJ. Bruce Fields nfsd4_has_session(cstate)); 33250836f587SJ. Bruce Fields if (status) 33261da177e4SLinus Torvalds goto out; 3327a4455be0SJ. Bruce Fields status = nfs4_check_openmode(stp, flags); 3328a4455be0SJ. Bruce Fields if (status) 33291da177e4SLinus Torvalds goto out; 33301da177e4SLinus Torvalds renew_client(stp->st_stateowner->so_client); 3331f9d7562fSJ. Bruce Fields if (filpp) { 3332f9d7562fSJ. Bruce Fields if (flags & RD_STATE) 3333f9d7562fSJ. Bruce Fields *filpp = find_readable_file(stp->st_file); 3334f9d7562fSJ. Bruce Fields else 3335f9d7562fSJ. Bruce Fields *filpp = find_writeable_file(stp->st_file); 3336f9d7562fSJ. Bruce Fields } 33371da177e4SLinus Torvalds } 33381da177e4SLinus Torvalds status = nfs_ok; 33391da177e4SLinus Torvalds out: 33401da177e4SLinus Torvalds return status; 33411da177e4SLinus Torvalds } 33421da177e4SLinus Torvalds 3343e1ca12dfSBryan Schumaker static __be32 3344e1ca12dfSBryan Schumaker nfsd4_free_delegation_stateid(stateid_t *stateid) 3345e1ca12dfSBryan Schumaker { 3346e1ca12dfSBryan Schumaker struct nfs4_delegation *dp = search_for_delegation(stateid); 3347e1ca12dfSBryan Schumaker if (dp) 3348e1ca12dfSBryan Schumaker return nfserr_locks_held; 3349e1ca12dfSBryan Schumaker return nfserr_bad_stateid; 3350e1ca12dfSBryan Schumaker } 3351e1ca12dfSBryan Schumaker 3352e1ca12dfSBryan Schumaker static __be32 3353e1ca12dfSBryan Schumaker nfsd4_free_lock_stateid(struct nfs4_stateid *stp) 3354e1ca12dfSBryan Schumaker { 3355fe0750e5SJ. Bruce Fields if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner))) 3356e1ca12dfSBryan Schumaker return nfserr_locks_held; 3357e1ca12dfSBryan Schumaker release_lock_stateid(stp); 3358e1ca12dfSBryan Schumaker return nfs_ok; 3359e1ca12dfSBryan Schumaker } 3360e1ca12dfSBryan Schumaker 3361e1ca12dfSBryan Schumaker /* 336217456804SBryan Schumaker * Test if the stateid is valid 336317456804SBryan Schumaker */ 336417456804SBryan Schumaker __be32 336517456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 336617456804SBryan Schumaker struct nfsd4_test_stateid *test_stateid) 336717456804SBryan Schumaker { 336817456804SBryan Schumaker test_stateid->ts_has_session = nfsd4_has_session(cstate); 336917456804SBryan Schumaker return nfs_ok; 337017456804SBryan Schumaker } 337117456804SBryan Schumaker 337217456804SBryan Schumaker /* 3373e1ca12dfSBryan Schumaker * Free a state id 3374e1ca12dfSBryan Schumaker */ 3375e1ca12dfSBryan Schumaker __be32 3376e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3377e1ca12dfSBryan Schumaker struct nfsd4_free_stateid *free_stateid) 3378e1ca12dfSBryan Schumaker { 3379e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 3380e1ca12dfSBryan Schumaker struct nfs4_stateid *stp; 3381e1ca12dfSBryan Schumaker __be32 ret; 3382e1ca12dfSBryan Schumaker 3383e1ca12dfSBryan Schumaker nfs4_lock_state(); 3384e1ca12dfSBryan Schumaker if (is_delegation_stateid(stateid)) { 3385e1ca12dfSBryan Schumaker ret = nfsd4_free_delegation_stateid(stateid); 3386e1ca12dfSBryan Schumaker goto out; 3387e1ca12dfSBryan Schumaker } 3388e1ca12dfSBryan Schumaker 33894d71ab87SJ. Bruce Fields stp = find_stateid(stateid); 3390e1ca12dfSBryan Schumaker if (!stp) { 3391e1ca12dfSBryan Schumaker ret = nfserr_bad_stateid; 3392e1ca12dfSBryan Schumaker goto out; 3393e1ca12dfSBryan Schumaker } 339481b82965SJ. Bruce Fields ret = check_stateid_generation(stateid, &stp->st_stateid, 1); 339581b82965SJ. Bruce Fields if (ret) 3396e1ca12dfSBryan Schumaker goto out; 3397e1ca12dfSBryan Schumaker 33985fa0bbb4SJ. Bruce Fields if (stp->st_type == NFS4_OPEN_STID) { 3399e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 3400e1ca12dfSBryan Schumaker goto out; 3401e1ca12dfSBryan Schumaker } else { 3402e1ca12dfSBryan Schumaker ret = nfsd4_free_lock_stateid(stp); 3403e1ca12dfSBryan Schumaker goto out; 3404e1ca12dfSBryan Schumaker } 3405e1ca12dfSBryan Schumaker 3406e1ca12dfSBryan Schumaker out: 3407e1ca12dfSBryan Schumaker nfs4_unlock_state(); 3408e1ca12dfSBryan Schumaker return ret; 3409e1ca12dfSBryan Schumaker } 3410e1ca12dfSBryan Schumaker 34114c4cd222SNeilBrown static inline int 34124c4cd222SNeilBrown setlkflg (int type) 34134c4cd222SNeilBrown { 34144c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 34154c4cd222SNeilBrown RD_STATE : WR_STATE; 34164c4cd222SNeilBrown } 34171da177e4SLinus Torvalds 3418c0a5d93eSJ. Bruce Fields static __be32 nfs4_nospecial_stateid_checks(stateid_t *stateid) 3419c0a5d93eSJ. Bruce Fields { 3420c0a5d93eSJ. Bruce Fields if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 3421c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 3422c0a5d93eSJ. Bruce Fields if (STALE_STATEID(stateid)) 3423c0a5d93eSJ. Bruce Fields return nfserr_stale_stateid; 3424c0a5d93eSJ. Bruce Fields return nfs_ok; 3425c0a5d93eSJ. Bruce Fields } 3426c0a5d93eSJ. Bruce Fields 3427c0a5d93eSJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_stateid *stp) 3428c0a5d93eSJ. Bruce Fields { 3429c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 3430c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 3431c0a5d93eSJ. Bruce Fields __be32 status; 3432c0a5d93eSJ. Bruce Fields 3433c0a5d93eSJ. Bruce Fields if (nfs4_check_fh(current_fh, stp)) 3434c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 3435c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 3436c0a5d93eSJ. Bruce Fields if (status) 3437c0a5d93eSJ. Bruce Fields return status; 3438c0a5d93eSJ. Bruce Fields return check_stateid_generation(stateid, &stp->st_stateid, nfsd4_has_session(cstate)); 3439c0a5d93eSJ. Bruce Fields } 3440c0a5d93eSJ. Bruce Fields 34411da177e4SLinus Torvalds /* 34421da177e4SLinus Torvalds * Checks for sequence id mutating operations. 34431da177e4SLinus Torvalds */ 3444b37ad28bSAl Viro static __be32 3445dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 34462288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 3447b34f27aaSJ. Bruce Fields struct nfs4_stateid **stpp) 34481da177e4SLinus Torvalds { 34490836f587SJ. Bruce Fields __be32 status; 34501da177e4SLinus Torvalds 34518c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 34528c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 34531da177e4SLinus Torvalds 34541da177e4SLinus Torvalds *stpp = NULL; 3455c0a5d93eSJ. Bruce Fields status = nfs4_nospecial_stateid_checks(stateid); 3456c0a5d93eSJ. Bruce Fields if (status) 3457c0a5d93eSJ. Bruce Fields return status; 34582288d0e3SJ. Bruce Fields *stpp = find_stateid_by_type(stateid, typemask); 3459f4dee24cSJ. Bruce Fields if (*stpp == NULL) 346033515142SJ. Bruce Fields return nfserr_expired; 3461c0a5d93eSJ. Bruce Fields cstate->replay_owner = (*stpp)->st_stateowner; 3462c0a5d93eSJ. Bruce Fields renew_client((*stpp)->st_stateowner->so_client); 34631da177e4SLinus Torvalds 3464c0a5d93eSJ. Bruce Fields return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); 34651da177e4SLinus Torvalds } 34661da177e4SLinus Torvalds 3467c0a5d93eSJ. Bruce Fields static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_stateid **stpp) 3468c0a5d93eSJ. Bruce Fields { 3469c0a5d93eSJ. Bruce Fields __be32 status; 3470c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 34711da177e4SLinus Torvalds 3472c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 34732288d0e3SJ. Bruce Fields NFS4_OPEN_STID, stpp); 34740836f587SJ. Bruce Fields if (status) 34750836f587SJ. Bruce Fields return status; 3476c0a5d93eSJ. Bruce Fields oo = openowner((*stpp)->st_stateowner); 3477c0a5d93eSJ. Bruce Fields if (!oo->oo_confirmed) 3478c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 34793a4f98bbSNeilBrown return nfs_ok; 34801da177e4SLinus Torvalds } 34811da177e4SLinus Torvalds 3482b37ad28bSAl Viro __be32 3483ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3484a4f1706aSJ.Bruce Fields struct nfsd4_open_confirm *oc) 34851da177e4SLinus Torvalds { 3486b37ad28bSAl Viro __be32 status; 3487fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 34881da177e4SLinus Torvalds struct nfs4_stateid *stp; 34891da177e4SLinus Torvalds 34901da177e4SLinus Torvalds dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", 3491ca364317SJ.Bruce Fields (int)cstate->current_fh.fh_dentry->d_name.len, 3492ca364317SJ.Bruce Fields cstate->current_fh.fh_dentry->d_name.name); 34931da177e4SLinus Torvalds 3494ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 3495a8cddc5dSJ. Bruce Fields if (status) 3496a8cddc5dSJ. Bruce Fields return status; 34971da177e4SLinus Torvalds 34981da177e4SLinus Torvalds nfs4_lock_state(); 34991da177e4SLinus Torvalds 35009072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 3501ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 35022288d0e3SJ. Bruce Fields NFS4_OPEN_STID, &stp); 35039072d5c6SJ. Bruce Fields if (status) 35041da177e4SLinus Torvalds goto out; 3505fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 350668b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 3507fe0750e5SJ. Bruce Fields if (oo->oo_confirmed) 350868b66e82SJ. Bruce Fields goto out; 3509fe0750e5SJ. Bruce Fields oo->oo_confirmed = 1; 35101da177e4SLinus Torvalds update_stateid(&stp->st_stateid); 35111da177e4SLinus Torvalds memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t)); 35128c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 35138c10cbdbSBenny Halevy __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid)); 3514c7b9a459SNeilBrown 3515fe0750e5SJ. Bruce Fields nfsd4_create_clid_dir(oo->oo_owner.so_client); 351668b66e82SJ. Bruce Fields status = nfs_ok; 35171da177e4SLinus Torvalds out: 35185ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 35191da177e4SLinus Torvalds nfs4_unlock_state(); 35201da177e4SLinus Torvalds return status; 35211da177e4SLinus Torvalds } 35221da177e4SLinus Torvalds 3523f197c271SJ. Bruce Fields static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access) 35241da177e4SLinus Torvalds { 35251da177e4SLinus Torvalds int i; 3526f197c271SJ. Bruce Fields 35271da177e4SLinus Torvalds for (i = 1; i < 4; i++) { 3528f197c271SJ. Bruce Fields if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) { 3529f197c271SJ. Bruce Fields nfs4_file_put_access(stp->st_file, i); 3530f197c271SJ. Bruce Fields __clear_bit(i, &stp->st_access_bmap); 3531f197c271SJ. Bruce Fields } 35321da177e4SLinus Torvalds } 35331da177e4SLinus Torvalds } 35341da177e4SLinus Torvalds 35351da177e4SLinus Torvalds static void 35361da177e4SLinus Torvalds reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) 35371da177e4SLinus Torvalds { 35381da177e4SLinus Torvalds int i; 35391da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 35401da177e4SLinus Torvalds if ((i & deny) != i) 35411da177e4SLinus Torvalds __clear_bit(i, bmap); 35421da177e4SLinus Torvalds } 35431da177e4SLinus Torvalds } 35441da177e4SLinus Torvalds 3545b37ad28bSAl Viro __be32 3546ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 3547ca364317SJ.Bruce Fields struct nfsd4_compound_state *cstate, 3548a4f1706aSJ.Bruce Fields struct nfsd4_open_downgrade *od) 35491da177e4SLinus Torvalds { 3550b37ad28bSAl Viro __be32 status; 35511da177e4SLinus Torvalds struct nfs4_stateid *stp; 35521da177e4SLinus Torvalds 35531da177e4SLinus Torvalds dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", 3554ca364317SJ.Bruce Fields (int)cstate->current_fh.fh_dentry->d_name.len, 3555ca364317SJ.Bruce Fields cstate->current_fh.fh_dentry->d_name.name); 35561da177e4SLinus Torvalds 3557d87a8adeSAndy Adamson if (!access_valid(od->od_share_access, cstate->minorversion) 3558ba5a6a19SJ. Bruce Fields || !deny_valid(od->od_share_deny)) 35591da177e4SLinus Torvalds return nfserr_inval; 35601da177e4SLinus Torvalds 35611da177e4SLinus Torvalds nfs4_lock_state(); 3562c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 3563c0a5d93eSJ. Bruce Fields &od->od_stateid, &stp); 35649072d5c6SJ. Bruce Fields if (status) 35651da177e4SLinus Torvalds goto out; 35661da177e4SLinus Torvalds status = nfserr_inval; 35671da177e4SLinus Torvalds if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { 35681da177e4SLinus Torvalds dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", 35691da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 35701da177e4SLinus Torvalds goto out; 35711da177e4SLinus Torvalds } 35721da177e4SLinus Torvalds if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) { 35731da177e4SLinus Torvalds dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", 35741da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 35751da177e4SLinus Torvalds goto out; 35761da177e4SLinus Torvalds } 3577f197c271SJ. Bruce Fields nfs4_file_downgrade(stp, od->od_share_access); 35781da177e4SLinus Torvalds 35791da177e4SLinus Torvalds reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); 35801da177e4SLinus Torvalds 35811da177e4SLinus Torvalds update_stateid(&stp->st_stateid); 35821da177e4SLinus Torvalds memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); 35831da177e4SLinus Torvalds status = nfs_ok; 35841da177e4SLinus Torvalds out: 35855ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 35861da177e4SLinus Torvalds nfs4_unlock_state(); 35871da177e4SLinus Torvalds return status; 35881da177e4SLinus Torvalds } 35891da177e4SLinus Torvalds 35901da177e4SLinus Torvalds /* 35911da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 35921da177e4SLinus Torvalds */ 3593b37ad28bSAl Viro __be32 3594ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3595a4f1706aSJ.Bruce Fields struct nfsd4_close *close) 35961da177e4SLinus Torvalds { 3597b37ad28bSAl Viro __be32 status; 3598fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 35991da177e4SLinus Torvalds struct nfs4_stateid *stp; 36001da177e4SLinus Torvalds 36011da177e4SLinus Torvalds dprintk("NFSD: nfsd4_close on file %.*s\n", 3602ca364317SJ.Bruce Fields (int)cstate->current_fh.fh_dentry->d_name.len, 3603ca364317SJ.Bruce Fields cstate->current_fh.fh_dentry->d_name.name); 36041da177e4SLinus Torvalds 36051da177e4SLinus Torvalds nfs4_lock_state(); 36061da177e4SLinus Torvalds /* check close_lru for replay */ 3607c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, close->cl_seqid, 3608c0a5d93eSJ. Bruce Fields &close->cl_stateid, &stp); 3609f4dee24cSJ. Bruce Fields if (stp == NULL && status == nfserr_expired) { 3610f4dee24cSJ. Bruce Fields /* 3611f4dee24cSJ. Bruce Fields * Also, we should make sure this isn't just the result of 3612f4dee24cSJ. Bruce Fields * a replayed close: 3613f4dee24cSJ. Bruce Fields */ 3614fe0750e5SJ. Bruce Fields oo = search_close_lru(close->cl_stateid.si_stateownerid); 3615f4dee24cSJ. Bruce Fields /* It's not stale; let's assume it's expired: */ 3616fe0750e5SJ. Bruce Fields if (oo == NULL) 3617f4dee24cSJ. Bruce Fields goto out; 3618fe0750e5SJ. Bruce Fields cstate->replay_owner = &oo->oo_owner; 3619fe0750e5SJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, close->cl_seqid); 3620f4dee24cSJ. Bruce Fields if (status) 3621f4dee24cSJ. Bruce Fields goto out; 3622f4dee24cSJ. Bruce Fields status = nfserr_bad_seqid; 3623f4dee24cSJ. Bruce Fields } 36249072d5c6SJ. Bruce Fields if (status) 36251da177e4SLinus Torvalds goto out; 3626fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 36271da177e4SLinus Torvalds status = nfs_ok; 36281da177e4SLinus Torvalds update_stateid(&stp->st_stateid); 36291da177e4SLinus Torvalds memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); 36301da177e4SLinus Torvalds 363104ef5954SJ. Bruce Fields /* release_stateid() calls nfsd_close() if needed */ 36322283963fSJ. Bruce Fields release_open_stateid(stp); 363304ef5954SJ. Bruce Fields 363404ef5954SJ. Bruce Fields /* place unused nfs4_stateowners on so_close_lru list to be 363504ef5954SJ. Bruce Fields * released by the laundromat service after the lease period 363604ef5954SJ. Bruce Fields * to enable us to handle CLOSE replay 363704ef5954SJ. Bruce Fields */ 3638fe0750e5SJ. Bruce Fields if (list_empty(&oo->oo_owner.so_stateids)) 3639fe0750e5SJ. Bruce Fields move_to_close_lru(oo); 36401da177e4SLinus Torvalds out: 36415ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 36421da177e4SLinus Torvalds nfs4_unlock_state(); 36431da177e4SLinus Torvalds return status; 36441da177e4SLinus Torvalds } 36451da177e4SLinus Torvalds 3646b37ad28bSAl Viro __be32 3647ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3648ca364317SJ.Bruce Fields struct nfsd4_delegreturn *dr) 36491da177e4SLinus Torvalds { 3650203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 3651203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 3652203a8c8eSJ. Bruce Fields struct inode *inode; 3653b37ad28bSAl Viro __be32 status; 36541da177e4SLinus Torvalds 3655ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 3656203a8c8eSJ. Bruce Fields return status; 3657203a8c8eSJ. Bruce Fields inode = cstate->current_fh.fh_dentry->d_inode; 36581da177e4SLinus Torvalds 36591da177e4SLinus Torvalds nfs4_lock_state(); 3660203a8c8eSJ. Bruce Fields status = nfserr_bad_stateid; 3661203a8c8eSJ. Bruce Fields if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 3662203a8c8eSJ. Bruce Fields goto out; 3663203a8c8eSJ. Bruce Fields status = nfserr_stale_stateid; 3664203a8c8eSJ. Bruce Fields if (STALE_STATEID(stateid)) 3665203a8c8eSJ. Bruce Fields goto out; 36667e0f7cf5SJ. Bruce Fields status = nfserr_bad_stateid; 3667203a8c8eSJ. Bruce Fields if (!is_delegation_stateid(stateid)) 3668203a8c8eSJ. Bruce Fields goto out; 366933515142SJ. Bruce Fields status = nfserr_expired; 3670203a8c8eSJ. Bruce Fields dp = find_delegation_stateid(inode, stateid); 3671e4e83ea4SJ. Bruce Fields if (!dp) 3672203a8c8eSJ. Bruce Fields goto out; 367328dde241SJ. Bruce Fields status = check_stateid_generation(stateid, &dp->dl_stateid, nfsd4_has_session(cstate)); 3674203a8c8eSJ. Bruce Fields if (status) 3675203a8c8eSJ. Bruce Fields goto out; 3676203a8c8eSJ. Bruce Fields renew_client(dp->dl_client); 3677203a8c8eSJ. Bruce Fields 3678203a8c8eSJ. Bruce Fields unhash_delegation(dp); 36791da177e4SLinus Torvalds out: 3680203a8c8eSJ. Bruce Fields nfs4_unlock_state(); 3681203a8c8eSJ. Bruce Fields 36821da177e4SLinus Torvalds return status; 36831da177e4SLinus Torvalds } 36841da177e4SLinus Torvalds 36851da177e4SLinus Torvalds 36861da177e4SLinus Torvalds /* 36871da177e4SLinus Torvalds * Lock owner state (byte-range locks) 36881da177e4SLinus Torvalds */ 36891da177e4SLinus Torvalds #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) 36901da177e4SLinus Torvalds #define LOCK_HASH_BITS 8 36911da177e4SLinus Torvalds #define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS) 36921da177e4SLinus Torvalds #define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1) 36931da177e4SLinus Torvalds 369487df4de8SBenny Halevy static inline u64 369587df4de8SBenny Halevy end_offset(u64 start, u64 len) 369687df4de8SBenny Halevy { 369787df4de8SBenny Halevy u64 end; 369887df4de8SBenny Halevy 369987df4de8SBenny Halevy end = start + len; 370087df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 370187df4de8SBenny Halevy } 370287df4de8SBenny Halevy 370387df4de8SBenny Halevy /* last octet in a range */ 370487df4de8SBenny Halevy static inline u64 370587df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 370687df4de8SBenny Halevy { 370787df4de8SBenny Halevy u64 end; 370887df4de8SBenny Halevy 370987df4de8SBenny Halevy BUG_ON(!len); 371087df4de8SBenny Halevy end = start + len; 371187df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 371287df4de8SBenny Halevy } 371387df4de8SBenny Halevy 3714ddc04c41SJ. Bruce Fields static unsigned int lockownerid_hashval(u32 id) 3715ddc04c41SJ. Bruce Fields { 3716ddc04c41SJ. Bruce Fields return id & LOCK_HASH_MASK; 3717ddc04c41SJ. Bruce Fields } 37181da177e4SLinus Torvalds 37191da177e4SLinus Torvalds static inline unsigned int 37201da177e4SLinus Torvalds lock_ownerstr_hashval(struct inode *inode, u32 cl_id, 37211da177e4SLinus Torvalds struct xdr_netobj *ownername) 37221da177e4SLinus Torvalds { 37231da177e4SLinus Torvalds return (file_hashval(inode) + cl_id 37241da177e4SLinus Torvalds + opaque_hashval(ownername->data, ownername->len)) 37251da177e4SLinus Torvalds & LOCK_HASH_MASK; 37261da177e4SLinus Torvalds } 37271da177e4SLinus Torvalds 37281da177e4SLinus Torvalds static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; 37291da177e4SLinus Torvalds static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; 37301da177e4SLinus Torvalds 3731e1ca12dfSBryan Schumaker static struct nfs4_delegation * 3732e1ca12dfSBryan Schumaker search_for_delegation(stateid_t *stid) 3733e1ca12dfSBryan Schumaker { 3734e1ca12dfSBryan Schumaker struct nfs4_file *fp; 3735e1ca12dfSBryan Schumaker struct nfs4_delegation *dp; 3736e1ca12dfSBryan Schumaker struct list_head *pos; 3737e1ca12dfSBryan Schumaker int i; 3738e1ca12dfSBryan Schumaker 3739e1ca12dfSBryan Schumaker for (i = 0; i < FILE_HASH_SIZE; i++) { 3740e1ca12dfSBryan Schumaker list_for_each_entry(fp, &file_hashtbl[i], fi_hash) { 3741e1ca12dfSBryan Schumaker list_for_each(pos, &fp->fi_delegations) { 3742e1ca12dfSBryan Schumaker dp = list_entry(pos, struct nfs4_delegation, dl_perfile); 3743e1ca12dfSBryan Schumaker if (same_stateid(&dp->dl_stateid, stid)) 3744e1ca12dfSBryan Schumaker return dp; 3745e1ca12dfSBryan Schumaker } 3746e1ca12dfSBryan Schumaker } 3747e1ca12dfSBryan Schumaker } 3748e1ca12dfSBryan Schumaker return NULL; 3749e1ca12dfSBryan Schumaker } 3750e1ca12dfSBryan Schumaker 37511da177e4SLinus Torvalds static struct nfs4_delegation * 37521da177e4SLinus Torvalds find_delegation_stateid(struct inode *ino, stateid_t *stid) 37531da177e4SLinus Torvalds { 375413cd2184SNeilBrown struct nfs4_file *fp; 375513cd2184SNeilBrown struct nfs4_delegation *dl; 37561da177e4SLinus Torvalds 37578c10cbdbSBenny Halevy dprintk("NFSD: %s: stateid=" STATEID_FMT "\n", __func__, 37588c10cbdbSBenny Halevy STATEID_VAL(stid)); 37591da177e4SLinus Torvalds 37601da177e4SLinus Torvalds fp = find_file(ino); 376113cd2184SNeilBrown if (!fp) 37621da177e4SLinus Torvalds return NULL; 376313cd2184SNeilBrown dl = find_delegation_file(fp, stid); 376413cd2184SNeilBrown put_nfs4_file(fp); 376513cd2184SNeilBrown return dl; 37661da177e4SLinus Torvalds } 37671da177e4SLinus Torvalds 37681da177e4SLinus Torvalds /* 37691da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 37701da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 37711da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 37721da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 37731da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 37741da177e4SLinus Torvalds * the VFS, but this is a very deep change! 37751da177e4SLinus Torvalds */ 37761da177e4SLinus Torvalds static inline void 37771da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 37781da177e4SLinus Torvalds { 37791da177e4SLinus Torvalds if (lock->fl_start < 0) 37801da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 37811da177e4SLinus Torvalds if (lock->fl_end < 0) 37821da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 37831da177e4SLinus Torvalds } 37841da177e4SLinus Torvalds 3785d5b9026aSNeilBrown /* Hack!: For now, we're defining this just so we can use a pointer to it 3786d5b9026aSNeilBrown * as a unique cookie to identify our (NFSv4's) posix locks. */ 37877b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 3788d5b9026aSNeilBrown }; 37891da177e4SLinus Torvalds 37901da177e4SLinus Torvalds static inline void 37911da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 37921da177e4SLinus Torvalds { 3793fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 37941da177e4SLinus Torvalds 3795d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 3796fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 3797fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 3798fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 37997c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 38007c13f344SJ. Bruce Fields /* We just don't care that much */ 38017c13f344SJ. Bruce Fields goto nevermind; 3802fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 3803fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 3804d5b9026aSNeilBrown } else { 38057c13f344SJ. Bruce Fields nevermind: 38067c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 38077c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 3808d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 3809d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 38101da177e4SLinus Torvalds } 38111da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 381287df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 381387df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 38141da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 38151da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 38161da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 38171da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 38181da177e4SLinus Torvalds } 38191da177e4SLinus Torvalds 3820fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 3821fe0750e5SJ. Bruce Fields find_lockowner_str(struct inode *inode, clientid_t *clid, 38221da177e4SLinus Torvalds struct xdr_netobj *owner) 38231da177e4SLinus Torvalds { 38241da177e4SLinus Torvalds unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner); 38251da177e4SLinus Torvalds struct nfs4_stateowner *op; 38261da177e4SLinus Torvalds 38271da177e4SLinus Torvalds list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { 3828599e0a22SJ. Bruce Fields if (same_owner_str(op, owner, clid)) 3829fe0750e5SJ. Bruce Fields return lockowner(op); 38301da177e4SLinus Torvalds } 38311da177e4SLinus Torvalds return NULL; 38321da177e4SLinus Torvalds } 38331da177e4SLinus Torvalds 3834fe0750e5SJ. Bruce Fields static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp) 3835ff194bd9SJ. Bruce Fields { 3836ff194bd9SJ. Bruce Fields unsigned int idhashval; 3837ff194bd9SJ. Bruce Fields 3838fe0750e5SJ. Bruce Fields idhashval = lockownerid_hashval(lo->lo_owner.so_id); 3839fe0750e5SJ. Bruce Fields list_add(&lo->lo_owner.so_idhash, &lock_ownerid_hashtbl[idhashval]); 3840fe0750e5SJ. Bruce Fields list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]); 3841fe0750e5SJ. Bruce Fields list_add(&lo->lo_perstateid, &open_stp->st_lockowners); 3842ff194bd9SJ. Bruce Fields } 3843ff194bd9SJ. Bruce Fields 38441da177e4SLinus Torvalds /* 38451da177e4SLinus Torvalds * Alloc a lock owner structure. 38461da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 384725985edcSLucas De Marchi * occurred. 38481da177e4SLinus Torvalds * 38491da177e4SLinus Torvalds * strhashval = lock_ownerstr_hashval 38501da177e4SLinus Torvalds */ 38511da177e4SLinus Torvalds 3852fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 38531da177e4SLinus Torvalds alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) { 3854fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 38551da177e4SLinus Torvalds 3856fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 3857fe0750e5SJ. Bruce Fields if (!lo) 38581da177e4SLinus Torvalds return NULL; 3859fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 3860fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 3861b59e3c0eSNeil Brown /* It is the openowner seqid that will be incremented in encode in the 3862b59e3c0eSNeil Brown * case of new lockowners; so increment the lock seqid manually: */ 3863fe0750e5SJ. Bruce Fields lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1; 3864fe0750e5SJ. Bruce Fields hash_lockowner(lo, strhashval, clp, open_stp); 3865fe0750e5SJ. Bruce Fields return lo; 38661da177e4SLinus Torvalds } 38671da177e4SLinus Torvalds 3868fd39ca9aSNeilBrown static struct nfs4_stateid * 3869fe0750e5SJ. Bruce Fields alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_stateid *open_stp) 38701da177e4SLinus Torvalds { 38711da177e4SLinus Torvalds struct nfs4_stateid *stp; 3872fe0750e5SJ. Bruce Fields unsigned int hashval = stateid_hashval(lo->lo_owner.so_id, fp->fi_id); 38731da177e4SLinus Torvalds 38745ac049acSNeilBrown stp = nfs4_alloc_stateid(); 38755ac049acSNeilBrown if (stp == NULL) 38761da177e4SLinus Torvalds goto out; 38771da177e4SLinus Torvalds INIT_LIST_HEAD(&stp->st_hash); 38781da177e4SLinus Torvalds INIT_LIST_HEAD(&stp->st_perfile); 3879ea1da636SNeilBrown INIT_LIST_HEAD(&stp->st_perstateowner); 3880ea1da636SNeilBrown INIT_LIST_HEAD(&stp->st_lockowners); /* not used */ 3881b79abaddSJ. Bruce Fields list_add(&stp->st_hash, &stateid_hashtbl[hashval]); 38828beefa24SNeilBrown list_add(&stp->st_perfile, &fp->fi_stateids); 3883fe0750e5SJ. Bruce Fields list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 3884fe0750e5SJ. Bruce Fields stp->st_stateowner = &lo->lo_owner; 38855fa0bbb4SJ. Bruce Fields stp->st_type = NFS4_LOCK_STID; 388613cd2184SNeilBrown get_nfs4_file(fp); 38871da177e4SLinus Torvalds stp->st_file = fp; 3888e4e83ea4SJ. Bruce Fields stp->st_stateid.si_boot = boot_time; 3889fe0750e5SJ. Bruce Fields stp->st_stateid.si_stateownerid = lo->lo_owner.so_id; 38901da177e4SLinus Torvalds stp->st_stateid.si_fileid = fp->fi_id; 389173997dc4SJ. Bruce Fields /* note will be incremented before first return to client: */ 38921da177e4SLinus Torvalds stp->st_stateid.si_generation = 0; 38930997b173SJ. Bruce Fields stp->st_access_bmap = 0; 38941da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 38954c4cd222SNeilBrown stp->st_openstp = open_stp; 38961da177e4SLinus Torvalds 38971da177e4SLinus Torvalds out: 38981da177e4SLinus Torvalds return stp; 38991da177e4SLinus Torvalds } 39001da177e4SLinus Torvalds 3901fd39ca9aSNeilBrown static int 39021da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 39031da177e4SLinus Torvalds { 390487df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 39051da177e4SLinus Torvalds LOFF_OVERFLOW(offset, length))); 39061da177e4SLinus Torvalds } 39071da177e4SLinus Torvalds 39080997b173SJ. Bruce Fields static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access) 39090997b173SJ. Bruce Fields { 39100997b173SJ. Bruce Fields struct nfs4_file *fp = lock_stp->st_file; 39110997b173SJ. Bruce Fields int oflag = nfs4_access_to_omode(access); 39120997b173SJ. Bruce Fields 39130997b173SJ. Bruce Fields if (test_bit(access, &lock_stp->st_access_bmap)) 39140997b173SJ. Bruce Fields return; 39150997b173SJ. Bruce Fields nfs4_file_get_access(fp, oflag); 39160997b173SJ. Bruce Fields __set_bit(access, &lock_stp->st_access_bmap); 39170997b173SJ. Bruce Fields } 39180997b173SJ. Bruce Fields 39191da177e4SLinus Torvalds /* 39201da177e4SLinus Torvalds * LOCK operation 39211da177e4SLinus Torvalds */ 3922b37ad28bSAl Viro __be32 3923ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3924a4f1706aSJ.Bruce Fields struct nfsd4_lock *lock) 39251da177e4SLinus Torvalds { 3926fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 3927fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 39281da177e4SLinus Torvalds struct nfs4_stateid *lock_stp; 39297d947842SJ. Bruce Fields struct nfs4_file *fp; 39307d947842SJ. Bruce Fields struct file *filp = NULL; 39311da177e4SLinus Torvalds struct file_lock file_lock; 39328dc7c311SAndy Adamson struct file_lock conflock; 3933b37ad28bSAl Viro __be32 status = 0; 39341da177e4SLinus Torvalds unsigned int strhashval; 3935b34f27aaSJ. Bruce Fields int lkflg; 3936b8dd7b9aSAl Viro int err; 39371da177e4SLinus Torvalds 39381da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 39391da177e4SLinus Torvalds (long long) lock->lk_offset, 39401da177e4SLinus Torvalds (long long) lock->lk_length); 39411da177e4SLinus Torvalds 39421da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 39431da177e4SLinus Torvalds return nfserr_inval; 39441da177e4SLinus Torvalds 3945ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 39468837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 3947a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 3948a6f6ef2fSAndy Adamson return status; 3949a6f6ef2fSAndy Adamson } 3950a6f6ef2fSAndy Adamson 39511da177e4SLinus Torvalds nfs4_lock_state(); 39521da177e4SLinus Torvalds 39531da177e4SLinus Torvalds if (lock->lk_is_new) { 39541da177e4SLinus Torvalds /* 39551da177e4SLinus Torvalds * Client indicates that this is a new lockowner. 3956893f8770SNeilBrown * Use open owner and open stateid to create lock owner and 3957893f8770SNeilBrown * lock stateid. 39581da177e4SLinus Torvalds */ 39591da177e4SLinus Torvalds struct nfs4_stateid *open_stp = NULL; 39601da177e4SLinus Torvalds 39611da177e4SLinus Torvalds status = nfserr_stale_clientid; 396260adfc50SAndy Adamson if (!nfsd4_has_session(cstate) && 396360adfc50SAndy Adamson STALE_CLIENTID(&lock->lk_new_clientid)) 39641da177e4SLinus Torvalds goto out; 39651da177e4SLinus Torvalds 39661da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 3967c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 39681da177e4SLinus Torvalds lock->lk_new_open_seqid, 39691da177e4SLinus Torvalds &lock->lk_new_open_stateid, 3970c0a5d93eSJ. Bruce Fields &open_stp); 397137515177SNeilBrown if (status) 39721da177e4SLinus Torvalds goto out; 3973fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 3974b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 3975b34f27aaSJ. Bruce Fields if (!nfsd4_has_session(cstate) && 3976fe0750e5SJ. Bruce Fields !same_clid(&open_sop->oo_owner.so_client->cl_clientid, 3977b34f27aaSJ. Bruce Fields &lock->v.new.clientid)) 3978b34f27aaSJ. Bruce Fields goto out; 39791da177e4SLinus Torvalds /* create lockowner and lock stateid */ 39801da177e4SLinus Torvalds fp = open_stp->st_file; 39811da177e4SLinus Torvalds strhashval = lock_ownerstr_hashval(fp->fi_inode, 3982fe0750e5SJ. Bruce Fields open_sop->oo_owner.so_client->cl_clientid.cl_id, 39831da177e4SLinus Torvalds &lock->v.new.owner); 39843e9e3dbeSNeilBrown /* XXX: Do we need to check for duplicate stateowners on 39853e9e3dbeSNeilBrown * the same file, or should they just be allowed (and 39863e9e3dbeSNeilBrown * create new stateids)? */ 39873e772463SJ. Bruce Fields status = nfserr_jukebox; 3988b59e3c0eSNeil Brown lock_sop = alloc_init_lock_stateowner(strhashval, 3989fe0750e5SJ. Bruce Fields open_sop->oo_owner.so_client, open_stp, lock); 3990b59e3c0eSNeil Brown if (lock_sop == NULL) 39911da177e4SLinus Torvalds goto out; 3992b59e3c0eSNeil Brown lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); 39938a280510SJ. Bruce Fields if (lock_stp == NULL) 39941da177e4SLinus Torvalds goto out; 39951da177e4SLinus Torvalds } else { 39961da177e4SLinus Torvalds /* lock (lock owner + lock stateid) already exists */ 3997dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 39981da177e4SLinus Torvalds lock->lk_old_lock_seqid, 39991da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 40002288d0e3SJ. Bruce Fields NFS4_LOCK_STID, &lock_stp); 40011da177e4SLinus Torvalds if (status) 40021da177e4SLinus Torvalds goto out; 4003fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 40047d947842SJ. Bruce Fields fp = lock_stp->st_file; 40051da177e4SLinus Torvalds } 40069072d5c6SJ. Bruce Fields /* lock_sop and lock_stp have been created or found */ 40071da177e4SLinus Torvalds 4008b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 4009b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 4010b34f27aaSJ. Bruce Fields if (status) 4011b34f27aaSJ. Bruce Fields goto out; 4012b34f27aaSJ. Bruce Fields 40130dd395dcSNeilBrown status = nfserr_grace; 4014af558e33SJ. Bruce Fields if (locks_in_grace() && !lock->lk_reclaim) 40150dd395dcSNeilBrown goto out; 40160dd395dcSNeilBrown status = nfserr_no_grace; 4017af558e33SJ. Bruce Fields if (!locks_in_grace() && lock->lk_reclaim) 40180dd395dcSNeilBrown goto out; 40190dd395dcSNeilBrown 40201da177e4SLinus Torvalds locks_init_lock(&file_lock); 40211da177e4SLinus Torvalds switch (lock->lk_type) { 40221da177e4SLinus Torvalds case NFS4_READ_LT: 40231da177e4SLinus Torvalds case NFS4_READW_LT: 4024f9d7562fSJ. Bruce Fields filp = find_readable_file(lock_stp->st_file); 40250997b173SJ. Bruce Fields if (filp) 40260997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 40271da177e4SLinus Torvalds file_lock.fl_type = F_RDLCK; 40281da177e4SLinus Torvalds break; 40291da177e4SLinus Torvalds case NFS4_WRITE_LT: 40301da177e4SLinus Torvalds case NFS4_WRITEW_LT: 4031f9d7562fSJ. Bruce Fields filp = find_writeable_file(lock_stp->st_file); 40320997b173SJ. Bruce Fields if (filp) 40330997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 40341da177e4SLinus Torvalds file_lock.fl_type = F_WRLCK; 40351da177e4SLinus Torvalds break; 40361da177e4SLinus Torvalds default: 40371da177e4SLinus Torvalds status = nfserr_inval; 40381da177e4SLinus Torvalds goto out; 40391da177e4SLinus Torvalds } 4040f9d7562fSJ. Bruce Fields if (!filp) { 4041f9d7562fSJ. Bruce Fields status = nfserr_openmode; 4042f9d7562fSJ. Bruce Fields goto out; 4043f9d7562fSJ. Bruce Fields } 4044b59e3c0eSNeil Brown file_lock.fl_owner = (fl_owner_t)lock_sop; 40451da177e4SLinus Torvalds file_lock.fl_pid = current->tgid; 40461da177e4SLinus Torvalds file_lock.fl_file = filp; 40471da177e4SLinus Torvalds file_lock.fl_flags = FL_POSIX; 4048d5b9026aSNeilBrown file_lock.fl_lmops = &nfsd_posix_mng_ops; 40491da177e4SLinus Torvalds 40501da177e4SLinus Torvalds file_lock.fl_start = lock->lk_offset; 405187df4de8SBenny Halevy file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 40521da177e4SLinus Torvalds nfs4_transform_lock_offset(&file_lock); 40531da177e4SLinus Torvalds 40541da177e4SLinus Torvalds /* 40551da177e4SLinus Torvalds * Try to lock the file in the VFS. 40561da177e4SLinus Torvalds * Note: locks.c uses the BKL to protect the inode's lock list. 40571da177e4SLinus Torvalds */ 40581da177e4SLinus Torvalds 4059529d7b2aSJ. Bruce Fields err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); 4060b8dd7b9aSAl Viro switch (-err) { 40611da177e4SLinus Torvalds case 0: /* success! */ 40621da177e4SLinus Torvalds update_stateid(&lock_stp->st_stateid); 40631da177e4SLinus Torvalds memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, 40641da177e4SLinus Torvalds sizeof(stateid_t)); 4065b8dd7b9aSAl Viro status = 0; 4066eb76b3fdSAndy Adamson break; 4067eb76b3fdSAndy Adamson case (EAGAIN): /* conflock holds conflicting lock */ 4068eb76b3fdSAndy Adamson status = nfserr_denied; 4069eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 4070eb76b3fdSAndy Adamson nfs4_set_lock_denied(&conflock, &lock->lk_denied); 4071eb76b3fdSAndy Adamson break; 40721da177e4SLinus Torvalds case (EDEADLK): 40731da177e4SLinus Torvalds status = nfserr_deadlock; 4074eb76b3fdSAndy Adamson break; 40751da177e4SLinus Torvalds default: 4076fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 40773e772463SJ. Bruce Fields status = nfserrno(err); 4078eb76b3fdSAndy Adamson break; 40791da177e4SLinus Torvalds } 40801da177e4SLinus Torvalds out: 40818a280510SJ. Bruce Fields if (status && lock->lk_is_new && lock_sop) 4082f044ff83SJ. Bruce Fields release_lockowner(lock_sop); 40835ec094c1SJ. Bruce Fields if (!cstate->replay_owner) 40841da177e4SLinus Torvalds nfs4_unlock_state(); 40851da177e4SLinus Torvalds return status; 40861da177e4SLinus Torvalds } 40871da177e4SLinus Torvalds 40881da177e4SLinus Torvalds /* 408955ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 409055ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 409155ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 409255ef1274SJ. Bruce Fields * inode operation.) 409355ef1274SJ. Bruce Fields */ 409455ef1274SJ. Bruce Fields static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 409555ef1274SJ. Bruce Fields { 409655ef1274SJ. Bruce Fields struct file *file; 409755ef1274SJ. Bruce Fields int err; 409855ef1274SJ. Bruce Fields 409955ef1274SJ. Bruce Fields err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 410055ef1274SJ. Bruce Fields if (err) 410155ef1274SJ. Bruce Fields return err; 410255ef1274SJ. Bruce Fields err = vfs_test_lock(file, lock); 410355ef1274SJ. Bruce Fields nfsd_close(file); 410455ef1274SJ. Bruce Fields return err; 410555ef1274SJ. Bruce Fields } 410655ef1274SJ. Bruce Fields 410755ef1274SJ. Bruce Fields /* 41081da177e4SLinus Torvalds * LOCKT operation 41091da177e4SLinus Torvalds */ 4110b37ad28bSAl Viro __be32 4111ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4112ca364317SJ.Bruce Fields struct nfsd4_lockt *lockt) 41131da177e4SLinus Torvalds { 41141da177e4SLinus Torvalds struct inode *inode; 41151da177e4SLinus Torvalds struct file_lock file_lock; 4116fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 4117fd85b817SMarc Eshel int error; 4118b37ad28bSAl Viro __be32 status; 41191da177e4SLinus Torvalds 4120af558e33SJ. Bruce Fields if (locks_in_grace()) 41211da177e4SLinus Torvalds return nfserr_grace; 41221da177e4SLinus Torvalds 41231da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 41241da177e4SLinus Torvalds return nfserr_inval; 41251da177e4SLinus Torvalds 41261da177e4SLinus Torvalds nfs4_lock_state(); 41271da177e4SLinus Torvalds 41281da177e4SLinus Torvalds status = nfserr_stale_clientid; 412960adfc50SAndy Adamson if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid)) 41301da177e4SLinus Torvalds goto out; 41311da177e4SLinus Torvalds 413275c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 41331da177e4SLinus Torvalds goto out; 41341da177e4SLinus Torvalds 4135ca364317SJ.Bruce Fields inode = cstate->current_fh.fh_dentry->d_inode; 41361da177e4SLinus Torvalds locks_init_lock(&file_lock); 41371da177e4SLinus Torvalds switch (lockt->lt_type) { 41381da177e4SLinus Torvalds case NFS4_READ_LT: 41391da177e4SLinus Torvalds case NFS4_READW_LT: 41401da177e4SLinus Torvalds file_lock.fl_type = F_RDLCK; 41411da177e4SLinus Torvalds break; 41421da177e4SLinus Torvalds case NFS4_WRITE_LT: 41431da177e4SLinus Torvalds case NFS4_WRITEW_LT: 41441da177e4SLinus Torvalds file_lock.fl_type = F_WRLCK; 41451da177e4SLinus Torvalds break; 41461da177e4SLinus Torvalds default: 41472fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 41481da177e4SLinus Torvalds status = nfserr_inval; 41491da177e4SLinus Torvalds goto out; 41501da177e4SLinus Torvalds } 41511da177e4SLinus Torvalds 4152fe0750e5SJ. Bruce Fields lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); 4153fe0750e5SJ. Bruce Fields if (lo) 4154fe0750e5SJ. Bruce Fields file_lock.fl_owner = (fl_owner_t)lo; 41551da177e4SLinus Torvalds file_lock.fl_pid = current->tgid; 41561da177e4SLinus Torvalds file_lock.fl_flags = FL_POSIX; 41571da177e4SLinus Torvalds 41581da177e4SLinus Torvalds file_lock.fl_start = lockt->lt_offset; 415987df4de8SBenny Halevy file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 41601da177e4SLinus Torvalds 41611da177e4SLinus Torvalds nfs4_transform_lock_offset(&file_lock); 41621da177e4SLinus Torvalds 41631da177e4SLinus Torvalds status = nfs_ok; 416455ef1274SJ. Bruce Fields error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); 4165fd85b817SMarc Eshel if (error) { 4166fd85b817SMarc Eshel status = nfserrno(error); 4167fd85b817SMarc Eshel goto out; 4168fd85b817SMarc Eshel } 41699d6a8c5cSMarc Eshel if (file_lock.fl_type != F_UNLCK) { 41701da177e4SLinus Torvalds status = nfserr_denied; 41719d6a8c5cSMarc Eshel nfs4_set_lock_denied(&file_lock, &lockt->lt_denied); 41721da177e4SLinus Torvalds } 41731da177e4SLinus Torvalds out: 41741da177e4SLinus Torvalds nfs4_unlock_state(); 41751da177e4SLinus Torvalds return status; 41761da177e4SLinus Torvalds } 41771da177e4SLinus Torvalds 4178b37ad28bSAl Viro __be32 4179ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4180a4f1706aSJ.Bruce Fields struct nfsd4_locku *locku) 41811da177e4SLinus Torvalds { 41821da177e4SLinus Torvalds struct nfs4_stateid *stp; 41831da177e4SLinus Torvalds struct file *filp = NULL; 41841da177e4SLinus Torvalds struct file_lock file_lock; 4185b37ad28bSAl Viro __be32 status; 4186b8dd7b9aSAl Viro int err; 41871da177e4SLinus Torvalds 41881da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 41891da177e4SLinus Torvalds (long long) locku->lu_offset, 41901da177e4SLinus Torvalds (long long) locku->lu_length); 41911da177e4SLinus Torvalds 41921da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 41931da177e4SLinus Torvalds return nfserr_inval; 41941da177e4SLinus Torvalds 41951da177e4SLinus Torvalds nfs4_lock_state(); 41961da177e4SLinus Torvalds 41979072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 41982288d0e3SJ. Bruce Fields &locku->lu_stateid, NFS4_LOCK_STID, &stp); 41999072d5c6SJ. Bruce Fields if (status) 42001da177e4SLinus Torvalds goto out; 4201f9d7562fSJ. Bruce Fields filp = find_any_file(stp->st_file); 4202f9d7562fSJ. Bruce Fields if (!filp) { 4203f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 4204f9d7562fSJ. Bruce Fields goto out; 4205f9d7562fSJ. Bruce Fields } 42061da177e4SLinus Torvalds BUG_ON(!filp); 42071da177e4SLinus Torvalds locks_init_lock(&file_lock); 42081da177e4SLinus Torvalds file_lock.fl_type = F_UNLCK; 4209fe0750e5SJ. Bruce Fields file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); 42101da177e4SLinus Torvalds file_lock.fl_pid = current->tgid; 42111da177e4SLinus Torvalds file_lock.fl_file = filp; 42121da177e4SLinus Torvalds file_lock.fl_flags = FL_POSIX; 4213d5b9026aSNeilBrown file_lock.fl_lmops = &nfsd_posix_mng_ops; 42141da177e4SLinus Torvalds file_lock.fl_start = locku->lu_offset; 42151da177e4SLinus Torvalds 421687df4de8SBenny Halevy file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length); 42171da177e4SLinus Torvalds nfs4_transform_lock_offset(&file_lock); 42181da177e4SLinus Torvalds 42191da177e4SLinus Torvalds /* 42201da177e4SLinus Torvalds * Try to unlock the file in the VFS. 42211da177e4SLinus Torvalds */ 4222fd85b817SMarc Eshel err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); 4223b8dd7b9aSAl Viro if (err) { 4224fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 42251da177e4SLinus Torvalds goto out_nfserr; 42261da177e4SLinus Torvalds } 42271da177e4SLinus Torvalds /* 42281da177e4SLinus Torvalds * OK, unlock succeeded; the only thing left to do is update the stateid. 42291da177e4SLinus Torvalds */ 42301da177e4SLinus Torvalds update_stateid(&stp->st_stateid); 42311da177e4SLinus Torvalds memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); 42321da177e4SLinus Torvalds 42331da177e4SLinus Torvalds out: 42341da177e4SLinus Torvalds nfs4_unlock_state(); 42351da177e4SLinus Torvalds return status; 42361da177e4SLinus Torvalds 42371da177e4SLinus Torvalds out_nfserr: 4238b8dd7b9aSAl Viro status = nfserrno(err); 42391da177e4SLinus Torvalds goto out; 42401da177e4SLinus Torvalds } 42411da177e4SLinus Torvalds 42421da177e4SLinus Torvalds /* 42431da177e4SLinus Torvalds * returns 42441da177e4SLinus Torvalds * 1: locks held by lockowner 42451da177e4SLinus Torvalds * 0: no locks held by lockowner 42461da177e4SLinus Torvalds */ 42471da177e4SLinus Torvalds static int 4248fe0750e5SJ. Bruce Fields check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) 42491da177e4SLinus Torvalds { 42501da177e4SLinus Torvalds struct file_lock **flpp; 4251f9d7562fSJ. Bruce Fields struct inode *inode = filp->fi_inode; 42521da177e4SLinus Torvalds int status = 0; 42531da177e4SLinus Torvalds 4254b89f4321SArnd Bergmann lock_flocks(); 42551da177e4SLinus Torvalds for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { 4256796dadfdSJ. Bruce Fields if ((*flpp)->fl_owner == (fl_owner_t)lowner) { 42571da177e4SLinus Torvalds status = 1; 42581da177e4SLinus Torvalds goto out; 42591da177e4SLinus Torvalds } 4260796dadfdSJ. Bruce Fields } 42611da177e4SLinus Torvalds out: 4262b89f4321SArnd Bergmann unlock_flocks(); 42631da177e4SLinus Torvalds return status; 42641da177e4SLinus Torvalds } 42651da177e4SLinus Torvalds 4266b37ad28bSAl Viro __be32 4267b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 4268b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 4269b591480bSJ.Bruce Fields struct nfsd4_release_lockowner *rlockowner) 42701da177e4SLinus Torvalds { 42711da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 42723e9e3dbeSNeilBrown struct nfs4_stateowner *sop; 4273fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 42743e9e3dbeSNeilBrown struct nfs4_stateid *stp; 42751da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 42763e9e3dbeSNeilBrown struct list_head matches; 42773e9e3dbeSNeilBrown int i; 4278b37ad28bSAl Viro __be32 status; 42791da177e4SLinus Torvalds 42801da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 42811da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 42821da177e4SLinus Torvalds 42831da177e4SLinus Torvalds /* XXX check for lease expiration */ 42841da177e4SLinus Torvalds 42851da177e4SLinus Torvalds status = nfserr_stale_clientid; 4286849823c5SNeil Brown if (STALE_CLIENTID(clid)) 42871da177e4SLinus Torvalds return status; 42881da177e4SLinus Torvalds 42891da177e4SLinus Torvalds nfs4_lock_state(); 42901da177e4SLinus Torvalds 42911da177e4SLinus Torvalds status = nfserr_locks_held; 42923e9e3dbeSNeilBrown /* XXX: we're doing a linear search through all the lockowners. 42933e9e3dbeSNeilBrown * Yipes! For now we'll just hope clients aren't really using 42943e9e3dbeSNeilBrown * release_lockowner much, but eventually we have to fix these 42953e9e3dbeSNeilBrown * data structures. */ 42963e9e3dbeSNeilBrown INIT_LIST_HEAD(&matches); 42973e9e3dbeSNeilBrown for (i = 0; i < LOCK_HASH_SIZE; i++) { 42983e9e3dbeSNeilBrown list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) { 4299599e0a22SJ. Bruce Fields if (!same_owner_str(sop, owner, clid)) 43003e9e3dbeSNeilBrown continue; 43013e9e3dbeSNeilBrown list_for_each_entry(stp, &sop->so_stateids, 4302ea1da636SNeilBrown st_perstateowner) { 4303fe0750e5SJ. Bruce Fields lo = lockowner(sop); 4304fe0750e5SJ. Bruce Fields if (check_for_locks(stp->st_file, lo)) 43051da177e4SLinus Torvalds goto out; 4306fe0750e5SJ. Bruce Fields list_add(&lo->lo_list, &matches); 43071da177e4SLinus Torvalds } 43083e9e3dbeSNeilBrown } 43093e9e3dbeSNeilBrown } 43103e9e3dbeSNeilBrown /* Clients probably won't expect us to return with some (but not all) 43113e9e3dbeSNeilBrown * of the lockowner state released; so don't release any until all 43123e9e3dbeSNeilBrown * have been checked. */ 43131da177e4SLinus Torvalds status = nfs_ok; 43140fa822e4SNeilBrown while (!list_empty(&matches)) { 4315fe0750e5SJ. Bruce Fields lo = list_entry(matches.next, struct nfs4_lockowner, 4316fe0750e5SJ. Bruce Fields lo_list); 43170fa822e4SNeilBrown /* unhash_stateowner deletes so_perclient only 43180fa822e4SNeilBrown * for openowners. */ 4319fe0750e5SJ. Bruce Fields list_del(&lo->lo_list); 4320fe0750e5SJ. Bruce Fields release_lockowner(lo); 43211da177e4SLinus Torvalds } 43221da177e4SLinus Torvalds out: 43231da177e4SLinus Torvalds nfs4_unlock_state(); 43241da177e4SLinus Torvalds return status; 43251da177e4SLinus Torvalds } 43261da177e4SLinus Torvalds 43271da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 4328a55370a3SNeilBrown alloc_reclaim(void) 43291da177e4SLinus Torvalds { 4330a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 43311da177e4SLinus Torvalds } 43321da177e4SLinus Torvalds 4333c7b9a459SNeilBrown int 4334a1bcecd2SAndy Adamson nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) 4335c7b9a459SNeilBrown { 4336c7b9a459SNeilBrown unsigned int strhashval = clientstr_hashval(name); 4337c7b9a459SNeilBrown struct nfs4_client *clp; 4338c7b9a459SNeilBrown 4339e203d506SJ. Bruce Fields clp = find_confirmed_client_by_str(name, strhashval); 4340c7b9a459SNeilBrown return clp ? 1 : 0; 4341c7b9a459SNeilBrown } 4342c7b9a459SNeilBrown 43431da177e4SLinus Torvalds /* 43441da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 43451da177e4SLinus Torvalds */ 4346190e4fbfSNeilBrown int 4347190e4fbfSNeilBrown nfs4_client_to_reclaim(const char *name) 43481da177e4SLinus Torvalds { 43491da177e4SLinus Torvalds unsigned int strhashval; 43501da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 43511da177e4SLinus Torvalds 4352a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 4353a55370a3SNeilBrown crp = alloc_reclaim(); 43541da177e4SLinus Torvalds if (!crp) 43551da177e4SLinus Torvalds return 0; 4356a55370a3SNeilBrown strhashval = clientstr_hashval(name); 43571da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 43581da177e4SLinus Torvalds list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); 4359a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 43601da177e4SLinus Torvalds reclaim_str_hashtbl_size++; 43611da177e4SLinus Torvalds return 1; 43621da177e4SLinus Torvalds } 43631da177e4SLinus Torvalds 43641da177e4SLinus Torvalds static void 43651da177e4SLinus Torvalds nfs4_release_reclaim(void) 43661da177e4SLinus Torvalds { 43671da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 43681da177e4SLinus Torvalds int i; 43691da177e4SLinus Torvalds 43701da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 43711da177e4SLinus Torvalds while (!list_empty(&reclaim_str_hashtbl[i])) { 43721da177e4SLinus Torvalds crp = list_entry(reclaim_str_hashtbl[i].next, 43731da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 43741da177e4SLinus Torvalds list_del(&crp->cr_strhash); 43751da177e4SLinus Torvalds kfree(crp); 43761da177e4SLinus Torvalds reclaim_str_hashtbl_size--; 43771da177e4SLinus Torvalds } 43781da177e4SLinus Torvalds } 43791da177e4SLinus Torvalds BUG_ON(reclaim_str_hashtbl_size); 43801da177e4SLinus Torvalds } 43811da177e4SLinus Torvalds 43821da177e4SLinus Torvalds /* 43831da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 4384fd39ca9aSNeilBrown static struct nfs4_client_reclaim * 43851da177e4SLinus Torvalds nfs4_find_reclaim_client(clientid_t *clid) 43861da177e4SLinus Torvalds { 43871da177e4SLinus Torvalds unsigned int strhashval; 43881da177e4SLinus Torvalds struct nfs4_client *clp; 43891da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 43901da177e4SLinus Torvalds 43911da177e4SLinus Torvalds 43921da177e4SLinus Torvalds /* find clientid in conf_id_hashtbl */ 43931da177e4SLinus Torvalds clp = find_confirmed_client(clid); 43941da177e4SLinus Torvalds if (clp == NULL) 43951da177e4SLinus Torvalds return NULL; 43961da177e4SLinus Torvalds 4397a55370a3SNeilBrown dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", 4398a55370a3SNeilBrown clp->cl_name.len, clp->cl_name.data, 4399a55370a3SNeilBrown clp->cl_recdir); 44001da177e4SLinus Torvalds 44011da177e4SLinus Torvalds /* find clp->cl_name in reclaim_str_hashtbl */ 4402a55370a3SNeilBrown strhashval = clientstr_hashval(clp->cl_recdir); 44031da177e4SLinus Torvalds list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { 4404a55370a3SNeilBrown if (same_name(crp->cr_recdir, clp->cl_recdir)) { 44051da177e4SLinus Torvalds return crp; 44061da177e4SLinus Torvalds } 44071da177e4SLinus Torvalds } 44081da177e4SLinus Torvalds return NULL; 44091da177e4SLinus Torvalds } 44101da177e4SLinus Torvalds 44111da177e4SLinus Torvalds /* 44121da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 44131da177e4SLinus Torvalds */ 4414b37ad28bSAl Viro __be32 44151da177e4SLinus Torvalds nfs4_check_open_reclaim(clientid_t *clid) 44161da177e4SLinus Torvalds { 4417dfc83565SNeilBrown return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; 44181da177e4SLinus Torvalds } 44191da177e4SLinus Torvalds 4420ac4d8ff2SNeilBrown /* initialization to perform at module load time: */ 44211da177e4SLinus Torvalds 4422e8ff2a84SJ. Bruce Fields int 4423ac4d8ff2SNeilBrown nfs4_state_init(void) 44241da177e4SLinus Torvalds { 4425e8ff2a84SJ. Bruce Fields int i, status; 44261da177e4SLinus Torvalds 4427e8ff2a84SJ. Bruce Fields status = nfsd4_init_slabs(); 4428e8ff2a84SJ. Bruce Fields if (status) 4429e8ff2a84SJ. Bruce Fields return status; 44301da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 44311da177e4SLinus Torvalds INIT_LIST_HEAD(&conf_id_hashtbl[i]); 44321da177e4SLinus Torvalds INIT_LIST_HEAD(&conf_str_hashtbl[i]); 44331da177e4SLinus Torvalds INIT_LIST_HEAD(&unconf_str_hashtbl[i]); 44341da177e4SLinus Torvalds INIT_LIST_HEAD(&unconf_id_hashtbl[i]); 443502cb2858SWang Chen INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); 44361da177e4SLinus Torvalds } 44375282fd72SMarc Eshel for (i = 0; i < SESSION_HASH_SIZE; i++) 44385282fd72SMarc Eshel INIT_LIST_HEAD(&sessionid_hashtbl[i]); 44391da177e4SLinus Torvalds for (i = 0; i < FILE_HASH_SIZE; i++) { 44401da177e4SLinus Torvalds INIT_LIST_HEAD(&file_hashtbl[i]); 44411da177e4SLinus Torvalds } 4442506f275fSJ. Bruce Fields for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) { 4443506f275fSJ. Bruce Fields INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]); 4444506f275fSJ. Bruce Fields INIT_LIST_HEAD(&open_ownerid_hashtbl[i]); 44451da177e4SLinus Torvalds } 4446b79abaddSJ. Bruce Fields for (i = 0; i < STATEID_HASH_SIZE; i++) 44471da177e4SLinus Torvalds INIT_LIST_HEAD(&stateid_hashtbl[i]); 44481da177e4SLinus Torvalds for (i = 0; i < LOCK_HASH_SIZE; i++) { 44491da177e4SLinus Torvalds INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]); 44501da177e4SLinus Torvalds INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); 44511da177e4SLinus Torvalds } 44521da177e4SLinus Torvalds memset(&onestateid, ~0, sizeof(stateid_t)); 44531da177e4SLinus Torvalds INIT_LIST_HEAD(&close_lru); 44541da177e4SLinus Torvalds INIT_LIST_HEAD(&client_lru); 44551da177e4SLinus Torvalds INIT_LIST_HEAD(&del_recall_lru); 4456ac4d8ff2SNeilBrown reclaim_str_hashtbl_size = 0; 4457e8ff2a84SJ. Bruce Fields return 0; 4458ac4d8ff2SNeilBrown } 4459ac4d8ff2SNeilBrown 4460190e4fbfSNeilBrown static void 4461190e4fbfSNeilBrown nfsd4_load_reboot_recovery_data(void) 4462190e4fbfSNeilBrown { 4463190e4fbfSNeilBrown int status; 4464190e4fbfSNeilBrown 44650964a3d3SNeilBrown nfs4_lock_state(); 446648483bf2SJ. Bruce Fields nfsd4_init_recdir(); 4467190e4fbfSNeilBrown status = nfsd4_recdir_load(); 44680964a3d3SNeilBrown nfs4_unlock_state(); 4469190e4fbfSNeilBrown if (status) 4470190e4fbfSNeilBrown printk("NFSD: Failure reading reboot recovery data\n"); 4471190e4fbfSNeilBrown } 4472190e4fbfSNeilBrown 4473c2f1a551SMeelap Shah /* 4474c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 4475c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 4476c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 4477c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 4478c2f1a551SMeelap Shah * 4479c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 4480c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 4481c2f1a551SMeelap Shah */ 4482c2f1a551SMeelap Shah static void 4483c2f1a551SMeelap Shah set_max_delegations(void) 4484c2f1a551SMeelap Shah { 4485c2f1a551SMeelap Shah /* 4486c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 4487c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 4488c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 4489c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 4490c2f1a551SMeelap Shah */ 4491c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 4492c2f1a551SMeelap Shah } 4493c2f1a551SMeelap Shah 4494ac4d8ff2SNeilBrown /* initialization to perform when the nfsd service is started: */ 4495ac4d8ff2SNeilBrown 449629ab23ccSJ. Bruce Fields static int 4497ac4d8ff2SNeilBrown __nfs4_state_start(void) 4498ac4d8ff2SNeilBrown { 4499b5a1a81eSJ. Bruce Fields int ret; 4500b5a1a81eSJ. Bruce Fields 45011da177e4SLinus Torvalds boot_time = get_seconds(); 4502af558e33SJ. Bruce Fields locks_start_grace(&nfsd4_manager); 45039a8db97eSMarc Eshel printk(KERN_INFO "NFSD: starting %ld-second grace period\n", 4504e46b498cSJ. Bruce Fields nfsd4_grace); 4505b5a1a81eSJ. Bruce Fields ret = set_callback_cred(); 4506b5a1a81eSJ. Bruce Fields if (ret) 4507b5a1a81eSJ. Bruce Fields return -ENOMEM; 450858da282bSNeilBrown laundry_wq = create_singlethread_workqueue("nfsd4"); 450929ab23ccSJ. Bruce Fields if (laundry_wq == NULL) 451029ab23ccSJ. Bruce Fields return -ENOMEM; 4511b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 4512b5a1a81eSJ. Bruce Fields if (ret) 4513b5a1a81eSJ. Bruce Fields goto out_free_laundry; 4514e46b498cSJ. Bruce Fields queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); 4515c2f1a551SMeelap Shah set_max_delegations(); 4516b5a1a81eSJ. Bruce Fields return 0; 4517b5a1a81eSJ. Bruce Fields out_free_laundry: 4518b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 4519b5a1a81eSJ. Bruce Fields return ret; 45201da177e4SLinus Torvalds } 45211da177e4SLinus Torvalds 452229ab23ccSJ. Bruce Fields int 452376a3550eSNeilBrown nfs4_state_start(void) 45241da177e4SLinus Torvalds { 4525190e4fbfSNeilBrown nfsd4_load_reboot_recovery_data(); 45264ad9a344SJeff Layton return __nfs4_state_start(); 45271da177e4SLinus Torvalds } 45281da177e4SLinus Torvalds 45291da177e4SLinus Torvalds static void 45301da177e4SLinus Torvalds __nfs4_state_shutdown(void) 45311da177e4SLinus Torvalds { 45321da177e4SLinus Torvalds int i; 45331da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 45341da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 45351da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 45361da177e4SLinus Torvalds 45371da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 45381da177e4SLinus Torvalds while (!list_empty(&conf_id_hashtbl[i])) { 45391da177e4SLinus Torvalds clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 45401da177e4SLinus Torvalds expire_client(clp); 45411da177e4SLinus Torvalds } 45421da177e4SLinus Torvalds while (!list_empty(&unconf_str_hashtbl[i])) { 45431da177e4SLinus Torvalds clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); 45441da177e4SLinus Torvalds expire_client(clp); 45451da177e4SLinus Torvalds } 45461da177e4SLinus Torvalds } 45471da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 45481da177e4SLinus Torvalds spin_lock(&recall_lock); 45491da177e4SLinus Torvalds list_for_each_safe(pos, next, &del_recall_lru) { 45501da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 45511da177e4SLinus Torvalds list_move(&dp->dl_recall_lru, &reaplist); 45521da177e4SLinus Torvalds } 45531da177e4SLinus Torvalds spin_unlock(&recall_lock); 45541da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 45551da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 45561da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 45571da177e4SLinus Torvalds unhash_delegation(dp); 45581da177e4SLinus Torvalds } 45591da177e4SLinus Torvalds 4560190e4fbfSNeilBrown nfsd4_shutdown_recdir(); 45611da177e4SLinus Torvalds } 45621da177e4SLinus Torvalds 45631da177e4SLinus Torvalds void 45641da177e4SLinus Torvalds nfs4_state_shutdown(void) 45651da177e4SLinus Torvalds { 4566afe2c511STejun Heo cancel_delayed_work_sync(&laundromat_work); 45675e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 45682c5e7615SJ. Bruce Fields locks_end_grace(&nfsd4_manager); 45691da177e4SLinus Torvalds nfs4_lock_state(); 45701da177e4SLinus Torvalds nfs4_release_reclaim(); 45711da177e4SLinus Torvalds __nfs4_state_shutdown(); 45721da177e4SLinus Torvalds nfs4_unlock_state(); 4573c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 45741da177e4SLinus Torvalds } 4575