11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2001 The Regents of the University of Michigan. 31da177e4SLinus Torvalds * All rights reserved. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Kendrick Smith <kmsmith@umich.edu> 61da177e4SLinus Torvalds * Andy Adamson <kandros@umich.edu> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 91da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 101da177e4SLinus Torvalds * are met: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 131da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer. 141da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 151da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer in the 161da177e4SLinus Torvalds * documentation and/or other materials provided with the distribution. 171da177e4SLinus Torvalds * 3. Neither the name of the University nor the names of its 181da177e4SLinus Torvalds * contributors may be used to endorse or promote products derived 191da177e4SLinus Torvalds * from this software without specific prior written permission. 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 221da177e4SLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 231da177e4SLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 241da177e4SLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251da177e4SLinus Torvalds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 261da177e4SLinus Torvalds * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 271da177e4SLinus Torvalds * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 281da177e4SLinus Torvalds * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 291da177e4SLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 301da177e4SLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 311da177e4SLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds 35aceaf78dSDave Hansen #include <linux/file.h> 36b89f4321SArnd Bergmann #include <linux/fs.h> 375a0e3ad6STejun Heo #include <linux/slab.h> 380964a3d3SNeilBrown #include <linux/namei.h> 39c2f1a551SMeelap Shah #include <linux/swap.h> 4017456804SBryan Schumaker #include <linux/pagemap.h> 417df302f7SChuck Lever #include <linux/ratelimit.h> 4268e76ad0SOlga Kornievskaia #include <linux/sunrpc/svcauth_gss.h> 435976687aSJeff Layton #include <linux/sunrpc/addr.h> 4487545899SDaniel Borkmann #include <linux/jhash.h> 459a74af21SBoaz Harrosh #include "xdr4.h" 4606b332a5SJ. Bruce Fields #include "xdr4cb.h" 470a3adadeSJ. Bruce Fields #include "vfs.h" 48bfa4b365SJ. Bruce Fields #include "current_stateid.h" 491da177e4SLinus Torvalds 505e1533c7SStanislav Kinsbursky #include "netns.h" 519cf514ccSChristoph Hellwig #include "pnfs.h" 525e1533c7SStanislav Kinsbursky 531da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 541da177e4SLinus Torvalds 55f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 56f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 57f32f3c2dSJ. Bruce Fields .si_generation = ~0, 58f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 59f32f3c2dSJ. Bruce Fields }; 60f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 61f32f3c2dSJ. Bruce Fields /* all fields zero */ 62f32f3c2dSJ. Bruce Fields }; 6319ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 6419ff0f28STigran Mkrtchyan .si_generation = 1, 6519ff0f28STigran Mkrtchyan }; 66fb500a7cSTrond Myklebust static const stateid_t close_stateid = { 67fb500a7cSTrond Myklebust .si_generation = 0xffffffffU, 68fb500a7cSTrond Myklebust }; 69f32f3c2dSJ. Bruce Fields 70ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 71fd39ca9aSNeilBrown 72f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 73f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 7419ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 75ae254dacSAndrew Elble #define CLOSE_STATEID(stateid) (!memcmp((stateid), &close_stateid, sizeof(stateid_t))) 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds /* forward declarations */ 78f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 796011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 801da177e4SLinus Torvalds 818b671b80SJ. Bruce Fields /* Locking: */ 828b671b80SJ. Bruce Fields 838b671b80SJ. Bruce Fields /* 848b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 858b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 868b671b80SJ. Bruce Fields * eventually cover more: 878b671b80SJ. Bruce Fields */ 88cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 898b671b80SJ. Bruce Fields 904f34bd05SAndrew Elble enum nfsd4_st_mutex_lock_subclass { 914f34bd05SAndrew Elble OPEN_STATEID_MUTEX = 0, 924f34bd05SAndrew Elble LOCK_STATEID_MUTEX = 1, 934f34bd05SAndrew Elble }; 944f34bd05SAndrew Elble 95b401be22SJeff Layton /* 96b401be22SJeff Layton * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for 97b401be22SJeff Layton * the refcount on the open stateid to drop. 98b401be22SJeff Layton */ 99b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq); 100b401be22SJeff Layton 1019258a2d5SJeff Layton static struct kmem_cache *client_slab; 102abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 103abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 104abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 105abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 106abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 1078287f009SSachin Bhamare static struct kmem_cache *odstate_slab; 108e60d4398SNeilBrown 10966b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 110508dc6e1SBenny Halevy 111c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; 11276d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; 1130162ac2bSChristoph Hellwig 11466b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 115508dc6e1SBenny Halevy { 11666b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 11766b2b9b2SJ. Bruce Fields } 11866b2b9b2SJ. Bruce Fields 119f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 120f0f51f5cSJ. Bruce Fields { 121f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 12266b2b9b2SJ. Bruce Fields return nfserr_jukebox; 12366b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 12466b2b9b2SJ. Bruce Fields return nfs_ok; 12566b2b9b2SJ. Bruce Fields } 12666b2b9b2SJ. Bruce Fields 127221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 128221a6876SJ. Bruce Fields { 129221a6876SJ. Bruce Fields return clp->cl_time == 0; 130221a6876SJ. Bruce Fields } 131221a6876SJ. Bruce Fields 132221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 133221a6876SJ. Bruce Fields { 1340a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1350a880a28STrond Myklebust 1360a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1370a880a28STrond Myklebust 138221a6876SJ. Bruce Fields if (is_client_expired(clp)) 139221a6876SJ. Bruce Fields return nfserr_expired; 140221a6876SJ. Bruce Fields atomic_inc(&clp->cl_refcount); 141221a6876SJ. Bruce Fields return nfs_ok; 142221a6876SJ. Bruce Fields } 143221a6876SJ. Bruce Fields 144221a6876SJ. Bruce Fields /* must be called under the client_lock */ 145221a6876SJ. Bruce Fields static inline void 146221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 147221a6876SJ. Bruce Fields { 148221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 149221a6876SJ. Bruce Fields 150221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 151221a6876SJ. Bruce Fields WARN_ON(1); 152221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 153221a6876SJ. Bruce Fields __func__, 154221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 155221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 156221a6876SJ. Bruce Fields return; 157221a6876SJ. Bruce Fields } 158221a6876SJ. Bruce Fields 159221a6876SJ. Bruce Fields dprintk("renewing client (clientid %08x/%08x)\n", 160221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 161221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 162221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 163221a6876SJ. Bruce Fields clp->cl_time = get_seconds(); 164221a6876SJ. Bruce Fields } 165221a6876SJ. Bruce Fields 166ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 167221a6876SJ. Bruce Fields { 1680a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1690a880a28STrond Myklebust 1700a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1710a880a28STrond Myklebust 172221a6876SJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_refcount)) 173221a6876SJ. Bruce Fields return; 174221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 175221a6876SJ. Bruce Fields renew_client_locked(clp); 176221a6876SJ. Bruce Fields } 177221a6876SJ. Bruce Fields 1784b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 1794b24ca7dSJeff Layton { 1804b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1814b24ca7dSJeff Layton 182d6c249b4SJeff Layton if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) 183d6c249b4SJeff Layton return; 184d6c249b4SJeff Layton if (!is_client_expired(clp)) 185d6c249b4SJeff Layton renew_client_locked(clp); 1864b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 1874b24ca7dSJeff Layton } 1884b24ca7dSJeff Layton 189d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 190d4e19e70STrond Myklebust { 191d4e19e70STrond Myklebust __be32 status; 192d4e19e70STrond Myklebust 193d4e19e70STrond Myklebust if (is_session_dead(ses)) 194d4e19e70STrond Myklebust return nfserr_badsession; 195d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 196d4e19e70STrond Myklebust if (status) 197d4e19e70STrond Myklebust return status; 198d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 199d4e19e70STrond Myklebust return nfs_ok; 200d4e19e70STrond Myklebust } 201d4e19e70STrond Myklebust 202d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 203d4e19e70STrond Myklebust { 204d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 2050a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2060a880a28STrond Myklebust 2070a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 208d4e19e70STrond Myklebust 209d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 210d4e19e70STrond Myklebust free_session(ses); 211d4e19e70STrond Myklebust put_client_renew_locked(clp); 212d4e19e70STrond Myklebust } 213d4e19e70STrond Myklebust 214d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 215d4e19e70STrond Myklebust { 216d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 217d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 218d4e19e70STrond Myklebust 219d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 220d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 221d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 222d4e19e70STrond Myklebust } 223d4e19e70STrond Myklebust 22476d348faSJeff Layton static struct nfsd4_blocked_lock * 22576d348faSJeff Layton find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 22676d348faSJeff Layton struct nfsd_net *nn) 22776d348faSJeff Layton { 22876d348faSJeff Layton struct nfsd4_blocked_lock *cur, *found = NULL; 22976d348faSJeff Layton 2300cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 23176d348faSJeff Layton list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { 23276d348faSJeff Layton if (fh_match(fh, &cur->nbl_fh)) { 23376d348faSJeff Layton list_del_init(&cur->nbl_list); 2347919d0a2SJeff Layton list_del_init(&cur->nbl_lru); 23576d348faSJeff Layton found = cur; 23676d348faSJeff Layton break; 23776d348faSJeff Layton } 23876d348faSJeff Layton } 2390cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 24076d348faSJeff Layton if (found) 241cb03f94fSNeilBrown locks_delete_block(&found->nbl_lock); 24276d348faSJeff Layton return found; 24376d348faSJeff Layton } 24476d348faSJeff Layton 24576d348faSJeff Layton static struct nfsd4_blocked_lock * 24676d348faSJeff Layton find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 24776d348faSJeff Layton struct nfsd_net *nn) 24876d348faSJeff Layton { 24976d348faSJeff Layton struct nfsd4_blocked_lock *nbl; 25076d348faSJeff Layton 25176d348faSJeff Layton nbl = find_blocked_lock(lo, fh, nn); 25276d348faSJeff Layton if (!nbl) { 25376d348faSJeff Layton nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); 25476d348faSJeff Layton if (nbl) { 25576d348faSJeff Layton fh_copy_shallow(&nbl->nbl_fh, fh); 25676d348faSJeff Layton locks_init_lock(&nbl->nbl_lock); 25776d348faSJeff Layton nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client, 25876d348faSJeff Layton &nfsd4_cb_notify_lock_ops, 25976d348faSJeff Layton NFSPROC4_CLNT_CB_NOTIFY_LOCK); 26076d348faSJeff Layton } 26176d348faSJeff Layton } 26276d348faSJeff Layton return nbl; 26376d348faSJeff Layton } 26476d348faSJeff Layton 26576d348faSJeff Layton static void 26676d348faSJeff Layton free_blocked_lock(struct nfsd4_blocked_lock *nbl) 26776d348faSJeff Layton { 26876d348faSJeff Layton locks_release_private(&nbl->nbl_lock); 26976d348faSJeff Layton kfree(nbl); 27076d348faSJeff Layton } 27176d348faSJeff Layton 27268ef3bc3SJeff Layton static void 27368ef3bc3SJeff Layton remove_blocked_locks(struct nfs4_lockowner *lo) 27468ef3bc3SJeff Layton { 27568ef3bc3SJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 27668ef3bc3SJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 27768ef3bc3SJeff Layton struct nfsd4_blocked_lock *nbl; 27868ef3bc3SJeff Layton LIST_HEAD(reaplist); 27968ef3bc3SJeff Layton 28068ef3bc3SJeff Layton /* Dequeue all blocked locks */ 28168ef3bc3SJeff Layton spin_lock(&nn->blocked_locks_lock); 28268ef3bc3SJeff Layton while (!list_empty(&lo->lo_blocked)) { 28368ef3bc3SJeff Layton nbl = list_first_entry(&lo->lo_blocked, 28468ef3bc3SJeff Layton struct nfsd4_blocked_lock, 28568ef3bc3SJeff Layton nbl_list); 28668ef3bc3SJeff Layton list_del_init(&nbl->nbl_list); 28768ef3bc3SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 28868ef3bc3SJeff Layton } 28968ef3bc3SJeff Layton spin_unlock(&nn->blocked_locks_lock); 29068ef3bc3SJeff Layton 29168ef3bc3SJeff Layton /* Now free them */ 29268ef3bc3SJeff Layton while (!list_empty(&reaplist)) { 29368ef3bc3SJeff Layton nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, 29468ef3bc3SJeff Layton nbl_lru); 29568ef3bc3SJeff Layton list_del_init(&nbl->nbl_lru); 296cb03f94fSNeilBrown locks_delete_block(&nbl->nbl_lock); 29768ef3bc3SJeff Layton free_blocked_lock(nbl); 29868ef3bc3SJeff Layton } 29968ef3bc3SJeff Layton } 30068ef3bc3SJeff Layton 30176d348faSJeff Layton static int 30276d348faSJeff Layton nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) 30376d348faSJeff Layton { 30476d348faSJeff Layton /* 30576d348faSJeff Layton * Since this is just an optimization, we don't try very hard if it 30676d348faSJeff Layton * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and 30776d348faSJeff Layton * just quit trying on anything else. 30876d348faSJeff Layton */ 30976d348faSJeff Layton switch (task->tk_status) { 31076d348faSJeff Layton case -NFS4ERR_DELAY: 31176d348faSJeff Layton rpc_delay(task, 1 * HZ); 31276d348faSJeff Layton return 0; 31376d348faSJeff Layton default: 31476d348faSJeff Layton return 1; 31576d348faSJeff Layton } 31676d348faSJeff Layton } 31776d348faSJeff Layton 31876d348faSJeff Layton static void 31976d348faSJeff Layton nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb) 32076d348faSJeff Layton { 32176d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(cb, 32276d348faSJeff Layton struct nfsd4_blocked_lock, nbl_cb); 32376d348faSJeff Layton 32476d348faSJeff Layton free_blocked_lock(nbl); 32576d348faSJeff Layton } 32676d348faSJeff Layton 32776d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { 32876d348faSJeff Layton .done = nfsd4_cb_notify_lock_done, 32976d348faSJeff Layton .release = nfsd4_cb_notify_lock_release, 33076d348faSJeff Layton }; 33176d348faSJeff Layton 332b5971afaSKinglong Mee static inline struct nfs4_stateowner * 333b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop) 334b5971afaSKinglong Mee { 335b5971afaSKinglong Mee atomic_inc(&sop->so_count); 336b5971afaSKinglong Mee return sop; 337b5971afaSKinglong Mee } 338b5971afaSKinglong Mee 3397ffb5880STrond Myklebust static int 340d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) 3417ffb5880STrond Myklebust { 3427ffb5880STrond Myklebust return (sop->so_owner.len == owner->len) && 343d4f0489fSTrond Myklebust 0 == memcmp(sop->so_owner.data, owner->data, owner->len); 3447ffb5880STrond Myklebust } 3457ffb5880STrond Myklebust 3467ffb5880STrond Myklebust static struct nfs4_openowner * 3477ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, 348d4f0489fSTrond Myklebust struct nfs4_client *clp) 3497ffb5880STrond Myklebust { 3507ffb5880STrond Myklebust struct nfs4_stateowner *so; 3517ffb5880STrond Myklebust 352d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 3537ffb5880STrond Myklebust 354d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval], 355d4f0489fSTrond Myklebust so_strhash) { 3567ffb5880STrond Myklebust if (!so->so_is_open_owner) 3577ffb5880STrond Myklebust continue; 358b5971afaSKinglong Mee if (same_owner_str(so, &open->op_owner)) 359b5971afaSKinglong Mee return openowner(nfs4_get_stateowner(so)); 3607ffb5880STrond Myklebust } 3617ffb5880STrond Myklebust return NULL; 3627ffb5880STrond Myklebust } 3637ffb5880STrond Myklebust 3647ffb5880STrond Myklebust static struct nfs4_openowner * 3657ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 366d4f0489fSTrond Myklebust struct nfs4_client *clp) 3677ffb5880STrond Myklebust { 3687ffb5880STrond Myklebust struct nfs4_openowner *oo; 3697ffb5880STrond Myklebust 370d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 371d4f0489fSTrond Myklebust oo = find_openstateowner_str_locked(hashval, open, clp); 372d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 3737ffb5880STrond Myklebust return oo; 3747ffb5880STrond Myklebust } 3757ffb5880STrond Myklebust 3761da177e4SLinus Torvalds static inline u32 3771da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 3781da177e4SLinus Torvalds { 3791da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds u32 x = 0; 3821da177e4SLinus Torvalds while (nbytes--) { 3831da177e4SLinus Torvalds x *= 37; 3841da177e4SLinus Torvalds x += *cptr++; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds return x; 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 3895b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu) 39032513b40SJ. Bruce Fields { 3915b095e99SJeff Layton struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu); 3925b095e99SJeff Layton 3935b095e99SJeff Layton kmem_cache_free(file_slab, fp); 39432513b40SJ. Bruce Fields } 39532513b40SJ. Bruce Fields 396e6ba76e1SChristoph Hellwig void 39713cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 39813cd2184SNeilBrown { 39902e1215fSJeff Layton might_lock(&state_lock); 40002e1215fSJeff Layton 401818a34ebSElena Reshetova if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) { 4025b095e99SJeff Layton hlist_del_rcu(&fi->fi_hash); 403cdc97505SBenny Halevy spin_unlock(&state_lock); 4048287f009SSachin Bhamare WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); 4055b095e99SJeff Layton WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); 4065b095e99SJeff Layton call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); 4078b671b80SJ. Bruce Fields } 40813cd2184SNeilBrown } 40913cd2184SNeilBrown 410de18643dSTrond Myklebust static struct file * 411de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag) 412de18643dSTrond Myklebust { 413de18643dSTrond Myklebust if (f->fi_fds[oflag]) 414de18643dSTrond Myklebust return get_file(f->fi_fds[oflag]); 415de18643dSTrond Myklebust return NULL; 416de18643dSTrond Myklebust } 417de18643dSTrond Myklebust 418de18643dSTrond Myklebust static struct file * 419de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f) 420de18643dSTrond Myklebust { 421de18643dSTrond Myklebust struct file *ret; 422de18643dSTrond Myklebust 423de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 424de18643dSTrond Myklebust 425de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 426de18643dSTrond Myklebust if (!ret) 427de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 428de18643dSTrond Myklebust return ret; 429de18643dSTrond Myklebust } 430de18643dSTrond Myklebust 431de18643dSTrond Myklebust static struct file * 432de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 433de18643dSTrond Myklebust { 434de18643dSTrond Myklebust struct file *ret; 435de18643dSTrond Myklebust 436de18643dSTrond Myklebust spin_lock(&f->fi_lock); 437de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 438de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 439de18643dSTrond Myklebust 440de18643dSTrond Myklebust return ret; 441de18643dSTrond Myklebust } 442de18643dSTrond Myklebust 443de18643dSTrond Myklebust static struct file *find_readable_file_locked(struct nfs4_file *f) 444de18643dSTrond Myklebust { 445de18643dSTrond Myklebust struct file *ret; 446de18643dSTrond Myklebust 447de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 448de18643dSTrond Myklebust 449de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 450de18643dSTrond Myklebust if (!ret) 451de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 452de18643dSTrond Myklebust return ret; 453de18643dSTrond Myklebust } 454de18643dSTrond Myklebust 455de18643dSTrond Myklebust static struct file * 456de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 457de18643dSTrond Myklebust { 458de18643dSTrond Myklebust struct file *ret; 459de18643dSTrond Myklebust 460de18643dSTrond Myklebust spin_lock(&f->fi_lock); 461de18643dSTrond Myklebust ret = find_readable_file_locked(f); 462de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 463de18643dSTrond Myklebust 464de18643dSTrond Myklebust return ret; 465de18643dSTrond Myklebust } 466de18643dSTrond Myklebust 4674d227fcaSChristoph Hellwig struct file * 468de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 469de18643dSTrond Myklebust { 470de18643dSTrond Myklebust struct file *ret; 471de18643dSTrond Myklebust 472de18643dSTrond Myklebust spin_lock(&f->fi_lock); 473de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 474de18643dSTrond Myklebust if (!ret) { 475de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 476de18643dSTrond Myklebust if (!ret) 477de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 478de18643dSTrond Myklebust } 479de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 480de18643dSTrond Myklebust return ret; 481de18643dSTrond Myklebust } 482de18643dSTrond Myklebust 48302a3508dSTrond Myklebust static atomic_long_t num_delegations; 484697ce9beSZhang Yanfei unsigned long max_delegations; 485ef0f3390SNeilBrown 486ef0f3390SNeilBrown /* 487ef0f3390SNeilBrown * Open owner state (share locks) 488ef0f3390SNeilBrown */ 489ef0f3390SNeilBrown 49016bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 49116bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 49216bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 49316bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 494ef0f3390SNeilBrown 495d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 496ddc04c41SJ. Bruce Fields { 497ddc04c41SJ. Bruce Fields unsigned int ret; 498ddc04c41SJ. Bruce Fields 499ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 50016bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 501ddc04c41SJ. Bruce Fields } 502ef0f3390SNeilBrown 503ef0f3390SNeilBrown /* hash table for nfs4_file */ 504ef0f3390SNeilBrown #define FILE_HASH_BITS 8 505ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 50635079582SShan Wei 507ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) 508ddc04c41SJ. Bruce Fields { 509ca943217STrond Myklebust return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); 510ca943217STrond Myklebust } 511ca943217STrond Myklebust 512ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh) 513ca943217STrond Myklebust { 514ca943217STrond Myklebust return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); 515ca943217STrond Myklebust } 516ca943217STrond Myklebust 51789876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 518ef0f3390SNeilBrown 51912659651SJeff Layton static void 52012659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 5213477565eSJ. Bruce Fields { 5227214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5237214e860SJeff Layton 52412659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 52512659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 52612659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 52712659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 5283477565eSJ. Bruce Fields } 5293477565eSJ. Bruce Fields 53012659651SJeff Layton static __be32 53112659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 532998db52cSJ. Bruce Fields { 5337214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5347214e860SJeff Layton 53512659651SJeff Layton /* Does this access mode make sense? */ 53612659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 53712659651SJeff Layton return nfserr_inval; 53812659651SJeff Layton 539baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 540baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 541baeb4ff0SJeff Layton return nfserr_share_denied; 542baeb4ff0SJeff Layton 54312659651SJeff Layton __nfs4_file_get_access(fp, access); 54412659651SJeff Layton return nfs_ok; 545998db52cSJ. Bruce Fields } 546998db52cSJ. Bruce Fields 547baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 548baeb4ff0SJeff Layton { 549baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 550baeb4ff0SJeff Layton if (deny) { 551baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 552baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 553baeb4ff0SJeff Layton return nfserr_inval; 554baeb4ff0SJeff Layton 555baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 556baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 557baeb4ff0SJeff Layton return nfserr_share_denied; 558baeb4ff0SJeff Layton 559baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 560baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 561baeb4ff0SJeff Layton return nfserr_share_denied; 562baeb4ff0SJeff Layton } 563baeb4ff0SJeff Layton return nfs_ok; 564baeb4ff0SJeff Layton } 565baeb4ff0SJeff Layton 566998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 567f9d7562fSJ. Bruce Fields { 568de18643dSTrond Myklebust might_lock(&fp->fi_lock); 569de18643dSTrond Myklebust 570de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 571de18643dSTrond Myklebust struct file *f1 = NULL; 572de18643dSTrond Myklebust struct file *f2 = NULL; 573de18643dSTrond Myklebust 5746d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 5750c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 5766d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 577de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 578de18643dSTrond Myklebust if (f1) 579de18643dSTrond Myklebust fput(f1); 580de18643dSTrond Myklebust if (f2) 581de18643dSTrond Myklebust fput(f2); 582f9d7562fSJ. Bruce Fields } 583f9d7562fSJ. Bruce Fields } 584f9d7562fSJ. Bruce Fields 58512659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 586998db52cSJ. Bruce Fields { 58712659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 58812659651SJeff Layton 58912659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 590998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 59112659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 59212659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 593998db52cSJ. Bruce Fields } 594998db52cSJ. Bruce Fields 5958287f009SSachin Bhamare /* 5968287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 5978287f009SSachin Bhamare * pNFS for proper return on close semantics. 5988287f009SSachin Bhamare * 5998287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 6008287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 6018287f009SSachin Bhamare */ 6028287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6038287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 6048287f009SSachin Bhamare { 6058287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6068287f009SSachin Bhamare 6078287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 6088287f009SSachin Bhamare if (co) { 6098287f009SSachin Bhamare co->co_client = clp; 610cff7cb2eSElena Reshetova refcount_set(&co->co_odcount, 1); 6118287f009SSachin Bhamare } 6128287f009SSachin Bhamare return co; 6138287f009SSachin Bhamare } 6148287f009SSachin Bhamare 6158287f009SSachin Bhamare static void 6168287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 6178287f009SSachin Bhamare { 6188287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 6198287f009SSachin Bhamare 6208287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 6218287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 6228287f009SSachin Bhamare } 6238287f009SSachin Bhamare 6248287f009SSachin Bhamare static inline void 6258287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 6268287f009SSachin Bhamare { 6278287f009SSachin Bhamare if (co) 628cff7cb2eSElena Reshetova refcount_inc(&co->co_odcount); 6298287f009SSachin Bhamare } 6308287f009SSachin Bhamare 6318287f009SSachin Bhamare static void 6328287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 6338287f009SSachin Bhamare { 6348287f009SSachin Bhamare struct nfs4_file *fp; 6358287f009SSachin Bhamare 6368287f009SSachin Bhamare if (!co) 6378287f009SSachin Bhamare return; 6388287f009SSachin Bhamare 6398287f009SSachin Bhamare fp = co->co_file; 640cff7cb2eSElena Reshetova if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 6418287f009SSachin Bhamare list_del(&co->co_perfile); 6428287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 6438287f009SSachin Bhamare 6448287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 6458287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 6468287f009SSachin Bhamare } 6478287f009SSachin Bhamare } 6488287f009SSachin Bhamare 6498287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6508287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 6518287f009SSachin Bhamare { 6528287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6538287f009SSachin Bhamare struct nfs4_client *cl; 6548287f009SSachin Bhamare 6558287f009SSachin Bhamare if (!new) 6568287f009SSachin Bhamare return NULL; 6578287f009SSachin Bhamare 6588287f009SSachin Bhamare cl = new->co_client; 6598287f009SSachin Bhamare 6608287f009SSachin Bhamare spin_lock(&fp->fi_lock); 6618287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 6628287f009SSachin Bhamare if (co->co_client == cl) { 6638287f009SSachin Bhamare get_clnt_odstate(co); 6648287f009SSachin Bhamare goto out; 6658287f009SSachin Bhamare } 6668287f009SSachin Bhamare } 6678287f009SSachin Bhamare co = new; 6688287f009SSachin Bhamare co->co_file = fp; 6698287f009SSachin Bhamare hash_clnt_odstate_locked(new); 6708287f009SSachin Bhamare out: 6718287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 6728287f009SSachin Bhamare return co; 6738287f009SSachin Bhamare } 6748287f009SSachin Bhamare 675d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 676d19fb70dSKinglong Mee void (*sc_free)(struct nfs4_stid *)) 677996e0938SJ. Bruce Fields { 6783abdb607SJ. Bruce Fields struct nfs4_stid *stid; 6793abdb607SJ. Bruce Fields int new_id; 6803abdb607SJ. Bruce Fields 681f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 6823abdb607SJ. Bruce Fields if (!stid) 6833abdb607SJ. Bruce Fields return NULL; 684996e0938SJ. Bruce Fields 6854770d722SJeff Layton idr_preload(GFP_KERNEL); 6864770d722SJeff Layton spin_lock(&cl->cl_lock); 6874770d722SJeff Layton new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT); 6884770d722SJeff Layton spin_unlock(&cl->cl_lock); 6894770d722SJeff Layton idr_preload_end(); 690ebd6c707STejun Heo if (new_id < 0) 6913abdb607SJ. Bruce Fields goto out_free; 692d19fb70dSKinglong Mee 693d19fb70dSKinglong Mee stid->sc_free = sc_free; 6943abdb607SJ. Bruce Fields stid->sc_client = cl; 6953abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 6963abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 6973abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 698a15dfcd5SElena Reshetova refcount_set(&stid->sc_count, 1); 6999767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 7003abdb607SJ. Bruce Fields 701996e0938SJ. Bruce Fields /* 7023abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 7033abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 7043abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 7053abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 7063abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 7073abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 7083abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 709996e0938SJ. Bruce Fields */ 7103abdb607SJ. Bruce Fields return stid; 7113abdb607SJ. Bruce Fields out_free: 7122c44a234SWei Yongjun kmem_cache_free(slab, stid); 7133abdb607SJ. Bruce Fields return NULL; 7142a74aba7SJ. Bruce Fields } 7152a74aba7SJ. Bruce Fields 716e0639dc5SOlga Kornievskaia /* 717e0639dc5SOlga Kornievskaia * Create a unique stateid_t to represent each COPY. 718e0639dc5SOlga Kornievskaia */ 719e0639dc5SOlga Kornievskaia int nfs4_init_cp_state(struct nfsd_net *nn, struct nfsd4_copy *copy) 720e0639dc5SOlga Kornievskaia { 721e0639dc5SOlga Kornievskaia int new_id; 722e0639dc5SOlga Kornievskaia 723e0639dc5SOlga Kornievskaia idr_preload(GFP_KERNEL); 724e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 725e0639dc5SOlga Kornievskaia new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, copy, 0, 0, GFP_NOWAIT); 726e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 727e0639dc5SOlga Kornievskaia idr_preload_end(); 728e0639dc5SOlga Kornievskaia if (new_id < 0) 729e0639dc5SOlga Kornievskaia return 0; 730e0639dc5SOlga Kornievskaia copy->cp_stateid.si_opaque.so_id = new_id; 731e0639dc5SOlga Kornievskaia copy->cp_stateid.si_opaque.so_clid.cl_boot = nn->boot_time; 732e0639dc5SOlga Kornievskaia copy->cp_stateid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; 733e0639dc5SOlga Kornievskaia return 1; 734e0639dc5SOlga Kornievskaia } 735e0639dc5SOlga Kornievskaia 736e0639dc5SOlga Kornievskaia void nfs4_free_cp_state(struct nfsd4_copy *copy) 737e0639dc5SOlga Kornievskaia { 738e0639dc5SOlga Kornievskaia struct nfsd_net *nn; 739e0639dc5SOlga Kornievskaia 740e0639dc5SOlga Kornievskaia nn = net_generic(copy->cp_clp->net, nfsd_net_id); 741e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 742e0639dc5SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, copy->cp_stateid.si_opaque.so_id); 743e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 744e0639dc5SOlga Kornievskaia } 745e0639dc5SOlga Kornievskaia 746b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 7474cdc951bSJ. Bruce Fields { 7486011695dSTrond Myklebust struct nfs4_stid *stid; 7496011695dSTrond Myklebust 750d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 7516011695dSTrond Myklebust if (!stid) 7526011695dSTrond Myklebust return NULL; 7536011695dSTrond Myklebust 754d19fb70dSKinglong Mee return openlockstateid(stid); 7556011695dSTrond Myklebust } 7566011695dSTrond Myklebust 7576011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 7586011695dSTrond Myklebust { 7596011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 7606011695dSTrond Myklebust atomic_long_dec(&num_delegations); 7614cdc951bSJ. Bruce Fields } 7624cdc951bSJ. Bruce Fields 7636282cd56SNeilBrown /* 7646282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 7656282cd56SNeilBrown * out again straight away. 7666282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 7676282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 7686282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 7696282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 7706282cd56SNeilBrown * filter. 7716282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 7726282cd56SNeilBrown * unless both are empty of course. 7736282cd56SNeilBrown * 7746282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 7756282cd56SNeilBrown * low 3 bytes as hash-table indices. 7766282cd56SNeilBrown * 777f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 7786282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 7796282cd56SNeilBrown * except when swapping the two filters. 7806282cd56SNeilBrown */ 781f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 7826282cd56SNeilBrown static struct bloom_pair { 7836282cd56SNeilBrown int entries, old_entries; 7846282cd56SNeilBrown time_t swap_time; 7856282cd56SNeilBrown int new; /* index into 'set' */ 7866282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 7876282cd56SNeilBrown } blocked_delegations; 7886282cd56SNeilBrown 7896282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 7906282cd56SNeilBrown { 7916282cd56SNeilBrown u32 hash; 7926282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 7936282cd56SNeilBrown 7946282cd56SNeilBrown if (bd->entries == 0) 7956282cd56SNeilBrown return 0; 7966282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 797f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 7986282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 7996282cd56SNeilBrown bd->entries -= bd->old_entries; 8006282cd56SNeilBrown bd->old_entries = bd->entries; 8016282cd56SNeilBrown memset(bd->set[bd->new], 0, 8026282cd56SNeilBrown sizeof(bd->set[0])); 8036282cd56SNeilBrown bd->new = 1-bd->new; 8046282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 8056282cd56SNeilBrown } 806f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 8076282cd56SNeilBrown } 80887545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 8096282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 8106282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 8116282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 8126282cd56SNeilBrown return 1; 8136282cd56SNeilBrown 8146282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 8156282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 8166282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 8176282cd56SNeilBrown return 1; 8186282cd56SNeilBrown 8196282cd56SNeilBrown return 0; 8206282cd56SNeilBrown } 8216282cd56SNeilBrown 8226282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 8236282cd56SNeilBrown { 8246282cd56SNeilBrown u32 hash; 8256282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 8266282cd56SNeilBrown 82787545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 8286282cd56SNeilBrown 829f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 8306282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 8316282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 8326282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 8336282cd56SNeilBrown if (bd->entries == 0) 8346282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 8356282cd56SNeilBrown bd->entries += 1; 836f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 8376282cd56SNeilBrown } 8386282cd56SNeilBrown 8391da177e4SLinus Torvalds static struct nfs4_delegation * 84086d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 84186d29b10SJ. Bruce Fields struct svc_fh *current_fh, 8428287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 8431da177e4SLinus Torvalds { 8441da177e4SLinus Torvalds struct nfs4_delegation *dp; 84502a3508dSTrond Myklebust long n; 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 84802a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 84902a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 85002a3508dSTrond Myklebust goto out_dec; 8516282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 85202a3508dSTrond Myklebust goto out_dec; 853d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 8545b2d21c1SNeilBrown if (dp == NULL) 85502a3508dSTrond Myklebust goto out_dec; 8566011695dSTrond Myklebust 8572a74aba7SJ. Bruce Fields /* 8582a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 8596136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 8606136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 8612a74aba7SJ. Bruce Fields */ 8622a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 863ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 864ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 8651da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 8668287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 8678287f009SSachin Bhamare get_clnt_odstate(odstate); 86899c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 869f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 870f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 8710162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 87286d29b10SJ. Bruce Fields get_nfs4_file(fp); 87386d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 8741da177e4SLinus Torvalds return dp; 87502a3508dSTrond Myklebust out_dec: 87602a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 87702a3508dSTrond Myklebust return NULL; 8781da177e4SLinus Torvalds } 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds void 8816011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 8821da177e4SLinus Torvalds { 88311b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 8846011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 8856011695dSTrond Myklebust 8864770d722SJeff Layton might_lock(&clp->cl_lock); 8874770d722SJeff Layton 888a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 889b401be22SJeff Layton wake_up_all(&close_wq); 8906011695dSTrond Myklebust return; 891b401be22SJeff Layton } 8926011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 8934770d722SJeff Layton spin_unlock(&clp->cl_lock); 8946011695dSTrond Myklebust s->sc_free(s); 89511b9164aSTrond Myklebust if (fp) 89611b9164aSTrond Myklebust put_nfs4_file(fp); 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds 8999767feb2SJeff Layton void 9009767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 9019767feb2SJeff Layton { 9029767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 9039767feb2SJeff Layton 9049767feb2SJeff Layton spin_lock(&stid->sc_lock); 9059767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 9069767feb2SJeff Layton src->si_generation = 1; 9079767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 9089767feb2SJeff Layton spin_unlock(&stid->sc_lock); 9099767feb2SJeff Layton } 9109767feb2SJeff Layton 911353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 9121da177e4SLinus Torvalds { 9136bcc034eSJeff Layton struct file *filp = NULL; 914353601e7SJ. Bruce Fields 915353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 916353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 917353601e7SJ. Bruce Fields swap(filp, fp->fi_deleg_file); 918353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 919353601e7SJ. Bruce Fields 920353601e7SJ. Bruce Fields if (filp) 921353601e7SJ. Bruce Fields fput(filp); 922353601e7SJ. Bruce Fields } 923353601e7SJ. Bruce Fields 924353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 925353601e7SJ. Bruce Fields { 926cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 927353601e7SJ. Bruce Fields struct file *filp = fp->fi_deleg_file; 928417c6629SJeff Layton 929b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 930b8232d33SJ. Bruce Fields 931653e514eSJ. Bruce Fields vfs_setlease(filp, F_UNLCK, NULL, (void **)&dp); 932353601e7SJ. Bruce Fields put_deleg_file(fp); 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 9350af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 9360af6e690SJ. Bruce Fields { 9370af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 938353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 9390af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 9400af6e690SJ. Bruce Fields } 9410af6e690SJ. Bruce Fields 942cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 9436136d2b4SJ. Bruce Fields { 9443abdb607SJ. Bruce Fields s->sc_type = 0; 9456136d2b4SJ. Bruce Fields } 9466136d2b4SJ. Bruce Fields 94734ed9872SAndrew Elble /** 94868b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 94934ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 95034ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 95134ed9872SAndrew Elble * 95234ed9872SAndrew Elble * Return: 95368b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 95434ed9872SAndrew Elble */ 95534ed9872SAndrew Elble 95668b18f52SJ. Bruce Fields static bool 95768b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 958931ee56cSBenny Halevy { 95934ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 96034ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 96134ed9872SAndrew Elble 962cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 963417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 964931ee56cSBenny Halevy 96534ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 96634ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 96734ed9872SAndrew Elble if (clp == searchclp) { 96851d87bc2SFengguang Wu return true; 96934ed9872SAndrew Elble } 97034ed9872SAndrew Elble } 97151d87bc2SFengguang Wu return false; 97234ed9872SAndrew Elble } 97334ed9872SAndrew Elble 97434ed9872SAndrew Elble /** 97534ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 97634ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 97734ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 97834ed9872SAndrew Elble * 97934ed9872SAndrew Elble * Return: 98034ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 98134ed9872SAndrew Elble * 98234ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 98334ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 98434ed9872SAndrew Elble * 98534ed9872SAndrew Elble */ 98634ed9872SAndrew Elble 98734ed9872SAndrew Elble static int 98834ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 98934ed9872SAndrew Elble { 99034ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 99134ed9872SAndrew Elble 99234ed9872SAndrew Elble lockdep_assert_held(&state_lock); 99334ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 99434ed9872SAndrew Elble 99568b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 99668b18f52SJ. Bruce Fields return -EAGAIN; 997a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 9983fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 999931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 100034ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 100134ed9872SAndrew Elble return 0; 1002931ee56cSBenny Halevy } 1003931ee56cSBenny Halevy 10043fcbbd24SJeff Layton static bool 100542690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 10061da177e4SLinus Torvalds { 100711b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 100802e1215fSJeff Layton 100942690676SJeff Layton lockdep_assert_held(&state_lock); 101042690676SJeff Layton 10113fcbbd24SJeff Layton if (list_empty(&dp->dl_perfile)) 10123fcbbd24SJeff Layton return false; 10133fcbbd24SJeff Layton 1014b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 1015d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 1016d55a166cSJeff Layton ++dp->dl_time; 1017417c6629SJeff Layton spin_lock(&fp->fi_lock); 1018931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 10191da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 102002e1215fSJeff Layton list_del_init(&dp->dl_perfile); 102102e1215fSJeff Layton spin_unlock(&fp->fi_lock); 10223fcbbd24SJeff Layton return true; 1023cbf7a75bSJ. Bruce Fields } 10243bd64a5bSJ. Bruce Fields 10253bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 10263bd64a5bSJ. Bruce Fields { 10273fcbbd24SJeff Layton bool unhashed; 10283fcbbd24SJeff Layton 102942690676SJeff Layton spin_lock(&state_lock); 10303fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 103142690676SJeff Layton spin_unlock(&state_lock); 10320af6e690SJ. Bruce Fields if (unhashed) 10330af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 10343fcbbd24SJeff Layton } 10353bd64a5bSJ. Bruce Fields 10363bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 10373bd64a5bSJ. Bruce Fields { 10383bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 10393bd64a5bSJ. Bruce Fields 10402d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 10412d4a532dSJeff Layton 10420af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 10433bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 10440af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 10452d4a532dSJeff Layton spin_lock(&clp->cl_lock); 10462d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 10472d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 10483bd64a5bSJ. Bruce Fields } 10490af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 10503bd64a5bSJ. Bruce Fields } 10513bd64a5bSJ. Bruce Fields 10521da177e4SLinus Torvalds /* 10531da177e4SLinus Torvalds * SETCLIENTID state 10541da177e4SLinus Torvalds */ 10551da177e4SLinus Torvalds 1056ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1057ddc04c41SJ. Bruce Fields { 1058ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1059ddc04c41SJ. Bruce Fields } 1060ddc04c41SJ. Bruce Fields 1061ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 1062ddc04c41SJ. Bruce Fields { 1063ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 1064ddc04c41SJ. Bruce Fields } 1065ddc04c41SJ. Bruce Fields 10661da177e4SLinus Torvalds /* 1067f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 1068f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 1069f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 1070f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 1071f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 1072f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 1073f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 1074f9d7562fSJ. Bruce Fields * 1075f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 1076f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 1077f9d7562fSJ. Bruce Fields * 1078f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 1079f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 1080f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 1081f9d7562fSJ. Bruce Fields * 1082f9d7562fSJ. Bruce Fields * which we should reject. 1083f9d7562fSJ. Bruce Fields */ 10845ae037e5SJeff Layton static unsigned int 10855ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 1086f9d7562fSJ. Bruce Fields int i; 10875ae037e5SJeff Layton unsigned int access = 0; 1088f9d7562fSJ. Bruce Fields 1089f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 1090f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 10915ae037e5SJeff Layton access |= i; 1092f9d7562fSJ. Bruce Fields } 10935ae037e5SJeff Layton return access; 1094f9d7562fSJ. Bruce Fields } 1095f9d7562fSJ. Bruce Fields 109682c5ff1bSJeff Layton /* set share access for a given stateid */ 109782c5ff1bSJeff Layton static inline void 109882c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 109982c5ff1bSJeff Layton { 1100c11c591fSJeff Layton unsigned char mask = 1 << access; 1101c11c591fSJeff Layton 1102c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1103c11c591fSJeff Layton stp->st_access_bmap |= mask; 110482c5ff1bSJeff Layton } 110582c5ff1bSJeff Layton 110682c5ff1bSJeff Layton /* clear share access for a given stateid */ 110782c5ff1bSJeff Layton static inline void 110882c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 110982c5ff1bSJeff Layton { 1110c11c591fSJeff Layton unsigned char mask = 1 << access; 1111c11c591fSJeff Layton 1112c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1113c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 111482c5ff1bSJeff Layton } 111582c5ff1bSJeff Layton 111682c5ff1bSJeff Layton /* test whether a given stateid has access */ 111782c5ff1bSJeff Layton static inline bool 111882c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 111982c5ff1bSJeff Layton { 1120c11c591fSJeff Layton unsigned char mask = 1 << access; 1121c11c591fSJeff Layton 1122c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 112382c5ff1bSJeff Layton } 112482c5ff1bSJeff Layton 1125ce0fc43cSJeff Layton /* set share deny for a given stateid */ 1126ce0fc43cSJeff Layton static inline void 1127c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 1128ce0fc43cSJeff Layton { 1129c11c591fSJeff Layton unsigned char mask = 1 << deny; 1130c11c591fSJeff Layton 1131c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1132c11c591fSJeff Layton stp->st_deny_bmap |= mask; 1133ce0fc43cSJeff Layton } 1134ce0fc43cSJeff Layton 1135ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 1136ce0fc43cSJeff Layton static inline void 1137c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 1138ce0fc43cSJeff Layton { 1139c11c591fSJeff Layton unsigned char mask = 1 << deny; 1140c11c591fSJeff Layton 1141c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1142c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 1143ce0fc43cSJeff Layton } 1144ce0fc43cSJeff Layton 1145ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 1146ce0fc43cSJeff Layton static inline bool 1147c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 1148ce0fc43cSJeff Layton { 1149c11c591fSJeff Layton unsigned char mask = 1 << deny; 1150c11c591fSJeff Layton 1151c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 1152f9d7562fSJ. Bruce Fields } 1153f9d7562fSJ. Bruce Fields 1154f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 1155f9d7562fSJ. Bruce Fields { 11568f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 1157f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 1158f9d7562fSJ. Bruce Fields return O_RDONLY; 1159f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 1160f9d7562fSJ. Bruce Fields return O_WRONLY; 1161f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 1162f9d7562fSJ. Bruce Fields return O_RDWR; 1163f9d7562fSJ. Bruce Fields } 1164063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 1165063b0fb9SJ. Bruce Fields return O_RDONLY; 1166f9d7562fSJ. Bruce Fields } 1167f9d7562fSJ. Bruce Fields 1168baeb4ff0SJeff Layton /* 1169baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1170baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1171baeb4ff0SJeff Layton */ 1172baeb4ff0SJeff Layton static void 1173baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1174baeb4ff0SJeff Layton { 1175baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1176baeb4ff0SJeff Layton 1177baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1178baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1179baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1180baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1181baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1182baeb4ff0SJeff Layton } 1183baeb4ff0SJeff Layton 1184baeb4ff0SJeff Layton static void 1185baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1186baeb4ff0SJeff Layton { 1187baeb4ff0SJeff Layton int i; 1188baeb4ff0SJeff Layton bool change = false; 1189baeb4ff0SJeff Layton 1190baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1191baeb4ff0SJeff Layton if ((i & deny) != i) { 1192baeb4ff0SJeff Layton change = true; 1193baeb4ff0SJeff Layton clear_deny(i, stp); 1194baeb4ff0SJeff Layton } 1195baeb4ff0SJeff Layton } 1196baeb4ff0SJeff Layton 1197baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1198baeb4ff0SJeff Layton if (change) 119911b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1200baeb4ff0SJeff Layton } 1201baeb4ff0SJeff Layton 120282c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 120382c5ff1bSJeff Layton static void 120482c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 120582c5ff1bSJeff Layton { 120682c5ff1bSJeff Layton int i; 120711b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1208baeb4ff0SJeff Layton 1209baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1210baeb4ff0SJeff Layton recalculate_deny_mode(fp); 121182c5ff1bSJeff Layton 121282c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 121382c5ff1bSJeff Layton if (test_access(i, stp)) 121411b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 121582c5ff1bSJeff Layton clear_access(i, stp); 121682c5ff1bSJeff Layton } 121782c5ff1bSJeff Layton } 121882c5ff1bSJeff Layton 1219d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1220d50ffdedSKinglong Mee { 1221d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1222d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1223d50ffdedSKinglong Mee } 1224d50ffdedSKinglong Mee 12256b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 12266b180f0bSJeff Layton { 1227a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1228a819ecc1SJeff Layton 1229a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1230a819ecc1SJeff Layton 1231a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 12326b180f0bSJeff Layton return; 12338f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1234a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1235d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 12366b180f0bSJeff Layton } 12376b180f0bSJeff Layton 1238e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1239529d7b2aSJ. Bruce Fields { 124011b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 12411d31a253STrond Myklebust 12421c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 12431c755dc1SJeff Layton 1244e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1245e8568739SJeff Layton return false; 1246e8568739SJeff Layton 12471d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1248e8568739SJeff Layton list_del_init(&stp->st_perfile); 12491d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1250529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1251e8568739SJeff Layton return true; 1252529d7b2aSJ. Bruce Fields } 1253529d7b2aSJ. Bruce Fields 12546011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1255529d7b2aSJ. Bruce Fields { 12566011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 12574665e2baSJ. Bruce Fields 12588287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 12596011695dSTrond Myklebust release_all_access(stp); 1260d3134b10SJeff Layton if (stp->st_stateowner) 1261d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 12626011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1263529d7b2aSJ. Bruce Fields } 1264529d7b2aSJ. Bruce Fields 1265b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1266529d7b2aSJ. Bruce Fields { 1267b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1268b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1269529d7b2aSJ. Bruce Fields struct file *file; 1270529d7b2aSJ. Bruce Fields 1271b49e084dSJeff Layton file = find_any_file(stp->st_stid.sc_file); 1272b49e084dSJeff Layton if (file) 1273b49e084dSJeff Layton filp_close(file, (fl_owner_t)lo); 1274b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1275b49e084dSJeff Layton } 1276b49e084dSJeff Layton 12772c41beb0SJeff Layton /* 12782c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 12792c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 12802c41beb0SJeff Layton * reaplist for later destruction. 12812c41beb0SJeff Layton */ 12822c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 12832c41beb0SJeff Layton struct list_head *reaplist) 12842c41beb0SJeff Layton { 12852c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 12862c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 12872c41beb0SJeff Layton 12882c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 12892c41beb0SJeff Layton 12902c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 12912c41beb0SJeff Layton 1292a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 12932c41beb0SJeff Layton wake_up_all(&close_wq); 12942c41beb0SJeff Layton return; 12952c41beb0SJeff Layton } 12962c41beb0SJeff Layton 12972c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 12982c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 12992c41beb0SJeff Layton } 13002c41beb0SJeff Layton 1301e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 13023c1c995cSJeff Layton { 1303f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 13043c1c995cSJeff Layton 13053c1c995cSJeff Layton list_del_init(&stp->st_locks); 1306cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1307e8568739SJeff Layton return unhash_ol_stateid(stp); 13083c1c995cSJeff Layton } 13093c1c995cSJeff Layton 13105adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1311b49e084dSJeff Layton { 1312f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1313e8568739SJeff Layton bool unhashed; 13141c755dc1SJeff Layton 1315f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1316e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1317f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1318e8568739SJeff Layton if (unhashed) 13196011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1320529d7b2aSJ. Bruce Fields } 1321529d7b2aSJ. Bruce Fields 1322c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1323529d7b2aSJ. Bruce Fields { 1324d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1325c58c6610STrond Myklebust 1326d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1327c58c6610STrond Myklebust 13288f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 13298f4b54c5SJeff Layton } 13308f4b54c5SJeff Layton 13312c41beb0SJeff Layton /* 13322c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 13332c41beb0SJeff Layton * fully unhashed. 13342c41beb0SJeff Layton */ 13352c41beb0SJeff Layton static void 13362c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 13372c41beb0SJeff Layton { 13382c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1339fb94d766SKinglong Mee struct nfs4_file *fp; 13402c41beb0SJeff Layton 13412c41beb0SJeff Layton might_sleep(); 13422c41beb0SJeff Layton 13432c41beb0SJeff Layton while (!list_empty(reaplist)) { 13442c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 13452c41beb0SJeff Layton st_locks); 13462c41beb0SJeff Layton list_del(&stp->st_locks); 1347fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 13482c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1349fb94d766SKinglong Mee if (fp) 1350fb94d766SKinglong Mee put_nfs4_file(fp); 13512c41beb0SJeff Layton } 13522c41beb0SJeff Layton } 13532c41beb0SJeff Layton 1354d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1355d83017f9SJeff Layton struct list_head *reaplist) 13563c87b9b7STrond Myklebust { 13573c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 13583c87b9b7STrond Myklebust 1359e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1360e8568739SJeff Layton 13613c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 13623c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 13633c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1364e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1365d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1366529d7b2aSJ. Bruce Fields } 1367529d7b2aSJ. Bruce Fields } 1368529d7b2aSJ. Bruce Fields 1369e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1370d83017f9SJeff Layton struct list_head *reaplist) 13712283963fSJ. Bruce Fields { 1372e8568739SJeff Layton bool unhashed; 1373e8568739SJeff Layton 13742c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 13752c41beb0SJeff Layton 1376e8568739SJeff Layton unhashed = unhash_ol_stateid(stp); 1377d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1378e8568739SJeff Layton return unhashed; 137938c387b5SJ. Bruce Fields } 138038c387b5SJ. Bruce Fields 138138c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 138238c387b5SJ. Bruce Fields { 13832c41beb0SJeff Layton LIST_HEAD(reaplist); 13842c41beb0SJeff Layton 13852c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1386e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 13872c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 13882c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 13892c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 13902283963fSJ. Bruce Fields } 13912283963fSJ. Bruce Fields 13927ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1393f1d110caSJ. Bruce Fields { 1394d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 13957ffb5880STrond Myklebust 1396d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 13977ffb5880STrond Myklebust 13988f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 13998f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1400f1d110caSJ. Bruce Fields } 1401f1d110caSJ. Bruce Fields 1402f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1403f7a4d872SJ. Bruce Fields { 1404217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1405217526e7SJeff Layton nfsd_net_id); 1406217526e7SJeff Layton struct nfs4_ol_stateid *s; 1407f7a4d872SJ. Bruce Fields 1408217526e7SJeff Layton spin_lock(&nn->client_lock); 1409217526e7SJeff Layton s = oo->oo_last_closed_stid; 1410f7a4d872SJ. Bruce Fields if (s) { 1411d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1412f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1413f7a4d872SJ. Bruce Fields } 1414217526e7SJeff Layton spin_unlock(&nn->client_lock); 1415217526e7SJeff Layton if (s) 1416217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1417f7a4d872SJ. Bruce Fields } 1418f7a4d872SJ. Bruce Fields 14192c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 14208f4b54c5SJeff Layton { 14218f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1422d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 14232c41beb0SJeff Layton struct list_head reaplist; 14247ffb5880STrond Myklebust 14252c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 14267ffb5880STrond Myklebust 1427d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 14287ffb5880STrond Myklebust unhash_openowner_locked(oo); 14292c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 14302c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 14312c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1432e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 14332c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 14342c41beb0SJeff Layton } 1435d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 14362c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1437f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 14386b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1439f1d110caSJ. Bruce Fields } 1440f1d110caSJ. Bruce Fields 14415282fd72SMarc Eshel static inline int 14425282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 14435282fd72SMarc Eshel { 14445282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 14455282fd72SMarc Eshel 14465282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 14475282fd72SMarc Eshel } 14485282fd72SMarc Eshel 1449135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 14505282fd72SMarc Eshel static inline void 14515282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 14525282fd72SMarc Eshel { 14535282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 14545282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 14555282fd72SMarc Eshel } 14568f199b82STrond Myklebust #else 14578f199b82STrond Myklebust static inline void 14588f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 14598f199b82STrond Myklebust { 14608f199b82STrond Myklebust } 14618f199b82STrond Myklebust #endif 14628f199b82STrond Myklebust 14639411b1d4SJ. Bruce Fields /* 14649411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 14659411b1d4SJ. Bruce Fields * won't be used for replay. 14669411b1d4SJ. Bruce Fields */ 14679411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 14689411b1d4SJ. Bruce Fields { 14699411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 14709411b1d4SJ. Bruce Fields 14719411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 14729411b1d4SJ. Bruce Fields return; 14739411b1d4SJ. Bruce Fields 14749411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 147558fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 14769411b1d4SJ. Bruce Fields return; 14779411b1d4SJ. Bruce Fields } 14789411b1d4SJ. Bruce Fields if (!so) 14799411b1d4SJ. Bruce Fields return; 14809411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 14819411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 14829411b1d4SJ. Bruce Fields so->so_seqid++; 14839411b1d4SJ. Bruce Fields return; 14849411b1d4SJ. Bruce Fields } 14855282fd72SMarc Eshel 1486ec6b5d7bSAndy Adamson static void 1487ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1488ec6b5d7bSAndy Adamson { 1489ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1490ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1491ec6b5d7bSAndy Adamson 1492ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1493ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1494ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1495ec6b5d7bSAndy Adamson sid->reserved = 0; 1496ec6b5d7bSAndy Adamson } 1497ec6b5d7bSAndy Adamson 1498ec6b5d7bSAndy Adamson /* 1499a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1500a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1501a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1502a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1503a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1504a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1505a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1506a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1507a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1508a649637cSAndy Adamson * for the SEQUENCE op response: 1509ec6b5d7bSAndy Adamson */ 1510a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1511a649637cSAndy Adamson 1512557ce264SAndy Adamson static void 1513557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1514557ce264SAndy Adamson { 1515557ce264SAndy Adamson int i; 1516557ce264SAndy Adamson 151753da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 151853da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1519557ce264SAndy Adamson kfree(ses->se_slots[i]); 1520557ce264SAndy Adamson } 152153da6a53SJ. Bruce Fields } 1522557ce264SAndy Adamson 1523efe0cb6dSJ. Bruce Fields /* 1524efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1525efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1526efe0cb6dSJ. Bruce Fields */ 152755c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1528efe0cb6dSJ. Bruce Fields { 152955c760cfSJ. Bruce Fields u32 size; 1530efe0cb6dSJ. Bruce Fields 153155c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 153255c760cfSJ. Bruce Fields size = 0; 153355c760cfSJ. Bruce Fields else 153455c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 153555c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1536557ce264SAndy Adamson } 1537557ce264SAndy Adamson 15385b6feee9SJ. Bruce Fields /* 15395b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 15405b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 154142b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 15425b6feee9SJ. Bruce Fields */ 154355c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 15445b6feee9SJ. Bruce Fields { 154555c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 154655c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 1547c54f24e3SJ. Bruce Fields unsigned long avail, total_avail; 15485b6feee9SJ. Bruce Fields 15495b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 1550c54f24e3SJ. Bruce Fields total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 1551c54f24e3SJ. Bruce Fields avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1552de766e57SJ. Bruce Fields /* 1553de766e57SJ. Bruce Fields * Never use more than a third of the remaining memory, 1554de766e57SJ. Bruce Fields * unless it's the only way to give this client a slot: 1555de766e57SJ. Bruce Fields */ 1556c54f24e3SJ. Bruce Fields avail = clamp_t(int, avail, slotsize, total_avail/3); 15575b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 15585b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 15595b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 15605b6feee9SJ. Bruce Fields 15615b6feee9SJ. Bruce Fields return num; 15625b6feee9SJ. Bruce Fields } 15635b6feee9SJ. Bruce Fields 156455c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 15655b6feee9SJ. Bruce Fields { 156655c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 156755c760cfSJ. Bruce Fields 15685b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 156955c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 15705b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 15715b6feee9SJ. Bruce Fields } 15725b6feee9SJ. Bruce Fields 157360810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 157460810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 15755b6feee9SJ. Bruce Fields { 157660810e54SKinglong Mee int numslots = fattrs->maxreqs; 157760810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 15785b6feee9SJ. Bruce Fields struct nfsd4_session *new; 15795b6feee9SJ. Bruce Fields int mem, i; 1580ec6b5d7bSAndy Adamson 1581c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1582ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 15835b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1584ec6b5d7bSAndy Adamson 15855b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 15866c18ba9fSAlexandros Batsakis if (!new) 15875b6feee9SJ. Bruce Fields return NULL; 1588ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 15895b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 159055c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 15915b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1592ec6b5d7bSAndy Adamson goto out_free; 1593ec6b5d7bSAndy Adamson } 159460810e54SKinglong Mee 159560810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 159660810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 159760810e54SKinglong Mee 15985b6feee9SJ. Bruce Fields return new; 15995b6feee9SJ. Bruce Fields out_free: 16005b6feee9SJ. Bruce Fields while (i--) 16015b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 16025b6feee9SJ. Bruce Fields kfree(new); 16035b6feee9SJ. Bruce Fields return NULL; 16045b6feee9SJ. Bruce Fields } 16055b6feee9SJ. Bruce Fields 160619cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 160719cf5c02SJ. Bruce Fields { 160819cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 160919cf5c02SJ. Bruce Fields kfree(c); 161019cf5c02SJ. Bruce Fields } 161119cf5c02SJ. Bruce Fields 161219cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 161319cf5c02SJ. Bruce Fields { 161419cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 161519cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 161619cf5c02SJ. Bruce Fields 161719cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 161819cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 161919cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 162019cf5c02SJ. Bruce Fields free_conn(c); 162119cf5c02SJ. Bruce Fields } 1622eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 16232e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 162419cf5c02SJ. Bruce Fields } 162519cf5c02SJ. Bruce Fields 1626d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1627c7662518SJ. Bruce Fields { 1628c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1629c7662518SJ. Bruce Fields 1630c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1631c7662518SJ. Bruce Fields if (!conn) 1632db90681dSJ. Bruce Fields return NULL; 1633c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1634c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1635d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1636db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1637db90681dSJ. Bruce Fields return conn; 1638db90681dSJ. Bruce Fields } 1639db90681dSJ. Bruce Fields 1640328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1641328ead28SJ. Bruce Fields { 1642328ead28SJ. Bruce Fields conn->cn_session = ses; 1643328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1644328ead28SJ. Bruce Fields } 1645328ead28SJ. Bruce Fields 1646db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1647db90681dSJ. Bruce Fields { 1648db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1649c7662518SJ. Bruce Fields 1650c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1651328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1652c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1653db90681dSJ. Bruce Fields } 1654c7662518SJ. Bruce Fields 165521b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1656db90681dSJ. Bruce Fields { 165719cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 165821b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1659db90681dSJ. Bruce Fields } 1660db90681dSJ. Bruce Fields 1661e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1662db90681dSJ. Bruce Fields { 166321b75b01SJ. Bruce Fields int ret; 1664db90681dSJ. Bruce Fields 1665db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 166621b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 166721b75b01SJ. Bruce Fields if (ret) 166821b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 166921b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 167057a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 167157a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1672c7662518SJ. Bruce Fields } 1673c7662518SJ. Bruce Fields 1674e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 16751d1bc8f2SJ. Bruce Fields { 16761d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 16771d1bc8f2SJ. Bruce Fields 1678e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 16791d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1680e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 16811d1bc8f2SJ. Bruce Fields } 16821d1bc8f2SJ. Bruce Fields 16831d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 168419cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1685c7662518SJ. Bruce Fields { 168619cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 168719cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 168819cf5c02SJ. Bruce Fields 168919cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 169019cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 169119cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 169219cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 169319cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 169419cf5c02SJ. Bruce Fields 169519cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 169619cf5c02SJ. Bruce Fields free_conn(c); 169719cf5c02SJ. Bruce Fields 169819cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 169919cf5c02SJ. Bruce Fields } 170019cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1701c7662518SJ. Bruce Fields } 1702c7662518SJ. Bruce Fields 17031377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 17041377b69eSJ. Bruce Fields { 17051377b69eSJ. Bruce Fields free_session_slots(ses); 17061377b69eSJ. Bruce Fields kfree(ses); 17071377b69eSJ. Bruce Fields } 17081377b69eSJ. Bruce Fields 170966b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1710508dc6e1SBenny Halevy { 1711c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 171255c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1713c7662518SJ. Bruce Fields __free_session(ses); 1714a827bcb2SJ. Bruce Fields } 1715ec6b5d7bSAndy Adamson 1716135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1717a827bcb2SJ. Bruce Fields { 1718a827bcb2SJ. Bruce Fields int idx; 17191872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1720a827bcb2SJ. Bruce Fields 1721ec6b5d7bSAndy Adamson new->se_client = clp; 1722ec6b5d7bSAndy Adamson gen_sessionid(new); 1723ec6b5d7bSAndy Adamson 1724c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1725c7662518SJ. Bruce Fields 1726ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1727ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 17288b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1729c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 173066b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 17315b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 17321872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 17334c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1734ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 17354c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 173660810e54SKinglong Mee 1737b0d2e42cSChuck Lever { 1738edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1739dcbeaa68SJ. Bruce Fields /* 1740dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1741dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1742dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1743dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1744dcbeaa68SJ. Bruce Fields * future: 1745dcbeaa68SJ. Bruce Fields */ 1746edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1747edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1748edd76786SJ. Bruce Fields } 1749ec6b5d7bSAndy Adamson } 1750ec6b5d7bSAndy Adamson 17519089f1b4SBenny Halevy /* caller must hold client_lock */ 17525282fd72SMarc Eshel static struct nfsd4_session * 1753d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 17545282fd72SMarc Eshel { 17555282fd72SMarc Eshel struct nfsd4_session *elem; 17565282fd72SMarc Eshel int idx; 17571872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 17585282fd72SMarc Eshel 17590a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 17600a880a28STrond Myklebust 17615282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 17625282fd72SMarc Eshel idx = hash_sessionid(sessionid); 17635282fd72SMarc Eshel /* Search in the appropriate list */ 17641872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 17655282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 17665282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 17675282fd72SMarc Eshel return elem; 17685282fd72SMarc Eshel } 17695282fd72SMarc Eshel } 17705282fd72SMarc Eshel 17715282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 17725282fd72SMarc Eshel return NULL; 17735282fd72SMarc Eshel } 17745282fd72SMarc Eshel 1775d4e19e70STrond Myklebust static struct nfsd4_session * 1776d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1777d4e19e70STrond Myklebust __be32 *ret) 1778d4e19e70STrond Myklebust { 1779d4e19e70STrond Myklebust struct nfsd4_session *session; 1780d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1781d4e19e70STrond Myklebust 1782d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1783d4e19e70STrond Myklebust if (!session) 1784d4e19e70STrond Myklebust goto out; 1785d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1786d4e19e70STrond Myklebust if (status) 1787d4e19e70STrond Myklebust session = NULL; 1788d4e19e70STrond Myklebust out: 1789d4e19e70STrond Myklebust *ret = status; 1790d4e19e70STrond Myklebust return session; 1791d4e19e70STrond Myklebust } 1792d4e19e70STrond Myklebust 17939089f1b4SBenny Halevy /* caller must hold client_lock */ 17947116ed6bSAndy Adamson static void 17955282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 17967116ed6bSAndy Adamson { 17970a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 17980a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 17990a880a28STrond Myklebust 18000a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 18010a880a28STrond Myklebust 18027116ed6bSAndy Adamson list_del(&ses->se_hash); 18034c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 18047116ed6bSAndy Adamson list_del(&ses->se_perclnt); 18054c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 18065282fd72SMarc Eshel } 18075282fd72SMarc Eshel 18081da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 18091da177e4SLinus Torvalds static int 18102c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 18111da177e4SLinus Torvalds { 1812bbc7f33aSJ. Bruce Fields /* 1813bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 1814bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 1815bbc7f33aSJ. Bruce Fields * a safe assumption: 1816bbc7f33aSJ. Bruce Fields */ 1817bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 18181da177e4SLinus Torvalds return 0; 181960adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 18202c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 18211da177e4SLinus Torvalds return 1; 18221da177e4SLinus Torvalds } 18231da177e4SLinus Torvalds 18241da177e4SLinus Torvalds /* 18251da177e4SLinus Torvalds * XXX Should we use a slab cache ? 18261da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 18271da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 18281da177e4SLinus Torvalds */ 182935bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 18301da177e4SLinus Torvalds { 18311da177e4SLinus Torvalds struct nfs4_client *clp; 1832d4f0489fSTrond Myklebust int i; 18331da177e4SLinus Torvalds 18349258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 183535bba9a3SJ. Bruce Fields if (clp == NULL) 183635bba9a3SJ. Bruce Fields return NULL; 183767114fe6SThomas Meyer clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); 1838d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1839d4f0489fSTrond Myklebust goto err_no_name; 18406da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 18416da2ec56SKees Cook sizeof(struct list_head), 18426da2ec56SKees Cook GFP_KERNEL); 1843d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1844d4f0489fSTrond Myklebust goto err_no_hashtbl; 1845d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1846d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 18471da177e4SLinus Torvalds clp->cl_name.len = name.len; 18485694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 18495694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 18505694c93eSTrond Myklebust atomic_set(&clp->cl_refcount, 0); 18515694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 18525694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 18535694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 18545694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 18555694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 18565694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 18579cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 18589cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 18599cf514ccSChristoph Hellwig #endif 1860e0639dc5SOlga Kornievskaia INIT_LIST_HEAD(&clp->async_copies); 1861e0639dc5SOlga Kornievskaia spin_lock_init(&clp->async_lock); 18625694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 18635694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 18641da177e4SLinus Torvalds return clp; 1865d4f0489fSTrond Myklebust err_no_hashtbl: 1866d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1867d4f0489fSTrond Myklebust err_no_name: 18689258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 1869d4f0489fSTrond Myklebust return NULL; 18701da177e4SLinus Torvalds } 18711da177e4SLinus Torvalds 18724dd86e15STrond Myklebust static void 18731da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 18741da177e4SLinus Torvalds { 1875792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1876792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1877792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1878792c95ddSJ. Bruce Fields se_perclnt); 1879792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 188066b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 188166b2b9b2SJ. Bruce Fields free_session(ses); 1882792c95ddSJ. Bruce Fields } 18834cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 188403a4e1f6SJ. Bruce Fields free_svc_cred(&clp->cl_cred); 1885d4f0489fSTrond Myklebust kfree(clp->cl_ownerstr_hashtbl); 18861da177e4SLinus Torvalds kfree(clp->cl_name.data); 18872d32b29aSmajianpeng idr_destroy(&clp->cl_stateids); 18889258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 18891da177e4SLinus Torvalds } 18901da177e4SLinus Torvalds 189184d38ac9SBenny Halevy /* must be called under the client_lock */ 18924beb345bSTrond Myklebust static void 189384d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 189484d38ac9SBenny Halevy { 18954beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1896792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1897792c95ddSJ. Bruce Fields 18980a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 18990a880a28STrond Myklebust 19004beb345bSTrond Myklebust /* Mark the client as expired! */ 19014beb345bSTrond Myklebust clp->cl_time = 0; 19024beb345bSTrond Myklebust /* Make it invisible */ 19034beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 19044beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 19054beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 19064beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 19074beb345bSTrond Myklebust else 19084beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 19094beb345bSTrond Myklebust } 19104beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 19114c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1912792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1913792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 19144c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 191584d38ac9SBenny Halevy } 191684d38ac9SBenny Halevy 19171da177e4SLinus Torvalds static void 19184beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 19194beb345bSTrond Myklebust { 19204beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 19214beb345bSTrond Myklebust 19224beb345bSTrond Myklebust spin_lock(&nn->client_lock); 19234beb345bSTrond Myklebust unhash_client_locked(clp); 19244beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 19254beb345bSTrond Myklebust } 19264beb345bSTrond Myklebust 192797403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 192897403d95SJeff Layton { 192997403d95SJeff Layton if (atomic_read(&clp->cl_refcount)) 193097403d95SJeff Layton return nfserr_jukebox; 193197403d95SJeff Layton unhash_client_locked(clp); 193297403d95SJeff Layton return nfs_ok; 193397403d95SJeff Layton } 193497403d95SJeff Layton 19354beb345bSTrond Myklebust static void 19364beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 19371da177e4SLinus Torvalds { 193868ef3bc3SJeff Layton int i; 1939fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 19401da177e4SLinus Torvalds struct nfs4_delegation *dp; 19411da177e4SLinus Torvalds struct list_head reaplist; 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 1944cdc97505SBenny Halevy spin_lock(&state_lock); 1945ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 1946ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 19473fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 194842690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 19491da177e4SLinus Torvalds } 1950cdc97505SBenny Halevy spin_unlock(&state_lock); 19511da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 19521da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 195342690676SJeff Layton list_del_init(&dp->dl_recall_lru); 19540af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 19551da177e4SLinus Torvalds } 19562d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 1957c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 19582d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 19596011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 1960956c4feeSBenny Halevy } 1961ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 1962fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1963b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 1964fe0750e5SJ. Bruce Fields release_openowner(oo); 19651da177e4SLinus Torvalds } 196668ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 196768ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 196868ef3bc3SJeff Layton 196968ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 197068ef3bc3SJeff Layton so_strhash) { 197168ef3bc3SJeff Layton /* Should be no openowners at this point */ 197268ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 197368ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 197468ef3bc3SJeff Layton } 197568ef3bc3SJeff Layton } 19769cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 1977e0639dc5SOlga Kornievskaia nfsd4_shutdown_copy(clp); 19786ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 19792bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 19802bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1981b12a05cbSJ. Bruce Fields free_client(clp); 19821da177e4SLinus Torvalds } 19831da177e4SLinus Torvalds 19844beb345bSTrond Myklebust static void 19854beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 19864beb345bSTrond Myklebust { 19874beb345bSTrond Myklebust unhash_client(clp); 19884beb345bSTrond Myklebust __destroy_client(clp); 19894beb345bSTrond Myklebust } 19904beb345bSTrond Myklebust 19910d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 19920d22f68fSJ. Bruce Fields { 19934beb345bSTrond Myklebust unhash_client(clp); 19940d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 19954beb345bSTrond Myklebust __destroy_client(clp); 19960d22f68fSJ. Bruce Fields } 19970d22f68fSJ. Bruce Fields 199835bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 199935bba9a3SJ. Bruce Fields { 200035bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 200135bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 20021da177e4SLinus Torvalds } 20031da177e4SLinus Torvalds 200435bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 200535bba9a3SJ. Bruce Fields { 20061da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 20071da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 20081da177e4SLinus Torvalds } 20091da177e4SLinus Torvalds 201050043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 201150043859SJ. Bruce Fields { 20122f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 20132f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 20142f10fdcbSNeilBrown GFP_KERNEL); 20159abdda5dSChuck Lever target->cr_targ_princ = kstrdup(source->cr_targ_princ, GFP_KERNEL); 20162f10fdcbSNeilBrown if ((source->cr_principal && !target->cr_principal) || 20179abdda5dSChuck Lever (source->cr_raw_principal && !target->cr_raw_principal) || 20189abdda5dSChuck Lever (source->cr_targ_princ && !target->cr_targ_princ)) 20192f10fdcbSNeilBrown return -ENOMEM; 202050043859SJ. Bruce Fields 2021d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 20221da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 20231da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 20241da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 20251da177e4SLinus Torvalds get_group_info(target->cr_group_info); 20260dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 20270dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 20280dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 202903a4e1f6SJ. Bruce Fields return 0; 20301da177e4SLinus Torvalds } 20311da177e4SLinus Torvalds 2032ef17af2aSRasmus Villemoes static int 2033ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 2034ac55fdc4SJeff Layton { 2035ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2036ef17af2aSRasmus Villemoes return -1; 2037ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2038ef17af2aSRasmus Villemoes return 1; 2039ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2040ac55fdc4SJeff Layton } 2041ac55fdc4SJeff Layton 204235bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 2043599e0a22SJ. Bruce Fields { 2044a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 20451da177e4SLinus Torvalds } 20461da177e4SLinus Torvalds 20471da177e4SLinus Torvalds static int 2048599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2049599e0a22SJ. Bruce Fields { 2050599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 20511da177e4SLinus Torvalds } 20521da177e4SLinus Torvalds 20531da177e4SLinus Torvalds static int 2054599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2055599e0a22SJ. Bruce Fields { 2056599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 20571da177e4SLinus Torvalds } 20581da177e4SLinus Torvalds 20598fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 20608fbba96eSJ. Bruce Fields { 20618fbba96eSJ. Bruce Fields int i; 20628fbba96eSJ. Bruce Fields 20638fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 20648fbba96eSJ. Bruce Fields return false; 20658fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 206681243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 20678fbba96eSJ. Bruce Fields return false; 20688fbba96eSJ. Bruce Fields return true; 20698fbba96eSJ. Bruce Fields } 20708fbba96eSJ. Bruce Fields 207168eb3508SJ. Bruce Fields /* 207268eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 207368eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 207468eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 207568eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 207668eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 207768eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 207868eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 207968eb3508SJ. Bruce Fields */ 208068eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 208168eb3508SJ. Bruce Fields { 208268eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 208368eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 208468eb3508SJ. Bruce Fields } 208568eb3508SJ. Bruce Fields 208668eb3508SJ. Bruce Fields 20875559b50aSVivek Trivedi static bool 2088599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2089599e0a22SJ. Bruce Fields { 209068eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 20916fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 20926fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 20938fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 20948fbba96eSJ. Bruce Fields return false; 20959abdda5dSChuck Lever /* XXX: check that cr_targ_princ fields match ? */ 20968fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 20978fbba96eSJ. Bruce Fields return true; 20988fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 20998fbba96eSJ. Bruce Fields return false; 21005559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 21011da177e4SLinus Torvalds } 21021da177e4SLinus Torvalds 210357266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 210457266a6eSJ. Bruce Fields { 210557266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 210657266a6eSJ. Bruce Fields u32 service; 210757266a6eSJ. Bruce Fields 2108c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2109c4720591SJ. Bruce Fields return false; 211057266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 211157266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 211257266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 211357266a6eSJ. Bruce Fields } 211457266a6eSJ. Bruce Fields 2115dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 211657266a6eSJ. Bruce Fields { 211757266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 211857266a6eSJ. Bruce Fields 211957266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 212057266a6eSJ. Bruce Fields return true; 212157266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 212257266a6eSJ. Bruce Fields return false; 212357266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 212457266a6eSJ. Bruce Fields return false; 2125414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2126414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2127414ca017SJ. Bruce Fields cr->cr_raw_principal); 212857266a6eSJ. Bruce Fields if (!cr->cr_principal) 212957266a6eSJ. Bruce Fields return false; 213057266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 213157266a6eSJ. Bruce Fields } 213257266a6eSJ. Bruce Fields 2133294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2134deda2faaSJ. Bruce Fields { 2135ab4684d1SChuck Lever __be32 verf[2]; 21361da177e4SLinus Torvalds 2137f419992cSJeff Layton /* 2138f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2139f419992cSJeff Layton * __force to keep sparse happy 2140f419992cSJeff Layton */ 2141f419992cSJeff Layton verf[0] = (__force __be32)get_seconds(); 214219311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2143ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 21441da177e4SLinus Torvalds } 21451da177e4SLinus Torvalds 2146294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2147294ac32eSJeff Layton { 2148294ac32eSJeff Layton clp->cl_clientid.cl_boot = nn->boot_time; 2149294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2150294ac32eSJeff Layton gen_confirm(clp, nn); 2151294ac32eSJeff Layton } 2152294ac32eSJeff Layton 21534770d722SJeff Layton static struct nfs4_stid * 21544770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 21554581d140SJ. Bruce Fields { 21563abdb607SJ. Bruce Fields struct nfs4_stid *ret; 21573abdb607SJ. Bruce Fields 21583abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 21593abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 21603abdb607SJ. Bruce Fields return NULL; 21613abdb607SJ. Bruce Fields return ret; 21624581d140SJ. Bruce Fields } 21634d71ab87SJ. Bruce Fields 21644770d722SJeff Layton static struct nfs4_stid * 21654770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2166f459e453SJ. Bruce Fields { 2167f459e453SJ. Bruce Fields struct nfs4_stid *s; 2168f459e453SJ. Bruce Fields 21694770d722SJeff Layton spin_lock(&cl->cl_lock); 21704770d722SJeff Layton s = find_stateid_locked(cl, t); 21712d3f9668STrond Myklebust if (s != NULL) { 21722d3f9668STrond Myklebust if (typemask & s->sc_type) 2173a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 21742d3f9668STrond Myklebust else 21754770d722SJeff Layton s = NULL; 21762d3f9668STrond Myklebust } 21774770d722SJeff Layton spin_unlock(&cl->cl_lock); 21784d71ab87SJ. Bruce Fields return s; 21794581d140SJ. Bruce Fields } 21804581d140SJ. Bruce Fields 21812216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2182b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2183b09333c4SRicardo Labiaga { 2184b09333c4SRicardo Labiaga struct nfs4_client *clp; 2185b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 218603a4e1f6SJ. Bruce Fields int ret; 2187c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2188b09333c4SRicardo Labiaga 2189b09333c4SRicardo Labiaga clp = alloc_client(name); 2190b09333c4SRicardo Labiaga if (clp == NULL) 2191b09333c4SRicardo Labiaga return NULL; 2192b09333c4SRicardo Labiaga 219303a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 219403a4e1f6SJ. Bruce Fields if (ret) { 2195b09333c4SRicardo Labiaga free_client(clp); 2196b09333c4SRicardo Labiaga return NULL; 2197b09333c4SRicardo Labiaga } 21980162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 219907cd4909SBenny Halevy clp->cl_time = get_seconds(); 2200b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2201b09333c4SRicardo Labiaga copy_verf(clp, verf); 2202b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 2203edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2204c212cecfSStanislav Kinsbursky clp->net = net; 2205b09333c4SRicardo Labiaga return clp; 2206b09333c4SRicardo Labiaga } 2207b09333c4SRicardo Labiaga 2208fd39ca9aSNeilBrown static void 2209ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2210ac55fdc4SJeff Layton { 2211ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2212ac55fdc4SJeff Layton struct nfs4_client *clp; 2213ac55fdc4SJeff Layton 2214ac55fdc4SJeff Layton while (*new) { 2215ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2216ac55fdc4SJeff Layton parent = *new; 2217ac55fdc4SJeff Layton 2218ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2219ac55fdc4SJeff Layton new = &((*new)->rb_left); 2220ac55fdc4SJeff Layton else 2221ac55fdc4SJeff Layton new = &((*new)->rb_right); 2222ac55fdc4SJeff Layton } 2223ac55fdc4SJeff Layton 2224ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2225ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2226ac55fdc4SJeff Layton } 2227ac55fdc4SJeff Layton 2228ac55fdc4SJeff Layton static struct nfs4_client * 2229ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2230ac55fdc4SJeff Layton { 2231ef17af2aSRasmus Villemoes int cmp; 2232ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2233ac55fdc4SJeff Layton struct nfs4_client *clp; 2234ac55fdc4SJeff Layton 2235ac55fdc4SJeff Layton while (node) { 2236ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2237ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2238ac55fdc4SJeff Layton if (cmp > 0) 2239ac55fdc4SJeff Layton node = node->rb_left; 2240ac55fdc4SJeff Layton else if (cmp < 0) 2241ac55fdc4SJeff Layton node = node->rb_right; 2242ac55fdc4SJeff Layton else 2243ac55fdc4SJeff Layton return clp; 2244ac55fdc4SJeff Layton } 2245ac55fdc4SJeff Layton return NULL; 2246ac55fdc4SJeff Layton } 2247ac55fdc4SJeff Layton 2248ac55fdc4SJeff Layton static void 2249ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 22501da177e4SLinus Torvalds { 22511da177e4SLinus Torvalds unsigned int idhashval; 22520a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 22531da177e4SLinus Torvalds 22540a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 22550a880a28STrond Myklebust 2256ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2257a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 22581da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 22590a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 22603dbacee6STrond Myklebust renew_client_locked(clp); 22611da177e4SLinus Torvalds } 22621da177e4SLinus Torvalds 2263fd39ca9aSNeilBrown static void 22641da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 22651da177e4SLinus Torvalds { 22661da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 22678daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 22681da177e4SLinus Torvalds 22690a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 22700a880a28STrond Myklebust 22711da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 22728daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2273a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2274382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2275ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 22763dbacee6STrond Myklebust renew_client_locked(clp); 22771da177e4SLinus Torvalds } 22781da177e4SLinus Torvalds 22791da177e4SLinus Torvalds static struct nfs4_client * 2280bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 22811da177e4SLinus Torvalds { 22821da177e4SLinus Torvalds struct nfs4_client *clp; 22831da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 22841da177e4SLinus Torvalds 2285bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2286a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2287d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2288d15c077eSJ. Bruce Fields return NULL; 22893dbacee6STrond Myklebust renew_client_locked(clp); 22901da177e4SLinus Torvalds return clp; 22911da177e4SLinus Torvalds } 2292a50d2ad1SJ. Bruce Fields } 22931da177e4SLinus Torvalds return NULL; 22941da177e4SLinus Torvalds } 22951da177e4SLinus Torvalds 22961da177e4SLinus Torvalds static struct nfs4_client * 2297bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2298bfa85e83SJ. Bruce Fields { 2299bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2300bfa85e83SJ. Bruce Fields 23010a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2302bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2303bfa85e83SJ. Bruce Fields } 2304bfa85e83SJ. Bruce Fields 2305bfa85e83SJ. Bruce Fields static struct nfs4_client * 23060a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 23071da177e4SLinus Torvalds { 2308bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 23091da177e4SLinus Torvalds 23100a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2311bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 23121da177e4SLinus Torvalds } 23131da177e4SLinus Torvalds 23146e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2315a1bcecd2SAndy Adamson { 23166e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2317a1bcecd2SAndy Adamson } 2318a1bcecd2SAndy Adamson 231928ce6054SNeilBrown static struct nfs4_client * 2320382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 232128ce6054SNeilBrown { 23220a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2323382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 232428ce6054SNeilBrown } 232528ce6054SNeilBrown 232628ce6054SNeilBrown static struct nfs4_client * 2327a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 232828ce6054SNeilBrown { 23290a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2330a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 233128ce6054SNeilBrown } 233228ce6054SNeilBrown 2333fd39ca9aSNeilBrown static void 23346f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 23351da177e4SLinus Torvalds { 233607263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 23376f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 23386f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 23397077ecbaSJeff Layton unsigned short expected_family; 23401da177e4SLinus Torvalds 23417077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 23427077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 23437077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 23447077ecbaSJeff Layton expected_family = AF_INET; 23457077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 23467077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 23477077ecbaSJeff Layton expected_family = AF_INET6; 23487077ecbaSJeff Layton else 23491da177e4SLinus Torvalds goto out_err; 23501da177e4SLinus Torvalds 2351c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2352aa9a4ec7SJeff Layton se->se_callback_addr_len, 235307263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 235407263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2355aa9a4ec7SJeff Layton 235607263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 23571da177e4SLinus Torvalds goto out_err; 2358aa9a4ec7SJeff Layton 235907263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 236007263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2361fbf4665fSJeff Layton 236207263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 236307263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2364849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 23651da177e4SLinus Torvalds return; 23661da177e4SLinus Torvalds out_err: 236707263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 236807263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 23694ab495bfSRasmus Villemoes dprintk("NFSD: this client (clientid %08x/%08x) " 23701da177e4SLinus Torvalds "will not receive delegations\n", 23711da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 23721da177e4SLinus Torvalds 23731da177e4SLinus Torvalds return; 23741da177e4SLinus Torvalds } 23751da177e4SLinus Torvalds 2376074fe897SAndy Adamson /* 2377067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2378074fe897SAndy Adamson */ 2379b607664eSTrond Myklebust static void 2380074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2381074fe897SAndy Adamson { 2382f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2383557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2384557ce264SAndy Adamson unsigned int base; 2385074fe897SAndy Adamson 2386557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2387074fe897SAndy Adamson 2388085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2389557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2390557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 239153da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 239253da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 2393bf864a31SAndy Adamson 2394085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 2395085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 2396bf864a31SAndy Adamson return; 2397bf864a31SAndy Adamson } 2398085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 2399085def3aSJ. Bruce Fields 2400f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2401f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2402f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2403d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 2404d3f03403SDan Carpenter __func__); 2405557ce264SAndy Adamson return; 2406074fe897SAndy Adamson } 2407074fe897SAndy Adamson 2408074fe897SAndy Adamson /* 2409abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2410abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2411abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2412abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2413abfabf8cSAndy Adamson * 2414074fe897SAndy Adamson */ 2415abfabf8cSAndy Adamson static __be32 2416abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2417abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2418074fe897SAndy Adamson { 2419abfabf8cSAndy Adamson struct nfsd4_op *op; 2420abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2421074fe897SAndy Adamson 2422abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2423abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2424abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2425abfabf8cSAndy Adamson 2426085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 2427085def3aSJ. Bruce Fields return op->status; 2428085def3aSJ. Bruce Fields if (args->opcnt == 1) { 2429085def3aSJ. Bruce Fields /* 2430085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 2431085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 2432085def3aSJ. Bruce Fields * original: 2433085def3aSJ. Bruce Fields */ 2434085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 2435085def3aSJ. Bruce Fields } else { 2436abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2437abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2438abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2439074fe897SAndy Adamson } 2440abfabf8cSAndy Adamson return op->status; 2441074fe897SAndy Adamson } 2442074fe897SAndy Adamson 2443074fe897SAndy Adamson /* 2444557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2445557ce264SAndy Adamson * session values. 2446074fe897SAndy Adamson */ 24473ca2eb98SJ. Bruce Fields static __be32 2448bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2449bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2450074fe897SAndy Adamson { 2451557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2452f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2453f5236013SJ. Bruce Fields __be32 *p; 2454074fe897SAndy Adamson __be32 status; 2455074fe897SAndy Adamson 2456557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2457074fe897SAndy Adamson 2458abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 24590da7b19cSJ. Bruce Fields if (status) 2460abfabf8cSAndy Adamson return status; 2461074fe897SAndy Adamson 2462f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2463f5236013SJ. Bruce Fields if (!p) { 2464f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2465f5236013SJ. Bruce Fields return nfserr_serverfault; 2466f5236013SJ. Bruce Fields } 2467f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2468f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2469074fe897SAndy Adamson 2470557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2471f5236013SJ. Bruce Fields return slot->sl_status; 2472074fe897SAndy Adamson } 2473074fe897SAndy Adamson 24740733d213SAndy Adamson /* 24750733d213SAndy Adamson * Set the exchange_id flags returned by the server. 24760733d213SAndy Adamson */ 24770733d213SAndy Adamson static void 24780733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 24790733d213SAndy Adamson { 24809cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 24819cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 24829cf514ccSChristoph Hellwig #else 24830733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 24849cf514ccSChristoph Hellwig #endif 24850733d213SAndy Adamson 24860733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 24870733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 24880733d213SAndy Adamson 24890733d213SAndy Adamson /* set the wire flags to return to client. */ 24900733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 24910733d213SAndy Adamson } 24920733d213SAndy Adamson 24934eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 24944eaea134SJ. Bruce Fields { 24954eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 24964eaea134SJ. Bruce Fields 24974eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 24984eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 24994eaea134SJ. Bruce Fields return true; 25004eaea134SJ. Bruce Fields } 25014eaea134SJ. Bruce Fields return false; 25024eaea134SJ. Bruce Fields } 25034eaea134SJ. Bruce Fields 2504631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 2505631fc9eaSJ. Bruce Fields { 25064eaea134SJ. Bruce Fields return client_has_openowners(clp) 250747e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 250847e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 250947e970beSKinglong Mee #endif 25106eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 2511e0639dc5SOlga Kornievskaia || !list_empty(&clp->cl_sessions) 2512e0639dc5SOlga Kornievskaia || !list_empty(&clp->async_copies); 2513631fc9eaSJ. Bruce Fields } 2514631fc9eaSJ. Bruce Fields 2515b37ad28bSAl Viro __be32 2516eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 2517eb69853dSChristoph Hellwig union nfsd4_op_u *u) 2518069b6ad4SAndy Adamson { 2519eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 25203dbacee6STrond Myklebust struct nfs4_client *conf, *new; 25213dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 252257b7b43bSJ. Bruce Fields __be32 status; 2523363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 25240733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 2525363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 252683e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 2527c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 25280733d213SAndy Adamson 2529363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 25300733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 2531363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 25320733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 2533363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 25340733d213SAndy Adamson 2535a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 25360733d213SAndy Adamson return nfserr_inval; 25370733d213SAndy Adamson 253850c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 253950c7b948SJ. Bruce Fields if (new == NULL) 254050c7b948SJ. Bruce Fields return nfserr_jukebox; 254150c7b948SJ. Bruce Fields 25420733d213SAndy Adamson switch (exid->spa_how) { 254357266a6eSJ. Bruce Fields case SP4_MACH_CRED: 2544ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 2545ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 2546ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 2547ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 2548ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 2549ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 2550ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 2551ed941643SAndrew Elble 2552ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 2553ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 2554ed941643SAndrew Elble 1 << (OP_LOCKU) | 2555ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 2556ed941643SAndrew Elble 2557ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 2558ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 2559ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 256050c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 256150c7b948SJ. Bruce Fields status = nfserr_inval; 256250c7b948SJ. Bruce Fields goto out_nolock; 256350c7b948SJ. Bruce Fields } 2564920dd9bbSJ. Bruce Fields /* 2565920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 2566920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 2567920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 2568920dd9bbSJ. Bruce Fields */ 2569414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 2570414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 2571920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 2572920dd9bbSJ. Bruce Fields goto out_nolock; 2573920dd9bbSJ. Bruce Fields } 257450c7b948SJ. Bruce Fields new->cl_mach_cred = true; 25750733d213SAndy Adamson case SP4_NONE: 25760733d213SAndy Adamson break; 2577063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 2578063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 25790a4c9265SGustavo A. R. Silva /* fall through */ 25800733d213SAndy Adamson case SP4_SSV: 25818edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 25828edf4b02SKinglong Mee goto out_nolock; 25830733d213SAndy Adamson } 25840733d213SAndy Adamson 25852dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 25863dbacee6STrond Myklebust spin_lock(&nn->client_lock); 2587382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 25880733d213SAndy Adamson if (conf) { 258983e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 259083e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 259183e08fd4SJ. Bruce Fields 2592136e658dSJ. Bruce Fields if (update) { 2593136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 25942dbb269dSJ. Bruce Fields status = nfserr_inval; 2595e203d506SJ. Bruce Fields goto out; 2596e203d506SJ. Bruce Fields } 2597dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 259857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 259957266a6eSJ. Bruce Fields goto out; 260057266a6eSJ. Bruce Fields } 26012dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 26020733d213SAndy Adamson status = nfserr_perm; 26030733d213SAndy Adamson goto out; 26040733d213SAndy Adamson } 26052dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 26060733d213SAndy Adamson status = nfserr_not_same; 26070733d213SAndy Adamson goto out; 26080733d213SAndy Adamson } 2609136e658dSJ. Bruce Fields /* case 6 */ 26100733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 26110733d213SAndy Adamson goto out_copy; 26126ddbbbfeSMike Sager } 2613136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 2614631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 2615136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 2616136e658dSJ. Bruce Fields goto out; 2617136e658dSJ. Bruce Fields } 2618b9831b59SJ. Bruce Fields goto out_new; 2619631fc9eaSJ. Bruce Fields } 2620136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 26210f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 2622136e658dSJ. Bruce Fields goto out_copy; 2623136e658dSJ. Bruce Fields } 26242dbb269dSJ. Bruce Fields /* case 5, client reboot */ 26253dbacee6STrond Myklebust conf = NULL; 26260733d213SAndy Adamson goto out_new; 26270733d213SAndy Adamson } 26286ddbbbfeSMike Sager 26292dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 26300733d213SAndy Adamson status = nfserr_noent; 26310733d213SAndy Adamson goto out; 26320733d213SAndy Adamson } 26330733d213SAndy Adamson 2634a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 26352dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 26363dbacee6STrond Myklebust unhash_client_locked(unconf); 26370733d213SAndy Adamson 26382dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 26390733d213SAndy Adamson out_new: 2640fd699b8aSJeff Layton if (conf) { 2641fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 2642fd699b8aSJeff Layton if (status) 2643fd699b8aSJeff Layton goto out; 2644fd699b8aSJeff Layton } 26454f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 2646ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 2647ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 26480733d213SAndy Adamson 2649c212cecfSStanislav Kinsbursky gen_clid(new, nn); 2650ac55fdc4SJeff Layton add_to_unconfirmed(new); 26513dbacee6STrond Myklebust swap(new, conf); 26520733d213SAndy Adamson out_copy: 26535cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 26545cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 26550733d213SAndy Adamson 26565cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 26575cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 26580733d213SAndy Adamson 26590733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 26605cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 26610733d213SAndy Adamson status = nfs_ok; 26620733d213SAndy Adamson 26630733d213SAndy Adamson out: 26643dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 266550c7b948SJ. Bruce Fields out_nolock: 26665cc40fd7STrond Myklebust if (new) 26673dbacee6STrond Myklebust expire_client(new); 26683dbacee6STrond Myklebust if (unconf) 26693dbacee6STrond Myklebust expire_client(unconf); 26700733d213SAndy Adamson return status; 2671069b6ad4SAndy Adamson } 2672069b6ad4SAndy Adamson 267357b7b43bSJ. Bruce Fields static __be32 267488e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 2675b85d4c01SBenny Halevy { 267688e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 267788e588d5SAndy Adamson slot_seqid); 2678b85d4c01SBenny Halevy 2679b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 268088e588d5SAndy Adamson if (slot_inuse) { 268188e588d5SAndy Adamson if (seqid == slot_seqid) 2682b85d4c01SBenny Halevy return nfserr_jukebox; 2683b85d4c01SBenny Halevy else 2684b85d4c01SBenny Halevy return nfserr_seq_misordered; 2685b85d4c01SBenny Halevy } 2686f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 268788e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 2688b85d4c01SBenny Halevy return nfs_ok; 268988e588d5SAndy Adamson if (seqid == slot_seqid) 2690b85d4c01SBenny Halevy return nfserr_replay_cache; 2691b85d4c01SBenny Halevy return nfserr_seq_misordered; 2692b85d4c01SBenny Halevy } 2693b85d4c01SBenny Halevy 269449557cc7SAndy Adamson /* 269549557cc7SAndy Adamson * Cache the create session result into the create session single DRC 269649557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 269749557cc7SAndy Adamson * Do this for solo or embedded create session operations. 269849557cc7SAndy Adamson */ 269949557cc7SAndy Adamson static void 270049557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 270157b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 270249557cc7SAndy Adamson { 270349557cc7SAndy Adamson slot->sl_status = nfserr; 270449557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 270549557cc7SAndy Adamson } 270649557cc7SAndy Adamson 270749557cc7SAndy Adamson static __be32 270849557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 270949557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 271049557cc7SAndy Adamson { 271149557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 271249557cc7SAndy Adamson return slot->sl_status; 271349557cc7SAndy Adamson } 271449557cc7SAndy Adamson 27151b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 27161b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 27171b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 27181b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 27191b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 27201b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 27211b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 27221b74c25bSMi Jinlong 27231b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 27241b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 27251b74c25bSMi Jinlong 1 + /* status */ \ 27261b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 27271b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 27281b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 27291b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 27301b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 27311b74c25bSMi Jinlong 273255c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 27331b74c25bSMi Jinlong { 273455c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 273555c760cfSJ. Bruce Fields 2736373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 2737373cd409SJ. Bruce Fields return nfserr_toosmall; 2738373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 2739373cd409SJ. Bruce Fields return nfserr_toosmall; 274055c760cfSJ. Bruce Fields ca->headerpadsz = 0; 274155c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 274255c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 274355c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 274455c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 274555c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 274655c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 274755c760cfSJ. Bruce Fields /* 274855c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 274955c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 275055c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 275155c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 275255c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 275355c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 275455c760cfSJ. Bruce Fields */ 275555c760cfSJ. Bruce Fields ca->maxreqs = nfsd4_get_drc_mem(ca); 275655c760cfSJ. Bruce Fields if (!ca->maxreqs) 275755c760cfSJ. Bruce Fields return nfserr_jukebox; 275855c760cfSJ. Bruce Fields 2759373cd409SJ. Bruce Fields return nfs_ok; 27601b74c25bSMi Jinlong } 27611b74c25bSMi Jinlong 27624500632fSChuck Lever /* 27634500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 27644500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 27654500632fSChuck Lever */ 27664500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 27674500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 27684500632fSChuck Lever 27694500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 27704500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 27714500632fSChuck Lever 27728a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 27734500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 27748a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 27754500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 27764500632fSChuck Lever sizeof(__be32)) 27778a891633SKinglong Mee 277806b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 277906b332a5SJ. Bruce Fields { 278006b332a5SJ. Bruce Fields ca->headerpadsz = 0; 278106b332a5SJ. Bruce Fields 27828a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 278306b332a5SJ. Bruce Fields return nfserr_toosmall; 27848a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 278506b332a5SJ. Bruce Fields return nfserr_toosmall; 278606b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 278706b332a5SJ. Bruce Fields if (ca->maxops < 2) 278806b332a5SJ. Bruce Fields return nfserr_toosmall; 278906b332a5SJ. Bruce Fields 279006b332a5SJ. Bruce Fields return nfs_ok; 2791069b6ad4SAndy Adamson } 2792069b6ad4SAndy Adamson 2793b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 2794b78724b7SJ. Bruce Fields { 2795b78724b7SJ. Bruce Fields switch (cbs->flavor) { 2796b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 2797b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 2798b78724b7SJ. Bruce Fields return nfs_ok; 2799b78724b7SJ. Bruce Fields default: 2800b78724b7SJ. Bruce Fields /* 2801b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 2802b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 2803b78724b7SJ. Bruce Fields * GSS. 2804b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 2805b78724b7SJ. Bruce Fields * client might think it can already handle: 2806b78724b7SJ. Bruce Fields */ 2807b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 2808b78724b7SJ. Bruce Fields } 2809b78724b7SJ. Bruce Fields } 2810b78724b7SJ. Bruce Fields 2811069b6ad4SAndy Adamson __be32 2812069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 2813eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 2814069b6ad4SAndy Adamson { 2815eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 2816363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 2817ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 2818d20c11d8SJeff Layton struct nfs4_client *old = NULL; 2819ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 282081f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 282149557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 282257b7b43bSJ. Bruce Fields __be32 status = 0; 28238daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2824ec6b5d7bSAndy Adamson 2825a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 2826a62573dcSMi Jinlong return nfserr_inval; 2827b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 2828b78724b7SJ. Bruce Fields if (status) 2829b78724b7SJ. Bruce Fields return status; 283055c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 2831373cd409SJ. Bruce Fields if (status) 2832373cd409SJ. Bruce Fields return status; 283306b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 283406b332a5SJ. Bruce Fields if (status) 2835f403e450SKinglong Mee goto out_release_drc_mem; 283681f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 283760810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 283855c760cfSJ. Bruce Fields if (!new) 283955c760cfSJ. Bruce Fields goto out_release_drc_mem; 284081f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 284181f0b2a4SJ. Bruce Fields if (!conn) 284281f0b2a4SJ. Bruce Fields goto out_free_session; 2843a62573dcSMi Jinlong 2844d20c11d8SJeff Layton spin_lock(&nn->client_lock); 28450a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 28468daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 284778389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2848ec6b5d7bSAndy Adamson 2849ec6b5d7bSAndy Adamson if (conf) { 285057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 2851dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 285257266a6eSJ. Bruce Fields goto out_free_conn; 285349557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 285449557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 2855f5e22bb6SKinglong Mee if (status) { 2856f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 285749557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 285881f0b2a4SJ. Bruce Fields goto out_free_conn; 2859ec6b5d7bSAndy Adamson } 2860ec6b5d7bSAndy Adamson } else if (unconf) { 2861ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 2862363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 2863ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 286481f0b2a4SJ. Bruce Fields goto out_free_conn; 2865ec6b5d7bSAndy Adamson } 286657266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 2867dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 286857266a6eSJ. Bruce Fields goto out_free_conn; 286949557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 287049557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 287138eb76a5SAndy Adamson if (status) { 287238eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 2873ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 287481f0b2a4SJ. Bruce Fields goto out_free_conn; 2875ec6b5d7bSAndy Adamson } 2876382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 2877221a6876SJ. Bruce Fields if (old) { 2878d20c11d8SJeff Layton status = mark_client_expired_locked(old); 28797abea1e8SJeff Layton if (status) { 28807abea1e8SJeff Layton old = NULL; 2881221a6876SJ. Bruce Fields goto out_free_conn; 2882221a6876SJ. Bruce Fields } 28837abea1e8SJeff Layton } 28848f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 2885ec6b5d7bSAndy Adamson conf = unconf; 2886ec6b5d7bSAndy Adamson } else { 2887ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 288881f0b2a4SJ. Bruce Fields goto out_free_conn; 2889ec6b5d7bSAndy Adamson } 289081f0b2a4SJ. Bruce Fields status = nfs_ok; 28914ce85c8cSChuck Lever /* Persistent sessions are not supported */ 2892408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 28934ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 2894408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 2895408b79bcSJ. Bruce Fields 289681f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 2897d20c11d8SJeff Layton nfsd4_get_session_locked(new); 289881f0b2a4SJ. Bruce Fields 2899ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 2900ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 290186c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 290249557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 2903ec6b5d7bSAndy Adamson 2904d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 290549557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 2906d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 2907d20c11d8SJeff Layton /* init connection and backchannel */ 2908d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 2909d20c11d8SJeff Layton nfsd4_put_session(new); 2910d20c11d8SJeff Layton if (old) 2911d20c11d8SJeff Layton expire_client(old); 2912ec6b5d7bSAndy Adamson return status; 291381f0b2a4SJ. Bruce Fields out_free_conn: 2914d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 291581f0b2a4SJ. Bruce Fields free_conn(conn); 2916d20c11d8SJeff Layton if (old) 2917d20c11d8SJeff Layton expire_client(old); 291881f0b2a4SJ. Bruce Fields out_free_session: 291981f0b2a4SJ. Bruce Fields __free_session(new); 292055c760cfSJ. Bruce Fields out_release_drc_mem: 292155c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 29221ca50792SJ. Bruce Fields return status; 2923069b6ad4SAndy Adamson } 2924069b6ad4SAndy Adamson 29251d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 29261d1bc8f2SJ. Bruce Fields { 29271d1bc8f2SJ. Bruce Fields switch (*dir) { 29281d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 29291d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 29301d1bc8f2SJ. Bruce Fields return nfs_ok; 29311d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 29321d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 29331d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 29341d1bc8f2SJ. Bruce Fields return nfs_ok; 29351d1bc8f2SJ. Bruce Fields }; 29361d1bc8f2SJ. Bruce Fields return nfserr_inval; 29371d1bc8f2SJ. Bruce Fields } 29381d1bc8f2SJ. Bruce Fields 2939eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 2940eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 2941eb69853dSChristoph Hellwig union nfsd4_op_u *u) 2942cb73a9f4SJ. Bruce Fields { 2943eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 2944cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 2945c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2946b78724b7SJ. Bruce Fields __be32 status; 2947cb73a9f4SJ. Bruce Fields 2948b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 2949b78724b7SJ. Bruce Fields if (status) 2950b78724b7SJ. Bruce Fields return status; 2951c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2952cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 2953cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 2954c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2955cb73a9f4SJ. Bruce Fields 2956cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 2957cb73a9f4SJ. Bruce Fields 2958cb73a9f4SJ. Bruce Fields return nfs_ok; 2959cb73a9f4SJ. Bruce Fields } 2960cb73a9f4SJ. Bruce Fields 29611d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 29621d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 2963eb69853dSChristoph Hellwig union nfsd4_op_u *u) 29641d1bc8f2SJ. Bruce Fields { 2965eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 29661d1bc8f2SJ. Bruce Fields __be32 status; 29673ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 29684f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 2969d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2970d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 29711d1bc8f2SJ. Bruce Fields 29721d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 29731d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 2974c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2975d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 2976c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 29774f6e6c17SJ. Bruce Fields if (!session) 2978d4e19e70STrond Myklebust goto out_no_session; 297957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 2980dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 298157266a6eSJ. Bruce Fields goto out; 29821d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 29833ba63671SJ. Bruce Fields if (status) 29844f6e6c17SJ. Bruce Fields goto out; 29853ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 29864f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 29873ba63671SJ. Bruce Fields if (!conn) 29884f6e6c17SJ. Bruce Fields goto out; 29894f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 29904f6e6c17SJ. Bruce Fields status = nfs_ok; 29914f6e6c17SJ. Bruce Fields out: 2992d4e19e70STrond Myklebust nfsd4_put_session(session); 2993d4e19e70STrond Myklebust out_no_session: 29944f6e6c17SJ. Bruce Fields return status; 29951d1bc8f2SJ. Bruce Fields } 29961d1bc8f2SJ. Bruce Fields 2997665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 29985d4cec2fSJ. Bruce Fields { 2999665d5072SJ. Bruce Fields if (!cstate->session) 300051d87bc2SFengguang Wu return false; 3001665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 30025d4cec2fSJ. Bruce Fields } 30035d4cec2fSJ. Bruce Fields 3004069b6ad4SAndy Adamson __be32 3005eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 3006eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3007069b6ad4SAndy Adamson { 3008ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 3009e10e0cfcSBenny Halevy struct nfsd4_session *ses; 3010abcdff09SJ. Bruce Fields __be32 status; 3011f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 3012d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 3013d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3014e10e0cfcSBenny Halevy 3015abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 3016ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 301757716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 3018abcdff09SJ. Bruce Fields goto out; 3019f0f51f5cSJ. Bruce Fields ref_held_by_me++; 302057716355SJ. Bruce Fields } 3021ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 3022c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3023ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 3024abcdff09SJ. Bruce Fields if (!ses) 3025abcdff09SJ. Bruce Fields goto out_client_lock; 302657266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3027dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 3028d4e19e70STrond Myklebust goto out_put_session; 3029f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 303066b2b9b2SJ. Bruce Fields if (status) 3031f0f51f5cSJ. Bruce Fields goto out_put_session; 3032e10e0cfcSBenny Halevy unhash_session(ses); 3033c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3034e10e0cfcSBenny Halevy 303584f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 303619cf5c02SJ. Bruce Fields 3037c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3038e10e0cfcSBenny Halevy status = nfs_ok; 3039f0f51f5cSJ. Bruce Fields out_put_session: 3040d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3041abcdff09SJ. Bruce Fields out_client_lock: 3042abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3043e10e0cfcSBenny Halevy out: 3044e10e0cfcSBenny Halevy return status; 3045069b6ad4SAndy Adamson } 3046069b6ad4SAndy Adamson 3047a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3048328ead28SJ. Bruce Fields { 3049328ead28SJ. Bruce Fields struct nfsd4_conn *c; 3050328ead28SJ. Bruce Fields 3051328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3052a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 3053328ead28SJ. Bruce Fields return c; 3054328ead28SJ. Bruce Fields } 3055328ead28SJ. Bruce Fields } 3056328ead28SJ. Bruce Fields return NULL; 3057328ead28SJ. Bruce Fields } 3058328ead28SJ. Bruce Fields 305957266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3060328ead28SJ. Bruce Fields { 3061328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3062a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 306357266a6eSJ. Bruce Fields __be32 status = nfs_ok; 306421b75b01SJ. Bruce Fields int ret; 3065328ead28SJ. Bruce Fields 3066328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3067a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 306857266a6eSJ. Bruce Fields if (c) 306957266a6eSJ. Bruce Fields goto out_free; 307057266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 307157266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 307257266a6eSJ. Bruce Fields goto out_free; 3073328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3074328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 307521b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 307621b75b01SJ. Bruce Fields if (ret) 307721b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 307821b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 307957266a6eSJ. Bruce Fields return nfs_ok; 308057266a6eSJ. Bruce Fields out_free: 308157266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 308257266a6eSJ. Bruce Fields free_conn(new); 308357266a6eSJ. Bruce Fields return status; 3084328ead28SJ. Bruce Fields } 3085328ead28SJ. Bruce Fields 3086868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3087868b89c3SMi Jinlong { 3088868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3089868b89c3SMi Jinlong 3090868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3091868b89c3SMi Jinlong } 3092868b89c3SMi Jinlong 3093ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3094ae82a8d0SMi Jinlong struct nfsd4_session *session) 3095ae82a8d0SMi Jinlong { 3096ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3097ae82a8d0SMi Jinlong 3098ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3099ae82a8d0SMi Jinlong } 3100ae82a8d0SMi Jinlong 310153da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 310253da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 310353da6a53SJ. Bruce Fields { 310453da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 310553da6a53SJ. Bruce Fields 310653da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 310753da6a53SJ. Bruce Fields (bool)seq->cachethis) 310853da6a53SJ. Bruce Fields return false; 310953da6a53SJ. Bruce Fields /* 311053da6a53SJ. Bruce Fields * If there's an error than the reply can have fewer ops than 311153da6a53SJ. Bruce Fields * the call. But if we cached a reply with *more* ops than the 311253da6a53SJ. Bruce Fields * call you're sending us now, then this new call is clearly not 311353da6a53SJ. Bruce Fields * really a replay of the old one: 311453da6a53SJ. Bruce Fields */ 311553da6a53SJ. Bruce Fields if (slot->sl_opcnt < argp->opcnt) 311653da6a53SJ. Bruce Fields return false; 311753da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 311853da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 311953da6a53SJ. Bruce Fields return false; 312053da6a53SJ. Bruce Fields /* 312153da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 312253da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 312353da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 312453da6a53SJ. Bruce Fields * the reply), so we don't bother. 312553da6a53SJ. Bruce Fields */ 312653da6a53SJ. Bruce Fields return true; 312753da6a53SJ. Bruce Fields } 312853da6a53SJ. Bruce Fields 3129069b6ad4SAndy Adamson __be32 3130eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3131eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3132069b6ad4SAndy Adamson { 3133eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3134f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 313547ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3136b85d4c01SBenny Halevy struct nfsd4_session *session; 3137221a6876SJ. Bruce Fields struct nfs4_client *clp; 3138b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3139a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 314057b7b43bSJ. Bruce Fields __be32 status; 314147ee5298SJ. Bruce Fields int buflen; 3142d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3143d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3144b85d4c01SBenny Halevy 3145f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3146f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3147f9bb94c4SAndy Adamson 3148a663bdd8SJ. Bruce Fields /* 3149a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3150a663bdd8SJ. Bruce Fields * below. 3151a663bdd8SJ. Bruce Fields */ 3152a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3153a663bdd8SJ. Bruce Fields if (!conn) 3154a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3155a663bdd8SJ. Bruce Fields 3156c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3157d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3158b85d4c01SBenny Halevy if (!session) 3159221a6876SJ. Bruce Fields goto out_no_session; 3160221a6876SJ. Bruce Fields clp = session->se_client; 3161b85d4c01SBenny Halevy 3162868b89c3SMi Jinlong status = nfserr_too_many_ops; 3163868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 316466b2b9b2SJ. Bruce Fields goto out_put_session; 3165868b89c3SMi Jinlong 3166ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3167ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 316866b2b9b2SJ. Bruce Fields goto out_put_session; 3169ae82a8d0SMi Jinlong 3170b85d4c01SBenny Halevy status = nfserr_badslot; 31716c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 317266b2b9b2SJ. Bruce Fields goto out_put_session; 3173b85d4c01SBenny Halevy 3174557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3175b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3176b85d4c01SBenny Halevy 3177a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3178a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3179a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3180a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 3181a8dfdaebSAndy Adamson 318273e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 318373e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 3184b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 3185bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 3186bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 318766b2b9b2SJ. Bruce Fields goto out_put_session; 318853da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 318953da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 319053da6a53SJ. Bruce Fields goto out_put_session; 3191b85d4c01SBenny Halevy cstate->slot = slot; 3192b85d4c01SBenny Halevy cstate->session = session; 31934b24ca7dSJeff Layton cstate->clp = clp; 3194da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 3195557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 3196bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 3197da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 3198aaf84eb9SBenny Halevy goto out; 3199b85d4c01SBenny Halevy } 3200b85d4c01SBenny Halevy if (status) 320166b2b9b2SJ. Bruce Fields goto out_put_session; 3202b85d4c01SBenny Halevy 320357266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 3204a663bdd8SJ. Bruce Fields conn = NULL; 320557266a6eSJ. Bruce Fields if (status) 320657266a6eSJ. Bruce Fields goto out_put_session; 3207328ead28SJ. Bruce Fields 320847ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 320947ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 321047ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 321147ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 321247ee5298SJ. Bruce Fields nfserr_rep_too_big; 3213a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 321447ee5298SJ. Bruce Fields goto out_put_session; 321532aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 321647ee5298SJ. Bruce Fields 321747ee5298SJ. Bruce Fields status = nfs_ok; 3218b85d4c01SBenny Halevy /* Success! bump slot seqid */ 3219b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 3220bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 322173e79482SJ. Bruce Fields if (seq->cachethis) 322273e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 3223bf5c43c8SJ. Bruce Fields else 3224bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 3225b85d4c01SBenny Halevy 3226b85d4c01SBenny Halevy cstate->slot = slot; 3227b85d4c01SBenny Halevy cstate->session = session; 32284b24ca7dSJeff Layton cstate->clp = clp; 3229b85d4c01SBenny Halevy 3230b85d4c01SBenny Halevy out: 32315423732aSBenny Halevy switch (clp->cl_cb_state) { 32325423732aSBenny Halevy case NFSD4_CB_DOWN: 3233fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 32345423732aSBenny Halevy break; 32355423732aSBenny Halevy case NFSD4_CB_FAULT: 3236fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 32375423732aSBenny Halevy break; 3238fc0c3dd1SBenny Halevy default: 3239fc0c3dd1SBenny Halevy seq->status_flags = 0; 32405423732aSBenny Halevy } 32413bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 32423bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 3243221a6876SJ. Bruce Fields out_no_session: 32443f42d2c4SKinglong Mee if (conn) 32453f42d2c4SKinglong Mee free_conn(conn); 3246c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3247b85d4c01SBenny Halevy return status; 324866b2b9b2SJ. Bruce Fields out_put_session: 3249d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 3250221a6876SJ. Bruce Fields goto out_no_session; 3251069b6ad4SAndy Adamson } 3252069b6ad4SAndy Adamson 3253b607664eSTrond Myklebust void 3254b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 3255b607664eSTrond Myklebust { 3256b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 3257b607664eSTrond Myklebust 3258b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 3259b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 3260b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 3261b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3262b607664eSTrond Myklebust } 3263d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 3264b607664eSTrond Myklebust nfsd4_put_session(cs->session); 32654b24ca7dSJeff Layton } else if (cs->clp) 32664b24ca7dSJeff Layton put_client_renew(cs->clp); 3267b607664eSTrond Myklebust } 3268b607664eSTrond Myklebust 3269345c2842SMi Jinlong __be32 3270eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 3271eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3272eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3273345c2842SMi Jinlong { 3274eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 32756b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 32766b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 327757b7b43bSJ. Bruce Fields __be32 status = 0; 32788daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3279345c2842SMi Jinlong 32806b10ad19STrond Myklebust spin_lock(&nn->client_lock); 32810a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 32828daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 328378389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3284345c2842SMi Jinlong 3285345c2842SMi Jinlong if (conf) { 3286c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 3287345c2842SMi Jinlong status = nfserr_clientid_busy; 3288345c2842SMi Jinlong goto out; 3289345c2842SMi Jinlong } 3290fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3291fd699b8aSJeff Layton if (status) 3292fd699b8aSJeff Layton goto out; 32936b10ad19STrond Myklebust clp = conf; 3294345c2842SMi Jinlong } else if (unconf) 3295345c2842SMi Jinlong clp = unconf; 3296345c2842SMi Jinlong else { 3297345c2842SMi Jinlong status = nfserr_stale_clientid; 3298345c2842SMi Jinlong goto out; 3299345c2842SMi Jinlong } 3300dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 33016b10ad19STrond Myklebust clp = NULL; 330257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 330357266a6eSJ. Bruce Fields goto out; 330457266a6eSJ. Bruce Fields } 33056b10ad19STrond Myklebust unhash_client_locked(clp); 3306345c2842SMi Jinlong out: 33076b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 33086b10ad19STrond Myklebust if (clp) 33096b10ad19STrond Myklebust expire_client(clp); 3310345c2842SMi Jinlong return status; 3311345c2842SMi Jinlong } 3312345c2842SMi Jinlong 3313069b6ad4SAndy Adamson __be32 3314eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 3315eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 33164dc6ec00SJ. Bruce Fields { 3317eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 331857b7b43bSJ. Bruce Fields __be32 status = 0; 3319bcecf1ccSMi Jinlong 33204dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 33214dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 33224dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 33234dc6ec00SJ. Bruce Fields /* 33244dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 33254dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 33264dc6ec00SJ. Bruce Fields */ 33274dc6ec00SJ. Bruce Fields return nfs_ok; 33284dc6ec00SJ. Bruce Fields } 3329bcecf1ccSMi Jinlong 3330bcecf1ccSMi Jinlong status = nfserr_complete_already; 3331a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 3332a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 3333bcecf1ccSMi Jinlong goto out; 3334bcecf1ccSMi Jinlong 3335bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 3336bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 33374dc6ec00SJ. Bruce Fields /* 33384dc6ec00SJ. Bruce Fields * The following error isn't really legal. 33394dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 33404dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 33414dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 33424dc6ec00SJ. Bruce Fields * client. 33434dc6ec00SJ. Bruce Fields */ 3344bcecf1ccSMi Jinlong goto out; 3345bcecf1ccSMi Jinlong 3346bcecf1ccSMi Jinlong status = nfs_ok; 33472a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 3348bcecf1ccSMi Jinlong out: 3349bcecf1ccSMi Jinlong return status; 33504dc6ec00SJ. Bruce Fields } 33514dc6ec00SJ. Bruce Fields 33524dc6ec00SJ. Bruce Fields __be32 3353b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3354eb69853dSChristoph Hellwig union nfsd4_op_u *u) 33551da177e4SLinus Torvalds { 3356eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 3357a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 33581da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 33593dbacee6STrond Myklebust struct nfs4_client *conf, *new; 33603dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 3361b37ad28bSAl Viro __be32 status; 3362c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3363a55370a3SNeilBrown 33645cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 33655cc40fd7STrond Myklebust if (new == NULL) 33665cc40fd7STrond Myklebust return nfserr_jukebox; 336763db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 33683dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3369382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 33702b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 337163db4632SJ. Bruce Fields /* case 0: */ 33721da177e4SLinus Torvalds status = nfserr_clid_inuse; 3373e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 3374e203d506SJ. Bruce Fields goto out; 3375026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 3376363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 3377363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 3378363168b4SJeff Layton sizeof(addr_str)); 3379026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 3380363168b4SJeff Layton "at %s\n", addr_str); 33811da177e4SLinus Torvalds goto out; 33821da177e4SLinus Torvalds } 33831da177e4SLinus Torvalds } 3384a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 33851da177e4SLinus Torvalds if (unconf) 33863dbacee6STrond Myklebust unhash_client_locked(unconf); 338741eb1670SKinglong Mee if (conf && same_verf(&conf->cl_verifier, &clverifier)) { 338863db4632SJ. Bruce Fields /* case 1: probable callback update */ 33891da177e4SLinus Torvalds copy_clid(new, conf); 339041eb1670SKinglong Mee gen_confirm(new, nn); 339141eb1670SKinglong Mee } else /* case 4 (new client) or cases 2, 3 (client reboot): */ 3392c212cecfSStanislav Kinsbursky gen_clid(new, nn); 33938323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 33946f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 3395ac55fdc4SJeff Layton add_to_unconfirmed(new); 33961da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 33971da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 33981da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 33995cc40fd7STrond Myklebust new = NULL; 34001da177e4SLinus Torvalds status = nfs_ok; 34011da177e4SLinus Torvalds out: 34023dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 34035cc40fd7STrond Myklebust if (new) 34045cc40fd7STrond Myklebust free_client(new); 34053dbacee6STrond Myklebust if (unconf) 34063dbacee6STrond Myklebust expire_client(unconf); 34071da177e4SLinus Torvalds return status; 34081da177e4SLinus Torvalds } 34091da177e4SLinus Torvalds 34101da177e4SLinus Torvalds 3411b37ad28bSAl Viro __be32 3412b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 3413b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 3414eb69853dSChristoph Hellwig union nfsd4_op_u *u) 34151da177e4SLinus Torvalds { 3416eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 3417eb69853dSChristoph Hellwig &u->setclientid_confirm; 341821ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 3419d20c11d8SJeff Layton struct nfs4_client *old = NULL; 34201da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 34211da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 3422b37ad28bSAl Viro __be32 status; 34237f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 34241da177e4SLinus Torvalds 34252c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 34261da177e4SLinus Torvalds return nfserr_stale_clientid; 342721ab45a4SNeilBrown 3428d20c11d8SJeff Layton spin_lock(&nn->client_lock); 34298daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 34300a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 3431a186e767SJ. Bruce Fields /* 34328695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 34338695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 3434f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 3435f984a7ceSJ. Bruce Fields * 3436f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 3437a186e767SJ. Bruce Fields */ 3438f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 34398695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 34408695b90aSJ. Bruce Fields goto out; 34418695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 34428695b90aSJ. Bruce Fields goto out; 344363db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 344490d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 34457d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 34467d22fc11SJ. Bruce Fields /* case 2: probable retransmit */ 344790d700b7SJ. Bruce Fields status = nfs_ok; 34487d22fc11SJ. Bruce Fields } else /* case 4: client hasn't noticed we rebooted yet? */ 344990d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 345090d700b7SJ. Bruce Fields goto out; 345190d700b7SJ. Bruce Fields } 345290d700b7SJ. Bruce Fields status = nfs_ok; 345390d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 3454d20c11d8SJeff Layton old = unconf; 3455d20c11d8SJeff Layton unhash_client_locked(old); 34565a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 345790d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 3458d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3459d20c11d8SJeff Layton if (old) { 34602b634821SJ. Bruce Fields status = nfserr_clid_inuse; 34612b634821SJ. Bruce Fields if (client_has_state(old) 34622b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 34632b634821SJ. Bruce Fields &old->cl_cred)) 34642b634821SJ. Bruce Fields goto out; 3465d20c11d8SJeff Layton status = mark_client_expired_locked(old); 34667abea1e8SJeff Layton if (status) { 34677abea1e8SJeff Layton old = NULL; 3468221a6876SJ. Bruce Fields goto out; 3469221a6876SJ. Bruce Fields } 34707abea1e8SJeff Layton } 34711da177e4SLinus Torvalds move_to_confirmed(unconf); 3472d20c11d8SJeff Layton conf = unconf; 347308e8987cSNeilBrown } 3474d20c11d8SJeff Layton get_client_locked(conf); 3475d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3476d20c11d8SJeff Layton nfsd4_probe_callback(conf); 3477d20c11d8SJeff Layton spin_lock(&nn->client_lock); 3478d20c11d8SJeff Layton put_client_renew_locked(conf); 34791da177e4SLinus Torvalds out: 3480d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3481d20c11d8SJeff Layton if (old) 3482d20c11d8SJeff Layton expire_client(old); 34831da177e4SLinus Torvalds return status; 34841da177e4SLinus Torvalds } 34851da177e4SLinus Torvalds 348632513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 34871da177e4SLinus Torvalds { 348832513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 348932513b40SJ. Bruce Fields } 349032513b40SJ. Bruce Fields 349132513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 34925b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, 34935b095e99SJeff Layton struct nfs4_file *fp) 349432513b40SJ. Bruce Fields { 3495950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3496950e0118STrond Myklebust 3497818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 34981d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 34998beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 35008beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 35018287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 3502e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 35030c637be8SJeff Layton fp->fi_deleg_file = NULL; 350447f9940cSMeelap Shah fp->fi_had_conflict = false; 3505baeb4ff0SJeff Layton fp->fi_share_deny = 0; 3506f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 3507f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 35089cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 35099cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 3510c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 35119cf514ccSChristoph Hellwig #endif 35125b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 35131da177e4SLinus Torvalds } 35141da177e4SLinus Torvalds 3515e8ff2a84SJ. Bruce Fields void 3516e60d4398SNeilBrown nfsd4_free_slabs(void) 3517e60d4398SNeilBrown { 35189258a2d5SJeff Layton kmem_cache_destroy(client_slab); 3519abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3520abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3521abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3522abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3523abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 35249258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 3525e60d4398SNeilBrown } 35261da177e4SLinus Torvalds 352772083396SBryan Schumaker int 35281da177e4SLinus Torvalds nfsd4_init_slabs(void) 35291da177e4SLinus Torvalds { 35309258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 35319258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 35329258a2d5SJeff Layton if (client_slab == NULL) 35339258a2d5SJeff Layton goto out; 3534fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 3535fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 3536fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 35379258a2d5SJeff Layton goto out_free_client_slab; 3538fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 35393c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 3540fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 3541abf1135bSChristoph Hellwig goto out_free_openowner_slab; 3542e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 354320c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 3544e60d4398SNeilBrown if (file_slab == NULL) 3545abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 35465ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 3547dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 35485ac049acSNeilBrown if (stateid_slab == NULL) 3549abf1135bSChristoph Hellwig goto out_free_file_slab; 35505b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 355120c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 35525b2d21c1SNeilBrown if (deleg_slab == NULL) 3553abf1135bSChristoph Hellwig goto out_free_stateid_slab; 35548287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 35558287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 35568287f009SSachin Bhamare if (odstate_slab == NULL) 35578287f009SSachin Bhamare goto out_free_deleg_slab; 3558e60d4398SNeilBrown return 0; 3559abf1135bSChristoph Hellwig 35608287f009SSachin Bhamare out_free_deleg_slab: 35618287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 3562abf1135bSChristoph Hellwig out_free_stateid_slab: 3563abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3564abf1135bSChristoph Hellwig out_free_file_slab: 3565abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3566abf1135bSChristoph Hellwig out_free_lockowner_slab: 3567abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3568abf1135bSChristoph Hellwig out_free_openowner_slab: 3569abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 35709258a2d5SJeff Layton out_free_client_slab: 35719258a2d5SJeff Layton kmem_cache_destroy(client_slab); 3572abf1135bSChristoph Hellwig out: 35731da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 35741da177e4SLinus Torvalds return -ENOMEM; 35751da177e4SLinus Torvalds } 35761da177e4SLinus Torvalds 3577ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 3578ff194bd9SJ. Bruce Fields { 3579ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 3580ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 3581ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 358258fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 358358fb12e6SJeff Layton } 358458fb12e6SJeff Layton 358558fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 358658fb12e6SJeff Layton struct nfs4_stateowner *so) 358758fb12e6SJeff Layton { 358858fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 358958fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 3590b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 359158fb12e6SJeff Layton } 359258fb12e6SJeff Layton } 359358fb12e6SJeff Layton 359458fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 359558fb12e6SJeff Layton { 359658fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 359758fb12e6SJeff Layton 359858fb12e6SJeff Layton if (so != NULL) { 359958fb12e6SJeff Layton cstate->replay_owner = NULL; 360058fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 360158fb12e6SJeff Layton nfs4_put_stateowner(so); 360258fb12e6SJeff Layton } 3603ff194bd9SJ. Bruce Fields } 3604ff194bd9SJ. Bruce Fields 3605fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 36061da177e4SLinus Torvalds { 36071da177e4SLinus Torvalds struct nfs4_stateowner *sop; 36081da177e4SLinus Torvalds 3609fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 3610ff194bd9SJ. Bruce Fields if (!sop) 3611ff194bd9SJ. Bruce Fields return NULL; 3612ff194bd9SJ. Bruce Fields 3613ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 3614ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 3615fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 3616ff194bd9SJ. Bruce Fields return NULL; 3617ff194bd9SJ. Bruce Fields } 36181da177e4SLinus Torvalds sop->so_owner.len = owner->len; 3619ff194bd9SJ. Bruce Fields 3620ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 3621ff194bd9SJ. Bruce Fields sop->so_client = clp; 3622ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 36236b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 36241da177e4SLinus Torvalds return sop; 36251da177e4SLinus Torvalds } 3626ff194bd9SJ. Bruce Fields 3627fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 3628ff194bd9SJ. Bruce Fields { 3629d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 36309b531137SStanislav Kinsbursky 3631d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 3632d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 3633fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 36341da177e4SLinus Torvalds } 36351da177e4SLinus Torvalds 36368f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 36378f4b54c5SJeff Layton { 3638d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 36398f4b54c5SJeff Layton } 36408f4b54c5SJeff Layton 36416b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 36426b180f0bSJeff Layton { 36436b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 36446b180f0bSJeff Layton 36456b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 36466b180f0bSJeff Layton } 36476b180f0bSJeff Layton 36486b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 36498f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 36506b180f0bSJeff Layton .so_free = nfs4_free_openowner, 36516b180f0bSJeff Layton }; 36526b180f0bSJeff Layton 36537fc0564eSAndrew Elble static struct nfs4_ol_stateid * 36547fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 36557fc0564eSAndrew Elble { 36567fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 36577fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 36587fc0564eSAndrew Elble 36597fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 36607fc0564eSAndrew Elble 36617fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 36627fc0564eSAndrew Elble /* ignore lock owners */ 36637fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 36647fc0564eSAndrew Elble continue; 366515ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 366615ca08d3STrond Myklebust continue; 366715ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 36687fc0564eSAndrew Elble ret = local; 3669a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 36707fc0564eSAndrew Elble break; 36717fc0564eSAndrew Elble } 36727fc0564eSAndrew Elble } 36737fc0564eSAndrew Elble return ret; 36747fc0564eSAndrew Elble } 36757fc0564eSAndrew Elble 367615ca08d3STrond Myklebust static __be32 367715ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 367815ca08d3STrond Myklebust { 367915ca08d3STrond Myklebust __be32 ret = nfs_ok; 368015ca08d3STrond Myklebust 368115ca08d3STrond Myklebust switch (s->sc_type) { 368215ca08d3STrond Myklebust default: 368315ca08d3STrond Myklebust break; 36844f176417STrond Myklebust case 0: 368515ca08d3STrond Myklebust case NFS4_CLOSED_STID: 368615ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 368715ca08d3STrond Myklebust ret = nfserr_bad_stateid; 368815ca08d3STrond Myklebust break; 368915ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 369015ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 369115ca08d3STrond Myklebust } 369215ca08d3STrond Myklebust return ret; 369315ca08d3STrond Myklebust } 369415ca08d3STrond Myklebust 369515ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 369615ca08d3STrond Myklebust static __be32 369715ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 369815ca08d3STrond Myklebust { 369915ca08d3STrond Myklebust __be32 ret; 370015ca08d3STrond Myklebust 37014f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 370215ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 370315ca08d3STrond Myklebust if (ret != nfs_ok) 370415ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 370515ca08d3STrond Myklebust return ret; 370615ca08d3STrond Myklebust } 370715ca08d3STrond Myklebust 370815ca08d3STrond Myklebust static struct nfs4_ol_stateid * 370915ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 371015ca08d3STrond Myklebust { 371115ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 371215ca08d3STrond Myklebust for (;;) { 371315ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 371415ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 371515ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 371615ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 371715ca08d3STrond Myklebust break; 371815ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 371915ca08d3STrond Myklebust } 372015ca08d3STrond Myklebust return stp; 372115ca08d3STrond Myklebust } 372215ca08d3STrond Myklebust 3723fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 372413d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 3725db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 3726db24b3b4SJeff Layton { 372713d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 37287ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 37291da177e4SLinus Torvalds 3730fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 3731fe0750e5SJ. Bruce Fields if (!oo) 37321da177e4SLinus Torvalds return NULL; 37336b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 3734fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 3735fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 3736d3134b10SJeff Layton oo->oo_flags = 0; 3737db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 3738db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 3739fe0750e5SJ. Bruce Fields oo->oo_time = 0; 374038c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 3741fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 3742d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 3743d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 37447ffb5880STrond Myklebust if (ret == NULL) { 3745fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 37467ffb5880STrond Myklebust ret = oo; 37477ffb5880STrond Myklebust } else 3748d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 3749d50ffdedSKinglong Mee 3750d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 3751c5952338SJeff Layton return ret; 37521da177e4SLinus Torvalds } 37531da177e4SLinus Torvalds 37547fc0564eSAndrew Elble static struct nfs4_ol_stateid * 37558c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 37567fc0564eSAndrew Elble { 37571da177e4SLinus Torvalds 37587fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 37597fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 37608c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 37617fc0564eSAndrew Elble 37628c7245abSOleg Drokin stp = open->op_stp; 37635cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 37645cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 37654f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 37665cc1fb2aSOleg Drokin 376715ca08d3STrond Myklebust retry: 37687fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 37697fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 37707fc0564eSAndrew Elble 37717fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 37727fc0564eSAndrew Elble if (retstp) 37737fc0564eSAndrew Elble goto out_unlock; 37748c7245abSOleg Drokin 37758c7245abSOleg Drokin open->op_stp = NULL; 3776a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 37773abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 37783c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 3779b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 378013cd2184SNeilBrown get_nfs4_file(fp); 378111b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 37821da177e4SLinus Torvalds stp->st_access_bmap = 0; 37831da177e4SLinus Torvalds stp->st_deny_bmap = 0; 37844c4cd222SNeilBrown stp->st_openstp = NULL; 37851c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 37861d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 37877fc0564eSAndrew Elble 37887fc0564eSAndrew Elble out_unlock: 37891d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 37901c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 37915cc1fb2aSOleg Drokin if (retstp) { 379215ca08d3STrond Myklebust /* Handle races with CLOSE */ 379315ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 379415ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 379515ca08d3STrond Myklebust goto retry; 379615ca08d3STrond Myklebust } 37978c7245abSOleg Drokin /* To keep mutex tracking happy */ 37985cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 37998c7245abSOleg Drokin stp = retstp; 38005cc1fb2aSOleg Drokin } 38018c7245abSOleg Drokin return stp; 38021da177e4SLinus Torvalds } 38031da177e4SLinus Torvalds 3804d3134b10SJeff Layton /* 3805d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 3806d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 3807d3134b10SJeff Layton * them before returning however. 3808d3134b10SJeff Layton */ 38091da177e4SLinus Torvalds static void 3810d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 38111da177e4SLinus Torvalds { 3812217526e7SJeff Layton struct nfs4_ol_stateid *last; 3813d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 3814d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 3815d3134b10SJeff Layton nfsd_net_id); 381673758fedSStanislav Kinsbursky 3817fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 38181da177e4SLinus Torvalds 3819b401be22SJeff Layton /* 3820b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 3821b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 3822b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 3823b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 3824b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 3825b401be22SJeff Layton * there should be no danger of the refcount going back up again at 3826b401be22SJeff Layton * this point. 3827b401be22SJeff Layton */ 3828a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 3829b401be22SJeff Layton 3830d3134b10SJeff Layton release_all_access(s); 3831d3134b10SJeff Layton if (s->st_stid.sc_file) { 3832d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 3833d3134b10SJeff Layton s->st_stid.sc_file = NULL; 3834d3134b10SJeff Layton } 3835217526e7SJeff Layton 3836217526e7SJeff Layton spin_lock(&nn->client_lock); 3837217526e7SJeff Layton last = oo->oo_last_closed_stid; 3838d3134b10SJeff Layton oo->oo_last_closed_stid = s; 383973758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 3840fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 3841217526e7SJeff Layton spin_unlock(&nn->client_lock); 3842217526e7SJeff Layton if (last) 3843217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 38441da177e4SLinus Torvalds } 38451da177e4SLinus Torvalds 38461da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 38471da177e4SLinus Torvalds static struct nfs4_file * 38485b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval) 38491da177e4SLinus Torvalds { 38501da177e4SLinus Torvalds struct nfs4_file *fp; 38511da177e4SLinus Torvalds 38525b095e99SJeff Layton hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { 38534d94c2efSChristoph Hellwig if (fh_match(&fp->fi_fhandle, fh)) { 3854818a34ebSElena Reshetova if (refcount_inc_not_zero(&fp->fi_ref)) 38551da177e4SLinus Torvalds return fp; 38561da177e4SLinus Torvalds } 385713cd2184SNeilBrown } 38581da177e4SLinus Torvalds return NULL; 38591da177e4SLinus Torvalds } 38601da177e4SLinus Torvalds 3861e6ba76e1SChristoph Hellwig struct nfs4_file * 3862ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 3863950e0118STrond Myklebust { 3864950e0118STrond Myklebust struct nfs4_file *fp; 38655b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 3866950e0118STrond Myklebust 38675b095e99SJeff Layton rcu_read_lock(); 38685b095e99SJeff Layton fp = find_file_locked(fh, hashval); 38695b095e99SJeff Layton rcu_read_unlock(); 3870950e0118STrond Myklebust return fp; 3871950e0118STrond Myklebust } 3872950e0118STrond Myklebust 3873950e0118STrond Myklebust static struct nfs4_file * 3874f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 3875950e0118STrond Myklebust { 3876950e0118STrond Myklebust struct nfs4_file *fp; 38775b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 38785b095e99SJeff Layton 38795b095e99SJeff Layton rcu_read_lock(); 38805b095e99SJeff Layton fp = find_file_locked(fh, hashval); 38815b095e99SJeff Layton rcu_read_unlock(); 38825b095e99SJeff Layton if (fp) 38835b095e99SJeff Layton return fp; 3884950e0118STrond Myklebust 3885950e0118STrond Myklebust spin_lock(&state_lock); 38865b095e99SJeff Layton fp = find_file_locked(fh, hashval); 38875b095e99SJeff Layton if (likely(fp == NULL)) { 38885b095e99SJeff Layton nfsd4_init_file(fh, hashval, new); 3889950e0118STrond Myklebust fp = new; 3890950e0118STrond Myklebust } 3891950e0118STrond Myklebust spin_unlock(&state_lock); 3892950e0118STrond Myklebust 3893950e0118STrond Myklebust return fp; 3894950e0118STrond Myklebust } 3895950e0118STrond Myklebust 38964f83aa30SJ. Bruce Fields /* 38971da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 38981da177e4SLinus Torvalds * WRITE with all zero or all one stateid 38991da177e4SLinus Torvalds */ 3900b37ad28bSAl Viro static __be32 39011da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 39021da177e4SLinus Torvalds { 39031da177e4SLinus Torvalds struct nfs4_file *fp; 3904baeb4ff0SJeff Layton __be32 ret = nfs_ok; 39051da177e4SLinus Torvalds 3906ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 390713cd2184SNeilBrown if (!fp) 3908baeb4ff0SJeff Layton return ret; 3909baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 39101d31a253STrond Myklebust spin_lock(&fp->fi_lock); 3911baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 3912baeb4ff0SJeff Layton ret = nfserr_locked; 39131d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 391413cd2184SNeilBrown put_nfs4_file(fp); 391513cd2184SNeilBrown return ret; 39161da177e4SLinus Torvalds } 39171da177e4SLinus Torvalds 39180162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 39191da177e4SLinus Torvalds { 39200162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 392111b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 392211b9164aSTrond Myklebust nfsd_net_id); 3923e8c69d17SJ. Bruce Fields 392411b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 3925f54fe962SJeff Layton 392602e1215fSJeff Layton /* 392702e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 3928f54fe962SJeff Layton * already holding inode->i_lock. 3929f54fe962SJeff Layton * 3930dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 3931dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 3932dff1399fSJeff Layton */ 3933f54fe962SJeff Layton spin_lock(&state_lock); 3934dff1399fSJeff Layton if (dp->dl_time == 0) { 39351da177e4SLinus Torvalds dp->dl_time = get_seconds(); 393602e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 393702e1215fSJeff Layton } 393802e1215fSJeff Layton spin_unlock(&state_lock); 3939dff1399fSJeff Layton } 39401da177e4SLinus Torvalds 39410162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 39420162ac2bSChristoph Hellwig struct rpc_task *task) 39430162ac2bSChristoph Hellwig { 39440162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 39450162ac2bSChristoph Hellwig 3946a457974fSAndrew Elble if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID) 3947a457974fSAndrew Elble return 1; 3948a457974fSAndrew Elble 39490162ac2bSChristoph Hellwig switch (task->tk_status) { 39500162ac2bSChristoph Hellwig case 0: 39510162ac2bSChristoph Hellwig return 1; 39520162ac2bSChristoph Hellwig case -EBADHANDLE: 39530162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 39540162ac2bSChristoph Hellwig /* 39550162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 39560162ac2bSChristoph Hellwig * granting delegation. 39570162ac2bSChristoph Hellwig */ 39580162ac2bSChristoph Hellwig if (dp->dl_retries--) { 39590162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 39600162ac2bSChristoph Hellwig return 0; 39610162ac2bSChristoph Hellwig } 39620162ac2bSChristoph Hellwig /*FALLTHRU*/ 39630162ac2bSChristoph Hellwig default: 39640162ac2bSChristoph Hellwig return -1; 39650162ac2bSChristoph Hellwig } 39660162ac2bSChristoph Hellwig } 39670162ac2bSChristoph Hellwig 39680162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 39690162ac2bSChristoph Hellwig { 39700162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 39710162ac2bSChristoph Hellwig 39720162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 39730162ac2bSChristoph Hellwig } 39740162ac2bSChristoph Hellwig 3975c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 39760162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 39770162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 39780162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 39790162ac2bSChristoph Hellwig }; 39800162ac2bSChristoph Hellwig 398102e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 398202e1215fSJeff Layton { 398302e1215fSJeff Layton /* 398402e1215fSJeff Layton * We're assuming the state code never drops its reference 398502e1215fSJeff Layton * without first removing the lease. Since we're in this lease 39864a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 39874a269efbSJ. Bruce Fields * i_lock) we know the server hasn't removed the lease yet, and 39884a269efbSJ. Bruce Fields * we know it's safe to take a reference. 398902e1215fSJeff Layton */ 3990a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 3991f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 39926b57d9c8SJ. Bruce Fields } 39936b57d9c8SJ. Bruce Fields 39941c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 39954d01b7f5SJeff Layton static bool 39964d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 39976b57d9c8SJ. Bruce Fields { 39984d01b7f5SJeff Layton bool ret = false; 3999653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 4000653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 40016b57d9c8SJ. Bruce Fields 40020272e1fdSJ. Bruce Fields /* 40030272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 4004acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 40056b57d9c8SJ. Bruce Fields * in time: 40060272e1fdSJ. Bruce Fields */ 40070272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 40081da177e4SLinus Torvalds 400902e1215fSJeff Layton spin_lock(&fp->fi_lock); 4010417c6629SJeff Layton fp->fi_had_conflict = true; 40115d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 401202e1215fSJeff Layton spin_unlock(&fp->fi_lock); 40134d01b7f5SJeff Layton return ret; 40141da177e4SLinus Torvalds } 40151da177e4SLinus Torvalds 4016c45198edSJeff Layton static int 40177448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 40187448cc37SJeff Layton struct list_head *dispose) 40191da177e4SLinus Torvalds { 40201da177e4SLinus Torvalds if (arg & F_UNLCK) 4021c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 40221da177e4SLinus Torvalds else 40231da177e4SLinus Torvalds return -EAGAIN; 40241da177e4SLinus Torvalds } 40251da177e4SLinus Torvalds 40267b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 40278fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 40288fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 40291da177e4SLinus Torvalds }; 40301da177e4SLinus Torvalds 40317a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 40327a8711c9SJ. Bruce Fields { 40337a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 40347a8711c9SJ. Bruce Fields return nfs_ok; 40357a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 40367a8711c9SJ. Bruce Fields return nfserr_replay_me; 40377a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 40387a8711c9SJ. Bruce Fields return nfs_ok; 40397a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 40407a8711c9SJ. Bruce Fields } 40411da177e4SLinus Torvalds 40424b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 40434b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 40444b24ca7dSJeff Layton struct nfsd_net *nn) 40454b24ca7dSJeff Layton { 40464b24ca7dSJeff Layton struct nfs4_client *found; 40474b24ca7dSJeff Layton 40484b24ca7dSJeff Layton if (cstate->clp) { 40494b24ca7dSJeff Layton found = cstate->clp; 40504b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 40514b24ca7dSJeff Layton return nfserr_stale_clientid; 40524b24ca7dSJeff Layton return nfs_ok; 40534b24ca7dSJeff Layton } 40544b24ca7dSJeff Layton 40554b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 40564b24ca7dSJeff Layton return nfserr_stale_clientid; 40574b24ca7dSJeff Layton 40584b24ca7dSJeff Layton /* 40594b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 40604b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 40614b24ca7dSJeff Layton * will be false. 40624b24ca7dSJeff Layton */ 40634b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 40643e339f96STrond Myklebust spin_lock(&nn->client_lock); 40654b24ca7dSJeff Layton found = find_confirmed_client(clid, false, nn); 40663e339f96STrond Myklebust if (!found) { 40673e339f96STrond Myklebust spin_unlock(&nn->client_lock); 40684b24ca7dSJeff Layton return nfserr_expired; 40693e339f96STrond Myklebust } 40703e339f96STrond Myklebust atomic_inc(&found->cl_refcount); 40713e339f96STrond Myklebust spin_unlock(&nn->client_lock); 40724b24ca7dSJeff Layton 40734b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 40744b24ca7dSJeff Layton cstate->clp = found; 40754b24ca7dSJeff Layton return nfs_ok; 40764b24ca7dSJeff Layton } 40774b24ca7dSJeff Layton 4078b37ad28bSAl Viro __be32 40796668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 40803320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 40811da177e4SLinus Torvalds { 40821da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 40831da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 40841da177e4SLinus Torvalds unsigned int strhashval; 4085fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 40864cdc951bSJ. Bruce Fields __be32 status; 40871da177e4SLinus Torvalds 40882c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 40891da177e4SLinus Torvalds return nfserr_stale_clientid; 409032513b40SJ. Bruce Fields /* 409132513b40SJ. Bruce Fields * In case we need it later, after we've already created the 409232513b40SJ. Bruce Fields * file and don't want to risk a further failure: 409332513b40SJ. Bruce Fields */ 409432513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 409532513b40SJ. Bruce Fields if (open->op_file == NULL) 409632513b40SJ. Bruce Fields return nfserr_jukebox; 40971da177e4SLinus Torvalds 409813d6f66bSTrond Myklebust status = lookup_clientid(clientid, cstate, nn); 409913d6f66bSTrond Myklebust if (status) 410013d6f66bSTrond Myklebust return status; 410113d6f66bSTrond Myklebust clp = cstate->clp; 41022d91e895STrond Myklebust 4103d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 4104d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 41052d91e895STrond Myklebust open->op_openowner = oo; 41062d91e895STrond Myklebust if (!oo) { 4107bcf130f9SJ. Bruce Fields goto new_owner; 41080f442aa2SJ. Bruce Fields } 4109dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 41100f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 4111fe0750e5SJ. Bruce Fields release_openowner(oo); 4112fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 4113bcf130f9SJ. Bruce Fields goto new_owner; 41140f442aa2SJ. Bruce Fields } 41154cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 41164cdc951bSJ. Bruce Fields if (status) 41174cdc951bSJ. Bruce Fields return status; 41184cdc951bSJ. Bruce Fields goto alloc_stateid; 4119bcf130f9SJ. Bruce Fields new_owner: 412013d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 4121fe0750e5SJ. Bruce Fields if (oo == NULL) 41223e772463SJ. Bruce Fields return nfserr_jukebox; 4123fe0750e5SJ. Bruce Fields open->op_openowner = oo; 41244cdc951bSJ. Bruce Fields alloc_stateid: 4125b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 41264cdc951bSJ. Bruce Fields if (!open->op_stp) 41274cdc951bSJ. Bruce Fields return nfserr_jukebox; 41288287f009SSachin Bhamare 41298287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 41308287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 41318287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 41328287f009SSachin Bhamare if (!open->op_odstate) 41338287f009SSachin Bhamare return nfserr_jukebox; 41348287f009SSachin Bhamare } 41358287f009SSachin Bhamare 41360f442aa2SJ. Bruce Fields return nfs_ok; 41371da177e4SLinus Torvalds } 41381da177e4SLinus Torvalds 4139b37ad28bSAl Viro static inline __be32 41404a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 41414a6e43e6SNeilBrown { 41424a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 41434a6e43e6SNeilBrown return nfserr_openmode; 41444a6e43e6SNeilBrown else 41454a6e43e6SNeilBrown return nfs_ok; 41464a6e43e6SNeilBrown } 41474a6e43e6SNeilBrown 4148c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 414924a0111eSJ. Bruce Fields { 415024a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 415124a0111eSJ. Bruce Fields } 415224a0111eSJ. Bruce Fields 415338c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 4154f459e453SJ. Bruce Fields { 4155f459e453SJ. Bruce Fields struct nfs4_stid *ret; 4156f459e453SJ. Bruce Fields 415795da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 415895da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 4159f459e453SJ. Bruce Fields if (!ret) 4160f459e453SJ. Bruce Fields return NULL; 4161f459e453SJ. Bruce Fields return delegstateid(ret); 4162f459e453SJ. Bruce Fields } 4163f459e453SJ. Bruce Fields 41648b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 41658b289b2cSJ. Bruce Fields { 41668b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 41678b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 41688b289b2cSJ. Bruce Fields } 41698b289b2cSJ. Bruce Fields 4170b37ad28bSAl Viro static __be32 417141d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 4172567d9829SNeilBrown struct nfs4_delegation **dp) 4173567d9829SNeilBrown { 4174567d9829SNeilBrown int flags; 4175b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 4176dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 4177567d9829SNeilBrown 4178dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 4179dcd94cc2STrond Myklebust if (deleg == NULL) 4180c44c5eebSNeilBrown goto out; 418195da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 418295da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 418395da1b3aSAndrew Elble if (cl->cl_minorversion) 418495da1b3aSAndrew Elble status = nfserr_deleg_revoked; 418595da1b3aSAndrew Elble goto out; 418695da1b3aSAndrew Elble } 418724a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 4188dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 4189dcd94cc2STrond Myklebust if (status) { 4190dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 4191dcd94cc2STrond Myklebust goto out; 4192dcd94cc2STrond Myklebust } 4193dcd94cc2STrond Myklebust *dp = deleg; 4194c44c5eebSNeilBrown out: 41958b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 4196c44c5eebSNeilBrown return nfs_ok; 4197c44c5eebSNeilBrown if (status) 4198c44c5eebSNeilBrown return status; 4199dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 4200c44c5eebSNeilBrown return nfs_ok; 4201567d9829SNeilBrown } 4202567d9829SNeilBrown 420321fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 420421fb4016SJ. Bruce Fields { 420521fb4016SJ. Bruce Fields int flags = 0; 420621fb4016SJ. Bruce Fields 420721fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 420821fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 420921fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 421021fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 421121fb4016SJ. Bruce Fields return flags; 421221fb4016SJ. Bruce Fields } 421321fb4016SJ. Bruce Fields 4214b37ad28bSAl Viro static inline __be32 42151da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 42161da177e4SLinus Torvalds struct nfsd4_open *open) 42171da177e4SLinus Torvalds { 42181da177e4SLinus Torvalds struct iattr iattr = { 42191da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 42201da177e4SLinus Torvalds .ia_size = 0, 42211da177e4SLinus Torvalds }; 42221da177e4SLinus Torvalds if (!open->op_truncate) 42231da177e4SLinus Torvalds return 0; 42241da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 42259246585aSAl Viro return nfserr_inval; 42261da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 42271da177e4SLinus Torvalds } 42281da177e4SLinus Torvalds 42297e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 42306eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 42316eb3a1d0SJeff Layton struct nfsd4_open *open) 42327e6a72e5SChristoph Hellwig { 4233de18643dSTrond Myklebust struct file *filp = NULL; 42347e6a72e5SChristoph Hellwig __be32 status; 42357e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 42367e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 4237baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 42387e6a72e5SChristoph Hellwig 4239de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4240baeb4ff0SJeff Layton 4241baeb4ff0SJeff Layton /* 4242baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 4243baeb4ff0SJeff Layton * current access? 4244baeb4ff0SJeff Layton */ 4245baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4246baeb4ff0SJeff Layton if (status != nfs_ok) { 4247baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4248baeb4ff0SJeff Layton goto out; 4249baeb4ff0SJeff Layton } 4250baeb4ff0SJeff Layton 4251baeb4ff0SJeff Layton /* set access to the file */ 4252baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 4253baeb4ff0SJeff Layton if (status != nfs_ok) { 4254baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4255baeb4ff0SJeff Layton goto out; 4256baeb4ff0SJeff Layton } 4257baeb4ff0SJeff Layton 4258baeb4ff0SJeff Layton /* Set access bits in stateid */ 4259baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 4260baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 4261baeb4ff0SJeff Layton 4262baeb4ff0SJeff Layton /* Set new deny mask */ 4263baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 4264baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4265baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 4266baeb4ff0SJeff Layton 42677e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 4268de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4269de18643dSTrond Myklebust status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); 42707e6a72e5SChristoph Hellwig if (status) 4271baeb4ff0SJeff Layton goto out_put_access; 4272de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4273de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 4274de18643dSTrond Myklebust fp->fi_fds[oflag] = filp; 4275de18643dSTrond Myklebust filp = NULL; 4276de18643dSTrond Myklebust } 42777e6a72e5SChristoph Hellwig } 4278de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4279de18643dSTrond Myklebust if (filp) 4280de18643dSTrond Myklebust fput(filp); 42817e6a72e5SChristoph Hellwig 42827e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 42837e6a72e5SChristoph Hellwig if (status) 42847e6a72e5SChristoph Hellwig goto out_put_access; 42857e6a72e5SChristoph Hellwig out: 42867e6a72e5SChristoph Hellwig return status; 4287baeb4ff0SJeff Layton out_put_access: 4288baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 4289baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 4290baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 4291baeb4ff0SJeff Layton goto out; 42927e6a72e5SChristoph Hellwig } 42937e6a72e5SChristoph Hellwig 4294b37ad28bSAl Viro static __be32 4295dcef0413SJ. Bruce Fields nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open) 42961da177e4SLinus Torvalds { 4297b37ad28bSAl Viro __be32 status; 42986ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 42991da177e4SLinus Torvalds 43006eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 4301baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 43027e6a72e5SChristoph Hellwig 4303baeb4ff0SJeff Layton /* test and set deny mode */ 4304baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 4305baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4306baeb4ff0SJeff Layton if (status == nfs_ok) { 4307baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4308baeb4ff0SJeff Layton fp->fi_share_deny |= 4309baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 43101da177e4SLinus Torvalds } 4311baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 43121da177e4SLinus Torvalds 4313baeb4ff0SJeff Layton if (status != nfs_ok) 4314baeb4ff0SJeff Layton return status; 4315baeb4ff0SJeff Layton 4316baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 4317baeb4ff0SJeff Layton if (status != nfs_ok) 4318baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 4319baeb4ff0SJeff Layton return status; 4320baeb4ff0SJeff Layton } 43211da177e4SLinus Torvalds 432214a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 432314a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 432414a24e99SJ. Bruce Fields { 432514a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 432614a24e99SJ. Bruce Fields return true; 432714a24e99SJ. Bruce Fields /* 432814a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 432914a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 433014a24e99SJ. Bruce Fields * until we hear otherwise: 433114a24e99SJ. Bruce Fields */ 433214a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 433314a24e99SJ. Bruce Fields } 433414a24e99SJ. Bruce Fields 4335653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 4336653e514eSJ. Bruce Fields int flag) 433722d38c4cSJ. Bruce Fields { 433822d38c4cSJ. Bruce Fields struct file_lock *fl; 433922d38c4cSJ. Bruce Fields 434022d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 434122d38c4cSJ. Bruce Fields if (!fl) 434222d38c4cSJ. Bruce Fields return NULL; 434322d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 4344617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 434522d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 434622d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 4347653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 434822d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 4349353601e7SJ. Bruce Fields fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file; 435022d38c4cSJ. Bruce Fields return fl; 435122d38c4cSJ. Bruce Fields } 435222d38c4cSJ. Bruce Fields 43530b26693cSJeff Layton static struct nfs4_delegation * 43540b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 43558287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 4356acfdf5c3SJ. Bruce Fields { 435768b18f52SJ. Bruce Fields int status = 0; 43580b26693cSJeff Layton struct nfs4_delegation *dp; 4359353601e7SJ. Bruce Fields struct file *filp; 4360353601e7SJ. Bruce Fields struct file_lock *fl; 4361417c6629SJeff Layton 4362353601e7SJ. Bruce Fields /* 4363353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 4364353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 4365353601e7SJ. Bruce Fields * the end: 4366353601e7SJ. Bruce Fields */ 4367bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 43680b26693cSJeff Layton return ERR_PTR(-EAGAIN); 43690b26693cSJeff Layton 4370353601e7SJ. Bruce Fields filp = find_readable_file(fp); 4371353601e7SJ. Bruce Fields if (!filp) { 4372353601e7SJ. Bruce Fields /* We should always have a readable file here */ 4373353601e7SJ. Bruce Fields WARN_ON_ONCE(1); 4374353601e7SJ. Bruce Fields return ERR_PTR(-EBADF); 4375353601e7SJ. Bruce Fields } 437634ed9872SAndrew Elble spin_lock(&state_lock); 437734ed9872SAndrew Elble spin_lock(&fp->fi_lock); 437868b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 437968b18f52SJ. Bruce Fields status = -EAGAIN; 4380353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 4381353601e7SJ. Bruce Fields fp->fi_deleg_file = filp; 4382353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 4383353601e7SJ. Bruce Fields * cleared */ 4384353601e7SJ. Bruce Fields fp->fi_delegees = 1; 4385353601e7SJ. Bruce Fields filp = NULL; 4386353601e7SJ. Bruce Fields } else 4387353601e7SJ. Bruce Fields fp->fi_delegees++; 4388353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 4389353601e7SJ. Bruce Fields spin_unlock(&state_lock); 4390353601e7SJ. Bruce Fields if (filp) 4391353601e7SJ. Bruce Fields fput(filp); 4392353601e7SJ. Bruce Fields if (status) 4393353601e7SJ. Bruce Fields return ERR_PTR(status); 4394353601e7SJ. Bruce Fields 4395353601e7SJ. Bruce Fields status = -ENOMEM; 4396353601e7SJ. Bruce Fields dp = alloc_init_deleg(clp, fp, fh, odstate); 4397353601e7SJ. Bruce Fields if (!dp) 4398353601e7SJ. Bruce Fields goto out_delegees; 4399353601e7SJ. Bruce Fields 4400353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 4401353601e7SJ. Bruce Fields if (!fl) 4402bd8d7250SAndrew Elble goto out_clnt_odstate; 4403353601e7SJ. Bruce Fields 4404353601e7SJ. Bruce Fields status = vfs_setlease(fp->fi_deleg_file, fl->fl_type, &fl, NULL); 4405353601e7SJ. Bruce Fields if (fl) 4406353601e7SJ. Bruce Fields locks_free_lock(fl); 4407353601e7SJ. Bruce Fields if (status) 4408353601e7SJ. Bruce Fields goto out_clnt_odstate; 4409353601e7SJ. Bruce Fields 4410353601e7SJ. Bruce Fields spin_lock(&state_lock); 4411353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 4412353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 4413353601e7SJ. Bruce Fields status = -EAGAIN; 4414353601e7SJ. Bruce Fields else 4415353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 441634ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 441734ed9872SAndrew Elble spin_unlock(&state_lock); 441834ed9872SAndrew Elble 441934ed9872SAndrew Elble if (status) 4420692ad280SAndrew Elble goto out_unlock; 4421692ad280SAndrew Elble 44220b26693cSJeff Layton return dp; 4423692ad280SAndrew Elble out_unlock: 4424692ad280SAndrew Elble vfs_setlease(fp->fi_deleg_file, F_UNLCK, NULL, (void **)&dp); 4425353601e7SJ. Bruce Fields out_clnt_odstate: 4426353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 4427353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 4428353601e7SJ. Bruce Fields out_delegees: 4429353601e7SJ. Bruce Fields put_deleg_file(fp); 4430353601e7SJ. Bruce Fields return ERR_PTR(status); 4431edab9782SJ. Bruce Fields } 4432edab9782SJ. Bruce Fields 44334aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 44344aa8913cSBenny Halevy { 44354aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 44364aa8913cSBenny Halevy if (status == -EAGAIN) 44374aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 44384aa8913cSBenny Halevy else { 44394aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 44404aa8913cSBenny Halevy switch (open->op_deleg_want) { 44414aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 44424aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 44434aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 44444aa8913cSBenny Halevy break; 44454aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 44464aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 44474aa8913cSBenny Halevy break; 44484aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 4449063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 44504aa8913cSBenny Halevy } 44514aa8913cSBenny Halevy } 44524aa8913cSBenny Halevy } 44534aa8913cSBenny Halevy 44541da177e4SLinus Torvalds /* 44551da177e4SLinus Torvalds * Attempt to hand out a delegation. 445699c41515SJ. Bruce Fields * 445799c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 445899c41515SJ. Bruce Fields * proper support for them. 44591da177e4SLinus Torvalds */ 44601da177e4SLinus Torvalds static void 44614cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 44624cf59221SJeff Layton struct nfs4_ol_stateid *stp) 44631da177e4SLinus Torvalds { 44641da177e4SLinus Torvalds struct nfs4_delegation *dp; 44654cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 44664cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 446714a24e99SJ. Bruce Fields int cb_up; 446899c41515SJ. Bruce Fields int status = 0; 44691da177e4SLinus Torvalds 4470fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 44717b190fecSNeilBrown open->op_recall = 0; 44727b190fecSNeilBrown switch (open->op_claim_type) { 44737b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 44742bf23875SJ. Bruce Fields if (!cb_up) 44757b190fecSNeilBrown open->op_recall = 1; 447699c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 447799c41515SJ. Bruce Fields goto out_no_deleg; 44787b190fecSNeilBrown break; 44797b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 4480ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 448199c41515SJ. Bruce Fields /* 448299c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 4483c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 4484c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 448599c41515SJ. Bruce Fields */ 44864cf59221SJeff Layton if (locks_in_grace(clp->net)) 448799c41515SJ. Bruce Fields goto out_no_deleg; 4488dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 448999c41515SJ. Bruce Fields goto out_no_deleg; 44909a0590aeSSteve Dickson /* 44919a0590aeSSteve Dickson * Also, if the file was opened for write or 44929a0590aeSSteve Dickson * create, there's a good chance the client's 44939a0590aeSSteve Dickson * about to write to it, resulting in an 44949a0590aeSSteve Dickson * immediate recall (since we don't support 44959a0590aeSSteve Dickson * write delegations): 44969a0590aeSSteve Dickson */ 44971da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 449899c41515SJ. Bruce Fields goto out_no_deleg; 449999c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 450099c41515SJ. Bruce Fields goto out_no_deleg; 45017b190fecSNeilBrown break; 45027b190fecSNeilBrown default: 450399c41515SJ. Bruce Fields goto out_no_deleg; 45047b190fecSNeilBrown } 45058287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 45060b26693cSJeff Layton if (IS_ERR(dp)) 4507dd239cc0SJ. Bruce Fields goto out_no_deleg; 45081da177e4SLinus Torvalds 4509d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 45101da177e4SLinus Torvalds 45118c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 4512d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 451399c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 451467cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4515dd239cc0SJ. Bruce Fields return; 4516dd239cc0SJ. Bruce Fields out_no_deleg: 451799c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 45187b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 4519d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 45201da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 4521d08d32e6SJ. Bruce Fields open->op_recall = 1; 4522d08d32e6SJ. Bruce Fields } 4523dd239cc0SJ. Bruce Fields 4524dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 4525dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 4526dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 4527dd239cc0SJ. Bruce Fields return; 45281da177e4SLinus Torvalds } 45291da177e4SLinus Torvalds 4530e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 4531e27f49c3SBenny Halevy struct nfs4_delegation *dp) 4532e27f49c3SBenny Halevy { 4533e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 4534e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4535e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4536e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 4537e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 4538e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4539e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4540e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 4541e27f49c3SBenny Halevy } 4542e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 4543e27f49c3SBenny Halevy * it already has, therefore we don't return 4544e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 4545e27f49c3SBenny Halevy */ 4546e27f49c3SBenny Halevy } 4547e27f49c3SBenny Halevy 4548b37ad28bSAl Viro __be32 45491da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 45501da177e4SLinus Torvalds { 45516668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 455238c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 45531da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 4554dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 4555567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 4556b37ad28bSAl Viro __be32 status; 4557d8a1a000STrond Myklebust bool new_stp = false; 45581da177e4SLinus Torvalds 45591da177e4SLinus Torvalds /* 45601da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 45611da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 45621da177e4SLinus Torvalds * If not found, create the nfs4_file struct 45631da177e4SLinus Torvalds */ 4564f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 4565950e0118STrond Myklebust if (fp != open->op_file) { 456641d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 4567c44c5eebSNeilBrown if (status) 4568c44c5eebSNeilBrown goto out; 456915ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 45701da177e4SLinus Torvalds } else { 4571950e0118STrond Myklebust open->op_file = NULL; 4572c44c5eebSNeilBrown status = nfserr_bad_stateid; 45738b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 4574c44c5eebSNeilBrown goto out; 45751da177e4SLinus Torvalds } 45761da177e4SLinus Torvalds 4577d8a1a000STrond Myklebust if (!stp) { 4578d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 4579d8a1a000STrond Myklebust if (!open->op_stp) 4580d8a1a000STrond Myklebust new_stp = true; 4581d8a1a000STrond Myklebust } 4582d8a1a000STrond Myklebust 45831da177e4SLinus Torvalds /* 45841da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 45851da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 4586d8a1a000STrond Myklebust * 4587d8a1a000STrond Myklebust * stp is already locked. 45881da177e4SLinus Torvalds */ 4589d8a1a000STrond Myklebust if (!new_stp) { 45901da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 4591f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 459235a92fe8SJeff Layton if (status) { 4593feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 45941da177e4SLinus Torvalds goto out; 459535a92fe8SJeff Layton } 45961da177e4SLinus Torvalds } else { 45976eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 45986eb3a1d0SJeff Layton if (status) { 4599d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 46006eb3a1d0SJeff Layton release_open_stateid(stp); 4601d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 46026eb3a1d0SJeff Layton goto out; 46036eb3a1d0SJeff Layton } 46048287f009SSachin Bhamare 46058287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 46068287f009SSachin Bhamare open->op_odstate); 46078287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 46088287f009SSachin Bhamare open->op_odstate = NULL; 46091da177e4SLinus Torvalds } 4610d8a1a000STrond Myklebust 46119767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 4612feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 46131da177e4SLinus Torvalds 4614d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 4615d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 4616d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4617d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 4618d24433cdSBenny Halevy goto nodeleg; 4619d24433cdSBenny Halevy } 4620d24433cdSBenny Halevy } 4621d24433cdSBenny Halevy 46221da177e4SLinus Torvalds /* 46231da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 46241da177e4SLinus Torvalds * OPEN succeeds even if we fail. 46251da177e4SLinus Torvalds */ 46264cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 4627d24433cdSBenny Halevy nodeleg: 46281da177e4SLinus Torvalds status = nfs_ok; 46291da177e4SLinus Torvalds 46308c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 4631dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 46321da177e4SLinus Torvalds out: 4633d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 4634d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 4635e27f49c3SBenny Halevy open->op_deleg_want) 4636e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 4637d24433cdSBenny Halevy 463813cd2184SNeilBrown if (fp) 463913cd2184SNeilBrown put_nfs4_file(fp); 464037515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 464187186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 46421da177e4SLinus Torvalds /* 46431da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 46441da177e4SLinus Torvalds */ 46451da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 464619e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 464719e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 464819e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 46491da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 465019e4c347SJeff Layton 4651dcd94cc2STrond Myklebust if (dp) 4652dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4653d6f2bc5dSTrond Myklebust if (stp) 4654d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 46551da177e4SLinus Torvalds 46561da177e4SLinus Torvalds return status; 46571da177e4SLinus Torvalds } 46581da177e4SLinus Torvalds 465958fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 466042297899SJeff Layton struct nfsd4_open *open) 4661d29b20cdSJ. Bruce Fields { 4662d29b20cdSJ. Bruce Fields if (open->op_openowner) { 4663d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 4664d29b20cdSJ. Bruce Fields 4665d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 4666d3134b10SJeff Layton nfs4_put_stateowner(so); 4667d29b20cdSJ. Bruce Fields } 466832513b40SJ. Bruce Fields if (open->op_file) 46695b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 46704cdc951bSJ. Bruce Fields if (open->op_stp) 46716011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 46728287f009SSachin Bhamare if (open->op_odstate) 46738287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 4674d29b20cdSJ. Bruce Fields } 4675d29b20cdSJ. Bruce Fields 4676b37ad28bSAl Viro __be32 4677b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4678eb69853dSChristoph Hellwig union nfsd4_op_u *u) 46791da177e4SLinus Torvalds { 4680eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 46811da177e4SLinus Torvalds struct nfs4_client *clp; 4682b37ad28bSAl Viro __be32 status; 46837f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 46841da177e4SLinus Torvalds 46851da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 46861da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 46874b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 46889b2ef62bSJ. Bruce Fields if (status) 46891da177e4SLinus Torvalds goto out; 46904b24ca7dSJeff Layton clp = cstate->clp; 46911da177e4SLinus Torvalds status = nfserr_cb_path_down; 4692ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 469377a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 46941da177e4SLinus Torvalds goto out; 46951da177e4SLinus Torvalds status = nfs_ok; 46961da177e4SLinus Torvalds out: 46971da177e4SLinus Torvalds return status; 46981da177e4SLinus Torvalds } 46991da177e4SLinus Torvalds 47007f5ef2e9SJeff Layton void 470112760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 4702a76b4319SNeilBrown { 470333dcc481SJeff Layton /* do nothing if grace period already ended */ 4704a51c84edSStanislav Kinsbursky if (nn->grace_ended) 470533dcc481SJeff Layton return; 470633dcc481SJeff Layton 4707a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 4708a51c84edSStanislav Kinsbursky nn->grace_ended = true; 470970b28235SJ. Bruce Fields /* 471070b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 471170b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 471270b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 471370b28235SJ. Bruce Fields * 471470b28235SJ. Bruce Fields */ 4715919b8049SJeff Layton nfsd4_record_grace_done(nn); 471670b28235SJ. Bruce Fields /* 471770b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 471870b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 471970b28235SJ. Bruce Fields * of luck on the next boot. 472070b28235SJ. Bruce Fields * 472170b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 472270b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 472370b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 472470b28235SJ. Bruce Fields */ 47255e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 472670b28235SJ. Bruce Fields /* 472770b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 472870b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 472970b28235SJ. Bruce Fields * regular locking can resume. 473070b28235SJ. Bruce Fields */ 4731a76b4319SNeilBrown } 4732a76b4319SNeilBrown 473303f318caSJ. Bruce Fields /* 473403f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 473503f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 473603f318caSJ. Bruce Fields */ 473703f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 473803f318caSJ. Bruce Fields { 473903f318caSJ. Bruce Fields unsigned long now = get_seconds(); 474003f318caSJ. Bruce Fields unsigned long double_grace_period_end = nn->boot_time + 474103f318caSJ. Bruce Fields 2 * nn->nfsd4_lease; 474203f318caSJ. Bruce Fields 474303f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 474403f318caSJ. Bruce Fields return false; 474503f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 474603f318caSJ. Bruce Fields /* 474703f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 474803f318caSJ. Bruce Fields * still not done, give up: 474903f318caSJ. Bruce Fields */ 475003f318caSJ. Bruce Fields if (time_after(now, double_grace_period_end)) 475103f318caSJ. Bruce Fields return false; 475203f318caSJ. Bruce Fields return true; 475303f318caSJ. Bruce Fields } 475403f318caSJ. Bruce Fields 4755fd39ca9aSNeilBrown static time_t 475609121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 47571da177e4SLinus Torvalds { 47581da177e4SLinus Torvalds struct nfs4_client *clp; 4759fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 47601da177e4SLinus Torvalds struct nfs4_delegation *dp; 4761217526e7SJeff Layton struct nfs4_ol_stateid *stp; 47627919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 47631da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 47643d733711SStanislav Kinsbursky time_t cutoff = get_seconds() - nn->nfsd4_lease; 4765a832e7aeSJeff Layton time_t t, new_timeo = nn->nfsd4_lease; 47661da177e4SLinus Torvalds 47671da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 476803f318caSJ. Bruce Fields 476903f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 477003f318caSJ. Bruce Fields new_timeo = 0; 477103f318caSJ. Bruce Fields goto out; 477203f318caSJ. Bruce Fields } 477312760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 477436acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 4775c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 47765ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 47771da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 47781da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 47791da177e4SLinus Torvalds t = clp->cl_time - cutoff; 4780a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 47811da177e4SLinus Torvalds break; 47821da177e4SLinus Torvalds } 4783221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 4784d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 4785d7682988SBenny Halevy clp->cl_clientid.cl_id); 4786d7682988SBenny Halevy continue; 4787d7682988SBenny Halevy } 47884864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 478936acb66bSBenny Halevy } 4790c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 479136acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 479236acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 47931da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 47941da177e4SLinus Torvalds clp->cl_clientid.cl_id); 47954864af97STrond Myklebust list_del_init(&clp->cl_lru); 47961da177e4SLinus Torvalds expire_client(clp); 47971da177e4SLinus Torvalds } 4798cdc97505SBenny Halevy spin_lock(&state_lock); 4799e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 48001da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 48011da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 4802a832e7aeSJeff Layton t = dp->dl_time - cutoff; 4803a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 48041da177e4SLinus Torvalds break; 48051da177e4SLinus Torvalds } 48063fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 480742690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 48081da177e4SLinus Torvalds } 4809cdc97505SBenny Halevy spin_unlock(&state_lock); 48102d4a532dSJeff Layton while (!list_empty(&reaplist)) { 48112d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 48122d4a532dSJeff Layton dl_recall_lru); 48132d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 48143bd64a5bSJ. Bruce Fields revoke_delegation(dp); 48151da177e4SLinus Torvalds } 4816217526e7SJeff Layton 4817217526e7SJeff Layton spin_lock(&nn->client_lock); 4818217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 4819217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 4820217526e7SJeff Layton oo_close_lru); 4821217526e7SJeff Layton if (time_after((unsigned long)oo->oo_time, 4822217526e7SJeff Layton (unsigned long)cutoff)) { 4823a832e7aeSJeff Layton t = oo->oo_time - cutoff; 4824a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 48251da177e4SLinus Torvalds break; 48261da177e4SLinus Torvalds } 4827217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 4828217526e7SJeff Layton stp = oo->oo_last_closed_stid; 4829217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 4830217526e7SJeff Layton spin_unlock(&nn->client_lock); 4831217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 4832217526e7SJeff Layton spin_lock(&nn->client_lock); 48331da177e4SLinus Torvalds } 4834217526e7SJeff Layton spin_unlock(&nn->client_lock); 4835217526e7SJeff Layton 48367919d0a2SJeff Layton /* 48377919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 48387919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 48397919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 48407919d0a2SJeff Layton * under the assumption that the client is no longer interested. 48417919d0a2SJeff Layton * 48427919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 48437919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 48447919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 48457919d0a2SJeff Layton * indefinitely once the lock does become free. 48467919d0a2SJeff Layton */ 48477919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 48480cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 48497919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 48507919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 48517919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 48527919d0a2SJeff Layton if (time_after((unsigned long)nbl->nbl_time, 48537919d0a2SJeff Layton (unsigned long)cutoff)) { 48547919d0a2SJeff Layton t = nbl->nbl_time - cutoff; 48557919d0a2SJeff Layton new_timeo = min(new_timeo, t); 48567919d0a2SJeff Layton break; 48577919d0a2SJeff Layton } 48587919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 48597919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 48607919d0a2SJeff Layton } 48610cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 48627919d0a2SJeff Layton 48637919d0a2SJeff Layton while (!list_empty(&reaplist)) { 486464ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 48657919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 48667919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 4867cb03f94fSNeilBrown locks_delete_block(&nbl->nbl_lock); 48687919d0a2SJeff Layton free_blocked_lock(nbl); 48697919d0a2SJeff Layton } 487003f318caSJ. Bruce Fields out: 4871a832e7aeSJeff Layton new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 4872a832e7aeSJeff Layton return new_timeo; 48731da177e4SLinus Torvalds } 48741da177e4SLinus Torvalds 4875a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 4876a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 4877a254b246SHarvey Harrison 4878a254b246SHarvey Harrison static void 487909121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 48801da177e4SLinus Torvalds { 48811da177e4SLinus Torvalds time_t t; 48822e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 488309121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 488409121281SStanislav Kinsbursky laundromat_work); 48851da177e4SLinus Torvalds 488609121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 48871da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 488809121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 48891da177e4SLinus Torvalds } 48901da177e4SLinus Torvalds 48918fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 4892f8816512SNeilBrown { 48938fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 4894f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4895f7a4d872SJ. Bruce Fields return nfs_ok; 48961da177e4SLinus Torvalds } 48971da177e4SLinus Torvalds 48981da177e4SLinus Torvalds static inline int 489982c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 49001da177e4SLinus Torvalds { 490182c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 490282c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 490382c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 49041da177e4SLinus Torvalds } 49051da177e4SLinus Torvalds 49061da177e4SLinus Torvalds static inline int 490782c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 49081da177e4SLinus Torvalds { 490982c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 491082c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 49111da177e4SLinus Torvalds } 49121da177e4SLinus Torvalds 49131da177e4SLinus Torvalds static 4914dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 49151da177e4SLinus Torvalds { 4916b37ad28bSAl Viro __be32 status = nfserr_openmode; 49171da177e4SLinus Torvalds 491802921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 491902921914SJ. Bruce Fields if (stp->st_openstp) 492002921914SJ. Bruce Fields stp = stp->st_openstp; 492182c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 49221da177e4SLinus Torvalds goto out; 492382c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 49241da177e4SLinus Torvalds goto out; 49251da177e4SLinus Torvalds status = nfs_ok; 49261da177e4SLinus Torvalds out: 49271da177e4SLinus Torvalds return status; 49281da177e4SLinus Torvalds } 49291da177e4SLinus Torvalds 4930b37ad28bSAl Viro static inline __be32 49315ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 49321da177e4SLinus Torvalds { 4933203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 49341da177e4SLinus Torvalds return nfs_ok; 4935c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 493625985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 49371da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 49381da177e4SLinus Torvalds return nfserr_grace; 49391da177e4SLinus Torvalds } else if (flags & WR_STATE) 49401da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 49411da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 49421da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 49431da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 49441da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 49451da177e4SLinus Torvalds } 49461da177e4SLinus Torvalds 49471da177e4SLinus Torvalds /* 49481da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 49491da177e4SLinus Torvalds * that are not able to provide mandatory locking. 49501da177e4SLinus Torvalds */ 49511da177e4SLinus Torvalds static inline int 49525ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 49531da177e4SLinus Torvalds { 4954c87fb4a3SJ. Bruce Fields return opens_in_grace(net) && mandatory_lock(inode); 49551da177e4SLinus Torvalds } 49561da177e4SLinus Torvalds 495757b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 49580836f587SJ. Bruce Fields { 49596668958fSAndy Adamson /* 49606668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 49616668958fSAndy Adamson * when it is zero. 49626668958fSAndy Adamson */ 496328dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 496481b82965SJ. Bruce Fields return nfs_ok; 496581b82965SJ. Bruce Fields 496681b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 496781b82965SJ. Bruce Fields return nfs_ok; 49686668958fSAndy Adamson 49690836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 497014b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 49710836f587SJ. Bruce Fields return nfserr_bad_stateid; 49720836f587SJ. Bruce Fields /* 497381b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 497481b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 497581b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 497681b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 497781b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 497881b82965SJ. Bruce Fields * but better performance may result in retrying IO that 497981b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 498081b82965SJ. Bruce Fields * reordered in flight: 49810836f587SJ. Bruce Fields */ 49820836f587SJ. Bruce Fields return nfserr_old_stateid; 49830836f587SJ. Bruce Fields } 49840836f587SJ. Bruce Fields 498503da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 498603da3169STrond Myklebust { 498703da3169STrond Myklebust __be32 ret; 498803da3169STrond Myklebust 498903da3169STrond Myklebust spin_lock(&s->sc_lock); 499003da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 499103da3169STrond Myklebust if (ret == nfs_ok) 499203da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 499303da3169STrond Myklebust spin_unlock(&s->sc_lock); 499403da3169STrond Myklebust return ret; 499503da3169STrond Myklebust } 499603da3169STrond Myklebust 4997ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 4998ebe9cb3bSChristoph Hellwig { 4999ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 5000ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 5001ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 5002ebe9cb3bSChristoph Hellwig return nfs_ok; 5003ebe9cb3bSChristoph Hellwig } 5004ebe9cb3bSChristoph Hellwig 50057df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 500617456804SBryan Schumaker { 500797b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 50081af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 500917456804SBryan Schumaker 5010ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5011ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 50121af71cc8SJeff Layton return status; 50137df302f7SChuck Lever /* Client debugging aid. */ 50147df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 50157df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 50167df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 50177df302f7SChuck Lever sizeof(addr_str)); 50187df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 50197df302f7SChuck Lever "with incorrect client ID\n", addr_str); 50201af71cc8SJeff Layton return status; 50217df302f7SChuck Lever } 50221af71cc8SJeff Layton spin_lock(&cl->cl_lock); 50231af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 502497b7e3b6SJ. Bruce Fields if (!s) 50251af71cc8SJeff Layton goto out_unlock; 502603da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 502717456804SBryan Schumaker if (status) 50281af71cc8SJeff Layton goto out_unlock; 502923340032SJ. Bruce Fields switch (s->sc_type) { 503023340032SJ. Bruce Fields case NFS4_DELEG_STID: 50311af71cc8SJeff Layton status = nfs_ok; 50321af71cc8SJeff Layton break; 50333bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 50341af71cc8SJeff Layton status = nfserr_deleg_revoked; 50351af71cc8SJeff Layton break; 503623340032SJ. Bruce Fields case NFS4_OPEN_STID: 503723340032SJ. Bruce Fields case NFS4_LOCK_STID: 5038ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 50391af71cc8SJeff Layton break; 504023340032SJ. Bruce Fields default: 504123340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 5042b0fc29d6STrond Myklebust /* Fallthrough */ 504323340032SJ. Bruce Fields case NFS4_CLOSED_STID: 5044b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 50451af71cc8SJeff Layton status = nfserr_bad_stateid; 504623340032SJ. Bruce Fields } 50471af71cc8SJeff Layton out_unlock: 50481af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 50491af71cc8SJeff Layton return status; 505017456804SBryan Schumaker } 505117456804SBryan Schumaker 5052cd61c522SChristoph Hellwig __be32 50532dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 50542dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 50552dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 505638c2f4b1SJ. Bruce Fields { 50570eb6f20aSJ. Bruce Fields __be32 status; 505895da1b3aSAndrew Elble bool return_revoked = false; 505995da1b3aSAndrew Elble 506095da1b3aSAndrew Elble /* 506195da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 506295da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 506395da1b3aSAndrew Elble */ 506495da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 506595da1b3aSAndrew Elble return_revoked = true; 506695da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 506795da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 506838c2f4b1SJ. Bruce Fields 5069ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5070ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 507138c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 50724b24ca7dSJeff Layton status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn); 5073a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 50744b24ca7dSJeff Layton if (cstate->session) 5075a8a7c677STrond Myklebust return nfserr_bad_stateid; 507638c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 5077a8a7c677STrond Myklebust } 50780eb6f20aSJ. Bruce Fields if (status) 50790eb6f20aSJ. Bruce Fields return status; 50804b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 508138c2f4b1SJ. Bruce Fields if (!*s) 508238c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 508395da1b3aSAndrew Elble if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 508495da1b3aSAndrew Elble nfs4_put_stid(*s); 508595da1b3aSAndrew Elble if (cstate->minorversion) 508695da1b3aSAndrew Elble return nfserr_deleg_revoked; 508795da1b3aSAndrew Elble return nfserr_bad_stateid; 508895da1b3aSAndrew Elble } 508938c2f4b1SJ. Bruce Fields return nfs_ok; 509038c2f4b1SJ. Bruce Fields } 509138c2f4b1SJ. Bruce Fields 5092a0649b2dSChristoph Hellwig static struct file * 5093a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 5094a0649b2dSChristoph Hellwig { 5095af90f707SChristoph Hellwig if (!s) 5096af90f707SChristoph Hellwig return NULL; 5097af90f707SChristoph Hellwig 5098a0649b2dSChristoph Hellwig switch (s->sc_type) { 5099a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 5100a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 5101a0649b2dSChristoph Hellwig return NULL; 5102a0649b2dSChristoph Hellwig return get_file(s->sc_file->fi_deleg_file); 5103a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 5104a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 5105a0649b2dSChristoph Hellwig if (flags & RD_STATE) 5106a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 5107a0649b2dSChristoph Hellwig else 5108a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 5109a0649b2dSChristoph Hellwig break; 5110a0649b2dSChristoph Hellwig } 5111a0649b2dSChristoph Hellwig 5112a0649b2dSChristoph Hellwig return NULL; 5113a0649b2dSChristoph Hellwig } 5114a0649b2dSChristoph Hellwig 5115a0649b2dSChristoph Hellwig static __be32 5116d8836f77SJ. Bruce Fields nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) 5117a0649b2dSChristoph Hellwig { 5118a0649b2dSChristoph Hellwig __be32 status; 5119a0649b2dSChristoph Hellwig 5120a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 5121a0649b2dSChristoph Hellwig if (status) 5122a0649b2dSChristoph Hellwig return status; 5123a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 5124a0649b2dSChristoph Hellwig } 5125a0649b2dSChristoph Hellwig 5126af90f707SChristoph Hellwig static __be32 5127af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 5128af90f707SChristoph Hellwig struct file **filpp, bool *tmp_file, int flags) 5129af90f707SChristoph Hellwig { 5130af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 5131af90f707SChristoph Hellwig struct file *file; 5132af90f707SChristoph Hellwig __be32 status; 5133af90f707SChristoph Hellwig 5134af90f707SChristoph Hellwig file = nfs4_find_file(s, flags); 5135af90f707SChristoph Hellwig if (file) { 5136af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 5137af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 5138af90f707SChristoph Hellwig if (status) { 5139af90f707SChristoph Hellwig fput(file); 5140af90f707SChristoph Hellwig return status; 5141af90f707SChristoph Hellwig } 5142af90f707SChristoph Hellwig 5143af90f707SChristoph Hellwig *filpp = file; 5144af90f707SChristoph Hellwig } else { 5145af90f707SChristoph Hellwig status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp); 5146af90f707SChristoph Hellwig if (status) 5147af90f707SChristoph Hellwig return status; 5148af90f707SChristoph Hellwig 5149af90f707SChristoph Hellwig if (tmp_file) 5150af90f707SChristoph Hellwig *tmp_file = true; 5151af90f707SChristoph Hellwig } 5152af90f707SChristoph Hellwig 5153af90f707SChristoph Hellwig return 0; 5154af90f707SChristoph Hellwig } 5155af90f707SChristoph Hellwig 51561da177e4SLinus Torvalds /* 51571da177e4SLinus Torvalds * Checks for stateid operations 51581da177e4SLinus Torvalds */ 5159b37ad28bSAl Viro __be32 5160af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 5161aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 5162aa0d6aedSAnna Schumaker stateid_t *stateid, int flags, struct file **filpp, bool *tmp_file) 51631da177e4SLinus Torvalds { 5164a0649b2dSChristoph Hellwig struct inode *ino = d_inode(fhp->fh_dentry); 5165af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 51663320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5167af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 5168b37ad28bSAl Viro __be32 status; 51691da177e4SLinus Torvalds 51701da177e4SLinus Torvalds if (filpp) 51711da177e4SLinus Torvalds *filpp = NULL; 5172af90f707SChristoph Hellwig if (tmp_file) 5173af90f707SChristoph Hellwig *tmp_file = false; 51741da177e4SLinus Torvalds 51755ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 51761da177e4SLinus Torvalds return nfserr_grace; 51771da177e4SLinus Torvalds 5178af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 5179af90f707SChristoph Hellwig status = check_special_stateids(net, fhp, stateid, flags); 5180af90f707SChristoph Hellwig goto done; 5181af90f707SChristoph Hellwig } 51821da177e4SLinus Torvalds 51832dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 5184db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 51852dd6e458STrond Myklebust &s, nn); 518638c2f4b1SJ. Bruce Fields if (status) 5187c2d1d6a8STrond Myklebust return status; 518803da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 5189a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 51900c2a498fSJ. Bruce Fields if (status) 51910c2a498fSJ. Bruce Fields goto out; 5192a0649b2dSChristoph Hellwig 5193f7a4d872SJ. Bruce Fields switch (s->sc_type) { 5194f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 5195a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 5196f7a4d872SJ. Bruce Fields break; 5197f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 5198f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 5199d8836f77SJ. Bruce Fields status = nfs4_check_olstateid(openlockstateid(s), flags); 5200f7a4d872SJ. Bruce Fields break; 5201f7a4d872SJ. Bruce Fields default: 520214bcab1aSTrond Myklebust status = nfserr_bad_stateid; 5203a0649b2dSChristoph Hellwig break; 52041da177e4SLinus Torvalds } 52058fcd461dSJeff Layton if (status) 52068fcd461dSJeff Layton goto out; 52078fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 5208a0649b2dSChristoph Hellwig 5209af90f707SChristoph Hellwig done: 5210af90f707SChristoph Hellwig if (!status && filpp) 5211af90f707SChristoph Hellwig status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags); 52121da177e4SLinus Torvalds out: 5213af90f707SChristoph Hellwig if (s) 5214fd911011STrond Myklebust nfs4_put_stid(s); 52151da177e4SLinus Torvalds return status; 52161da177e4SLinus Torvalds } 52171da177e4SLinus Torvalds 5218e1ca12dfSBryan Schumaker /* 521917456804SBryan Schumaker * Test if the stateid is valid 522017456804SBryan Schumaker */ 522117456804SBryan Schumaker __be32 522217456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5223eb69853dSChristoph Hellwig union nfsd4_op_u *u) 522417456804SBryan Schumaker { 5225eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 522603cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 522703cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 522803cfb420SBryan Schumaker 522903cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 52307df302f7SChuck Lever stateid->ts_id_status = 52317df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 523203cfb420SBryan Schumaker 523317456804SBryan Schumaker return nfs_ok; 523417456804SBryan Schumaker } 523517456804SBryan Schumaker 523642691398SChuck Lever static __be32 523742691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 523842691398SChuck Lever { 523942691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 524042691398SChuck Lever __be32 ret; 524142691398SChuck Lever 5242659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 5243659aefb6STrond Myklebust if (ret) 5244659aefb6STrond Myklebust goto out_put_stid; 524542691398SChuck Lever 524642691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 524742691398SChuck Lever if (ret) 524842691398SChuck Lever goto out; 524942691398SChuck Lever 525042691398SChuck Lever ret = nfserr_locks_held; 525142691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 525242691398SChuck Lever lockowner(stp->st_stateowner))) 525342691398SChuck Lever goto out; 525442691398SChuck Lever 525542691398SChuck Lever release_lock_stateid(stp); 525642691398SChuck Lever ret = nfs_ok; 525742691398SChuck Lever 525842691398SChuck Lever out: 525942691398SChuck Lever mutex_unlock(&stp->st_mutex); 5260659aefb6STrond Myklebust out_put_stid: 526142691398SChuck Lever nfs4_put_stid(s); 526242691398SChuck Lever return ret; 526342691398SChuck Lever } 526442691398SChuck Lever 5265e1ca12dfSBryan Schumaker __be32 5266e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5267eb69853dSChristoph Hellwig union nfsd4_op_u *u) 5268e1ca12dfSBryan Schumaker { 5269eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 5270e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 52712da1cec7SJ. Bruce Fields struct nfs4_stid *s; 52723bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 527338c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 52742da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 5275e1ca12dfSBryan Schumaker 52761af71cc8SJeff Layton spin_lock(&cl->cl_lock); 52771af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 52782da1cec7SJ. Bruce Fields if (!s) 52791af71cc8SJeff Layton goto out_unlock; 528003da3169STrond Myklebust spin_lock(&s->sc_lock); 52812da1cec7SJ. Bruce Fields switch (s->sc_type) { 52822da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 5283e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 52841af71cc8SJeff Layton break; 52852da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 52861af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 52871af71cc8SJeff Layton if (ret) 52881af71cc8SJeff Layton break; 52891af71cc8SJeff Layton ret = nfserr_locks_held; 52901af71cc8SJeff Layton break; 52912da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 529203da3169STrond Myklebust spin_unlock(&s->sc_lock); 5293a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 52941af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 529542691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 52961af71cc8SJeff Layton goto out; 52973bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 529803da3169STrond Myklebust spin_unlock(&s->sc_lock); 52993bd64a5bSJ. Bruce Fields dp = delegstateid(s); 53002d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 53012d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 53026011695dSTrond Myklebust nfs4_put_stid(s); 53033bd64a5bSJ. Bruce Fields ret = nfs_ok; 53041af71cc8SJeff Layton goto out; 53051af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 5306e1ca12dfSBryan Schumaker } 530703da3169STrond Myklebust spin_unlock(&s->sc_lock); 53081af71cc8SJeff Layton out_unlock: 53091af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 5310e1ca12dfSBryan Schumaker out: 5311e1ca12dfSBryan Schumaker return ret; 5312e1ca12dfSBryan Schumaker } 5313e1ca12dfSBryan Schumaker 53144c4cd222SNeilBrown static inline int 53154c4cd222SNeilBrown setlkflg (int type) 53164c4cd222SNeilBrown { 53174c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 53184c4cd222SNeilBrown RD_STATE : WR_STATE; 53194c4cd222SNeilBrown } 53201da177e4SLinus Torvalds 5321dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 5322c0a5d93eSJ. Bruce Fields { 5323c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 5324c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 5325c0a5d93eSJ. Bruce Fields __be32 status; 5326c0a5d93eSJ. Bruce Fields 5327c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 5328c0a5d93eSJ. Bruce Fields if (status) 5329c0a5d93eSJ. Bruce Fields return status; 53309271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 53319271d7e5STrond Myklebust if (status != nfs_ok) 53329271d7e5STrond Myklebust return status; 5333f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 533435a92fe8SJeff Layton if (status == nfs_ok) 533535a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 533635a92fe8SJeff Layton if (status != nfs_ok) 5337feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 5338f7a4d872SJ. Bruce Fields return status; 5339c0a5d93eSJ. Bruce Fields } 5340c0a5d93eSJ. Bruce Fields 53411da177e4SLinus Torvalds /* 53421da177e4SLinus Torvalds * Checks for sequence id mutating operations. 53431da177e4SLinus Torvalds */ 5344b37ad28bSAl Viro static __be32 5345dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 53462288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 53473320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 53483320fef1SStanislav Kinsbursky struct nfsd_net *nn) 53491da177e4SLinus Torvalds { 53500836f587SJ. Bruce Fields __be32 status; 535138c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 5352e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 53531da177e4SLinus Torvalds 53548c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 53558c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 53561da177e4SLinus Torvalds 53571da177e4SLinus Torvalds *stpp = NULL; 53582dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 5359c0a5d93eSJ. Bruce Fields if (status) 5360c0a5d93eSJ. Bruce Fields return status; 5361e17f99b7STrond Myklebust stp = openlockstateid(s); 536258fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 53631da177e4SLinus Torvalds 5364e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 5365fd911011STrond Myklebust if (!status) 5366e17f99b7STrond Myklebust *stpp = stp; 5367fd911011STrond Myklebust else 5368fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 5369e17f99b7STrond Myklebust return status; 53701da177e4SLinus Torvalds } 53711da177e4SLinus Torvalds 53723320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 53733320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 5374c0a5d93eSJ. Bruce Fields { 5375c0a5d93eSJ. Bruce Fields __be32 status; 5376c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 53774cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 53781da177e4SLinus Torvalds 5379c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 53804cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 53810836f587SJ. Bruce Fields if (status) 53820836f587SJ. Bruce Fields return status; 53834cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 53844cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 5385feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 53864cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 5387c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 53884cbfc9f7STrond Myklebust } 53894cbfc9f7STrond Myklebust *stpp = stp; 53903a4f98bbSNeilBrown return nfs_ok; 53911da177e4SLinus Torvalds } 53921da177e4SLinus Torvalds 5393b37ad28bSAl Viro __be32 5394ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5395eb69853dSChristoph Hellwig union nfsd4_op_u *u) 53961da177e4SLinus Torvalds { 5397eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 5398b37ad28bSAl Viro __be32 status; 5399fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 5400dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 54013320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 54021da177e4SLinus Torvalds 5403a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 5404a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 54051da177e4SLinus Torvalds 5406ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 5407a8cddc5dSJ. Bruce Fields if (status) 5408a8cddc5dSJ. Bruce Fields return status; 54091da177e4SLinus Torvalds 54109072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 5411ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 54123320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 54139072d5c6SJ. Bruce Fields if (status) 54141da177e4SLinus Torvalds goto out; 5415fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 541668b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 541735a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 5418feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 54192585fc79STrond Myklebust goto put_stateid; 542035a92fe8SJeff Layton } 5421dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 54229767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 5423feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 54248c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 5425dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 5426c7b9a459SNeilBrown 54272a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 542868b66e82SJ. Bruce Fields status = nfs_ok; 54292585fc79STrond Myklebust put_stateid: 54302585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 54311da177e4SLinus Torvalds out: 54329411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 54331da177e4SLinus Torvalds return status; 54341da177e4SLinus Torvalds } 54351da177e4SLinus Torvalds 54366409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 54371da177e4SLinus Torvalds { 543882c5ff1bSJeff Layton if (!test_access(access, stp)) 54396409a5a6SJ. Bruce Fields return; 544011b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 544182c5ff1bSJeff Layton clear_access(access, stp); 5442f197c271SJ. Bruce Fields } 54436409a5a6SJ. Bruce Fields 54446409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 54456409a5a6SJ. Bruce Fields { 54466409a5a6SJ. Bruce Fields switch (to_access) { 54476409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 54486409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 54496409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 54506409a5a6SJ. Bruce Fields break; 54516409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 54526409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 54536409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 54546409a5a6SJ. Bruce Fields break; 54556409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 54566409a5a6SJ. Bruce Fields break; 54576409a5a6SJ. Bruce Fields default: 5458063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 54591da177e4SLinus Torvalds } 54601da177e4SLinus Torvalds } 54611da177e4SLinus Torvalds 5462b37ad28bSAl Viro __be32 5463ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 5464eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 54651da177e4SLinus Torvalds { 5466eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 5467b37ad28bSAl Viro __be32 status; 5468dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 54693320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 54701da177e4SLinus Torvalds 5471a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 5472a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 54731da177e4SLinus Torvalds 5474c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 54752c8bd7e0SBenny Halevy if (od->od_deleg_want) 54762c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 54772c8bd7e0SBenny Halevy od->od_deleg_want); 54781da177e4SLinus Torvalds 5479c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 54803320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 54819072d5c6SJ. Bruce Fields if (status) 54821da177e4SLinus Torvalds goto out; 54831da177e4SLinus Torvalds status = nfserr_inval; 548482c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 5485c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 54861da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 54870667b1e9STrond Myklebust goto put_stateid; 54881da177e4SLinus Torvalds } 5489ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 5490c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 54911da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 54920667b1e9STrond Myklebust goto put_stateid; 54931da177e4SLinus Torvalds } 54946409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 5495ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 54969767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 54971da177e4SLinus Torvalds status = nfs_ok; 54980667b1e9STrond Myklebust put_stateid: 5499feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 55000667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 55011da177e4SLinus Torvalds out: 55029411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 55031da177e4SLinus Torvalds return status; 55041da177e4SLinus Torvalds } 55051da177e4SLinus Torvalds 5506f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 5507f7a4d872SJ. Bruce Fields { 5508acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 5509e8568739SJeff Layton bool unhashed; 5510d83017f9SJeff Layton LIST_HEAD(reaplist); 5511acf9295bSTrond Myklebust 55122c41beb0SJeff Layton spin_lock(&clp->cl_lock); 5513e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 5514acf9295bSTrond Myklebust 5515d83017f9SJeff Layton if (clp->cl_minorversion) { 5516e8568739SJeff Layton if (unhashed) 5517d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 5518d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 5519d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 5520d83017f9SJeff Layton } else { 5521d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 5522d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 5523e8568739SJeff Layton if (unhashed) 5524d3134b10SJeff Layton move_to_close_lru(s, clp->net); 552538c387b5SJ. Bruce Fields } 5526d83017f9SJeff Layton } 552738c387b5SJ. Bruce Fields 55281da177e4SLinus Torvalds /* 55291da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 55301da177e4SLinus Torvalds */ 5531b37ad28bSAl Viro __be32 5532ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5533eb69853dSChristoph Hellwig union nfsd4_op_u *u) 55341da177e4SLinus Torvalds { 5535eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 5536b37ad28bSAl Viro __be32 status; 5537dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 55383320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 55393320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 55401da177e4SLinus Torvalds 5541a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 5542a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 55431da177e4SLinus Torvalds 5544f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 5545f7a4d872SJ. Bruce Fields &close->cl_stateid, 5546f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 55473320fef1SStanislav Kinsbursky &stp, nn); 55489411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 55499072d5c6SJ. Bruce Fields if (status) 55501da177e4SLinus Torvalds goto out; 555115ca08d3STrond Myklebust 555215ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 5553bd2decacSJeff Layton 5554bd2decacSJeff Layton /* 5555bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 5556bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 5557bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 5558bd2decacSJeff Layton * that racing ops see that there was a state change. 5559bd2decacSJeff Layton */ 55609767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 55611da177e4SLinus Torvalds 5562f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 556315ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 55648a0b589dSTrond Myklebust 5565bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 5566bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 5567bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 5568bd2decacSJeff Layton * universally. 5569bd2decacSJeff Layton * 5570bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 5571bd2decacSJeff Layton */ 5572bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 5573fb500a7cSTrond Myklebust 55748a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 55758a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 55761da177e4SLinus Torvalds out: 55771da177e4SLinus Torvalds return status; 55781da177e4SLinus Torvalds } 55791da177e4SLinus Torvalds 5580b37ad28bSAl Viro __be32 5581ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5582eb69853dSChristoph Hellwig union nfsd4_op_u *u) 55831da177e4SLinus Torvalds { 5584eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 5585203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 5586203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 558738c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 5588b37ad28bSAl Viro __be32 status; 55893320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 55901da177e4SLinus Torvalds 5591ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 5592203a8c8eSJ. Bruce Fields return status; 55931da177e4SLinus Torvalds 55942dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 559538c2f4b1SJ. Bruce Fields if (status) 5596203a8c8eSJ. Bruce Fields goto out; 559738c2f4b1SJ. Bruce Fields dp = delegstateid(s); 559803da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 5599203a8c8eSJ. Bruce Fields if (status) 5600fd911011STrond Myklebust goto put_stateid; 5601203a8c8eSJ. Bruce Fields 56023bd64a5bSJ. Bruce Fields destroy_delegation(dp); 5603fd911011STrond Myklebust put_stateid: 5604fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 56051da177e4SLinus Torvalds out: 56061da177e4SLinus Torvalds return status; 56071da177e4SLinus Torvalds } 56081da177e4SLinus Torvalds 560987df4de8SBenny Halevy static inline u64 561087df4de8SBenny Halevy end_offset(u64 start, u64 len) 561187df4de8SBenny Halevy { 561287df4de8SBenny Halevy u64 end; 561387df4de8SBenny Halevy 561487df4de8SBenny Halevy end = start + len; 561587df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 561687df4de8SBenny Halevy } 561787df4de8SBenny Halevy 561887df4de8SBenny Halevy /* last octet in a range */ 561987df4de8SBenny Halevy static inline u64 562087df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 562187df4de8SBenny Halevy { 562287df4de8SBenny Halevy u64 end; 562387df4de8SBenny Halevy 5624063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 562587df4de8SBenny Halevy end = start + len; 562687df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 562787df4de8SBenny Halevy } 562887df4de8SBenny Halevy 56291da177e4SLinus Torvalds /* 56301da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 56311da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 56321da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 56331da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 56341da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 56351da177e4SLinus Torvalds * the VFS, but this is a very deep change! 56361da177e4SLinus Torvalds */ 56371da177e4SLinus Torvalds static inline void 56381da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 56391da177e4SLinus Torvalds { 56401da177e4SLinus Torvalds if (lock->fl_start < 0) 56411da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 56421da177e4SLinus Torvalds if (lock->fl_end < 0) 56431da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 56441da177e4SLinus Torvalds } 56451da177e4SLinus Torvalds 5646cae80b30SJeff Layton static fl_owner_t 5647cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner) 5648aef9583bSKinglong Mee { 5649cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5650cae80b30SJeff Layton 5651cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 5652cae80b30SJeff Layton return owner; 5653aef9583bSKinglong Mee } 5654aef9583bSKinglong Mee 5655cae80b30SJeff Layton static void 5656cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner) 5657aef9583bSKinglong Mee { 5658cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5659aef9583bSKinglong Mee 5660cae80b30SJeff Layton if (lo) 5661aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 5662aef9583bSKinglong Mee } 5663aef9583bSKinglong Mee 566476d348faSJeff Layton static void 566576d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 566676d348faSJeff Layton { 566776d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 566876d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 566976d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 567076d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 567176d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 567276d348faSJeff Layton bool queue = false; 567376d348faSJeff Layton 56747919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 56750cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 567676d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 567776d348faSJeff Layton list_del_init(&nbl->nbl_list); 56787919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 567976d348faSJeff Layton queue = true; 568076d348faSJeff Layton } 56810cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 568276d348faSJeff Layton 568376d348faSJeff Layton if (queue) 568476d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 568576d348faSJeff Layton } 568676d348faSJeff Layton 56877b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 568876d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 5689aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 5690aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 5691d5b9026aSNeilBrown }; 56921da177e4SLinus Torvalds 56931da177e4SLinus Torvalds static inline void 56941da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 56951da177e4SLinus Torvalds { 5696fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 56971da177e4SLinus Torvalds 5698d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 5699fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 5700fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 5701fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 57027c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 57037c13f344SJ. Bruce Fields /* We just don't care that much */ 57047c13f344SJ. Bruce Fields goto nevermind; 5705fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 5706fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 5707d5b9026aSNeilBrown } else { 57087c13f344SJ. Bruce Fields nevermind: 57097c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 57107c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 5711d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 5712d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 57131da177e4SLinus Torvalds } 57141da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 571587df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 571687df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 57171da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 57181da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 57191da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 57201da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 57211da177e4SLinus Torvalds } 57221da177e4SLinus Torvalds 5723fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5724c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 57251da177e4SLinus Torvalds { 5726d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 5727b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 57281da177e4SLinus Torvalds 57290a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 57300a880a28STrond Myklebust 5731d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 5732d4f0489fSTrond Myklebust so_strhash) { 5733b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 5734b3c32bcdSTrond Myklebust continue; 5735b5971afaSKinglong Mee if (same_owner_str(so, owner)) 5736b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 57371da177e4SLinus Torvalds } 57381da177e4SLinus Torvalds return NULL; 57391da177e4SLinus Torvalds } 57401da177e4SLinus Torvalds 5741c58c6610STrond Myklebust static struct nfs4_lockowner * 5742c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 5743c58c6610STrond Myklebust { 5744c58c6610STrond Myklebust struct nfs4_lockowner *lo; 5745c58c6610STrond Myklebust 5746d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5747c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 5748d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5749c58c6610STrond Myklebust return lo; 5750c58c6610STrond Myklebust } 5751c58c6610STrond Myklebust 57528f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 57538f4b54c5SJeff Layton { 5754c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 57558f4b54c5SJeff Layton } 57568f4b54c5SJeff Layton 57576b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 57586b180f0bSJeff Layton { 57596b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 57606b180f0bSJeff Layton 57616b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 57626b180f0bSJeff Layton } 57636b180f0bSJeff Layton 57646b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 57658f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 57666b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 57676b180f0bSJeff Layton }; 57686b180f0bSJeff Layton 57691da177e4SLinus Torvalds /* 57701da177e4SLinus Torvalds * Alloc a lock owner structure. 57711da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 577225985edcSLucas De Marchi * occurred. 57731da177e4SLinus Torvalds * 577416bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 57751da177e4SLinus Torvalds */ 5776fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5777c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 5778c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 5779c58c6610STrond Myklebust struct nfsd4_lock *lock) 5780c58c6610STrond Myklebust { 5781c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 57821da177e4SLinus Torvalds 5783fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 5784fe0750e5SJ. Bruce Fields if (!lo) 57851da177e4SLinus Torvalds return NULL; 578676d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 5787fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 5788fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 57895db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 57906b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 5791d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5792c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 5793c58c6610STrond Myklebust if (ret == NULL) { 5794c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 5795d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 5796c58c6610STrond Myklebust ret = lo; 5797c58c6610STrond Myklebust } else 5798d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 5799d50ffdedSKinglong Mee 5800d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5801340f0ba1SJ. Bruce Fields return ret; 58021da177e4SLinus Torvalds } 58031da177e4SLinus Torvalds 5804fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 5805fd1fd685STrond Myklebust find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) 5806fd1fd685STrond Myklebust { 5807fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 5808fd1fd685STrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 5809fd1fd685STrond Myklebust 5810fd1fd685STrond Myklebust lockdep_assert_held(&clp->cl_lock); 5811fd1fd685STrond Myklebust 5812fd1fd685STrond Myklebust list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { 5813fd1fd685STrond Myklebust if (lst->st_stid.sc_type != NFS4_LOCK_STID) 5814fd1fd685STrond Myklebust continue; 5815fd1fd685STrond Myklebust if (lst->st_stid.sc_file == fp) { 5816fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 5817fd1fd685STrond Myklebust return lst; 5818fd1fd685STrond Myklebust } 5819fd1fd685STrond Myklebust } 5820fd1fd685STrond Myklebust return NULL; 5821fd1fd685STrond Myklebust } 5822fd1fd685STrond Myklebust 5823beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 5824356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 5825356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 5826f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 58271da177e4SLinus Torvalds { 5828d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 5829beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 58301da177e4SLinus Torvalds 5831beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 58324f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 5833beeca19cSTrond Myklebust retry: 5834beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 5835beeca19cSTrond Myklebust spin_lock(&fp->fi_lock); 5836beeca19cSTrond Myklebust retstp = find_lock_stateid(lo, fp); 5837beeca19cSTrond Myklebust if (retstp) 5838beeca19cSTrond Myklebust goto out_unlock; 5839356a95ecSJeff Layton 5840a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 58413abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 5842b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 584313cd2184SNeilBrown get_nfs4_file(fp); 584411b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 58450997b173SJ. Bruce Fields stp->st_access_bmap = 0; 58461da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 58474c4cd222SNeilBrown stp->st_openstp = open_stp; 58483c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 58491c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 58501d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 5851beeca19cSTrond Myklebust out_unlock: 58521d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 5853beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 5854beeca19cSTrond Myklebust if (retstp) { 5855beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 5856beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 5857beeca19cSTrond Myklebust goto retry; 5858beeca19cSTrond Myklebust } 5859beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 5860beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 5861beeca19cSTrond Myklebust stp = retstp; 5862beeca19cSTrond Myklebust } 5863beeca19cSTrond Myklebust return stp; 58641da177e4SLinus Torvalds } 58651da177e4SLinus Torvalds 5866c53530daSJeff Layton static struct nfs4_ol_stateid * 5867356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 5868356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 5869356a95ecSJeff Layton bool *new) 5870356a95ecSJeff Layton { 5871356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 5872356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 5873356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 5874356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 5875356a95ecSJeff Layton 5876beeca19cSTrond Myklebust *new = false; 5877356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5878356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5879356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5880beeca19cSTrond Myklebust if (lst != NULL) { 5881beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 5882beeca19cSTrond Myklebust goto out; 5883beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 5884beeca19cSTrond Myklebust } 5885d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 5886356a95ecSJeff Layton if (ns == NULL) 5887356a95ecSJeff Layton return NULL; 5888356a95ecSJeff Layton 5889beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 5890beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 5891356a95ecSJeff Layton *new = true; 5892beeca19cSTrond Myklebust else 5893356a95ecSJeff Layton nfs4_put_stid(ns); 5894beeca19cSTrond Myklebust out: 5895356a95ecSJeff Layton return lst; 5896356a95ecSJeff Layton } 5897c53530daSJeff Layton 5898fd39ca9aSNeilBrown static int 58991da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 59001da177e4SLinus Torvalds { 590187df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 5902e7969315SKinglong Mee (length > ~offset))); 59031da177e4SLinus Torvalds } 59041da177e4SLinus Torvalds 5905dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 59060997b173SJ. Bruce Fields { 590711b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 59080997b173SJ. Bruce Fields 59097214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 59107214e860SJeff Layton 591182c5ff1bSJeff Layton if (test_access(access, lock_stp)) 59120997b173SJ. Bruce Fields return; 591312659651SJeff Layton __nfs4_file_get_access(fp, access); 591482c5ff1bSJeff Layton set_access(access, lock_stp); 59150997b173SJ. Bruce Fields } 59160997b173SJ. Bruce Fields 5917356a95ecSJeff Layton static __be32 5918356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 5919356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 5920356a95ecSJeff Layton struct nfsd4_lock *lock, 5921dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 592264a284d0SJ. Bruce Fields { 59235db1c03fSJeff Layton __be32 status; 592411b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 592564a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 592664a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 59272b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 592864a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 5929dd257933SJeff Layton struct nfs4_ol_stateid *lst; 593064a284d0SJ. Bruce Fields unsigned int strhashval; 593164a284d0SJ. Bruce Fields 5932c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 5933c53530daSJeff Layton if (!lo) { 593476f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 593564a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 593664a284d0SJ. Bruce Fields if (lo == NULL) 593764a284d0SJ. Bruce Fields return nfserr_jukebox; 5938c53530daSJeff Layton } else { 5939c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 59405db1c03fSJeff Layton status = nfserr_bad_seqid; 5941c53530daSJeff Layton if (!cstate->minorversion && 5942c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 59435db1c03fSJeff Layton goto out; 5944c53530daSJeff Layton } 5945c53530daSJeff Layton 5946dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 5947dd257933SJeff Layton if (lst == NULL) { 59485db1c03fSJeff Layton status = nfserr_jukebox; 59495db1c03fSJeff Layton goto out; 595064a284d0SJ. Bruce Fields } 5951dd257933SJeff Layton 59525db1c03fSJeff Layton status = nfs_ok; 5953dd257933SJeff Layton *plst = lst; 59545db1c03fSJeff Layton out: 59555db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 59565db1c03fSJeff Layton return status; 595764a284d0SJ. Bruce Fields } 595864a284d0SJ. Bruce Fields 59591da177e4SLinus Torvalds /* 59601da177e4SLinus Torvalds * LOCK operation 59611da177e4SLinus Torvalds */ 5962b37ad28bSAl Viro __be32 5963ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5964eb69853dSChristoph Hellwig union nfsd4_op_u *u) 59651da177e4SLinus Torvalds { 5966eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 5967fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 5968fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 59693d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 59700667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 59717214e860SJeff Layton struct nfs4_file *fp; 59727d947842SJ. Bruce Fields struct file *filp = NULL; 597376d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 597421179d81SJeff Layton struct file_lock *file_lock = NULL; 597521179d81SJeff Layton struct file_lock *conflock = NULL; 5976b37ad28bSAl Viro __be32 status = 0; 5977b34f27aaSJ. Bruce Fields int lkflg; 5978b8dd7b9aSAl Viro int err; 59795db1c03fSJeff Layton bool new = false; 598076d348faSJeff Layton unsigned char fl_type; 598176d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 59823320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 59833320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 59841da177e4SLinus Torvalds 59851da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 59861da177e4SLinus Torvalds (long long) lock->lk_offset, 59871da177e4SLinus Torvalds (long long) lock->lk_length); 59881da177e4SLinus Torvalds 59891da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 59901da177e4SLinus Torvalds return nfserr_inval; 59911da177e4SLinus Torvalds 5992ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 59938837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 5994a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 5995a6f6ef2fSAndy Adamson return status; 5996a6f6ef2fSAndy Adamson } 5997a6f6ef2fSAndy Adamson 59981da177e4SLinus Torvalds if (lock->lk_is_new) { 5999684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 6000684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 600176f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 6002684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 6003684e5638SJ. Bruce Fields sizeof(clientid_t)); 6004684e5638SJ. Bruce Fields 60051da177e4SLinus Torvalds status = nfserr_stale_clientid; 60062c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 60071da177e4SLinus Torvalds goto out; 60081da177e4SLinus Torvalds 60091da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 6010c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 60111da177e4SLinus Torvalds lock->lk_new_open_seqid, 60121da177e4SLinus Torvalds &lock->lk_new_open_stateid, 60133320fef1SStanislav Kinsbursky &open_stp, nn); 601437515177SNeilBrown if (status) 60151da177e4SLinus Torvalds goto out; 6016feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 6017fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 6018b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 6019684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 602076f6c9e1SKinglong Mee &lock->lk_new_clientid)) 6021b34f27aaSJ. Bruce Fields goto out; 602264a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 60235db1c03fSJeff Layton &lock_stp, &new); 60243d0fabd5STrond Myklebust } else { 6025dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 60261da177e4SLinus Torvalds lock->lk_old_lock_seqid, 60271da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 60283320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 60293d0fabd5STrond Myklebust } 60301da177e4SLinus Torvalds if (status) 60311da177e4SLinus Torvalds goto out; 6032fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 60331da177e4SLinus Torvalds 6034b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 6035b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 6036b34f27aaSJ. Bruce Fields if (status) 6037b34f27aaSJ. Bruce Fields goto out; 6038b34f27aaSJ. Bruce Fields 60390dd395dcSNeilBrown status = nfserr_grace; 60403320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 60410dd395dcSNeilBrown goto out; 60420dd395dcSNeilBrown status = nfserr_no_grace; 60433320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 60440dd395dcSNeilBrown goto out; 60450dd395dcSNeilBrown 604611b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 60471da177e4SLinus Torvalds switch (lock->lk_type) { 60481da177e4SLinus Torvalds case NFS4_READW_LT: 604976d348faSJeff Layton if (nfsd4_has_session(cstate)) 605076d348faSJeff Layton fl_flags |= FL_SLEEP; 605176d348faSJeff Layton /* Fallthrough */ 605276d348faSJeff Layton case NFS4_READ_LT: 60537214e860SJeff Layton spin_lock(&fp->fi_lock); 60547214e860SJeff Layton filp = find_readable_file_locked(fp); 60550997b173SJ. Bruce Fields if (filp) 60560997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 60577214e860SJeff Layton spin_unlock(&fp->fi_lock); 605876d348faSJeff Layton fl_type = F_RDLCK; 60591da177e4SLinus Torvalds break; 60601da177e4SLinus Torvalds case NFS4_WRITEW_LT: 606176d348faSJeff Layton if (nfsd4_has_session(cstate)) 606276d348faSJeff Layton fl_flags |= FL_SLEEP; 606376d348faSJeff Layton /* Fallthrough */ 606476d348faSJeff Layton case NFS4_WRITE_LT: 60657214e860SJeff Layton spin_lock(&fp->fi_lock); 60667214e860SJeff Layton filp = find_writeable_file_locked(fp); 60670997b173SJ. Bruce Fields if (filp) 60680997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 60697214e860SJeff Layton spin_unlock(&fp->fi_lock); 607076d348faSJeff Layton fl_type = F_WRLCK; 60711da177e4SLinus Torvalds break; 60721da177e4SLinus Torvalds default: 60731da177e4SLinus Torvalds status = nfserr_inval; 60741da177e4SLinus Torvalds goto out; 60751da177e4SLinus Torvalds } 607676d348faSJeff Layton 6077f9d7562fSJ. Bruce Fields if (!filp) { 6078f9d7562fSJ. Bruce Fields status = nfserr_openmode; 6079f9d7562fSJ. Bruce Fields goto out; 6080f9d7562fSJ. Bruce Fields } 6081aef9583bSKinglong Mee 608276d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 608376d348faSJeff Layton if (!nbl) { 608476d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 608576d348faSJeff Layton status = nfserr_jukebox; 608676d348faSJeff Layton goto out; 608776d348faSJeff Layton } 608876d348faSJeff Layton 608976d348faSJeff Layton file_lock = &nbl->nbl_lock; 609076d348faSJeff Layton file_lock->fl_type = fl_type; 6091aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 609221179d81SJeff Layton file_lock->fl_pid = current->tgid; 609321179d81SJeff Layton file_lock->fl_file = filp; 609476d348faSJeff Layton file_lock->fl_flags = fl_flags; 609521179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 609621179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 609721179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 609821179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 60991da177e4SLinus Torvalds 610021179d81SJeff Layton conflock = locks_alloc_lock(); 610121179d81SJeff Layton if (!conflock) { 610221179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 610321179d81SJeff Layton status = nfserr_jukebox; 610421179d81SJeff Layton goto out; 610521179d81SJeff Layton } 61061da177e4SLinus Torvalds 610776d348faSJeff Layton if (fl_flags & FL_SLEEP) { 61087919d0a2SJeff Layton nbl->nbl_time = jiffies; 61090cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 611076d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 61117919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 61120cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 611376d348faSJeff Layton } 611476d348faSJeff Layton 611521179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); 611676d348faSJeff Layton switch (err) { 61171da177e4SLinus Torvalds case 0: /* success! */ 61189767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 6119b8dd7b9aSAl Viro status = 0; 612003f318caSJ. Bruce Fields if (lock->lk_reclaim) 612103f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 6122eb76b3fdSAndy Adamson break; 612376d348faSJeff Layton case FILE_LOCK_DEFERRED: 612476d348faSJeff Layton nbl = NULL; 612576d348faSJeff Layton /* Fallthrough */ 612676d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 6127eb76b3fdSAndy Adamson status = nfserr_denied; 6128eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 612921179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 6130eb76b3fdSAndy Adamson break; 613176d348faSJeff Layton case -EDEADLK: 61321da177e4SLinus Torvalds status = nfserr_deadlock; 6133eb76b3fdSAndy Adamson break; 61341da177e4SLinus Torvalds default: 6135fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 61363e772463SJ. Bruce Fields status = nfserrno(err); 6137eb76b3fdSAndy Adamson break; 61381da177e4SLinus Torvalds } 61391da177e4SLinus Torvalds out: 614076d348faSJeff Layton if (nbl) { 614176d348faSJeff Layton /* dequeue it if we queued it before */ 614276d348faSJeff Layton if (fl_flags & FL_SLEEP) { 61430cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 614476d348faSJeff Layton list_del_init(&nbl->nbl_list); 61457919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 61460cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 614776d348faSJeff Layton } 614876d348faSJeff Layton free_blocked_lock(nbl); 614976d348faSJeff Layton } 6150de18643dSTrond Myklebust if (filp) 6151de18643dSTrond Myklebust fput(filp); 61525db1c03fSJeff Layton if (lock_stp) { 61535db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 61545db1c03fSJeff Layton if (cstate->replay_owner && 61555db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 61565db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 61575db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 61585db1c03fSJeff Layton 61595db1c03fSJeff Layton /* 61605db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 61615db1c03fSJeff Layton * returning an error, then just go ahead and release it. 61625db1c03fSJeff Layton */ 616325020720SJ. Bruce Fields if (status && new) 61645db1c03fSJeff Layton release_lock_stateid(lock_stp); 6165beeca19cSTrond Myklebust 6166beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 61675db1c03fSJeff Layton 61683d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 61695db1c03fSJeff Layton } 61700667b1e9STrond Myklebust if (open_stp) 61710667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 61729411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 617321179d81SJeff Layton if (conflock) 617421179d81SJeff Layton locks_free_lock(conflock); 61751da177e4SLinus Torvalds return status; 61761da177e4SLinus Torvalds } 61771da177e4SLinus Torvalds 61781da177e4SLinus Torvalds /* 617955ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 618055ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 618155ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 618255ef1274SJ. Bruce Fields * inode operation.) 618355ef1274SJ. Bruce Fields */ 618404da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 618555ef1274SJ. Bruce Fields { 618655ef1274SJ. Bruce Fields struct file *file; 618704da6e9dSAl Viro __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 618804da6e9dSAl Viro if (!err) { 618904da6e9dSAl Viro err = nfserrno(vfs_test_lock(file, lock)); 6190fd891454SChristoph Hellwig fput(file); 619104da6e9dSAl Viro } 619255ef1274SJ. Bruce Fields return err; 619355ef1274SJ. Bruce Fields } 619455ef1274SJ. Bruce Fields 619555ef1274SJ. Bruce Fields /* 61961da177e4SLinus Torvalds * LOCKT operation 61971da177e4SLinus Torvalds */ 6198b37ad28bSAl Viro __be32 6199ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6200eb69853dSChristoph Hellwig union nfsd4_op_u *u) 62011da177e4SLinus Torvalds { 6202eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 620321179d81SJeff Layton struct file_lock *file_lock = NULL; 62045db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 6205b37ad28bSAl Viro __be32 status; 62067f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 62071da177e4SLinus Torvalds 62085ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 62091da177e4SLinus Torvalds return nfserr_grace; 62101da177e4SLinus Torvalds 62111da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 62121da177e4SLinus Torvalds return nfserr_inval; 62131da177e4SLinus Torvalds 62149b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 62154b24ca7dSJeff Layton status = lookup_clientid(&lockt->lt_clientid, cstate, nn); 62169b2ef62bSJ. Bruce Fields if (status) 62171da177e4SLinus Torvalds goto out; 62189b2ef62bSJ. Bruce Fields } 62191da177e4SLinus Torvalds 622075c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 62211da177e4SLinus Torvalds goto out; 62221da177e4SLinus Torvalds 622321179d81SJeff Layton file_lock = locks_alloc_lock(); 622421179d81SJeff Layton if (!file_lock) { 622521179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 622621179d81SJeff Layton status = nfserr_jukebox; 622721179d81SJeff Layton goto out; 622821179d81SJeff Layton } 62296cd90662SKinglong Mee 62301da177e4SLinus Torvalds switch (lockt->lt_type) { 62311da177e4SLinus Torvalds case NFS4_READ_LT: 62321da177e4SLinus Torvalds case NFS4_READW_LT: 623321179d81SJeff Layton file_lock->fl_type = F_RDLCK; 62341da177e4SLinus Torvalds break; 62351da177e4SLinus Torvalds case NFS4_WRITE_LT: 62361da177e4SLinus Torvalds case NFS4_WRITEW_LT: 623721179d81SJeff Layton file_lock->fl_type = F_WRLCK; 62381da177e4SLinus Torvalds break; 62391da177e4SLinus Torvalds default: 62402fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 62411da177e4SLinus Torvalds status = nfserr_inval; 62421da177e4SLinus Torvalds goto out; 62431da177e4SLinus Torvalds } 62441da177e4SLinus Torvalds 6245c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 6246fe0750e5SJ. Bruce Fields if (lo) 624721179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 624821179d81SJeff Layton file_lock->fl_pid = current->tgid; 624921179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 62501da177e4SLinus Torvalds 625121179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 625221179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 62531da177e4SLinus Torvalds 625421179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 62551da177e4SLinus Torvalds 625621179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 625704da6e9dSAl Viro if (status) 6258fd85b817SMarc Eshel goto out; 625904da6e9dSAl Viro 626021179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 62611da177e4SLinus Torvalds status = nfserr_denied; 626221179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 62631da177e4SLinus Torvalds } 62641da177e4SLinus Torvalds out: 62655db1c03fSJeff Layton if (lo) 62665db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 626721179d81SJeff Layton if (file_lock) 626821179d81SJeff Layton locks_free_lock(file_lock); 62691da177e4SLinus Torvalds return status; 62701da177e4SLinus Torvalds } 62711da177e4SLinus Torvalds 6272b37ad28bSAl Viro __be32 6273ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6274eb69853dSChristoph Hellwig union nfsd4_op_u *u) 62751da177e4SLinus Torvalds { 6276eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 6277dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 62781da177e4SLinus Torvalds struct file *filp = NULL; 627921179d81SJeff Layton struct file_lock *file_lock = NULL; 6280b37ad28bSAl Viro __be32 status; 6281b8dd7b9aSAl Viro int err; 62823320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 62831da177e4SLinus Torvalds 62841da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 62851da177e4SLinus Torvalds (long long) locku->lu_offset, 62861da177e4SLinus Torvalds (long long) locku->lu_length); 62871da177e4SLinus Torvalds 62881da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 62891da177e4SLinus Torvalds return nfserr_inval; 62901da177e4SLinus Torvalds 62919072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 62923320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 62933320fef1SStanislav Kinsbursky &stp, nn); 62949072d5c6SJ. Bruce Fields if (status) 62951da177e4SLinus Torvalds goto out; 629611b9164aSTrond Myklebust filp = find_any_file(stp->st_stid.sc_file); 6297f9d7562fSJ. Bruce Fields if (!filp) { 6298f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 6299858cc573STrond Myklebust goto put_stateid; 6300f9d7562fSJ. Bruce Fields } 630121179d81SJeff Layton file_lock = locks_alloc_lock(); 630221179d81SJeff Layton if (!file_lock) { 630321179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 630421179d81SJeff Layton status = nfserr_jukebox; 6305de18643dSTrond Myklebust goto fput; 630621179d81SJeff Layton } 63076cd90662SKinglong Mee 630821179d81SJeff Layton file_lock->fl_type = F_UNLCK; 6309aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 631021179d81SJeff Layton file_lock->fl_pid = current->tgid; 631121179d81SJeff Layton file_lock->fl_file = filp; 631221179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 631321179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 631421179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 63151da177e4SLinus Torvalds 631621179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 631721179d81SJeff Layton locku->lu_length); 631821179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 63191da177e4SLinus Torvalds 632021179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); 6321b8dd7b9aSAl Viro if (err) { 6322fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 63231da177e4SLinus Torvalds goto out_nfserr; 63241da177e4SLinus Torvalds } 63259767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 6326de18643dSTrond Myklebust fput: 6327de18643dSTrond Myklebust fput(filp); 6328858cc573STrond Myklebust put_stateid: 6329feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6330858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 63311da177e4SLinus Torvalds out: 63329411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 633321179d81SJeff Layton if (file_lock) 633421179d81SJeff Layton locks_free_lock(file_lock); 63351da177e4SLinus Torvalds return status; 63361da177e4SLinus Torvalds 63371da177e4SLinus Torvalds out_nfserr: 6338b8dd7b9aSAl Viro status = nfserrno(err); 6339de18643dSTrond Myklebust goto fput; 63401da177e4SLinus Torvalds } 63411da177e4SLinus Torvalds 63421da177e4SLinus Torvalds /* 63431da177e4SLinus Torvalds * returns 6344f9c00c3aSJeff Layton * true: locks held by lockowner 6345f9c00c3aSJeff Layton * false: no locks held by lockowner 63461da177e4SLinus Torvalds */ 6347f9c00c3aSJeff Layton static bool 6348f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 63491da177e4SLinus Torvalds { 6350bd61e0a9SJeff Layton struct file_lock *fl; 6351f9c00c3aSJeff Layton int status = false; 6352f9c00c3aSJeff Layton struct file *filp = find_any_file(fp); 6353f9c00c3aSJeff Layton struct inode *inode; 6354bd61e0a9SJeff Layton struct file_lock_context *flctx; 6355f9c00c3aSJeff Layton 6356f9c00c3aSJeff Layton if (!filp) { 6357f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 6358f9c00c3aSJeff Layton WARN_ON_ONCE(1); 6359f9c00c3aSJeff Layton return status; 6360f9c00c3aSJeff Layton } 6361f9c00c3aSJeff Layton 636264bed6cbSAmir Goldstein inode = locks_inode(filp); 6363bd61e0a9SJeff Layton flctx = inode->i_flctx; 63641da177e4SLinus Torvalds 6365bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 63666109c850SJeff Layton spin_lock(&flctx->flc_lock); 6367bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 6368bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 6369f9c00c3aSJeff Layton status = true; 6370f9c00c3aSJeff Layton break; 63711da177e4SLinus Torvalds } 6372796dadfdSJ. Bruce Fields } 63736109c850SJeff Layton spin_unlock(&flctx->flc_lock); 6374bd61e0a9SJeff Layton } 6375f9c00c3aSJeff Layton fput(filp); 63761da177e4SLinus Torvalds return status; 63771da177e4SLinus Torvalds } 63781da177e4SLinus Torvalds 6379b37ad28bSAl Viro __be32 6380b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 6381b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 6382eb69853dSChristoph Hellwig union nfsd4_op_u *u) 63831da177e4SLinus Torvalds { 6384eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 63851da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 6386882e9d25SJeff Layton struct nfs4_stateowner *sop; 6387882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 6388dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 63891da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 6390d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 6391b37ad28bSAl Viro __be32 status; 63927f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 6393c58c6610STrond Myklebust struct nfs4_client *clp; 639488584818SChuck Lever LIST_HEAD (reaplist); 63951da177e4SLinus Torvalds 63961da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 63971da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 63981da177e4SLinus Torvalds 63994b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 64009b2ef62bSJ. Bruce Fields if (status) 640151f5e783STrond Myklebust return status; 64029b2ef62bSJ. Bruce Fields 6403d4f0489fSTrond Myklebust clp = cstate->clp; 6404fd44907cSJeff Layton /* Find the matching lock stateowner */ 6405d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6406882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 6407d4f0489fSTrond Myklebust so_strhash) { 6408882e9d25SJeff Layton 6409882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 641016bfdaafSJ. Bruce Fields continue; 6411882e9d25SJeff Layton 6412882e9d25SJeff Layton /* see if there are still any locks associated with it */ 6413882e9d25SJeff Layton lo = lockowner(sop); 6414882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 6415882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 6416882e9d25SJeff Layton status = nfserr_locks_held; 6417882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 641851f5e783STrond Myklebust return status; 6419882e9d25SJeff Layton } 6420882e9d25SJeff Layton } 6421882e9d25SJeff Layton 6422b5971afaSKinglong Mee nfs4_get_stateowner(sop); 6423fd44907cSJeff Layton break; 6424fd44907cSJeff Layton } 642588584818SChuck Lever if (!lo) { 6426d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 642788584818SChuck Lever return status; 642888584818SChuck Lever } 642988584818SChuck Lever 643088584818SChuck Lever unhash_lockowner_locked(lo); 643188584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 643288584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 643388584818SChuck Lever struct nfs4_ol_stateid, 643488584818SChuck Lever st_perstateowner); 643588584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 643688584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 643788584818SChuck Lever } 643888584818SChuck Lever spin_unlock(&clp->cl_lock); 643988584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 644068ef3bc3SJeff Layton remove_blocked_locks(lo); 644188584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 644288584818SChuck Lever 64431da177e4SLinus Torvalds return status; 64441da177e4SLinus Torvalds } 64451da177e4SLinus Torvalds 64461da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 6447a55370a3SNeilBrown alloc_reclaim(void) 64481da177e4SLinus Torvalds { 6449a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 64501da177e4SLinus Torvalds } 64511da177e4SLinus Torvalds 64520ce0c2b5SJeff Layton bool 645352e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 6454c7b9a459SNeilBrown { 64550ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 6456c7b9a459SNeilBrown 645752e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 64580ce0c2b5SJeff Layton return (crp && crp->cr_clp); 6459c7b9a459SNeilBrown } 6460c7b9a459SNeilBrown 64611da177e4SLinus Torvalds /* 64621da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 64631da177e4SLinus Torvalds */ 6464772a9bbbSJeff Layton struct nfs4_client_reclaim * 646552e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 64661da177e4SLinus Torvalds { 64671da177e4SLinus Torvalds unsigned int strhashval; 6468772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 64691da177e4SLinus Torvalds 6470a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 6471a55370a3SNeilBrown crp = alloc_reclaim(); 6472772a9bbbSJeff Layton if (crp) { 6473a55370a3SNeilBrown strhashval = clientstr_hashval(name); 64741da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 647552e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 6476a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 64770ce0c2b5SJeff Layton crp->cr_clp = NULL; 647852e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 6479772a9bbbSJeff Layton } 6480772a9bbbSJeff Layton return crp; 64811da177e4SLinus Torvalds } 64821da177e4SLinus Torvalds 64832a4317c5SJeff Layton void 648452e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 6485ce30e539SJeff Layton { 6486ce30e539SJeff Layton list_del(&crp->cr_strhash); 6487ce30e539SJeff Layton kfree(crp); 648852e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 6489ce30e539SJeff Layton } 6490ce30e539SJeff Layton 6491ce30e539SJeff Layton void 649252e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 64931da177e4SLinus Torvalds { 64941da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 64951da177e4SLinus Torvalds int i; 64961da177e4SLinus Torvalds 64971da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 649852e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 649952e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 65001da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 650152e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 65021da177e4SLinus Torvalds } 65031da177e4SLinus Torvalds } 6504063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 65051da177e4SLinus Torvalds } 65061da177e4SLinus Torvalds 65071da177e4SLinus Torvalds /* 65081da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 65092a4317c5SJeff Layton struct nfs4_client_reclaim * 651052e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 65111da177e4SLinus Torvalds { 65121da177e4SLinus Torvalds unsigned int strhashval; 65131da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 65141da177e4SLinus Torvalds 6515278c931cSJeff Layton dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 65161da177e4SLinus Torvalds 6517278c931cSJeff Layton strhashval = clientstr_hashval(recdir); 651852e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 6519278c931cSJeff Layton if (same_name(crp->cr_recdir, recdir)) { 65201da177e4SLinus Torvalds return crp; 65211da177e4SLinus Torvalds } 65221da177e4SLinus Torvalds } 65231da177e4SLinus Torvalds return NULL; 65241da177e4SLinus Torvalds } 65251da177e4SLinus Torvalds 65261da177e4SLinus Torvalds /* 65271da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 65281da177e4SLinus Torvalds */ 6529b37ad28bSAl Viro __be32 65300fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 65310fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 65320fe492dbSTrond Myklebust struct nfsd_net *nn) 65331da177e4SLinus Torvalds { 65340fe492dbSTrond Myklebust __be32 status; 6535a52d726bSJeff Layton 6536a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 65370fe492dbSTrond Myklebust status = lookup_clientid(clid, cstate, nn); 65380fe492dbSTrond Myklebust if (status) 6539a52d726bSJeff Layton return nfserr_reclaim_bad; 6540a52d726bSJeff Layton 65413b3e7b72SJeff Layton if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) 65423b3e7b72SJeff Layton return nfserr_no_grace; 65433b3e7b72SJeff Layton 65440fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 65450fe492dbSTrond Myklebust return nfserr_reclaim_bad; 65460fe492dbSTrond Myklebust 65470fe492dbSTrond Myklebust return nfs_ok; 65481da177e4SLinus Torvalds } 65491da177e4SLinus Torvalds 655065178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 6551016200c3SJeff Layton static inline void 6552016200c3SJeff Layton put_client(struct nfs4_client *clp) 6553016200c3SJeff Layton { 6554016200c3SJeff Layton atomic_dec(&clp->cl_refcount); 6555016200c3SJeff Layton } 6556016200c3SJeff Layton 6557285abdeeSJeff Layton static struct nfs4_client * 6558285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 6559285abdeeSJeff Layton { 6560285abdeeSJeff Layton struct nfs4_client *clp; 6561285abdeeSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6562285abdeeSJeff Layton nfsd_net_id); 6563285abdeeSJeff Layton 6564285abdeeSJeff Layton if (!nfsd_netns_ready(nn)) 6565285abdeeSJeff Layton return NULL; 6566285abdeeSJeff Layton 6567285abdeeSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 6568285abdeeSJeff Layton if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 6569285abdeeSJeff Layton return clp; 6570285abdeeSJeff Layton } 6571285abdeeSJeff Layton return NULL; 6572285abdeeSJeff Layton } 6573285abdeeSJeff Layton 65747ec0e36fSJeff Layton u64 6575285abdeeSJeff Layton nfsd_inject_print_clients(void) 65767ec0e36fSJeff Layton { 65777ec0e36fSJeff Layton struct nfs4_client *clp; 65787ec0e36fSJeff Layton u64 count = 0; 65797ec0e36fSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 65807ec0e36fSJeff Layton nfsd_net_id); 65817ec0e36fSJeff Layton char buf[INET6_ADDRSTRLEN]; 65827ec0e36fSJeff Layton 65837ec0e36fSJeff Layton if (!nfsd_netns_ready(nn)) 65847ec0e36fSJeff Layton return 0; 65857ec0e36fSJeff Layton 65867ec0e36fSJeff Layton spin_lock(&nn->client_lock); 65877ec0e36fSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 65887ec0e36fSJeff Layton rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 65897ec0e36fSJeff Layton pr_info("NFS Client: %s\n", buf); 65907ec0e36fSJeff Layton ++count; 65917ec0e36fSJeff Layton } 65927ec0e36fSJeff Layton spin_unlock(&nn->client_lock); 65937ec0e36fSJeff Layton 65947ec0e36fSJeff Layton return count; 65957ec0e36fSJeff Layton } 659665178db4SBryan Schumaker 6597a0926d15SJeff Layton u64 6598285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) 6599a0926d15SJeff Layton { 6600a0926d15SJeff Layton u64 count = 0; 6601a0926d15SJeff Layton struct nfs4_client *clp; 6602a0926d15SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6603a0926d15SJeff Layton nfsd_net_id); 6604a0926d15SJeff Layton 6605a0926d15SJeff Layton if (!nfsd_netns_ready(nn)) 6606a0926d15SJeff Layton return count; 6607a0926d15SJeff Layton 6608a0926d15SJeff Layton spin_lock(&nn->client_lock); 6609a0926d15SJeff Layton clp = nfsd_find_client(addr, addr_size); 6610a0926d15SJeff Layton if (clp) { 6611a0926d15SJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) 6612a0926d15SJeff Layton ++count; 6613a0926d15SJeff Layton else 6614a0926d15SJeff Layton clp = NULL; 6615a0926d15SJeff Layton } 6616a0926d15SJeff Layton spin_unlock(&nn->client_lock); 6617a0926d15SJeff Layton 6618a0926d15SJeff Layton if (clp) 6619a0926d15SJeff Layton expire_client(clp); 6620a0926d15SJeff Layton 6621a0926d15SJeff Layton return count; 6622a0926d15SJeff Layton } 6623a0926d15SJeff Layton 662469fc9edfSJeff Layton u64 6625285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max) 662669fc9edfSJeff Layton { 662769fc9edfSJeff Layton u64 count = 0; 662869fc9edfSJeff Layton struct nfs4_client *clp, *next; 662969fc9edfSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 663069fc9edfSJeff Layton nfsd_net_id); 663169fc9edfSJeff Layton LIST_HEAD(reaplist); 663269fc9edfSJeff Layton 663369fc9edfSJeff Layton if (!nfsd_netns_ready(nn)) 663469fc9edfSJeff Layton return count; 663569fc9edfSJeff Layton 663669fc9edfSJeff Layton spin_lock(&nn->client_lock); 663769fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 663869fc9edfSJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) { 663969fc9edfSJeff Layton list_add(&clp->cl_lru, &reaplist); 664069fc9edfSJeff Layton if (max != 0 && ++count >= max) 664169fc9edfSJeff Layton break; 664269fc9edfSJeff Layton } 664369fc9edfSJeff Layton } 664469fc9edfSJeff Layton spin_unlock(&nn->client_lock); 664569fc9edfSJeff Layton 664669fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &reaplist, cl_lru) 664769fc9edfSJeff Layton expire_client(clp); 664869fc9edfSJeff Layton 664969fc9edfSJeff Layton return count; 665069fc9edfSJeff Layton } 665169fc9edfSJeff Layton 6652184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 6653184c1847SBryan Schumaker const char *type) 6654184c1847SBryan Schumaker { 6655184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 66560a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 6657184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 6658184c1847SBryan Schumaker } 6659184c1847SBryan Schumaker 6660016200c3SJeff Layton static void 6661016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, 6662016200c3SJeff Layton struct list_head *collect) 6663016200c3SJeff Layton { 6664016200c3SJeff Layton struct nfs4_client *clp = lst->st_stid.sc_client; 6665016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6666016200c3SJeff Layton nfsd_net_id); 6667016200c3SJeff Layton 6668016200c3SJeff Layton if (!collect) 6669016200c3SJeff Layton return; 6670016200c3SJeff Layton 6671016200c3SJeff Layton lockdep_assert_held(&nn->client_lock); 6672016200c3SJeff Layton atomic_inc(&clp->cl_refcount); 6673016200c3SJeff Layton list_add(&lst->st_locks, collect); 6674016200c3SJeff Layton } 6675016200c3SJeff Layton 66763c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 66773738d50eSJeff Layton struct list_head *collect, 6678e8568739SJeff Layton bool (*func)(struct nfs4_ol_stateid *)) 6679fc29171fSBryan Schumaker { 6680fc29171fSBryan Schumaker struct nfs4_openowner *oop; 6681fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 66823c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 6683fc29171fSBryan Schumaker u64 count = 0; 6684fc29171fSBryan Schumaker 6685016200c3SJeff Layton spin_lock(&clp->cl_lock); 6686fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 66873c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 66883c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 66893c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 66903c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 66913738d50eSJeff Layton if (func) { 6692e8568739SJeff Layton if (func(lst)) 6693016200c3SJeff Layton nfsd_inject_add_lock_to_list(lst, 66943738d50eSJeff Layton collect); 66953738d50eSJeff Layton } 6696016200c3SJeff Layton ++count; 6697016200c3SJeff Layton /* 6698016200c3SJeff Layton * Despite the fact that these functions deal 6699016200c3SJeff Layton * with 64-bit integers for "count", we must 6700016200c3SJeff Layton * ensure that it doesn't blow up the 6701016200c3SJeff Layton * clp->cl_refcount. Throw a warning if we 6702016200c3SJeff Layton * start to approach INT_MAX here. 6703016200c3SJeff Layton */ 6704016200c3SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 6705016200c3SJeff Layton if (count == max) 6706016200c3SJeff Layton goto out; 6707fc29171fSBryan Schumaker } 6708fc29171fSBryan Schumaker } 6709fc29171fSBryan Schumaker } 6710016200c3SJeff Layton out: 6711016200c3SJeff Layton spin_unlock(&clp->cl_lock); 6712fc29171fSBryan Schumaker 6713fc29171fSBryan Schumaker return count; 6714fc29171fSBryan Schumaker } 6715fc29171fSBryan Schumaker 6716016200c3SJeff Layton static u64 6717016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, 6718016200c3SJeff Layton u64 max) 6719fc29171fSBryan Schumaker { 6720016200c3SJeff Layton return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); 6721fc29171fSBryan Schumaker } 6722fc29171fSBryan Schumaker 6723016200c3SJeff Layton static u64 6724016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp) 6725184c1847SBryan Schumaker { 6726016200c3SJeff Layton u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); 6727184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 6728184c1847SBryan Schumaker return count; 6729184c1847SBryan Schumaker } 6730184c1847SBryan Schumaker 6731016200c3SJeff Layton u64 6732285abdeeSJeff Layton nfsd_inject_print_locks(void) 6733016200c3SJeff Layton { 6734016200c3SJeff Layton struct nfs4_client *clp; 6735016200c3SJeff Layton u64 count = 0; 6736016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6737016200c3SJeff Layton nfsd_net_id); 6738016200c3SJeff Layton 6739016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6740016200c3SJeff Layton return 0; 6741016200c3SJeff Layton 6742016200c3SJeff Layton spin_lock(&nn->client_lock); 6743016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 6744016200c3SJeff Layton count += nfsd_print_client_locks(clp); 6745016200c3SJeff Layton spin_unlock(&nn->client_lock); 6746016200c3SJeff Layton 6747016200c3SJeff Layton return count; 6748016200c3SJeff Layton } 6749016200c3SJeff Layton 6750016200c3SJeff Layton static void 6751016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist) 6752016200c3SJeff Layton { 6753016200c3SJeff Layton struct nfs4_client *clp; 6754016200c3SJeff Layton struct nfs4_ol_stateid *stp, *next; 6755016200c3SJeff Layton 6756016200c3SJeff Layton list_for_each_entry_safe(stp, next, reaplist, st_locks) { 6757016200c3SJeff Layton list_del_init(&stp->st_locks); 6758016200c3SJeff Layton clp = stp->st_stid.sc_client; 6759016200c3SJeff Layton nfs4_put_stid(&stp->st_stid); 6760016200c3SJeff Layton put_client(clp); 6761016200c3SJeff Layton } 6762016200c3SJeff Layton } 6763016200c3SJeff Layton 6764016200c3SJeff Layton u64 6765285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) 6766016200c3SJeff Layton { 6767016200c3SJeff Layton unsigned int count = 0; 6768016200c3SJeff Layton struct nfs4_client *clp; 6769016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6770016200c3SJeff Layton nfsd_net_id); 6771016200c3SJeff Layton LIST_HEAD(reaplist); 6772016200c3SJeff Layton 6773016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6774016200c3SJeff Layton return count; 6775016200c3SJeff Layton 6776016200c3SJeff Layton spin_lock(&nn->client_lock); 6777016200c3SJeff Layton clp = nfsd_find_client(addr, addr_size); 6778016200c3SJeff Layton if (clp) 6779016200c3SJeff Layton count = nfsd_collect_client_locks(clp, &reaplist, 0); 6780016200c3SJeff Layton spin_unlock(&nn->client_lock); 6781016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6782016200c3SJeff Layton return count; 6783016200c3SJeff Layton } 6784016200c3SJeff Layton 6785016200c3SJeff Layton u64 6786285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max) 6787016200c3SJeff Layton { 6788016200c3SJeff Layton u64 count = 0; 6789016200c3SJeff Layton struct nfs4_client *clp; 6790016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6791016200c3SJeff Layton nfsd_net_id); 6792016200c3SJeff Layton LIST_HEAD(reaplist); 6793016200c3SJeff Layton 6794016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6795016200c3SJeff Layton return count; 6796016200c3SJeff Layton 6797016200c3SJeff Layton spin_lock(&nn->client_lock); 6798016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 6799016200c3SJeff Layton count += nfsd_collect_client_locks(clp, &reaplist, max - count); 6800016200c3SJeff Layton if (max != 0 && count >= max) 6801016200c3SJeff Layton break; 6802016200c3SJeff Layton } 6803016200c3SJeff Layton spin_unlock(&nn->client_lock); 6804016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6805016200c3SJeff Layton return count; 6806016200c3SJeff Layton } 6807016200c3SJeff Layton 680882e05efaSJeff Layton static u64 680982e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, 681082e05efaSJeff Layton struct list_head *collect, 681182e05efaSJeff Layton void (*func)(struct nfs4_openowner *)) 68124dbdbda8SBryan Schumaker { 68134dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 681482e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 681582e05efaSJeff Layton nfsd_net_id); 68164dbdbda8SBryan Schumaker u64 count = 0; 68174dbdbda8SBryan Schumaker 681882e05efaSJeff Layton lockdep_assert_held(&nn->client_lock); 681982e05efaSJeff Layton 682082e05efaSJeff Layton spin_lock(&clp->cl_lock); 68214dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 682282e05efaSJeff Layton if (func) { 68234dbdbda8SBryan Schumaker func(oop); 682482e05efaSJeff Layton if (collect) { 682582e05efaSJeff Layton atomic_inc(&clp->cl_refcount); 682682e05efaSJeff Layton list_add(&oop->oo_perclient, collect); 682782e05efaSJeff Layton } 682882e05efaSJeff Layton } 682982e05efaSJeff Layton ++count; 683082e05efaSJeff Layton /* 683182e05efaSJeff Layton * Despite the fact that these functions deal with 683282e05efaSJeff Layton * 64-bit integers for "count", we must ensure that 683382e05efaSJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 683482e05efaSJeff Layton * warning if we start to approach INT_MAX here. 683582e05efaSJeff Layton */ 683682e05efaSJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 683782e05efaSJeff Layton if (count == max) 68384dbdbda8SBryan Schumaker break; 68394dbdbda8SBryan Schumaker } 684082e05efaSJeff Layton spin_unlock(&clp->cl_lock); 68414dbdbda8SBryan Schumaker 68424dbdbda8SBryan Schumaker return count; 68434dbdbda8SBryan Schumaker } 68444dbdbda8SBryan Schumaker 684582e05efaSJeff Layton static u64 684682e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp) 68474dbdbda8SBryan Schumaker { 684882e05efaSJeff Layton u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); 684982e05efaSJeff Layton 685082e05efaSJeff Layton nfsd_print_count(clp, count, "openowners"); 685182e05efaSJeff Layton return count; 68524dbdbda8SBryan Schumaker } 68534dbdbda8SBryan Schumaker 685482e05efaSJeff Layton static u64 685582e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp, 685682e05efaSJeff Layton struct list_head *collect, u64 max) 6857184c1847SBryan Schumaker { 685882e05efaSJeff Layton return nfsd_foreach_client_openowner(clp, max, collect, 685982e05efaSJeff Layton unhash_openowner_locked); 686082e05efaSJeff Layton } 686182e05efaSJeff Layton 686282e05efaSJeff Layton u64 6863285abdeeSJeff Layton nfsd_inject_print_openowners(void) 686482e05efaSJeff Layton { 686582e05efaSJeff Layton struct nfs4_client *clp; 686682e05efaSJeff Layton u64 count = 0; 686782e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 686882e05efaSJeff Layton nfsd_net_id); 686982e05efaSJeff Layton 687082e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 687182e05efaSJeff Layton return 0; 687282e05efaSJeff Layton 687382e05efaSJeff Layton spin_lock(&nn->client_lock); 687482e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 687582e05efaSJeff Layton count += nfsd_print_client_openowners(clp); 687682e05efaSJeff Layton spin_unlock(&nn->client_lock); 687782e05efaSJeff Layton 687882e05efaSJeff Layton return count; 687982e05efaSJeff Layton } 688082e05efaSJeff Layton 688182e05efaSJeff Layton static void 688282e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist) 688382e05efaSJeff Layton { 688482e05efaSJeff Layton struct nfs4_client *clp; 688582e05efaSJeff Layton struct nfs4_openowner *oop, *next; 688682e05efaSJeff Layton 688782e05efaSJeff Layton list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { 688882e05efaSJeff Layton list_del_init(&oop->oo_perclient); 688982e05efaSJeff Layton clp = oop->oo_owner.so_client; 689082e05efaSJeff Layton release_openowner(oop); 689182e05efaSJeff Layton put_client(clp); 689282e05efaSJeff Layton } 689382e05efaSJeff Layton } 689482e05efaSJeff Layton 689582e05efaSJeff Layton u64 6896285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, 6897285abdeeSJeff Layton size_t addr_size) 689882e05efaSJeff Layton { 689982e05efaSJeff Layton unsigned int count = 0; 690082e05efaSJeff Layton struct nfs4_client *clp; 690182e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 690282e05efaSJeff Layton nfsd_net_id); 690382e05efaSJeff Layton LIST_HEAD(reaplist); 690482e05efaSJeff Layton 690582e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 690682e05efaSJeff Layton return count; 690782e05efaSJeff Layton 690882e05efaSJeff Layton spin_lock(&nn->client_lock); 690982e05efaSJeff Layton clp = nfsd_find_client(addr, addr_size); 691082e05efaSJeff Layton if (clp) 691182e05efaSJeff Layton count = nfsd_collect_client_openowners(clp, &reaplist, 0); 691282e05efaSJeff Layton spin_unlock(&nn->client_lock); 691382e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 691482e05efaSJeff Layton return count; 691582e05efaSJeff Layton } 691682e05efaSJeff Layton 691782e05efaSJeff Layton u64 6918285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max) 691982e05efaSJeff Layton { 692082e05efaSJeff Layton u64 count = 0; 692182e05efaSJeff Layton struct nfs4_client *clp; 692282e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 692382e05efaSJeff Layton nfsd_net_id); 692482e05efaSJeff Layton LIST_HEAD(reaplist); 692582e05efaSJeff Layton 692682e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 692782e05efaSJeff Layton return count; 692882e05efaSJeff Layton 692982e05efaSJeff Layton spin_lock(&nn->client_lock); 693082e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 693182e05efaSJeff Layton count += nfsd_collect_client_openowners(clp, &reaplist, 693282e05efaSJeff Layton max - count); 693382e05efaSJeff Layton if (max != 0 && count >= max) 693482e05efaSJeff Layton break; 693582e05efaSJeff Layton } 693682e05efaSJeff Layton spin_unlock(&nn->client_lock); 693782e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 6938184c1847SBryan Schumaker return count; 6939184c1847SBryan Schumaker } 6940184c1847SBryan Schumaker 6941269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 6942269de30fSBryan Schumaker struct list_head *victims) 6943269de30fSBryan Schumaker { 6944269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 694598d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 694698d5c7c5SJeff Layton nfsd_net_id); 6947269de30fSBryan Schumaker u64 count = 0; 6948269de30fSBryan Schumaker 694998d5c7c5SJeff Layton lockdep_assert_held(&nn->client_lock); 695098d5c7c5SJeff Layton 695198d5c7c5SJeff Layton spin_lock(&state_lock); 6952269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 6953dff1399fSJeff Layton if (victims) { 6954dff1399fSJeff Layton /* 6955dff1399fSJeff Layton * It's not safe to mess with delegations that have a 6956dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 6957dff1399fSJeff Layton * and could be processed by the laundromat outside of 6958dff1399fSJeff Layton * the state_lock. Just leave them be. 6959dff1399fSJeff Layton */ 6960dff1399fSJeff Layton if (dp->dl_time != 0) 6961dff1399fSJeff Layton continue; 6962dff1399fSJeff Layton 696398d5c7c5SJeff Layton atomic_inc(&clp->cl_refcount); 69643fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 696542690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 6966dff1399fSJeff Layton } 696798d5c7c5SJeff Layton ++count; 696898d5c7c5SJeff Layton /* 696998d5c7c5SJeff Layton * Despite the fact that these functions deal with 697098d5c7c5SJeff Layton * 64-bit integers for "count", we must ensure that 697198d5c7c5SJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 697298d5c7c5SJeff Layton * warning if we start to approach INT_MAX here. 697398d5c7c5SJeff Layton */ 697498d5c7c5SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 697598d5c7c5SJeff Layton if (count == max) 6976269de30fSBryan Schumaker break; 6977269de30fSBryan Schumaker } 697898d5c7c5SJeff Layton spin_unlock(&state_lock); 6979269de30fSBryan Schumaker return count; 6980269de30fSBryan Schumaker } 6981269de30fSBryan Schumaker 698298d5c7c5SJeff Layton static u64 698398d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp) 6984269de30fSBryan Schumaker { 698598d5c7c5SJeff Layton u64 count = nfsd_find_all_delegations(clp, 0, NULL); 6986184c1847SBryan Schumaker 6987184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 6988184c1847SBryan Schumaker return count; 6989184c1847SBryan Schumaker } 6990184c1847SBryan Schumaker 699198d5c7c5SJeff Layton u64 6992285abdeeSJeff Layton nfsd_inject_print_delegations(void) 699398d5c7c5SJeff Layton { 699498d5c7c5SJeff Layton struct nfs4_client *clp; 699598d5c7c5SJeff Layton u64 count = 0; 699698d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 699798d5c7c5SJeff Layton nfsd_net_id); 699898d5c7c5SJeff Layton 699998d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 700098d5c7c5SJeff Layton return 0; 700198d5c7c5SJeff Layton 700298d5c7c5SJeff Layton spin_lock(&nn->client_lock); 700398d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 700498d5c7c5SJeff Layton count += nfsd_print_client_delegations(clp); 700598d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 700698d5c7c5SJeff Layton 700798d5c7c5SJeff Layton return count; 700898d5c7c5SJeff Layton } 700998d5c7c5SJeff Layton 701098d5c7c5SJeff Layton static void 701198d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist) 701298d5c7c5SJeff Layton { 701398d5c7c5SJeff Layton struct nfs4_client *clp; 701498d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 701598d5c7c5SJeff Layton 701698d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 701798d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 701898d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 701998d5c7c5SJeff Layton revoke_delegation(dp); 702098d5c7c5SJeff Layton put_client(clp); 702198d5c7c5SJeff Layton } 702298d5c7c5SJeff Layton } 702398d5c7c5SJeff Layton 702498d5c7c5SJeff Layton u64 7025285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, 7026285abdeeSJeff Layton size_t addr_size) 702798d5c7c5SJeff Layton { 702898d5c7c5SJeff Layton u64 count = 0; 702998d5c7c5SJeff Layton struct nfs4_client *clp; 703098d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 703198d5c7c5SJeff Layton nfsd_net_id); 703298d5c7c5SJeff Layton LIST_HEAD(reaplist); 703398d5c7c5SJeff Layton 703498d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 703598d5c7c5SJeff Layton return count; 703698d5c7c5SJeff Layton 703798d5c7c5SJeff Layton spin_lock(&nn->client_lock); 703898d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 703998d5c7c5SJeff Layton if (clp) 704098d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 704198d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 704298d5c7c5SJeff Layton 704398d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 704498d5c7c5SJeff Layton return count; 704598d5c7c5SJeff Layton } 704698d5c7c5SJeff Layton 704798d5c7c5SJeff Layton u64 7048285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max) 704998d5c7c5SJeff Layton { 705098d5c7c5SJeff Layton u64 count = 0; 705198d5c7c5SJeff Layton struct nfs4_client *clp; 705298d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 705398d5c7c5SJeff Layton nfsd_net_id); 705498d5c7c5SJeff Layton LIST_HEAD(reaplist); 705598d5c7c5SJeff Layton 705698d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 705798d5c7c5SJeff Layton return count; 705898d5c7c5SJeff Layton 705998d5c7c5SJeff Layton spin_lock(&nn->client_lock); 706098d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 706198d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 706298d5c7c5SJeff Layton if (max != 0 && count >= max) 706398d5c7c5SJeff Layton break; 706498d5c7c5SJeff Layton } 706598d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 706698d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 706798d5c7c5SJeff Layton return count; 706898d5c7c5SJeff Layton } 706998d5c7c5SJeff Layton 707098d5c7c5SJeff Layton static void 707198d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist) 707298d5c7c5SJeff Layton { 707398d5c7c5SJeff Layton struct nfs4_client *clp; 707498d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 707598d5c7c5SJeff Layton 707698d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 707798d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 707898d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 707998d5c7c5SJeff Layton /* 708098d5c7c5SJeff Layton * We skipped all entries that had a zero dl_time before, 708198d5c7c5SJeff Layton * so we can now reset the dl_time back to 0. If a delegation 708298d5c7c5SJeff Layton * break comes in now, then it won't make any difference since 708398d5c7c5SJeff Layton * we're recalling it either way. 708498d5c7c5SJeff Layton */ 708598d5c7c5SJeff Layton spin_lock(&state_lock); 708698d5c7c5SJeff Layton dp->dl_time = 0; 708798d5c7c5SJeff Layton spin_unlock(&state_lock); 708898d5c7c5SJeff Layton nfsd_break_one_deleg(dp); 708998d5c7c5SJeff Layton put_client(clp); 709098d5c7c5SJeff Layton } 709198d5c7c5SJeff Layton } 709298d5c7c5SJeff Layton 709398d5c7c5SJeff Layton u64 7094285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, 709598d5c7c5SJeff Layton size_t addr_size) 709698d5c7c5SJeff Layton { 709798d5c7c5SJeff Layton u64 count = 0; 709898d5c7c5SJeff Layton struct nfs4_client *clp; 709998d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 710098d5c7c5SJeff Layton nfsd_net_id); 710198d5c7c5SJeff Layton LIST_HEAD(reaplist); 710298d5c7c5SJeff Layton 710398d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 710498d5c7c5SJeff Layton return count; 710598d5c7c5SJeff Layton 710698d5c7c5SJeff Layton spin_lock(&nn->client_lock); 710798d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 710898d5c7c5SJeff Layton if (clp) 710998d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 711098d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 711198d5c7c5SJeff Layton 711298d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 711398d5c7c5SJeff Layton return count; 711498d5c7c5SJeff Layton } 711598d5c7c5SJeff Layton 711698d5c7c5SJeff Layton u64 7117285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max) 711898d5c7c5SJeff Layton { 711998d5c7c5SJeff Layton u64 count = 0; 712098d5c7c5SJeff Layton struct nfs4_client *clp, *next; 712198d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 712298d5c7c5SJeff Layton nfsd_net_id); 712398d5c7c5SJeff Layton LIST_HEAD(reaplist); 712498d5c7c5SJeff Layton 712598d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 712698d5c7c5SJeff Layton return count; 712798d5c7c5SJeff Layton 712898d5c7c5SJeff Layton spin_lock(&nn->client_lock); 712998d5c7c5SJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 713098d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 713198d5c7c5SJeff Layton if (max != 0 && ++count >= max) 713298d5c7c5SJeff Layton break; 713398d5c7c5SJeff Layton } 713498d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 713598d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 713698d5c7c5SJeff Layton return count; 713798d5c7c5SJeff Layton } 713865178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 713965178db4SBryan Schumaker 7140c2f1a551SMeelap Shah /* 7141c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 7142c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 7143c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 7144c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 7145c2f1a551SMeelap Shah * 7146c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 7147c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 7148c2f1a551SMeelap Shah */ 7149c2f1a551SMeelap Shah static void 7150c2f1a551SMeelap Shah set_max_delegations(void) 7151c2f1a551SMeelap Shah { 7152c2f1a551SMeelap Shah /* 7153c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 7154c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 7155c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 7156c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 7157c2f1a551SMeelap Shah */ 7158c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 7159c2f1a551SMeelap Shah } 7160c2f1a551SMeelap Shah 7161d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 71628daae4dcSStanislav Kinsbursky { 71638daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 71648daae4dcSStanislav Kinsbursky int i; 71658daae4dcSStanislav Kinsbursky 71666da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 71676da2ec56SKees Cook sizeof(struct list_head), 71686da2ec56SKees Cook GFP_KERNEL); 71698daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 7170382a62e7SStanislav Kinsbursky goto err; 71716da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 71726da2ec56SKees Cook sizeof(struct list_head), 71736da2ec56SKees Cook GFP_KERNEL); 71740a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 71750a7ec377SStanislav Kinsbursky goto err_unconf_id; 71766da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 71776da2ec56SKees Cook sizeof(struct list_head), 71786da2ec56SKees Cook GFP_KERNEL); 71791872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 71801872de0eSStanislav Kinsbursky goto err_sessionid; 71818daae4dcSStanislav Kinsbursky 7182382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 71838daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 71840a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 7185382a62e7SStanislav Kinsbursky } 71861872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 71871872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 7188382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 7189a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 719081833de1SVasily Averin nn->boot_time = get_seconds(); 719181833de1SVasily Averin nn->grace_ended = false; 719281833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 719381833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 71945ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 719573758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 7196e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 7197c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 7198e0639dc5SOlga Kornievskaia spin_lock_init(&nn->s2s_cp_lock); 7199e0639dc5SOlga Kornievskaia idr_init(&nn->s2s_cp_stateids); 72008daae4dcSStanislav Kinsbursky 72010cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 72020cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 72030cc11a61SJeff Layton 720409121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 7205d85ed443SStanislav Kinsbursky get_net(net); 720609121281SStanislav Kinsbursky 72078daae4dcSStanislav Kinsbursky return 0; 7208382a62e7SStanislav Kinsbursky 72091872de0eSStanislav Kinsbursky err_sessionid: 72109b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 72110a7ec377SStanislav Kinsbursky err_unconf_id: 72120a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 7213382a62e7SStanislav Kinsbursky err: 7214382a62e7SStanislav Kinsbursky return -ENOMEM; 72158daae4dcSStanislav Kinsbursky } 72168daae4dcSStanislav Kinsbursky 72178daae4dcSStanislav Kinsbursky static void 72184dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 72198daae4dcSStanislav Kinsbursky { 72208daae4dcSStanislav Kinsbursky int i; 72218daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 72228daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 72238daae4dcSStanislav Kinsbursky 72248daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 72258daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 72268daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 72278daae4dcSStanislav Kinsbursky destroy_client(clp); 72288daae4dcSStanislav Kinsbursky } 72298daae4dcSStanislav Kinsbursky } 7230a99454aaSStanislav Kinsbursky 723168ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 723268ef3bc3SJeff Layton 72332b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 72342b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 72352b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 7236a99454aaSStanislav Kinsbursky destroy_client(clp); 7237a99454aaSStanislav Kinsbursky } 72382b905635SKinglong Mee } 7239a99454aaSStanislav Kinsbursky 72401872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 72410a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 72428daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 72434dce0ac9SStanislav Kinsbursky put_net(net); 72448daae4dcSStanislav Kinsbursky } 72458daae4dcSStanislav Kinsbursky 7246f252bc68SStanislav Kinsbursky int 7247d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 7248ac4d8ff2SNeilBrown { 72495e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 7250b5a1a81eSJ. Bruce Fields int ret; 7251b5a1a81eSJ. Bruce Fields 7252d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 72538daae4dcSStanislav Kinsbursky if (ret) 72548daae4dcSStanislav Kinsbursky return ret; 7255d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 7256d4318acdSJeff Layton nfsd4_client_tracking_init(net); 72577e981a8aSVasily Averin printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n", 72587e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 72595284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 7260d85ed443SStanislav Kinsbursky return 0; 7261a6d6b781SJeff Layton } 7262d85ed443SStanislav Kinsbursky 7263d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 7264d85ed443SStanislav Kinsbursky 7265d85ed443SStanislav Kinsbursky int 7266d85ed443SStanislav Kinsbursky nfs4_state_start(void) 7267d85ed443SStanislav Kinsbursky { 7268d85ed443SStanislav Kinsbursky int ret; 7269d85ed443SStanislav Kinsbursky 727051a54568SJeff Layton laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 7271a6d6b781SJeff Layton if (laundry_wq == NULL) { 7272a6d6b781SJeff Layton ret = -ENOMEM; 7273a26dd64fSChuck Lever goto out; 7274a6d6b781SJeff Layton } 7275b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 7276b5a1a81eSJ. Bruce Fields if (ret) 7277b5a1a81eSJ. Bruce Fields goto out_free_laundry; 727809121281SStanislav Kinsbursky 7279c2f1a551SMeelap Shah set_max_delegations(); 7280b5a1a81eSJ. Bruce Fields return 0; 7281d85ed443SStanislav Kinsbursky 7282b5a1a81eSJ. Bruce Fields out_free_laundry: 7283b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 7284a26dd64fSChuck Lever out: 7285b5a1a81eSJ. Bruce Fields return ret; 72861da177e4SLinus Torvalds } 72871da177e4SLinus Torvalds 7288f252bc68SStanislav Kinsbursky void 72894dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 72901da177e4SLinus Torvalds { 72911da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 72921da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 72934dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 72941da177e4SLinus Torvalds 72954dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 72964dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 7297ac55fdc4SJeff Layton 72981da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 7299cdc97505SBenny Halevy spin_lock(&state_lock); 7300e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 73011da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 73023fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 730342690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 73041da177e4SLinus Torvalds } 7305cdc97505SBenny Halevy spin_unlock(&state_lock); 73061da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 73071da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 730842690676SJeff Layton list_del_init(&dp->dl_recall_lru); 73090af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 73101da177e4SLinus Torvalds } 73111da177e4SLinus Torvalds 73123320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 73134dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 73141da177e4SLinus Torvalds } 73151da177e4SLinus Torvalds 73161da177e4SLinus Torvalds void 73171da177e4SLinus Torvalds nfs4_state_shutdown(void) 73181da177e4SLinus Torvalds { 73195e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 7320c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 73211da177e4SLinus Torvalds } 73228b70484cSTigran Mkrtchyan 73238b70484cSTigran Mkrtchyan static void 73248b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 73258b70484cSTigran Mkrtchyan { 732637c593c5STigran Mkrtchyan if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) 732737c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 73288b70484cSTigran Mkrtchyan } 73298b70484cSTigran Mkrtchyan 73308b70484cSTigran Mkrtchyan static void 73318b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 73328b70484cSTigran Mkrtchyan { 733337c593c5STigran Mkrtchyan if (cstate->minorversion) { 733437c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 733537c593c5STigran Mkrtchyan SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 733637c593c5STigran Mkrtchyan } 733737c593c5STigran Mkrtchyan } 733837c593c5STigran Mkrtchyan 733937c593c5STigran Mkrtchyan void 734037c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 734137c593c5STigran Mkrtchyan { 734237c593c5STigran Mkrtchyan CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 73438b70484cSTigran Mkrtchyan } 73448b70484cSTigran Mkrtchyan 734562cd4a59STigran Mkrtchyan /* 734662cd4a59STigran Mkrtchyan * functions to set current state id 734762cd4a59STigran Mkrtchyan */ 73488b70484cSTigran Mkrtchyan void 7349b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 7350b60e9859SChristoph Hellwig union nfsd4_op_u *u) 73519428fe1aSTigran Mkrtchyan { 7352b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 73539428fe1aSTigran Mkrtchyan } 73549428fe1aSTigran Mkrtchyan 73559428fe1aSTigran Mkrtchyan void 7356b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 7357b60e9859SChristoph Hellwig union nfsd4_op_u *u) 73588b70484cSTigran Mkrtchyan { 7359b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 73608b70484cSTigran Mkrtchyan } 73618b70484cSTigran Mkrtchyan 73628b70484cSTigran Mkrtchyan void 7363b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 7364b60e9859SChristoph Hellwig union nfsd4_op_u *u) 736562cd4a59STigran Mkrtchyan { 7366b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 736762cd4a59STigran Mkrtchyan } 736862cd4a59STigran Mkrtchyan 736962cd4a59STigran Mkrtchyan void 7370b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 7371b60e9859SChristoph Hellwig union nfsd4_op_u *u) 737262cd4a59STigran Mkrtchyan { 7373b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 737462cd4a59STigran Mkrtchyan } 737562cd4a59STigran Mkrtchyan 737662cd4a59STigran Mkrtchyan /* 737762cd4a59STigran Mkrtchyan * functions to consume current state id 737862cd4a59STigran Mkrtchyan */ 73791e97b519STigran Mkrtchyan 73801e97b519STigran Mkrtchyan void 738157832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 738257832e7bSChristoph Hellwig union nfsd4_op_u *u) 73839428fe1aSTigran Mkrtchyan { 738457832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 73859428fe1aSTigran Mkrtchyan } 73869428fe1aSTigran Mkrtchyan 73879428fe1aSTigran Mkrtchyan void 738857832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 738957832e7bSChristoph Hellwig union nfsd4_op_u *u) 73909428fe1aSTigran Mkrtchyan { 739157832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 73929428fe1aSTigran Mkrtchyan } 73939428fe1aSTigran Mkrtchyan 73949428fe1aSTigran Mkrtchyan void 739557832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 739657832e7bSChristoph Hellwig union nfsd4_op_u *u) 73971e97b519STigran Mkrtchyan { 739857832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 73991e97b519STigran Mkrtchyan } 74001e97b519STigran Mkrtchyan 74011e97b519STigran Mkrtchyan void 740257832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 740357832e7bSChristoph Hellwig union nfsd4_op_u *u) 74041e97b519STigran Mkrtchyan { 740557832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 74061e97b519STigran Mkrtchyan } 74071e97b519STigran Mkrtchyan 740862cd4a59STigran Mkrtchyan void 740957832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 741057832e7bSChristoph Hellwig union nfsd4_op_u *u) 74118b70484cSTigran Mkrtchyan { 741257832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 74138b70484cSTigran Mkrtchyan } 74148b70484cSTigran Mkrtchyan 74158b70484cSTigran Mkrtchyan void 741657832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 741757832e7bSChristoph Hellwig union nfsd4_op_u *u) 74188b70484cSTigran Mkrtchyan { 741957832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 74208b70484cSTigran Mkrtchyan } 742130813e27STigran Mkrtchyan 742230813e27STigran Mkrtchyan void 742357832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 742457832e7bSChristoph Hellwig union nfsd4_op_u *u) 742530813e27STigran Mkrtchyan { 742657832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 742730813e27STigran Mkrtchyan } 742830813e27STigran Mkrtchyan 742930813e27STigran Mkrtchyan void 743057832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 743157832e7bSChristoph Hellwig union nfsd4_op_u *u) 743230813e27STigran Mkrtchyan { 743357832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 743430813e27STigran Mkrtchyan } 7435