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) 24176d348faSJeff Layton posix_unblock_lock(&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); 29668ef3bc3SJeff Layton posix_unblock_lock(&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 716b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 7174cdc951bSJ. Bruce Fields { 7186011695dSTrond Myklebust struct nfs4_stid *stid; 7196011695dSTrond Myklebust 720d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 7216011695dSTrond Myklebust if (!stid) 7226011695dSTrond Myklebust return NULL; 7236011695dSTrond Myklebust 724d19fb70dSKinglong Mee return openlockstateid(stid); 7256011695dSTrond Myklebust } 7266011695dSTrond Myklebust 7276011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 7286011695dSTrond Myklebust { 7296011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 7306011695dSTrond Myklebust atomic_long_dec(&num_delegations); 7314cdc951bSJ. Bruce Fields } 7324cdc951bSJ. Bruce Fields 7336282cd56SNeilBrown /* 7346282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 7356282cd56SNeilBrown * out again straight away. 7366282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 7376282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 7386282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 7396282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 7406282cd56SNeilBrown * filter. 7416282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 7426282cd56SNeilBrown * unless both are empty of course. 7436282cd56SNeilBrown * 7446282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 7456282cd56SNeilBrown * low 3 bytes as hash-table indices. 7466282cd56SNeilBrown * 747f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 7486282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 7496282cd56SNeilBrown * except when swapping the two filters. 7506282cd56SNeilBrown */ 751f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 7526282cd56SNeilBrown static struct bloom_pair { 7536282cd56SNeilBrown int entries, old_entries; 7546282cd56SNeilBrown time_t swap_time; 7556282cd56SNeilBrown int new; /* index into 'set' */ 7566282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 7576282cd56SNeilBrown } blocked_delegations; 7586282cd56SNeilBrown 7596282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 7606282cd56SNeilBrown { 7616282cd56SNeilBrown u32 hash; 7626282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 7636282cd56SNeilBrown 7646282cd56SNeilBrown if (bd->entries == 0) 7656282cd56SNeilBrown return 0; 7666282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 767f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 7686282cd56SNeilBrown if (seconds_since_boot() - bd->swap_time > 30) { 7696282cd56SNeilBrown bd->entries -= bd->old_entries; 7706282cd56SNeilBrown bd->old_entries = bd->entries; 7716282cd56SNeilBrown memset(bd->set[bd->new], 0, 7726282cd56SNeilBrown sizeof(bd->set[0])); 7736282cd56SNeilBrown bd->new = 1-bd->new; 7746282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 7756282cd56SNeilBrown } 776f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 7776282cd56SNeilBrown } 77887545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 7796282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 7806282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 7816282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 7826282cd56SNeilBrown return 1; 7836282cd56SNeilBrown 7846282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 7856282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 7866282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 7876282cd56SNeilBrown return 1; 7886282cd56SNeilBrown 7896282cd56SNeilBrown return 0; 7906282cd56SNeilBrown } 7916282cd56SNeilBrown 7926282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 7936282cd56SNeilBrown { 7946282cd56SNeilBrown u32 hash; 7956282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 7966282cd56SNeilBrown 79787545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 7986282cd56SNeilBrown 799f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 8006282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 8016282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 8026282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 8036282cd56SNeilBrown if (bd->entries == 0) 8046282cd56SNeilBrown bd->swap_time = seconds_since_boot(); 8056282cd56SNeilBrown bd->entries += 1; 806f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 8076282cd56SNeilBrown } 8086282cd56SNeilBrown 8091da177e4SLinus Torvalds static struct nfs4_delegation * 81086d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 81186d29b10SJ. Bruce Fields struct svc_fh *current_fh, 8128287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 8131da177e4SLinus Torvalds { 8141da177e4SLinus Torvalds struct nfs4_delegation *dp; 81502a3508dSTrond Myklebust long n; 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 81802a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 81902a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 82002a3508dSTrond Myklebust goto out_dec; 8216282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 82202a3508dSTrond Myklebust goto out_dec; 823d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 8245b2d21c1SNeilBrown if (dp == NULL) 82502a3508dSTrond Myklebust goto out_dec; 8266011695dSTrond Myklebust 8272a74aba7SJ. Bruce Fields /* 8282a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 8296136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 8306136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 8312a74aba7SJ. Bruce Fields */ 8322a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 833ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 834ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 8351da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 8368287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 8378287f009SSachin Bhamare get_clnt_odstate(odstate); 83899c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 839f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 840f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 8410162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 84286d29b10SJ. Bruce Fields get_nfs4_file(fp); 84386d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 8441da177e4SLinus Torvalds return dp; 84502a3508dSTrond Myklebust out_dec: 84602a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 84702a3508dSTrond Myklebust return NULL; 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds 8501da177e4SLinus Torvalds void 8516011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 8521da177e4SLinus Torvalds { 85311b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 8546011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 8556011695dSTrond Myklebust 8564770d722SJeff Layton might_lock(&clp->cl_lock); 8574770d722SJeff Layton 858a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 859b401be22SJeff Layton wake_up_all(&close_wq); 8606011695dSTrond Myklebust return; 861b401be22SJeff Layton } 8626011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 8634770d722SJeff Layton spin_unlock(&clp->cl_lock); 8646011695dSTrond Myklebust s->sc_free(s); 86511b9164aSTrond Myklebust if (fp) 86611b9164aSTrond Myklebust put_nfs4_file(fp); 8671da177e4SLinus Torvalds } 8681da177e4SLinus Torvalds 8699767feb2SJeff Layton void 8709767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 8719767feb2SJeff Layton { 8729767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 8739767feb2SJeff Layton 8749767feb2SJeff Layton spin_lock(&stid->sc_lock); 8759767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 8769767feb2SJeff Layton src->si_generation = 1; 8779767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 8789767feb2SJeff Layton spin_unlock(&stid->sc_lock); 8799767feb2SJeff Layton } 8809767feb2SJeff Layton 881353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 8821da177e4SLinus Torvalds { 8836bcc034eSJeff Layton struct file *filp = NULL; 884353601e7SJ. Bruce Fields 885353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 886353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 887353601e7SJ. Bruce Fields swap(filp, fp->fi_deleg_file); 888353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 889353601e7SJ. Bruce Fields 890353601e7SJ. Bruce Fields if (filp) 891353601e7SJ. Bruce Fields fput(filp); 892353601e7SJ. Bruce Fields } 893353601e7SJ. Bruce Fields 894353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 895353601e7SJ. Bruce Fields { 896cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 897353601e7SJ. Bruce Fields struct file *filp = fp->fi_deleg_file; 898417c6629SJeff Layton 899b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 900b8232d33SJ. Bruce Fields 901653e514eSJ. Bruce Fields vfs_setlease(filp, F_UNLCK, NULL, (void **)&dp); 902353601e7SJ. Bruce Fields put_deleg_file(fp); 9031da177e4SLinus Torvalds } 9041da177e4SLinus Torvalds 9050af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 9060af6e690SJ. Bruce Fields { 9070af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 908353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 9090af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 9100af6e690SJ. Bruce Fields } 9110af6e690SJ. Bruce Fields 912cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 9136136d2b4SJ. Bruce Fields { 9143abdb607SJ. Bruce Fields s->sc_type = 0; 9156136d2b4SJ. Bruce Fields } 9166136d2b4SJ. Bruce Fields 91734ed9872SAndrew Elble /** 91868b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 91934ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 92034ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 92134ed9872SAndrew Elble * 92234ed9872SAndrew Elble * Return: 92368b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 92434ed9872SAndrew Elble */ 92534ed9872SAndrew Elble 92668b18f52SJ. Bruce Fields static bool 92768b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 928931ee56cSBenny Halevy { 92934ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 93034ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 93134ed9872SAndrew Elble 932cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 933417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 934931ee56cSBenny Halevy 93534ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 93634ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 93734ed9872SAndrew Elble if (clp == searchclp) { 93851d87bc2SFengguang Wu return true; 93934ed9872SAndrew Elble } 94034ed9872SAndrew Elble } 94151d87bc2SFengguang Wu return false; 94234ed9872SAndrew Elble } 94334ed9872SAndrew Elble 94434ed9872SAndrew Elble /** 94534ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 94634ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 94734ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 94834ed9872SAndrew Elble * 94934ed9872SAndrew Elble * Return: 95034ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 95134ed9872SAndrew Elble * 95234ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 95334ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 95434ed9872SAndrew Elble * 95534ed9872SAndrew Elble */ 95634ed9872SAndrew Elble 95734ed9872SAndrew Elble static int 95834ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 95934ed9872SAndrew Elble { 96034ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 96134ed9872SAndrew Elble 96234ed9872SAndrew Elble lockdep_assert_held(&state_lock); 96334ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 96434ed9872SAndrew Elble 96568b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 96668b18f52SJ. Bruce Fields return -EAGAIN; 967a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 9683fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 969931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 97034ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 97134ed9872SAndrew Elble return 0; 972931ee56cSBenny Halevy } 973931ee56cSBenny Halevy 9743fcbbd24SJeff Layton static bool 97542690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 9761da177e4SLinus Torvalds { 97711b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 97802e1215fSJeff Layton 97942690676SJeff Layton lockdep_assert_held(&state_lock); 98042690676SJeff Layton 9813fcbbd24SJeff Layton if (list_empty(&dp->dl_perfile)) 9823fcbbd24SJeff Layton return false; 9833fcbbd24SJeff Layton 984b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 985d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 986d55a166cSJeff Layton ++dp->dl_time; 987417c6629SJeff Layton spin_lock(&fp->fi_lock); 988931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 9891da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 99002e1215fSJeff Layton list_del_init(&dp->dl_perfile); 99102e1215fSJeff Layton spin_unlock(&fp->fi_lock); 9923fcbbd24SJeff Layton return true; 993cbf7a75bSJ. Bruce Fields } 9943bd64a5bSJ. Bruce Fields 9953bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 9963bd64a5bSJ. Bruce Fields { 9973fcbbd24SJeff Layton bool unhashed; 9983fcbbd24SJeff Layton 99942690676SJeff Layton spin_lock(&state_lock); 10003fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 100142690676SJeff Layton spin_unlock(&state_lock); 10020af6e690SJ. Bruce Fields if (unhashed) 10030af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 10043fcbbd24SJeff Layton } 10053bd64a5bSJ. Bruce Fields 10063bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 10073bd64a5bSJ. Bruce Fields { 10083bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 10093bd64a5bSJ. Bruce Fields 10102d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 10112d4a532dSJeff Layton 10120af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 10133bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 10140af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 10152d4a532dSJeff Layton spin_lock(&clp->cl_lock); 10162d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 10172d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 10183bd64a5bSJ. Bruce Fields } 10190af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 10203bd64a5bSJ. Bruce Fields } 10213bd64a5bSJ. Bruce Fields 10221da177e4SLinus Torvalds /* 10231da177e4SLinus Torvalds * SETCLIENTID state 10241da177e4SLinus Torvalds */ 10251da177e4SLinus Torvalds 1026ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1027ddc04c41SJ. Bruce Fields { 1028ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1029ddc04c41SJ. Bruce Fields } 1030ddc04c41SJ. Bruce Fields 1031ddc04c41SJ. Bruce Fields static unsigned int clientstr_hashval(const char *name) 1032ddc04c41SJ. Bruce Fields { 1033ddc04c41SJ. Bruce Fields return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 1034ddc04c41SJ. Bruce Fields } 1035ddc04c41SJ. Bruce Fields 10361da177e4SLinus Torvalds /* 1037f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 1038f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 1039f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 1040f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 1041f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 1042f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 1043f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 1044f9d7562fSJ. Bruce Fields * 1045f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 1046f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 1047f9d7562fSJ. Bruce Fields * 1048f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 1049f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 1050f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 1051f9d7562fSJ. Bruce Fields * 1052f9d7562fSJ. Bruce Fields * which we should reject. 1053f9d7562fSJ. Bruce Fields */ 10545ae037e5SJeff Layton static unsigned int 10555ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 1056f9d7562fSJ. Bruce Fields int i; 10575ae037e5SJeff Layton unsigned int access = 0; 1058f9d7562fSJ. Bruce Fields 1059f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 1060f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 10615ae037e5SJeff Layton access |= i; 1062f9d7562fSJ. Bruce Fields } 10635ae037e5SJeff Layton return access; 1064f9d7562fSJ. Bruce Fields } 1065f9d7562fSJ. Bruce Fields 106682c5ff1bSJeff Layton /* set share access for a given stateid */ 106782c5ff1bSJeff Layton static inline void 106882c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 106982c5ff1bSJeff Layton { 1070c11c591fSJeff Layton unsigned char mask = 1 << access; 1071c11c591fSJeff Layton 1072c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1073c11c591fSJeff Layton stp->st_access_bmap |= mask; 107482c5ff1bSJeff Layton } 107582c5ff1bSJeff Layton 107682c5ff1bSJeff Layton /* clear share access for a given stateid */ 107782c5ff1bSJeff Layton static inline void 107882c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 107982c5ff1bSJeff Layton { 1080c11c591fSJeff Layton unsigned char mask = 1 << access; 1081c11c591fSJeff Layton 1082c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1083c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 108482c5ff1bSJeff Layton } 108582c5ff1bSJeff Layton 108682c5ff1bSJeff Layton /* test whether a given stateid has access */ 108782c5ff1bSJeff Layton static inline bool 108882c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 108982c5ff1bSJeff Layton { 1090c11c591fSJeff Layton unsigned char mask = 1 << access; 1091c11c591fSJeff Layton 1092c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 109382c5ff1bSJeff Layton } 109482c5ff1bSJeff Layton 1095ce0fc43cSJeff Layton /* set share deny for a given stateid */ 1096ce0fc43cSJeff Layton static inline void 1097c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 1098ce0fc43cSJeff Layton { 1099c11c591fSJeff Layton unsigned char mask = 1 << deny; 1100c11c591fSJeff Layton 1101c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1102c11c591fSJeff Layton stp->st_deny_bmap |= mask; 1103ce0fc43cSJeff Layton } 1104ce0fc43cSJeff Layton 1105ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 1106ce0fc43cSJeff Layton static inline void 1107c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 1108ce0fc43cSJeff Layton { 1109c11c591fSJeff Layton unsigned char mask = 1 << deny; 1110c11c591fSJeff Layton 1111c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1112c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 1113ce0fc43cSJeff Layton } 1114ce0fc43cSJeff Layton 1115ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 1116ce0fc43cSJeff Layton static inline bool 1117c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 1118ce0fc43cSJeff Layton { 1119c11c591fSJeff Layton unsigned char mask = 1 << deny; 1120c11c591fSJeff Layton 1121c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 1122f9d7562fSJ. Bruce Fields } 1123f9d7562fSJ. Bruce Fields 1124f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 1125f9d7562fSJ. Bruce Fields { 11268f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 1127f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 1128f9d7562fSJ. Bruce Fields return O_RDONLY; 1129f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 1130f9d7562fSJ. Bruce Fields return O_WRONLY; 1131f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 1132f9d7562fSJ. Bruce Fields return O_RDWR; 1133f9d7562fSJ. Bruce Fields } 1134063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 1135063b0fb9SJ. Bruce Fields return O_RDONLY; 1136f9d7562fSJ. Bruce Fields } 1137f9d7562fSJ. Bruce Fields 1138baeb4ff0SJeff Layton /* 1139baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1140baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1141baeb4ff0SJeff Layton */ 1142baeb4ff0SJeff Layton static void 1143baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1144baeb4ff0SJeff Layton { 1145baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1146baeb4ff0SJeff Layton 1147baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1148baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1149baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1150baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1151baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1152baeb4ff0SJeff Layton } 1153baeb4ff0SJeff Layton 1154baeb4ff0SJeff Layton static void 1155baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1156baeb4ff0SJeff Layton { 1157baeb4ff0SJeff Layton int i; 1158baeb4ff0SJeff Layton bool change = false; 1159baeb4ff0SJeff Layton 1160baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1161baeb4ff0SJeff Layton if ((i & deny) != i) { 1162baeb4ff0SJeff Layton change = true; 1163baeb4ff0SJeff Layton clear_deny(i, stp); 1164baeb4ff0SJeff Layton } 1165baeb4ff0SJeff Layton } 1166baeb4ff0SJeff Layton 1167baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1168baeb4ff0SJeff Layton if (change) 116911b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1170baeb4ff0SJeff Layton } 1171baeb4ff0SJeff Layton 117282c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 117382c5ff1bSJeff Layton static void 117482c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 117582c5ff1bSJeff Layton { 117682c5ff1bSJeff Layton int i; 117711b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1178baeb4ff0SJeff Layton 1179baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1180baeb4ff0SJeff Layton recalculate_deny_mode(fp); 118182c5ff1bSJeff Layton 118282c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 118382c5ff1bSJeff Layton if (test_access(i, stp)) 118411b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 118582c5ff1bSJeff Layton clear_access(i, stp); 118682c5ff1bSJeff Layton } 118782c5ff1bSJeff Layton } 118882c5ff1bSJeff Layton 1189d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1190d50ffdedSKinglong Mee { 1191d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1192d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1193d50ffdedSKinglong Mee } 1194d50ffdedSKinglong Mee 11956b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 11966b180f0bSJeff Layton { 1197a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1198a819ecc1SJeff Layton 1199a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1200a819ecc1SJeff Layton 1201a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 12026b180f0bSJeff Layton return; 12038f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1204a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1205d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 12066b180f0bSJeff Layton } 12076b180f0bSJeff Layton 1208e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1209529d7b2aSJ. Bruce Fields { 121011b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 12111d31a253STrond Myklebust 12121c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 12131c755dc1SJeff Layton 1214e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1215e8568739SJeff Layton return false; 1216e8568739SJeff Layton 12171d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1218e8568739SJeff Layton list_del_init(&stp->st_perfile); 12191d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1220529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1221e8568739SJeff Layton return true; 1222529d7b2aSJ. Bruce Fields } 1223529d7b2aSJ. Bruce Fields 12246011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1225529d7b2aSJ. Bruce Fields { 12266011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 12274665e2baSJ. Bruce Fields 12288287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 12296011695dSTrond Myklebust release_all_access(stp); 1230d3134b10SJeff Layton if (stp->st_stateowner) 1231d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 12326011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1233529d7b2aSJ. Bruce Fields } 1234529d7b2aSJ. Bruce Fields 1235b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1236529d7b2aSJ. Bruce Fields { 1237b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1238b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1239529d7b2aSJ. Bruce Fields struct file *file; 1240529d7b2aSJ. Bruce Fields 1241b49e084dSJeff Layton file = find_any_file(stp->st_stid.sc_file); 1242b49e084dSJeff Layton if (file) 1243b49e084dSJeff Layton filp_close(file, (fl_owner_t)lo); 1244b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1245b49e084dSJeff Layton } 1246b49e084dSJeff Layton 12472c41beb0SJeff Layton /* 12482c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 12492c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 12502c41beb0SJeff Layton * reaplist for later destruction. 12512c41beb0SJeff Layton */ 12522c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 12532c41beb0SJeff Layton struct list_head *reaplist) 12542c41beb0SJeff Layton { 12552c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 12562c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 12572c41beb0SJeff Layton 12582c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 12592c41beb0SJeff Layton 12602c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 12612c41beb0SJeff Layton 1262a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 12632c41beb0SJeff Layton wake_up_all(&close_wq); 12642c41beb0SJeff Layton return; 12652c41beb0SJeff Layton } 12662c41beb0SJeff Layton 12672c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 12682c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 12692c41beb0SJeff Layton } 12702c41beb0SJeff Layton 1271e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 12723c1c995cSJeff Layton { 1273f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 12743c1c995cSJeff Layton 12753c1c995cSJeff Layton list_del_init(&stp->st_locks); 1276cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1277e8568739SJeff Layton return unhash_ol_stateid(stp); 12783c1c995cSJeff Layton } 12793c1c995cSJeff Layton 12805adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1281b49e084dSJeff Layton { 1282f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1283e8568739SJeff Layton bool unhashed; 12841c755dc1SJeff Layton 1285f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1286e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1287f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1288e8568739SJeff Layton if (unhashed) 12896011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1290529d7b2aSJ. Bruce Fields } 1291529d7b2aSJ. Bruce Fields 1292c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1293529d7b2aSJ. Bruce Fields { 1294d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1295c58c6610STrond Myklebust 1296d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1297c58c6610STrond Myklebust 12988f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 12998f4b54c5SJeff Layton } 13008f4b54c5SJeff Layton 13012c41beb0SJeff Layton /* 13022c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 13032c41beb0SJeff Layton * fully unhashed. 13042c41beb0SJeff Layton */ 13052c41beb0SJeff Layton static void 13062c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 13072c41beb0SJeff Layton { 13082c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1309fb94d766SKinglong Mee struct nfs4_file *fp; 13102c41beb0SJeff Layton 13112c41beb0SJeff Layton might_sleep(); 13122c41beb0SJeff Layton 13132c41beb0SJeff Layton while (!list_empty(reaplist)) { 13142c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 13152c41beb0SJeff Layton st_locks); 13162c41beb0SJeff Layton list_del(&stp->st_locks); 1317fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 13182c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1319fb94d766SKinglong Mee if (fp) 1320fb94d766SKinglong Mee put_nfs4_file(fp); 13212c41beb0SJeff Layton } 13222c41beb0SJeff Layton } 13232c41beb0SJeff Layton 1324d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1325d83017f9SJeff Layton struct list_head *reaplist) 13263c87b9b7STrond Myklebust { 13273c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 13283c87b9b7STrond Myklebust 1329e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1330e8568739SJeff Layton 13313c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 13323c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 13333c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1334e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1335d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1336529d7b2aSJ. Bruce Fields } 1337529d7b2aSJ. Bruce Fields } 1338529d7b2aSJ. Bruce Fields 1339e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1340d83017f9SJeff Layton struct list_head *reaplist) 13412283963fSJ. Bruce Fields { 1342e8568739SJeff Layton bool unhashed; 1343e8568739SJeff Layton 13442c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 13452c41beb0SJeff Layton 1346e8568739SJeff Layton unhashed = unhash_ol_stateid(stp); 1347d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1348e8568739SJeff Layton return unhashed; 134938c387b5SJ. Bruce Fields } 135038c387b5SJ. Bruce Fields 135138c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 135238c387b5SJ. Bruce Fields { 13532c41beb0SJeff Layton LIST_HEAD(reaplist); 13542c41beb0SJeff Layton 13552c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1356e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 13572c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 13582c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 13592c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 13602283963fSJ. Bruce Fields } 13612283963fSJ. Bruce Fields 13627ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1363f1d110caSJ. Bruce Fields { 1364d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 13657ffb5880STrond Myklebust 1366d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 13677ffb5880STrond Myklebust 13688f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 13698f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1370f1d110caSJ. Bruce Fields } 1371f1d110caSJ. Bruce Fields 1372f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1373f7a4d872SJ. Bruce Fields { 1374217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1375217526e7SJeff Layton nfsd_net_id); 1376217526e7SJeff Layton struct nfs4_ol_stateid *s; 1377f7a4d872SJ. Bruce Fields 1378217526e7SJeff Layton spin_lock(&nn->client_lock); 1379217526e7SJeff Layton s = oo->oo_last_closed_stid; 1380f7a4d872SJ. Bruce Fields if (s) { 1381d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1382f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1383f7a4d872SJ. Bruce Fields } 1384217526e7SJeff Layton spin_unlock(&nn->client_lock); 1385217526e7SJeff Layton if (s) 1386217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1387f7a4d872SJ. Bruce Fields } 1388f7a4d872SJ. Bruce Fields 13892c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 13908f4b54c5SJeff Layton { 13918f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1392d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 13932c41beb0SJeff Layton struct list_head reaplist; 13947ffb5880STrond Myklebust 13952c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 13967ffb5880STrond Myklebust 1397d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 13987ffb5880STrond Myklebust unhash_openowner_locked(oo); 13992c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 14002c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 14012c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1402e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 14032c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 14042c41beb0SJeff Layton } 1405d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 14062c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1407f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 14086b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1409f1d110caSJ. Bruce Fields } 1410f1d110caSJ. Bruce Fields 14115282fd72SMarc Eshel static inline int 14125282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 14135282fd72SMarc Eshel { 14145282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 14155282fd72SMarc Eshel 14165282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 14175282fd72SMarc Eshel } 14185282fd72SMarc Eshel 1419135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 14205282fd72SMarc Eshel static inline void 14215282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 14225282fd72SMarc Eshel { 14235282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 14245282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 14255282fd72SMarc Eshel } 14268f199b82STrond Myklebust #else 14278f199b82STrond Myklebust static inline void 14288f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 14298f199b82STrond Myklebust { 14308f199b82STrond Myklebust } 14318f199b82STrond Myklebust #endif 14328f199b82STrond Myklebust 14339411b1d4SJ. Bruce Fields /* 14349411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 14359411b1d4SJ. Bruce Fields * won't be used for replay. 14369411b1d4SJ. Bruce Fields */ 14379411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 14389411b1d4SJ. Bruce Fields { 14399411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 14409411b1d4SJ. Bruce Fields 14419411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 14429411b1d4SJ. Bruce Fields return; 14439411b1d4SJ. Bruce Fields 14449411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 144558fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 14469411b1d4SJ. Bruce Fields return; 14479411b1d4SJ. Bruce Fields } 14489411b1d4SJ. Bruce Fields if (!so) 14499411b1d4SJ. Bruce Fields return; 14509411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 14519411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 14529411b1d4SJ. Bruce Fields so->so_seqid++; 14539411b1d4SJ. Bruce Fields return; 14549411b1d4SJ. Bruce Fields } 14555282fd72SMarc Eshel 1456ec6b5d7bSAndy Adamson static void 1457ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1458ec6b5d7bSAndy Adamson { 1459ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1460ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1461ec6b5d7bSAndy Adamson 1462ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1463ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1464ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1465ec6b5d7bSAndy Adamson sid->reserved = 0; 1466ec6b5d7bSAndy Adamson } 1467ec6b5d7bSAndy Adamson 1468ec6b5d7bSAndy Adamson /* 1469a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1470a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1471a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1472a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1473a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1474a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1475a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1476a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1477a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1478a649637cSAndy Adamson * for the SEQUENCE op response: 1479ec6b5d7bSAndy Adamson */ 1480a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1481a649637cSAndy Adamson 1482557ce264SAndy Adamson static void 1483557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1484557ce264SAndy Adamson { 1485557ce264SAndy Adamson int i; 1486557ce264SAndy Adamson 148753da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 148853da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1489557ce264SAndy Adamson kfree(ses->se_slots[i]); 1490557ce264SAndy Adamson } 149153da6a53SJ. Bruce Fields } 1492557ce264SAndy Adamson 1493efe0cb6dSJ. Bruce Fields /* 1494efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1495efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1496efe0cb6dSJ. Bruce Fields */ 149755c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1498efe0cb6dSJ. Bruce Fields { 149955c760cfSJ. Bruce Fields u32 size; 1500efe0cb6dSJ. Bruce Fields 150155c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 150255c760cfSJ. Bruce Fields size = 0; 150355c760cfSJ. Bruce Fields else 150455c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 150555c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1506557ce264SAndy Adamson } 1507557ce264SAndy Adamson 15085b6feee9SJ. Bruce Fields /* 15095b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 15105b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 151142b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 15125b6feee9SJ. Bruce Fields */ 151355c760cfSJ. Bruce Fields static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 15145b6feee9SJ. Bruce Fields { 151555c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 151655c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 15175b6feee9SJ. Bruce Fields int avail; 15185b6feee9SJ. Bruce Fields 15195b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 1520697ce9beSZhang Yanfei avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, 15215b6feee9SJ. Bruce Fields nfsd_drc_max_mem - nfsd_drc_mem_used); 1522de766e57SJ. Bruce Fields /* 1523de766e57SJ. Bruce Fields * Never use more than a third of the remaining memory, 1524de766e57SJ. Bruce Fields * unless it's the only way to give this client a slot: 1525de766e57SJ. Bruce Fields */ 1526de766e57SJ. Bruce Fields avail = clamp_t(int, avail, slotsize, avail/3); 15275b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 15285b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 15295b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 15305b6feee9SJ. Bruce Fields 15315b6feee9SJ. Bruce Fields return num; 15325b6feee9SJ. Bruce Fields } 15335b6feee9SJ. Bruce Fields 153455c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 15355b6feee9SJ. Bruce Fields { 153655c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 153755c760cfSJ. Bruce Fields 15385b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 153955c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 15405b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 15415b6feee9SJ. Bruce Fields } 15425b6feee9SJ. Bruce Fields 154360810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 154460810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 15455b6feee9SJ. Bruce Fields { 154660810e54SKinglong Mee int numslots = fattrs->maxreqs; 154760810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 15485b6feee9SJ. Bruce Fields struct nfsd4_session *new; 15495b6feee9SJ. Bruce Fields int mem, i; 1550ec6b5d7bSAndy Adamson 1551c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1552ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 15535b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1554ec6b5d7bSAndy Adamson 15555b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 15566c18ba9fSAlexandros Batsakis if (!new) 15575b6feee9SJ. Bruce Fields return NULL; 1558ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 15595b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 156055c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 15615b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1562ec6b5d7bSAndy Adamson goto out_free; 1563ec6b5d7bSAndy Adamson } 156460810e54SKinglong Mee 156560810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 156660810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 156760810e54SKinglong Mee 15685b6feee9SJ. Bruce Fields return new; 15695b6feee9SJ. Bruce Fields out_free: 15705b6feee9SJ. Bruce Fields while (i--) 15715b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 15725b6feee9SJ. Bruce Fields kfree(new); 15735b6feee9SJ. Bruce Fields return NULL; 15745b6feee9SJ. Bruce Fields } 15755b6feee9SJ. Bruce Fields 157619cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 157719cf5c02SJ. Bruce Fields { 157819cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 157919cf5c02SJ. Bruce Fields kfree(c); 158019cf5c02SJ. Bruce Fields } 158119cf5c02SJ. Bruce Fields 158219cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 158319cf5c02SJ. Bruce Fields { 158419cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 158519cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 158619cf5c02SJ. Bruce Fields 158719cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 158819cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 158919cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 159019cf5c02SJ. Bruce Fields free_conn(c); 159119cf5c02SJ. Bruce Fields } 1592eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 15932e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 159419cf5c02SJ. Bruce Fields } 159519cf5c02SJ. Bruce Fields 1596d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1597c7662518SJ. Bruce Fields { 1598c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1599c7662518SJ. Bruce Fields 1600c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1601c7662518SJ. Bruce Fields if (!conn) 1602db90681dSJ. Bruce Fields return NULL; 1603c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1604c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1605d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1606db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1607db90681dSJ. Bruce Fields return conn; 1608db90681dSJ. Bruce Fields } 1609db90681dSJ. Bruce Fields 1610328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1611328ead28SJ. Bruce Fields { 1612328ead28SJ. Bruce Fields conn->cn_session = ses; 1613328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1614328ead28SJ. Bruce Fields } 1615328ead28SJ. Bruce Fields 1616db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1617db90681dSJ. Bruce Fields { 1618db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1619c7662518SJ. Bruce Fields 1620c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1621328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1622c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1623db90681dSJ. Bruce Fields } 1624c7662518SJ. Bruce Fields 162521b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1626db90681dSJ. Bruce Fields { 162719cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 162821b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1629db90681dSJ. Bruce Fields } 1630db90681dSJ. Bruce Fields 1631e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1632db90681dSJ. Bruce Fields { 163321b75b01SJ. Bruce Fields int ret; 1634db90681dSJ. Bruce Fields 1635db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 163621b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 163721b75b01SJ. Bruce Fields if (ret) 163821b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 163921b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 164057a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 164157a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1642c7662518SJ. Bruce Fields } 1643c7662518SJ. Bruce Fields 1644e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 16451d1bc8f2SJ. Bruce Fields { 16461d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 16471d1bc8f2SJ. Bruce Fields 1648e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 16491d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1650e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 16511d1bc8f2SJ. Bruce Fields } 16521d1bc8f2SJ. Bruce Fields 16531d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 165419cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1655c7662518SJ. Bruce Fields { 165619cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 165719cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 165819cf5c02SJ. Bruce Fields 165919cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 166019cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 166119cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 166219cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 166319cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 166419cf5c02SJ. Bruce Fields 166519cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 166619cf5c02SJ. Bruce Fields free_conn(c); 166719cf5c02SJ. Bruce Fields 166819cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 166919cf5c02SJ. Bruce Fields } 167019cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1671c7662518SJ. Bruce Fields } 1672c7662518SJ. Bruce Fields 16731377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 16741377b69eSJ. Bruce Fields { 16751377b69eSJ. Bruce Fields free_session_slots(ses); 16761377b69eSJ. Bruce Fields kfree(ses); 16771377b69eSJ. Bruce Fields } 16781377b69eSJ. Bruce Fields 167966b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1680508dc6e1SBenny Halevy { 1681c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 168255c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1683c7662518SJ. Bruce Fields __free_session(ses); 1684a827bcb2SJ. Bruce Fields } 1685ec6b5d7bSAndy Adamson 1686135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1687a827bcb2SJ. Bruce Fields { 1688a827bcb2SJ. Bruce Fields int idx; 16891872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1690a827bcb2SJ. Bruce Fields 1691ec6b5d7bSAndy Adamson new->se_client = clp; 1692ec6b5d7bSAndy Adamson gen_sessionid(new); 1693ec6b5d7bSAndy Adamson 1694c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1695c7662518SJ. Bruce Fields 1696ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1697ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 16988b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1699c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 170066b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 17015b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 17021872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 17034c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1704ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 17054c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 170660810e54SKinglong Mee 1707b0d2e42cSChuck Lever { 1708edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1709dcbeaa68SJ. Bruce Fields /* 1710dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1711dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1712dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1713dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1714dcbeaa68SJ. Bruce Fields * future: 1715dcbeaa68SJ. Bruce Fields */ 1716edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1717edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1718edd76786SJ. Bruce Fields } 1719ec6b5d7bSAndy Adamson } 1720ec6b5d7bSAndy Adamson 17219089f1b4SBenny Halevy /* caller must hold client_lock */ 17225282fd72SMarc Eshel static struct nfsd4_session * 1723d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 17245282fd72SMarc Eshel { 17255282fd72SMarc Eshel struct nfsd4_session *elem; 17265282fd72SMarc Eshel int idx; 17271872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 17285282fd72SMarc Eshel 17290a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 17300a880a28STrond Myklebust 17315282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 17325282fd72SMarc Eshel idx = hash_sessionid(sessionid); 17335282fd72SMarc Eshel /* Search in the appropriate list */ 17341872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 17355282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 17365282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 17375282fd72SMarc Eshel return elem; 17385282fd72SMarc Eshel } 17395282fd72SMarc Eshel } 17405282fd72SMarc Eshel 17415282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 17425282fd72SMarc Eshel return NULL; 17435282fd72SMarc Eshel } 17445282fd72SMarc Eshel 1745d4e19e70STrond Myklebust static struct nfsd4_session * 1746d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1747d4e19e70STrond Myklebust __be32 *ret) 1748d4e19e70STrond Myklebust { 1749d4e19e70STrond Myklebust struct nfsd4_session *session; 1750d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1751d4e19e70STrond Myklebust 1752d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1753d4e19e70STrond Myklebust if (!session) 1754d4e19e70STrond Myklebust goto out; 1755d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1756d4e19e70STrond Myklebust if (status) 1757d4e19e70STrond Myklebust session = NULL; 1758d4e19e70STrond Myklebust out: 1759d4e19e70STrond Myklebust *ret = status; 1760d4e19e70STrond Myklebust return session; 1761d4e19e70STrond Myklebust } 1762d4e19e70STrond Myklebust 17639089f1b4SBenny Halevy /* caller must hold client_lock */ 17647116ed6bSAndy Adamson static void 17655282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 17667116ed6bSAndy Adamson { 17670a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 17680a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 17690a880a28STrond Myklebust 17700a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 17710a880a28STrond Myklebust 17727116ed6bSAndy Adamson list_del(&ses->se_hash); 17734c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 17747116ed6bSAndy Adamson list_del(&ses->se_perclnt); 17754c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 17765282fd72SMarc Eshel } 17775282fd72SMarc Eshel 17781da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 17791da177e4SLinus Torvalds static int 17802c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 17811da177e4SLinus Torvalds { 1782bbc7f33aSJ. Bruce Fields /* 1783bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 1784bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 1785bbc7f33aSJ. Bruce Fields * a safe assumption: 1786bbc7f33aSJ. Bruce Fields */ 1787bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 17881da177e4SLinus Torvalds return 0; 178960adfc50SAndy Adamson dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", 17902c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 17911da177e4SLinus Torvalds return 1; 17921da177e4SLinus Torvalds } 17931da177e4SLinus Torvalds 17941da177e4SLinus Torvalds /* 17951da177e4SLinus Torvalds * XXX Should we use a slab cache ? 17961da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 17971da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 17981da177e4SLinus Torvalds */ 179935bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 18001da177e4SLinus Torvalds { 18011da177e4SLinus Torvalds struct nfs4_client *clp; 1802d4f0489fSTrond Myklebust int i; 18031da177e4SLinus Torvalds 18049258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 180535bba9a3SJ. Bruce Fields if (clp == NULL) 180635bba9a3SJ. Bruce Fields return NULL; 180767114fe6SThomas Meyer clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); 1808d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1809d4f0489fSTrond Myklebust goto err_no_name; 18106da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 18116da2ec56SKees Cook sizeof(struct list_head), 18126da2ec56SKees Cook GFP_KERNEL); 1813d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1814d4f0489fSTrond Myklebust goto err_no_hashtbl; 1815d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1816d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 18171da177e4SLinus Torvalds clp->cl_name.len = name.len; 18185694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 18195694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 18205694c93eSTrond Myklebust atomic_set(&clp->cl_refcount, 0); 18215694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 18225694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 18235694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 18245694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 18255694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 18265694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 18279cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 18289cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 18299cf514ccSChristoph Hellwig #endif 18305694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 18315694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 18321da177e4SLinus Torvalds return clp; 1833d4f0489fSTrond Myklebust err_no_hashtbl: 1834d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1835d4f0489fSTrond Myklebust err_no_name: 18369258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 1837d4f0489fSTrond Myklebust return NULL; 18381da177e4SLinus Torvalds } 18391da177e4SLinus Torvalds 18404dd86e15STrond Myklebust static void 18411da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 18421da177e4SLinus Torvalds { 1843792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1844792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1845792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1846792c95ddSJ. Bruce Fields se_perclnt); 1847792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 184866b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 184966b2b9b2SJ. Bruce Fields free_session(ses); 1850792c95ddSJ. Bruce Fields } 18514cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 185203a4e1f6SJ. Bruce Fields free_svc_cred(&clp->cl_cred); 1853d4f0489fSTrond Myklebust kfree(clp->cl_ownerstr_hashtbl); 18541da177e4SLinus Torvalds kfree(clp->cl_name.data); 18552d32b29aSmajianpeng idr_destroy(&clp->cl_stateids); 18569258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 18571da177e4SLinus Torvalds } 18581da177e4SLinus Torvalds 185984d38ac9SBenny Halevy /* must be called under the client_lock */ 18604beb345bSTrond Myklebust static void 186184d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 186284d38ac9SBenny Halevy { 18634beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1864792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1865792c95ddSJ. Bruce Fields 18660a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 18670a880a28STrond Myklebust 18684beb345bSTrond Myklebust /* Mark the client as expired! */ 18694beb345bSTrond Myklebust clp->cl_time = 0; 18704beb345bSTrond Myklebust /* Make it invisible */ 18714beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 18724beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 18734beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 18744beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 18754beb345bSTrond Myklebust else 18764beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 18774beb345bSTrond Myklebust } 18784beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 18794c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1880792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1881792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 18824c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 188384d38ac9SBenny Halevy } 188484d38ac9SBenny Halevy 18851da177e4SLinus Torvalds static void 18864beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 18874beb345bSTrond Myklebust { 18884beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 18894beb345bSTrond Myklebust 18904beb345bSTrond Myklebust spin_lock(&nn->client_lock); 18914beb345bSTrond Myklebust unhash_client_locked(clp); 18924beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 18934beb345bSTrond Myklebust } 18944beb345bSTrond Myklebust 189597403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 189697403d95SJeff Layton { 189797403d95SJeff Layton if (atomic_read(&clp->cl_refcount)) 189897403d95SJeff Layton return nfserr_jukebox; 189997403d95SJeff Layton unhash_client_locked(clp); 190097403d95SJeff Layton return nfs_ok; 190197403d95SJeff Layton } 190297403d95SJeff Layton 19034beb345bSTrond Myklebust static void 19044beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 19051da177e4SLinus Torvalds { 190668ef3bc3SJeff Layton int i; 1907fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 19081da177e4SLinus Torvalds struct nfs4_delegation *dp; 19091da177e4SLinus Torvalds struct list_head reaplist; 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 1912cdc97505SBenny Halevy spin_lock(&state_lock); 1913ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 1914ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 19153fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 191642690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 19171da177e4SLinus Torvalds } 1918cdc97505SBenny Halevy spin_unlock(&state_lock); 19191da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 19201da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 192142690676SJeff Layton list_del_init(&dp->dl_recall_lru); 19220af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 19231da177e4SLinus Torvalds } 19242d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 1925c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 19262d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 19276011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 1928956c4feeSBenny Halevy } 1929ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 1930fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1931b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 1932fe0750e5SJ. Bruce Fields release_openowner(oo); 19331da177e4SLinus Torvalds } 193468ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 193568ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 193668ef3bc3SJeff Layton 193768ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 193868ef3bc3SJeff Layton so_strhash) { 193968ef3bc3SJeff Layton /* Should be no openowners at this point */ 194068ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 194168ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 194268ef3bc3SJeff Layton } 194368ef3bc3SJeff Layton } 19449cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 19456ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 19462bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 19472bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1948b12a05cbSJ. Bruce Fields free_client(clp); 19491da177e4SLinus Torvalds } 19501da177e4SLinus Torvalds 19514beb345bSTrond Myklebust static void 19524beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 19534beb345bSTrond Myklebust { 19544beb345bSTrond Myklebust unhash_client(clp); 19554beb345bSTrond Myklebust __destroy_client(clp); 19564beb345bSTrond Myklebust } 19574beb345bSTrond Myklebust 19580d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 19590d22f68fSJ. Bruce Fields { 19604beb345bSTrond Myklebust unhash_client(clp); 19610d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 19624beb345bSTrond Myklebust __destroy_client(clp); 19630d22f68fSJ. Bruce Fields } 19640d22f68fSJ. Bruce Fields 196535bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 196635bba9a3SJ. Bruce Fields { 196735bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 196835bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 19691da177e4SLinus Torvalds } 19701da177e4SLinus Torvalds 197135bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 197235bba9a3SJ. Bruce Fields { 19731da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 19741da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 19751da177e4SLinus Torvalds } 19761da177e4SLinus Torvalds 197750043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 197850043859SJ. Bruce Fields { 19792f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 19802f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 19812f10fdcbSNeilBrown GFP_KERNEL); 19822f10fdcbSNeilBrown if ((source->cr_principal && ! target->cr_principal) || 19832f10fdcbSNeilBrown (source->cr_raw_principal && ! target->cr_raw_principal)) 19842f10fdcbSNeilBrown return -ENOMEM; 198550043859SJ. Bruce Fields 1986d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 19871da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 19881da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 19891da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 19901da177e4SLinus Torvalds get_group_info(target->cr_group_info); 19910dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 19920dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 19930dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 199403a4e1f6SJ. Bruce Fields return 0; 19951da177e4SLinus Torvalds } 19961da177e4SLinus Torvalds 1997ef17af2aSRasmus Villemoes static int 1998ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 1999ac55fdc4SJeff Layton { 2000ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2001ef17af2aSRasmus Villemoes return -1; 2002ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2003ef17af2aSRasmus Villemoes return 1; 2004ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2005ac55fdc4SJeff Layton } 2006ac55fdc4SJeff Layton 200735bba9a3SJ. Bruce Fields static int same_name(const char *n1, const char *n2) 2008599e0a22SJ. Bruce Fields { 2009a55370a3SNeilBrown return 0 == memcmp(n1, n2, HEXDIR_LEN); 20101da177e4SLinus Torvalds } 20111da177e4SLinus Torvalds 20121da177e4SLinus Torvalds static int 2013599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2014599e0a22SJ. Bruce Fields { 2015599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 20161da177e4SLinus Torvalds } 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds static int 2019599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2020599e0a22SJ. Bruce Fields { 2021599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 20221da177e4SLinus Torvalds } 20231da177e4SLinus Torvalds 20248fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 20258fbba96eSJ. Bruce Fields { 20268fbba96eSJ. Bruce Fields int i; 20278fbba96eSJ. Bruce Fields 20288fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 20298fbba96eSJ. Bruce Fields return false; 20308fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 203181243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 20328fbba96eSJ. Bruce Fields return false; 20338fbba96eSJ. Bruce Fields return true; 20348fbba96eSJ. Bruce Fields } 20358fbba96eSJ. Bruce Fields 203668eb3508SJ. Bruce Fields /* 203768eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 203868eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 203968eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 204068eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 204168eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 204268eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 204368eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 204468eb3508SJ. Bruce Fields */ 204568eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 204668eb3508SJ. Bruce Fields { 204768eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 204868eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 204968eb3508SJ. Bruce Fields } 205068eb3508SJ. Bruce Fields 205168eb3508SJ. Bruce Fields 20525559b50aSVivek Trivedi static bool 2053599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2054599e0a22SJ. Bruce Fields { 205568eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 20566fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 20576fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 20588fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 20598fbba96eSJ. Bruce Fields return false; 20608fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 20618fbba96eSJ. Bruce Fields return true; 20628fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 20638fbba96eSJ. Bruce Fields return false; 20645559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 20651da177e4SLinus Torvalds } 20661da177e4SLinus Torvalds 206757266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 206857266a6eSJ. Bruce Fields { 206957266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 207057266a6eSJ. Bruce Fields u32 service; 207157266a6eSJ. Bruce Fields 2072c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2073c4720591SJ. Bruce Fields return false; 207457266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 207557266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 207657266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 207757266a6eSJ. Bruce Fields } 207857266a6eSJ. Bruce Fields 2079dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 208057266a6eSJ. Bruce Fields { 208157266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 208257266a6eSJ. Bruce Fields 208357266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 208457266a6eSJ. Bruce Fields return true; 208557266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 208657266a6eSJ. Bruce Fields return false; 208757266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 208857266a6eSJ. Bruce Fields return false; 2089414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2090414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2091414ca017SJ. Bruce Fields cr->cr_raw_principal); 209257266a6eSJ. Bruce Fields if (!cr->cr_principal) 209357266a6eSJ. Bruce Fields return false; 209457266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 209557266a6eSJ. Bruce Fields } 209657266a6eSJ. Bruce Fields 2097294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2098deda2faaSJ. Bruce Fields { 2099ab4684d1SChuck Lever __be32 verf[2]; 21001da177e4SLinus Torvalds 2101f419992cSJeff Layton /* 2102f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2103f419992cSJeff Layton * __force to keep sparse happy 2104f419992cSJeff Layton */ 2105f419992cSJeff Layton verf[0] = (__force __be32)get_seconds(); 210619311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2107ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 21081da177e4SLinus Torvalds } 21091da177e4SLinus Torvalds 2110294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2111294ac32eSJeff Layton { 2112294ac32eSJeff Layton clp->cl_clientid.cl_boot = nn->boot_time; 2113294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2114294ac32eSJeff Layton gen_confirm(clp, nn); 2115294ac32eSJeff Layton } 2116294ac32eSJeff Layton 21174770d722SJeff Layton static struct nfs4_stid * 21184770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 21194581d140SJ. Bruce Fields { 21203abdb607SJ. Bruce Fields struct nfs4_stid *ret; 21213abdb607SJ. Bruce Fields 21223abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 21233abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 21243abdb607SJ. Bruce Fields return NULL; 21253abdb607SJ. Bruce Fields return ret; 21264581d140SJ. Bruce Fields } 21274d71ab87SJ. Bruce Fields 21284770d722SJeff Layton static struct nfs4_stid * 21294770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2130f459e453SJ. Bruce Fields { 2131f459e453SJ. Bruce Fields struct nfs4_stid *s; 2132f459e453SJ. Bruce Fields 21334770d722SJeff Layton spin_lock(&cl->cl_lock); 21344770d722SJeff Layton s = find_stateid_locked(cl, t); 21352d3f9668STrond Myklebust if (s != NULL) { 21362d3f9668STrond Myklebust if (typemask & s->sc_type) 2137a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 21382d3f9668STrond Myklebust else 21394770d722SJeff Layton s = NULL; 21402d3f9668STrond Myklebust } 21414770d722SJeff Layton spin_unlock(&cl->cl_lock); 21424d71ab87SJ. Bruce Fields return s; 21434581d140SJ. Bruce Fields } 21444581d140SJ. Bruce Fields 21452216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2146b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2147b09333c4SRicardo Labiaga { 2148b09333c4SRicardo Labiaga struct nfs4_client *clp; 2149b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 215003a4e1f6SJ. Bruce Fields int ret; 2151c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2152b09333c4SRicardo Labiaga 2153b09333c4SRicardo Labiaga clp = alloc_client(name); 2154b09333c4SRicardo Labiaga if (clp == NULL) 2155b09333c4SRicardo Labiaga return NULL; 2156b09333c4SRicardo Labiaga 215703a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 215803a4e1f6SJ. Bruce Fields if (ret) { 2159b09333c4SRicardo Labiaga free_client(clp); 2160b09333c4SRicardo Labiaga return NULL; 2161b09333c4SRicardo Labiaga } 21620162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 216307cd4909SBenny Halevy clp->cl_time = get_seconds(); 2164b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2165b09333c4SRicardo Labiaga copy_verf(clp, verf); 2166b09333c4SRicardo Labiaga rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 2167edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2168c212cecfSStanislav Kinsbursky clp->net = net; 2169b09333c4SRicardo Labiaga return clp; 2170b09333c4SRicardo Labiaga } 2171b09333c4SRicardo Labiaga 2172fd39ca9aSNeilBrown static void 2173ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2174ac55fdc4SJeff Layton { 2175ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2176ac55fdc4SJeff Layton struct nfs4_client *clp; 2177ac55fdc4SJeff Layton 2178ac55fdc4SJeff Layton while (*new) { 2179ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2180ac55fdc4SJeff Layton parent = *new; 2181ac55fdc4SJeff Layton 2182ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2183ac55fdc4SJeff Layton new = &((*new)->rb_left); 2184ac55fdc4SJeff Layton else 2185ac55fdc4SJeff Layton new = &((*new)->rb_right); 2186ac55fdc4SJeff Layton } 2187ac55fdc4SJeff Layton 2188ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2189ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2190ac55fdc4SJeff Layton } 2191ac55fdc4SJeff Layton 2192ac55fdc4SJeff Layton static struct nfs4_client * 2193ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2194ac55fdc4SJeff Layton { 2195ef17af2aSRasmus Villemoes int cmp; 2196ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2197ac55fdc4SJeff Layton struct nfs4_client *clp; 2198ac55fdc4SJeff Layton 2199ac55fdc4SJeff Layton while (node) { 2200ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2201ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2202ac55fdc4SJeff Layton if (cmp > 0) 2203ac55fdc4SJeff Layton node = node->rb_left; 2204ac55fdc4SJeff Layton else if (cmp < 0) 2205ac55fdc4SJeff Layton node = node->rb_right; 2206ac55fdc4SJeff Layton else 2207ac55fdc4SJeff Layton return clp; 2208ac55fdc4SJeff Layton } 2209ac55fdc4SJeff Layton return NULL; 2210ac55fdc4SJeff Layton } 2211ac55fdc4SJeff Layton 2212ac55fdc4SJeff Layton static void 2213ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 22141da177e4SLinus Torvalds { 22151da177e4SLinus Torvalds unsigned int idhashval; 22160a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 22171da177e4SLinus Torvalds 22180a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 22190a880a28STrond Myklebust 2220ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2221a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 22221da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 22230a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 22243dbacee6STrond Myklebust renew_client_locked(clp); 22251da177e4SLinus Torvalds } 22261da177e4SLinus Torvalds 2227fd39ca9aSNeilBrown static void 22281da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 22291da177e4SLinus Torvalds { 22301da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 22318daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 22321da177e4SLinus Torvalds 22330a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 22340a880a28STrond Myklebust 22351da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 22368daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2237a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2238382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2239ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 22403dbacee6STrond Myklebust renew_client_locked(clp); 22411da177e4SLinus Torvalds } 22421da177e4SLinus Torvalds 22431da177e4SLinus Torvalds static struct nfs4_client * 2244bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 22451da177e4SLinus Torvalds { 22461da177e4SLinus Torvalds struct nfs4_client *clp; 22471da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 22481da177e4SLinus Torvalds 2249bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2250a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2251d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2252d15c077eSJ. Bruce Fields return NULL; 22533dbacee6STrond Myklebust renew_client_locked(clp); 22541da177e4SLinus Torvalds return clp; 22551da177e4SLinus Torvalds } 2256a50d2ad1SJ. Bruce Fields } 22571da177e4SLinus Torvalds return NULL; 22581da177e4SLinus Torvalds } 22591da177e4SLinus Torvalds 22601da177e4SLinus Torvalds static struct nfs4_client * 2261bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2262bfa85e83SJ. Bruce Fields { 2263bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2264bfa85e83SJ. Bruce Fields 22650a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2266bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2267bfa85e83SJ. Bruce Fields } 2268bfa85e83SJ. Bruce Fields 2269bfa85e83SJ. Bruce Fields static struct nfs4_client * 22700a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 22711da177e4SLinus Torvalds { 2272bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 22731da177e4SLinus Torvalds 22740a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2275bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 22761da177e4SLinus Torvalds } 22771da177e4SLinus Torvalds 22786e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2279a1bcecd2SAndy Adamson { 22806e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2281a1bcecd2SAndy Adamson } 2282a1bcecd2SAndy Adamson 228328ce6054SNeilBrown static struct nfs4_client * 2284382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 228528ce6054SNeilBrown { 22860a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2287382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 228828ce6054SNeilBrown } 228928ce6054SNeilBrown 229028ce6054SNeilBrown static struct nfs4_client * 2291a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 229228ce6054SNeilBrown { 22930a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2294a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 229528ce6054SNeilBrown } 229628ce6054SNeilBrown 2297fd39ca9aSNeilBrown static void 22986f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 22991da177e4SLinus Torvalds { 230007263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 23016f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 23026f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 23037077ecbaSJeff Layton unsigned short expected_family; 23041da177e4SLinus Torvalds 23057077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 23067077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 23077077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 23087077ecbaSJeff Layton expected_family = AF_INET; 23097077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 23107077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 23117077ecbaSJeff Layton expected_family = AF_INET6; 23127077ecbaSJeff Layton else 23131da177e4SLinus Torvalds goto out_err; 23141da177e4SLinus Torvalds 2315c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2316aa9a4ec7SJeff Layton se->se_callback_addr_len, 231707263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 231807263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2319aa9a4ec7SJeff Layton 232007263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 23211da177e4SLinus Torvalds goto out_err; 2322aa9a4ec7SJeff Layton 232307263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 232407263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2325fbf4665fSJeff Layton 232607263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 232707263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2328849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 23291da177e4SLinus Torvalds return; 23301da177e4SLinus Torvalds out_err: 233107263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 233207263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 23334ab495bfSRasmus Villemoes dprintk("NFSD: this client (clientid %08x/%08x) " 23341da177e4SLinus Torvalds "will not receive delegations\n", 23351da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 23361da177e4SLinus Torvalds 23371da177e4SLinus Torvalds return; 23381da177e4SLinus Torvalds } 23391da177e4SLinus Torvalds 2340074fe897SAndy Adamson /* 2341067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2342074fe897SAndy Adamson */ 2343b607664eSTrond Myklebust static void 2344074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2345074fe897SAndy Adamson { 2346f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2347557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2348557ce264SAndy Adamson unsigned int base; 2349074fe897SAndy Adamson 2350557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2351074fe897SAndy Adamson 2352085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2353557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2354557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 235553da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 235653da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 2357bf864a31SAndy Adamson 2358085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 2359085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 2360bf864a31SAndy Adamson return; 2361bf864a31SAndy Adamson } 2362085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 2363085def3aSJ. Bruce Fields 2364f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2365f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2366f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2367d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 2368d3f03403SDan Carpenter __func__); 2369557ce264SAndy Adamson return; 2370074fe897SAndy Adamson } 2371074fe897SAndy Adamson 2372074fe897SAndy Adamson /* 2373abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2374abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2375abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2376abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2377abfabf8cSAndy Adamson * 2378074fe897SAndy Adamson */ 2379abfabf8cSAndy Adamson static __be32 2380abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2381abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2382074fe897SAndy Adamson { 2383abfabf8cSAndy Adamson struct nfsd4_op *op; 2384abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2385074fe897SAndy Adamson 2386abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2387abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2388abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2389abfabf8cSAndy Adamson 2390085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 2391085def3aSJ. Bruce Fields return op->status; 2392085def3aSJ. Bruce Fields if (args->opcnt == 1) { 2393085def3aSJ. Bruce Fields /* 2394085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 2395085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 2396085def3aSJ. Bruce Fields * original: 2397085def3aSJ. Bruce Fields */ 2398085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 2399085def3aSJ. Bruce Fields } else { 2400abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2401abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2402abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2403074fe897SAndy Adamson } 2404abfabf8cSAndy Adamson return op->status; 2405074fe897SAndy Adamson } 2406074fe897SAndy Adamson 2407074fe897SAndy Adamson /* 2408557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2409557ce264SAndy Adamson * session values. 2410074fe897SAndy Adamson */ 24113ca2eb98SJ. Bruce Fields static __be32 2412bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2413bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2414074fe897SAndy Adamson { 2415557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2416f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2417f5236013SJ. Bruce Fields __be32 *p; 2418074fe897SAndy Adamson __be32 status; 2419074fe897SAndy Adamson 2420557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2421074fe897SAndy Adamson 2422abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 24230da7b19cSJ. Bruce Fields if (status) 2424abfabf8cSAndy Adamson return status; 2425074fe897SAndy Adamson 2426f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2427f5236013SJ. Bruce Fields if (!p) { 2428f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2429f5236013SJ. Bruce Fields return nfserr_serverfault; 2430f5236013SJ. Bruce Fields } 2431f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2432f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2433074fe897SAndy Adamson 2434557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2435f5236013SJ. Bruce Fields return slot->sl_status; 2436074fe897SAndy Adamson } 2437074fe897SAndy Adamson 24380733d213SAndy Adamson /* 24390733d213SAndy Adamson * Set the exchange_id flags returned by the server. 24400733d213SAndy Adamson */ 24410733d213SAndy Adamson static void 24420733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 24430733d213SAndy Adamson { 24449cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 24459cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 24469cf514ccSChristoph Hellwig #else 24470733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 24489cf514ccSChristoph Hellwig #endif 24490733d213SAndy Adamson 24500733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 24510733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 24520733d213SAndy Adamson 24530733d213SAndy Adamson /* set the wire flags to return to client. */ 24540733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 24550733d213SAndy Adamson } 24560733d213SAndy Adamson 24574eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 24584eaea134SJ. Bruce Fields { 24594eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 24604eaea134SJ. Bruce Fields 24614eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 24624eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 24634eaea134SJ. Bruce Fields return true; 24644eaea134SJ. Bruce Fields } 24654eaea134SJ. Bruce Fields return false; 24664eaea134SJ. Bruce Fields } 24674eaea134SJ. Bruce Fields 2468631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 2469631fc9eaSJ. Bruce Fields { 24704eaea134SJ. Bruce Fields return client_has_openowners(clp) 247147e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 247247e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 247347e970beSKinglong Mee #endif 24746eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 24756eccece9SJ. Bruce Fields || !list_empty(&clp->cl_sessions); 2476631fc9eaSJ. Bruce Fields } 2477631fc9eaSJ. Bruce Fields 2478b37ad28bSAl Viro __be32 2479eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 2480eb69853dSChristoph Hellwig union nfsd4_op_u *u) 2481069b6ad4SAndy Adamson { 2482eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 24833dbacee6STrond Myklebust struct nfs4_client *conf, *new; 24843dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 248557b7b43bSJ. Bruce Fields __be32 status; 2486363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 24870733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 2488363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 248983e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 2490c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 24910733d213SAndy Adamson 2492363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 24930733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 2494363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 24950733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 2496363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 24970733d213SAndy Adamson 2498a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 24990733d213SAndy Adamson return nfserr_inval; 25000733d213SAndy Adamson 250150c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 250250c7b948SJ. Bruce Fields if (new == NULL) 250350c7b948SJ. Bruce Fields return nfserr_jukebox; 250450c7b948SJ. Bruce Fields 25050733d213SAndy Adamson switch (exid->spa_how) { 250657266a6eSJ. Bruce Fields case SP4_MACH_CRED: 2507ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 2508ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 2509ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 2510ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 2511ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 2512ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 2513ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 2514ed941643SAndrew Elble 2515ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 2516ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 2517ed941643SAndrew Elble 1 << (OP_LOCKU) | 2518ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 2519ed941643SAndrew Elble 2520ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 2521ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 2522ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 252350c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 252450c7b948SJ. Bruce Fields status = nfserr_inval; 252550c7b948SJ. Bruce Fields goto out_nolock; 252650c7b948SJ. Bruce Fields } 2527920dd9bbSJ. Bruce Fields /* 2528920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 2529920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 2530920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 2531920dd9bbSJ. Bruce Fields */ 2532414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 2533414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 2534920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 2535920dd9bbSJ. Bruce Fields goto out_nolock; 2536920dd9bbSJ. Bruce Fields } 253750c7b948SJ. Bruce Fields new->cl_mach_cred = true; 25380733d213SAndy Adamson case SP4_NONE: 25390733d213SAndy Adamson break; 2540063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 2541063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 25420733d213SAndy Adamson case SP4_SSV: 25438edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 25448edf4b02SKinglong Mee goto out_nolock; 25450733d213SAndy Adamson } 25460733d213SAndy Adamson 25472dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 25483dbacee6STrond Myklebust spin_lock(&nn->client_lock); 2549382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 25500733d213SAndy Adamson if (conf) { 255183e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 255283e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 255383e08fd4SJ. Bruce Fields 2554136e658dSJ. Bruce Fields if (update) { 2555136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 25562dbb269dSJ. Bruce Fields status = nfserr_inval; 2557e203d506SJ. Bruce Fields goto out; 2558e203d506SJ. Bruce Fields } 2559dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 256057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 256157266a6eSJ. Bruce Fields goto out; 256257266a6eSJ. Bruce Fields } 25632dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 25640733d213SAndy Adamson status = nfserr_perm; 25650733d213SAndy Adamson goto out; 25660733d213SAndy Adamson } 25672dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 25680733d213SAndy Adamson status = nfserr_not_same; 25690733d213SAndy Adamson goto out; 25700733d213SAndy Adamson } 2571136e658dSJ. Bruce Fields /* case 6 */ 25720733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 25730733d213SAndy Adamson goto out_copy; 25746ddbbbfeSMike Sager } 2575136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 2576631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 2577136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 2578136e658dSJ. Bruce Fields goto out; 2579136e658dSJ. Bruce Fields } 2580b9831b59SJ. Bruce Fields goto out_new; 2581631fc9eaSJ. Bruce Fields } 2582136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 25830f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 2584136e658dSJ. Bruce Fields goto out_copy; 2585136e658dSJ. Bruce Fields } 25862dbb269dSJ. Bruce Fields /* case 5, client reboot */ 25873dbacee6STrond Myklebust conf = NULL; 25880733d213SAndy Adamson goto out_new; 25890733d213SAndy Adamson } 25906ddbbbfeSMike Sager 25912dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 25920733d213SAndy Adamson status = nfserr_noent; 25930733d213SAndy Adamson goto out; 25940733d213SAndy Adamson } 25950733d213SAndy Adamson 2596a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 25972dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 25983dbacee6STrond Myklebust unhash_client_locked(unconf); 25990733d213SAndy Adamson 26002dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 26010733d213SAndy Adamson out_new: 2602fd699b8aSJeff Layton if (conf) { 2603fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 2604fd699b8aSJeff Layton if (status) 2605fd699b8aSJeff Layton goto out; 2606fd699b8aSJeff Layton } 26074f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 2608ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 2609ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 26100733d213SAndy Adamson 2611c212cecfSStanislav Kinsbursky gen_clid(new, nn); 2612ac55fdc4SJeff Layton add_to_unconfirmed(new); 26133dbacee6STrond Myklebust swap(new, conf); 26140733d213SAndy Adamson out_copy: 26155cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 26165cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 26170733d213SAndy Adamson 26185cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 26195cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 26200733d213SAndy Adamson 26210733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 26225cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 26230733d213SAndy Adamson status = nfs_ok; 26240733d213SAndy Adamson 26250733d213SAndy Adamson out: 26263dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 262750c7b948SJ. Bruce Fields out_nolock: 26285cc40fd7STrond Myklebust if (new) 26293dbacee6STrond Myklebust expire_client(new); 26303dbacee6STrond Myklebust if (unconf) 26313dbacee6STrond Myklebust expire_client(unconf); 26320733d213SAndy Adamson return status; 2633069b6ad4SAndy Adamson } 2634069b6ad4SAndy Adamson 263557b7b43bSJ. Bruce Fields static __be32 263688e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 2637b85d4c01SBenny Halevy { 263888e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 263988e588d5SAndy Adamson slot_seqid); 2640b85d4c01SBenny Halevy 2641b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 264288e588d5SAndy Adamson if (slot_inuse) { 264388e588d5SAndy Adamson if (seqid == slot_seqid) 2644b85d4c01SBenny Halevy return nfserr_jukebox; 2645b85d4c01SBenny Halevy else 2646b85d4c01SBenny Halevy return nfserr_seq_misordered; 2647b85d4c01SBenny Halevy } 2648f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 264988e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 2650b85d4c01SBenny Halevy return nfs_ok; 265188e588d5SAndy Adamson if (seqid == slot_seqid) 2652b85d4c01SBenny Halevy return nfserr_replay_cache; 2653b85d4c01SBenny Halevy return nfserr_seq_misordered; 2654b85d4c01SBenny Halevy } 2655b85d4c01SBenny Halevy 265649557cc7SAndy Adamson /* 265749557cc7SAndy Adamson * Cache the create session result into the create session single DRC 265849557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 265949557cc7SAndy Adamson * Do this for solo or embedded create session operations. 266049557cc7SAndy Adamson */ 266149557cc7SAndy Adamson static void 266249557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 266357b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 266449557cc7SAndy Adamson { 266549557cc7SAndy Adamson slot->sl_status = nfserr; 266649557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 266749557cc7SAndy Adamson } 266849557cc7SAndy Adamson 266949557cc7SAndy Adamson static __be32 267049557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 267149557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 267249557cc7SAndy Adamson { 267349557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 267449557cc7SAndy Adamson return slot->sl_status; 267549557cc7SAndy Adamson } 267649557cc7SAndy Adamson 26771b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 26781b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 26791b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 26801b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 26811b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 26821b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 26831b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 26841b74c25bSMi Jinlong 26851b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 26861b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 26871b74c25bSMi Jinlong 1 + /* status */ \ 26881b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 26891b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 26901b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 26911b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 26921b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 26931b74c25bSMi Jinlong 269455c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 26951b74c25bSMi Jinlong { 269655c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 269755c760cfSJ. Bruce Fields 2698373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 2699373cd409SJ. Bruce Fields return nfserr_toosmall; 2700373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 2701373cd409SJ. Bruce Fields return nfserr_toosmall; 270255c760cfSJ. Bruce Fields ca->headerpadsz = 0; 270355c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 270455c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 270555c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 270655c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 270755c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 270855c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 270955c760cfSJ. Bruce Fields /* 271055c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 271155c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 271255c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 271355c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 271455c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 271555c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 271655c760cfSJ. Bruce Fields */ 271755c760cfSJ. Bruce Fields ca->maxreqs = nfsd4_get_drc_mem(ca); 271855c760cfSJ. Bruce Fields if (!ca->maxreqs) 271955c760cfSJ. Bruce Fields return nfserr_jukebox; 272055c760cfSJ. Bruce Fields 2721373cd409SJ. Bruce Fields return nfs_ok; 27221b74c25bSMi Jinlong } 27231b74c25bSMi Jinlong 27244500632fSChuck Lever /* 27254500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 27264500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 27274500632fSChuck Lever */ 27284500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 27294500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 27304500632fSChuck Lever 27314500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 27324500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 27334500632fSChuck Lever 27348a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 27354500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 27368a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 27374500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 27384500632fSChuck Lever sizeof(__be32)) 27398a891633SKinglong Mee 274006b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 274106b332a5SJ. Bruce Fields { 274206b332a5SJ. Bruce Fields ca->headerpadsz = 0; 274306b332a5SJ. Bruce Fields 27448a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 274506b332a5SJ. Bruce Fields return nfserr_toosmall; 27468a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 274706b332a5SJ. Bruce Fields return nfserr_toosmall; 274806b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 274906b332a5SJ. Bruce Fields if (ca->maxops < 2) 275006b332a5SJ. Bruce Fields return nfserr_toosmall; 275106b332a5SJ. Bruce Fields 275206b332a5SJ. Bruce Fields return nfs_ok; 2753069b6ad4SAndy Adamson } 2754069b6ad4SAndy Adamson 2755b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 2756b78724b7SJ. Bruce Fields { 2757b78724b7SJ. Bruce Fields switch (cbs->flavor) { 2758b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 2759b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 2760b78724b7SJ. Bruce Fields return nfs_ok; 2761b78724b7SJ. Bruce Fields default: 2762b78724b7SJ. Bruce Fields /* 2763b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 2764b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 2765b78724b7SJ. Bruce Fields * GSS. 2766b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 2767b78724b7SJ. Bruce Fields * client might think it can already handle: 2768b78724b7SJ. Bruce Fields */ 2769b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 2770b78724b7SJ. Bruce Fields } 2771b78724b7SJ. Bruce Fields } 2772b78724b7SJ. Bruce Fields 2773069b6ad4SAndy Adamson __be32 2774069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 2775eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 2776069b6ad4SAndy Adamson { 2777eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 2778363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 2779ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 2780d20c11d8SJeff Layton struct nfs4_client *old = NULL; 2781ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 278281f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 278349557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 278457b7b43bSJ. Bruce Fields __be32 status = 0; 27858daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2786ec6b5d7bSAndy Adamson 2787a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 2788a62573dcSMi Jinlong return nfserr_inval; 2789b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 2790b78724b7SJ. Bruce Fields if (status) 2791b78724b7SJ. Bruce Fields return status; 279255c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 2793373cd409SJ. Bruce Fields if (status) 2794373cd409SJ. Bruce Fields return status; 279506b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 279606b332a5SJ. Bruce Fields if (status) 2797f403e450SKinglong Mee goto out_release_drc_mem; 279881f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 279960810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 280055c760cfSJ. Bruce Fields if (!new) 280155c760cfSJ. Bruce Fields goto out_release_drc_mem; 280281f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 280381f0b2a4SJ. Bruce Fields if (!conn) 280481f0b2a4SJ. Bruce Fields goto out_free_session; 2805a62573dcSMi Jinlong 2806d20c11d8SJeff Layton spin_lock(&nn->client_lock); 28070a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 28088daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 280978389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 2810ec6b5d7bSAndy Adamson 2811ec6b5d7bSAndy Adamson if (conf) { 281257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 2813dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 281457266a6eSJ. Bruce Fields goto out_free_conn; 281549557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 281649557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 2817f5e22bb6SKinglong Mee if (status) { 2818f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 281949557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 282081f0b2a4SJ. Bruce Fields goto out_free_conn; 2821ec6b5d7bSAndy Adamson } 2822ec6b5d7bSAndy Adamson } else if (unconf) { 2823ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 2824363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 2825ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 282681f0b2a4SJ. Bruce Fields goto out_free_conn; 2827ec6b5d7bSAndy Adamson } 282857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 2829dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 283057266a6eSJ. Bruce Fields goto out_free_conn; 283149557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 283249557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 283338eb76a5SAndy Adamson if (status) { 283438eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 2835ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 283681f0b2a4SJ. Bruce Fields goto out_free_conn; 2837ec6b5d7bSAndy Adamson } 2838382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 2839221a6876SJ. Bruce Fields if (old) { 2840d20c11d8SJeff Layton status = mark_client_expired_locked(old); 28417abea1e8SJeff Layton if (status) { 28427abea1e8SJeff Layton old = NULL; 2843221a6876SJ. Bruce Fields goto out_free_conn; 2844221a6876SJ. Bruce Fields } 28457abea1e8SJeff Layton } 28468f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 2847ec6b5d7bSAndy Adamson conf = unconf; 2848ec6b5d7bSAndy Adamson } else { 2849ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 285081f0b2a4SJ. Bruce Fields goto out_free_conn; 2851ec6b5d7bSAndy Adamson } 285281f0b2a4SJ. Bruce Fields status = nfs_ok; 28534ce85c8cSChuck Lever /* Persistent sessions are not supported */ 2854408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 28554ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 2856408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 2857408b79bcSJ. Bruce Fields 285881f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 2859d20c11d8SJeff Layton nfsd4_get_session_locked(new); 286081f0b2a4SJ. Bruce Fields 2861ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 2862ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 286386c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 286449557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 2865ec6b5d7bSAndy Adamson 2866d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 286749557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 2868d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 2869d20c11d8SJeff Layton /* init connection and backchannel */ 2870d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 2871d20c11d8SJeff Layton nfsd4_put_session(new); 2872d20c11d8SJeff Layton if (old) 2873d20c11d8SJeff Layton expire_client(old); 2874ec6b5d7bSAndy Adamson return status; 287581f0b2a4SJ. Bruce Fields out_free_conn: 2876d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 287781f0b2a4SJ. Bruce Fields free_conn(conn); 2878d20c11d8SJeff Layton if (old) 2879d20c11d8SJeff Layton expire_client(old); 288081f0b2a4SJ. Bruce Fields out_free_session: 288181f0b2a4SJ. Bruce Fields __free_session(new); 288255c760cfSJ. Bruce Fields out_release_drc_mem: 288355c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 28841ca50792SJ. Bruce Fields return status; 2885069b6ad4SAndy Adamson } 2886069b6ad4SAndy Adamson 28871d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 28881d1bc8f2SJ. Bruce Fields { 28891d1bc8f2SJ. Bruce Fields switch (*dir) { 28901d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 28911d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 28921d1bc8f2SJ. Bruce Fields return nfs_ok; 28931d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 28941d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 28951d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 28961d1bc8f2SJ. Bruce Fields return nfs_ok; 28971d1bc8f2SJ. Bruce Fields }; 28981d1bc8f2SJ. Bruce Fields return nfserr_inval; 28991d1bc8f2SJ. Bruce Fields } 29001d1bc8f2SJ. Bruce Fields 2901eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 2902eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 2903eb69853dSChristoph Hellwig union nfsd4_op_u *u) 2904cb73a9f4SJ. Bruce Fields { 2905eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 2906cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 2907c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 2908b78724b7SJ. Bruce Fields __be32 status; 2909cb73a9f4SJ. Bruce Fields 2910b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 2911b78724b7SJ. Bruce Fields if (status) 2912b78724b7SJ. Bruce Fields return status; 2913c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2914cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 2915cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 2916c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2917cb73a9f4SJ. Bruce Fields 2918cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 2919cb73a9f4SJ. Bruce Fields 2920cb73a9f4SJ. Bruce Fields return nfs_ok; 2921cb73a9f4SJ. Bruce Fields } 2922cb73a9f4SJ. Bruce Fields 29231d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 29241d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 2925eb69853dSChristoph Hellwig union nfsd4_op_u *u) 29261d1bc8f2SJ. Bruce Fields { 2927eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 29281d1bc8f2SJ. Bruce Fields __be32 status; 29293ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 29304f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 2931d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 2932d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 29331d1bc8f2SJ. Bruce Fields 29341d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 29351d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 2936c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2937d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 2938c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 29394f6e6c17SJ. Bruce Fields if (!session) 2940d4e19e70STrond Myklebust goto out_no_session; 294157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 2942dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 294357266a6eSJ. Bruce Fields goto out; 29441d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 29453ba63671SJ. Bruce Fields if (status) 29464f6e6c17SJ. Bruce Fields goto out; 29473ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 29484f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 29493ba63671SJ. Bruce Fields if (!conn) 29504f6e6c17SJ. Bruce Fields goto out; 29514f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 29524f6e6c17SJ. Bruce Fields status = nfs_ok; 29534f6e6c17SJ. Bruce Fields out: 2954d4e19e70STrond Myklebust nfsd4_put_session(session); 2955d4e19e70STrond Myklebust out_no_session: 29564f6e6c17SJ. Bruce Fields return status; 29571d1bc8f2SJ. Bruce Fields } 29581d1bc8f2SJ. Bruce Fields 2959665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 29605d4cec2fSJ. Bruce Fields { 2961665d5072SJ. Bruce Fields if (!cstate->session) 296251d87bc2SFengguang Wu return false; 2963665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 29645d4cec2fSJ. Bruce Fields } 29655d4cec2fSJ. Bruce Fields 2966069b6ad4SAndy Adamson __be32 2967eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 2968eb69853dSChristoph Hellwig union nfsd4_op_u *u) 2969069b6ad4SAndy Adamson { 2970ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 2971e10e0cfcSBenny Halevy struct nfsd4_session *ses; 2972abcdff09SJ. Bruce Fields __be32 status; 2973f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 2974d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 2975d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2976e10e0cfcSBenny Halevy 2977abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 2978ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 297957716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 2980abcdff09SJ. Bruce Fields goto out; 2981f0f51f5cSJ. Bruce Fields ref_held_by_me++; 298257716355SJ. Bruce Fields } 2983ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 2984c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 2985ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 2986abcdff09SJ. Bruce Fields if (!ses) 2987abcdff09SJ. Bruce Fields goto out_client_lock; 298857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 2989dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 2990d4e19e70STrond Myklebust goto out_put_session; 2991f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 299266b2b9b2SJ. Bruce Fields if (status) 2993f0f51f5cSJ. Bruce Fields goto out_put_session; 2994e10e0cfcSBenny Halevy unhash_session(ses); 2995c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 2996e10e0cfcSBenny Halevy 299784f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 299819cf5c02SJ. Bruce Fields 2999c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3000e10e0cfcSBenny Halevy status = nfs_ok; 3001f0f51f5cSJ. Bruce Fields out_put_session: 3002d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3003abcdff09SJ. Bruce Fields out_client_lock: 3004abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3005e10e0cfcSBenny Halevy out: 3006e10e0cfcSBenny Halevy return status; 3007069b6ad4SAndy Adamson } 3008069b6ad4SAndy Adamson 3009a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3010328ead28SJ. Bruce Fields { 3011328ead28SJ. Bruce Fields struct nfsd4_conn *c; 3012328ead28SJ. Bruce Fields 3013328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3014a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 3015328ead28SJ. Bruce Fields return c; 3016328ead28SJ. Bruce Fields } 3017328ead28SJ. Bruce Fields } 3018328ead28SJ. Bruce Fields return NULL; 3019328ead28SJ. Bruce Fields } 3020328ead28SJ. Bruce Fields 302157266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3022328ead28SJ. Bruce Fields { 3023328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3024a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 302557266a6eSJ. Bruce Fields __be32 status = nfs_ok; 302621b75b01SJ. Bruce Fields int ret; 3027328ead28SJ. Bruce Fields 3028328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3029a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 303057266a6eSJ. Bruce Fields if (c) 303157266a6eSJ. Bruce Fields goto out_free; 303257266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 303357266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 303457266a6eSJ. Bruce Fields goto out_free; 3035328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3036328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 303721b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 303821b75b01SJ. Bruce Fields if (ret) 303921b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 304021b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 304157266a6eSJ. Bruce Fields return nfs_ok; 304257266a6eSJ. Bruce Fields out_free: 304357266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 304457266a6eSJ. Bruce Fields free_conn(new); 304557266a6eSJ. Bruce Fields return status; 3046328ead28SJ. Bruce Fields } 3047328ead28SJ. Bruce Fields 3048868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3049868b89c3SMi Jinlong { 3050868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3051868b89c3SMi Jinlong 3052868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3053868b89c3SMi Jinlong } 3054868b89c3SMi Jinlong 3055ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3056ae82a8d0SMi Jinlong struct nfsd4_session *session) 3057ae82a8d0SMi Jinlong { 3058ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3059ae82a8d0SMi Jinlong 3060ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3061ae82a8d0SMi Jinlong } 3062ae82a8d0SMi Jinlong 306353da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 306453da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 306553da6a53SJ. Bruce Fields { 306653da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 306753da6a53SJ. Bruce Fields 306853da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 306953da6a53SJ. Bruce Fields (bool)seq->cachethis) 307053da6a53SJ. Bruce Fields return false; 307153da6a53SJ. Bruce Fields /* 307253da6a53SJ. Bruce Fields * If there's an error than the reply can have fewer ops than 307353da6a53SJ. Bruce Fields * the call. But if we cached a reply with *more* ops than the 307453da6a53SJ. Bruce Fields * call you're sending us now, then this new call is clearly not 307553da6a53SJ. Bruce Fields * really a replay of the old one: 307653da6a53SJ. Bruce Fields */ 307753da6a53SJ. Bruce Fields if (slot->sl_opcnt < argp->opcnt) 307853da6a53SJ. Bruce Fields return false; 307953da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 308053da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 308153da6a53SJ. Bruce Fields return false; 308253da6a53SJ. Bruce Fields /* 308353da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 308453da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 308553da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 308653da6a53SJ. Bruce Fields * the reply), so we don't bother. 308753da6a53SJ. Bruce Fields */ 308853da6a53SJ. Bruce Fields return true; 308953da6a53SJ. Bruce Fields } 309053da6a53SJ. Bruce Fields 3091069b6ad4SAndy Adamson __be32 3092eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3093eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3094069b6ad4SAndy Adamson { 3095eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3096f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 309747ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3098b85d4c01SBenny Halevy struct nfsd4_session *session; 3099221a6876SJ. Bruce Fields struct nfs4_client *clp; 3100b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3101a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 310257b7b43bSJ. Bruce Fields __be32 status; 310347ee5298SJ. Bruce Fields int buflen; 3104d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3105d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3106b85d4c01SBenny Halevy 3107f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3108f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3109f9bb94c4SAndy Adamson 3110a663bdd8SJ. Bruce Fields /* 3111a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3112a663bdd8SJ. Bruce Fields * below. 3113a663bdd8SJ. Bruce Fields */ 3114a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3115a663bdd8SJ. Bruce Fields if (!conn) 3116a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3117a663bdd8SJ. Bruce Fields 3118c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3119d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3120b85d4c01SBenny Halevy if (!session) 3121221a6876SJ. Bruce Fields goto out_no_session; 3122221a6876SJ. Bruce Fields clp = session->se_client; 3123b85d4c01SBenny Halevy 3124868b89c3SMi Jinlong status = nfserr_too_many_ops; 3125868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 312666b2b9b2SJ. Bruce Fields goto out_put_session; 3127868b89c3SMi Jinlong 3128ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3129ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 313066b2b9b2SJ. Bruce Fields goto out_put_session; 3131ae82a8d0SMi Jinlong 3132b85d4c01SBenny Halevy status = nfserr_badslot; 31336c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 313466b2b9b2SJ. Bruce Fields goto out_put_session; 3135b85d4c01SBenny Halevy 3136557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3137b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3138b85d4c01SBenny Halevy 3139a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3140a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3141a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3142a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 3143a8dfdaebSAndy Adamson 314473e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 314573e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 3146b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 3147bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 3148bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 314966b2b9b2SJ. Bruce Fields goto out_put_session; 315053da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 315153da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 315253da6a53SJ. Bruce Fields goto out_put_session; 3153b85d4c01SBenny Halevy cstate->slot = slot; 3154b85d4c01SBenny Halevy cstate->session = session; 31554b24ca7dSJeff Layton cstate->clp = clp; 3156da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 3157557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 3158bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 3159da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 3160aaf84eb9SBenny Halevy goto out; 3161b85d4c01SBenny Halevy } 3162b85d4c01SBenny Halevy if (status) 316366b2b9b2SJ. Bruce Fields goto out_put_session; 3164b85d4c01SBenny Halevy 316557266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 3166a663bdd8SJ. Bruce Fields conn = NULL; 316757266a6eSJ. Bruce Fields if (status) 316857266a6eSJ. Bruce Fields goto out_put_session; 3169328ead28SJ. Bruce Fields 317047ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 317147ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 317247ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 317347ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 317447ee5298SJ. Bruce Fields nfserr_rep_too_big; 3175a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 317647ee5298SJ. Bruce Fields goto out_put_session; 317732aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 317847ee5298SJ. Bruce Fields 317947ee5298SJ. Bruce Fields status = nfs_ok; 3180b85d4c01SBenny Halevy /* Success! bump slot seqid */ 3181b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 3182bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 318373e79482SJ. Bruce Fields if (seq->cachethis) 318473e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 3185bf5c43c8SJ. Bruce Fields else 3186bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 3187b85d4c01SBenny Halevy 3188b85d4c01SBenny Halevy cstate->slot = slot; 3189b85d4c01SBenny Halevy cstate->session = session; 31904b24ca7dSJeff Layton cstate->clp = clp; 3191b85d4c01SBenny Halevy 3192b85d4c01SBenny Halevy out: 31935423732aSBenny Halevy switch (clp->cl_cb_state) { 31945423732aSBenny Halevy case NFSD4_CB_DOWN: 3195fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 31965423732aSBenny Halevy break; 31975423732aSBenny Halevy case NFSD4_CB_FAULT: 3198fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 31995423732aSBenny Halevy break; 3200fc0c3dd1SBenny Halevy default: 3201fc0c3dd1SBenny Halevy seq->status_flags = 0; 32025423732aSBenny Halevy } 32033bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 32043bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 3205221a6876SJ. Bruce Fields out_no_session: 32063f42d2c4SKinglong Mee if (conn) 32073f42d2c4SKinglong Mee free_conn(conn); 3208c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3209b85d4c01SBenny Halevy return status; 321066b2b9b2SJ. Bruce Fields out_put_session: 3211d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 3212221a6876SJ. Bruce Fields goto out_no_session; 3213069b6ad4SAndy Adamson } 3214069b6ad4SAndy Adamson 3215b607664eSTrond Myklebust void 3216b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 3217b607664eSTrond Myklebust { 3218b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 3219b607664eSTrond Myklebust 3220b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 3221b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 3222b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 3223b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3224b607664eSTrond Myklebust } 3225d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 3226b607664eSTrond Myklebust nfsd4_put_session(cs->session); 32274b24ca7dSJeff Layton } else if (cs->clp) 32284b24ca7dSJeff Layton put_client_renew(cs->clp); 3229b607664eSTrond Myklebust } 3230b607664eSTrond Myklebust 3231345c2842SMi Jinlong __be32 3232eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 3233eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3234eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3235345c2842SMi Jinlong { 3236eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 32376b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 32386b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 323957b7b43bSJ. Bruce Fields __be32 status = 0; 32408daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3241345c2842SMi Jinlong 32426b10ad19STrond Myklebust spin_lock(&nn->client_lock); 32430a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 32448daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 324578389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3246345c2842SMi Jinlong 3247345c2842SMi Jinlong if (conf) { 3248c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 3249345c2842SMi Jinlong status = nfserr_clientid_busy; 3250345c2842SMi Jinlong goto out; 3251345c2842SMi Jinlong } 3252fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3253fd699b8aSJeff Layton if (status) 3254fd699b8aSJeff Layton goto out; 32556b10ad19STrond Myklebust clp = conf; 3256345c2842SMi Jinlong } else if (unconf) 3257345c2842SMi Jinlong clp = unconf; 3258345c2842SMi Jinlong else { 3259345c2842SMi Jinlong status = nfserr_stale_clientid; 3260345c2842SMi Jinlong goto out; 3261345c2842SMi Jinlong } 3262dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 32636b10ad19STrond Myklebust clp = NULL; 326457266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 326557266a6eSJ. Bruce Fields goto out; 326657266a6eSJ. Bruce Fields } 32676b10ad19STrond Myklebust unhash_client_locked(clp); 3268345c2842SMi Jinlong out: 32696b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 32706b10ad19STrond Myklebust if (clp) 32716b10ad19STrond Myklebust expire_client(clp); 3272345c2842SMi Jinlong return status; 3273345c2842SMi Jinlong } 3274345c2842SMi Jinlong 3275069b6ad4SAndy Adamson __be32 3276eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 3277eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 32784dc6ec00SJ. Bruce Fields { 3279eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 328057b7b43bSJ. Bruce Fields __be32 status = 0; 3281bcecf1ccSMi Jinlong 32824dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 32834dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 32844dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 32854dc6ec00SJ. Bruce Fields /* 32864dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 32874dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 32884dc6ec00SJ. Bruce Fields */ 32894dc6ec00SJ. Bruce Fields return nfs_ok; 32904dc6ec00SJ. Bruce Fields } 3291bcecf1ccSMi Jinlong 3292bcecf1ccSMi Jinlong status = nfserr_complete_already; 3293a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 3294a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 3295bcecf1ccSMi Jinlong goto out; 3296bcecf1ccSMi Jinlong 3297bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 3298bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 32994dc6ec00SJ. Bruce Fields /* 33004dc6ec00SJ. Bruce Fields * The following error isn't really legal. 33014dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 33024dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 33034dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 33044dc6ec00SJ. Bruce Fields * client. 33054dc6ec00SJ. Bruce Fields */ 3306bcecf1ccSMi Jinlong goto out; 3307bcecf1ccSMi Jinlong 3308bcecf1ccSMi Jinlong status = nfs_ok; 33092a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 3310bcecf1ccSMi Jinlong out: 3311bcecf1ccSMi Jinlong return status; 33124dc6ec00SJ. Bruce Fields } 33134dc6ec00SJ. Bruce Fields 33144dc6ec00SJ. Bruce Fields __be32 3315b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3316eb69853dSChristoph Hellwig union nfsd4_op_u *u) 33171da177e4SLinus Torvalds { 3318eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 3319a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 33201da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 33213dbacee6STrond Myklebust struct nfs4_client *conf, *new; 33223dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 3323b37ad28bSAl Viro __be32 status; 3324c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3325a55370a3SNeilBrown 33265cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 33275cc40fd7STrond Myklebust if (new == NULL) 33285cc40fd7STrond Myklebust return nfserr_jukebox; 332963db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 33303dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3331382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 33322b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 333363db4632SJ. Bruce Fields /* case 0: */ 33341da177e4SLinus Torvalds status = nfserr_clid_inuse; 3335e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 3336e203d506SJ. Bruce Fields goto out; 3337026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 3338363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 3339363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 3340363168b4SJeff Layton sizeof(addr_str)); 3341026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 3342363168b4SJeff Layton "at %s\n", addr_str); 33431da177e4SLinus Torvalds goto out; 33441da177e4SLinus Torvalds } 33451da177e4SLinus Torvalds } 3346a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 33471da177e4SLinus Torvalds if (unconf) 33483dbacee6STrond Myklebust unhash_client_locked(unconf); 334941eb1670SKinglong Mee if (conf && same_verf(&conf->cl_verifier, &clverifier)) { 335063db4632SJ. Bruce Fields /* case 1: probable callback update */ 33511da177e4SLinus Torvalds copy_clid(new, conf); 335241eb1670SKinglong Mee gen_confirm(new, nn); 335341eb1670SKinglong Mee } else /* case 4 (new client) or cases 2, 3 (client reboot): */ 3354c212cecfSStanislav Kinsbursky gen_clid(new, nn); 33558323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 33566f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 3357ac55fdc4SJeff Layton add_to_unconfirmed(new); 33581da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 33591da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 33601da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 33615cc40fd7STrond Myklebust new = NULL; 33621da177e4SLinus Torvalds status = nfs_ok; 33631da177e4SLinus Torvalds out: 33643dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 33655cc40fd7STrond Myklebust if (new) 33665cc40fd7STrond Myklebust free_client(new); 33673dbacee6STrond Myklebust if (unconf) 33683dbacee6STrond Myklebust expire_client(unconf); 33691da177e4SLinus Torvalds return status; 33701da177e4SLinus Torvalds } 33711da177e4SLinus Torvalds 33721da177e4SLinus Torvalds 3373b37ad28bSAl Viro __be32 3374b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 3375b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 3376eb69853dSChristoph Hellwig union nfsd4_op_u *u) 33771da177e4SLinus Torvalds { 3378eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 3379eb69853dSChristoph Hellwig &u->setclientid_confirm; 338021ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 3381d20c11d8SJeff Layton struct nfs4_client *old = NULL; 33821da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 33831da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 3384b37ad28bSAl Viro __be32 status; 33857f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 33861da177e4SLinus Torvalds 33872c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 33881da177e4SLinus Torvalds return nfserr_stale_clientid; 338921ab45a4SNeilBrown 3390d20c11d8SJeff Layton spin_lock(&nn->client_lock); 33918daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 33920a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 3393a186e767SJ. Bruce Fields /* 33948695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 33958695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 3396f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 3397f984a7ceSJ. Bruce Fields * 3398f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 3399a186e767SJ. Bruce Fields */ 3400f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 34018695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 34028695b90aSJ. Bruce Fields goto out; 34038695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 34048695b90aSJ. Bruce Fields goto out; 340563db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 340690d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 34077d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 34087d22fc11SJ. Bruce Fields /* case 2: probable retransmit */ 340990d700b7SJ. Bruce Fields status = nfs_ok; 34107d22fc11SJ. Bruce Fields } else /* case 4: client hasn't noticed we rebooted yet? */ 341190d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 341290d700b7SJ. Bruce Fields goto out; 341390d700b7SJ. Bruce Fields } 341490d700b7SJ. Bruce Fields status = nfs_ok; 341590d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 3416d20c11d8SJeff Layton old = unconf; 3417d20c11d8SJeff Layton unhash_client_locked(old); 34185a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 341990d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 3420d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3421d20c11d8SJeff Layton if (old) { 34222b634821SJ. Bruce Fields status = nfserr_clid_inuse; 34232b634821SJ. Bruce Fields if (client_has_state(old) 34242b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 34252b634821SJ. Bruce Fields &old->cl_cred)) 34262b634821SJ. Bruce Fields goto out; 3427d20c11d8SJeff Layton status = mark_client_expired_locked(old); 34287abea1e8SJeff Layton if (status) { 34297abea1e8SJeff Layton old = NULL; 3430221a6876SJ. Bruce Fields goto out; 3431221a6876SJ. Bruce Fields } 34327abea1e8SJeff Layton } 34331da177e4SLinus Torvalds move_to_confirmed(unconf); 3434d20c11d8SJeff Layton conf = unconf; 343508e8987cSNeilBrown } 3436d20c11d8SJeff Layton get_client_locked(conf); 3437d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3438d20c11d8SJeff Layton nfsd4_probe_callback(conf); 3439d20c11d8SJeff Layton spin_lock(&nn->client_lock); 3440d20c11d8SJeff Layton put_client_renew_locked(conf); 34411da177e4SLinus Torvalds out: 3442d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3443d20c11d8SJeff Layton if (old) 3444d20c11d8SJeff Layton expire_client(old); 34451da177e4SLinus Torvalds return status; 34461da177e4SLinus Torvalds } 34471da177e4SLinus Torvalds 344832513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 34491da177e4SLinus Torvalds { 345032513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 345132513b40SJ. Bruce Fields } 345232513b40SJ. Bruce Fields 345332513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 34545b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, 34555b095e99SJeff Layton struct nfs4_file *fp) 345632513b40SJ. Bruce Fields { 3457950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3458950e0118STrond Myklebust 3459818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 34601d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 34618beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 34628beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 34638287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 3464e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 34650c637be8SJeff Layton fp->fi_deleg_file = NULL; 346647f9940cSMeelap Shah fp->fi_had_conflict = false; 3467baeb4ff0SJeff Layton fp->fi_share_deny = 0; 3468f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 3469f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 34709cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 34719cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 3472c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 34739cf514ccSChristoph Hellwig #endif 34745b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 34751da177e4SLinus Torvalds } 34761da177e4SLinus Torvalds 3477e8ff2a84SJ. Bruce Fields void 3478e60d4398SNeilBrown nfsd4_free_slabs(void) 3479e60d4398SNeilBrown { 34809258a2d5SJeff Layton kmem_cache_destroy(client_slab); 3481abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 3482abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3483abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3484abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3485abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 34869258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 3487e60d4398SNeilBrown } 34881da177e4SLinus Torvalds 348972083396SBryan Schumaker int 34901da177e4SLinus Torvalds nfsd4_init_slabs(void) 34911da177e4SLinus Torvalds { 34929258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 34939258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 34949258a2d5SJeff Layton if (client_slab == NULL) 34959258a2d5SJeff Layton goto out; 3496fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 3497fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 3498fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 34999258a2d5SJeff Layton goto out_free_client_slab; 3500fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 35013c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 3502fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 3503abf1135bSChristoph Hellwig goto out_free_openowner_slab; 3504e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 350520c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 3506e60d4398SNeilBrown if (file_slab == NULL) 3507abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 35085ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 3509dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 35105ac049acSNeilBrown if (stateid_slab == NULL) 3511abf1135bSChristoph Hellwig goto out_free_file_slab; 35125b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 351320c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 35145b2d21c1SNeilBrown if (deleg_slab == NULL) 3515abf1135bSChristoph Hellwig goto out_free_stateid_slab; 35168287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 35178287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 35188287f009SSachin Bhamare if (odstate_slab == NULL) 35198287f009SSachin Bhamare goto out_free_deleg_slab; 3520e60d4398SNeilBrown return 0; 3521abf1135bSChristoph Hellwig 35228287f009SSachin Bhamare out_free_deleg_slab: 35238287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 3524abf1135bSChristoph Hellwig out_free_stateid_slab: 3525abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 3526abf1135bSChristoph Hellwig out_free_file_slab: 3527abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 3528abf1135bSChristoph Hellwig out_free_lockowner_slab: 3529abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 3530abf1135bSChristoph Hellwig out_free_openowner_slab: 3531abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 35329258a2d5SJeff Layton out_free_client_slab: 35339258a2d5SJeff Layton kmem_cache_destroy(client_slab); 3534abf1135bSChristoph Hellwig out: 35351da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 35361da177e4SLinus Torvalds return -ENOMEM; 35371da177e4SLinus Torvalds } 35381da177e4SLinus Torvalds 3539ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 3540ff194bd9SJ. Bruce Fields { 3541ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 3542ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 3543ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 354458fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 354558fb12e6SJeff Layton } 354658fb12e6SJeff Layton 354758fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 354858fb12e6SJeff Layton struct nfs4_stateowner *so) 354958fb12e6SJeff Layton { 355058fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 355158fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 3552b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 355358fb12e6SJeff Layton } 355458fb12e6SJeff Layton } 355558fb12e6SJeff Layton 355658fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 355758fb12e6SJeff Layton { 355858fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 355958fb12e6SJeff Layton 356058fb12e6SJeff Layton if (so != NULL) { 356158fb12e6SJeff Layton cstate->replay_owner = NULL; 356258fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 356358fb12e6SJeff Layton nfs4_put_stateowner(so); 356458fb12e6SJeff Layton } 3565ff194bd9SJ. Bruce Fields } 3566ff194bd9SJ. Bruce Fields 3567fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 35681da177e4SLinus Torvalds { 35691da177e4SLinus Torvalds struct nfs4_stateowner *sop; 35701da177e4SLinus Torvalds 3571fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 3572ff194bd9SJ. Bruce Fields if (!sop) 3573ff194bd9SJ. Bruce Fields return NULL; 3574ff194bd9SJ. Bruce Fields 3575ff194bd9SJ. Bruce Fields sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); 3576ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 3577fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 3578ff194bd9SJ. Bruce Fields return NULL; 3579ff194bd9SJ. Bruce Fields } 35801da177e4SLinus Torvalds sop->so_owner.len = owner->len; 3581ff194bd9SJ. Bruce Fields 3582ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 3583ff194bd9SJ. Bruce Fields sop->so_client = clp; 3584ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 35856b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 35861da177e4SLinus Torvalds return sop; 35871da177e4SLinus Torvalds } 3588ff194bd9SJ. Bruce Fields 3589fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 3590ff194bd9SJ. Bruce Fields { 3591d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 35929b531137SStanislav Kinsbursky 3593d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 3594d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 3595fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 35961da177e4SLinus Torvalds } 35971da177e4SLinus Torvalds 35988f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 35998f4b54c5SJeff Layton { 3600d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 36018f4b54c5SJeff Layton } 36028f4b54c5SJeff Layton 36036b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 36046b180f0bSJeff Layton { 36056b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 36066b180f0bSJeff Layton 36076b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 36086b180f0bSJeff Layton } 36096b180f0bSJeff Layton 36106b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 36118f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 36126b180f0bSJeff Layton .so_free = nfs4_free_openowner, 36136b180f0bSJeff Layton }; 36146b180f0bSJeff Layton 36157fc0564eSAndrew Elble static struct nfs4_ol_stateid * 36167fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 36177fc0564eSAndrew Elble { 36187fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 36197fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 36207fc0564eSAndrew Elble 36217fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 36227fc0564eSAndrew Elble 36237fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 36247fc0564eSAndrew Elble /* ignore lock owners */ 36257fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 36267fc0564eSAndrew Elble continue; 362715ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 362815ca08d3STrond Myklebust continue; 362915ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 36307fc0564eSAndrew Elble ret = local; 3631a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 36327fc0564eSAndrew Elble break; 36337fc0564eSAndrew Elble } 36347fc0564eSAndrew Elble } 36357fc0564eSAndrew Elble return ret; 36367fc0564eSAndrew Elble } 36377fc0564eSAndrew Elble 363815ca08d3STrond Myklebust static __be32 363915ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 364015ca08d3STrond Myklebust { 364115ca08d3STrond Myklebust __be32 ret = nfs_ok; 364215ca08d3STrond Myklebust 364315ca08d3STrond Myklebust switch (s->sc_type) { 364415ca08d3STrond Myklebust default: 364515ca08d3STrond Myklebust break; 36464f176417STrond Myklebust case 0: 364715ca08d3STrond Myklebust case NFS4_CLOSED_STID: 364815ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 364915ca08d3STrond Myklebust ret = nfserr_bad_stateid; 365015ca08d3STrond Myklebust break; 365115ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 365215ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 365315ca08d3STrond Myklebust } 365415ca08d3STrond Myklebust return ret; 365515ca08d3STrond Myklebust } 365615ca08d3STrond Myklebust 365715ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 365815ca08d3STrond Myklebust static __be32 365915ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 366015ca08d3STrond Myklebust { 366115ca08d3STrond Myklebust __be32 ret; 366215ca08d3STrond Myklebust 36634f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 366415ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 366515ca08d3STrond Myklebust if (ret != nfs_ok) 366615ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 366715ca08d3STrond Myklebust return ret; 366815ca08d3STrond Myklebust } 366915ca08d3STrond Myklebust 367015ca08d3STrond Myklebust static struct nfs4_ol_stateid * 367115ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 367215ca08d3STrond Myklebust { 367315ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 367415ca08d3STrond Myklebust for (;;) { 367515ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 367615ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 367715ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 367815ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 367915ca08d3STrond Myklebust break; 368015ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 368115ca08d3STrond Myklebust } 368215ca08d3STrond Myklebust return stp; 368315ca08d3STrond Myklebust } 368415ca08d3STrond Myklebust 3685fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 368613d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 3687db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 3688db24b3b4SJeff Layton { 368913d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 36907ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 36911da177e4SLinus Torvalds 3692fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 3693fe0750e5SJ. Bruce Fields if (!oo) 36941da177e4SLinus Torvalds return NULL; 36956b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 3696fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 3697fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 3698d3134b10SJeff Layton oo->oo_flags = 0; 3699db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 3700db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 3701fe0750e5SJ. Bruce Fields oo->oo_time = 0; 370238c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 3703fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 3704d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 3705d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 37067ffb5880STrond Myklebust if (ret == NULL) { 3707fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 37087ffb5880STrond Myklebust ret = oo; 37097ffb5880STrond Myklebust } else 3710d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 3711d50ffdedSKinglong Mee 3712d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 3713c5952338SJeff Layton return ret; 37141da177e4SLinus Torvalds } 37151da177e4SLinus Torvalds 37167fc0564eSAndrew Elble static struct nfs4_ol_stateid * 37178c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 37187fc0564eSAndrew Elble { 37191da177e4SLinus Torvalds 37207fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 37217fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 37228c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 37237fc0564eSAndrew Elble 37248c7245abSOleg Drokin stp = open->op_stp; 37255cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 37265cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 37274f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 37285cc1fb2aSOleg Drokin 372915ca08d3STrond Myklebust retry: 37307fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 37317fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 37327fc0564eSAndrew Elble 37337fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 37347fc0564eSAndrew Elble if (retstp) 37357fc0564eSAndrew Elble goto out_unlock; 37368c7245abSOleg Drokin 37378c7245abSOleg Drokin open->op_stp = NULL; 3738a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 37393abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 37403c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 3741b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 374213cd2184SNeilBrown get_nfs4_file(fp); 374311b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 37441da177e4SLinus Torvalds stp->st_access_bmap = 0; 37451da177e4SLinus Torvalds stp->st_deny_bmap = 0; 37464c4cd222SNeilBrown stp->st_openstp = NULL; 37471c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 37481d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 37497fc0564eSAndrew Elble 37507fc0564eSAndrew Elble out_unlock: 37511d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 37521c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 37535cc1fb2aSOleg Drokin if (retstp) { 375415ca08d3STrond Myklebust /* Handle races with CLOSE */ 375515ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 375615ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 375715ca08d3STrond Myklebust goto retry; 375815ca08d3STrond Myklebust } 37598c7245abSOleg Drokin /* To keep mutex tracking happy */ 37605cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 37618c7245abSOleg Drokin stp = retstp; 37625cc1fb2aSOleg Drokin } 37638c7245abSOleg Drokin return stp; 37641da177e4SLinus Torvalds } 37651da177e4SLinus Torvalds 3766d3134b10SJeff Layton /* 3767d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 3768d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 3769d3134b10SJeff Layton * them before returning however. 3770d3134b10SJeff Layton */ 37711da177e4SLinus Torvalds static void 3772d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 37731da177e4SLinus Torvalds { 3774217526e7SJeff Layton struct nfs4_ol_stateid *last; 3775d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 3776d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 3777d3134b10SJeff Layton nfsd_net_id); 377873758fedSStanislav Kinsbursky 3779fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 37801da177e4SLinus Torvalds 3781b401be22SJeff Layton /* 3782b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 3783b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 3784b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 3785b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 3786b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 3787b401be22SJeff Layton * there should be no danger of the refcount going back up again at 3788b401be22SJeff Layton * this point. 3789b401be22SJeff Layton */ 3790a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 3791b401be22SJeff Layton 3792d3134b10SJeff Layton release_all_access(s); 3793d3134b10SJeff Layton if (s->st_stid.sc_file) { 3794d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 3795d3134b10SJeff Layton s->st_stid.sc_file = NULL; 3796d3134b10SJeff Layton } 3797217526e7SJeff Layton 3798217526e7SJeff Layton spin_lock(&nn->client_lock); 3799217526e7SJeff Layton last = oo->oo_last_closed_stid; 3800d3134b10SJeff Layton oo->oo_last_closed_stid = s; 380173758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 3802fe0750e5SJ. Bruce Fields oo->oo_time = get_seconds(); 3803217526e7SJeff Layton spin_unlock(&nn->client_lock); 3804217526e7SJeff Layton if (last) 3805217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 38061da177e4SLinus Torvalds } 38071da177e4SLinus Torvalds 38081da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 38091da177e4SLinus Torvalds static struct nfs4_file * 38105b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval) 38111da177e4SLinus Torvalds { 38121da177e4SLinus Torvalds struct nfs4_file *fp; 38131da177e4SLinus Torvalds 38145b095e99SJeff Layton hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { 38154d94c2efSChristoph Hellwig if (fh_match(&fp->fi_fhandle, fh)) { 3816818a34ebSElena Reshetova if (refcount_inc_not_zero(&fp->fi_ref)) 38171da177e4SLinus Torvalds return fp; 38181da177e4SLinus Torvalds } 381913cd2184SNeilBrown } 38201da177e4SLinus Torvalds return NULL; 38211da177e4SLinus Torvalds } 38221da177e4SLinus Torvalds 3823e6ba76e1SChristoph Hellwig struct nfs4_file * 3824ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 3825950e0118STrond Myklebust { 3826950e0118STrond Myklebust struct nfs4_file *fp; 38275b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 3828950e0118STrond Myklebust 38295b095e99SJeff Layton rcu_read_lock(); 38305b095e99SJeff Layton fp = find_file_locked(fh, hashval); 38315b095e99SJeff Layton rcu_read_unlock(); 3832950e0118STrond Myklebust return fp; 3833950e0118STrond Myklebust } 3834950e0118STrond Myklebust 3835950e0118STrond Myklebust static struct nfs4_file * 3836f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 3837950e0118STrond Myklebust { 3838950e0118STrond Myklebust struct nfs4_file *fp; 38395b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 38405b095e99SJeff Layton 38415b095e99SJeff Layton rcu_read_lock(); 38425b095e99SJeff Layton fp = find_file_locked(fh, hashval); 38435b095e99SJeff Layton rcu_read_unlock(); 38445b095e99SJeff Layton if (fp) 38455b095e99SJeff Layton return fp; 3846950e0118STrond Myklebust 3847950e0118STrond Myklebust spin_lock(&state_lock); 38485b095e99SJeff Layton fp = find_file_locked(fh, hashval); 38495b095e99SJeff Layton if (likely(fp == NULL)) { 38505b095e99SJeff Layton nfsd4_init_file(fh, hashval, new); 3851950e0118STrond Myklebust fp = new; 3852950e0118STrond Myklebust } 3853950e0118STrond Myklebust spin_unlock(&state_lock); 3854950e0118STrond Myklebust 3855950e0118STrond Myklebust return fp; 3856950e0118STrond Myklebust } 3857950e0118STrond Myklebust 38584f83aa30SJ. Bruce Fields /* 38591da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 38601da177e4SLinus Torvalds * WRITE with all zero or all one stateid 38611da177e4SLinus Torvalds */ 3862b37ad28bSAl Viro static __be32 38631da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 38641da177e4SLinus Torvalds { 38651da177e4SLinus Torvalds struct nfs4_file *fp; 3866baeb4ff0SJeff Layton __be32 ret = nfs_ok; 38671da177e4SLinus Torvalds 3868ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 386913cd2184SNeilBrown if (!fp) 3870baeb4ff0SJeff Layton return ret; 3871baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 38721d31a253STrond Myklebust spin_lock(&fp->fi_lock); 3873baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 3874baeb4ff0SJeff Layton ret = nfserr_locked; 38751d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 387613cd2184SNeilBrown put_nfs4_file(fp); 387713cd2184SNeilBrown return ret; 38781da177e4SLinus Torvalds } 38791da177e4SLinus Torvalds 38800162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 38811da177e4SLinus Torvalds { 38820162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 388311b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 388411b9164aSTrond Myklebust nfsd_net_id); 3885e8c69d17SJ. Bruce Fields 388611b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 3887f54fe962SJeff Layton 388802e1215fSJeff Layton /* 388902e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 3890f54fe962SJeff Layton * already holding inode->i_lock. 3891f54fe962SJeff Layton * 3892dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 3893dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 3894dff1399fSJeff Layton */ 3895f54fe962SJeff Layton spin_lock(&state_lock); 3896dff1399fSJeff Layton if (dp->dl_time == 0) { 38971da177e4SLinus Torvalds dp->dl_time = get_seconds(); 389802e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 389902e1215fSJeff Layton } 390002e1215fSJeff Layton spin_unlock(&state_lock); 3901dff1399fSJeff Layton } 39021da177e4SLinus Torvalds 39030162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 39040162ac2bSChristoph Hellwig struct rpc_task *task) 39050162ac2bSChristoph Hellwig { 39060162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 39070162ac2bSChristoph Hellwig 3908a457974fSAndrew Elble if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID) 3909a457974fSAndrew Elble return 1; 3910a457974fSAndrew Elble 39110162ac2bSChristoph Hellwig switch (task->tk_status) { 39120162ac2bSChristoph Hellwig case 0: 39130162ac2bSChristoph Hellwig return 1; 39140162ac2bSChristoph Hellwig case -EBADHANDLE: 39150162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 39160162ac2bSChristoph Hellwig /* 39170162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 39180162ac2bSChristoph Hellwig * granting delegation. 39190162ac2bSChristoph Hellwig */ 39200162ac2bSChristoph Hellwig if (dp->dl_retries--) { 39210162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 39220162ac2bSChristoph Hellwig return 0; 39230162ac2bSChristoph Hellwig } 39240162ac2bSChristoph Hellwig /*FALLTHRU*/ 39250162ac2bSChristoph Hellwig default: 39260162ac2bSChristoph Hellwig return -1; 39270162ac2bSChristoph Hellwig } 39280162ac2bSChristoph Hellwig } 39290162ac2bSChristoph Hellwig 39300162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 39310162ac2bSChristoph Hellwig { 39320162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 39330162ac2bSChristoph Hellwig 39340162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 39350162ac2bSChristoph Hellwig } 39360162ac2bSChristoph Hellwig 3937c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 39380162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 39390162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 39400162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 39410162ac2bSChristoph Hellwig }; 39420162ac2bSChristoph Hellwig 394302e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 394402e1215fSJeff Layton { 394502e1215fSJeff Layton /* 394602e1215fSJeff Layton * We're assuming the state code never drops its reference 394702e1215fSJeff Layton * without first removing the lease. Since we're in this lease 39484a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 39494a269efbSJ. Bruce Fields * i_lock) we know the server hasn't removed the lease yet, and 39504a269efbSJ. Bruce Fields * we know it's safe to take a reference. 395102e1215fSJeff Layton */ 3952a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 3953f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 39546b57d9c8SJ. Bruce Fields } 39556b57d9c8SJ. Bruce Fields 39561c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 39574d01b7f5SJeff Layton static bool 39584d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 39596b57d9c8SJ. Bruce Fields { 39604d01b7f5SJeff Layton bool ret = false; 3961653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 3962653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 39636b57d9c8SJ. Bruce Fields 39640272e1fdSJ. Bruce Fields /* 39650272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 3966acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 39676b57d9c8SJ. Bruce Fields * in time: 39680272e1fdSJ. Bruce Fields */ 39690272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 39701da177e4SLinus Torvalds 397102e1215fSJeff Layton spin_lock(&fp->fi_lock); 3972417c6629SJeff Layton fp->fi_had_conflict = true; 39735d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 397402e1215fSJeff Layton spin_unlock(&fp->fi_lock); 39754d01b7f5SJeff Layton return ret; 39761da177e4SLinus Torvalds } 39771da177e4SLinus Torvalds 3978c45198edSJeff Layton static int 39797448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 39807448cc37SJeff Layton struct list_head *dispose) 39811da177e4SLinus Torvalds { 39821da177e4SLinus Torvalds if (arg & F_UNLCK) 3983c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 39841da177e4SLinus Torvalds else 39851da177e4SLinus Torvalds return -EAGAIN; 39861da177e4SLinus Torvalds } 39871da177e4SLinus Torvalds 39887b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 39898fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 39908fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 39911da177e4SLinus Torvalds }; 39921da177e4SLinus Torvalds 39937a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 39947a8711c9SJ. Bruce Fields { 39957a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 39967a8711c9SJ. Bruce Fields return nfs_ok; 39977a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 39987a8711c9SJ. Bruce Fields return nfserr_replay_me; 39997a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 40007a8711c9SJ. Bruce Fields return nfs_ok; 40017a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 40027a8711c9SJ. Bruce Fields } 40031da177e4SLinus Torvalds 40044b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 40054b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 40064b24ca7dSJeff Layton struct nfsd_net *nn) 40074b24ca7dSJeff Layton { 40084b24ca7dSJeff Layton struct nfs4_client *found; 40094b24ca7dSJeff Layton 40104b24ca7dSJeff Layton if (cstate->clp) { 40114b24ca7dSJeff Layton found = cstate->clp; 40124b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 40134b24ca7dSJeff Layton return nfserr_stale_clientid; 40144b24ca7dSJeff Layton return nfs_ok; 40154b24ca7dSJeff Layton } 40164b24ca7dSJeff Layton 40174b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 40184b24ca7dSJeff Layton return nfserr_stale_clientid; 40194b24ca7dSJeff Layton 40204b24ca7dSJeff Layton /* 40214b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 40224b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 40234b24ca7dSJeff Layton * will be false. 40244b24ca7dSJeff Layton */ 40254b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 40263e339f96STrond Myklebust spin_lock(&nn->client_lock); 40274b24ca7dSJeff Layton found = find_confirmed_client(clid, false, nn); 40283e339f96STrond Myklebust if (!found) { 40293e339f96STrond Myklebust spin_unlock(&nn->client_lock); 40304b24ca7dSJeff Layton return nfserr_expired; 40313e339f96STrond Myklebust } 40323e339f96STrond Myklebust atomic_inc(&found->cl_refcount); 40333e339f96STrond Myklebust spin_unlock(&nn->client_lock); 40344b24ca7dSJeff Layton 40354b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 40364b24ca7dSJeff Layton cstate->clp = found; 40374b24ca7dSJeff Layton return nfs_ok; 40384b24ca7dSJeff Layton } 40394b24ca7dSJeff Layton 4040b37ad28bSAl Viro __be32 40416668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 40423320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 40431da177e4SLinus Torvalds { 40441da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 40451da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 40461da177e4SLinus Torvalds unsigned int strhashval; 4047fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 40484cdc951bSJ. Bruce Fields __be32 status; 40491da177e4SLinus Torvalds 40502c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 40511da177e4SLinus Torvalds return nfserr_stale_clientid; 405232513b40SJ. Bruce Fields /* 405332513b40SJ. Bruce Fields * In case we need it later, after we've already created the 405432513b40SJ. Bruce Fields * file and don't want to risk a further failure: 405532513b40SJ. Bruce Fields */ 405632513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 405732513b40SJ. Bruce Fields if (open->op_file == NULL) 405832513b40SJ. Bruce Fields return nfserr_jukebox; 40591da177e4SLinus Torvalds 406013d6f66bSTrond Myklebust status = lookup_clientid(clientid, cstate, nn); 406113d6f66bSTrond Myklebust if (status) 406213d6f66bSTrond Myklebust return status; 406313d6f66bSTrond Myklebust clp = cstate->clp; 40642d91e895STrond Myklebust 4065d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 4066d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 40672d91e895STrond Myklebust open->op_openowner = oo; 40682d91e895STrond Myklebust if (!oo) { 4069bcf130f9SJ. Bruce Fields goto new_owner; 40700f442aa2SJ. Bruce Fields } 4071dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 40720f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 4073fe0750e5SJ. Bruce Fields release_openowner(oo); 4074fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 4075bcf130f9SJ. Bruce Fields goto new_owner; 40760f442aa2SJ. Bruce Fields } 40774cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 40784cdc951bSJ. Bruce Fields if (status) 40794cdc951bSJ. Bruce Fields return status; 40804cdc951bSJ. Bruce Fields goto alloc_stateid; 4081bcf130f9SJ. Bruce Fields new_owner: 408213d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 4083fe0750e5SJ. Bruce Fields if (oo == NULL) 40843e772463SJ. Bruce Fields return nfserr_jukebox; 4085fe0750e5SJ. Bruce Fields open->op_openowner = oo; 40864cdc951bSJ. Bruce Fields alloc_stateid: 4087b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 40884cdc951bSJ. Bruce Fields if (!open->op_stp) 40894cdc951bSJ. Bruce Fields return nfserr_jukebox; 40908287f009SSachin Bhamare 40918287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 40928287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 40938287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 40948287f009SSachin Bhamare if (!open->op_odstate) 40958287f009SSachin Bhamare return nfserr_jukebox; 40968287f009SSachin Bhamare } 40978287f009SSachin Bhamare 40980f442aa2SJ. Bruce Fields return nfs_ok; 40991da177e4SLinus Torvalds } 41001da177e4SLinus Torvalds 4101b37ad28bSAl Viro static inline __be32 41024a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 41034a6e43e6SNeilBrown { 41044a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 41054a6e43e6SNeilBrown return nfserr_openmode; 41064a6e43e6SNeilBrown else 41074a6e43e6SNeilBrown return nfs_ok; 41084a6e43e6SNeilBrown } 41094a6e43e6SNeilBrown 4110c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 411124a0111eSJ. Bruce Fields { 411224a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 411324a0111eSJ. Bruce Fields } 411424a0111eSJ. Bruce Fields 411538c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 4116f459e453SJ. Bruce Fields { 4117f459e453SJ. Bruce Fields struct nfs4_stid *ret; 4118f459e453SJ. Bruce Fields 411995da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 412095da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 4121f459e453SJ. Bruce Fields if (!ret) 4122f459e453SJ. Bruce Fields return NULL; 4123f459e453SJ. Bruce Fields return delegstateid(ret); 4124f459e453SJ. Bruce Fields } 4125f459e453SJ. Bruce Fields 41268b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 41278b289b2cSJ. Bruce Fields { 41288b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 41298b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 41308b289b2cSJ. Bruce Fields } 41318b289b2cSJ. Bruce Fields 4132b37ad28bSAl Viro static __be32 413341d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 4134567d9829SNeilBrown struct nfs4_delegation **dp) 4135567d9829SNeilBrown { 4136567d9829SNeilBrown int flags; 4137b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 4138dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 4139567d9829SNeilBrown 4140dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 4141dcd94cc2STrond Myklebust if (deleg == NULL) 4142c44c5eebSNeilBrown goto out; 414395da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 414495da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 414595da1b3aSAndrew Elble if (cl->cl_minorversion) 414695da1b3aSAndrew Elble status = nfserr_deleg_revoked; 414795da1b3aSAndrew Elble goto out; 414895da1b3aSAndrew Elble } 414924a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 4150dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 4151dcd94cc2STrond Myklebust if (status) { 4152dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 4153dcd94cc2STrond Myklebust goto out; 4154dcd94cc2STrond Myklebust } 4155dcd94cc2STrond Myklebust *dp = deleg; 4156c44c5eebSNeilBrown out: 41578b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 4158c44c5eebSNeilBrown return nfs_ok; 4159c44c5eebSNeilBrown if (status) 4160c44c5eebSNeilBrown return status; 4161dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 4162c44c5eebSNeilBrown return nfs_ok; 4163567d9829SNeilBrown } 4164567d9829SNeilBrown 416521fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 416621fb4016SJ. Bruce Fields { 416721fb4016SJ. Bruce Fields int flags = 0; 416821fb4016SJ. Bruce Fields 416921fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 417021fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 417121fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 417221fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 417321fb4016SJ. Bruce Fields return flags; 417421fb4016SJ. Bruce Fields } 417521fb4016SJ. Bruce Fields 4176b37ad28bSAl Viro static inline __be32 41771da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 41781da177e4SLinus Torvalds struct nfsd4_open *open) 41791da177e4SLinus Torvalds { 41801da177e4SLinus Torvalds struct iattr iattr = { 41811da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 41821da177e4SLinus Torvalds .ia_size = 0, 41831da177e4SLinus Torvalds }; 41841da177e4SLinus Torvalds if (!open->op_truncate) 41851da177e4SLinus Torvalds return 0; 41861da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 41879246585aSAl Viro return nfserr_inval; 41881da177e4SLinus Torvalds return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); 41891da177e4SLinus Torvalds } 41901da177e4SLinus Torvalds 41917e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 41926eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 41936eb3a1d0SJeff Layton struct nfsd4_open *open) 41947e6a72e5SChristoph Hellwig { 4195de18643dSTrond Myklebust struct file *filp = NULL; 41967e6a72e5SChristoph Hellwig __be32 status; 41977e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 41987e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 4199baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 42007e6a72e5SChristoph Hellwig 4201de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4202baeb4ff0SJeff Layton 4203baeb4ff0SJeff Layton /* 4204baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 4205baeb4ff0SJeff Layton * current access? 4206baeb4ff0SJeff Layton */ 4207baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4208baeb4ff0SJeff Layton if (status != nfs_ok) { 4209baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4210baeb4ff0SJeff Layton goto out; 4211baeb4ff0SJeff Layton } 4212baeb4ff0SJeff Layton 4213baeb4ff0SJeff Layton /* set access to the file */ 4214baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 4215baeb4ff0SJeff Layton if (status != nfs_ok) { 4216baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4217baeb4ff0SJeff Layton goto out; 4218baeb4ff0SJeff Layton } 4219baeb4ff0SJeff Layton 4220baeb4ff0SJeff Layton /* Set access bits in stateid */ 4221baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 4222baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 4223baeb4ff0SJeff Layton 4224baeb4ff0SJeff Layton /* Set new deny mask */ 4225baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 4226baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4227baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 4228baeb4ff0SJeff Layton 42297e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 4230de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4231de18643dSTrond Myklebust status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); 42327e6a72e5SChristoph Hellwig if (status) 4233baeb4ff0SJeff Layton goto out_put_access; 4234de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4235de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 4236de18643dSTrond Myklebust fp->fi_fds[oflag] = filp; 4237de18643dSTrond Myklebust filp = NULL; 4238de18643dSTrond Myklebust } 42397e6a72e5SChristoph Hellwig } 4240de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4241de18643dSTrond Myklebust if (filp) 4242de18643dSTrond Myklebust fput(filp); 42437e6a72e5SChristoph Hellwig 42447e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 42457e6a72e5SChristoph Hellwig if (status) 42467e6a72e5SChristoph Hellwig goto out_put_access; 42477e6a72e5SChristoph Hellwig out: 42487e6a72e5SChristoph Hellwig return status; 4249baeb4ff0SJeff Layton out_put_access: 4250baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 4251baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 4252baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 4253baeb4ff0SJeff Layton goto out; 42547e6a72e5SChristoph Hellwig } 42557e6a72e5SChristoph Hellwig 4256b37ad28bSAl Viro static __be32 4257dcef0413SJ. 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) 42581da177e4SLinus Torvalds { 4259b37ad28bSAl Viro __be32 status; 42606ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 42611da177e4SLinus Torvalds 42626eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 4263baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 42647e6a72e5SChristoph Hellwig 4265baeb4ff0SJeff Layton /* test and set deny mode */ 4266baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 4267baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4268baeb4ff0SJeff Layton if (status == nfs_ok) { 4269baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4270baeb4ff0SJeff Layton fp->fi_share_deny |= 4271baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 42721da177e4SLinus Torvalds } 4273baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 42741da177e4SLinus Torvalds 4275baeb4ff0SJeff Layton if (status != nfs_ok) 4276baeb4ff0SJeff Layton return status; 4277baeb4ff0SJeff Layton 4278baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 4279baeb4ff0SJeff Layton if (status != nfs_ok) 4280baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 4281baeb4ff0SJeff Layton return status; 4282baeb4ff0SJeff Layton } 42831da177e4SLinus Torvalds 428414a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 428514a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 428614a24e99SJ. Bruce Fields { 428714a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 428814a24e99SJ. Bruce Fields return true; 428914a24e99SJ. Bruce Fields /* 429014a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 429114a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 429214a24e99SJ. Bruce Fields * until we hear otherwise: 429314a24e99SJ. Bruce Fields */ 429414a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 429514a24e99SJ. Bruce Fields } 429614a24e99SJ. Bruce Fields 4297653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 4298653e514eSJ. Bruce Fields int flag) 429922d38c4cSJ. Bruce Fields { 430022d38c4cSJ. Bruce Fields struct file_lock *fl; 430122d38c4cSJ. Bruce Fields 430222d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 430322d38c4cSJ. Bruce Fields if (!fl) 430422d38c4cSJ. Bruce Fields return NULL; 430522d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 4306617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 430722d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 430822d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 4309653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 431022d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 4311353601e7SJ. Bruce Fields fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file; 431222d38c4cSJ. Bruce Fields return fl; 431322d38c4cSJ. Bruce Fields } 431422d38c4cSJ. Bruce Fields 43150b26693cSJeff Layton static struct nfs4_delegation * 43160b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 43178287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 4318acfdf5c3SJ. Bruce Fields { 431968b18f52SJ. Bruce Fields int status = 0; 43200b26693cSJeff Layton struct nfs4_delegation *dp; 4321353601e7SJ. Bruce Fields struct file *filp; 4322353601e7SJ. Bruce Fields struct file_lock *fl; 4323417c6629SJeff Layton 4324353601e7SJ. Bruce Fields /* 4325353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 4326353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 4327353601e7SJ. Bruce Fields * the end: 4328353601e7SJ. Bruce Fields */ 4329bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 43300b26693cSJeff Layton return ERR_PTR(-EAGAIN); 43310b26693cSJeff Layton 4332353601e7SJ. Bruce Fields filp = find_readable_file(fp); 4333353601e7SJ. Bruce Fields if (!filp) { 4334353601e7SJ. Bruce Fields /* We should always have a readable file here */ 4335353601e7SJ. Bruce Fields WARN_ON_ONCE(1); 4336353601e7SJ. Bruce Fields return ERR_PTR(-EBADF); 4337353601e7SJ. Bruce Fields } 433834ed9872SAndrew Elble spin_lock(&state_lock); 433934ed9872SAndrew Elble spin_lock(&fp->fi_lock); 434068b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 434168b18f52SJ. Bruce Fields status = -EAGAIN; 4342353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 4343353601e7SJ. Bruce Fields fp->fi_deleg_file = filp; 4344353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 4345353601e7SJ. Bruce Fields * cleared */ 4346353601e7SJ. Bruce Fields fp->fi_delegees = 1; 4347353601e7SJ. Bruce Fields filp = NULL; 4348353601e7SJ. Bruce Fields } else 4349353601e7SJ. Bruce Fields fp->fi_delegees++; 4350353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 4351353601e7SJ. Bruce Fields spin_unlock(&state_lock); 4352353601e7SJ. Bruce Fields if (filp) 4353353601e7SJ. Bruce Fields fput(filp); 4354353601e7SJ. Bruce Fields if (status) 4355353601e7SJ. Bruce Fields return ERR_PTR(status); 4356353601e7SJ. Bruce Fields 4357353601e7SJ. Bruce Fields status = -ENOMEM; 4358353601e7SJ. Bruce Fields dp = alloc_init_deleg(clp, fp, fh, odstate); 4359353601e7SJ. Bruce Fields if (!dp) 4360353601e7SJ. Bruce Fields goto out_delegees; 4361353601e7SJ. Bruce Fields 4362353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 4363353601e7SJ. Bruce Fields if (!fl) 4364353601e7SJ. Bruce Fields goto out_stid; 4365353601e7SJ. Bruce Fields 4366353601e7SJ. Bruce Fields status = vfs_setlease(fp->fi_deleg_file, fl->fl_type, &fl, NULL); 4367353601e7SJ. Bruce Fields if (fl) 4368353601e7SJ. Bruce Fields locks_free_lock(fl); 4369353601e7SJ. Bruce Fields if (status) 4370353601e7SJ. Bruce Fields goto out_clnt_odstate; 4371353601e7SJ. Bruce Fields 4372353601e7SJ. Bruce Fields spin_lock(&state_lock); 4373353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 4374353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 4375353601e7SJ. Bruce Fields status = -EAGAIN; 4376353601e7SJ. Bruce Fields else 4377353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 437834ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 437934ed9872SAndrew Elble spin_unlock(&state_lock); 438034ed9872SAndrew Elble 438134ed9872SAndrew Elble if (status) 4382692ad280SAndrew Elble goto out_unlock; 4383692ad280SAndrew Elble 43840b26693cSJeff Layton return dp; 4385692ad280SAndrew Elble out_unlock: 4386692ad280SAndrew Elble vfs_setlease(fp->fi_deleg_file, F_UNLCK, NULL, (void **)&dp); 4387353601e7SJ. Bruce Fields out_clnt_odstate: 4388353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 4389353601e7SJ. Bruce Fields out_stid: 4390353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 4391353601e7SJ. Bruce Fields out_delegees: 4392353601e7SJ. Bruce Fields put_deleg_file(fp); 4393353601e7SJ. Bruce Fields return ERR_PTR(status); 4394edab9782SJ. Bruce Fields } 4395edab9782SJ. Bruce Fields 43964aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 43974aa8913cSBenny Halevy { 43984aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 43994aa8913cSBenny Halevy if (status == -EAGAIN) 44004aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 44014aa8913cSBenny Halevy else { 44024aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 44034aa8913cSBenny Halevy switch (open->op_deleg_want) { 44044aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 44054aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 44064aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 44074aa8913cSBenny Halevy break; 44084aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 44094aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 44104aa8913cSBenny Halevy break; 44114aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 4412063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 44134aa8913cSBenny Halevy } 44144aa8913cSBenny Halevy } 44154aa8913cSBenny Halevy } 44164aa8913cSBenny Halevy 44171da177e4SLinus Torvalds /* 44181da177e4SLinus Torvalds * Attempt to hand out a delegation. 441999c41515SJ. Bruce Fields * 442099c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 442199c41515SJ. Bruce Fields * proper support for them. 44221da177e4SLinus Torvalds */ 44231da177e4SLinus Torvalds static void 44244cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 44254cf59221SJeff Layton struct nfs4_ol_stateid *stp) 44261da177e4SLinus Torvalds { 44271da177e4SLinus Torvalds struct nfs4_delegation *dp; 44284cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 44294cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 443014a24e99SJ. Bruce Fields int cb_up; 443199c41515SJ. Bruce Fields int status = 0; 44321da177e4SLinus Torvalds 4433fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 44347b190fecSNeilBrown open->op_recall = 0; 44357b190fecSNeilBrown switch (open->op_claim_type) { 44367b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 44372bf23875SJ. Bruce Fields if (!cb_up) 44387b190fecSNeilBrown open->op_recall = 1; 443999c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 444099c41515SJ. Bruce Fields goto out_no_deleg; 44417b190fecSNeilBrown break; 44427b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 4443ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 444499c41515SJ. Bruce Fields /* 444599c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 4446c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 4447c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 444899c41515SJ. Bruce Fields */ 44494cf59221SJeff Layton if (locks_in_grace(clp->net)) 445099c41515SJ. Bruce Fields goto out_no_deleg; 4451dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 445299c41515SJ. Bruce Fields goto out_no_deleg; 44539a0590aeSSteve Dickson /* 44549a0590aeSSteve Dickson * Also, if the file was opened for write or 44559a0590aeSSteve Dickson * create, there's a good chance the client's 44569a0590aeSSteve Dickson * about to write to it, resulting in an 44579a0590aeSSteve Dickson * immediate recall (since we don't support 44589a0590aeSSteve Dickson * write delegations): 44599a0590aeSSteve Dickson */ 44601da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 446199c41515SJ. Bruce Fields goto out_no_deleg; 446299c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 446399c41515SJ. Bruce Fields goto out_no_deleg; 44647b190fecSNeilBrown break; 44657b190fecSNeilBrown default: 446699c41515SJ. Bruce Fields goto out_no_deleg; 44677b190fecSNeilBrown } 44688287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 44690b26693cSJeff Layton if (IS_ERR(dp)) 4470dd239cc0SJ. Bruce Fields goto out_no_deleg; 44711da177e4SLinus Torvalds 4472d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 44731da177e4SLinus Torvalds 44748c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 4475d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 447699c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 447767cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4478dd239cc0SJ. Bruce Fields return; 4479dd239cc0SJ. Bruce Fields out_no_deleg: 448099c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 44817b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 4482d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 44831da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 4484d08d32e6SJ. Bruce Fields open->op_recall = 1; 4485d08d32e6SJ. Bruce Fields } 4486dd239cc0SJ. Bruce Fields 4487dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 4488dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 4489dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 4490dd239cc0SJ. Bruce Fields return; 44911da177e4SLinus Torvalds } 44921da177e4SLinus Torvalds 4493e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 4494e27f49c3SBenny Halevy struct nfs4_delegation *dp) 4495e27f49c3SBenny Halevy { 4496e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 4497e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4498e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4499e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 4500e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 4501e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 4502e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4503e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 4504e27f49c3SBenny Halevy } 4505e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 4506e27f49c3SBenny Halevy * it already has, therefore we don't return 4507e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 4508e27f49c3SBenny Halevy */ 4509e27f49c3SBenny Halevy } 4510e27f49c3SBenny Halevy 4511b37ad28bSAl Viro __be32 45121da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 45131da177e4SLinus Torvalds { 45146668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 451538c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 45161da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 4517dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 4518567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 4519b37ad28bSAl Viro __be32 status; 4520d8a1a000STrond Myklebust bool new_stp = false; 45211da177e4SLinus Torvalds 45221da177e4SLinus Torvalds /* 45231da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 45241da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 45251da177e4SLinus Torvalds * If not found, create the nfs4_file struct 45261da177e4SLinus Torvalds */ 4527f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 4528950e0118STrond Myklebust if (fp != open->op_file) { 452941d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 4530c44c5eebSNeilBrown if (status) 4531c44c5eebSNeilBrown goto out; 453215ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 45331da177e4SLinus Torvalds } else { 4534950e0118STrond Myklebust open->op_file = NULL; 4535c44c5eebSNeilBrown status = nfserr_bad_stateid; 45368b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 4537c44c5eebSNeilBrown goto out; 45381da177e4SLinus Torvalds } 45391da177e4SLinus Torvalds 4540d8a1a000STrond Myklebust if (!stp) { 4541d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 4542d8a1a000STrond Myklebust if (!open->op_stp) 4543d8a1a000STrond Myklebust new_stp = true; 4544d8a1a000STrond Myklebust } 4545d8a1a000STrond Myklebust 45461da177e4SLinus Torvalds /* 45471da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 45481da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 4549d8a1a000STrond Myklebust * 4550d8a1a000STrond Myklebust * stp is already locked. 45511da177e4SLinus Torvalds */ 4552d8a1a000STrond Myklebust if (!new_stp) { 45531da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 4554f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 455535a92fe8SJeff Layton if (status) { 4556feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 45571da177e4SLinus Torvalds goto out; 455835a92fe8SJeff Layton } 45591da177e4SLinus Torvalds } else { 45606eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 45616eb3a1d0SJeff Layton if (status) { 4562d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 45636eb3a1d0SJeff Layton release_open_stateid(stp); 4564d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 45656eb3a1d0SJeff Layton goto out; 45666eb3a1d0SJeff Layton } 45678287f009SSachin Bhamare 45688287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 45698287f009SSachin Bhamare open->op_odstate); 45708287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 45718287f009SSachin Bhamare open->op_odstate = NULL; 45721da177e4SLinus Torvalds } 4573d8a1a000STrond Myklebust 45749767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 4575feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 45761da177e4SLinus Torvalds 4577d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 4578d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 4579d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 4580d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 4581d24433cdSBenny Halevy goto nodeleg; 4582d24433cdSBenny Halevy } 4583d24433cdSBenny Halevy } 4584d24433cdSBenny Halevy 45851da177e4SLinus Torvalds /* 45861da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 45871da177e4SLinus Torvalds * OPEN succeeds even if we fail. 45881da177e4SLinus Torvalds */ 45894cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 4590d24433cdSBenny Halevy nodeleg: 45911da177e4SLinus Torvalds status = nfs_ok; 45921da177e4SLinus Torvalds 45938c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 4594dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 45951da177e4SLinus Torvalds out: 4596d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 4597d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 4598e27f49c3SBenny Halevy open->op_deleg_want) 4599e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 4600d24433cdSBenny Halevy 460113cd2184SNeilBrown if (fp) 460213cd2184SNeilBrown put_nfs4_file(fp); 460337515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 460487186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 46051da177e4SLinus Torvalds /* 46061da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 46071da177e4SLinus Torvalds */ 46081da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 460919e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 461019e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 461119e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 46121da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 461319e4c347SJeff Layton 4614dcd94cc2STrond Myklebust if (dp) 4615dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 4616d6f2bc5dSTrond Myklebust if (stp) 4617d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 46181da177e4SLinus Torvalds 46191da177e4SLinus Torvalds return status; 46201da177e4SLinus Torvalds } 46211da177e4SLinus Torvalds 462258fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 462342297899SJeff Layton struct nfsd4_open *open) 4624d29b20cdSJ. Bruce Fields { 4625d29b20cdSJ. Bruce Fields if (open->op_openowner) { 4626d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 4627d29b20cdSJ. Bruce Fields 4628d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 4629d3134b10SJeff Layton nfs4_put_stateowner(so); 4630d29b20cdSJ. Bruce Fields } 463132513b40SJ. Bruce Fields if (open->op_file) 46325b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 46334cdc951bSJ. Bruce Fields if (open->op_stp) 46346011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 46358287f009SSachin Bhamare if (open->op_odstate) 46368287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 4637d29b20cdSJ. Bruce Fields } 4638d29b20cdSJ. Bruce Fields 4639b37ad28bSAl Viro __be32 4640b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4641eb69853dSChristoph Hellwig union nfsd4_op_u *u) 46421da177e4SLinus Torvalds { 4643eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 46441da177e4SLinus Torvalds struct nfs4_client *clp; 4645b37ad28bSAl Viro __be32 status; 46467f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 46471da177e4SLinus Torvalds 46481da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 46491da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 46504b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 46519b2ef62bSJ. Bruce Fields if (status) 46521da177e4SLinus Torvalds goto out; 46534b24ca7dSJeff Layton clp = cstate->clp; 46541da177e4SLinus Torvalds status = nfserr_cb_path_down; 4655ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 465677a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 46571da177e4SLinus Torvalds goto out; 46581da177e4SLinus Torvalds status = nfs_ok; 46591da177e4SLinus Torvalds out: 46601da177e4SLinus Torvalds return status; 46611da177e4SLinus Torvalds } 46621da177e4SLinus Torvalds 46637f5ef2e9SJeff Layton void 466412760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 4665a76b4319SNeilBrown { 466633dcc481SJeff Layton /* do nothing if grace period already ended */ 4667a51c84edSStanislav Kinsbursky if (nn->grace_ended) 466833dcc481SJeff Layton return; 466933dcc481SJeff Layton 4670a76b4319SNeilBrown dprintk("NFSD: end of grace period\n"); 4671a51c84edSStanislav Kinsbursky nn->grace_ended = true; 467270b28235SJ. Bruce Fields /* 467370b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 467470b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 467570b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 467670b28235SJ. Bruce Fields * 467770b28235SJ. Bruce Fields */ 4678919b8049SJeff Layton nfsd4_record_grace_done(nn); 467970b28235SJ. Bruce Fields /* 468070b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 468170b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 468270b28235SJ. Bruce Fields * of luck on the next boot. 468370b28235SJ. Bruce Fields * 468470b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 468570b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 468670b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 468770b28235SJ. Bruce Fields */ 46885e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 468970b28235SJ. Bruce Fields /* 469070b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 469170b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 469270b28235SJ. Bruce Fields * regular locking can resume. 469370b28235SJ. Bruce Fields */ 4694a76b4319SNeilBrown } 4695a76b4319SNeilBrown 469603f318caSJ. Bruce Fields /* 469703f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 469803f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 469903f318caSJ. Bruce Fields */ 470003f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 470103f318caSJ. Bruce Fields { 470203f318caSJ. Bruce Fields unsigned long now = get_seconds(); 470303f318caSJ. Bruce Fields unsigned long double_grace_period_end = nn->boot_time + 470403f318caSJ. Bruce Fields 2 * nn->nfsd4_lease; 470503f318caSJ. Bruce Fields 470603f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 470703f318caSJ. Bruce Fields return false; 470803f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 470903f318caSJ. Bruce Fields /* 471003f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 471103f318caSJ. Bruce Fields * still not done, give up: 471203f318caSJ. Bruce Fields */ 471303f318caSJ. Bruce Fields if (time_after(now, double_grace_period_end)) 471403f318caSJ. Bruce Fields return false; 471503f318caSJ. Bruce Fields return true; 471603f318caSJ. Bruce Fields } 471703f318caSJ. Bruce Fields 4718fd39ca9aSNeilBrown static time_t 471909121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 47201da177e4SLinus Torvalds { 47211da177e4SLinus Torvalds struct nfs4_client *clp; 4722fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 47231da177e4SLinus Torvalds struct nfs4_delegation *dp; 4724217526e7SJeff Layton struct nfs4_ol_stateid *stp; 47257919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 47261da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 47273d733711SStanislav Kinsbursky time_t cutoff = get_seconds() - nn->nfsd4_lease; 4728a832e7aeSJeff Layton time_t t, new_timeo = nn->nfsd4_lease; 47291da177e4SLinus Torvalds 47301da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 473103f318caSJ. Bruce Fields 473203f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 473303f318caSJ. Bruce Fields new_timeo = 0; 473403f318caSJ. Bruce Fields goto out; 473503f318caSJ. Bruce Fields } 473612760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 473736acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 4738c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 47395ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 47401da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 47411da177e4SLinus Torvalds if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 47421da177e4SLinus Torvalds t = clp->cl_time - cutoff; 4743a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 47441da177e4SLinus Torvalds break; 47451da177e4SLinus Torvalds } 4746221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 4747d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 4748d7682988SBenny Halevy clp->cl_clientid.cl_id); 4749d7682988SBenny Halevy continue; 4750d7682988SBenny Halevy } 47514864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 475236acb66bSBenny Halevy } 4753c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 475436acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 475536acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 47561da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 47571da177e4SLinus Torvalds clp->cl_clientid.cl_id); 47584864af97STrond Myklebust list_del_init(&clp->cl_lru); 47591da177e4SLinus Torvalds expire_client(clp); 47601da177e4SLinus Torvalds } 4761cdc97505SBenny Halevy spin_lock(&state_lock); 4762e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 47631da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 47641da177e4SLinus Torvalds if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { 4765a832e7aeSJeff Layton t = dp->dl_time - cutoff; 4766a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 47671da177e4SLinus Torvalds break; 47681da177e4SLinus Torvalds } 47693fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 477042690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 47711da177e4SLinus Torvalds } 4772cdc97505SBenny Halevy spin_unlock(&state_lock); 47732d4a532dSJeff Layton while (!list_empty(&reaplist)) { 47742d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 47752d4a532dSJeff Layton dl_recall_lru); 47762d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 47773bd64a5bSJ. Bruce Fields revoke_delegation(dp); 47781da177e4SLinus Torvalds } 4779217526e7SJeff Layton 4780217526e7SJeff Layton spin_lock(&nn->client_lock); 4781217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 4782217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 4783217526e7SJeff Layton oo_close_lru); 4784217526e7SJeff Layton if (time_after((unsigned long)oo->oo_time, 4785217526e7SJeff Layton (unsigned long)cutoff)) { 4786a832e7aeSJeff Layton t = oo->oo_time - cutoff; 4787a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 47881da177e4SLinus Torvalds break; 47891da177e4SLinus Torvalds } 4790217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 4791217526e7SJeff Layton stp = oo->oo_last_closed_stid; 4792217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 4793217526e7SJeff Layton spin_unlock(&nn->client_lock); 4794217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 4795217526e7SJeff Layton spin_lock(&nn->client_lock); 47961da177e4SLinus Torvalds } 4797217526e7SJeff Layton spin_unlock(&nn->client_lock); 4798217526e7SJeff Layton 47997919d0a2SJeff Layton /* 48007919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 48017919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 48027919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 48037919d0a2SJeff Layton * under the assumption that the client is no longer interested. 48047919d0a2SJeff Layton * 48057919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 48067919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 48077919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 48087919d0a2SJeff Layton * indefinitely once the lock does become free. 48097919d0a2SJeff Layton */ 48107919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 48110cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 48127919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 48137919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 48147919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 48157919d0a2SJeff Layton if (time_after((unsigned long)nbl->nbl_time, 48167919d0a2SJeff Layton (unsigned long)cutoff)) { 48177919d0a2SJeff Layton t = nbl->nbl_time - cutoff; 48187919d0a2SJeff Layton new_timeo = min(new_timeo, t); 48197919d0a2SJeff Layton break; 48207919d0a2SJeff Layton } 48217919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 48227919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 48237919d0a2SJeff Layton } 48240cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 48257919d0a2SJeff Layton 48267919d0a2SJeff Layton while (!list_empty(&reaplist)) { 482764ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 48287919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 48297919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 48307919d0a2SJeff Layton posix_unblock_lock(&nbl->nbl_lock); 48317919d0a2SJeff Layton free_blocked_lock(nbl); 48327919d0a2SJeff Layton } 483303f318caSJ. Bruce Fields out: 4834a832e7aeSJeff Layton new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 4835a832e7aeSJeff Layton return new_timeo; 48361da177e4SLinus Torvalds } 48371da177e4SLinus Torvalds 4838a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 4839a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 4840a254b246SHarvey Harrison 4841a254b246SHarvey Harrison static void 484209121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 48431da177e4SLinus Torvalds { 48441da177e4SLinus Torvalds time_t t; 48452e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 484609121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 484709121281SStanislav Kinsbursky laundromat_work); 48481da177e4SLinus Torvalds 484909121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 48501da177e4SLinus Torvalds dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); 485109121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 48521da177e4SLinus Torvalds } 48531da177e4SLinus Torvalds 48548fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 4855f8816512SNeilBrown { 48568fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 4857f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 4858f7a4d872SJ. Bruce Fields return nfs_ok; 48591da177e4SLinus Torvalds } 48601da177e4SLinus Torvalds 48611da177e4SLinus Torvalds static inline int 486282c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 48631da177e4SLinus Torvalds { 486482c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 486582c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 486682c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 48671da177e4SLinus Torvalds } 48681da177e4SLinus Torvalds 48691da177e4SLinus Torvalds static inline int 487082c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 48711da177e4SLinus Torvalds { 487282c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 487382c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 48741da177e4SLinus Torvalds } 48751da177e4SLinus Torvalds 48761da177e4SLinus Torvalds static 4877dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 48781da177e4SLinus Torvalds { 4879b37ad28bSAl Viro __be32 status = nfserr_openmode; 48801da177e4SLinus Torvalds 488102921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 488202921914SJ. Bruce Fields if (stp->st_openstp) 488302921914SJ. Bruce Fields stp = stp->st_openstp; 488482c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 48851da177e4SLinus Torvalds goto out; 488682c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 48871da177e4SLinus Torvalds goto out; 48881da177e4SLinus Torvalds status = nfs_ok; 48891da177e4SLinus Torvalds out: 48901da177e4SLinus Torvalds return status; 48911da177e4SLinus Torvalds } 48921da177e4SLinus Torvalds 4893b37ad28bSAl Viro static inline __be32 48945ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 48951da177e4SLinus Torvalds { 4896203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 48971da177e4SLinus Torvalds return nfs_ok; 4898c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 489925985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 49001da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 49011da177e4SLinus Torvalds return nfserr_grace; 49021da177e4SLinus Torvalds } else if (flags & WR_STATE) 49031da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 49041da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 49051da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 49061da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 49071da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 49081da177e4SLinus Torvalds } 49091da177e4SLinus Torvalds 49101da177e4SLinus Torvalds /* 49111da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 49121da177e4SLinus Torvalds * that are not able to provide mandatory locking. 49131da177e4SLinus Torvalds */ 49141da177e4SLinus Torvalds static inline int 49155ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 49161da177e4SLinus Torvalds { 4917c87fb4a3SJ. Bruce Fields return opens_in_grace(net) && mandatory_lock(inode); 49181da177e4SLinus Torvalds } 49191da177e4SLinus Torvalds 492057b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 49210836f587SJ. Bruce Fields { 49226668958fSAndy Adamson /* 49236668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 49246668958fSAndy Adamson * when it is zero. 49256668958fSAndy Adamson */ 492628dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 492781b82965SJ. Bruce Fields return nfs_ok; 492881b82965SJ. Bruce Fields 492981b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 493081b82965SJ. Bruce Fields return nfs_ok; 49316668958fSAndy Adamson 49320836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 493314b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 49340836f587SJ. Bruce Fields return nfserr_bad_stateid; 49350836f587SJ. Bruce Fields /* 493681b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 493781b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 493881b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 493981b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 494081b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 494181b82965SJ. Bruce Fields * but better performance may result in retrying IO that 494281b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 494381b82965SJ. Bruce Fields * reordered in flight: 49440836f587SJ. Bruce Fields */ 49450836f587SJ. Bruce Fields return nfserr_old_stateid; 49460836f587SJ. Bruce Fields } 49470836f587SJ. Bruce Fields 494803da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 494903da3169STrond Myklebust { 495003da3169STrond Myklebust __be32 ret; 495103da3169STrond Myklebust 495203da3169STrond Myklebust spin_lock(&s->sc_lock); 495303da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 495403da3169STrond Myklebust if (ret == nfs_ok) 495503da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 495603da3169STrond Myklebust spin_unlock(&s->sc_lock); 495703da3169STrond Myklebust return ret; 495803da3169STrond Myklebust } 495903da3169STrond Myklebust 4960ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 4961ebe9cb3bSChristoph Hellwig { 4962ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 4963ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 4964ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 4965ebe9cb3bSChristoph Hellwig return nfs_ok; 4966ebe9cb3bSChristoph Hellwig } 4967ebe9cb3bSChristoph Hellwig 49687df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 496917456804SBryan Schumaker { 497097b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 49711af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 497217456804SBryan Schumaker 4973ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 4974ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 49751af71cc8SJeff Layton return status; 49767df302f7SChuck Lever /* Client debugging aid. */ 49777df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 49787df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 49797df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 49807df302f7SChuck Lever sizeof(addr_str)); 49817df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 49827df302f7SChuck Lever "with incorrect client ID\n", addr_str); 49831af71cc8SJeff Layton return status; 49847df302f7SChuck Lever } 49851af71cc8SJeff Layton spin_lock(&cl->cl_lock); 49861af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 498797b7e3b6SJ. Bruce Fields if (!s) 49881af71cc8SJeff Layton goto out_unlock; 498903da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 499017456804SBryan Schumaker if (status) 49911af71cc8SJeff Layton goto out_unlock; 499223340032SJ. Bruce Fields switch (s->sc_type) { 499323340032SJ. Bruce Fields case NFS4_DELEG_STID: 49941af71cc8SJeff Layton status = nfs_ok; 49951af71cc8SJeff Layton break; 49963bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 49971af71cc8SJeff Layton status = nfserr_deleg_revoked; 49981af71cc8SJeff Layton break; 499923340032SJ. Bruce Fields case NFS4_OPEN_STID: 500023340032SJ. Bruce Fields case NFS4_LOCK_STID: 5001ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 50021af71cc8SJeff Layton break; 500323340032SJ. Bruce Fields default: 500423340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 5005b0fc29d6STrond Myklebust /* Fallthrough */ 500623340032SJ. Bruce Fields case NFS4_CLOSED_STID: 5007b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 50081af71cc8SJeff Layton status = nfserr_bad_stateid; 500923340032SJ. Bruce Fields } 50101af71cc8SJeff Layton out_unlock: 50111af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 50121af71cc8SJeff Layton return status; 501317456804SBryan Schumaker } 501417456804SBryan Schumaker 5015cd61c522SChristoph Hellwig __be32 50162dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 50172dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 50182dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 501938c2f4b1SJ. Bruce Fields { 50200eb6f20aSJ. Bruce Fields __be32 status; 502195da1b3aSAndrew Elble bool return_revoked = false; 502295da1b3aSAndrew Elble 502395da1b3aSAndrew Elble /* 502495da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 502595da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 502695da1b3aSAndrew Elble */ 502795da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 502895da1b3aSAndrew Elble return_revoked = true; 502995da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 503095da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 503138c2f4b1SJ. Bruce Fields 5032ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5033ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 503438c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 50354b24ca7dSJeff Layton status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn); 5036a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 50374b24ca7dSJeff Layton if (cstate->session) 5038a8a7c677STrond Myklebust return nfserr_bad_stateid; 503938c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 5040a8a7c677STrond Myklebust } 50410eb6f20aSJ. Bruce Fields if (status) 50420eb6f20aSJ. Bruce Fields return status; 50434b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 504438c2f4b1SJ. Bruce Fields if (!*s) 504538c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 504695da1b3aSAndrew Elble if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 504795da1b3aSAndrew Elble nfs4_put_stid(*s); 504895da1b3aSAndrew Elble if (cstate->minorversion) 504995da1b3aSAndrew Elble return nfserr_deleg_revoked; 505095da1b3aSAndrew Elble return nfserr_bad_stateid; 505195da1b3aSAndrew Elble } 505238c2f4b1SJ. Bruce Fields return nfs_ok; 505338c2f4b1SJ. Bruce Fields } 505438c2f4b1SJ. Bruce Fields 5055a0649b2dSChristoph Hellwig static struct file * 5056a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 5057a0649b2dSChristoph Hellwig { 5058af90f707SChristoph Hellwig if (!s) 5059af90f707SChristoph Hellwig return NULL; 5060af90f707SChristoph Hellwig 5061a0649b2dSChristoph Hellwig switch (s->sc_type) { 5062a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 5063a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 5064a0649b2dSChristoph Hellwig return NULL; 5065a0649b2dSChristoph Hellwig return get_file(s->sc_file->fi_deleg_file); 5066a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 5067a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 5068a0649b2dSChristoph Hellwig if (flags & RD_STATE) 5069a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 5070a0649b2dSChristoph Hellwig else 5071a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 5072a0649b2dSChristoph Hellwig break; 5073a0649b2dSChristoph Hellwig } 5074a0649b2dSChristoph Hellwig 5075a0649b2dSChristoph Hellwig return NULL; 5076a0649b2dSChristoph Hellwig } 5077a0649b2dSChristoph Hellwig 5078a0649b2dSChristoph Hellwig static __be32 5079a0649b2dSChristoph Hellwig nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags) 5080a0649b2dSChristoph Hellwig { 5081a0649b2dSChristoph Hellwig __be32 status; 5082a0649b2dSChristoph Hellwig 5083a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 5084a0649b2dSChristoph Hellwig if (status) 5085a0649b2dSChristoph Hellwig return status; 5086a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 5087a0649b2dSChristoph Hellwig } 5088a0649b2dSChristoph Hellwig 5089af90f707SChristoph Hellwig static __be32 5090af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 5091af90f707SChristoph Hellwig struct file **filpp, bool *tmp_file, int flags) 5092af90f707SChristoph Hellwig { 5093af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 5094af90f707SChristoph Hellwig struct file *file; 5095af90f707SChristoph Hellwig __be32 status; 5096af90f707SChristoph Hellwig 5097af90f707SChristoph Hellwig file = nfs4_find_file(s, flags); 5098af90f707SChristoph Hellwig if (file) { 5099af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 5100af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 5101af90f707SChristoph Hellwig if (status) { 5102af90f707SChristoph Hellwig fput(file); 5103af90f707SChristoph Hellwig return status; 5104af90f707SChristoph Hellwig } 5105af90f707SChristoph Hellwig 5106af90f707SChristoph Hellwig *filpp = file; 5107af90f707SChristoph Hellwig } else { 5108af90f707SChristoph Hellwig status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp); 5109af90f707SChristoph Hellwig if (status) 5110af90f707SChristoph Hellwig return status; 5111af90f707SChristoph Hellwig 5112af90f707SChristoph Hellwig if (tmp_file) 5113af90f707SChristoph Hellwig *tmp_file = true; 5114af90f707SChristoph Hellwig } 5115af90f707SChristoph Hellwig 5116af90f707SChristoph Hellwig return 0; 5117af90f707SChristoph Hellwig } 5118af90f707SChristoph Hellwig 51191da177e4SLinus Torvalds /* 51201da177e4SLinus Torvalds * Checks for stateid operations 51211da177e4SLinus Torvalds */ 5122b37ad28bSAl Viro __be32 5123af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 5124aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 5125aa0d6aedSAnna Schumaker stateid_t *stateid, int flags, struct file **filpp, bool *tmp_file) 51261da177e4SLinus Torvalds { 5127a0649b2dSChristoph Hellwig struct inode *ino = d_inode(fhp->fh_dentry); 5128af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 51293320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5130af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 5131b37ad28bSAl Viro __be32 status; 51321da177e4SLinus Torvalds 51331da177e4SLinus Torvalds if (filpp) 51341da177e4SLinus Torvalds *filpp = NULL; 5135af90f707SChristoph Hellwig if (tmp_file) 5136af90f707SChristoph Hellwig *tmp_file = false; 51371da177e4SLinus Torvalds 51385ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 51391da177e4SLinus Torvalds return nfserr_grace; 51401da177e4SLinus Torvalds 5141af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 5142af90f707SChristoph Hellwig status = check_special_stateids(net, fhp, stateid, flags); 5143af90f707SChristoph Hellwig goto done; 5144af90f707SChristoph Hellwig } 51451da177e4SLinus Torvalds 51462dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 5147db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 51482dd6e458STrond Myklebust &s, nn); 514938c2f4b1SJ. Bruce Fields if (status) 5150c2d1d6a8STrond Myklebust return status; 515103da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 5152a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 51530c2a498fSJ. Bruce Fields if (status) 51540c2a498fSJ. Bruce Fields goto out; 5155a0649b2dSChristoph Hellwig 5156f7a4d872SJ. Bruce Fields switch (s->sc_type) { 5157f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 5158a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 5159f7a4d872SJ. Bruce Fields break; 5160f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 5161f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 5162a0649b2dSChristoph Hellwig status = nfs4_check_olstateid(fhp, openlockstateid(s), flags); 5163f7a4d872SJ. Bruce Fields break; 5164f7a4d872SJ. Bruce Fields default: 516514bcab1aSTrond Myklebust status = nfserr_bad_stateid; 5166a0649b2dSChristoph Hellwig break; 51671da177e4SLinus Torvalds } 51688fcd461dSJeff Layton if (status) 51698fcd461dSJeff Layton goto out; 51708fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 5171a0649b2dSChristoph Hellwig 5172af90f707SChristoph Hellwig done: 5173af90f707SChristoph Hellwig if (!status && filpp) 5174af90f707SChristoph Hellwig status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags); 51751da177e4SLinus Torvalds out: 5176af90f707SChristoph Hellwig if (s) 5177fd911011STrond Myklebust nfs4_put_stid(s); 51781da177e4SLinus Torvalds return status; 51791da177e4SLinus Torvalds } 51801da177e4SLinus Torvalds 5181e1ca12dfSBryan Schumaker /* 518217456804SBryan Schumaker * Test if the stateid is valid 518317456804SBryan Schumaker */ 518417456804SBryan Schumaker __be32 518517456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5186eb69853dSChristoph Hellwig union nfsd4_op_u *u) 518717456804SBryan Schumaker { 5188eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 518903cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 519003cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 519103cfb420SBryan Schumaker 519203cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 51937df302f7SChuck Lever stateid->ts_id_status = 51947df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 519503cfb420SBryan Schumaker 519617456804SBryan Schumaker return nfs_ok; 519717456804SBryan Schumaker } 519817456804SBryan Schumaker 519942691398SChuck Lever static __be32 520042691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 520142691398SChuck Lever { 520242691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 520342691398SChuck Lever __be32 ret; 520442691398SChuck Lever 5205659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 5206659aefb6STrond Myklebust if (ret) 5207659aefb6STrond Myklebust goto out_put_stid; 520842691398SChuck Lever 520942691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 521042691398SChuck Lever if (ret) 521142691398SChuck Lever goto out; 521242691398SChuck Lever 521342691398SChuck Lever ret = nfserr_locks_held; 521442691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 521542691398SChuck Lever lockowner(stp->st_stateowner))) 521642691398SChuck Lever goto out; 521742691398SChuck Lever 521842691398SChuck Lever release_lock_stateid(stp); 521942691398SChuck Lever ret = nfs_ok; 522042691398SChuck Lever 522142691398SChuck Lever out: 522242691398SChuck Lever mutex_unlock(&stp->st_mutex); 5223659aefb6STrond Myklebust out_put_stid: 522442691398SChuck Lever nfs4_put_stid(s); 522542691398SChuck Lever return ret; 522642691398SChuck Lever } 522742691398SChuck Lever 5228e1ca12dfSBryan Schumaker __be32 5229e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5230eb69853dSChristoph Hellwig union nfsd4_op_u *u) 5231e1ca12dfSBryan Schumaker { 5232eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 5233e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 52342da1cec7SJ. Bruce Fields struct nfs4_stid *s; 52353bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 523638c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 52372da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 5238e1ca12dfSBryan Schumaker 52391af71cc8SJeff Layton spin_lock(&cl->cl_lock); 52401af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 52412da1cec7SJ. Bruce Fields if (!s) 52421af71cc8SJeff Layton goto out_unlock; 524303da3169STrond Myklebust spin_lock(&s->sc_lock); 52442da1cec7SJ. Bruce Fields switch (s->sc_type) { 52452da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 5246e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 52471af71cc8SJeff Layton break; 52482da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 52491af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 52501af71cc8SJeff Layton if (ret) 52511af71cc8SJeff Layton break; 52521af71cc8SJeff Layton ret = nfserr_locks_held; 52531af71cc8SJeff Layton break; 52542da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 525503da3169STrond Myklebust spin_unlock(&s->sc_lock); 5256a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 52571af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 525842691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 52591af71cc8SJeff Layton goto out; 52603bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 526103da3169STrond Myklebust spin_unlock(&s->sc_lock); 52623bd64a5bSJ. Bruce Fields dp = delegstateid(s); 52632d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 52642d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 52656011695dSTrond Myklebust nfs4_put_stid(s); 52663bd64a5bSJ. Bruce Fields ret = nfs_ok; 52671af71cc8SJeff Layton goto out; 52681af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 5269e1ca12dfSBryan Schumaker } 527003da3169STrond Myklebust spin_unlock(&s->sc_lock); 52711af71cc8SJeff Layton out_unlock: 52721af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 5273e1ca12dfSBryan Schumaker out: 5274e1ca12dfSBryan Schumaker return ret; 5275e1ca12dfSBryan Schumaker } 5276e1ca12dfSBryan Schumaker 52774c4cd222SNeilBrown static inline int 52784c4cd222SNeilBrown setlkflg (int type) 52794c4cd222SNeilBrown { 52804c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 52814c4cd222SNeilBrown RD_STATE : WR_STATE; 52824c4cd222SNeilBrown } 52831da177e4SLinus Torvalds 5284dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 5285c0a5d93eSJ. Bruce Fields { 5286c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 5287c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 5288c0a5d93eSJ. Bruce Fields __be32 status; 5289c0a5d93eSJ. Bruce Fields 5290c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 5291c0a5d93eSJ. Bruce Fields if (status) 5292c0a5d93eSJ. Bruce Fields return status; 52939271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 52949271d7e5STrond Myklebust if (status != nfs_ok) 52959271d7e5STrond Myklebust return status; 5296f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 529735a92fe8SJeff Layton if (status == nfs_ok) 529835a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 529935a92fe8SJeff Layton if (status != nfs_ok) 5300feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 5301f7a4d872SJ. Bruce Fields return status; 5302c0a5d93eSJ. Bruce Fields } 5303c0a5d93eSJ. Bruce Fields 53041da177e4SLinus Torvalds /* 53051da177e4SLinus Torvalds * Checks for sequence id mutating operations. 53061da177e4SLinus Torvalds */ 5307b37ad28bSAl Viro static __be32 5308dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 53092288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 53103320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 53113320fef1SStanislav Kinsbursky struct nfsd_net *nn) 53121da177e4SLinus Torvalds { 53130836f587SJ. Bruce Fields __be32 status; 531438c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 5315e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 53161da177e4SLinus Torvalds 53178c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 53188c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 53191da177e4SLinus Torvalds 53201da177e4SLinus Torvalds *stpp = NULL; 53212dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 5322c0a5d93eSJ. Bruce Fields if (status) 5323c0a5d93eSJ. Bruce Fields return status; 5324e17f99b7STrond Myklebust stp = openlockstateid(s); 532558fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 53261da177e4SLinus Torvalds 5327e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 5328fd911011STrond Myklebust if (!status) 5329e17f99b7STrond Myklebust *stpp = stp; 5330fd911011STrond Myklebust else 5331fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 5332e17f99b7STrond Myklebust return status; 53331da177e4SLinus Torvalds } 53341da177e4SLinus Torvalds 53353320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 53363320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 5337c0a5d93eSJ. Bruce Fields { 5338c0a5d93eSJ. Bruce Fields __be32 status; 5339c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 53404cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 53411da177e4SLinus Torvalds 5342c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 53434cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 53440836f587SJ. Bruce Fields if (status) 53450836f587SJ. Bruce Fields return status; 53464cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 53474cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 5348feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 53494cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 5350c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 53514cbfc9f7STrond Myklebust } 53524cbfc9f7STrond Myklebust *stpp = stp; 53533a4f98bbSNeilBrown return nfs_ok; 53541da177e4SLinus Torvalds } 53551da177e4SLinus Torvalds 5356b37ad28bSAl Viro __be32 5357ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5358eb69853dSChristoph Hellwig union nfsd4_op_u *u) 53591da177e4SLinus Torvalds { 5360eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 5361b37ad28bSAl Viro __be32 status; 5362fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 5363dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 53643320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 53651da177e4SLinus Torvalds 5366a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 5367a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 53681da177e4SLinus Torvalds 5369ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 5370a8cddc5dSJ. Bruce Fields if (status) 5371a8cddc5dSJ. Bruce Fields return status; 53721da177e4SLinus Torvalds 53739072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 5374ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 53753320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 53769072d5c6SJ. Bruce Fields if (status) 53771da177e4SLinus Torvalds goto out; 5378fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 537968b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 538035a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 5381feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 53822585fc79STrond Myklebust goto put_stateid; 538335a92fe8SJeff Layton } 5384dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 53859767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 5386feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 53878c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 5388dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 5389c7b9a459SNeilBrown 53902a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 539168b66e82SJ. Bruce Fields status = nfs_ok; 53922585fc79STrond Myklebust put_stateid: 53932585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 53941da177e4SLinus Torvalds out: 53959411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 53961da177e4SLinus Torvalds return status; 53971da177e4SLinus Torvalds } 53981da177e4SLinus Torvalds 53996409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 54001da177e4SLinus Torvalds { 540182c5ff1bSJeff Layton if (!test_access(access, stp)) 54026409a5a6SJ. Bruce Fields return; 540311b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 540482c5ff1bSJeff Layton clear_access(access, stp); 5405f197c271SJ. Bruce Fields } 54066409a5a6SJ. Bruce Fields 54076409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 54086409a5a6SJ. Bruce Fields { 54096409a5a6SJ. Bruce Fields switch (to_access) { 54106409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 54116409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 54126409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 54136409a5a6SJ. Bruce Fields break; 54146409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 54156409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 54166409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 54176409a5a6SJ. Bruce Fields break; 54186409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 54196409a5a6SJ. Bruce Fields break; 54206409a5a6SJ. Bruce Fields default: 5421063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 54221da177e4SLinus Torvalds } 54231da177e4SLinus Torvalds } 54241da177e4SLinus Torvalds 5425b37ad28bSAl Viro __be32 5426ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 5427eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 54281da177e4SLinus Torvalds { 5429eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 5430b37ad28bSAl Viro __be32 status; 5431dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 54323320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 54331da177e4SLinus Torvalds 5434a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 5435a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 54361da177e4SLinus Torvalds 5437c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 54382c8bd7e0SBenny Halevy if (od->od_deleg_want) 54392c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 54402c8bd7e0SBenny Halevy od->od_deleg_want); 54411da177e4SLinus Torvalds 5442c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 54433320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 54449072d5c6SJ. Bruce Fields if (status) 54451da177e4SLinus Torvalds goto out; 54461da177e4SLinus Torvalds status = nfserr_inval; 544782c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 5448c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 54491da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 54500667b1e9STrond Myklebust goto put_stateid; 54511da177e4SLinus Torvalds } 5452ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 5453c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 54541da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 54550667b1e9STrond Myklebust goto put_stateid; 54561da177e4SLinus Torvalds } 54576409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 5458ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 54599767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 54601da177e4SLinus Torvalds status = nfs_ok; 54610667b1e9STrond Myklebust put_stateid: 5462feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 54630667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 54641da177e4SLinus Torvalds out: 54659411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 54661da177e4SLinus Torvalds return status; 54671da177e4SLinus Torvalds } 54681da177e4SLinus Torvalds 5469f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 5470f7a4d872SJ. Bruce Fields { 5471acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 5472e8568739SJeff Layton bool unhashed; 5473d83017f9SJeff Layton LIST_HEAD(reaplist); 5474acf9295bSTrond Myklebust 54752c41beb0SJeff Layton spin_lock(&clp->cl_lock); 5476e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 5477acf9295bSTrond Myklebust 5478d83017f9SJeff Layton if (clp->cl_minorversion) { 5479e8568739SJeff Layton if (unhashed) 5480d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 5481d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 5482d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 5483d83017f9SJeff Layton } else { 5484d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 5485d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 5486e8568739SJeff Layton if (unhashed) 5487d3134b10SJeff Layton move_to_close_lru(s, clp->net); 548838c387b5SJ. Bruce Fields } 5489d83017f9SJeff Layton } 549038c387b5SJ. Bruce Fields 54911da177e4SLinus Torvalds /* 54921da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 54931da177e4SLinus Torvalds */ 5494b37ad28bSAl Viro __be32 5495ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5496eb69853dSChristoph Hellwig union nfsd4_op_u *u) 54971da177e4SLinus Torvalds { 5498eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 5499b37ad28bSAl Viro __be32 status; 5500dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 55013320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 55023320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 55031da177e4SLinus Torvalds 5504a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 5505a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 55061da177e4SLinus Torvalds 5507f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 5508f7a4d872SJ. Bruce Fields &close->cl_stateid, 5509f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 55103320fef1SStanislav Kinsbursky &stp, nn); 55119411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 55129072d5c6SJ. Bruce Fields if (status) 55131da177e4SLinus Torvalds goto out; 551415ca08d3STrond Myklebust 551515ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 5516bd2decacSJeff Layton 5517bd2decacSJeff Layton /* 5518bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 5519bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 5520bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 5521bd2decacSJeff Layton * that racing ops see that there was a state change. 5522bd2decacSJeff Layton */ 55239767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 55241da177e4SLinus Torvalds 5525f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 552615ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 55278a0b589dSTrond Myklebust 5528bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 5529bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 5530bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 5531bd2decacSJeff Layton * universally. 5532bd2decacSJeff Layton * 5533bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 5534bd2decacSJeff Layton */ 5535bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 5536fb500a7cSTrond Myklebust 55378a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 55388a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 55391da177e4SLinus Torvalds out: 55401da177e4SLinus Torvalds return status; 55411da177e4SLinus Torvalds } 55421da177e4SLinus Torvalds 5543b37ad28bSAl Viro __be32 5544ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5545eb69853dSChristoph Hellwig union nfsd4_op_u *u) 55461da177e4SLinus Torvalds { 5547eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 5548203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 5549203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 555038c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 5551b37ad28bSAl Viro __be32 status; 55523320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 55531da177e4SLinus Torvalds 5554ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 5555203a8c8eSJ. Bruce Fields return status; 55561da177e4SLinus Torvalds 55572dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 555838c2f4b1SJ. Bruce Fields if (status) 5559203a8c8eSJ. Bruce Fields goto out; 556038c2f4b1SJ. Bruce Fields dp = delegstateid(s); 556103da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 5562203a8c8eSJ. Bruce Fields if (status) 5563fd911011STrond Myklebust goto put_stateid; 5564203a8c8eSJ. Bruce Fields 55653bd64a5bSJ. Bruce Fields destroy_delegation(dp); 5566fd911011STrond Myklebust put_stateid: 5567fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 55681da177e4SLinus Torvalds out: 55691da177e4SLinus Torvalds return status; 55701da177e4SLinus Torvalds } 55711da177e4SLinus Torvalds 557287df4de8SBenny Halevy static inline u64 557387df4de8SBenny Halevy end_offset(u64 start, u64 len) 557487df4de8SBenny Halevy { 557587df4de8SBenny Halevy u64 end; 557687df4de8SBenny Halevy 557787df4de8SBenny Halevy end = start + len; 557887df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 557987df4de8SBenny Halevy } 558087df4de8SBenny Halevy 558187df4de8SBenny Halevy /* last octet in a range */ 558287df4de8SBenny Halevy static inline u64 558387df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 558487df4de8SBenny Halevy { 558587df4de8SBenny Halevy u64 end; 558687df4de8SBenny Halevy 5587063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 558887df4de8SBenny Halevy end = start + len; 558987df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 559087df4de8SBenny Halevy } 559187df4de8SBenny Halevy 55921da177e4SLinus Torvalds /* 55931da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 55941da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 55951da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 55961da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 55971da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 55981da177e4SLinus Torvalds * the VFS, but this is a very deep change! 55991da177e4SLinus Torvalds */ 56001da177e4SLinus Torvalds static inline void 56011da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 56021da177e4SLinus Torvalds { 56031da177e4SLinus Torvalds if (lock->fl_start < 0) 56041da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 56051da177e4SLinus Torvalds if (lock->fl_end < 0) 56061da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 56071da177e4SLinus Torvalds } 56081da177e4SLinus Torvalds 5609cae80b30SJeff Layton static fl_owner_t 5610cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner) 5611aef9583bSKinglong Mee { 5612cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5613cae80b30SJeff Layton 5614cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 5615cae80b30SJeff Layton return owner; 5616aef9583bSKinglong Mee } 5617aef9583bSKinglong Mee 5618cae80b30SJeff Layton static void 5619cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner) 5620aef9583bSKinglong Mee { 5621cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 5622aef9583bSKinglong Mee 5623cae80b30SJeff Layton if (lo) 5624aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 5625aef9583bSKinglong Mee } 5626aef9583bSKinglong Mee 562776d348faSJeff Layton static void 562876d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 562976d348faSJeff Layton { 563076d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 563176d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 563276d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 563376d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 563476d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 563576d348faSJeff Layton bool queue = false; 563676d348faSJeff Layton 56377919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 56380cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 563976d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 564076d348faSJeff Layton list_del_init(&nbl->nbl_list); 56417919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 564276d348faSJeff Layton queue = true; 564376d348faSJeff Layton } 56440cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 564576d348faSJeff Layton 564676d348faSJeff Layton if (queue) 564776d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 564876d348faSJeff Layton } 564976d348faSJeff Layton 56507b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 565176d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 5652aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 5653aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 5654d5b9026aSNeilBrown }; 56551da177e4SLinus Torvalds 56561da177e4SLinus Torvalds static inline void 56571da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 56581da177e4SLinus Torvalds { 5659fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 56601da177e4SLinus Torvalds 5661d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 5662fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 5663fe0750e5SJ. Bruce Fields deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, 5664fe0750e5SJ. Bruce Fields lo->lo_owner.so_owner.len, GFP_KERNEL); 56657c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 56667c13f344SJ. Bruce Fields /* We just don't care that much */ 56677c13f344SJ. Bruce Fields goto nevermind; 5668fe0750e5SJ. Bruce Fields deny->ld_owner.len = lo->lo_owner.so_owner.len; 5669fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 5670d5b9026aSNeilBrown } else { 56717c13f344SJ. Bruce Fields nevermind: 56727c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 56737c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 5674d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 5675d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 56761da177e4SLinus Torvalds } 56771da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 567887df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 567987df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 56801da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 56811da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 56821da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 56831da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 56841da177e4SLinus Torvalds } 56851da177e4SLinus Torvalds 5686fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5687c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 56881da177e4SLinus Torvalds { 5689d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 5690b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 56911da177e4SLinus Torvalds 56920a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 56930a880a28STrond Myklebust 5694d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 5695d4f0489fSTrond Myklebust so_strhash) { 5696b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 5697b3c32bcdSTrond Myklebust continue; 5698b5971afaSKinglong Mee if (same_owner_str(so, owner)) 5699b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 57001da177e4SLinus Torvalds } 57011da177e4SLinus Torvalds return NULL; 57021da177e4SLinus Torvalds } 57031da177e4SLinus Torvalds 5704c58c6610STrond Myklebust static struct nfs4_lockowner * 5705c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 5706c58c6610STrond Myklebust { 5707c58c6610STrond Myklebust struct nfs4_lockowner *lo; 5708c58c6610STrond Myklebust 5709d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5710c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 5711d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5712c58c6610STrond Myklebust return lo; 5713c58c6610STrond Myklebust } 5714c58c6610STrond Myklebust 57158f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 57168f4b54c5SJeff Layton { 5717c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 57188f4b54c5SJeff Layton } 57198f4b54c5SJeff Layton 57206b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 57216b180f0bSJeff Layton { 57226b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 57236b180f0bSJeff Layton 57246b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 57256b180f0bSJeff Layton } 57266b180f0bSJeff Layton 57276b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 57288f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 57296b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 57306b180f0bSJeff Layton }; 57316b180f0bSJeff Layton 57321da177e4SLinus Torvalds /* 57331da177e4SLinus Torvalds * Alloc a lock owner structure. 57341da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 573525985edcSLucas De Marchi * occurred. 57361da177e4SLinus Torvalds * 573716bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 57381da177e4SLinus Torvalds */ 5739fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 5740c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 5741c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 5742c58c6610STrond Myklebust struct nfsd4_lock *lock) 5743c58c6610STrond Myklebust { 5744c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 57451da177e4SLinus Torvalds 5746fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 5747fe0750e5SJ. Bruce Fields if (!lo) 57481da177e4SLinus Torvalds return NULL; 574976d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 5750fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 5751fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 57525db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 57536b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 5754d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 5755c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 5756c58c6610STrond Myklebust if (ret == NULL) { 5757c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 5758d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 5759c58c6610STrond Myklebust ret = lo; 5760c58c6610STrond Myklebust } else 5761d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 5762d50ffdedSKinglong Mee 5763d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5764340f0ba1SJ. Bruce Fields return ret; 57651da177e4SLinus Torvalds } 57661da177e4SLinus Torvalds 5767fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 5768fd1fd685STrond Myklebust find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) 5769fd1fd685STrond Myklebust { 5770fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 5771fd1fd685STrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 5772fd1fd685STrond Myklebust 5773fd1fd685STrond Myklebust lockdep_assert_held(&clp->cl_lock); 5774fd1fd685STrond Myklebust 5775fd1fd685STrond Myklebust list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { 5776fd1fd685STrond Myklebust if (lst->st_stid.sc_type != NFS4_LOCK_STID) 5777fd1fd685STrond Myklebust continue; 5778fd1fd685STrond Myklebust if (lst->st_stid.sc_file == fp) { 5779fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 5780fd1fd685STrond Myklebust return lst; 5781fd1fd685STrond Myklebust } 5782fd1fd685STrond Myklebust } 5783fd1fd685STrond Myklebust return NULL; 5784fd1fd685STrond Myklebust } 5785fd1fd685STrond Myklebust 5786beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 5787356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 5788356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 5789f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 57901da177e4SLinus Torvalds { 5791d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 5792beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 57931da177e4SLinus Torvalds 5794beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 57954f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 5796beeca19cSTrond Myklebust retry: 5797beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 5798beeca19cSTrond Myklebust spin_lock(&fp->fi_lock); 5799beeca19cSTrond Myklebust retstp = find_lock_stateid(lo, fp); 5800beeca19cSTrond Myklebust if (retstp) 5801beeca19cSTrond Myklebust goto out_unlock; 5802356a95ecSJeff Layton 5803a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 58043abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 5805b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 580613cd2184SNeilBrown get_nfs4_file(fp); 580711b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 58080997b173SJ. Bruce Fields stp->st_access_bmap = 0; 58091da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 58104c4cd222SNeilBrown stp->st_openstp = open_stp; 58113c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 58121c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 58131d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 5814beeca19cSTrond Myklebust out_unlock: 58151d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 5816beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 5817beeca19cSTrond Myklebust if (retstp) { 5818beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 5819beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 5820beeca19cSTrond Myklebust goto retry; 5821beeca19cSTrond Myklebust } 5822beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 5823beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 5824beeca19cSTrond Myklebust stp = retstp; 5825beeca19cSTrond Myklebust } 5826beeca19cSTrond Myklebust return stp; 58271da177e4SLinus Torvalds } 58281da177e4SLinus Torvalds 5829c53530daSJeff Layton static struct nfs4_ol_stateid * 5830356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 5831356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 5832356a95ecSJeff Layton bool *new) 5833356a95ecSJeff Layton { 5834356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 5835356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 5836356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 5837356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 5838356a95ecSJeff Layton 5839beeca19cSTrond Myklebust *new = false; 5840356a95ecSJeff Layton spin_lock(&clp->cl_lock); 5841356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 5842356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 5843beeca19cSTrond Myklebust if (lst != NULL) { 5844beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 5845beeca19cSTrond Myklebust goto out; 5846beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 5847beeca19cSTrond Myklebust } 5848d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 5849356a95ecSJeff Layton if (ns == NULL) 5850356a95ecSJeff Layton return NULL; 5851356a95ecSJeff Layton 5852beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 5853beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 5854356a95ecSJeff Layton *new = true; 5855beeca19cSTrond Myklebust else 5856356a95ecSJeff Layton nfs4_put_stid(ns); 5857beeca19cSTrond Myklebust out: 5858356a95ecSJeff Layton return lst; 5859356a95ecSJeff Layton } 5860c53530daSJeff Layton 5861fd39ca9aSNeilBrown static int 58621da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 58631da177e4SLinus Torvalds { 586487df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 5865e7969315SKinglong Mee (length > ~offset))); 58661da177e4SLinus Torvalds } 58671da177e4SLinus Torvalds 5868dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 58690997b173SJ. Bruce Fields { 587011b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 58710997b173SJ. Bruce Fields 58727214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 58737214e860SJeff Layton 587482c5ff1bSJeff Layton if (test_access(access, lock_stp)) 58750997b173SJ. Bruce Fields return; 587612659651SJeff Layton __nfs4_file_get_access(fp, access); 587782c5ff1bSJeff Layton set_access(access, lock_stp); 58780997b173SJ. Bruce Fields } 58790997b173SJ. Bruce Fields 5880356a95ecSJeff Layton static __be32 5881356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 5882356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 5883356a95ecSJeff Layton struct nfsd4_lock *lock, 5884dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 588564a284d0SJ. Bruce Fields { 58865db1c03fSJeff Layton __be32 status; 588711b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 588864a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 588964a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 58902b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 589164a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 5892dd257933SJeff Layton struct nfs4_ol_stateid *lst; 589364a284d0SJ. Bruce Fields unsigned int strhashval; 589464a284d0SJ. Bruce Fields 5895c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 5896c53530daSJeff Layton if (!lo) { 589776f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 589864a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 589964a284d0SJ. Bruce Fields if (lo == NULL) 590064a284d0SJ. Bruce Fields return nfserr_jukebox; 5901c53530daSJeff Layton } else { 5902c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 59035db1c03fSJeff Layton status = nfserr_bad_seqid; 5904c53530daSJeff Layton if (!cstate->minorversion && 5905c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 59065db1c03fSJeff Layton goto out; 5907c53530daSJeff Layton } 5908c53530daSJeff Layton 5909dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 5910dd257933SJeff Layton if (lst == NULL) { 59115db1c03fSJeff Layton status = nfserr_jukebox; 59125db1c03fSJeff Layton goto out; 591364a284d0SJ. Bruce Fields } 5914dd257933SJeff Layton 59155db1c03fSJeff Layton status = nfs_ok; 5916dd257933SJeff Layton *plst = lst; 59175db1c03fSJeff Layton out: 59185db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 59195db1c03fSJeff Layton return status; 592064a284d0SJ. Bruce Fields } 592164a284d0SJ. Bruce Fields 59221da177e4SLinus Torvalds /* 59231da177e4SLinus Torvalds * LOCK operation 59241da177e4SLinus Torvalds */ 5925b37ad28bSAl Viro __be32 5926ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5927eb69853dSChristoph Hellwig union nfsd4_op_u *u) 59281da177e4SLinus Torvalds { 5929eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 5930fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 5931fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 59323d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 59330667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 59347214e860SJeff Layton struct nfs4_file *fp; 59357d947842SJ. Bruce Fields struct file *filp = NULL; 593676d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 593721179d81SJeff Layton struct file_lock *file_lock = NULL; 593821179d81SJeff Layton struct file_lock *conflock = NULL; 5939b37ad28bSAl Viro __be32 status = 0; 5940b34f27aaSJ. Bruce Fields int lkflg; 5941b8dd7b9aSAl Viro int err; 59425db1c03fSJeff Layton bool new = false; 594376d348faSJeff Layton unsigned char fl_type; 594476d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 59453320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 59463320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 59471da177e4SLinus Torvalds 59481da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 59491da177e4SLinus Torvalds (long long) lock->lk_offset, 59501da177e4SLinus Torvalds (long long) lock->lk_length); 59511da177e4SLinus Torvalds 59521da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 59531da177e4SLinus Torvalds return nfserr_inval; 59541da177e4SLinus Torvalds 5955ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 59568837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 5957a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 5958a6f6ef2fSAndy Adamson return status; 5959a6f6ef2fSAndy Adamson } 5960a6f6ef2fSAndy Adamson 59611da177e4SLinus Torvalds if (lock->lk_is_new) { 5962684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 5963684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 596476f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 5965684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 5966684e5638SJ. Bruce Fields sizeof(clientid_t)); 5967684e5638SJ. Bruce Fields 59681da177e4SLinus Torvalds status = nfserr_stale_clientid; 59692c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 59701da177e4SLinus Torvalds goto out; 59711da177e4SLinus Torvalds 59721da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 5973c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 59741da177e4SLinus Torvalds lock->lk_new_open_seqid, 59751da177e4SLinus Torvalds &lock->lk_new_open_stateid, 59763320fef1SStanislav Kinsbursky &open_stp, nn); 597737515177SNeilBrown if (status) 59781da177e4SLinus Torvalds goto out; 5979feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 5980fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 5981b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 5982684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 598376f6c9e1SKinglong Mee &lock->lk_new_clientid)) 5984b34f27aaSJ. Bruce Fields goto out; 598564a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 59865db1c03fSJeff Layton &lock_stp, &new); 59873d0fabd5STrond Myklebust } else { 5988dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 59891da177e4SLinus Torvalds lock->lk_old_lock_seqid, 59901da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 59913320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 59923d0fabd5STrond Myklebust } 59931da177e4SLinus Torvalds if (status) 59941da177e4SLinus Torvalds goto out; 5995fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 59961da177e4SLinus Torvalds 5997b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 5998b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 5999b34f27aaSJ. Bruce Fields if (status) 6000b34f27aaSJ. Bruce Fields goto out; 6001b34f27aaSJ. Bruce Fields 60020dd395dcSNeilBrown status = nfserr_grace; 60033320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 60040dd395dcSNeilBrown goto out; 60050dd395dcSNeilBrown status = nfserr_no_grace; 60063320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 60070dd395dcSNeilBrown goto out; 60080dd395dcSNeilBrown 600911b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 60101da177e4SLinus Torvalds switch (lock->lk_type) { 60111da177e4SLinus Torvalds case NFS4_READW_LT: 601276d348faSJeff Layton if (nfsd4_has_session(cstate)) 601376d348faSJeff Layton fl_flags |= FL_SLEEP; 601476d348faSJeff Layton /* Fallthrough */ 601576d348faSJeff Layton case NFS4_READ_LT: 60167214e860SJeff Layton spin_lock(&fp->fi_lock); 60177214e860SJeff Layton filp = find_readable_file_locked(fp); 60180997b173SJ. Bruce Fields if (filp) 60190997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 60207214e860SJeff Layton spin_unlock(&fp->fi_lock); 602176d348faSJeff Layton fl_type = F_RDLCK; 60221da177e4SLinus Torvalds break; 60231da177e4SLinus Torvalds case NFS4_WRITEW_LT: 602476d348faSJeff Layton if (nfsd4_has_session(cstate)) 602576d348faSJeff Layton fl_flags |= FL_SLEEP; 602676d348faSJeff Layton /* Fallthrough */ 602776d348faSJeff Layton case NFS4_WRITE_LT: 60287214e860SJeff Layton spin_lock(&fp->fi_lock); 60297214e860SJeff Layton filp = find_writeable_file_locked(fp); 60300997b173SJ. Bruce Fields if (filp) 60310997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 60327214e860SJeff Layton spin_unlock(&fp->fi_lock); 603376d348faSJeff Layton fl_type = F_WRLCK; 60341da177e4SLinus Torvalds break; 60351da177e4SLinus Torvalds default: 60361da177e4SLinus Torvalds status = nfserr_inval; 60371da177e4SLinus Torvalds goto out; 60381da177e4SLinus Torvalds } 603976d348faSJeff Layton 6040f9d7562fSJ. Bruce Fields if (!filp) { 6041f9d7562fSJ. Bruce Fields status = nfserr_openmode; 6042f9d7562fSJ. Bruce Fields goto out; 6043f9d7562fSJ. Bruce Fields } 6044aef9583bSKinglong Mee 604576d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 604676d348faSJeff Layton if (!nbl) { 604776d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 604876d348faSJeff Layton status = nfserr_jukebox; 604976d348faSJeff Layton goto out; 605076d348faSJeff Layton } 605176d348faSJeff Layton 605276d348faSJeff Layton file_lock = &nbl->nbl_lock; 605376d348faSJeff Layton file_lock->fl_type = fl_type; 6054aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 605521179d81SJeff Layton file_lock->fl_pid = current->tgid; 605621179d81SJeff Layton file_lock->fl_file = filp; 605776d348faSJeff Layton file_lock->fl_flags = fl_flags; 605821179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 605921179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 606021179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 606121179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 60621da177e4SLinus Torvalds 606321179d81SJeff Layton conflock = locks_alloc_lock(); 606421179d81SJeff Layton if (!conflock) { 606521179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 606621179d81SJeff Layton status = nfserr_jukebox; 606721179d81SJeff Layton goto out; 606821179d81SJeff Layton } 60691da177e4SLinus Torvalds 607076d348faSJeff Layton if (fl_flags & FL_SLEEP) { 60717919d0a2SJeff Layton nbl->nbl_time = jiffies; 60720cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 607376d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 60747919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 60750cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 607676d348faSJeff Layton } 607776d348faSJeff Layton 607821179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); 607976d348faSJeff Layton switch (err) { 60801da177e4SLinus Torvalds case 0: /* success! */ 60819767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 6082b8dd7b9aSAl Viro status = 0; 608303f318caSJ. Bruce Fields if (lock->lk_reclaim) 608403f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 6085eb76b3fdSAndy Adamson break; 608676d348faSJeff Layton case FILE_LOCK_DEFERRED: 608776d348faSJeff Layton nbl = NULL; 608876d348faSJeff Layton /* Fallthrough */ 608976d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 6090eb76b3fdSAndy Adamson status = nfserr_denied; 6091eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 609221179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 6093eb76b3fdSAndy Adamson break; 609476d348faSJeff Layton case -EDEADLK: 60951da177e4SLinus Torvalds status = nfserr_deadlock; 6096eb76b3fdSAndy Adamson break; 60971da177e4SLinus Torvalds default: 6098fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 60993e772463SJ. Bruce Fields status = nfserrno(err); 6100eb76b3fdSAndy Adamson break; 61011da177e4SLinus Torvalds } 61021da177e4SLinus Torvalds out: 610376d348faSJeff Layton if (nbl) { 610476d348faSJeff Layton /* dequeue it if we queued it before */ 610576d348faSJeff Layton if (fl_flags & FL_SLEEP) { 61060cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 610776d348faSJeff Layton list_del_init(&nbl->nbl_list); 61087919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 61090cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 611076d348faSJeff Layton } 611176d348faSJeff Layton free_blocked_lock(nbl); 611276d348faSJeff Layton } 6113de18643dSTrond Myklebust if (filp) 6114de18643dSTrond Myklebust fput(filp); 61155db1c03fSJeff Layton if (lock_stp) { 61165db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 61175db1c03fSJeff Layton if (cstate->replay_owner && 61185db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 61195db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 61205db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 61215db1c03fSJeff Layton 61225db1c03fSJeff Layton /* 61235db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 61245db1c03fSJeff Layton * returning an error, then just go ahead and release it. 61255db1c03fSJeff Layton */ 612625020720SJ. Bruce Fields if (status && new) 61275db1c03fSJeff Layton release_lock_stateid(lock_stp); 6128beeca19cSTrond Myklebust 6129beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 61305db1c03fSJeff Layton 61313d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 61325db1c03fSJeff Layton } 61330667b1e9STrond Myklebust if (open_stp) 61340667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 61359411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 613621179d81SJeff Layton if (conflock) 613721179d81SJeff Layton locks_free_lock(conflock); 61381da177e4SLinus Torvalds return status; 61391da177e4SLinus Torvalds } 61401da177e4SLinus Torvalds 61411da177e4SLinus Torvalds /* 614255ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 614355ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 614455ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 614555ef1274SJ. Bruce Fields * inode operation.) 614655ef1274SJ. Bruce Fields */ 614704da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 614855ef1274SJ. Bruce Fields { 614955ef1274SJ. Bruce Fields struct file *file; 615004da6e9dSAl Viro __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 615104da6e9dSAl Viro if (!err) { 615204da6e9dSAl Viro err = nfserrno(vfs_test_lock(file, lock)); 6153fd891454SChristoph Hellwig fput(file); 615404da6e9dSAl Viro } 615555ef1274SJ. Bruce Fields return err; 615655ef1274SJ. Bruce Fields } 615755ef1274SJ. Bruce Fields 615855ef1274SJ. Bruce Fields /* 61591da177e4SLinus Torvalds * LOCKT operation 61601da177e4SLinus Torvalds */ 6161b37ad28bSAl Viro __be32 6162ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6163eb69853dSChristoph Hellwig union nfsd4_op_u *u) 61641da177e4SLinus Torvalds { 6165eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 616621179d81SJeff Layton struct file_lock *file_lock = NULL; 61675db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 6168b37ad28bSAl Viro __be32 status; 61697f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 61701da177e4SLinus Torvalds 61715ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 61721da177e4SLinus Torvalds return nfserr_grace; 61731da177e4SLinus Torvalds 61741da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 61751da177e4SLinus Torvalds return nfserr_inval; 61761da177e4SLinus Torvalds 61779b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 61784b24ca7dSJeff Layton status = lookup_clientid(&lockt->lt_clientid, cstate, nn); 61799b2ef62bSJ. Bruce Fields if (status) 61801da177e4SLinus Torvalds goto out; 61819b2ef62bSJ. Bruce Fields } 61821da177e4SLinus Torvalds 618375c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 61841da177e4SLinus Torvalds goto out; 61851da177e4SLinus Torvalds 618621179d81SJeff Layton file_lock = locks_alloc_lock(); 618721179d81SJeff Layton if (!file_lock) { 618821179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 618921179d81SJeff Layton status = nfserr_jukebox; 619021179d81SJeff Layton goto out; 619121179d81SJeff Layton } 61926cd90662SKinglong Mee 61931da177e4SLinus Torvalds switch (lockt->lt_type) { 61941da177e4SLinus Torvalds case NFS4_READ_LT: 61951da177e4SLinus Torvalds case NFS4_READW_LT: 619621179d81SJeff Layton file_lock->fl_type = F_RDLCK; 61971da177e4SLinus Torvalds break; 61981da177e4SLinus Torvalds case NFS4_WRITE_LT: 61991da177e4SLinus Torvalds case NFS4_WRITEW_LT: 620021179d81SJeff Layton file_lock->fl_type = F_WRLCK; 62011da177e4SLinus Torvalds break; 62021da177e4SLinus Torvalds default: 62032fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 62041da177e4SLinus Torvalds status = nfserr_inval; 62051da177e4SLinus Torvalds goto out; 62061da177e4SLinus Torvalds } 62071da177e4SLinus Torvalds 6208c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 6209fe0750e5SJ. Bruce Fields if (lo) 621021179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 621121179d81SJeff Layton file_lock->fl_pid = current->tgid; 621221179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 62131da177e4SLinus Torvalds 621421179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 621521179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 62161da177e4SLinus Torvalds 621721179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 62181da177e4SLinus Torvalds 621921179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 622004da6e9dSAl Viro if (status) 6221fd85b817SMarc Eshel goto out; 622204da6e9dSAl Viro 622321179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 62241da177e4SLinus Torvalds status = nfserr_denied; 622521179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 62261da177e4SLinus Torvalds } 62271da177e4SLinus Torvalds out: 62285db1c03fSJeff Layton if (lo) 62295db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 623021179d81SJeff Layton if (file_lock) 623121179d81SJeff Layton locks_free_lock(file_lock); 62321da177e4SLinus Torvalds return status; 62331da177e4SLinus Torvalds } 62341da177e4SLinus Torvalds 6235b37ad28bSAl Viro __be32 6236ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6237eb69853dSChristoph Hellwig union nfsd4_op_u *u) 62381da177e4SLinus Torvalds { 6239eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 6240dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 62411da177e4SLinus Torvalds struct file *filp = NULL; 624221179d81SJeff Layton struct file_lock *file_lock = NULL; 6243b37ad28bSAl Viro __be32 status; 6244b8dd7b9aSAl Viro int err; 62453320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 62461da177e4SLinus Torvalds 62471da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 62481da177e4SLinus Torvalds (long long) locku->lu_offset, 62491da177e4SLinus Torvalds (long long) locku->lu_length); 62501da177e4SLinus Torvalds 62511da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 62521da177e4SLinus Torvalds return nfserr_inval; 62531da177e4SLinus Torvalds 62549072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 62553320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 62563320fef1SStanislav Kinsbursky &stp, nn); 62579072d5c6SJ. Bruce Fields if (status) 62581da177e4SLinus Torvalds goto out; 625911b9164aSTrond Myklebust filp = find_any_file(stp->st_stid.sc_file); 6260f9d7562fSJ. Bruce Fields if (!filp) { 6261f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 6262858cc573STrond Myklebust goto put_stateid; 6263f9d7562fSJ. Bruce Fields } 626421179d81SJeff Layton file_lock = locks_alloc_lock(); 626521179d81SJeff Layton if (!file_lock) { 626621179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 626721179d81SJeff Layton status = nfserr_jukebox; 6268de18643dSTrond Myklebust goto fput; 626921179d81SJeff Layton } 62706cd90662SKinglong Mee 627121179d81SJeff Layton file_lock->fl_type = F_UNLCK; 6272aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 627321179d81SJeff Layton file_lock->fl_pid = current->tgid; 627421179d81SJeff Layton file_lock->fl_file = filp; 627521179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 627621179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 627721179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 62781da177e4SLinus Torvalds 627921179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 628021179d81SJeff Layton locku->lu_length); 628121179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 62821da177e4SLinus Torvalds 628321179d81SJeff Layton err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); 6284b8dd7b9aSAl Viro if (err) { 6285fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 62861da177e4SLinus Torvalds goto out_nfserr; 62871da177e4SLinus Torvalds } 62889767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 6289de18643dSTrond Myklebust fput: 6290de18643dSTrond Myklebust fput(filp); 6291858cc573STrond Myklebust put_stateid: 6292feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6293858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 62941da177e4SLinus Torvalds out: 62959411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 629621179d81SJeff Layton if (file_lock) 629721179d81SJeff Layton locks_free_lock(file_lock); 62981da177e4SLinus Torvalds return status; 62991da177e4SLinus Torvalds 63001da177e4SLinus Torvalds out_nfserr: 6301b8dd7b9aSAl Viro status = nfserrno(err); 6302de18643dSTrond Myklebust goto fput; 63031da177e4SLinus Torvalds } 63041da177e4SLinus Torvalds 63051da177e4SLinus Torvalds /* 63061da177e4SLinus Torvalds * returns 6307f9c00c3aSJeff Layton * true: locks held by lockowner 6308f9c00c3aSJeff Layton * false: no locks held by lockowner 63091da177e4SLinus Torvalds */ 6310f9c00c3aSJeff Layton static bool 6311f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 63121da177e4SLinus Torvalds { 6313bd61e0a9SJeff Layton struct file_lock *fl; 6314f9c00c3aSJeff Layton int status = false; 6315f9c00c3aSJeff Layton struct file *filp = find_any_file(fp); 6316f9c00c3aSJeff Layton struct inode *inode; 6317bd61e0a9SJeff Layton struct file_lock_context *flctx; 6318f9c00c3aSJeff Layton 6319f9c00c3aSJeff Layton if (!filp) { 6320f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 6321f9c00c3aSJeff Layton WARN_ON_ONCE(1); 6322f9c00c3aSJeff Layton return status; 6323f9c00c3aSJeff Layton } 6324f9c00c3aSJeff Layton 632564bed6cbSAmir Goldstein inode = locks_inode(filp); 6326bd61e0a9SJeff Layton flctx = inode->i_flctx; 63271da177e4SLinus Torvalds 6328bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 63296109c850SJeff Layton spin_lock(&flctx->flc_lock); 6330bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 6331bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 6332f9c00c3aSJeff Layton status = true; 6333f9c00c3aSJeff Layton break; 63341da177e4SLinus Torvalds } 6335796dadfdSJ. Bruce Fields } 63366109c850SJeff Layton spin_unlock(&flctx->flc_lock); 6337bd61e0a9SJeff Layton } 6338f9c00c3aSJeff Layton fput(filp); 63391da177e4SLinus Torvalds return status; 63401da177e4SLinus Torvalds } 63411da177e4SLinus Torvalds 6342b37ad28bSAl Viro __be32 6343b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 6344b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 6345eb69853dSChristoph Hellwig union nfsd4_op_u *u) 63461da177e4SLinus Torvalds { 6347eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 63481da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 6349882e9d25SJeff Layton struct nfs4_stateowner *sop; 6350882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 6351dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 63521da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 6353d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 6354b37ad28bSAl Viro __be32 status; 63557f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 6356c58c6610STrond Myklebust struct nfs4_client *clp; 635788584818SChuck Lever LIST_HEAD (reaplist); 63581da177e4SLinus Torvalds 63591da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 63601da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 63611da177e4SLinus Torvalds 63624b24ca7dSJeff Layton status = lookup_clientid(clid, cstate, nn); 63639b2ef62bSJ. Bruce Fields if (status) 636451f5e783STrond Myklebust return status; 63659b2ef62bSJ. Bruce Fields 6366d4f0489fSTrond Myklebust clp = cstate->clp; 6367fd44907cSJeff Layton /* Find the matching lock stateowner */ 6368d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6369882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 6370d4f0489fSTrond Myklebust so_strhash) { 6371882e9d25SJeff Layton 6372882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 637316bfdaafSJ. Bruce Fields continue; 6374882e9d25SJeff Layton 6375882e9d25SJeff Layton /* see if there are still any locks associated with it */ 6376882e9d25SJeff Layton lo = lockowner(sop); 6377882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 6378882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 6379882e9d25SJeff Layton status = nfserr_locks_held; 6380882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 638151f5e783STrond Myklebust return status; 6382882e9d25SJeff Layton } 6383882e9d25SJeff Layton } 6384882e9d25SJeff Layton 6385b5971afaSKinglong Mee nfs4_get_stateowner(sop); 6386fd44907cSJeff Layton break; 6387fd44907cSJeff Layton } 638888584818SChuck Lever if (!lo) { 6389d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 639088584818SChuck Lever return status; 639188584818SChuck Lever } 639288584818SChuck Lever 639388584818SChuck Lever unhash_lockowner_locked(lo); 639488584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 639588584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 639688584818SChuck Lever struct nfs4_ol_stateid, 639788584818SChuck Lever st_perstateowner); 639888584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 639988584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 640088584818SChuck Lever } 640188584818SChuck Lever spin_unlock(&clp->cl_lock); 640288584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 640368ef3bc3SJeff Layton remove_blocked_locks(lo); 640488584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 640588584818SChuck Lever 64061da177e4SLinus Torvalds return status; 64071da177e4SLinus Torvalds } 64081da177e4SLinus Torvalds 64091da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 6410a55370a3SNeilBrown alloc_reclaim(void) 64111da177e4SLinus Torvalds { 6412a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 64131da177e4SLinus Torvalds } 64141da177e4SLinus Torvalds 64150ce0c2b5SJeff Layton bool 641652e19c09SStanislav Kinsbursky nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 6417c7b9a459SNeilBrown { 64180ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 6419c7b9a459SNeilBrown 642052e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 64210ce0c2b5SJeff Layton return (crp && crp->cr_clp); 6422c7b9a459SNeilBrown } 6423c7b9a459SNeilBrown 64241da177e4SLinus Torvalds /* 64251da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 64261da177e4SLinus Torvalds */ 6427772a9bbbSJeff Layton struct nfs4_client_reclaim * 642852e19c09SStanislav Kinsbursky nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 64291da177e4SLinus Torvalds { 64301da177e4SLinus Torvalds unsigned int strhashval; 6431772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 64321da177e4SLinus Torvalds 6433a55370a3SNeilBrown dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 6434a55370a3SNeilBrown crp = alloc_reclaim(); 6435772a9bbbSJeff Layton if (crp) { 6436a55370a3SNeilBrown strhashval = clientstr_hashval(name); 64371da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 643852e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 6439a55370a3SNeilBrown memcpy(crp->cr_recdir, name, HEXDIR_LEN); 64400ce0c2b5SJeff Layton crp->cr_clp = NULL; 644152e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 6442772a9bbbSJeff Layton } 6443772a9bbbSJeff Layton return crp; 64441da177e4SLinus Torvalds } 64451da177e4SLinus Torvalds 64462a4317c5SJeff Layton void 644752e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 6448ce30e539SJeff Layton { 6449ce30e539SJeff Layton list_del(&crp->cr_strhash); 6450ce30e539SJeff Layton kfree(crp); 645152e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 6452ce30e539SJeff Layton } 6453ce30e539SJeff Layton 6454ce30e539SJeff Layton void 645552e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 64561da177e4SLinus Torvalds { 64571da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 64581da177e4SLinus Torvalds int i; 64591da177e4SLinus Torvalds 64601da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 646152e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 646252e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 64631da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 646452e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 64651da177e4SLinus Torvalds } 64661da177e4SLinus Torvalds } 6467063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 64681da177e4SLinus Torvalds } 64691da177e4SLinus Torvalds 64701da177e4SLinus Torvalds /* 64711da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 64722a4317c5SJeff Layton struct nfs4_client_reclaim * 647352e19c09SStanislav Kinsbursky nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 64741da177e4SLinus Torvalds { 64751da177e4SLinus Torvalds unsigned int strhashval; 64761da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 64771da177e4SLinus Torvalds 6478278c931cSJeff Layton dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 64791da177e4SLinus Torvalds 6480278c931cSJeff Layton strhashval = clientstr_hashval(recdir); 648152e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 6482278c931cSJeff Layton if (same_name(crp->cr_recdir, recdir)) { 64831da177e4SLinus Torvalds return crp; 64841da177e4SLinus Torvalds } 64851da177e4SLinus Torvalds } 64861da177e4SLinus Torvalds return NULL; 64871da177e4SLinus Torvalds } 64881da177e4SLinus Torvalds 64891da177e4SLinus Torvalds /* 64901da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 64911da177e4SLinus Torvalds */ 6492b37ad28bSAl Viro __be32 64930fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 64940fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 64950fe492dbSTrond Myklebust struct nfsd_net *nn) 64961da177e4SLinus Torvalds { 64970fe492dbSTrond Myklebust __be32 status; 6498a52d726bSJeff Layton 6499a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 65000fe492dbSTrond Myklebust status = lookup_clientid(clid, cstate, nn); 65010fe492dbSTrond Myklebust if (status) 6502a52d726bSJeff Layton return nfserr_reclaim_bad; 6503a52d726bSJeff Layton 65043b3e7b72SJeff Layton if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) 65053b3e7b72SJeff Layton return nfserr_no_grace; 65063b3e7b72SJeff Layton 65070fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 65080fe492dbSTrond Myklebust return nfserr_reclaim_bad; 65090fe492dbSTrond Myklebust 65100fe492dbSTrond Myklebust return nfs_ok; 65111da177e4SLinus Torvalds } 65121da177e4SLinus Torvalds 651365178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 6514016200c3SJeff Layton static inline void 6515016200c3SJeff Layton put_client(struct nfs4_client *clp) 6516016200c3SJeff Layton { 6517016200c3SJeff Layton atomic_dec(&clp->cl_refcount); 6518016200c3SJeff Layton } 6519016200c3SJeff Layton 6520285abdeeSJeff Layton static struct nfs4_client * 6521285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 6522285abdeeSJeff Layton { 6523285abdeeSJeff Layton struct nfs4_client *clp; 6524285abdeeSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6525285abdeeSJeff Layton nfsd_net_id); 6526285abdeeSJeff Layton 6527285abdeeSJeff Layton if (!nfsd_netns_ready(nn)) 6528285abdeeSJeff Layton return NULL; 6529285abdeeSJeff Layton 6530285abdeeSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 6531285abdeeSJeff Layton if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 6532285abdeeSJeff Layton return clp; 6533285abdeeSJeff Layton } 6534285abdeeSJeff Layton return NULL; 6535285abdeeSJeff Layton } 6536285abdeeSJeff Layton 65377ec0e36fSJeff Layton u64 6538285abdeeSJeff Layton nfsd_inject_print_clients(void) 65397ec0e36fSJeff Layton { 65407ec0e36fSJeff Layton struct nfs4_client *clp; 65417ec0e36fSJeff Layton u64 count = 0; 65427ec0e36fSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 65437ec0e36fSJeff Layton nfsd_net_id); 65447ec0e36fSJeff Layton char buf[INET6_ADDRSTRLEN]; 65457ec0e36fSJeff Layton 65467ec0e36fSJeff Layton if (!nfsd_netns_ready(nn)) 65477ec0e36fSJeff Layton return 0; 65487ec0e36fSJeff Layton 65497ec0e36fSJeff Layton spin_lock(&nn->client_lock); 65507ec0e36fSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 65517ec0e36fSJeff Layton rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 65527ec0e36fSJeff Layton pr_info("NFS Client: %s\n", buf); 65537ec0e36fSJeff Layton ++count; 65547ec0e36fSJeff Layton } 65557ec0e36fSJeff Layton spin_unlock(&nn->client_lock); 65567ec0e36fSJeff Layton 65577ec0e36fSJeff Layton return count; 65587ec0e36fSJeff Layton } 655965178db4SBryan Schumaker 6560a0926d15SJeff Layton u64 6561285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) 6562a0926d15SJeff Layton { 6563a0926d15SJeff Layton u64 count = 0; 6564a0926d15SJeff Layton struct nfs4_client *clp; 6565a0926d15SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6566a0926d15SJeff Layton nfsd_net_id); 6567a0926d15SJeff Layton 6568a0926d15SJeff Layton if (!nfsd_netns_ready(nn)) 6569a0926d15SJeff Layton return count; 6570a0926d15SJeff Layton 6571a0926d15SJeff Layton spin_lock(&nn->client_lock); 6572a0926d15SJeff Layton clp = nfsd_find_client(addr, addr_size); 6573a0926d15SJeff Layton if (clp) { 6574a0926d15SJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) 6575a0926d15SJeff Layton ++count; 6576a0926d15SJeff Layton else 6577a0926d15SJeff Layton clp = NULL; 6578a0926d15SJeff Layton } 6579a0926d15SJeff Layton spin_unlock(&nn->client_lock); 6580a0926d15SJeff Layton 6581a0926d15SJeff Layton if (clp) 6582a0926d15SJeff Layton expire_client(clp); 6583a0926d15SJeff Layton 6584a0926d15SJeff Layton return count; 6585a0926d15SJeff Layton } 6586a0926d15SJeff Layton 658769fc9edfSJeff Layton u64 6588285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max) 658969fc9edfSJeff Layton { 659069fc9edfSJeff Layton u64 count = 0; 659169fc9edfSJeff Layton struct nfs4_client *clp, *next; 659269fc9edfSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 659369fc9edfSJeff Layton nfsd_net_id); 659469fc9edfSJeff Layton LIST_HEAD(reaplist); 659569fc9edfSJeff Layton 659669fc9edfSJeff Layton if (!nfsd_netns_ready(nn)) 659769fc9edfSJeff Layton return count; 659869fc9edfSJeff Layton 659969fc9edfSJeff Layton spin_lock(&nn->client_lock); 660069fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 660169fc9edfSJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) { 660269fc9edfSJeff Layton list_add(&clp->cl_lru, &reaplist); 660369fc9edfSJeff Layton if (max != 0 && ++count >= max) 660469fc9edfSJeff Layton break; 660569fc9edfSJeff Layton } 660669fc9edfSJeff Layton } 660769fc9edfSJeff Layton spin_unlock(&nn->client_lock); 660869fc9edfSJeff Layton 660969fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &reaplist, cl_lru) 661069fc9edfSJeff Layton expire_client(clp); 661169fc9edfSJeff Layton 661269fc9edfSJeff Layton return count; 661369fc9edfSJeff Layton } 661469fc9edfSJeff Layton 6615184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 6616184c1847SBryan Schumaker const char *type) 6617184c1847SBryan Schumaker { 6618184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 66190a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 6620184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 6621184c1847SBryan Schumaker } 6622184c1847SBryan Schumaker 6623016200c3SJeff Layton static void 6624016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, 6625016200c3SJeff Layton struct list_head *collect) 6626016200c3SJeff Layton { 6627016200c3SJeff Layton struct nfs4_client *clp = lst->st_stid.sc_client; 6628016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6629016200c3SJeff Layton nfsd_net_id); 6630016200c3SJeff Layton 6631016200c3SJeff Layton if (!collect) 6632016200c3SJeff Layton return; 6633016200c3SJeff Layton 6634016200c3SJeff Layton lockdep_assert_held(&nn->client_lock); 6635016200c3SJeff Layton atomic_inc(&clp->cl_refcount); 6636016200c3SJeff Layton list_add(&lst->st_locks, collect); 6637016200c3SJeff Layton } 6638016200c3SJeff Layton 66393c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 66403738d50eSJeff Layton struct list_head *collect, 6641e8568739SJeff Layton bool (*func)(struct nfs4_ol_stateid *)) 6642fc29171fSBryan Schumaker { 6643fc29171fSBryan Schumaker struct nfs4_openowner *oop; 6644fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 66453c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 6646fc29171fSBryan Schumaker u64 count = 0; 6647fc29171fSBryan Schumaker 6648016200c3SJeff Layton spin_lock(&clp->cl_lock); 6649fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 66503c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 66513c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 66523c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 66533c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 66543738d50eSJeff Layton if (func) { 6655e8568739SJeff Layton if (func(lst)) 6656016200c3SJeff Layton nfsd_inject_add_lock_to_list(lst, 66573738d50eSJeff Layton collect); 66583738d50eSJeff Layton } 6659016200c3SJeff Layton ++count; 6660016200c3SJeff Layton /* 6661016200c3SJeff Layton * Despite the fact that these functions deal 6662016200c3SJeff Layton * with 64-bit integers for "count", we must 6663016200c3SJeff Layton * ensure that it doesn't blow up the 6664016200c3SJeff Layton * clp->cl_refcount. Throw a warning if we 6665016200c3SJeff Layton * start to approach INT_MAX here. 6666016200c3SJeff Layton */ 6667016200c3SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 6668016200c3SJeff Layton if (count == max) 6669016200c3SJeff Layton goto out; 6670fc29171fSBryan Schumaker } 6671fc29171fSBryan Schumaker } 6672fc29171fSBryan Schumaker } 6673016200c3SJeff Layton out: 6674016200c3SJeff Layton spin_unlock(&clp->cl_lock); 6675fc29171fSBryan Schumaker 6676fc29171fSBryan Schumaker return count; 6677fc29171fSBryan Schumaker } 6678fc29171fSBryan Schumaker 6679016200c3SJeff Layton static u64 6680016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, 6681016200c3SJeff Layton u64 max) 6682fc29171fSBryan Schumaker { 6683016200c3SJeff Layton return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); 6684fc29171fSBryan Schumaker } 6685fc29171fSBryan Schumaker 6686016200c3SJeff Layton static u64 6687016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp) 6688184c1847SBryan Schumaker { 6689016200c3SJeff Layton u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); 6690184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 6691184c1847SBryan Schumaker return count; 6692184c1847SBryan Schumaker } 6693184c1847SBryan Schumaker 6694016200c3SJeff Layton u64 6695285abdeeSJeff Layton nfsd_inject_print_locks(void) 6696016200c3SJeff Layton { 6697016200c3SJeff Layton struct nfs4_client *clp; 6698016200c3SJeff Layton u64 count = 0; 6699016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6700016200c3SJeff Layton nfsd_net_id); 6701016200c3SJeff Layton 6702016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6703016200c3SJeff Layton return 0; 6704016200c3SJeff Layton 6705016200c3SJeff Layton spin_lock(&nn->client_lock); 6706016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 6707016200c3SJeff Layton count += nfsd_print_client_locks(clp); 6708016200c3SJeff Layton spin_unlock(&nn->client_lock); 6709016200c3SJeff Layton 6710016200c3SJeff Layton return count; 6711016200c3SJeff Layton } 6712016200c3SJeff Layton 6713016200c3SJeff Layton static void 6714016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist) 6715016200c3SJeff Layton { 6716016200c3SJeff Layton struct nfs4_client *clp; 6717016200c3SJeff Layton struct nfs4_ol_stateid *stp, *next; 6718016200c3SJeff Layton 6719016200c3SJeff Layton list_for_each_entry_safe(stp, next, reaplist, st_locks) { 6720016200c3SJeff Layton list_del_init(&stp->st_locks); 6721016200c3SJeff Layton clp = stp->st_stid.sc_client; 6722016200c3SJeff Layton nfs4_put_stid(&stp->st_stid); 6723016200c3SJeff Layton put_client(clp); 6724016200c3SJeff Layton } 6725016200c3SJeff Layton } 6726016200c3SJeff Layton 6727016200c3SJeff Layton u64 6728285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) 6729016200c3SJeff Layton { 6730016200c3SJeff Layton unsigned int count = 0; 6731016200c3SJeff Layton struct nfs4_client *clp; 6732016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6733016200c3SJeff Layton nfsd_net_id); 6734016200c3SJeff Layton LIST_HEAD(reaplist); 6735016200c3SJeff Layton 6736016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6737016200c3SJeff Layton return count; 6738016200c3SJeff Layton 6739016200c3SJeff Layton spin_lock(&nn->client_lock); 6740016200c3SJeff Layton clp = nfsd_find_client(addr, addr_size); 6741016200c3SJeff Layton if (clp) 6742016200c3SJeff Layton count = nfsd_collect_client_locks(clp, &reaplist, 0); 6743016200c3SJeff Layton spin_unlock(&nn->client_lock); 6744016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6745016200c3SJeff Layton return count; 6746016200c3SJeff Layton } 6747016200c3SJeff Layton 6748016200c3SJeff Layton u64 6749285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max) 6750016200c3SJeff Layton { 6751016200c3SJeff Layton u64 count = 0; 6752016200c3SJeff Layton struct nfs4_client *clp; 6753016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 6754016200c3SJeff Layton nfsd_net_id); 6755016200c3SJeff Layton LIST_HEAD(reaplist); 6756016200c3SJeff Layton 6757016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 6758016200c3SJeff Layton return count; 6759016200c3SJeff Layton 6760016200c3SJeff Layton spin_lock(&nn->client_lock); 6761016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 6762016200c3SJeff Layton count += nfsd_collect_client_locks(clp, &reaplist, max - count); 6763016200c3SJeff Layton if (max != 0 && count >= max) 6764016200c3SJeff Layton break; 6765016200c3SJeff Layton } 6766016200c3SJeff Layton spin_unlock(&nn->client_lock); 6767016200c3SJeff Layton nfsd_reap_locks(&reaplist); 6768016200c3SJeff Layton return count; 6769016200c3SJeff Layton } 6770016200c3SJeff Layton 677182e05efaSJeff Layton static u64 677282e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, 677382e05efaSJeff Layton struct list_head *collect, 677482e05efaSJeff Layton void (*func)(struct nfs4_openowner *)) 67754dbdbda8SBryan Schumaker { 67764dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 677782e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 677882e05efaSJeff Layton nfsd_net_id); 67794dbdbda8SBryan Schumaker u64 count = 0; 67804dbdbda8SBryan Schumaker 678182e05efaSJeff Layton lockdep_assert_held(&nn->client_lock); 678282e05efaSJeff Layton 678382e05efaSJeff Layton spin_lock(&clp->cl_lock); 67844dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 678582e05efaSJeff Layton if (func) { 67864dbdbda8SBryan Schumaker func(oop); 678782e05efaSJeff Layton if (collect) { 678882e05efaSJeff Layton atomic_inc(&clp->cl_refcount); 678982e05efaSJeff Layton list_add(&oop->oo_perclient, collect); 679082e05efaSJeff Layton } 679182e05efaSJeff Layton } 679282e05efaSJeff Layton ++count; 679382e05efaSJeff Layton /* 679482e05efaSJeff Layton * Despite the fact that these functions deal with 679582e05efaSJeff Layton * 64-bit integers for "count", we must ensure that 679682e05efaSJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 679782e05efaSJeff Layton * warning if we start to approach INT_MAX here. 679882e05efaSJeff Layton */ 679982e05efaSJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 680082e05efaSJeff Layton if (count == max) 68014dbdbda8SBryan Schumaker break; 68024dbdbda8SBryan Schumaker } 680382e05efaSJeff Layton spin_unlock(&clp->cl_lock); 68044dbdbda8SBryan Schumaker 68054dbdbda8SBryan Schumaker return count; 68064dbdbda8SBryan Schumaker } 68074dbdbda8SBryan Schumaker 680882e05efaSJeff Layton static u64 680982e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp) 68104dbdbda8SBryan Schumaker { 681182e05efaSJeff Layton u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); 681282e05efaSJeff Layton 681382e05efaSJeff Layton nfsd_print_count(clp, count, "openowners"); 681482e05efaSJeff Layton return count; 68154dbdbda8SBryan Schumaker } 68164dbdbda8SBryan Schumaker 681782e05efaSJeff Layton static u64 681882e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp, 681982e05efaSJeff Layton struct list_head *collect, u64 max) 6820184c1847SBryan Schumaker { 682182e05efaSJeff Layton return nfsd_foreach_client_openowner(clp, max, collect, 682282e05efaSJeff Layton unhash_openowner_locked); 682382e05efaSJeff Layton } 682482e05efaSJeff Layton 682582e05efaSJeff Layton u64 6826285abdeeSJeff Layton nfsd_inject_print_openowners(void) 682782e05efaSJeff Layton { 682882e05efaSJeff Layton struct nfs4_client *clp; 682982e05efaSJeff Layton u64 count = 0; 683082e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 683182e05efaSJeff Layton nfsd_net_id); 683282e05efaSJeff Layton 683382e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 683482e05efaSJeff Layton return 0; 683582e05efaSJeff Layton 683682e05efaSJeff Layton spin_lock(&nn->client_lock); 683782e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 683882e05efaSJeff Layton count += nfsd_print_client_openowners(clp); 683982e05efaSJeff Layton spin_unlock(&nn->client_lock); 684082e05efaSJeff Layton 684182e05efaSJeff Layton return count; 684282e05efaSJeff Layton } 684382e05efaSJeff Layton 684482e05efaSJeff Layton static void 684582e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist) 684682e05efaSJeff Layton { 684782e05efaSJeff Layton struct nfs4_client *clp; 684882e05efaSJeff Layton struct nfs4_openowner *oop, *next; 684982e05efaSJeff Layton 685082e05efaSJeff Layton list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { 685182e05efaSJeff Layton list_del_init(&oop->oo_perclient); 685282e05efaSJeff Layton clp = oop->oo_owner.so_client; 685382e05efaSJeff Layton release_openowner(oop); 685482e05efaSJeff Layton put_client(clp); 685582e05efaSJeff Layton } 685682e05efaSJeff Layton } 685782e05efaSJeff Layton 685882e05efaSJeff Layton u64 6859285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, 6860285abdeeSJeff Layton size_t addr_size) 686182e05efaSJeff Layton { 686282e05efaSJeff Layton unsigned int count = 0; 686382e05efaSJeff Layton struct nfs4_client *clp; 686482e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 686582e05efaSJeff Layton nfsd_net_id); 686682e05efaSJeff Layton LIST_HEAD(reaplist); 686782e05efaSJeff Layton 686882e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 686982e05efaSJeff Layton return count; 687082e05efaSJeff Layton 687182e05efaSJeff Layton spin_lock(&nn->client_lock); 687282e05efaSJeff Layton clp = nfsd_find_client(addr, addr_size); 687382e05efaSJeff Layton if (clp) 687482e05efaSJeff Layton count = nfsd_collect_client_openowners(clp, &reaplist, 0); 687582e05efaSJeff Layton spin_unlock(&nn->client_lock); 687682e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 687782e05efaSJeff Layton return count; 687882e05efaSJeff Layton } 687982e05efaSJeff Layton 688082e05efaSJeff Layton u64 6881285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max) 688282e05efaSJeff Layton { 688382e05efaSJeff Layton u64 count = 0; 688482e05efaSJeff Layton struct nfs4_client *clp; 688582e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 688682e05efaSJeff Layton nfsd_net_id); 688782e05efaSJeff Layton LIST_HEAD(reaplist); 688882e05efaSJeff Layton 688982e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 689082e05efaSJeff Layton return count; 689182e05efaSJeff Layton 689282e05efaSJeff Layton spin_lock(&nn->client_lock); 689382e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 689482e05efaSJeff Layton count += nfsd_collect_client_openowners(clp, &reaplist, 689582e05efaSJeff Layton max - count); 689682e05efaSJeff Layton if (max != 0 && count >= max) 689782e05efaSJeff Layton break; 689882e05efaSJeff Layton } 689982e05efaSJeff Layton spin_unlock(&nn->client_lock); 690082e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 6901184c1847SBryan Schumaker return count; 6902184c1847SBryan Schumaker } 6903184c1847SBryan Schumaker 6904269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 6905269de30fSBryan Schumaker struct list_head *victims) 6906269de30fSBryan Schumaker { 6907269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 690898d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 690998d5c7c5SJeff Layton nfsd_net_id); 6910269de30fSBryan Schumaker u64 count = 0; 6911269de30fSBryan Schumaker 691298d5c7c5SJeff Layton lockdep_assert_held(&nn->client_lock); 691398d5c7c5SJeff Layton 691498d5c7c5SJeff Layton spin_lock(&state_lock); 6915269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 6916dff1399fSJeff Layton if (victims) { 6917dff1399fSJeff Layton /* 6918dff1399fSJeff Layton * It's not safe to mess with delegations that have a 6919dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 6920dff1399fSJeff Layton * and could be processed by the laundromat outside of 6921dff1399fSJeff Layton * the state_lock. Just leave them be. 6922dff1399fSJeff Layton */ 6923dff1399fSJeff Layton if (dp->dl_time != 0) 6924dff1399fSJeff Layton continue; 6925dff1399fSJeff Layton 692698d5c7c5SJeff Layton atomic_inc(&clp->cl_refcount); 69273fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 692842690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 6929dff1399fSJeff Layton } 693098d5c7c5SJeff Layton ++count; 693198d5c7c5SJeff Layton /* 693298d5c7c5SJeff Layton * Despite the fact that these functions deal with 693398d5c7c5SJeff Layton * 64-bit integers for "count", we must ensure that 693498d5c7c5SJeff Layton * it doesn't blow up the clp->cl_refcount. Throw a 693598d5c7c5SJeff Layton * warning if we start to approach INT_MAX here. 693698d5c7c5SJeff Layton */ 693798d5c7c5SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 693898d5c7c5SJeff Layton if (count == max) 6939269de30fSBryan Schumaker break; 6940269de30fSBryan Schumaker } 694198d5c7c5SJeff Layton spin_unlock(&state_lock); 6942269de30fSBryan Schumaker return count; 6943269de30fSBryan Schumaker } 6944269de30fSBryan Schumaker 694598d5c7c5SJeff Layton static u64 694698d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp) 6947269de30fSBryan Schumaker { 694898d5c7c5SJeff Layton u64 count = nfsd_find_all_delegations(clp, 0, NULL); 6949184c1847SBryan Schumaker 6950184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 6951184c1847SBryan Schumaker return count; 6952184c1847SBryan Schumaker } 6953184c1847SBryan Schumaker 695498d5c7c5SJeff Layton u64 6955285abdeeSJeff Layton nfsd_inject_print_delegations(void) 695698d5c7c5SJeff Layton { 695798d5c7c5SJeff Layton struct nfs4_client *clp; 695898d5c7c5SJeff Layton u64 count = 0; 695998d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 696098d5c7c5SJeff Layton nfsd_net_id); 696198d5c7c5SJeff Layton 696298d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 696398d5c7c5SJeff Layton return 0; 696498d5c7c5SJeff Layton 696598d5c7c5SJeff Layton spin_lock(&nn->client_lock); 696698d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 696798d5c7c5SJeff Layton count += nfsd_print_client_delegations(clp); 696898d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 696998d5c7c5SJeff Layton 697098d5c7c5SJeff Layton return count; 697198d5c7c5SJeff Layton } 697298d5c7c5SJeff Layton 697398d5c7c5SJeff Layton static void 697498d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist) 697598d5c7c5SJeff Layton { 697698d5c7c5SJeff Layton struct nfs4_client *clp; 697798d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 697898d5c7c5SJeff Layton 697998d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 698098d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 698198d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 698298d5c7c5SJeff Layton revoke_delegation(dp); 698398d5c7c5SJeff Layton put_client(clp); 698498d5c7c5SJeff Layton } 698598d5c7c5SJeff Layton } 698698d5c7c5SJeff Layton 698798d5c7c5SJeff Layton u64 6988285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, 6989285abdeeSJeff Layton size_t addr_size) 699098d5c7c5SJeff Layton { 699198d5c7c5SJeff Layton u64 count = 0; 699298d5c7c5SJeff Layton struct nfs4_client *clp; 699398d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 699498d5c7c5SJeff Layton nfsd_net_id); 699598d5c7c5SJeff Layton LIST_HEAD(reaplist); 699698d5c7c5SJeff Layton 699798d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 699898d5c7c5SJeff Layton return count; 699998d5c7c5SJeff Layton 700098d5c7c5SJeff Layton spin_lock(&nn->client_lock); 700198d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 700298d5c7c5SJeff Layton if (clp) 700398d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 700498d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 700598d5c7c5SJeff Layton 700698d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 700798d5c7c5SJeff Layton return count; 700898d5c7c5SJeff Layton } 700998d5c7c5SJeff Layton 701098d5c7c5SJeff Layton u64 7011285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max) 701298d5c7c5SJeff Layton { 701398d5c7c5SJeff Layton u64 count = 0; 701498d5c7c5SJeff Layton struct nfs4_client *clp; 701598d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 701698d5c7c5SJeff Layton nfsd_net_id); 701798d5c7c5SJeff Layton LIST_HEAD(reaplist); 701898d5c7c5SJeff Layton 701998d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 702098d5c7c5SJeff Layton return count; 702198d5c7c5SJeff Layton 702298d5c7c5SJeff Layton spin_lock(&nn->client_lock); 702398d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 702498d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 702598d5c7c5SJeff Layton if (max != 0 && count >= max) 702698d5c7c5SJeff Layton break; 702798d5c7c5SJeff Layton } 702898d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 702998d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 703098d5c7c5SJeff Layton return count; 703198d5c7c5SJeff Layton } 703298d5c7c5SJeff Layton 703398d5c7c5SJeff Layton static void 703498d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist) 703598d5c7c5SJeff Layton { 703698d5c7c5SJeff Layton struct nfs4_client *clp; 703798d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 703898d5c7c5SJeff Layton 703998d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 704098d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 704198d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 704298d5c7c5SJeff Layton /* 704398d5c7c5SJeff Layton * We skipped all entries that had a zero dl_time before, 704498d5c7c5SJeff Layton * so we can now reset the dl_time back to 0. If a delegation 704598d5c7c5SJeff Layton * break comes in now, then it won't make any difference since 704698d5c7c5SJeff Layton * we're recalling it either way. 704798d5c7c5SJeff Layton */ 704898d5c7c5SJeff Layton spin_lock(&state_lock); 704998d5c7c5SJeff Layton dp->dl_time = 0; 705098d5c7c5SJeff Layton spin_unlock(&state_lock); 705198d5c7c5SJeff Layton nfsd_break_one_deleg(dp); 705298d5c7c5SJeff Layton put_client(clp); 705398d5c7c5SJeff Layton } 705498d5c7c5SJeff Layton } 705598d5c7c5SJeff Layton 705698d5c7c5SJeff Layton u64 7057285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, 705898d5c7c5SJeff Layton size_t addr_size) 705998d5c7c5SJeff Layton { 706098d5c7c5SJeff Layton u64 count = 0; 706198d5c7c5SJeff Layton struct nfs4_client *clp; 706298d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 706398d5c7c5SJeff Layton nfsd_net_id); 706498d5c7c5SJeff Layton LIST_HEAD(reaplist); 706598d5c7c5SJeff Layton 706698d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 706798d5c7c5SJeff Layton return count; 706898d5c7c5SJeff Layton 706998d5c7c5SJeff Layton spin_lock(&nn->client_lock); 707098d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 707198d5c7c5SJeff Layton if (clp) 707298d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 707398d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 707498d5c7c5SJeff Layton 707598d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 707698d5c7c5SJeff Layton return count; 707798d5c7c5SJeff Layton } 707898d5c7c5SJeff Layton 707998d5c7c5SJeff Layton u64 7080285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max) 708198d5c7c5SJeff Layton { 708298d5c7c5SJeff Layton u64 count = 0; 708398d5c7c5SJeff Layton struct nfs4_client *clp, *next; 708498d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 708598d5c7c5SJeff Layton nfsd_net_id); 708698d5c7c5SJeff Layton LIST_HEAD(reaplist); 708798d5c7c5SJeff Layton 708898d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 708998d5c7c5SJeff Layton return count; 709098d5c7c5SJeff Layton 709198d5c7c5SJeff Layton spin_lock(&nn->client_lock); 709298d5c7c5SJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 709398d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 709498d5c7c5SJeff Layton if (max != 0 && ++count >= max) 709598d5c7c5SJeff Layton break; 709698d5c7c5SJeff Layton } 709798d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 709898d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 709998d5c7c5SJeff Layton return count; 710098d5c7c5SJeff Layton } 710165178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 710265178db4SBryan Schumaker 7103c2f1a551SMeelap Shah /* 7104c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 7105c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 7106c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 7107c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 7108c2f1a551SMeelap Shah * 7109c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 7110c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 7111c2f1a551SMeelap Shah */ 7112c2f1a551SMeelap Shah static void 7113c2f1a551SMeelap Shah set_max_delegations(void) 7114c2f1a551SMeelap Shah { 7115c2f1a551SMeelap Shah /* 7116c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 7117c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 7118c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 7119c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 7120c2f1a551SMeelap Shah */ 7121c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 7122c2f1a551SMeelap Shah } 7123c2f1a551SMeelap Shah 7124d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 71258daae4dcSStanislav Kinsbursky { 71268daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 71278daae4dcSStanislav Kinsbursky int i; 71288daae4dcSStanislav Kinsbursky 71296da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 71306da2ec56SKees Cook sizeof(struct list_head), 71316da2ec56SKees Cook GFP_KERNEL); 71328daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 7133382a62e7SStanislav Kinsbursky goto err; 71346da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 71356da2ec56SKees Cook sizeof(struct list_head), 71366da2ec56SKees Cook GFP_KERNEL); 71370a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 71380a7ec377SStanislav Kinsbursky goto err_unconf_id; 71396da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 71406da2ec56SKees Cook sizeof(struct list_head), 71416da2ec56SKees Cook GFP_KERNEL); 71421872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 71431872de0eSStanislav Kinsbursky goto err_sessionid; 71448daae4dcSStanislav Kinsbursky 7145382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 71468daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 71470a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 7148382a62e7SStanislav Kinsbursky } 71491872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 71501872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 7151382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 7152a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 715381833de1SVasily Averin nn->boot_time = get_seconds(); 715481833de1SVasily Averin nn->grace_ended = false; 715581833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 715681833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 71575ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 715873758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 7159e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 7160c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 71618daae4dcSStanislav Kinsbursky 71620cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 71630cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 71640cc11a61SJeff Layton 716509121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 7166d85ed443SStanislav Kinsbursky get_net(net); 716709121281SStanislav Kinsbursky 71688daae4dcSStanislav Kinsbursky return 0; 7169382a62e7SStanislav Kinsbursky 71701872de0eSStanislav Kinsbursky err_sessionid: 71719b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 71720a7ec377SStanislav Kinsbursky err_unconf_id: 71730a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 7174382a62e7SStanislav Kinsbursky err: 7175382a62e7SStanislav Kinsbursky return -ENOMEM; 71768daae4dcSStanislav Kinsbursky } 71778daae4dcSStanislav Kinsbursky 71788daae4dcSStanislav Kinsbursky static void 71794dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 71808daae4dcSStanislav Kinsbursky { 71818daae4dcSStanislav Kinsbursky int i; 71828daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 71838daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 71848daae4dcSStanislav Kinsbursky 71858daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 71868daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 71878daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 71888daae4dcSStanislav Kinsbursky destroy_client(clp); 71898daae4dcSStanislav Kinsbursky } 71908daae4dcSStanislav Kinsbursky } 7191a99454aaSStanislav Kinsbursky 719268ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 719368ef3bc3SJeff Layton 71942b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 71952b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 71962b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 7197a99454aaSStanislav Kinsbursky destroy_client(clp); 7198a99454aaSStanislav Kinsbursky } 71992b905635SKinglong Mee } 7200a99454aaSStanislav Kinsbursky 72011872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 72020a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 72038daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 72044dce0ac9SStanislav Kinsbursky put_net(net); 72058daae4dcSStanislav Kinsbursky } 72068daae4dcSStanislav Kinsbursky 7207f252bc68SStanislav Kinsbursky int 7208d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 7209ac4d8ff2SNeilBrown { 72105e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 7211b5a1a81eSJ. Bruce Fields int ret; 7212b5a1a81eSJ. Bruce Fields 7213d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 72148daae4dcSStanislav Kinsbursky if (ret) 72158daae4dcSStanislav Kinsbursky return ret; 7216d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 7217d4318acdSJeff Layton nfsd4_client_tracking_init(net); 72187e981a8aSVasily Averin printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n", 72197e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 72205284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 7221d85ed443SStanislav Kinsbursky return 0; 7222a6d6b781SJeff Layton } 7223d85ed443SStanislav Kinsbursky 7224d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 7225d85ed443SStanislav Kinsbursky 7226d85ed443SStanislav Kinsbursky int 7227d85ed443SStanislav Kinsbursky nfs4_state_start(void) 7228d85ed443SStanislav Kinsbursky { 7229d85ed443SStanislav Kinsbursky int ret; 7230d85ed443SStanislav Kinsbursky 7231d85ed443SStanislav Kinsbursky ret = set_callback_cred(); 7232d85ed443SStanislav Kinsbursky if (ret) 7233f7d1ddbeSKinglong Mee return ret; 7234f7d1ddbeSKinglong Mee 723551a54568SJeff Layton laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 7236a6d6b781SJeff Layton if (laundry_wq == NULL) { 7237a6d6b781SJeff Layton ret = -ENOMEM; 7238f7d1ddbeSKinglong Mee goto out_cleanup_cred; 7239a6d6b781SJeff Layton } 7240b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 7241b5a1a81eSJ. Bruce Fields if (ret) 7242b5a1a81eSJ. Bruce Fields goto out_free_laundry; 724309121281SStanislav Kinsbursky 7244c2f1a551SMeelap Shah set_max_delegations(); 7245b5a1a81eSJ. Bruce Fields return 0; 7246d85ed443SStanislav Kinsbursky 7247b5a1a81eSJ. Bruce Fields out_free_laundry: 7248b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 7249f7d1ddbeSKinglong Mee out_cleanup_cred: 7250f7d1ddbeSKinglong Mee cleanup_callback_cred(); 7251b5a1a81eSJ. Bruce Fields return ret; 72521da177e4SLinus Torvalds } 72531da177e4SLinus Torvalds 7254f252bc68SStanislav Kinsbursky void 72554dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 72561da177e4SLinus Torvalds { 72571da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 72581da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 72594dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 72601da177e4SLinus Torvalds 72614dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 72624dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 7263ac55fdc4SJeff Layton 72641da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 7265cdc97505SBenny Halevy spin_lock(&state_lock); 7266e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 72671da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 72683fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 726942690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 72701da177e4SLinus Torvalds } 7271cdc97505SBenny Halevy spin_unlock(&state_lock); 72721da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 72731da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 727442690676SJeff Layton list_del_init(&dp->dl_recall_lru); 72750af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 72761da177e4SLinus Torvalds } 72771da177e4SLinus Torvalds 72783320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 72794dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 72801da177e4SLinus Torvalds } 72811da177e4SLinus Torvalds 72821da177e4SLinus Torvalds void 72831da177e4SLinus Torvalds nfs4_state_shutdown(void) 72841da177e4SLinus Torvalds { 72855e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 7286c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 7287f7d1ddbeSKinglong Mee cleanup_callback_cred(); 72881da177e4SLinus Torvalds } 72898b70484cSTigran Mkrtchyan 72908b70484cSTigran Mkrtchyan static void 72918b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 72928b70484cSTigran Mkrtchyan { 729337c593c5STigran Mkrtchyan if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) 729437c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 72958b70484cSTigran Mkrtchyan } 72968b70484cSTigran Mkrtchyan 72978b70484cSTigran Mkrtchyan static void 72988b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 72998b70484cSTigran Mkrtchyan { 730037c593c5STigran Mkrtchyan if (cstate->minorversion) { 730137c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 730237c593c5STigran Mkrtchyan SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 730337c593c5STigran Mkrtchyan } 730437c593c5STigran Mkrtchyan } 730537c593c5STigran Mkrtchyan 730637c593c5STigran Mkrtchyan void 730737c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 730837c593c5STigran Mkrtchyan { 730937c593c5STigran Mkrtchyan CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); 73108b70484cSTigran Mkrtchyan } 73118b70484cSTigran Mkrtchyan 731262cd4a59STigran Mkrtchyan /* 731362cd4a59STigran Mkrtchyan * functions to set current state id 731462cd4a59STigran Mkrtchyan */ 73158b70484cSTigran Mkrtchyan void 7316b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 7317b60e9859SChristoph Hellwig union nfsd4_op_u *u) 73189428fe1aSTigran Mkrtchyan { 7319b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 73209428fe1aSTigran Mkrtchyan } 73219428fe1aSTigran Mkrtchyan 73229428fe1aSTigran Mkrtchyan void 7323b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 7324b60e9859SChristoph Hellwig union nfsd4_op_u *u) 73258b70484cSTigran Mkrtchyan { 7326b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 73278b70484cSTigran Mkrtchyan } 73288b70484cSTigran Mkrtchyan 73298b70484cSTigran Mkrtchyan void 7330b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 7331b60e9859SChristoph Hellwig union nfsd4_op_u *u) 733262cd4a59STigran Mkrtchyan { 7333b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 733462cd4a59STigran Mkrtchyan } 733562cd4a59STigran Mkrtchyan 733662cd4a59STigran Mkrtchyan void 7337b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 7338b60e9859SChristoph Hellwig union nfsd4_op_u *u) 733962cd4a59STigran Mkrtchyan { 7340b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 734162cd4a59STigran Mkrtchyan } 734262cd4a59STigran Mkrtchyan 734362cd4a59STigran Mkrtchyan /* 734462cd4a59STigran Mkrtchyan * functions to consume current state id 734562cd4a59STigran Mkrtchyan */ 73461e97b519STigran Mkrtchyan 73471e97b519STigran Mkrtchyan void 734857832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 734957832e7bSChristoph Hellwig union nfsd4_op_u *u) 73509428fe1aSTigran Mkrtchyan { 735157832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 73529428fe1aSTigran Mkrtchyan } 73539428fe1aSTigran Mkrtchyan 73549428fe1aSTigran Mkrtchyan void 735557832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 735657832e7bSChristoph Hellwig union nfsd4_op_u *u) 73579428fe1aSTigran Mkrtchyan { 735857832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 73599428fe1aSTigran Mkrtchyan } 73609428fe1aSTigran Mkrtchyan 73619428fe1aSTigran Mkrtchyan void 736257832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 736357832e7bSChristoph Hellwig union nfsd4_op_u *u) 73641e97b519STigran Mkrtchyan { 736557832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 73661e97b519STigran Mkrtchyan } 73671e97b519STigran Mkrtchyan 73681e97b519STigran Mkrtchyan void 736957832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 737057832e7bSChristoph Hellwig union nfsd4_op_u *u) 73711e97b519STigran Mkrtchyan { 737257832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 73731e97b519STigran Mkrtchyan } 73741e97b519STigran Mkrtchyan 737562cd4a59STigran Mkrtchyan void 737657832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 737757832e7bSChristoph Hellwig union nfsd4_op_u *u) 73788b70484cSTigran Mkrtchyan { 737957832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 73808b70484cSTigran Mkrtchyan } 73818b70484cSTigran Mkrtchyan 73828b70484cSTigran Mkrtchyan void 738357832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 738457832e7bSChristoph Hellwig union nfsd4_op_u *u) 73858b70484cSTigran Mkrtchyan { 738657832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 73878b70484cSTigran Mkrtchyan } 738830813e27STigran Mkrtchyan 738930813e27STigran Mkrtchyan void 739057832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 739157832e7bSChristoph Hellwig union nfsd4_op_u *u) 739230813e27STigran Mkrtchyan { 739357832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 739430813e27STigran Mkrtchyan } 739530813e27STigran Mkrtchyan 739630813e27STigran Mkrtchyan void 739757832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 739857832e7bSChristoph Hellwig union nfsd4_op_u *u) 739930813e27STigran Mkrtchyan { 740057832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 740130813e27STigran Mkrtchyan } 7402