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> 45169319f1SJ. Bruce Fields #include <linux/string_helpers.h> 469a74af21SBoaz Harrosh #include "xdr4.h" 4706b332a5SJ. Bruce Fields #include "xdr4cb.h" 480a3adadeSJ. Bruce Fields #include "vfs.h" 49bfa4b365SJ. Bruce Fields #include "current_stateid.h" 501da177e4SLinus Torvalds 515e1533c7SStanislav Kinsbursky #include "netns.h" 529cf514ccSChristoph Hellwig #include "pnfs.h" 53fd4f83fdSJeff Layton #include "filecache.h" 545e1533c7SStanislav Kinsbursky 551da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 561da177e4SLinus Torvalds 57f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 58f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 59f32f3c2dSJ. Bruce Fields .si_generation = ~0, 60f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 61f32f3c2dSJ. Bruce Fields }; 62f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 63f32f3c2dSJ. Bruce Fields /* all fields zero */ 64f32f3c2dSJ. Bruce Fields }; 6519ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 6619ff0f28STigran Mkrtchyan .si_generation = 1, 6719ff0f28STigran Mkrtchyan }; 68fb500a7cSTrond Myklebust static const stateid_t close_stateid = { 69fb500a7cSTrond Myklebust .si_generation = 0xffffffffU, 70fb500a7cSTrond Myklebust }; 71f32f3c2dSJ. Bruce Fields 72ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 73fd39ca9aSNeilBrown 74f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 75f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 7619ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 77ae254dacSAndrew Elble #define CLOSE_STATEID(stateid) (!memcmp((stateid), &close_stateid, sizeof(stateid_t))) 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* forward declarations */ 80f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 816011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 82362063a5SScott Mayhew void nfsd4_end_grace(struct nfsd_net *nn); 83624322f1SOlga Kornievskaia static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); 841da177e4SLinus Torvalds 858b671b80SJ. Bruce Fields /* Locking: */ 868b671b80SJ. Bruce Fields 878b671b80SJ. Bruce Fields /* 888b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 898b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 908b671b80SJ. Bruce Fields * eventually cover more: 918b671b80SJ. Bruce Fields */ 92cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 938b671b80SJ. Bruce Fields 944f34bd05SAndrew Elble enum nfsd4_st_mutex_lock_subclass { 954f34bd05SAndrew Elble OPEN_STATEID_MUTEX = 0, 964f34bd05SAndrew Elble LOCK_STATEID_MUTEX = 1, 974f34bd05SAndrew Elble }; 984f34bd05SAndrew Elble 99b401be22SJeff Layton /* 100b401be22SJeff Layton * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for 101b401be22SJeff Layton * the refcount on the open stateid to drop. 102b401be22SJeff Layton */ 103b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq); 104b401be22SJeff Layton 10589c905beSJ. Bruce Fields /* 10689c905beSJ. Bruce Fields * A waitqueue where a writer to clients/#/ctl destroying a client can 10789c905beSJ. Bruce Fields * wait for cl_rpc_users to drop to 0 and then for the client to be 10889c905beSJ. Bruce Fields * unhashed. 10989c905beSJ. Bruce Fields */ 11089c905beSJ. Bruce Fields static DECLARE_WAIT_QUEUE_HEAD(expiry_wq); 11189c905beSJ. Bruce Fields 1129258a2d5SJeff Layton static struct kmem_cache *client_slab; 113abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 114abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 115abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 116abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 117abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 1188287f009SSachin Bhamare static struct kmem_cache *odstate_slab; 119e60d4398SNeilBrown 12066b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 121508dc6e1SBenny Halevy 122c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; 12376d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; 1240162ac2bSChristoph Hellwig 12566b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 126508dc6e1SBenny Halevy { 12766b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 12866b2b9b2SJ. Bruce Fields } 12966b2b9b2SJ. Bruce Fields 130f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 131f0f51f5cSJ. Bruce Fields { 132f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 13366b2b9b2SJ. Bruce Fields return nfserr_jukebox; 13466b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 13566b2b9b2SJ. Bruce Fields return nfs_ok; 13666b2b9b2SJ. Bruce Fields } 13766b2b9b2SJ. Bruce Fields 138221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 139221a6876SJ. Bruce Fields { 140221a6876SJ. Bruce Fields return clp->cl_time == 0; 141221a6876SJ. Bruce Fields } 142221a6876SJ. Bruce Fields 143221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 144221a6876SJ. Bruce Fields { 1450a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1460a880a28STrond Myklebust 1470a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1480a880a28STrond Myklebust 149221a6876SJ. Bruce Fields if (is_client_expired(clp)) 150221a6876SJ. Bruce Fields return nfserr_expired; 15114ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 152221a6876SJ. Bruce Fields return nfs_ok; 153221a6876SJ. Bruce Fields } 154221a6876SJ. Bruce Fields 155221a6876SJ. Bruce Fields /* must be called under the client_lock */ 156221a6876SJ. Bruce Fields static inline void 157221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 158221a6876SJ. Bruce Fields { 159221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 160221a6876SJ. Bruce Fields 161221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 162221a6876SJ. Bruce Fields WARN_ON(1); 163221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 164221a6876SJ. Bruce Fields __func__, 165221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 166221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 167221a6876SJ. Bruce Fields return; 168221a6876SJ. Bruce Fields } 169221a6876SJ. Bruce Fields 170221a6876SJ. Bruce Fields dprintk("renewing client (clientid %08x/%08x)\n", 171221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 172221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 173221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 17420b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 175221a6876SJ. Bruce Fields } 176221a6876SJ. Bruce Fields 177ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 178221a6876SJ. Bruce Fields { 1790a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1800a880a28STrond Myklebust 1810a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1820a880a28STrond Myklebust 18314ed14ccSJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_rpc_users)) 184221a6876SJ. Bruce Fields return; 185221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 186221a6876SJ. Bruce Fields renew_client_locked(clp); 18789c905beSJ. Bruce Fields else 18889c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 189221a6876SJ. Bruce Fields } 190221a6876SJ. Bruce Fields 1914b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 1924b24ca7dSJeff Layton { 1934b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1944b24ca7dSJeff Layton 19514ed14ccSJ. Bruce Fields if (!atomic_dec_and_lock(&clp->cl_rpc_users, &nn->client_lock)) 196d6c249b4SJeff Layton return; 197d6c249b4SJeff Layton if (!is_client_expired(clp)) 198d6c249b4SJeff Layton renew_client_locked(clp); 19989c905beSJ. Bruce Fields else 20089c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 2014b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 2024b24ca7dSJeff Layton } 2034b24ca7dSJeff Layton 204d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 205d4e19e70STrond Myklebust { 206d4e19e70STrond Myklebust __be32 status; 207d4e19e70STrond Myklebust 208d4e19e70STrond Myklebust if (is_session_dead(ses)) 209d4e19e70STrond Myklebust return nfserr_badsession; 210d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 211d4e19e70STrond Myklebust if (status) 212d4e19e70STrond Myklebust return status; 213d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 214d4e19e70STrond Myklebust return nfs_ok; 215d4e19e70STrond Myklebust } 216d4e19e70STrond Myklebust 217d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 218d4e19e70STrond Myklebust { 219d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 2200a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2210a880a28STrond Myklebust 2220a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 223d4e19e70STrond Myklebust 224d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 225d4e19e70STrond Myklebust free_session(ses); 226d4e19e70STrond Myklebust put_client_renew_locked(clp); 227d4e19e70STrond Myklebust } 228d4e19e70STrond Myklebust 229d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 230d4e19e70STrond Myklebust { 231d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 232d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 233d4e19e70STrond Myklebust 234d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 235d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 236d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 237d4e19e70STrond Myklebust } 238d4e19e70STrond Myklebust 23976d348faSJeff Layton static struct nfsd4_blocked_lock * 24076d348faSJeff Layton find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 24176d348faSJeff Layton struct nfsd_net *nn) 24276d348faSJeff Layton { 24376d348faSJeff Layton struct nfsd4_blocked_lock *cur, *found = NULL; 24476d348faSJeff Layton 2450cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 24676d348faSJeff Layton list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { 24776d348faSJeff Layton if (fh_match(fh, &cur->nbl_fh)) { 24876d348faSJeff Layton list_del_init(&cur->nbl_list); 2497919d0a2SJeff Layton list_del_init(&cur->nbl_lru); 25076d348faSJeff Layton found = cur; 25176d348faSJeff Layton break; 25276d348faSJeff Layton } 25376d348faSJeff Layton } 2540cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 25576d348faSJeff Layton if (found) 256cb03f94fSNeilBrown locks_delete_block(&found->nbl_lock); 25776d348faSJeff Layton return found; 25876d348faSJeff Layton } 25976d348faSJeff Layton 26076d348faSJeff Layton static struct nfsd4_blocked_lock * 26176d348faSJeff Layton find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 26276d348faSJeff Layton struct nfsd_net *nn) 26376d348faSJeff Layton { 26476d348faSJeff Layton struct nfsd4_blocked_lock *nbl; 26576d348faSJeff Layton 26676d348faSJeff Layton nbl = find_blocked_lock(lo, fh, nn); 26776d348faSJeff Layton if (!nbl) { 26876d348faSJeff Layton nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); 26976d348faSJeff Layton if (nbl) { 27076d348faSJeff Layton fh_copy_shallow(&nbl->nbl_fh, fh); 27176d348faSJeff Layton locks_init_lock(&nbl->nbl_lock); 27276d348faSJeff Layton nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client, 27376d348faSJeff Layton &nfsd4_cb_notify_lock_ops, 27476d348faSJeff Layton NFSPROC4_CLNT_CB_NOTIFY_LOCK); 27576d348faSJeff Layton } 27676d348faSJeff Layton } 27776d348faSJeff Layton return nbl; 27876d348faSJeff Layton } 27976d348faSJeff Layton 28076d348faSJeff Layton static void 28176d348faSJeff Layton free_blocked_lock(struct nfsd4_blocked_lock *nbl) 28276d348faSJeff Layton { 2836aaafc43SJeff Layton locks_delete_block(&nbl->nbl_lock); 28476d348faSJeff Layton locks_release_private(&nbl->nbl_lock); 28576d348faSJeff Layton kfree(nbl); 28676d348faSJeff Layton } 28776d348faSJeff Layton 28868ef3bc3SJeff Layton static void 28968ef3bc3SJeff Layton remove_blocked_locks(struct nfs4_lockowner *lo) 29068ef3bc3SJeff Layton { 29168ef3bc3SJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 29268ef3bc3SJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 29368ef3bc3SJeff Layton struct nfsd4_blocked_lock *nbl; 29468ef3bc3SJeff Layton LIST_HEAD(reaplist); 29568ef3bc3SJeff Layton 29668ef3bc3SJeff Layton /* Dequeue all blocked locks */ 29768ef3bc3SJeff Layton spin_lock(&nn->blocked_locks_lock); 29868ef3bc3SJeff Layton while (!list_empty(&lo->lo_blocked)) { 29968ef3bc3SJeff Layton nbl = list_first_entry(&lo->lo_blocked, 30068ef3bc3SJeff Layton struct nfsd4_blocked_lock, 30168ef3bc3SJeff Layton nbl_list); 30268ef3bc3SJeff Layton list_del_init(&nbl->nbl_list); 30368ef3bc3SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 30468ef3bc3SJeff Layton } 30568ef3bc3SJeff Layton spin_unlock(&nn->blocked_locks_lock); 30668ef3bc3SJeff Layton 30768ef3bc3SJeff Layton /* Now free them */ 30868ef3bc3SJeff Layton while (!list_empty(&reaplist)) { 30968ef3bc3SJeff Layton nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, 31068ef3bc3SJeff Layton nbl_lru); 31168ef3bc3SJeff Layton list_del_init(&nbl->nbl_lru); 31268ef3bc3SJeff Layton free_blocked_lock(nbl); 31368ef3bc3SJeff Layton } 31468ef3bc3SJeff Layton } 31568ef3bc3SJeff Layton 316f456458eSJeff Layton static void 317f456458eSJeff Layton nfsd4_cb_notify_lock_prepare(struct nfsd4_callback *cb) 318f456458eSJeff Layton { 319f456458eSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(cb, 320f456458eSJeff Layton struct nfsd4_blocked_lock, nbl_cb); 321f456458eSJeff Layton locks_delete_block(&nbl->nbl_lock); 322f456458eSJeff Layton } 323f456458eSJeff Layton 32476d348faSJeff Layton static int 32576d348faSJeff Layton nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) 32676d348faSJeff Layton { 32776d348faSJeff Layton /* 32876d348faSJeff Layton * Since this is just an optimization, we don't try very hard if it 32976d348faSJeff Layton * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and 33076d348faSJeff Layton * just quit trying on anything else. 33176d348faSJeff Layton */ 33276d348faSJeff Layton switch (task->tk_status) { 33376d348faSJeff Layton case -NFS4ERR_DELAY: 33476d348faSJeff Layton rpc_delay(task, 1 * HZ); 33576d348faSJeff Layton return 0; 33676d348faSJeff Layton default: 33776d348faSJeff Layton return 1; 33876d348faSJeff Layton } 33976d348faSJeff Layton } 34076d348faSJeff Layton 34176d348faSJeff Layton static void 34276d348faSJeff Layton nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb) 34376d348faSJeff Layton { 34476d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(cb, 34576d348faSJeff Layton struct nfsd4_blocked_lock, nbl_cb); 34676d348faSJeff Layton 34776d348faSJeff Layton free_blocked_lock(nbl); 34876d348faSJeff Layton } 34976d348faSJeff Layton 35076d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { 351f456458eSJeff Layton .prepare = nfsd4_cb_notify_lock_prepare, 35276d348faSJeff Layton .done = nfsd4_cb_notify_lock_done, 35376d348faSJeff Layton .release = nfsd4_cb_notify_lock_release, 35476d348faSJeff Layton }; 35576d348faSJeff Layton 356b5971afaSKinglong Mee static inline struct nfs4_stateowner * 357b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop) 358b5971afaSKinglong Mee { 359b5971afaSKinglong Mee atomic_inc(&sop->so_count); 360b5971afaSKinglong Mee return sop; 361b5971afaSKinglong Mee } 362b5971afaSKinglong Mee 3637ffb5880STrond Myklebust static int 364d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) 3657ffb5880STrond Myklebust { 3667ffb5880STrond Myklebust return (sop->so_owner.len == owner->len) && 367d4f0489fSTrond Myklebust 0 == memcmp(sop->so_owner.data, owner->data, owner->len); 3687ffb5880STrond Myklebust } 3697ffb5880STrond Myklebust 3707ffb5880STrond Myklebust static struct nfs4_openowner * 3717ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, 372d4f0489fSTrond Myklebust struct nfs4_client *clp) 3737ffb5880STrond Myklebust { 3747ffb5880STrond Myklebust struct nfs4_stateowner *so; 3757ffb5880STrond Myklebust 376d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 3777ffb5880STrond Myklebust 378d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval], 379d4f0489fSTrond Myklebust so_strhash) { 3807ffb5880STrond Myklebust if (!so->so_is_open_owner) 3817ffb5880STrond Myklebust continue; 382b5971afaSKinglong Mee if (same_owner_str(so, &open->op_owner)) 383b5971afaSKinglong Mee return openowner(nfs4_get_stateowner(so)); 3847ffb5880STrond Myklebust } 3857ffb5880STrond Myklebust return NULL; 3867ffb5880STrond Myklebust } 3877ffb5880STrond Myklebust 3887ffb5880STrond Myklebust static struct nfs4_openowner * 3897ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 390d4f0489fSTrond Myklebust struct nfs4_client *clp) 3917ffb5880STrond Myklebust { 3927ffb5880STrond Myklebust struct nfs4_openowner *oo; 3937ffb5880STrond Myklebust 394d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 395d4f0489fSTrond Myklebust oo = find_openstateowner_str_locked(hashval, open, clp); 396d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 3977ffb5880STrond Myklebust return oo; 3987ffb5880STrond Myklebust } 3997ffb5880STrond Myklebust 4001da177e4SLinus Torvalds static inline u32 4011da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 4021da177e4SLinus Torvalds { 4031da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds u32 x = 0; 4061da177e4SLinus Torvalds while (nbytes--) { 4071da177e4SLinus Torvalds x *= 37; 4081da177e4SLinus Torvalds x += *cptr++; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds return x; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4135b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu) 41432513b40SJ. Bruce Fields { 4155b095e99SJeff Layton struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu); 4165b095e99SJeff Layton 4175b095e99SJeff Layton kmem_cache_free(file_slab, fp); 41832513b40SJ. Bruce Fields } 41932513b40SJ. Bruce Fields 420e6ba76e1SChristoph Hellwig void 42113cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 42213cd2184SNeilBrown { 42302e1215fSJeff Layton might_lock(&state_lock); 42402e1215fSJeff Layton 425818a34ebSElena Reshetova if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) { 4265b095e99SJeff Layton hlist_del_rcu(&fi->fi_hash); 427cdc97505SBenny Halevy spin_unlock(&state_lock); 4288287f009SSachin Bhamare WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); 4295b095e99SJeff Layton WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); 4305b095e99SJeff Layton call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); 4318b671b80SJ. Bruce Fields } 43213cd2184SNeilBrown } 43313cd2184SNeilBrown 434eb82dd39SJeff Layton static struct nfsd_file * 435de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag) 436de18643dSTrond Myklebust { 437de18643dSTrond Myklebust if (f->fi_fds[oflag]) 438eb82dd39SJeff Layton return nfsd_file_get(f->fi_fds[oflag]); 439de18643dSTrond Myklebust return NULL; 440de18643dSTrond Myklebust } 441de18643dSTrond Myklebust 442eb82dd39SJeff Layton static struct nfsd_file * 443de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f) 444de18643dSTrond Myklebust { 445eb82dd39SJeff Layton struct nfsd_file *ret; 446de18643dSTrond Myklebust 447de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 448de18643dSTrond Myklebust 449de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 450de18643dSTrond Myklebust if (!ret) 451de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 452de18643dSTrond Myklebust return ret; 453de18643dSTrond Myklebust } 454de18643dSTrond Myklebust 455eb82dd39SJeff Layton static struct nfsd_file * 456de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 457de18643dSTrond Myklebust { 458eb82dd39SJeff Layton struct nfsd_file *ret; 459de18643dSTrond Myklebust 460de18643dSTrond Myklebust spin_lock(&f->fi_lock); 461de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 462de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 463de18643dSTrond Myklebust 464de18643dSTrond Myklebust return ret; 465de18643dSTrond Myklebust } 466de18643dSTrond Myklebust 467eb82dd39SJeff Layton static struct nfsd_file * 468eb82dd39SJeff Layton find_readable_file_locked(struct nfs4_file *f) 469de18643dSTrond Myklebust { 470eb82dd39SJeff Layton struct nfsd_file *ret; 471de18643dSTrond Myklebust 472de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 473de18643dSTrond Myklebust 474de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 475de18643dSTrond Myklebust if (!ret) 476de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 477de18643dSTrond Myklebust return ret; 478de18643dSTrond Myklebust } 479de18643dSTrond Myklebust 480eb82dd39SJeff Layton static struct nfsd_file * 481de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 482de18643dSTrond Myklebust { 483eb82dd39SJeff Layton struct nfsd_file *ret; 484de18643dSTrond Myklebust 485de18643dSTrond Myklebust spin_lock(&f->fi_lock); 486de18643dSTrond Myklebust ret = find_readable_file_locked(f); 487de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 488de18643dSTrond Myklebust 489de18643dSTrond Myklebust return ret; 490de18643dSTrond Myklebust } 491de18643dSTrond Myklebust 492eb82dd39SJeff Layton struct nfsd_file * 493de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 494de18643dSTrond Myklebust { 495eb82dd39SJeff Layton struct nfsd_file *ret; 496de18643dSTrond Myklebust 497de18643dSTrond Myklebust spin_lock(&f->fi_lock); 498de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 499de18643dSTrond Myklebust if (!ret) { 500de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 501de18643dSTrond Myklebust if (!ret) 502de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 503de18643dSTrond Myklebust } 504de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 505de18643dSTrond Myklebust return ret; 506de18643dSTrond Myklebust } 507de18643dSTrond Myklebust 50802a3508dSTrond Myklebust static atomic_long_t num_delegations; 509697ce9beSZhang Yanfei unsigned long max_delegations; 510ef0f3390SNeilBrown 511ef0f3390SNeilBrown /* 512ef0f3390SNeilBrown * Open owner state (share locks) 513ef0f3390SNeilBrown */ 514ef0f3390SNeilBrown 51516bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 51616bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 51716bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 51816bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 519ef0f3390SNeilBrown 520d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 521ddc04c41SJ. Bruce Fields { 522ddc04c41SJ. Bruce Fields unsigned int ret; 523ddc04c41SJ. Bruce Fields 524ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 52516bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 526ddc04c41SJ. Bruce Fields } 527ef0f3390SNeilBrown 528ef0f3390SNeilBrown /* hash table for nfs4_file */ 529ef0f3390SNeilBrown #define FILE_HASH_BITS 8 530ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 53135079582SShan Wei 532ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) 533ddc04c41SJ. Bruce Fields { 534ca943217STrond Myklebust return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); 535ca943217STrond Myklebust } 536ca943217STrond Myklebust 537ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh) 538ca943217STrond Myklebust { 539ca943217STrond Myklebust return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); 540ca943217STrond Myklebust } 541ca943217STrond Myklebust 54289876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 543ef0f3390SNeilBrown 54412659651SJeff Layton static void 54512659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 5463477565eSJ. Bruce Fields { 5477214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5487214e860SJeff Layton 54912659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 55012659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 55112659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 55212659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 5533477565eSJ. Bruce Fields } 5543477565eSJ. Bruce Fields 55512659651SJeff Layton static __be32 55612659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 557998db52cSJ. Bruce Fields { 5587214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5597214e860SJeff Layton 56012659651SJeff Layton /* Does this access mode make sense? */ 56112659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 56212659651SJeff Layton return nfserr_inval; 56312659651SJeff Layton 564baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 565baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 566baeb4ff0SJeff Layton return nfserr_share_denied; 567baeb4ff0SJeff Layton 56812659651SJeff Layton __nfs4_file_get_access(fp, access); 56912659651SJeff Layton return nfs_ok; 570998db52cSJ. Bruce Fields } 571998db52cSJ. Bruce Fields 572baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 573baeb4ff0SJeff Layton { 574baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 575baeb4ff0SJeff Layton if (deny) { 576baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 577baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 578baeb4ff0SJeff Layton return nfserr_inval; 579baeb4ff0SJeff Layton 580baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 581baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 582baeb4ff0SJeff Layton return nfserr_share_denied; 583baeb4ff0SJeff Layton 584baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 585baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 586baeb4ff0SJeff Layton return nfserr_share_denied; 587baeb4ff0SJeff Layton } 588baeb4ff0SJeff Layton return nfs_ok; 589baeb4ff0SJeff Layton } 590baeb4ff0SJeff Layton 591998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 592f9d7562fSJ. Bruce Fields { 593de18643dSTrond Myklebust might_lock(&fp->fi_lock); 594de18643dSTrond Myklebust 595de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 596fd4f83fdSJeff Layton struct nfsd_file *f1 = NULL; 597fd4f83fdSJeff Layton struct nfsd_file *f2 = NULL; 598de18643dSTrond Myklebust 5996d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 6000c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 6016d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 602de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 603de18643dSTrond Myklebust if (f1) 604fd4f83fdSJeff Layton nfsd_file_put(f1); 605de18643dSTrond Myklebust if (f2) 606fd4f83fdSJeff Layton nfsd_file_put(f2); 607f9d7562fSJ. Bruce Fields } 608f9d7562fSJ. Bruce Fields } 609f9d7562fSJ. Bruce Fields 61012659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 611998db52cSJ. Bruce Fields { 61212659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 61312659651SJeff Layton 61412659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 615998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 61612659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 61712659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 618998db52cSJ. Bruce Fields } 619998db52cSJ. Bruce Fields 6208287f009SSachin Bhamare /* 6218287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 6228287f009SSachin Bhamare * pNFS for proper return on close semantics. 6238287f009SSachin Bhamare * 6248287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 6258287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 6268287f009SSachin Bhamare */ 6278287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6288287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 6298287f009SSachin Bhamare { 6308287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6318287f009SSachin Bhamare 6328287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 6338287f009SSachin Bhamare if (co) { 6348287f009SSachin Bhamare co->co_client = clp; 635cff7cb2eSElena Reshetova refcount_set(&co->co_odcount, 1); 6368287f009SSachin Bhamare } 6378287f009SSachin Bhamare return co; 6388287f009SSachin Bhamare } 6398287f009SSachin Bhamare 6408287f009SSachin Bhamare static void 6418287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 6428287f009SSachin Bhamare { 6438287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 6448287f009SSachin Bhamare 6458287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 6468287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 6478287f009SSachin Bhamare } 6488287f009SSachin Bhamare 6498287f009SSachin Bhamare static inline void 6508287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 6518287f009SSachin Bhamare { 6528287f009SSachin Bhamare if (co) 653cff7cb2eSElena Reshetova refcount_inc(&co->co_odcount); 6548287f009SSachin Bhamare } 6558287f009SSachin Bhamare 6568287f009SSachin Bhamare static void 6578287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 6588287f009SSachin Bhamare { 6598287f009SSachin Bhamare struct nfs4_file *fp; 6608287f009SSachin Bhamare 6618287f009SSachin Bhamare if (!co) 6628287f009SSachin Bhamare return; 6638287f009SSachin Bhamare 6648287f009SSachin Bhamare fp = co->co_file; 665cff7cb2eSElena Reshetova if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 6668287f009SSachin Bhamare list_del(&co->co_perfile); 6678287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 6688287f009SSachin Bhamare 6698287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 6708287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 6718287f009SSachin Bhamare } 6728287f009SSachin Bhamare } 6738287f009SSachin Bhamare 6748287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6758287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 6768287f009SSachin Bhamare { 6778287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6788287f009SSachin Bhamare struct nfs4_client *cl; 6798287f009SSachin Bhamare 6808287f009SSachin Bhamare if (!new) 6818287f009SSachin Bhamare return NULL; 6828287f009SSachin Bhamare 6838287f009SSachin Bhamare cl = new->co_client; 6848287f009SSachin Bhamare 6858287f009SSachin Bhamare spin_lock(&fp->fi_lock); 6868287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 6878287f009SSachin Bhamare if (co->co_client == cl) { 6888287f009SSachin Bhamare get_clnt_odstate(co); 6898287f009SSachin Bhamare goto out; 6908287f009SSachin Bhamare } 6918287f009SSachin Bhamare } 6928287f009SSachin Bhamare co = new; 6938287f009SSachin Bhamare co->co_file = fp; 6948287f009SSachin Bhamare hash_clnt_odstate_locked(new); 6958287f009SSachin Bhamare out: 6968287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 6978287f009SSachin Bhamare return co; 6988287f009SSachin Bhamare } 6998287f009SSachin Bhamare 700d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 701d19fb70dSKinglong Mee void (*sc_free)(struct nfs4_stid *)) 702996e0938SJ. Bruce Fields { 7033abdb607SJ. Bruce Fields struct nfs4_stid *stid; 7043abdb607SJ. Bruce Fields int new_id; 7053abdb607SJ. Bruce Fields 706f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 7073abdb607SJ. Bruce Fields if (!stid) 7083abdb607SJ. Bruce Fields return NULL; 709996e0938SJ. Bruce Fields 7104770d722SJeff Layton idr_preload(GFP_KERNEL); 7114770d722SJeff Layton spin_lock(&cl->cl_lock); 71278599c42SJ. Bruce Fields /* Reserving 0 for start of file in nfsdfs "states" file: */ 71378599c42SJ. Bruce Fields new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 1, 0, GFP_NOWAIT); 7144770d722SJeff Layton spin_unlock(&cl->cl_lock); 7154770d722SJeff Layton idr_preload_end(); 716ebd6c707STejun Heo if (new_id < 0) 7173abdb607SJ. Bruce Fields goto out_free; 718d19fb70dSKinglong Mee 719d19fb70dSKinglong Mee stid->sc_free = sc_free; 7203abdb607SJ. Bruce Fields stid->sc_client = cl; 7213abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 7223abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 7233abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 724a15dfcd5SElena Reshetova refcount_set(&stid->sc_count, 1); 7259767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 726624322f1SOlga Kornievskaia INIT_LIST_HEAD(&stid->sc_cp_list); 7273abdb607SJ. Bruce Fields 728996e0938SJ. Bruce Fields /* 7293abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 7303abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 7313abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 7323abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 7333abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 7343abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 7353abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 736996e0938SJ. Bruce Fields */ 7373abdb607SJ. Bruce Fields return stid; 7383abdb607SJ. Bruce Fields out_free: 7392c44a234SWei Yongjun kmem_cache_free(slab, stid); 7403abdb607SJ. Bruce Fields return NULL; 7412a74aba7SJ. Bruce Fields } 7422a74aba7SJ. Bruce Fields 743e0639dc5SOlga Kornievskaia /* 744e0639dc5SOlga Kornievskaia * Create a unique stateid_t to represent each COPY. 745e0639dc5SOlga Kornievskaia */ 746624322f1SOlga Kornievskaia static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, 747624322f1SOlga Kornievskaia unsigned char sc_type) 748e0639dc5SOlga Kornievskaia { 749e0639dc5SOlga Kornievskaia int new_id; 750e0639dc5SOlga Kornievskaia 7519cc76801SArnd Bergmann stid->stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; 752624322f1SOlga Kornievskaia stid->stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; 753624322f1SOlga Kornievskaia stid->sc_type = sc_type; 754624322f1SOlga Kornievskaia 755e0639dc5SOlga Kornievskaia idr_preload(GFP_KERNEL); 756e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 757624322f1SOlga Kornievskaia new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT); 758624322f1SOlga Kornievskaia stid->stid.si_opaque.so_id = new_id; 759e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 760e0639dc5SOlga Kornievskaia idr_preload_end(); 761e0639dc5SOlga Kornievskaia if (new_id < 0) 762e0639dc5SOlga Kornievskaia return 0; 763e0639dc5SOlga Kornievskaia return 1; 764e0639dc5SOlga Kornievskaia } 765e0639dc5SOlga Kornievskaia 766624322f1SOlga Kornievskaia int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy) 767624322f1SOlga Kornievskaia { 768624322f1SOlga Kornievskaia return nfs4_init_cp_state(nn, ©->cp_stateid, NFS4_COPY_STID); 769624322f1SOlga Kornievskaia } 770624322f1SOlga Kornievskaia 771624322f1SOlga Kornievskaia struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, 772624322f1SOlga Kornievskaia struct nfs4_stid *p_stid) 773624322f1SOlga Kornievskaia { 774624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 775624322f1SOlga Kornievskaia 776624322f1SOlga Kornievskaia cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL); 777624322f1SOlga Kornievskaia if (!cps) 778624322f1SOlga Kornievskaia return NULL; 77920b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 780624322f1SOlga Kornievskaia refcount_set(&cps->cp_stateid.sc_count, 1); 781624322f1SOlga Kornievskaia if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID)) 782624322f1SOlga Kornievskaia goto out_free; 783624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 784624322f1SOlga Kornievskaia list_add(&cps->cp_list, &p_stid->sc_cp_list); 785624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 786624322f1SOlga Kornievskaia return cps; 787624322f1SOlga Kornievskaia out_free: 788624322f1SOlga Kornievskaia kfree(cps); 789624322f1SOlga Kornievskaia return NULL; 790624322f1SOlga Kornievskaia } 791624322f1SOlga Kornievskaia 792624322f1SOlga Kornievskaia void nfs4_free_copy_state(struct nfsd4_copy *copy) 793e0639dc5SOlga Kornievskaia { 794e0639dc5SOlga Kornievskaia struct nfsd_net *nn; 795e0639dc5SOlga Kornievskaia 796624322f1SOlga Kornievskaia WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID); 797e0639dc5SOlga Kornievskaia nn = net_generic(copy->cp_clp->net, nfsd_net_id); 798e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 799624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 800624322f1SOlga Kornievskaia copy->cp_stateid.stid.si_opaque.so_id); 801624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 802624322f1SOlga Kornievskaia } 803624322f1SOlga Kornievskaia 804624322f1SOlga Kornievskaia static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid) 805624322f1SOlga Kornievskaia { 806624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 807624322f1SOlga Kornievskaia struct nfsd_net *nn; 808624322f1SOlga Kornievskaia 809624322f1SOlga Kornievskaia nn = net_generic(net, nfsd_net_id); 810624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 811624322f1SOlga Kornievskaia while (!list_empty(&stid->sc_cp_list)) { 812624322f1SOlga Kornievskaia cps = list_first_entry(&stid->sc_cp_list, 813624322f1SOlga Kornievskaia struct nfs4_cpntf_state, cp_list); 814624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 815624322f1SOlga Kornievskaia } 816e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 817e0639dc5SOlga Kornievskaia } 818e0639dc5SOlga Kornievskaia 819b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 8204cdc951bSJ. Bruce Fields { 8216011695dSTrond Myklebust struct nfs4_stid *stid; 8226011695dSTrond Myklebust 823d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 8246011695dSTrond Myklebust if (!stid) 8256011695dSTrond Myklebust return NULL; 8266011695dSTrond Myklebust 827d19fb70dSKinglong Mee return openlockstateid(stid); 8286011695dSTrond Myklebust } 8296011695dSTrond Myklebust 8306011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 8316011695dSTrond Myklebust { 8326011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 8336011695dSTrond Myklebust atomic_long_dec(&num_delegations); 8344cdc951bSJ. Bruce Fields } 8354cdc951bSJ. Bruce Fields 8366282cd56SNeilBrown /* 8376282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 8386282cd56SNeilBrown * out again straight away. 8396282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 8406282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 8416282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 8426282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 8436282cd56SNeilBrown * filter. 8446282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 8456282cd56SNeilBrown * unless both are empty of course. 8466282cd56SNeilBrown * 8476282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 8486282cd56SNeilBrown * low 3 bytes as hash-table indices. 8496282cd56SNeilBrown * 850f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 8516282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 8526282cd56SNeilBrown * except when swapping the two filters. 8536282cd56SNeilBrown */ 854f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 8556282cd56SNeilBrown static struct bloom_pair { 8566282cd56SNeilBrown int entries, old_entries; 857b3f255efSArnd Bergmann time64_t swap_time; 8586282cd56SNeilBrown int new; /* index into 'set' */ 8596282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 8606282cd56SNeilBrown } blocked_delegations; 8616282cd56SNeilBrown 8626282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 8636282cd56SNeilBrown { 8646282cd56SNeilBrown u32 hash; 8656282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 8666282cd56SNeilBrown 8676282cd56SNeilBrown if (bd->entries == 0) 8686282cd56SNeilBrown return 0; 869b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 870f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 871b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 8726282cd56SNeilBrown bd->entries -= bd->old_entries; 8736282cd56SNeilBrown bd->old_entries = bd->entries; 8746282cd56SNeilBrown memset(bd->set[bd->new], 0, 8756282cd56SNeilBrown sizeof(bd->set[0])); 8766282cd56SNeilBrown bd->new = 1-bd->new; 877b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 8786282cd56SNeilBrown } 879f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 8806282cd56SNeilBrown } 88187545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 8826282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 8836282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 8846282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 8856282cd56SNeilBrown return 1; 8866282cd56SNeilBrown 8876282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 8886282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 8896282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 8906282cd56SNeilBrown return 1; 8916282cd56SNeilBrown 8926282cd56SNeilBrown return 0; 8936282cd56SNeilBrown } 8946282cd56SNeilBrown 8956282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 8966282cd56SNeilBrown { 8976282cd56SNeilBrown u32 hash; 8986282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 8996282cd56SNeilBrown 90087545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 9016282cd56SNeilBrown 902f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 9036282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 9046282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 9056282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 9066282cd56SNeilBrown if (bd->entries == 0) 907b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 9086282cd56SNeilBrown bd->entries += 1; 909f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 9106282cd56SNeilBrown } 9116282cd56SNeilBrown 9121da177e4SLinus Torvalds static struct nfs4_delegation * 91386d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 91486d29b10SJ. Bruce Fields struct svc_fh *current_fh, 9158287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 9161da177e4SLinus Torvalds { 9171da177e4SLinus Torvalds struct nfs4_delegation *dp; 91802a3508dSTrond Myklebust long n; 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 92102a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 92202a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 92302a3508dSTrond Myklebust goto out_dec; 9246282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 92502a3508dSTrond Myklebust goto out_dec; 926d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 9275b2d21c1SNeilBrown if (dp == NULL) 92802a3508dSTrond Myklebust goto out_dec; 9296011695dSTrond Myklebust 9302a74aba7SJ. Bruce Fields /* 9312a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 9326136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 9336136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 9342a74aba7SJ. Bruce Fields */ 9352a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 936ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 937ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 9381da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 9398287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 9408287f009SSachin Bhamare get_clnt_odstate(odstate); 94199c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 942f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 943f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 9440162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 94586d29b10SJ. Bruce Fields get_nfs4_file(fp); 94686d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 9471da177e4SLinus Torvalds return dp; 94802a3508dSTrond Myklebust out_dec: 94902a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 95002a3508dSTrond Myklebust return NULL; 9511da177e4SLinus Torvalds } 9521da177e4SLinus Torvalds 9531da177e4SLinus Torvalds void 9546011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 9551da177e4SLinus Torvalds { 95611b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 9576011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 9586011695dSTrond Myklebust 9594770d722SJeff Layton might_lock(&clp->cl_lock); 9604770d722SJeff Layton 961a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 962b401be22SJeff Layton wake_up_all(&close_wq); 9636011695dSTrond Myklebust return; 964b401be22SJeff Layton } 9656011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 966624322f1SOlga Kornievskaia nfs4_free_cpntf_statelist(clp->net, s); 9674770d722SJeff Layton spin_unlock(&clp->cl_lock); 9686011695dSTrond Myklebust s->sc_free(s); 96911b9164aSTrond Myklebust if (fp) 97011b9164aSTrond Myklebust put_nfs4_file(fp); 9711da177e4SLinus Torvalds } 9721da177e4SLinus Torvalds 9739767feb2SJeff Layton void 9749767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 9759767feb2SJeff Layton { 9769767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 9779767feb2SJeff Layton 9789767feb2SJeff Layton spin_lock(&stid->sc_lock); 9799767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 9809767feb2SJeff Layton src->si_generation = 1; 9819767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 9829767feb2SJeff Layton spin_unlock(&stid->sc_lock); 9839767feb2SJeff Layton } 9849767feb2SJeff Layton 985353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 9861da177e4SLinus Torvalds { 987eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 988353601e7SJ. Bruce Fields 989353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 990353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 991eb82dd39SJeff Layton swap(nf, fp->fi_deleg_file); 992353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 993353601e7SJ. Bruce Fields 994eb82dd39SJeff Layton if (nf) 995eb82dd39SJeff Layton nfsd_file_put(nf); 996353601e7SJ. Bruce Fields } 997353601e7SJ. Bruce Fields 998353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 999353601e7SJ. Bruce Fields { 1000cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 1001eb82dd39SJeff Layton struct nfsd_file *nf = fp->fi_deleg_file; 1002417c6629SJeff Layton 1003b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 1004b8232d33SJ. Bruce Fields 1005eb82dd39SJeff Layton vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); 1006353601e7SJ. Bruce Fields put_deleg_file(fp); 10071da177e4SLinus Torvalds } 10081da177e4SLinus Torvalds 10090af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 10100af6e690SJ. Bruce Fields { 10110af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 1012353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 10130af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 10140af6e690SJ. Bruce Fields } 10150af6e690SJ. Bruce Fields 1016cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 10176136d2b4SJ. Bruce Fields { 10183abdb607SJ. Bruce Fields s->sc_type = 0; 10196136d2b4SJ. Bruce Fields } 10206136d2b4SJ. Bruce Fields 102134ed9872SAndrew Elble /** 102268b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 102334ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 102434ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 102534ed9872SAndrew Elble * 102634ed9872SAndrew Elble * Return: 102768b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 102834ed9872SAndrew Elble */ 102934ed9872SAndrew Elble 103068b18f52SJ. Bruce Fields static bool 103168b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 1032931ee56cSBenny Halevy { 103334ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 103434ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 103534ed9872SAndrew Elble 1036cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 1037417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 1038931ee56cSBenny Halevy 103934ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 104034ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 104134ed9872SAndrew Elble if (clp == searchclp) { 104251d87bc2SFengguang Wu return true; 104334ed9872SAndrew Elble } 104434ed9872SAndrew Elble } 104551d87bc2SFengguang Wu return false; 104634ed9872SAndrew Elble } 104734ed9872SAndrew Elble 104834ed9872SAndrew Elble /** 104934ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 105034ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 105134ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 105234ed9872SAndrew Elble * 105334ed9872SAndrew Elble * Return: 105434ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 105534ed9872SAndrew Elble * 105634ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 105734ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 105834ed9872SAndrew Elble * 105934ed9872SAndrew Elble */ 106034ed9872SAndrew Elble 106134ed9872SAndrew Elble static int 106234ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 106334ed9872SAndrew Elble { 106434ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 106534ed9872SAndrew Elble 106634ed9872SAndrew Elble lockdep_assert_held(&state_lock); 106734ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 106834ed9872SAndrew Elble 106968b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 107068b18f52SJ. Bruce Fields return -EAGAIN; 1071a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 10723fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 1073931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 107434ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 107534ed9872SAndrew Elble return 0; 1076931ee56cSBenny Halevy } 1077931ee56cSBenny Halevy 10783fcbbd24SJeff Layton static bool 107942690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 10801da177e4SLinus Torvalds { 108111b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 108202e1215fSJeff Layton 108342690676SJeff Layton lockdep_assert_held(&state_lock); 108442690676SJeff Layton 10853fcbbd24SJeff Layton if (list_empty(&dp->dl_perfile)) 10863fcbbd24SJeff Layton return false; 10873fcbbd24SJeff Layton 1088b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 1089d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 1090d55a166cSJeff Layton ++dp->dl_time; 1091417c6629SJeff Layton spin_lock(&fp->fi_lock); 1092931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 10931da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 109402e1215fSJeff Layton list_del_init(&dp->dl_perfile); 109502e1215fSJeff Layton spin_unlock(&fp->fi_lock); 10963fcbbd24SJeff Layton return true; 1097cbf7a75bSJ. Bruce Fields } 10983bd64a5bSJ. Bruce Fields 10993bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 11003bd64a5bSJ. Bruce Fields { 11013fcbbd24SJeff Layton bool unhashed; 11023fcbbd24SJeff Layton 110342690676SJeff Layton spin_lock(&state_lock); 11043fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 110542690676SJeff Layton spin_unlock(&state_lock); 11060af6e690SJ. Bruce Fields if (unhashed) 11070af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 11083fcbbd24SJeff Layton } 11093bd64a5bSJ. Bruce Fields 11103bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 11113bd64a5bSJ. Bruce Fields { 11123bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 11133bd64a5bSJ. Bruce Fields 11142d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 11152d4a532dSJeff Layton 11160af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 11173bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 11180af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 11192d4a532dSJeff Layton spin_lock(&clp->cl_lock); 11202d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 11212d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 11223bd64a5bSJ. Bruce Fields } 11230af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 11243bd64a5bSJ. Bruce Fields } 11253bd64a5bSJ. Bruce Fields 11261da177e4SLinus Torvalds /* 11271da177e4SLinus Torvalds * SETCLIENTID state 11281da177e4SLinus Torvalds */ 11291da177e4SLinus Torvalds 1130ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1131ddc04c41SJ. Bruce Fields { 1132ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1133ddc04c41SJ. Bruce Fields } 1134ddc04c41SJ. Bruce Fields 11356b189105SScott Mayhew static unsigned int clientstr_hashval(struct xdr_netobj name) 1136ddc04c41SJ. Bruce Fields { 11376b189105SScott Mayhew return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; 1138ddc04c41SJ. Bruce Fields } 1139ddc04c41SJ. Bruce Fields 11401da177e4SLinus Torvalds /* 1141f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 1142f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 1143f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 1144f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 1145f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 1146f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 1147f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 1148f9d7562fSJ. Bruce Fields * 1149f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 1150f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 1151f9d7562fSJ. Bruce Fields * 1152f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 1153f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 1154f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 1155f9d7562fSJ. Bruce Fields * 1156f9d7562fSJ. Bruce Fields * which we should reject. 1157f9d7562fSJ. Bruce Fields */ 11585ae037e5SJeff Layton static unsigned int 11595ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 1160f9d7562fSJ. Bruce Fields int i; 11615ae037e5SJeff Layton unsigned int access = 0; 1162f9d7562fSJ. Bruce Fields 1163f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 1164f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 11655ae037e5SJeff Layton access |= i; 1166f9d7562fSJ. Bruce Fields } 11675ae037e5SJeff Layton return access; 1168f9d7562fSJ. Bruce Fields } 1169f9d7562fSJ. Bruce Fields 117082c5ff1bSJeff Layton /* set share access for a given stateid */ 117182c5ff1bSJeff Layton static inline void 117282c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 117382c5ff1bSJeff Layton { 1174c11c591fSJeff Layton unsigned char mask = 1 << access; 1175c11c591fSJeff Layton 1176c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1177c11c591fSJeff Layton stp->st_access_bmap |= mask; 117882c5ff1bSJeff Layton } 117982c5ff1bSJeff Layton 118082c5ff1bSJeff Layton /* clear share access for a given stateid */ 118182c5ff1bSJeff Layton static inline void 118282c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 118382c5ff1bSJeff Layton { 1184c11c591fSJeff Layton unsigned char mask = 1 << access; 1185c11c591fSJeff Layton 1186c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1187c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 118882c5ff1bSJeff Layton } 118982c5ff1bSJeff Layton 119082c5ff1bSJeff Layton /* test whether a given stateid has access */ 119182c5ff1bSJeff Layton static inline bool 119282c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 119382c5ff1bSJeff Layton { 1194c11c591fSJeff Layton unsigned char mask = 1 << access; 1195c11c591fSJeff Layton 1196c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 119782c5ff1bSJeff Layton } 119882c5ff1bSJeff Layton 1199ce0fc43cSJeff Layton /* set share deny for a given stateid */ 1200ce0fc43cSJeff Layton static inline void 1201c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 1202ce0fc43cSJeff Layton { 1203c11c591fSJeff Layton unsigned char mask = 1 << deny; 1204c11c591fSJeff Layton 1205c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1206c11c591fSJeff Layton stp->st_deny_bmap |= mask; 1207ce0fc43cSJeff Layton } 1208ce0fc43cSJeff Layton 1209ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 1210ce0fc43cSJeff Layton static inline void 1211c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 1212ce0fc43cSJeff Layton { 1213c11c591fSJeff Layton unsigned char mask = 1 << deny; 1214c11c591fSJeff Layton 1215c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1216c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 1217ce0fc43cSJeff Layton } 1218ce0fc43cSJeff Layton 1219ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 1220ce0fc43cSJeff Layton static inline bool 1221c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 1222ce0fc43cSJeff Layton { 1223c11c591fSJeff Layton unsigned char mask = 1 << deny; 1224c11c591fSJeff Layton 1225c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 1226f9d7562fSJ. Bruce Fields } 1227f9d7562fSJ. Bruce Fields 1228f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 1229f9d7562fSJ. Bruce Fields { 12308f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 1231f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 1232f9d7562fSJ. Bruce Fields return O_RDONLY; 1233f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 1234f9d7562fSJ. Bruce Fields return O_WRONLY; 1235f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 1236f9d7562fSJ. Bruce Fields return O_RDWR; 1237f9d7562fSJ. Bruce Fields } 1238063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 1239063b0fb9SJ. Bruce Fields return O_RDONLY; 1240f9d7562fSJ. Bruce Fields } 1241f9d7562fSJ. Bruce Fields 1242baeb4ff0SJeff Layton /* 1243baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1244baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1245baeb4ff0SJeff Layton */ 1246baeb4ff0SJeff Layton static void 1247baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1248baeb4ff0SJeff Layton { 1249baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1250baeb4ff0SJeff Layton 1251baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1252baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1253baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1254baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1255baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1256baeb4ff0SJeff Layton } 1257baeb4ff0SJeff Layton 1258baeb4ff0SJeff Layton static void 1259baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1260baeb4ff0SJeff Layton { 1261baeb4ff0SJeff Layton int i; 1262baeb4ff0SJeff Layton bool change = false; 1263baeb4ff0SJeff Layton 1264baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1265baeb4ff0SJeff Layton if ((i & deny) != i) { 1266baeb4ff0SJeff Layton change = true; 1267baeb4ff0SJeff Layton clear_deny(i, stp); 1268baeb4ff0SJeff Layton } 1269baeb4ff0SJeff Layton } 1270baeb4ff0SJeff Layton 1271baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1272baeb4ff0SJeff Layton if (change) 127311b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1274baeb4ff0SJeff Layton } 1275baeb4ff0SJeff Layton 127682c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 127782c5ff1bSJeff Layton static void 127882c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 127982c5ff1bSJeff Layton { 128082c5ff1bSJeff Layton int i; 128111b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1282baeb4ff0SJeff Layton 1283baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1284baeb4ff0SJeff Layton recalculate_deny_mode(fp); 128582c5ff1bSJeff Layton 128682c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 128782c5ff1bSJeff Layton if (test_access(i, stp)) 128811b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 128982c5ff1bSJeff Layton clear_access(i, stp); 129082c5ff1bSJeff Layton } 129182c5ff1bSJeff Layton } 129282c5ff1bSJeff Layton 1293d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1294d50ffdedSKinglong Mee { 1295d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1296d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1297d50ffdedSKinglong Mee } 1298d50ffdedSKinglong Mee 12996b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 13006b180f0bSJeff Layton { 1301a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1302a819ecc1SJeff Layton 1303a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1304a819ecc1SJeff Layton 1305a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 13066b180f0bSJeff Layton return; 13078f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1308a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1309d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 13106b180f0bSJeff Layton } 13116b180f0bSJeff Layton 1312e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1313529d7b2aSJ. Bruce Fields { 131411b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 13151d31a253STrond Myklebust 13161c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 13171c755dc1SJeff Layton 1318e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1319e8568739SJeff Layton return false; 1320e8568739SJeff Layton 13211d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1322e8568739SJeff Layton list_del_init(&stp->st_perfile); 13231d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1324529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1325e8568739SJeff Layton return true; 1326529d7b2aSJ. Bruce Fields } 1327529d7b2aSJ. Bruce Fields 13286011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1329529d7b2aSJ. Bruce Fields { 13306011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 13314665e2baSJ. Bruce Fields 13328287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 13336011695dSTrond Myklebust release_all_access(stp); 1334d3134b10SJeff Layton if (stp->st_stateowner) 1335d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 13366011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1337529d7b2aSJ. Bruce Fields } 1338529d7b2aSJ. Bruce Fields 1339b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1340529d7b2aSJ. Bruce Fields { 1341b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1342b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1343eb82dd39SJeff Layton struct nfsd_file *nf; 1344529d7b2aSJ. Bruce Fields 1345eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 1346eb82dd39SJeff Layton if (nf) { 1347eb82dd39SJeff Layton get_file(nf->nf_file); 1348eb82dd39SJeff Layton filp_close(nf->nf_file, (fl_owner_t)lo); 1349eb82dd39SJeff Layton nfsd_file_put(nf); 1350eb82dd39SJeff Layton } 1351b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1352b49e084dSJeff Layton } 1353b49e084dSJeff Layton 13542c41beb0SJeff Layton /* 13552c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 13562c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 13572c41beb0SJeff Layton * reaplist for later destruction. 13582c41beb0SJeff Layton */ 13592c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 13602c41beb0SJeff Layton struct list_head *reaplist) 13612c41beb0SJeff Layton { 13622c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 13632c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 13642c41beb0SJeff Layton 13652c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 13662c41beb0SJeff Layton 13672c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 13682c41beb0SJeff Layton 1369a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 13702c41beb0SJeff Layton wake_up_all(&close_wq); 13712c41beb0SJeff Layton return; 13722c41beb0SJeff Layton } 13732c41beb0SJeff Layton 13742c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 13752c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 13762c41beb0SJeff Layton } 13772c41beb0SJeff Layton 1378e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 13793c1c995cSJeff Layton { 1380f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 13813c1c995cSJeff Layton 13823c1c995cSJeff Layton list_del_init(&stp->st_locks); 1383cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1384e8568739SJeff Layton return unhash_ol_stateid(stp); 13853c1c995cSJeff Layton } 13863c1c995cSJeff Layton 13875adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1388b49e084dSJeff Layton { 1389f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1390e8568739SJeff Layton bool unhashed; 13911c755dc1SJeff Layton 1392f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1393e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1394f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1395e8568739SJeff Layton if (unhashed) 13966011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1397529d7b2aSJ. Bruce Fields } 1398529d7b2aSJ. Bruce Fields 1399c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1400529d7b2aSJ. Bruce Fields { 1401d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1402c58c6610STrond Myklebust 1403d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1404c58c6610STrond Myklebust 14058f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 14068f4b54c5SJeff Layton } 14078f4b54c5SJeff Layton 14082c41beb0SJeff Layton /* 14092c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 14102c41beb0SJeff Layton * fully unhashed. 14112c41beb0SJeff Layton */ 14122c41beb0SJeff Layton static void 14132c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 14142c41beb0SJeff Layton { 14152c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1416fb94d766SKinglong Mee struct nfs4_file *fp; 14172c41beb0SJeff Layton 14182c41beb0SJeff Layton might_sleep(); 14192c41beb0SJeff Layton 14202c41beb0SJeff Layton while (!list_empty(reaplist)) { 14212c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 14222c41beb0SJeff Layton st_locks); 14232c41beb0SJeff Layton list_del(&stp->st_locks); 1424fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 14252c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1426fb94d766SKinglong Mee if (fp) 1427fb94d766SKinglong Mee put_nfs4_file(fp); 14282c41beb0SJeff Layton } 14292c41beb0SJeff Layton } 14302c41beb0SJeff Layton 1431d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1432d83017f9SJeff Layton struct list_head *reaplist) 14333c87b9b7STrond Myklebust { 14343c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 14353c87b9b7STrond Myklebust 1436e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1437e8568739SJeff Layton 14383c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 14393c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 14403c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1441e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1442d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1443529d7b2aSJ. Bruce Fields } 1444529d7b2aSJ. Bruce Fields } 1445529d7b2aSJ. Bruce Fields 1446e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1447d83017f9SJeff Layton struct list_head *reaplist) 14482283963fSJ. Bruce Fields { 1449e8568739SJeff Layton bool unhashed; 1450e8568739SJeff Layton 14512c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 14522c41beb0SJeff Layton 1453e8568739SJeff Layton unhashed = unhash_ol_stateid(stp); 1454d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1455e8568739SJeff Layton return unhashed; 145638c387b5SJ. Bruce Fields } 145738c387b5SJ. Bruce Fields 145838c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 145938c387b5SJ. Bruce Fields { 14602c41beb0SJeff Layton LIST_HEAD(reaplist); 14612c41beb0SJeff Layton 14622c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1463e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 14642c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 14652c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 14662c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 14672283963fSJ. Bruce Fields } 14682283963fSJ. Bruce Fields 14697ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1470f1d110caSJ. Bruce Fields { 1471d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 14727ffb5880STrond Myklebust 1473d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 14747ffb5880STrond Myklebust 14758f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 14768f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1477f1d110caSJ. Bruce Fields } 1478f1d110caSJ. Bruce Fields 1479f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1480f7a4d872SJ. Bruce Fields { 1481217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1482217526e7SJeff Layton nfsd_net_id); 1483217526e7SJeff Layton struct nfs4_ol_stateid *s; 1484f7a4d872SJ. Bruce Fields 1485217526e7SJeff Layton spin_lock(&nn->client_lock); 1486217526e7SJeff Layton s = oo->oo_last_closed_stid; 1487f7a4d872SJ. Bruce Fields if (s) { 1488d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1489f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1490f7a4d872SJ. Bruce Fields } 1491217526e7SJeff Layton spin_unlock(&nn->client_lock); 1492217526e7SJeff Layton if (s) 1493217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1494f7a4d872SJ. Bruce Fields } 1495f7a4d872SJ. Bruce Fields 14962c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 14978f4b54c5SJeff Layton { 14988f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1499d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 15002c41beb0SJeff Layton struct list_head reaplist; 15017ffb5880STrond Myklebust 15022c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 15037ffb5880STrond Myklebust 1504d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 15057ffb5880STrond Myklebust unhash_openowner_locked(oo); 15062c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 15072c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 15082c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1509e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 15102c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 15112c41beb0SJeff Layton } 1512d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 15132c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1514f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 15156b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1516f1d110caSJ. Bruce Fields } 1517f1d110caSJ. Bruce Fields 15185282fd72SMarc Eshel static inline int 15195282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 15205282fd72SMarc Eshel { 15215282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 15225282fd72SMarc Eshel 15235282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 15245282fd72SMarc Eshel } 15255282fd72SMarc Eshel 1526135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 15275282fd72SMarc Eshel static inline void 15285282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 15295282fd72SMarc Eshel { 15305282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 15315282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 15325282fd72SMarc Eshel } 15338f199b82STrond Myklebust #else 15348f199b82STrond Myklebust static inline void 15358f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 15368f199b82STrond Myklebust { 15378f199b82STrond Myklebust } 15388f199b82STrond Myklebust #endif 15398f199b82STrond Myklebust 15409411b1d4SJ. Bruce Fields /* 15419411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 15429411b1d4SJ. Bruce Fields * won't be used for replay. 15439411b1d4SJ. Bruce Fields */ 15449411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 15459411b1d4SJ. Bruce Fields { 15469411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 15479411b1d4SJ. Bruce Fields 15489411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 15499411b1d4SJ. Bruce Fields return; 15509411b1d4SJ. Bruce Fields 15519411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 155258fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 15539411b1d4SJ. Bruce Fields return; 15549411b1d4SJ. Bruce Fields } 15559411b1d4SJ. Bruce Fields if (!so) 15569411b1d4SJ. Bruce Fields return; 15579411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 15589411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 15599411b1d4SJ. Bruce Fields so->so_seqid++; 15609411b1d4SJ. Bruce Fields return; 15619411b1d4SJ. Bruce Fields } 15625282fd72SMarc Eshel 1563ec6b5d7bSAndy Adamson static void 1564ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1565ec6b5d7bSAndy Adamson { 1566ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1567ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1568ec6b5d7bSAndy Adamson 1569ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1570ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1571ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1572ec6b5d7bSAndy Adamson sid->reserved = 0; 1573ec6b5d7bSAndy Adamson } 1574ec6b5d7bSAndy Adamson 1575ec6b5d7bSAndy Adamson /* 1576a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1577a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1578a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1579a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1580a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1581a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1582a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1583a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1584a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1585a649637cSAndy Adamson * for the SEQUENCE op response: 1586ec6b5d7bSAndy Adamson */ 1587a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1588a649637cSAndy Adamson 1589557ce264SAndy Adamson static void 1590557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1591557ce264SAndy Adamson { 1592557ce264SAndy Adamson int i; 1593557ce264SAndy Adamson 159453da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 159553da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1596557ce264SAndy Adamson kfree(ses->se_slots[i]); 1597557ce264SAndy Adamson } 159853da6a53SJ. Bruce Fields } 1599557ce264SAndy Adamson 1600efe0cb6dSJ. Bruce Fields /* 1601efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1602efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1603efe0cb6dSJ. Bruce Fields */ 160455c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1605efe0cb6dSJ. Bruce Fields { 160655c760cfSJ. Bruce Fields u32 size; 1607efe0cb6dSJ. Bruce Fields 160855c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 160955c760cfSJ. Bruce Fields size = 0; 161055c760cfSJ. Bruce Fields else 161155c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 161255c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1613557ce264SAndy Adamson } 1614557ce264SAndy Adamson 16155b6feee9SJ. Bruce Fields /* 16165b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 16175b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 161842b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 16195b6feee9SJ. Bruce Fields */ 16202030ca56SNeilBrown static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 16215b6feee9SJ. Bruce Fields { 162255c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 162355c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 1624c54f24e3SJ. Bruce Fields unsigned long avail, total_avail; 16252030ca56SNeilBrown unsigned int scale_factor; 16265b6feee9SJ. Bruce Fields 16275b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 16287f49fd5dSNeilBrown if (nfsd_drc_max_mem > nfsd_drc_mem_used) 1629c54f24e3SJ. Bruce Fields total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 16307f49fd5dSNeilBrown else 16317f49fd5dSNeilBrown /* We have handed out more space than we chose in 16327f49fd5dSNeilBrown * set_max_drc() to allow. That isn't really a 16337f49fd5dSNeilBrown * problem as long as that doesn't make us think we 16347f49fd5dSNeilBrown * have lots more due to integer overflow. 16357f49fd5dSNeilBrown */ 16367f49fd5dSNeilBrown total_avail = 0; 1637c54f24e3SJ. Bruce Fields avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1638de766e57SJ. Bruce Fields /* 16392030ca56SNeilBrown * Never use more than a fraction of the remaining memory, 16407f49fd5dSNeilBrown * unless it's the only way to give this client a slot. 16412030ca56SNeilBrown * The chosen fraction is either 1/8 or 1/number of threads, 16422030ca56SNeilBrown * whichever is smaller. This ensures there are adequate 16432030ca56SNeilBrown * slots to support multiple clients per thread. 16447f49fd5dSNeilBrown * Give the client one slot even if that would require 16457f49fd5dSNeilBrown * over-allocation--it is better than failure. 1646de766e57SJ. Bruce Fields */ 16472030ca56SNeilBrown scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); 16482030ca56SNeilBrown 16492030ca56SNeilBrown avail = clamp_t(unsigned long, avail, slotsize, 16502030ca56SNeilBrown total_avail/scale_factor); 16515b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 16527f49fd5dSNeilBrown num = max_t(int, num, 1); 16535b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 16545b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 16555b6feee9SJ. Bruce Fields 16565b6feee9SJ. Bruce Fields return num; 16575b6feee9SJ. Bruce Fields } 16585b6feee9SJ. Bruce Fields 165955c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 16605b6feee9SJ. Bruce Fields { 166155c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 166255c760cfSJ. Bruce Fields 16635b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 166455c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 16655b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 16665b6feee9SJ. Bruce Fields } 16675b6feee9SJ. Bruce Fields 166860810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 166960810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 16705b6feee9SJ. Bruce Fields { 167160810e54SKinglong Mee int numslots = fattrs->maxreqs; 167260810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 16735b6feee9SJ. Bruce Fields struct nfsd4_session *new; 16745b6feee9SJ. Bruce Fields int mem, i; 1675ec6b5d7bSAndy Adamson 1676c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1677ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 16785b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1679ec6b5d7bSAndy Adamson 16805b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 16816c18ba9fSAlexandros Batsakis if (!new) 16825b6feee9SJ. Bruce Fields return NULL; 1683ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 16845b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 168555c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 16865b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1687ec6b5d7bSAndy Adamson goto out_free; 1688ec6b5d7bSAndy Adamson } 168960810e54SKinglong Mee 169060810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 169160810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 169260810e54SKinglong Mee 16935b6feee9SJ. Bruce Fields return new; 16945b6feee9SJ. Bruce Fields out_free: 16955b6feee9SJ. Bruce Fields while (i--) 16965b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 16975b6feee9SJ. Bruce Fields kfree(new); 16985b6feee9SJ. Bruce Fields return NULL; 16995b6feee9SJ. Bruce Fields } 17005b6feee9SJ. Bruce Fields 170119cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 170219cf5c02SJ. Bruce Fields { 170319cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 170419cf5c02SJ. Bruce Fields kfree(c); 170519cf5c02SJ. Bruce Fields } 170619cf5c02SJ. Bruce Fields 170719cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 170819cf5c02SJ. Bruce Fields { 170919cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 171019cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 171119cf5c02SJ. Bruce Fields 171219cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 171319cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 171419cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 171519cf5c02SJ. Bruce Fields free_conn(c); 171619cf5c02SJ. Bruce Fields } 1717eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 17182e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 171919cf5c02SJ. Bruce Fields } 172019cf5c02SJ. Bruce Fields 1721d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1722c7662518SJ. Bruce Fields { 1723c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1724c7662518SJ. Bruce Fields 1725c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1726c7662518SJ. Bruce Fields if (!conn) 1727db90681dSJ. Bruce Fields return NULL; 1728c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1729c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1730d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1731db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1732db90681dSJ. Bruce Fields return conn; 1733db90681dSJ. Bruce Fields } 1734db90681dSJ. Bruce Fields 1735328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1736328ead28SJ. Bruce Fields { 1737328ead28SJ. Bruce Fields conn->cn_session = ses; 1738328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1739328ead28SJ. Bruce Fields } 1740328ead28SJ. Bruce Fields 1741db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1742db90681dSJ. Bruce Fields { 1743db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1744c7662518SJ. Bruce Fields 1745c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1746328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1747c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1748db90681dSJ. Bruce Fields } 1749c7662518SJ. Bruce Fields 175021b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1751db90681dSJ. Bruce Fields { 175219cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 175321b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1754db90681dSJ. Bruce Fields } 1755db90681dSJ. Bruce Fields 1756e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1757db90681dSJ. Bruce Fields { 175821b75b01SJ. Bruce Fields int ret; 1759db90681dSJ. Bruce Fields 1760db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 176121b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 176221b75b01SJ. Bruce Fields if (ret) 176321b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 176421b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 176557a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 176657a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1767c7662518SJ. Bruce Fields } 1768c7662518SJ. Bruce Fields 1769e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 17701d1bc8f2SJ. Bruce Fields { 17711d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 17721d1bc8f2SJ. Bruce Fields 1773e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 17741d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1775e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 17761d1bc8f2SJ. Bruce Fields } 17771d1bc8f2SJ. Bruce Fields 17781d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 177919cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1780c7662518SJ. Bruce Fields { 178119cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 178219cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 178319cf5c02SJ. Bruce Fields 178419cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 178519cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 178619cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 178719cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 178819cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 178919cf5c02SJ. Bruce Fields 179019cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 179119cf5c02SJ. Bruce Fields free_conn(c); 179219cf5c02SJ. Bruce Fields 179319cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 179419cf5c02SJ. Bruce Fields } 179519cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1796c7662518SJ. Bruce Fields } 1797c7662518SJ. Bruce Fields 17981377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 17991377b69eSJ. Bruce Fields { 18001377b69eSJ. Bruce Fields free_session_slots(ses); 18011377b69eSJ. Bruce Fields kfree(ses); 18021377b69eSJ. Bruce Fields } 18031377b69eSJ. Bruce Fields 180466b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1805508dc6e1SBenny Halevy { 1806c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 180755c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1808c7662518SJ. Bruce Fields __free_session(ses); 1809a827bcb2SJ. Bruce Fields } 1810ec6b5d7bSAndy Adamson 1811135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1812a827bcb2SJ. Bruce Fields { 1813a827bcb2SJ. Bruce Fields int idx; 18141872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1815a827bcb2SJ. Bruce Fields 1816ec6b5d7bSAndy Adamson new->se_client = clp; 1817ec6b5d7bSAndy Adamson gen_sessionid(new); 1818ec6b5d7bSAndy Adamson 1819c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1820c7662518SJ. Bruce Fields 1821ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1822ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 18238b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1824c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 182566b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 18265b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 18271872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 18284c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1829ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 18304c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 183160810e54SKinglong Mee 1832b0d2e42cSChuck Lever { 1833edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1834dcbeaa68SJ. Bruce Fields /* 1835dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1836dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1837dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1838dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1839dcbeaa68SJ. Bruce Fields * future: 1840dcbeaa68SJ. Bruce Fields */ 1841edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1842edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1843edd76786SJ. Bruce Fields } 1844ec6b5d7bSAndy Adamson } 1845ec6b5d7bSAndy Adamson 18469089f1b4SBenny Halevy /* caller must hold client_lock */ 18475282fd72SMarc Eshel static struct nfsd4_session * 1848d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 18495282fd72SMarc Eshel { 18505282fd72SMarc Eshel struct nfsd4_session *elem; 18515282fd72SMarc Eshel int idx; 18521872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 18535282fd72SMarc Eshel 18540a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 18550a880a28STrond Myklebust 18565282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 18575282fd72SMarc Eshel idx = hash_sessionid(sessionid); 18585282fd72SMarc Eshel /* Search in the appropriate list */ 18591872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 18605282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 18615282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 18625282fd72SMarc Eshel return elem; 18635282fd72SMarc Eshel } 18645282fd72SMarc Eshel } 18655282fd72SMarc Eshel 18665282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 18675282fd72SMarc Eshel return NULL; 18685282fd72SMarc Eshel } 18695282fd72SMarc Eshel 1870d4e19e70STrond Myklebust static struct nfsd4_session * 1871d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1872d4e19e70STrond Myklebust __be32 *ret) 1873d4e19e70STrond Myklebust { 1874d4e19e70STrond Myklebust struct nfsd4_session *session; 1875d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1876d4e19e70STrond Myklebust 1877d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1878d4e19e70STrond Myklebust if (!session) 1879d4e19e70STrond Myklebust goto out; 1880d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1881d4e19e70STrond Myklebust if (status) 1882d4e19e70STrond Myklebust session = NULL; 1883d4e19e70STrond Myklebust out: 1884d4e19e70STrond Myklebust *ret = status; 1885d4e19e70STrond Myklebust return session; 1886d4e19e70STrond Myklebust } 1887d4e19e70STrond Myklebust 18889089f1b4SBenny Halevy /* caller must hold client_lock */ 18897116ed6bSAndy Adamson static void 18905282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 18917116ed6bSAndy Adamson { 18920a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 18930a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 18940a880a28STrond Myklebust 18950a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 18960a880a28STrond Myklebust 18977116ed6bSAndy Adamson list_del(&ses->se_hash); 18984c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 18997116ed6bSAndy Adamson list_del(&ses->se_perclnt); 19004c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 19015282fd72SMarc Eshel } 19025282fd72SMarc Eshel 19031da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 19041da177e4SLinus Torvalds static int 19052c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 19061da177e4SLinus Torvalds { 1907bbc7f33aSJ. Bruce Fields /* 1908bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 1909bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 1910bbc7f33aSJ. Bruce Fields * a safe assumption: 1911bbc7f33aSJ. Bruce Fields */ 1912bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 19131da177e4SLinus Torvalds return 0; 19149cc76801SArnd Bergmann dprintk("NFSD stale clientid (%08x/%08x) boot_time %08llx\n", 19152c142baaSStanislav Kinsbursky clid->cl_boot, clid->cl_id, nn->boot_time); 19161da177e4SLinus Torvalds return 1; 19171da177e4SLinus Torvalds } 19181da177e4SLinus Torvalds 19191da177e4SLinus Torvalds /* 19201da177e4SLinus Torvalds * XXX Should we use a slab cache ? 19211da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 19221da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 19231da177e4SLinus Torvalds */ 192435bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 19251da177e4SLinus Torvalds { 19261da177e4SLinus Torvalds struct nfs4_client *clp; 1927d4f0489fSTrond Myklebust int i; 19281da177e4SLinus Torvalds 19299258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 193035bba9a3SJ. Bruce Fields if (clp == NULL) 193135bba9a3SJ. Bruce Fields return NULL; 19326f4859b8SJ. Bruce Fields xdr_netobj_dup(&clp->cl_name, &name, GFP_KERNEL); 1933d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1934d4f0489fSTrond Myklebust goto err_no_name; 19356da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 19366da2ec56SKees Cook sizeof(struct list_head), 19376da2ec56SKees Cook GFP_KERNEL); 1938d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1939d4f0489fSTrond Myklebust goto err_no_hashtbl; 1940d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1941d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 19425694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 19435694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 194414ed14ccSJ. Bruce Fields atomic_set(&clp->cl_rpc_users, 0); 19455694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 19465694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 19475694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 19485694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 19495694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 19505694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 19519cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 19529cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 19539cf514ccSChristoph Hellwig #endif 1954e0639dc5SOlga Kornievskaia INIT_LIST_HEAD(&clp->async_copies); 1955e0639dc5SOlga Kornievskaia spin_lock_init(&clp->async_lock); 19565694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 19575694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 19581da177e4SLinus Torvalds return clp; 1959d4f0489fSTrond Myklebust err_no_hashtbl: 1960d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1961d4f0489fSTrond Myklebust err_no_name: 19629258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 1963d4f0489fSTrond Myklebust return NULL; 19641da177e4SLinus Torvalds } 19651da177e4SLinus Torvalds 196659f8e91bSJ. Bruce Fields static void __free_client(struct kref *k) 196759f8e91bSJ. Bruce Fields { 1968e8a79fb1SJ. Bruce Fields struct nfsdfs_client *c = container_of(k, struct nfsdfs_client, cl_ref); 1969e8a79fb1SJ. Bruce Fields struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs); 197059f8e91bSJ. Bruce Fields 197159f8e91bSJ. Bruce Fields free_svc_cred(&clp->cl_cred); 197259f8e91bSJ. Bruce Fields kfree(clp->cl_ownerstr_hashtbl); 197359f8e91bSJ. Bruce Fields kfree(clp->cl_name.data); 197479123444SJ. Bruce Fields kfree(clp->cl_nii_domain.data); 197579123444SJ. Bruce Fields kfree(clp->cl_nii_name.data); 197659f8e91bSJ. Bruce Fields idr_destroy(&clp->cl_stateids); 197759f8e91bSJ. Bruce Fields kmem_cache_free(client_slab, clp); 197859f8e91bSJ. Bruce Fields } 197959f8e91bSJ. Bruce Fields 1980297e57a2SYueHaibing static void drop_client(struct nfs4_client *clp) 198159f8e91bSJ. Bruce Fields { 1982e8a79fb1SJ. Bruce Fields kref_put(&clp->cl_nfsdfs.cl_ref, __free_client); 198359f8e91bSJ. Bruce Fields } 198459f8e91bSJ. Bruce Fields 19854dd86e15STrond Myklebust static void 19861da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 19871da177e4SLinus Torvalds { 1988792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1989792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1990792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1991792c95ddSJ. Bruce Fields se_perclnt); 1992792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 199366b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 199466b2b9b2SJ. Bruce Fields free_session(ses); 1995792c95ddSJ. Bruce Fields } 19964cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 199789c905beSJ. Bruce Fields if (clp->cl_nfsd_dentry) { 1998e8a79fb1SJ. Bruce Fields nfsd_client_rmdir(clp->cl_nfsd_dentry); 199989c905beSJ. Bruce Fields clp->cl_nfsd_dentry = NULL; 200089c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 200189c905beSJ. Bruce Fields } 200259f8e91bSJ. Bruce Fields drop_client(clp); 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds 200584d38ac9SBenny Halevy /* must be called under the client_lock */ 20064beb345bSTrond Myklebust static void 200784d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 200884d38ac9SBenny Halevy { 20094beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2010792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2011792c95ddSJ. Bruce Fields 20120a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20130a880a28STrond Myklebust 20144beb345bSTrond Myklebust /* Mark the client as expired! */ 20154beb345bSTrond Myklebust clp->cl_time = 0; 20164beb345bSTrond Myklebust /* Make it invisible */ 20174beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 20184beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 20194beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 20204beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 20214beb345bSTrond Myklebust else 20224beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 20234beb345bSTrond Myklebust } 20244beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 20254c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 2026792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 2027792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 20284c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 202984d38ac9SBenny Halevy } 203084d38ac9SBenny Halevy 20311da177e4SLinus Torvalds static void 20324beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 20334beb345bSTrond Myklebust { 20344beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20354beb345bSTrond Myklebust 20364beb345bSTrond Myklebust spin_lock(&nn->client_lock); 20374beb345bSTrond Myklebust unhash_client_locked(clp); 20384beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 20394beb345bSTrond Myklebust } 20404beb345bSTrond Myklebust 204197403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 204297403d95SJeff Layton { 204314ed14ccSJ. Bruce Fields if (atomic_read(&clp->cl_rpc_users)) 204497403d95SJeff Layton return nfserr_jukebox; 204597403d95SJeff Layton unhash_client_locked(clp); 204697403d95SJeff Layton return nfs_ok; 204797403d95SJeff Layton } 204897403d95SJeff Layton 20494beb345bSTrond Myklebust static void 20504beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 20511da177e4SLinus Torvalds { 205268ef3bc3SJeff Layton int i; 2053fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 20541da177e4SLinus Torvalds struct nfs4_delegation *dp; 20551da177e4SLinus Torvalds struct list_head reaplist; 20561da177e4SLinus Torvalds 20571da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 2058cdc97505SBenny Halevy spin_lock(&state_lock); 2059ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 2060ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 20613fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 206242690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 20631da177e4SLinus Torvalds } 2064cdc97505SBenny Halevy spin_unlock(&state_lock); 20651da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 20661da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 206742690676SJeff Layton list_del_init(&dp->dl_recall_lru); 20680af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 20691da177e4SLinus Torvalds } 20702d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 2071c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 20722d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 20736011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 2074956c4feeSBenny Halevy } 2075ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 2076fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 2077b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 2078fe0750e5SJ. Bruce Fields release_openowner(oo); 20791da177e4SLinus Torvalds } 208068ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 208168ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 208268ef3bc3SJeff Layton 208368ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 208468ef3bc3SJeff Layton so_strhash) { 208568ef3bc3SJeff Layton /* Should be no openowners at this point */ 208668ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 208768ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 208868ef3bc3SJeff Layton } 208968ef3bc3SJeff Layton } 20909cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 2091e0639dc5SOlga Kornievskaia nfsd4_shutdown_copy(clp); 20926ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 20932bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 20942bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 2095b12a05cbSJ. Bruce Fields free_client(clp); 209689c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 20971da177e4SLinus Torvalds } 20981da177e4SLinus Torvalds 20994beb345bSTrond Myklebust static void 21004beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 21014beb345bSTrond Myklebust { 21024beb345bSTrond Myklebust unhash_client(clp); 21034beb345bSTrond Myklebust __destroy_client(clp); 21044beb345bSTrond Myklebust } 21054beb345bSTrond Myklebust 2106362063a5SScott Mayhew static void inc_reclaim_complete(struct nfs4_client *clp) 2107362063a5SScott Mayhew { 2108362063a5SScott Mayhew struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2109362063a5SScott Mayhew 2110362063a5SScott Mayhew if (!nn->track_reclaim_completes) 2111362063a5SScott Mayhew return; 2112362063a5SScott Mayhew if (!nfsd4_find_reclaim_client(clp->cl_name, nn)) 2113362063a5SScott Mayhew return; 2114362063a5SScott Mayhew if (atomic_inc_return(&nn->nr_reclaim_complete) == 2115362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) { 2116362063a5SScott Mayhew printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n", 2117362063a5SScott Mayhew clp->net->ns.inum); 2118362063a5SScott Mayhew nfsd4_end_grace(nn); 2119362063a5SScott Mayhew } 2120362063a5SScott Mayhew } 2121362063a5SScott Mayhew 21220d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 21230d22f68fSJ. Bruce Fields { 21244beb345bSTrond Myklebust unhash_client(clp); 21250d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 21264beb345bSTrond Myklebust __destroy_client(clp); 21270d22f68fSJ. Bruce Fields } 21280d22f68fSJ. Bruce Fields 212935bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 213035bba9a3SJ. Bruce Fields { 213135bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 213235bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 21331da177e4SLinus Torvalds } 21341da177e4SLinus Torvalds 213535bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 213635bba9a3SJ. Bruce Fields { 21371da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 21381da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 21391da177e4SLinus Torvalds } 21401da177e4SLinus Torvalds 214150043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 214250043859SJ. Bruce Fields { 21432f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 21442f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 21452f10fdcbSNeilBrown GFP_KERNEL); 21469abdda5dSChuck Lever target->cr_targ_princ = kstrdup(source->cr_targ_princ, GFP_KERNEL); 21472f10fdcbSNeilBrown if ((source->cr_principal && !target->cr_principal) || 21489abdda5dSChuck Lever (source->cr_raw_principal && !target->cr_raw_principal) || 21499abdda5dSChuck Lever (source->cr_targ_princ && !target->cr_targ_princ)) 21502f10fdcbSNeilBrown return -ENOMEM; 215150043859SJ. Bruce Fields 2152d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 21531da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 21541da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 21551da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 21561da177e4SLinus Torvalds get_group_info(target->cr_group_info); 21570dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 21580dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 21590dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 216003a4e1f6SJ. Bruce Fields return 0; 21611da177e4SLinus Torvalds } 21621da177e4SLinus Torvalds 2163ef17af2aSRasmus Villemoes static int 2164ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 2165ac55fdc4SJeff Layton { 2166ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2167ef17af2aSRasmus Villemoes return -1; 2168ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2169ef17af2aSRasmus Villemoes return 1; 2170ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2171ac55fdc4SJeff Layton } 2172ac55fdc4SJeff Layton 21731da177e4SLinus Torvalds static int 2174599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2175599e0a22SJ. Bruce Fields { 2176599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 21771da177e4SLinus Torvalds } 21781da177e4SLinus Torvalds 21791da177e4SLinus Torvalds static int 2180599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2181599e0a22SJ. Bruce Fields { 2182599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 21831da177e4SLinus Torvalds } 21841da177e4SLinus Torvalds 21858fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 21868fbba96eSJ. Bruce Fields { 21878fbba96eSJ. Bruce Fields int i; 21888fbba96eSJ. Bruce Fields 21898fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 21908fbba96eSJ. Bruce Fields return false; 21918fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 219281243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 21938fbba96eSJ. Bruce Fields return false; 21948fbba96eSJ. Bruce Fields return true; 21958fbba96eSJ. Bruce Fields } 21968fbba96eSJ. Bruce Fields 219768eb3508SJ. Bruce Fields /* 219868eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 219968eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 220068eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 220168eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 220268eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 220368eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 220468eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 220568eb3508SJ. Bruce Fields */ 220668eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 220768eb3508SJ. Bruce Fields { 220868eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 220968eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 221068eb3508SJ. Bruce Fields } 221168eb3508SJ. Bruce Fields 221268eb3508SJ. Bruce Fields 22135559b50aSVivek Trivedi static bool 2214599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2215599e0a22SJ. Bruce Fields { 221668eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 22176fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 22186fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 22198fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 22208fbba96eSJ. Bruce Fields return false; 22219abdda5dSChuck Lever /* XXX: check that cr_targ_princ fields match ? */ 22228fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 22238fbba96eSJ. Bruce Fields return true; 22248fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 22258fbba96eSJ. Bruce Fields return false; 22265559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 22271da177e4SLinus Torvalds } 22281da177e4SLinus Torvalds 222957266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 223057266a6eSJ. Bruce Fields { 223157266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 223257266a6eSJ. Bruce Fields u32 service; 223357266a6eSJ. Bruce Fields 2234c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2235c4720591SJ. Bruce Fields return false; 223657266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 223757266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 223857266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 223957266a6eSJ. Bruce Fields } 224057266a6eSJ. Bruce Fields 2241dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 224257266a6eSJ. Bruce Fields { 224357266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 224457266a6eSJ. Bruce Fields 224557266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 224657266a6eSJ. Bruce Fields return true; 224757266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 224857266a6eSJ. Bruce Fields return false; 224957266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 225057266a6eSJ. Bruce Fields return false; 2251414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2252414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2253414ca017SJ. Bruce Fields cr->cr_raw_principal); 225457266a6eSJ. Bruce Fields if (!cr->cr_principal) 225557266a6eSJ. Bruce Fields return false; 225657266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 225757266a6eSJ. Bruce Fields } 225857266a6eSJ. Bruce Fields 2259294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2260deda2faaSJ. Bruce Fields { 2261ab4684d1SChuck Lever __be32 verf[2]; 22621da177e4SLinus Torvalds 2263f419992cSJeff Layton /* 2264f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2265f419992cSJeff Layton * __force to keep sparse happy 2266f419992cSJeff Layton */ 22679104ae49SArnd Bergmann verf[0] = (__force __be32)(u32)ktime_get_real_seconds(); 226819311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2269ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 22701da177e4SLinus Torvalds } 22711da177e4SLinus Torvalds 2272294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2273294ac32eSJeff Layton { 22749cc76801SArnd Bergmann clp->cl_clientid.cl_boot = (u32)nn->boot_time; 2275294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2276294ac32eSJeff Layton gen_confirm(clp, nn); 2277294ac32eSJeff Layton } 2278294ac32eSJeff Layton 22794770d722SJeff Layton static struct nfs4_stid * 22804770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 22814581d140SJ. Bruce Fields { 22823abdb607SJ. Bruce Fields struct nfs4_stid *ret; 22833abdb607SJ. Bruce Fields 22843abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 22853abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 22863abdb607SJ. Bruce Fields return NULL; 22873abdb607SJ. Bruce Fields return ret; 22884581d140SJ. Bruce Fields } 22894d71ab87SJ. Bruce Fields 22904770d722SJeff Layton static struct nfs4_stid * 22914770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2292f459e453SJ. Bruce Fields { 2293f459e453SJ. Bruce Fields struct nfs4_stid *s; 2294f459e453SJ. Bruce Fields 22954770d722SJeff Layton spin_lock(&cl->cl_lock); 22964770d722SJeff Layton s = find_stateid_locked(cl, t); 22972d3f9668STrond Myklebust if (s != NULL) { 22982d3f9668STrond Myklebust if (typemask & s->sc_type) 2299a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 23002d3f9668STrond Myklebust else 23014770d722SJeff Layton s = NULL; 23022d3f9668STrond Myklebust } 23034770d722SJeff Layton spin_unlock(&cl->cl_lock); 23044d71ab87SJ. Bruce Fields return s; 23054581d140SJ. Bruce Fields } 23064581d140SJ. Bruce Fields 2307a204f25eSJ. Bruce Fields static struct nfs4_client *get_nfsdfs_clp(struct inode *inode) 2308a204f25eSJ. Bruce Fields { 2309a204f25eSJ. Bruce Fields struct nfsdfs_client *nc; 2310a204f25eSJ. Bruce Fields nc = get_nfsdfs_client(inode); 2311a204f25eSJ. Bruce Fields if (!nc) 2312a204f25eSJ. Bruce Fields return NULL; 2313a204f25eSJ. Bruce Fields return container_of(nc, struct nfs4_client, cl_nfsdfs); 2314a204f25eSJ. Bruce Fields } 2315a204f25eSJ. Bruce Fields 2316169319f1SJ. Bruce Fields static void seq_quote_mem(struct seq_file *m, char *data, int len) 2317169319f1SJ. Bruce Fields { 2318169319f1SJ. Bruce Fields seq_printf(m, "\""); 2319169319f1SJ. Bruce Fields seq_escape_mem_ascii(m, data, len); 2320169319f1SJ. Bruce Fields seq_printf(m, "\""); 2321169319f1SJ. Bruce Fields } 2322169319f1SJ. Bruce Fields 232397ad4031SJ. Bruce Fields static int client_info_show(struct seq_file *m, void *v) 232497ad4031SJ. Bruce Fields { 232597ad4031SJ. Bruce Fields struct inode *inode = m->private; 232697ad4031SJ. Bruce Fields struct nfs4_client *clp; 232797ad4031SJ. Bruce Fields u64 clid; 232897ad4031SJ. Bruce Fields 2329a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2330a204f25eSJ. Bruce Fields if (!clp) 233197ad4031SJ. Bruce Fields return -ENXIO; 233297ad4031SJ. Bruce Fields memcpy(&clid, &clp->cl_clientid, sizeof(clid)); 233397ad4031SJ. Bruce Fields seq_printf(m, "clientid: 0x%llx\n", clid); 2334169319f1SJ. Bruce Fields seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); 2335169319f1SJ. Bruce Fields seq_printf(m, "name: "); 2336169319f1SJ. Bruce Fields seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); 2337169319f1SJ. Bruce Fields seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); 233879123444SJ. Bruce Fields if (clp->cl_nii_domain.data) { 233979123444SJ. Bruce Fields seq_printf(m, "Implementation domain: "); 234079123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_domain.data, 234179123444SJ. Bruce Fields clp->cl_nii_domain.len); 234279123444SJ. Bruce Fields seq_printf(m, "\nImplementation name: "); 234379123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_name.data, clp->cl_nii_name.len); 2344e29f4703SArnd Bergmann seq_printf(m, "\nImplementation time: [%lld, %ld]\n", 234579123444SJ. Bruce Fields clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); 234679123444SJ. Bruce Fields } 234797ad4031SJ. Bruce Fields drop_client(clp); 234897ad4031SJ. Bruce Fields 234997ad4031SJ. Bruce Fields return 0; 235097ad4031SJ. Bruce Fields } 235197ad4031SJ. Bruce Fields 235297ad4031SJ. Bruce Fields static int client_info_open(struct inode *inode, struct file *file) 235397ad4031SJ. Bruce Fields { 235497ad4031SJ. Bruce Fields return single_open(file, client_info_show, inode); 235597ad4031SJ. Bruce Fields } 235697ad4031SJ. Bruce Fields 235797ad4031SJ. Bruce Fields static const struct file_operations client_info_fops = { 235897ad4031SJ. Bruce Fields .open = client_info_open, 235997ad4031SJ. Bruce Fields .read = seq_read, 236097ad4031SJ. Bruce Fields .llseek = seq_lseek, 236197ad4031SJ. Bruce Fields .release = single_release, 236297ad4031SJ. Bruce Fields }; 236397ad4031SJ. Bruce Fields 236478599c42SJ. Bruce Fields static void *states_start(struct seq_file *s, loff_t *pos) 236578599c42SJ. Bruce Fields __acquires(&clp->cl_lock) 236678599c42SJ. Bruce Fields { 236778599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 236878599c42SJ. Bruce Fields unsigned long id = *pos; 236978599c42SJ. Bruce Fields void *ret; 237078599c42SJ. Bruce Fields 237178599c42SJ. Bruce Fields spin_lock(&clp->cl_lock); 237278599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 237378599c42SJ. Bruce Fields *pos = id; 237478599c42SJ. Bruce Fields return ret; 237578599c42SJ. Bruce Fields } 237678599c42SJ. Bruce Fields 237778599c42SJ. Bruce Fields static void *states_next(struct seq_file *s, void *v, loff_t *pos) 237878599c42SJ. Bruce Fields { 237978599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 238078599c42SJ. Bruce Fields unsigned long id = *pos; 238178599c42SJ. Bruce Fields void *ret; 238278599c42SJ. Bruce Fields 238378599c42SJ. Bruce Fields id = *pos; 238478599c42SJ. Bruce Fields id++; 238578599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 238678599c42SJ. Bruce Fields *pos = id; 238778599c42SJ. Bruce Fields return ret; 238878599c42SJ. Bruce Fields } 238978599c42SJ. Bruce Fields 239078599c42SJ. Bruce Fields static void states_stop(struct seq_file *s, void *v) 239178599c42SJ. Bruce Fields __releases(&clp->cl_lock) 239278599c42SJ. Bruce Fields { 239378599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 239478599c42SJ. Bruce Fields 239578599c42SJ. Bruce Fields spin_unlock(&clp->cl_lock); 239678599c42SJ. Bruce Fields } 239778599c42SJ. Bruce Fields 2398fd4f83fdSJeff Layton static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) 239978599c42SJ. Bruce Fields { 2400fd4f83fdSJeff Layton struct inode *inode = f->nf_inode; 240178599c42SJ. Bruce Fields 240278599c42SJ. Bruce Fields seq_printf(s, "superblock: \"%02x:%02x:%ld\"", 240378599c42SJ. Bruce Fields MAJOR(inode->i_sb->s_dev), 240478599c42SJ. Bruce Fields MINOR(inode->i_sb->s_dev), 240578599c42SJ. Bruce Fields inode->i_ino); 240678599c42SJ. Bruce Fields } 240778599c42SJ. Bruce Fields 240878599c42SJ. Bruce Fields static void nfs4_show_owner(struct seq_file *s, struct nfs4_stateowner *oo) 240978599c42SJ. Bruce Fields { 241078599c42SJ. Bruce Fields seq_printf(s, "owner: "); 241178599c42SJ. Bruce Fields seq_quote_mem(s, oo->so_owner.data, oo->so_owner.len); 241278599c42SJ. Bruce Fields } 241378599c42SJ. Bruce Fields 241478599c42SJ. Bruce Fields static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) 241578599c42SJ. Bruce Fields { 241678599c42SJ. Bruce Fields struct nfs4_ol_stateid *ols; 241778599c42SJ. Bruce Fields struct nfs4_file *nf; 2418fd4f83fdSJeff Layton struct nfsd_file *file; 241978599c42SJ. Bruce Fields struct nfs4_stateowner *oo; 242078599c42SJ. Bruce Fields unsigned int access, deny; 242178599c42SJ. Bruce Fields 242278599c42SJ. Bruce Fields if (st->sc_type != NFS4_OPEN_STID && st->sc_type != NFS4_LOCK_STID) 242378599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 242478599c42SJ. Bruce Fields ols = openlockstateid(st); 242578599c42SJ. Bruce Fields oo = ols->st_stateowner; 242678599c42SJ. Bruce Fields nf = st->sc_file; 242778599c42SJ. Bruce Fields file = find_any_file(nf); 242878599c42SJ. Bruce Fields 242978599c42SJ. Bruce Fields seq_printf(s, "- 0x%16phN: { type: open, ", &st->sc_stateid); 243078599c42SJ. Bruce Fields 243178599c42SJ. Bruce Fields access = bmap_to_share_mode(ols->st_access_bmap); 243278599c42SJ. Bruce Fields deny = bmap_to_share_mode(ols->st_deny_bmap); 243378599c42SJ. Bruce Fields 2434c4b77edbSJ. Bruce Fields seq_printf(s, "access: %s%s, ", 243578599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_READ ? "r" : "-", 243678599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 2437c4b77edbSJ. Bruce Fields seq_printf(s, "deny: %s%s, ", 243878599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", 243978599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 244078599c42SJ. Bruce Fields 244178599c42SJ. Bruce Fields nfs4_show_superblock(s, file); 244278599c42SJ. Bruce Fields seq_printf(s, ", "); 244378599c42SJ. Bruce Fields nfs4_show_owner(s, oo); 244478599c42SJ. Bruce Fields seq_printf(s, " }\n"); 2445fd4f83fdSJeff Layton nfsd_file_put(file); 244678599c42SJ. Bruce Fields 244778599c42SJ. Bruce Fields return 0; 244878599c42SJ. Bruce Fields } 244978599c42SJ. Bruce Fields 245016d36e09SJ. Bruce Fields static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) 245116d36e09SJ. Bruce Fields { 245216d36e09SJ. Bruce Fields struct nfs4_ol_stateid *ols; 245316d36e09SJ. Bruce Fields struct nfs4_file *nf; 2454fd4f83fdSJeff Layton struct nfsd_file *file; 245516d36e09SJ. Bruce Fields struct nfs4_stateowner *oo; 245616d36e09SJ. Bruce Fields 245716d36e09SJ. Bruce Fields ols = openlockstateid(st); 245816d36e09SJ. Bruce Fields oo = ols->st_stateowner; 245916d36e09SJ. Bruce Fields nf = st->sc_file; 246016d36e09SJ. Bruce Fields file = find_any_file(nf); 246116d36e09SJ. Bruce Fields 246216d36e09SJ. Bruce Fields seq_printf(s, "- 0x%16phN: { type: lock, ", &st->sc_stateid); 246316d36e09SJ. Bruce Fields 246416d36e09SJ. Bruce Fields /* 246516d36e09SJ. Bruce Fields * Note: a lock stateid isn't really the same thing as a lock, 246616d36e09SJ. Bruce Fields * it's the locking state held by one owner on a file, and there 246716d36e09SJ. Bruce Fields * may be multiple (or no) lock ranges associated with it. 246816d36e09SJ. Bruce Fields * (Same for the matter is true of open stateids.) 246916d36e09SJ. Bruce Fields */ 247016d36e09SJ. Bruce Fields 247116d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 247216d36e09SJ. Bruce Fields /* XXX: open stateid? */ 247316d36e09SJ. Bruce Fields seq_printf(s, ", "); 247416d36e09SJ. Bruce Fields nfs4_show_owner(s, oo); 247516d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2476fd4f83fdSJeff Layton nfsd_file_put(file); 247716d36e09SJ. Bruce Fields 247816d36e09SJ. Bruce Fields return 0; 247916d36e09SJ. Bruce Fields } 248016d36e09SJ. Bruce Fields 248116d36e09SJ. Bruce Fields static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) 248216d36e09SJ. Bruce Fields { 248316d36e09SJ. Bruce Fields struct nfs4_delegation *ds; 248416d36e09SJ. Bruce Fields struct nfs4_file *nf; 2485eb82dd39SJeff Layton struct nfsd_file *file; 248616d36e09SJ. Bruce Fields 248716d36e09SJ. Bruce Fields ds = delegstateid(st); 248816d36e09SJ. Bruce Fields nf = st->sc_file; 248916d36e09SJ. Bruce Fields file = nf->fi_deleg_file; 249016d36e09SJ. Bruce Fields 249116d36e09SJ. Bruce Fields seq_printf(s, "- 0x%16phN: { type: deleg, ", &st->sc_stateid); 249216d36e09SJ. Bruce Fields 249316d36e09SJ. Bruce Fields /* Kinda dead code as long as we only support read delegs: */ 249416d36e09SJ. Bruce Fields seq_printf(s, "access: %s, ", 249516d36e09SJ. Bruce Fields ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); 249616d36e09SJ. Bruce Fields 249716d36e09SJ. Bruce Fields /* XXX: lease time, whether it's being recalled. */ 249816d36e09SJ. Bruce Fields 249916d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 250016d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 250116d36e09SJ. Bruce Fields 250216d36e09SJ. Bruce Fields return 0; 250316d36e09SJ. Bruce Fields } 250416d36e09SJ. Bruce Fields 25050c4b62b0SJ. Bruce Fields static int nfs4_show_layout(struct seq_file *s, struct nfs4_stid *st) 25060c4b62b0SJ. Bruce Fields { 25070c4b62b0SJ. Bruce Fields struct nfs4_layout_stateid *ls; 2508eb82dd39SJeff Layton struct nfsd_file *file; 25090c4b62b0SJ. Bruce Fields 25100c4b62b0SJ. Bruce Fields ls = container_of(st, struct nfs4_layout_stateid, ls_stid); 25110c4b62b0SJ. Bruce Fields file = ls->ls_file; 25120c4b62b0SJ. Bruce Fields 25130c4b62b0SJ. Bruce Fields seq_printf(s, "- 0x%16phN: { type: layout, ", &st->sc_stateid); 25140c4b62b0SJ. Bruce Fields 25150c4b62b0SJ. Bruce Fields /* XXX: What else would be useful? */ 25160c4b62b0SJ. Bruce Fields 25170c4b62b0SJ. Bruce Fields nfs4_show_superblock(s, file); 25180c4b62b0SJ. Bruce Fields seq_printf(s, " }\n"); 25190c4b62b0SJ. Bruce Fields 25200c4b62b0SJ. Bruce Fields return 0; 25210c4b62b0SJ. Bruce Fields } 25220c4b62b0SJ. Bruce Fields 252378599c42SJ. Bruce Fields static int states_show(struct seq_file *s, void *v) 252478599c42SJ. Bruce Fields { 252578599c42SJ. Bruce Fields struct nfs4_stid *st = v; 252678599c42SJ. Bruce Fields 252778599c42SJ. Bruce Fields switch (st->sc_type) { 252878599c42SJ. Bruce Fields case NFS4_OPEN_STID: 252978599c42SJ. Bruce Fields return nfs4_show_open(s, st); 253016d36e09SJ. Bruce Fields case NFS4_LOCK_STID: 253116d36e09SJ. Bruce Fields return nfs4_show_lock(s, st); 253216d36e09SJ. Bruce Fields case NFS4_DELEG_STID: 253316d36e09SJ. Bruce Fields return nfs4_show_deleg(s, st); 25340c4b62b0SJ. Bruce Fields case NFS4_LAYOUT_STID: 25350c4b62b0SJ. Bruce Fields return nfs4_show_layout(s, st); 253678599c42SJ. Bruce Fields default: 253778599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 253878599c42SJ. Bruce Fields } 253916d36e09SJ. Bruce Fields /* XXX: copy stateids? */ 254078599c42SJ. Bruce Fields } 254178599c42SJ. Bruce Fields 254278599c42SJ. Bruce Fields static struct seq_operations states_seq_ops = { 254378599c42SJ. Bruce Fields .start = states_start, 254478599c42SJ. Bruce Fields .next = states_next, 254578599c42SJ. Bruce Fields .stop = states_stop, 254678599c42SJ. Bruce Fields .show = states_show 254778599c42SJ. Bruce Fields }; 254878599c42SJ. Bruce Fields 254978599c42SJ. Bruce Fields static int client_states_open(struct inode *inode, struct file *file) 255078599c42SJ. Bruce Fields { 255178599c42SJ. Bruce Fields struct seq_file *s; 255278599c42SJ. Bruce Fields struct nfs4_client *clp; 255378599c42SJ. Bruce Fields int ret; 255478599c42SJ. Bruce Fields 2555a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2556a204f25eSJ. Bruce Fields if (!clp) 255778599c42SJ. Bruce Fields return -ENXIO; 255878599c42SJ. Bruce Fields 255978599c42SJ. Bruce Fields ret = seq_open(file, &states_seq_ops); 256078599c42SJ. Bruce Fields if (ret) 256178599c42SJ. Bruce Fields return ret; 256278599c42SJ. Bruce Fields s = file->private_data; 256378599c42SJ. Bruce Fields s->private = clp; 256478599c42SJ. Bruce Fields return 0; 256578599c42SJ. Bruce Fields } 256678599c42SJ. Bruce Fields 256778599c42SJ. Bruce Fields static int client_opens_release(struct inode *inode, struct file *file) 256878599c42SJ. Bruce Fields { 256978599c42SJ. Bruce Fields struct seq_file *m = file->private_data; 257078599c42SJ. Bruce Fields struct nfs4_client *clp = m->private; 257178599c42SJ. Bruce Fields 257278599c42SJ. Bruce Fields /* XXX: alternatively, we could get/drop in seq start/stop */ 257378599c42SJ. Bruce Fields drop_client(clp); 257478599c42SJ. Bruce Fields return 0; 257578599c42SJ. Bruce Fields } 257678599c42SJ. Bruce Fields 257778599c42SJ. Bruce Fields static const struct file_operations client_states_fops = { 257878599c42SJ. Bruce Fields .open = client_states_open, 257978599c42SJ. Bruce Fields .read = seq_read, 258078599c42SJ. Bruce Fields .llseek = seq_lseek, 258178599c42SJ. Bruce Fields .release = client_opens_release, 258278599c42SJ. Bruce Fields }; 258378599c42SJ. Bruce Fields 258489c905beSJ. Bruce Fields /* 258589c905beSJ. Bruce Fields * Normally we refuse to destroy clients that are in use, but here the 258689c905beSJ. Bruce Fields * administrator is telling us to just do it. We also want to wait 258789c905beSJ. Bruce Fields * so the caller has a guarantee that the client's locks are gone by 258889c905beSJ. Bruce Fields * the time the write returns: 258989c905beSJ. Bruce Fields */ 2590297e57a2SYueHaibing static void force_expire_client(struct nfs4_client *clp) 259189c905beSJ. Bruce Fields { 259289c905beSJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 259389c905beSJ. Bruce Fields bool already_expired; 259489c905beSJ. Bruce Fields 259589c905beSJ. Bruce Fields spin_lock(&clp->cl_lock); 259689c905beSJ. Bruce Fields clp->cl_time = 0; 259789c905beSJ. Bruce Fields spin_unlock(&clp->cl_lock); 259889c905beSJ. Bruce Fields 259989c905beSJ. Bruce Fields wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0); 260089c905beSJ. Bruce Fields spin_lock(&nn->client_lock); 260189c905beSJ. Bruce Fields already_expired = list_empty(&clp->cl_lru); 260289c905beSJ. Bruce Fields if (!already_expired) 260389c905beSJ. Bruce Fields unhash_client_locked(clp); 260489c905beSJ. Bruce Fields spin_unlock(&nn->client_lock); 260589c905beSJ. Bruce Fields 260689c905beSJ. Bruce Fields if (!already_expired) 260789c905beSJ. Bruce Fields expire_client(clp); 260889c905beSJ. Bruce Fields else 260989c905beSJ. Bruce Fields wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL); 261089c905beSJ. Bruce Fields } 261189c905beSJ. Bruce Fields 261289c905beSJ. Bruce Fields static ssize_t client_ctl_write(struct file *file, const char __user *buf, 261389c905beSJ. Bruce Fields size_t size, loff_t *pos) 261489c905beSJ. Bruce Fields { 261589c905beSJ. Bruce Fields char *data; 261689c905beSJ. Bruce Fields struct nfs4_client *clp; 261789c905beSJ. Bruce Fields 261889c905beSJ. Bruce Fields data = simple_transaction_get(file, buf, size); 261989c905beSJ. Bruce Fields if (IS_ERR(data)) 262089c905beSJ. Bruce Fields return PTR_ERR(data); 262189c905beSJ. Bruce Fields if (size != 7 || 0 != memcmp(data, "expire\n", 7)) 262289c905beSJ. Bruce Fields return -EINVAL; 262389c905beSJ. Bruce Fields clp = get_nfsdfs_clp(file_inode(file)); 262489c905beSJ. Bruce Fields if (!clp) 262589c905beSJ. Bruce Fields return -ENXIO; 262689c905beSJ. Bruce Fields force_expire_client(clp); 262789c905beSJ. Bruce Fields drop_client(clp); 262889c905beSJ. Bruce Fields return 7; 262989c905beSJ. Bruce Fields } 263089c905beSJ. Bruce Fields 263189c905beSJ. Bruce Fields static const struct file_operations client_ctl_fops = { 263289c905beSJ. Bruce Fields .write = client_ctl_write, 263389c905beSJ. Bruce Fields .release = simple_transaction_release, 263489c905beSJ. Bruce Fields }; 263589c905beSJ. Bruce Fields 263697ad4031SJ. Bruce Fields static const struct tree_descr client_files[] = { 263797ad4031SJ. Bruce Fields [0] = {"info", &client_info_fops, S_IRUSR}, 263878599c42SJ. Bruce Fields [1] = {"states", &client_states_fops, S_IRUSR}, 263989c905beSJ. Bruce Fields [2] = {"ctl", &client_ctl_fops, S_IRUSR|S_IWUSR}, 264078599c42SJ. Bruce Fields [3] = {""}, 264197ad4031SJ. Bruce Fields }; 264297ad4031SJ. Bruce Fields 26432216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2644b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2645b09333c4SRicardo Labiaga { 2646b09333c4SRicardo Labiaga struct nfs4_client *clp; 2647b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 264803a4e1f6SJ. Bruce Fields int ret; 2649c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2650e8a79fb1SJ. Bruce Fields struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2651b09333c4SRicardo Labiaga 2652b09333c4SRicardo Labiaga clp = alloc_client(name); 2653b09333c4SRicardo Labiaga if (clp == NULL) 2654b09333c4SRicardo Labiaga return NULL; 2655b09333c4SRicardo Labiaga 265603a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 265703a4e1f6SJ. Bruce Fields if (ret) { 2658b09333c4SRicardo Labiaga free_client(clp); 2659b09333c4SRicardo Labiaga return NULL; 2660b09333c4SRicardo Labiaga } 2661e8a79fb1SJ. Bruce Fields gen_clid(clp, nn); 2662e8a79fb1SJ. Bruce Fields kref_init(&clp->cl_nfsdfs.cl_ref); 26630162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 266420b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 2665b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2666b09333c4SRicardo Labiaga copy_verf(clp, verf); 26673bade247SJ. Bruce Fields memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); 2668edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2669c212cecfSStanislav Kinsbursky clp->net = net; 2670e8a79fb1SJ. Bruce Fields clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs, 267197ad4031SJ. Bruce Fields clp->cl_clientid.cl_id - nn->clientid_base, 267297ad4031SJ. Bruce Fields client_files); 2673e8a79fb1SJ. Bruce Fields if (!clp->cl_nfsd_dentry) { 2674e8a79fb1SJ. Bruce Fields free_client(clp); 2675e8a79fb1SJ. Bruce Fields return NULL; 2676e8a79fb1SJ. Bruce Fields } 2677b09333c4SRicardo Labiaga return clp; 2678b09333c4SRicardo Labiaga } 2679b09333c4SRicardo Labiaga 2680fd39ca9aSNeilBrown static void 2681ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2682ac55fdc4SJeff Layton { 2683ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2684ac55fdc4SJeff Layton struct nfs4_client *clp; 2685ac55fdc4SJeff Layton 2686ac55fdc4SJeff Layton while (*new) { 2687ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2688ac55fdc4SJeff Layton parent = *new; 2689ac55fdc4SJeff Layton 2690ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2691ac55fdc4SJeff Layton new = &((*new)->rb_left); 2692ac55fdc4SJeff Layton else 2693ac55fdc4SJeff Layton new = &((*new)->rb_right); 2694ac55fdc4SJeff Layton } 2695ac55fdc4SJeff Layton 2696ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2697ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2698ac55fdc4SJeff Layton } 2699ac55fdc4SJeff Layton 2700ac55fdc4SJeff Layton static struct nfs4_client * 2701ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2702ac55fdc4SJeff Layton { 2703ef17af2aSRasmus Villemoes int cmp; 2704ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2705ac55fdc4SJeff Layton struct nfs4_client *clp; 2706ac55fdc4SJeff Layton 2707ac55fdc4SJeff Layton while (node) { 2708ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2709ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2710ac55fdc4SJeff Layton if (cmp > 0) 2711ac55fdc4SJeff Layton node = node->rb_left; 2712ac55fdc4SJeff Layton else if (cmp < 0) 2713ac55fdc4SJeff Layton node = node->rb_right; 2714ac55fdc4SJeff Layton else 2715ac55fdc4SJeff Layton return clp; 2716ac55fdc4SJeff Layton } 2717ac55fdc4SJeff Layton return NULL; 2718ac55fdc4SJeff Layton } 2719ac55fdc4SJeff Layton 2720ac55fdc4SJeff Layton static void 2721ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 27221da177e4SLinus Torvalds { 27231da177e4SLinus Torvalds unsigned int idhashval; 27240a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 27251da177e4SLinus Torvalds 27260a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 27270a880a28STrond Myklebust 2728ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2729a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 27301da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 27310a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 27323dbacee6STrond Myklebust renew_client_locked(clp); 27331da177e4SLinus Torvalds } 27341da177e4SLinus Torvalds 2735fd39ca9aSNeilBrown static void 27361da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 27371da177e4SLinus Torvalds { 27381da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 27398daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 27401da177e4SLinus Torvalds 27410a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 27420a880a28STrond Myklebust 27431da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 27448daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2745a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2746382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2747ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 27483dbacee6STrond Myklebust renew_client_locked(clp); 27491da177e4SLinus Torvalds } 27501da177e4SLinus Torvalds 27511da177e4SLinus Torvalds static struct nfs4_client * 2752bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 27531da177e4SLinus Torvalds { 27541da177e4SLinus Torvalds struct nfs4_client *clp; 27551da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 27561da177e4SLinus Torvalds 2757bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2758a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2759d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2760d15c077eSJ. Bruce Fields return NULL; 27613dbacee6STrond Myklebust renew_client_locked(clp); 27621da177e4SLinus Torvalds return clp; 27631da177e4SLinus Torvalds } 2764a50d2ad1SJ. Bruce Fields } 27651da177e4SLinus Torvalds return NULL; 27661da177e4SLinus Torvalds } 27671da177e4SLinus Torvalds 27681da177e4SLinus Torvalds static struct nfs4_client * 2769bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2770bfa85e83SJ. Bruce Fields { 2771bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2772bfa85e83SJ. Bruce Fields 27730a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2774bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2775bfa85e83SJ. Bruce Fields } 2776bfa85e83SJ. Bruce Fields 2777bfa85e83SJ. Bruce Fields static struct nfs4_client * 27780a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 27791da177e4SLinus Torvalds { 2780bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 27811da177e4SLinus Torvalds 27820a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2783bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 27841da177e4SLinus Torvalds } 27851da177e4SLinus Torvalds 27866e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2787a1bcecd2SAndy Adamson { 27886e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2789a1bcecd2SAndy Adamson } 2790a1bcecd2SAndy Adamson 279128ce6054SNeilBrown static struct nfs4_client * 2792382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 279328ce6054SNeilBrown { 27940a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2795382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 279628ce6054SNeilBrown } 279728ce6054SNeilBrown 279828ce6054SNeilBrown static struct nfs4_client * 2799a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 280028ce6054SNeilBrown { 28010a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2802a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 280328ce6054SNeilBrown } 280428ce6054SNeilBrown 2805fd39ca9aSNeilBrown static void 28066f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 28071da177e4SLinus Torvalds { 280807263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 28096f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 28106f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 28117077ecbaSJeff Layton unsigned short expected_family; 28121da177e4SLinus Torvalds 28137077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 28147077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 28157077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 28167077ecbaSJeff Layton expected_family = AF_INET; 28177077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 28187077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 28197077ecbaSJeff Layton expected_family = AF_INET6; 28207077ecbaSJeff Layton else 28211da177e4SLinus Torvalds goto out_err; 28221da177e4SLinus Torvalds 2823c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2824aa9a4ec7SJeff Layton se->se_callback_addr_len, 282507263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 282607263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2827aa9a4ec7SJeff Layton 282807263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 28291da177e4SLinus Torvalds goto out_err; 2830aa9a4ec7SJeff Layton 283107263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 283207263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2833fbf4665fSJeff Layton 283407263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 283507263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2836849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 28371da177e4SLinus Torvalds return; 28381da177e4SLinus Torvalds out_err: 283907263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 284007263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 28414ab495bfSRasmus Villemoes dprintk("NFSD: this client (clientid %08x/%08x) " 28421da177e4SLinus Torvalds "will not receive delegations\n", 28431da177e4SLinus Torvalds clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); 28441da177e4SLinus Torvalds 28451da177e4SLinus Torvalds return; 28461da177e4SLinus Torvalds } 28471da177e4SLinus Torvalds 2848074fe897SAndy Adamson /* 2849067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2850074fe897SAndy Adamson */ 2851b607664eSTrond Myklebust static void 2852074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2853074fe897SAndy Adamson { 2854f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2855557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2856557ce264SAndy Adamson unsigned int base; 2857074fe897SAndy Adamson 2858557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2859074fe897SAndy Adamson 2860085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2861557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2862557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 286353da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 286453da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 2865bf864a31SAndy Adamson 2866085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 2867085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 2868bf864a31SAndy Adamson return; 2869bf864a31SAndy Adamson } 2870085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 2871085def3aSJ. Bruce Fields 2872f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2873f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2874f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2875d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 2876d3f03403SDan Carpenter __func__); 2877557ce264SAndy Adamson return; 2878074fe897SAndy Adamson } 2879074fe897SAndy Adamson 2880074fe897SAndy Adamson /* 2881abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2882abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2883abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2884abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2885abfabf8cSAndy Adamson * 2886074fe897SAndy Adamson */ 2887abfabf8cSAndy Adamson static __be32 2888abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2889abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2890074fe897SAndy Adamson { 2891abfabf8cSAndy Adamson struct nfsd4_op *op; 2892abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2893074fe897SAndy Adamson 2894abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2895abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2896abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2897abfabf8cSAndy Adamson 2898085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 2899085def3aSJ. Bruce Fields return op->status; 2900085def3aSJ. Bruce Fields if (args->opcnt == 1) { 2901085def3aSJ. Bruce Fields /* 2902085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 2903085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 2904085def3aSJ. Bruce Fields * original: 2905085def3aSJ. Bruce Fields */ 2906085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 2907085def3aSJ. Bruce Fields } else { 2908abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2909abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2910abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2911074fe897SAndy Adamson } 2912abfabf8cSAndy Adamson return op->status; 2913074fe897SAndy Adamson } 2914074fe897SAndy Adamson 2915074fe897SAndy Adamson /* 2916557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2917557ce264SAndy Adamson * session values. 2918074fe897SAndy Adamson */ 29193ca2eb98SJ. Bruce Fields static __be32 2920bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2921bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2922074fe897SAndy Adamson { 2923557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2924f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2925f5236013SJ. Bruce Fields __be32 *p; 2926074fe897SAndy Adamson __be32 status; 2927074fe897SAndy Adamson 2928557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2929074fe897SAndy Adamson 2930abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 29310da7b19cSJ. Bruce Fields if (status) 2932abfabf8cSAndy Adamson return status; 2933074fe897SAndy Adamson 2934f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2935f5236013SJ. Bruce Fields if (!p) { 2936f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2937f5236013SJ. Bruce Fields return nfserr_serverfault; 2938f5236013SJ. Bruce Fields } 2939f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2940f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2941074fe897SAndy Adamson 2942557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2943f5236013SJ. Bruce Fields return slot->sl_status; 2944074fe897SAndy Adamson } 2945074fe897SAndy Adamson 29460733d213SAndy Adamson /* 29470733d213SAndy Adamson * Set the exchange_id flags returned by the server. 29480733d213SAndy Adamson */ 29490733d213SAndy Adamson static void 29500733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 29510733d213SAndy Adamson { 29529cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 29539cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 29549cf514ccSChristoph Hellwig #else 29550733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 29569cf514ccSChristoph Hellwig #endif 29570733d213SAndy Adamson 29580733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 29590733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 29600733d213SAndy Adamson 29610733d213SAndy Adamson /* set the wire flags to return to client. */ 29620733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 29630733d213SAndy Adamson } 29640733d213SAndy Adamson 29654eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 29664eaea134SJ. Bruce Fields { 29674eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 29684eaea134SJ. Bruce Fields 29694eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 29704eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 29714eaea134SJ. Bruce Fields return true; 29724eaea134SJ. Bruce Fields } 29734eaea134SJ. Bruce Fields return false; 29744eaea134SJ. Bruce Fields } 29754eaea134SJ. Bruce Fields 2976631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 2977631fc9eaSJ. Bruce Fields { 29784eaea134SJ. Bruce Fields return client_has_openowners(clp) 297947e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 298047e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 298147e970beSKinglong Mee #endif 29826eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 2983e0639dc5SOlga Kornievskaia || !list_empty(&clp->cl_sessions) 2984e0639dc5SOlga Kornievskaia || !list_empty(&clp->async_copies); 2985631fc9eaSJ. Bruce Fields } 2986631fc9eaSJ. Bruce Fields 298779123444SJ. Bruce Fields static __be32 copy_impl_id(struct nfs4_client *clp, 298879123444SJ. Bruce Fields struct nfsd4_exchange_id *exid) 298979123444SJ. Bruce Fields { 299079123444SJ. Bruce Fields if (!exid->nii_domain.data) 299179123444SJ. Bruce Fields return 0; 299279123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_domain, &exid->nii_domain, GFP_KERNEL); 299379123444SJ. Bruce Fields if (!clp->cl_nii_domain.data) 299479123444SJ. Bruce Fields return nfserr_jukebox; 299579123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_name, &exid->nii_name, GFP_KERNEL); 299679123444SJ. Bruce Fields if (!clp->cl_nii_name.data) 299779123444SJ. Bruce Fields return nfserr_jukebox; 2998e29f4703SArnd Bergmann clp->cl_nii_time = exid->nii_time; 299979123444SJ. Bruce Fields return 0; 300079123444SJ. Bruce Fields } 300179123444SJ. Bruce Fields 3002b37ad28bSAl Viro __be32 3003eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3004eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3005069b6ad4SAndy Adamson { 3006eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 30073dbacee6STrond Myklebust struct nfs4_client *conf, *new; 30083dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 300957b7b43bSJ. Bruce Fields __be32 status; 3010363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 30110733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 3012363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 301383e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 3014c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 30150733d213SAndy Adamson 3016363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 30170733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 3018363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 30190733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 3020363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 30210733d213SAndy Adamson 3022a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 30230733d213SAndy Adamson return nfserr_inval; 30240733d213SAndy Adamson 302550c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 302650c7b948SJ. Bruce Fields if (new == NULL) 302750c7b948SJ. Bruce Fields return nfserr_jukebox; 302879123444SJ. Bruce Fields status = copy_impl_id(new, exid); 302979123444SJ. Bruce Fields if (status) 303079123444SJ. Bruce Fields goto out_nolock; 303150c7b948SJ. Bruce Fields 30320733d213SAndy Adamson switch (exid->spa_how) { 303357266a6eSJ. Bruce Fields case SP4_MACH_CRED: 3034ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 3035ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 3036ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 3037ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 3038ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 3039ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 3040ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 3041ed941643SAndrew Elble 3042ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 3043ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 3044ed941643SAndrew Elble 1 << (OP_LOCKU) | 3045ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 3046ed941643SAndrew Elble 3047ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 3048ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 3049ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 305050c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 305150c7b948SJ. Bruce Fields status = nfserr_inval; 305250c7b948SJ. Bruce Fields goto out_nolock; 305350c7b948SJ. Bruce Fields } 3054920dd9bbSJ. Bruce Fields /* 3055920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 3056920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 3057920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 3058920dd9bbSJ. Bruce Fields */ 3059414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 3060414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 3061920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 3062920dd9bbSJ. Bruce Fields goto out_nolock; 3063920dd9bbSJ. Bruce Fields } 306450c7b948SJ. Bruce Fields new->cl_mach_cred = true; 30650733d213SAndy Adamson case SP4_NONE: 30660733d213SAndy Adamson break; 3067063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 3068063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 30690a4c9265SGustavo A. R. Silva /* fall through */ 30700733d213SAndy Adamson case SP4_SSV: 30718edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 30728edf4b02SKinglong Mee goto out_nolock; 30730733d213SAndy Adamson } 30740733d213SAndy Adamson 30752dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 30763dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3077382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 30780733d213SAndy Adamson if (conf) { 307983e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 308083e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 308183e08fd4SJ. Bruce Fields 3082136e658dSJ. Bruce Fields if (update) { 3083136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 30842dbb269dSJ. Bruce Fields status = nfserr_inval; 3085e203d506SJ. Bruce Fields goto out; 3086e203d506SJ. Bruce Fields } 3087dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 308857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 308957266a6eSJ. Bruce Fields goto out; 309057266a6eSJ. Bruce Fields } 30912dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 30920733d213SAndy Adamson status = nfserr_perm; 30930733d213SAndy Adamson goto out; 30940733d213SAndy Adamson } 30952dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 30960733d213SAndy Adamson status = nfserr_not_same; 30970733d213SAndy Adamson goto out; 30980733d213SAndy Adamson } 3099136e658dSJ. Bruce Fields /* case 6 */ 31000733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 31010733d213SAndy Adamson goto out_copy; 31026ddbbbfeSMike Sager } 3103136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 3104631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 3105136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 3106136e658dSJ. Bruce Fields goto out; 3107136e658dSJ. Bruce Fields } 3108b9831b59SJ. Bruce Fields goto out_new; 3109631fc9eaSJ. Bruce Fields } 3110136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 31110f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 3112136e658dSJ. Bruce Fields goto out_copy; 3113136e658dSJ. Bruce Fields } 31142dbb269dSJ. Bruce Fields /* case 5, client reboot */ 31153dbacee6STrond Myklebust conf = NULL; 31160733d213SAndy Adamson goto out_new; 31170733d213SAndy Adamson } 31186ddbbbfeSMike Sager 31192dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 31200733d213SAndy Adamson status = nfserr_noent; 31210733d213SAndy Adamson goto out; 31220733d213SAndy Adamson } 31230733d213SAndy Adamson 3124a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 31252dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 31263dbacee6STrond Myklebust unhash_client_locked(unconf); 31270733d213SAndy Adamson 31282dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 31290733d213SAndy Adamson out_new: 3130fd699b8aSJeff Layton if (conf) { 3131fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3132fd699b8aSJeff Layton if (status) 3133fd699b8aSJeff Layton goto out; 3134fd699b8aSJeff Layton } 31354f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 3136ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 3137ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 31380733d213SAndy Adamson 3139ac55fdc4SJeff Layton add_to_unconfirmed(new); 31403dbacee6STrond Myklebust swap(new, conf); 31410733d213SAndy Adamson out_copy: 31425cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 31435cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 31440733d213SAndy Adamson 31455cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 31465cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 31470733d213SAndy Adamson 31480733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 31495cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 31500733d213SAndy Adamson status = nfs_ok; 31510733d213SAndy Adamson 31520733d213SAndy Adamson out: 31533dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 315450c7b948SJ. Bruce Fields out_nolock: 31555cc40fd7STrond Myklebust if (new) 31563dbacee6STrond Myklebust expire_client(new); 31573dbacee6STrond Myklebust if (unconf) 31583dbacee6STrond Myklebust expire_client(unconf); 31590733d213SAndy Adamson return status; 3160069b6ad4SAndy Adamson } 3161069b6ad4SAndy Adamson 316257b7b43bSJ. Bruce Fields static __be32 316388e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 3164b85d4c01SBenny Halevy { 316588e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 316688e588d5SAndy Adamson slot_seqid); 3167b85d4c01SBenny Halevy 3168b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 316988e588d5SAndy Adamson if (slot_inuse) { 317088e588d5SAndy Adamson if (seqid == slot_seqid) 3171b85d4c01SBenny Halevy return nfserr_jukebox; 3172b85d4c01SBenny Halevy else 3173b85d4c01SBenny Halevy return nfserr_seq_misordered; 3174b85d4c01SBenny Halevy } 3175f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 317688e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 3177b85d4c01SBenny Halevy return nfs_ok; 317888e588d5SAndy Adamson if (seqid == slot_seqid) 3179b85d4c01SBenny Halevy return nfserr_replay_cache; 3180b85d4c01SBenny Halevy return nfserr_seq_misordered; 3181b85d4c01SBenny Halevy } 3182b85d4c01SBenny Halevy 318349557cc7SAndy Adamson /* 318449557cc7SAndy Adamson * Cache the create session result into the create session single DRC 318549557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 318649557cc7SAndy Adamson * Do this for solo or embedded create session operations. 318749557cc7SAndy Adamson */ 318849557cc7SAndy Adamson static void 318949557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 319057b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 319149557cc7SAndy Adamson { 319249557cc7SAndy Adamson slot->sl_status = nfserr; 319349557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 319449557cc7SAndy Adamson } 319549557cc7SAndy Adamson 319649557cc7SAndy Adamson static __be32 319749557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 319849557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 319949557cc7SAndy Adamson { 320049557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 320149557cc7SAndy Adamson return slot->sl_status; 320249557cc7SAndy Adamson } 320349557cc7SAndy Adamson 32041b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 32051b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 32061b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 32071b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 32081b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 32091b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 32101b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 32111b74c25bSMi Jinlong 32121b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 32131b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 32141b74c25bSMi Jinlong 1 + /* status */ \ 32151b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 32161b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 32171b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 32181b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 32191b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 32201b74c25bSMi Jinlong 322155c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 32221b74c25bSMi Jinlong { 322355c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 322455c760cfSJ. Bruce Fields 3225373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 3226373cd409SJ. Bruce Fields return nfserr_toosmall; 3227373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 3228373cd409SJ. Bruce Fields return nfserr_toosmall; 322955c760cfSJ. Bruce Fields ca->headerpadsz = 0; 323055c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 323155c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 323255c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 323355c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 323455c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 323555c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 323655c760cfSJ. Bruce Fields /* 323755c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 323855c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 323955c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 324055c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 324155c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 324255c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 32437f49fd5dSNeilBrown * Note that we always allow at least one slot, because our 32447f49fd5dSNeilBrown * accounting is soft and provides no guarantees either way. 324555c760cfSJ. Bruce Fields */ 32462030ca56SNeilBrown ca->maxreqs = nfsd4_get_drc_mem(ca, nn); 324755c760cfSJ. Bruce Fields 3248373cd409SJ. Bruce Fields return nfs_ok; 32491b74c25bSMi Jinlong } 32501b74c25bSMi Jinlong 32514500632fSChuck Lever /* 32524500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 32534500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 32544500632fSChuck Lever */ 32554500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 32564500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 32574500632fSChuck Lever 32584500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 32594500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 32604500632fSChuck Lever 32618a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 32624500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 32638a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 32644500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 32654500632fSChuck Lever sizeof(__be32)) 32668a891633SKinglong Mee 326706b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 326806b332a5SJ. Bruce Fields { 326906b332a5SJ. Bruce Fields ca->headerpadsz = 0; 327006b332a5SJ. Bruce Fields 32718a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 327206b332a5SJ. Bruce Fields return nfserr_toosmall; 32738a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 327406b332a5SJ. Bruce Fields return nfserr_toosmall; 327506b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 327606b332a5SJ. Bruce Fields if (ca->maxops < 2) 327706b332a5SJ. Bruce Fields return nfserr_toosmall; 327806b332a5SJ. Bruce Fields 327906b332a5SJ. Bruce Fields return nfs_ok; 3280069b6ad4SAndy Adamson } 3281069b6ad4SAndy Adamson 3282b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 3283b78724b7SJ. Bruce Fields { 3284b78724b7SJ. Bruce Fields switch (cbs->flavor) { 3285b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 3286b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 3287b78724b7SJ. Bruce Fields return nfs_ok; 3288b78724b7SJ. Bruce Fields default: 3289b78724b7SJ. Bruce Fields /* 3290b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 3291b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 3292b78724b7SJ. Bruce Fields * GSS. 3293b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 3294b78724b7SJ. Bruce Fields * client might think it can already handle: 3295b78724b7SJ. Bruce Fields */ 3296b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 3297b78724b7SJ. Bruce Fields } 3298b78724b7SJ. Bruce Fields } 3299b78724b7SJ. Bruce Fields 3300069b6ad4SAndy Adamson __be32 3301069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 3302eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 3303069b6ad4SAndy Adamson { 3304eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 3305363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 3306ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 3307d20c11d8SJeff Layton struct nfs4_client *old = NULL; 3308ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 330981f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 331049557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 331157b7b43bSJ. Bruce Fields __be32 status = 0; 33128daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3313ec6b5d7bSAndy Adamson 3314a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 3315a62573dcSMi Jinlong return nfserr_inval; 3316b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 3317b78724b7SJ. Bruce Fields if (status) 3318b78724b7SJ. Bruce Fields return status; 331955c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 3320373cd409SJ. Bruce Fields if (status) 3321373cd409SJ. Bruce Fields return status; 332206b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 332306b332a5SJ. Bruce Fields if (status) 3324f403e450SKinglong Mee goto out_release_drc_mem; 332581f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 332660810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 332755c760cfSJ. Bruce Fields if (!new) 332855c760cfSJ. Bruce Fields goto out_release_drc_mem; 332981f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 333081f0b2a4SJ. Bruce Fields if (!conn) 333181f0b2a4SJ. Bruce Fields goto out_free_session; 3332a62573dcSMi Jinlong 3333d20c11d8SJeff Layton spin_lock(&nn->client_lock); 33340a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 33358daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 333678389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3337ec6b5d7bSAndy Adamson 3338ec6b5d7bSAndy Adamson if (conf) { 333957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3340dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 334157266a6eSJ. Bruce Fields goto out_free_conn; 334249557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 334349557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 3344f5e22bb6SKinglong Mee if (status) { 3345f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 334649557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 334781f0b2a4SJ. Bruce Fields goto out_free_conn; 3348ec6b5d7bSAndy Adamson } 3349ec6b5d7bSAndy Adamson } else if (unconf) { 3350ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 3351363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 3352ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 335381f0b2a4SJ. Bruce Fields goto out_free_conn; 3354ec6b5d7bSAndy Adamson } 335557266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3356dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 335757266a6eSJ. Bruce Fields goto out_free_conn; 335849557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 335949557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 336038eb76a5SAndy Adamson if (status) { 336138eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 3362ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 336381f0b2a4SJ. Bruce Fields goto out_free_conn; 3364ec6b5d7bSAndy Adamson } 3365382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3366221a6876SJ. Bruce Fields if (old) { 3367d20c11d8SJeff Layton status = mark_client_expired_locked(old); 33687abea1e8SJeff Layton if (status) { 33697abea1e8SJeff Layton old = NULL; 3370221a6876SJ. Bruce Fields goto out_free_conn; 3371221a6876SJ. Bruce Fields } 33727abea1e8SJeff Layton } 33738f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 3374ec6b5d7bSAndy Adamson conf = unconf; 3375ec6b5d7bSAndy Adamson } else { 3376ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 337781f0b2a4SJ. Bruce Fields goto out_free_conn; 3378ec6b5d7bSAndy Adamson } 337981f0b2a4SJ. Bruce Fields status = nfs_ok; 33804ce85c8cSChuck Lever /* Persistent sessions are not supported */ 3381408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 33824ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 3383408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 3384408b79bcSJ. Bruce Fields 338581f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 3386d20c11d8SJeff Layton nfsd4_get_session_locked(new); 338781f0b2a4SJ. Bruce Fields 3388ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 3389ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 339086c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 339149557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 3392ec6b5d7bSAndy Adamson 3393d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 339449557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 3395d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3396d20c11d8SJeff Layton /* init connection and backchannel */ 3397d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 3398d20c11d8SJeff Layton nfsd4_put_session(new); 3399d20c11d8SJeff Layton if (old) 3400d20c11d8SJeff Layton expire_client(old); 3401ec6b5d7bSAndy Adamson return status; 340281f0b2a4SJ. Bruce Fields out_free_conn: 3403d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 340481f0b2a4SJ. Bruce Fields free_conn(conn); 3405d20c11d8SJeff Layton if (old) 3406d20c11d8SJeff Layton expire_client(old); 340781f0b2a4SJ. Bruce Fields out_free_session: 340881f0b2a4SJ. Bruce Fields __free_session(new); 340955c760cfSJ. Bruce Fields out_release_drc_mem: 341055c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 34111ca50792SJ. Bruce Fields return status; 3412069b6ad4SAndy Adamson } 3413069b6ad4SAndy Adamson 34141d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 34151d1bc8f2SJ. Bruce Fields { 34161d1bc8f2SJ. Bruce Fields switch (*dir) { 34171d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 34181d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 34191d1bc8f2SJ. Bruce Fields return nfs_ok; 34201d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 34211d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 34221d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 34231d1bc8f2SJ. Bruce Fields return nfs_ok; 3424fc5fc5d7Szhengbin } 34251d1bc8f2SJ. Bruce Fields return nfserr_inval; 34261d1bc8f2SJ. Bruce Fields } 34271d1bc8f2SJ. Bruce Fields 3428eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 3429eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3430eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3431cb73a9f4SJ. Bruce Fields { 3432eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 3433cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 3434c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3435b78724b7SJ. Bruce Fields __be32 status; 3436cb73a9f4SJ. Bruce Fields 3437b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 3438b78724b7SJ. Bruce Fields if (status) 3439b78724b7SJ. Bruce Fields return status; 3440c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3441cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 3442cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 3443c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3444cb73a9f4SJ. Bruce Fields 3445cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 3446cb73a9f4SJ. Bruce Fields 3447cb73a9f4SJ. Bruce Fields return nfs_ok; 3448cb73a9f4SJ. Bruce Fields } 3449cb73a9f4SJ. Bruce Fields 34501d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 34511d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 3452eb69853dSChristoph Hellwig union nfsd4_op_u *u) 34531d1bc8f2SJ. Bruce Fields { 3454eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 34551d1bc8f2SJ. Bruce Fields __be32 status; 34563ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 34574f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 3458d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3459d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 34601d1bc8f2SJ. Bruce Fields 34611d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 34621d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 3463c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3464d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 3465c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 34664f6e6c17SJ. Bruce Fields if (!session) 3467d4e19e70STrond Myklebust goto out_no_session; 346857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3469dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 347057266a6eSJ. Bruce Fields goto out; 34711d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 34723ba63671SJ. Bruce Fields if (status) 34734f6e6c17SJ. Bruce Fields goto out; 34743ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 34754f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 34763ba63671SJ. Bruce Fields if (!conn) 34774f6e6c17SJ. Bruce Fields goto out; 34784f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 34794f6e6c17SJ. Bruce Fields status = nfs_ok; 34804f6e6c17SJ. Bruce Fields out: 3481d4e19e70STrond Myklebust nfsd4_put_session(session); 3482d4e19e70STrond Myklebust out_no_session: 34834f6e6c17SJ. Bruce Fields return status; 34841d1bc8f2SJ. Bruce Fields } 34851d1bc8f2SJ. Bruce Fields 3486665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 34875d4cec2fSJ. Bruce Fields { 3488665d5072SJ. Bruce Fields if (!cstate->session) 348951d87bc2SFengguang Wu return false; 3490665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 34915d4cec2fSJ. Bruce Fields } 34925d4cec2fSJ. Bruce Fields 3493069b6ad4SAndy Adamson __be32 3494eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 3495eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3496069b6ad4SAndy Adamson { 3497ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 3498e10e0cfcSBenny Halevy struct nfsd4_session *ses; 3499abcdff09SJ. Bruce Fields __be32 status; 3500f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 3501d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 3502d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3503e10e0cfcSBenny Halevy 3504abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 3505ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 350657716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 3507abcdff09SJ. Bruce Fields goto out; 3508f0f51f5cSJ. Bruce Fields ref_held_by_me++; 350957716355SJ. Bruce Fields } 3510ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 3511c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3512ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 3513abcdff09SJ. Bruce Fields if (!ses) 3514abcdff09SJ. Bruce Fields goto out_client_lock; 351557266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3516dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 3517d4e19e70STrond Myklebust goto out_put_session; 3518f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 351966b2b9b2SJ. Bruce Fields if (status) 3520f0f51f5cSJ. Bruce Fields goto out_put_session; 3521e10e0cfcSBenny Halevy unhash_session(ses); 3522c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3523e10e0cfcSBenny Halevy 352484f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 352519cf5c02SJ. Bruce Fields 3526c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3527e10e0cfcSBenny Halevy status = nfs_ok; 3528f0f51f5cSJ. Bruce Fields out_put_session: 3529d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3530abcdff09SJ. Bruce Fields out_client_lock: 3531abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3532e10e0cfcSBenny Halevy out: 3533e10e0cfcSBenny Halevy return status; 3534069b6ad4SAndy Adamson } 3535069b6ad4SAndy Adamson 3536a663bdd8SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3537328ead28SJ. Bruce Fields { 3538328ead28SJ. Bruce Fields struct nfsd4_conn *c; 3539328ead28SJ. Bruce Fields 3540328ead28SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3541a663bdd8SJ. Bruce Fields if (c->cn_xprt == xpt) { 3542328ead28SJ. Bruce Fields return c; 3543328ead28SJ. Bruce Fields } 3544328ead28SJ. Bruce Fields } 3545328ead28SJ. Bruce Fields return NULL; 3546328ead28SJ. Bruce Fields } 3547328ead28SJ. Bruce Fields 354857266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3549328ead28SJ. Bruce Fields { 3550328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3551a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 355257266a6eSJ. Bruce Fields __be32 status = nfs_ok; 355321b75b01SJ. Bruce Fields int ret; 3554328ead28SJ. Bruce Fields 3555328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3556a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 355757266a6eSJ. Bruce Fields if (c) 355857266a6eSJ. Bruce Fields goto out_free; 355957266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 356057266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 356157266a6eSJ. Bruce Fields goto out_free; 3562328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3563328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 356421b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 356521b75b01SJ. Bruce Fields if (ret) 356621b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 356721b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 356857266a6eSJ. Bruce Fields return nfs_ok; 356957266a6eSJ. Bruce Fields out_free: 357057266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 357157266a6eSJ. Bruce Fields free_conn(new); 357257266a6eSJ. Bruce Fields return status; 3573328ead28SJ. Bruce Fields } 3574328ead28SJ. Bruce Fields 3575868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3576868b89c3SMi Jinlong { 3577868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3578868b89c3SMi Jinlong 3579868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3580868b89c3SMi Jinlong } 3581868b89c3SMi Jinlong 3582ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3583ae82a8d0SMi Jinlong struct nfsd4_session *session) 3584ae82a8d0SMi Jinlong { 3585ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3586ae82a8d0SMi Jinlong 3587ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3588ae82a8d0SMi Jinlong } 3589ae82a8d0SMi Jinlong 359053da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 359153da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 359253da6a53SJ. Bruce Fields { 359353da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 359453da6a53SJ. Bruce Fields 359553da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 359653da6a53SJ. Bruce Fields (bool)seq->cachethis) 359753da6a53SJ. Bruce Fields return false; 359853da6a53SJ. Bruce Fields /* 35996e73e92bSScott Mayhew * If there's an error then the reply can have fewer ops than 36006e73e92bSScott Mayhew * the call. 360153da6a53SJ. Bruce Fields */ 36026e73e92bSScott Mayhew if (slot->sl_opcnt < argp->opcnt && !slot->sl_status) 36036e73e92bSScott Mayhew return false; 36046e73e92bSScott Mayhew /* 36056e73e92bSScott Mayhew * But if we cached a reply with *more* ops than the call you're 36066e73e92bSScott Mayhew * sending us now, then this new call is clearly not really a 36076e73e92bSScott Mayhew * replay of the old one: 36086e73e92bSScott Mayhew */ 36096e73e92bSScott Mayhew if (slot->sl_opcnt > argp->opcnt) 361053da6a53SJ. Bruce Fields return false; 361153da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 361253da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 361353da6a53SJ. Bruce Fields return false; 361453da6a53SJ. Bruce Fields /* 361553da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 361653da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 361753da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 361853da6a53SJ. Bruce Fields * the reply), so we don't bother. 361953da6a53SJ. Bruce Fields */ 362053da6a53SJ. Bruce Fields return true; 362153da6a53SJ. Bruce Fields } 362253da6a53SJ. Bruce Fields 3623069b6ad4SAndy Adamson __be32 3624eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3625eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3626069b6ad4SAndy Adamson { 3627eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3628f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 362947ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3630b85d4c01SBenny Halevy struct nfsd4_session *session; 3631221a6876SJ. Bruce Fields struct nfs4_client *clp; 3632b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3633a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 363457b7b43bSJ. Bruce Fields __be32 status; 363547ee5298SJ. Bruce Fields int buflen; 3636d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3637d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3638b85d4c01SBenny Halevy 3639f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3640f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3641f9bb94c4SAndy Adamson 3642a663bdd8SJ. Bruce Fields /* 3643a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3644a663bdd8SJ. Bruce Fields * below. 3645a663bdd8SJ. Bruce Fields */ 3646a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3647a663bdd8SJ. Bruce Fields if (!conn) 3648a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3649a663bdd8SJ. Bruce Fields 3650c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3651d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3652b85d4c01SBenny Halevy if (!session) 3653221a6876SJ. Bruce Fields goto out_no_session; 3654221a6876SJ. Bruce Fields clp = session->se_client; 3655b85d4c01SBenny Halevy 3656868b89c3SMi Jinlong status = nfserr_too_many_ops; 3657868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 365866b2b9b2SJ. Bruce Fields goto out_put_session; 3659868b89c3SMi Jinlong 3660ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3661ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 366266b2b9b2SJ. Bruce Fields goto out_put_session; 3663ae82a8d0SMi Jinlong 3664b85d4c01SBenny Halevy status = nfserr_badslot; 36656c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 366666b2b9b2SJ. Bruce Fields goto out_put_session; 3667b85d4c01SBenny Halevy 3668557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3669b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3670b85d4c01SBenny Halevy 3671a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3672a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3673a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3674a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 3675a8dfdaebSAndy Adamson 367673e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 367773e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 3678b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 3679bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 3680bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 368166b2b9b2SJ. Bruce Fields goto out_put_session; 368253da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 368353da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 368453da6a53SJ. Bruce Fields goto out_put_session; 3685b85d4c01SBenny Halevy cstate->slot = slot; 3686b85d4c01SBenny Halevy cstate->session = session; 36874b24ca7dSJeff Layton cstate->clp = clp; 3688da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 3689557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 3690bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 3691da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 3692aaf84eb9SBenny Halevy goto out; 3693b85d4c01SBenny Halevy } 3694b85d4c01SBenny Halevy if (status) 369566b2b9b2SJ. Bruce Fields goto out_put_session; 3696b85d4c01SBenny Halevy 369757266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 3698a663bdd8SJ. Bruce Fields conn = NULL; 369957266a6eSJ. Bruce Fields if (status) 370057266a6eSJ. Bruce Fields goto out_put_session; 3701328ead28SJ. Bruce Fields 370247ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 370347ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 370447ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 370547ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 370647ee5298SJ. Bruce Fields nfserr_rep_too_big; 3707a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 370847ee5298SJ. Bruce Fields goto out_put_session; 370932aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 371047ee5298SJ. Bruce Fields 371147ee5298SJ. Bruce Fields status = nfs_ok; 3712b85d4c01SBenny Halevy /* Success! bump slot seqid */ 3713b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 3714bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 371573e79482SJ. Bruce Fields if (seq->cachethis) 371673e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 3717bf5c43c8SJ. Bruce Fields else 3718bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 3719b85d4c01SBenny Halevy 3720b85d4c01SBenny Halevy cstate->slot = slot; 3721b85d4c01SBenny Halevy cstate->session = session; 37224b24ca7dSJeff Layton cstate->clp = clp; 3723b85d4c01SBenny Halevy 3724b85d4c01SBenny Halevy out: 37255423732aSBenny Halevy switch (clp->cl_cb_state) { 37265423732aSBenny Halevy case NFSD4_CB_DOWN: 3727fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 37285423732aSBenny Halevy break; 37295423732aSBenny Halevy case NFSD4_CB_FAULT: 3730fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 37315423732aSBenny Halevy break; 3732fc0c3dd1SBenny Halevy default: 3733fc0c3dd1SBenny Halevy seq->status_flags = 0; 37345423732aSBenny Halevy } 37353bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 37363bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 3737221a6876SJ. Bruce Fields out_no_session: 37383f42d2c4SKinglong Mee if (conn) 37393f42d2c4SKinglong Mee free_conn(conn); 3740c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3741b85d4c01SBenny Halevy return status; 374266b2b9b2SJ. Bruce Fields out_put_session: 3743d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 3744221a6876SJ. Bruce Fields goto out_no_session; 3745069b6ad4SAndy Adamson } 3746069b6ad4SAndy Adamson 3747b607664eSTrond Myklebust void 3748b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 3749b607664eSTrond Myklebust { 3750b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 3751b607664eSTrond Myklebust 3752b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 3753b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 3754b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 3755b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3756b607664eSTrond Myklebust } 3757d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 3758b607664eSTrond Myklebust nfsd4_put_session(cs->session); 37594b24ca7dSJeff Layton } else if (cs->clp) 37604b24ca7dSJeff Layton put_client_renew(cs->clp); 3761b607664eSTrond Myklebust } 3762b607664eSTrond Myklebust 3763345c2842SMi Jinlong __be32 3764eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 3765eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3766eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3767345c2842SMi Jinlong { 3768eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 37696b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 37706b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 377157b7b43bSJ. Bruce Fields __be32 status = 0; 37728daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3773345c2842SMi Jinlong 37746b10ad19STrond Myklebust spin_lock(&nn->client_lock); 37750a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 37768daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 377778389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3778345c2842SMi Jinlong 3779345c2842SMi Jinlong if (conf) { 3780c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 3781345c2842SMi Jinlong status = nfserr_clientid_busy; 3782345c2842SMi Jinlong goto out; 3783345c2842SMi Jinlong } 3784fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3785fd699b8aSJeff Layton if (status) 3786fd699b8aSJeff Layton goto out; 37876b10ad19STrond Myklebust clp = conf; 3788345c2842SMi Jinlong } else if (unconf) 3789345c2842SMi Jinlong clp = unconf; 3790345c2842SMi Jinlong else { 3791345c2842SMi Jinlong status = nfserr_stale_clientid; 3792345c2842SMi Jinlong goto out; 3793345c2842SMi Jinlong } 3794dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 37956b10ad19STrond Myklebust clp = NULL; 379657266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 379757266a6eSJ. Bruce Fields goto out; 379857266a6eSJ. Bruce Fields } 37996b10ad19STrond Myklebust unhash_client_locked(clp); 3800345c2842SMi Jinlong out: 38016b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 38026b10ad19STrond Myklebust if (clp) 38036b10ad19STrond Myklebust expire_client(clp); 3804345c2842SMi Jinlong return status; 3805345c2842SMi Jinlong } 3806345c2842SMi Jinlong 3807069b6ad4SAndy Adamson __be32 3808eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 3809eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 38104dc6ec00SJ. Bruce Fields { 3811eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 381257b7b43bSJ. Bruce Fields __be32 status = 0; 3813bcecf1ccSMi Jinlong 38144dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 38154dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 38164dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 38174dc6ec00SJ. Bruce Fields /* 38184dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 38194dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 38204dc6ec00SJ. Bruce Fields */ 38214dc6ec00SJ. Bruce Fields return nfs_ok; 38224dc6ec00SJ. Bruce Fields } 3823bcecf1ccSMi Jinlong 3824bcecf1ccSMi Jinlong status = nfserr_complete_already; 3825a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 3826a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 3827bcecf1ccSMi Jinlong goto out; 3828bcecf1ccSMi Jinlong 3829bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 3830bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 38314dc6ec00SJ. Bruce Fields /* 38324dc6ec00SJ. Bruce Fields * The following error isn't really legal. 38334dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 38344dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 38354dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 38364dc6ec00SJ. Bruce Fields * client. 38374dc6ec00SJ. Bruce Fields */ 3838bcecf1ccSMi Jinlong goto out; 3839bcecf1ccSMi Jinlong 3840bcecf1ccSMi Jinlong status = nfs_ok; 38412a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 3842362063a5SScott Mayhew inc_reclaim_complete(cstate->session->se_client); 3843bcecf1ccSMi Jinlong out: 3844bcecf1ccSMi Jinlong return status; 38454dc6ec00SJ. Bruce Fields } 38464dc6ec00SJ. Bruce Fields 38474dc6ec00SJ. Bruce Fields __be32 3848b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3849eb69853dSChristoph Hellwig union nfsd4_op_u *u) 38501da177e4SLinus Torvalds { 3851eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 3852a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 38531da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 38543dbacee6STrond Myklebust struct nfs4_client *conf, *new; 38553dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 3856b37ad28bSAl Viro __be32 status; 3857c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3858a55370a3SNeilBrown 38595cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 38605cc40fd7STrond Myklebust if (new == NULL) 38615cc40fd7STrond Myklebust return nfserr_jukebox; 386263db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 38633dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3864382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 38652b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 386663db4632SJ. Bruce Fields /* case 0: */ 38671da177e4SLinus Torvalds status = nfserr_clid_inuse; 3868e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 3869e203d506SJ. Bruce Fields goto out; 3870026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 3871363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 3872363168b4SJeff Layton rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, 3873363168b4SJeff Layton sizeof(addr_str)); 3874026722c2SJ. Bruce Fields dprintk("NFSD: setclientid: string in use by client " 3875363168b4SJeff Layton "at %s\n", addr_str); 38761da177e4SLinus Torvalds goto out; 38771da177e4SLinus Torvalds } 38781da177e4SLinus Torvalds } 3879a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 38801da177e4SLinus Torvalds if (unconf) 38813dbacee6STrond Myklebust unhash_client_locked(unconf); 388241eb1670SKinglong Mee if (conf && same_verf(&conf->cl_verifier, &clverifier)) { 388363db4632SJ. Bruce Fields /* case 1: probable callback update */ 38841da177e4SLinus Torvalds copy_clid(new, conf); 388541eb1670SKinglong Mee gen_confirm(new, nn); 388641eb1670SKinglong Mee } else /* case 4 (new client) or cases 2, 3 (client reboot): */ 3887e8a79fb1SJ. Bruce Fields ; 38888323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 38896f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 3890ac55fdc4SJeff Layton add_to_unconfirmed(new); 38911da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 38921da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 38931da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 38945cc40fd7STrond Myklebust new = NULL; 38951da177e4SLinus Torvalds status = nfs_ok; 38961da177e4SLinus Torvalds out: 38973dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 38985cc40fd7STrond Myklebust if (new) 38995cc40fd7STrond Myklebust free_client(new); 39003dbacee6STrond Myklebust if (unconf) 39013dbacee6STrond Myklebust expire_client(unconf); 39021da177e4SLinus Torvalds return status; 39031da177e4SLinus Torvalds } 39041da177e4SLinus Torvalds 39051da177e4SLinus Torvalds 3906b37ad28bSAl Viro __be32 3907b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 3908b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 3909eb69853dSChristoph Hellwig union nfsd4_op_u *u) 39101da177e4SLinus Torvalds { 3911eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 3912eb69853dSChristoph Hellwig &u->setclientid_confirm; 391321ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 3914d20c11d8SJeff Layton struct nfs4_client *old = NULL; 39151da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 39161da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 3917b37ad28bSAl Viro __be32 status; 39187f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 39191da177e4SLinus Torvalds 39202c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 39211da177e4SLinus Torvalds return nfserr_stale_clientid; 392221ab45a4SNeilBrown 3923d20c11d8SJeff Layton spin_lock(&nn->client_lock); 39248daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 39250a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 3926a186e767SJ. Bruce Fields /* 39278695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 39288695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 3929f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 3930f984a7ceSJ. Bruce Fields * 3931f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 3932a186e767SJ. Bruce Fields */ 3933f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 39348695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 39358695b90aSJ. Bruce Fields goto out; 39368695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 39378695b90aSJ. Bruce Fields goto out; 393863db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 393990d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 39407d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 39417d22fc11SJ. Bruce Fields /* case 2: probable retransmit */ 394290d700b7SJ. Bruce Fields status = nfs_ok; 39437d22fc11SJ. Bruce Fields } else /* case 4: client hasn't noticed we rebooted yet? */ 394490d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 394590d700b7SJ. Bruce Fields goto out; 394690d700b7SJ. Bruce Fields } 394790d700b7SJ. Bruce Fields status = nfs_ok; 394890d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 3949d20c11d8SJeff Layton old = unconf; 3950d20c11d8SJeff Layton unhash_client_locked(old); 39515a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 395290d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 3953d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3954d20c11d8SJeff Layton if (old) { 39552b634821SJ. Bruce Fields status = nfserr_clid_inuse; 39562b634821SJ. Bruce Fields if (client_has_state(old) 39572b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 39582b634821SJ. Bruce Fields &old->cl_cred)) 39592b634821SJ. Bruce Fields goto out; 3960d20c11d8SJeff Layton status = mark_client_expired_locked(old); 39617abea1e8SJeff Layton if (status) { 39627abea1e8SJeff Layton old = NULL; 3963221a6876SJ. Bruce Fields goto out; 3964221a6876SJ. Bruce Fields } 39657abea1e8SJeff Layton } 39661da177e4SLinus Torvalds move_to_confirmed(unconf); 3967d20c11d8SJeff Layton conf = unconf; 396808e8987cSNeilBrown } 3969d20c11d8SJeff Layton get_client_locked(conf); 3970d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3971d20c11d8SJeff Layton nfsd4_probe_callback(conf); 3972d20c11d8SJeff Layton spin_lock(&nn->client_lock); 3973d20c11d8SJeff Layton put_client_renew_locked(conf); 39741da177e4SLinus Torvalds out: 3975d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3976d20c11d8SJeff Layton if (old) 3977d20c11d8SJeff Layton expire_client(old); 39781da177e4SLinus Torvalds return status; 39791da177e4SLinus Torvalds } 39801da177e4SLinus Torvalds 398132513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 39821da177e4SLinus Torvalds { 398332513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 398432513b40SJ. Bruce Fields } 398532513b40SJ. Bruce Fields 398632513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 39875b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, 39885b095e99SJeff Layton struct nfs4_file *fp) 398932513b40SJ. Bruce Fields { 3990950e0118STrond Myklebust lockdep_assert_held(&state_lock); 3991950e0118STrond Myklebust 3992818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 39931d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 39948beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 39958beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 39968287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 3997e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 39980c637be8SJeff Layton fp->fi_deleg_file = NULL; 399947f9940cSMeelap Shah fp->fi_had_conflict = false; 4000baeb4ff0SJeff Layton fp->fi_share_deny = 0; 4001f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 4002f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 40039cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 40049cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 4005c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 40069cf514ccSChristoph Hellwig #endif 40075b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 40081da177e4SLinus Torvalds } 40091da177e4SLinus Torvalds 4010e8ff2a84SJ. Bruce Fields void 4011e60d4398SNeilBrown nfsd4_free_slabs(void) 4012e60d4398SNeilBrown { 40139258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4014abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 4015abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4016abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4017abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4018abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 40199258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 4020e60d4398SNeilBrown } 40211da177e4SLinus Torvalds 402272083396SBryan Schumaker int 40231da177e4SLinus Torvalds nfsd4_init_slabs(void) 40241da177e4SLinus Torvalds { 40259258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 40269258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 40279258a2d5SJeff Layton if (client_slab == NULL) 40289258a2d5SJeff Layton goto out; 4029fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 4030fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 4031fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 40329258a2d5SJeff Layton goto out_free_client_slab; 4033fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 40343c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 4035fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 4036abf1135bSChristoph Hellwig goto out_free_openowner_slab; 4037e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 403820c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 4039e60d4398SNeilBrown if (file_slab == NULL) 4040abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 40415ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 4042dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 40435ac049acSNeilBrown if (stateid_slab == NULL) 4044abf1135bSChristoph Hellwig goto out_free_file_slab; 40455b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 404620c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 40475b2d21c1SNeilBrown if (deleg_slab == NULL) 4048abf1135bSChristoph Hellwig goto out_free_stateid_slab; 40498287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 40508287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 40518287f009SSachin Bhamare if (odstate_slab == NULL) 40528287f009SSachin Bhamare goto out_free_deleg_slab; 4053e60d4398SNeilBrown return 0; 4054abf1135bSChristoph Hellwig 40558287f009SSachin Bhamare out_free_deleg_slab: 40568287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 4057abf1135bSChristoph Hellwig out_free_stateid_slab: 4058abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4059abf1135bSChristoph Hellwig out_free_file_slab: 4060abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4061abf1135bSChristoph Hellwig out_free_lockowner_slab: 4062abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4063abf1135bSChristoph Hellwig out_free_openowner_slab: 4064abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 40659258a2d5SJeff Layton out_free_client_slab: 40669258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4067abf1135bSChristoph Hellwig out: 40681da177e4SLinus Torvalds dprintk("nfsd4: out of memory while initializing nfsv4\n"); 40691da177e4SLinus Torvalds return -ENOMEM; 40701da177e4SLinus Torvalds } 40711da177e4SLinus Torvalds 4072ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 4073ff194bd9SJ. Bruce Fields { 4074ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 4075ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 4076ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 407758fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 407858fb12e6SJeff Layton } 407958fb12e6SJeff Layton 408058fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 408158fb12e6SJeff Layton struct nfs4_stateowner *so) 408258fb12e6SJeff Layton { 408358fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 408458fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 4085b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 408658fb12e6SJeff Layton } 408758fb12e6SJeff Layton } 408858fb12e6SJeff Layton 408958fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 409058fb12e6SJeff Layton { 409158fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 409258fb12e6SJeff Layton 409358fb12e6SJeff Layton if (so != NULL) { 409458fb12e6SJeff Layton cstate->replay_owner = NULL; 409558fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 409658fb12e6SJeff Layton nfs4_put_stateowner(so); 409758fb12e6SJeff Layton } 4098ff194bd9SJ. Bruce Fields } 4099ff194bd9SJ. Bruce Fields 4100fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 41011da177e4SLinus Torvalds { 41021da177e4SLinus Torvalds struct nfs4_stateowner *sop; 41031da177e4SLinus Torvalds 4104fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 4105ff194bd9SJ. Bruce Fields if (!sop) 4106ff194bd9SJ. Bruce Fields return NULL; 4107ff194bd9SJ. Bruce Fields 41086f4859b8SJ. Bruce Fields xdr_netobj_dup(&sop->so_owner, owner, GFP_KERNEL); 4109ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 4110fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 4111ff194bd9SJ. Bruce Fields return NULL; 4112ff194bd9SJ. Bruce Fields } 4113ff194bd9SJ. Bruce Fields 4114ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 4115ff194bd9SJ. Bruce Fields sop->so_client = clp; 4116ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 41176b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 41181da177e4SLinus Torvalds return sop; 41191da177e4SLinus Torvalds } 4120ff194bd9SJ. Bruce Fields 4121fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 4122ff194bd9SJ. Bruce Fields { 4123d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 41249b531137SStanislav Kinsbursky 4125d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 4126d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 4127fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 41281da177e4SLinus Torvalds } 41291da177e4SLinus Torvalds 41308f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 41318f4b54c5SJeff Layton { 4132d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 41338f4b54c5SJeff Layton } 41348f4b54c5SJeff Layton 41356b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 41366b180f0bSJeff Layton { 41376b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 41386b180f0bSJeff Layton 41396b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 41406b180f0bSJeff Layton } 41416b180f0bSJeff Layton 41426b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 41438f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 41446b180f0bSJeff Layton .so_free = nfs4_free_openowner, 41456b180f0bSJeff Layton }; 41466b180f0bSJeff Layton 41477fc0564eSAndrew Elble static struct nfs4_ol_stateid * 41487fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 41497fc0564eSAndrew Elble { 41507fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 41517fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 41527fc0564eSAndrew Elble 41537fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 41547fc0564eSAndrew Elble 41557fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 41567fc0564eSAndrew Elble /* ignore lock owners */ 41577fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 41587fc0564eSAndrew Elble continue; 415915ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 416015ca08d3STrond Myklebust continue; 416115ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 41627fc0564eSAndrew Elble ret = local; 4163a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 41647fc0564eSAndrew Elble break; 41657fc0564eSAndrew Elble } 41667fc0564eSAndrew Elble } 41677fc0564eSAndrew Elble return ret; 41687fc0564eSAndrew Elble } 41697fc0564eSAndrew Elble 417015ca08d3STrond Myklebust static __be32 417115ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 417215ca08d3STrond Myklebust { 417315ca08d3STrond Myklebust __be32 ret = nfs_ok; 417415ca08d3STrond Myklebust 417515ca08d3STrond Myklebust switch (s->sc_type) { 417615ca08d3STrond Myklebust default: 417715ca08d3STrond Myklebust break; 41784f176417STrond Myklebust case 0: 417915ca08d3STrond Myklebust case NFS4_CLOSED_STID: 418015ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 418115ca08d3STrond Myklebust ret = nfserr_bad_stateid; 418215ca08d3STrond Myklebust break; 418315ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 418415ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 418515ca08d3STrond Myklebust } 418615ca08d3STrond Myklebust return ret; 418715ca08d3STrond Myklebust } 418815ca08d3STrond Myklebust 418915ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 419015ca08d3STrond Myklebust static __be32 419115ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 419215ca08d3STrond Myklebust { 419315ca08d3STrond Myklebust __be32 ret; 419415ca08d3STrond Myklebust 41954f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 419615ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 419715ca08d3STrond Myklebust if (ret != nfs_ok) 419815ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 419915ca08d3STrond Myklebust return ret; 420015ca08d3STrond Myklebust } 420115ca08d3STrond Myklebust 420215ca08d3STrond Myklebust static struct nfs4_ol_stateid * 420315ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 420415ca08d3STrond Myklebust { 420515ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 420615ca08d3STrond Myklebust for (;;) { 420715ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 420815ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 420915ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 421015ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 421115ca08d3STrond Myklebust break; 421215ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 421315ca08d3STrond Myklebust } 421415ca08d3STrond Myklebust return stp; 421515ca08d3STrond Myklebust } 421615ca08d3STrond Myklebust 4217fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 421813d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 4219db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 4220db24b3b4SJeff Layton { 422113d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 42227ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 42231da177e4SLinus Torvalds 4224fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 4225fe0750e5SJ. Bruce Fields if (!oo) 42261da177e4SLinus Torvalds return NULL; 42276b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 4228fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 4229fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 4230d3134b10SJeff Layton oo->oo_flags = 0; 4231db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 4232db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 4233fe0750e5SJ. Bruce Fields oo->oo_time = 0; 423438c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 4235fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 4236d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 4237d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 42387ffb5880STrond Myklebust if (ret == NULL) { 4239fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 42407ffb5880STrond Myklebust ret = oo; 42417ffb5880STrond Myklebust } else 4242d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 4243d50ffdedSKinglong Mee 4244d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 4245c5952338SJeff Layton return ret; 42461da177e4SLinus Torvalds } 42471da177e4SLinus Torvalds 42487fc0564eSAndrew Elble static struct nfs4_ol_stateid * 42498c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 42507fc0564eSAndrew Elble { 42511da177e4SLinus Torvalds 42527fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 42537fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 42548c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 42557fc0564eSAndrew Elble 42568c7245abSOleg Drokin stp = open->op_stp; 42575cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 42585cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 42594f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 42605cc1fb2aSOleg Drokin 426115ca08d3STrond Myklebust retry: 42627fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 42637fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 42647fc0564eSAndrew Elble 42657fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 42667fc0564eSAndrew Elble if (retstp) 42677fc0564eSAndrew Elble goto out_unlock; 42688c7245abSOleg Drokin 42698c7245abSOleg Drokin open->op_stp = NULL; 4270a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 42713abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 42723c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 4273b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 427413cd2184SNeilBrown get_nfs4_file(fp); 427511b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 42761da177e4SLinus Torvalds stp->st_access_bmap = 0; 42771da177e4SLinus Torvalds stp->st_deny_bmap = 0; 42784c4cd222SNeilBrown stp->st_openstp = NULL; 42791c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 42801d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 42817fc0564eSAndrew Elble 42827fc0564eSAndrew Elble out_unlock: 42831d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 42841c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 42855cc1fb2aSOleg Drokin if (retstp) { 428615ca08d3STrond Myklebust /* Handle races with CLOSE */ 428715ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 428815ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 428915ca08d3STrond Myklebust goto retry; 429015ca08d3STrond Myklebust } 42918c7245abSOleg Drokin /* To keep mutex tracking happy */ 42925cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 42938c7245abSOleg Drokin stp = retstp; 42945cc1fb2aSOleg Drokin } 42958c7245abSOleg Drokin return stp; 42961da177e4SLinus Torvalds } 42971da177e4SLinus Torvalds 4298d3134b10SJeff Layton /* 4299d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 4300d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 4301d3134b10SJeff Layton * them before returning however. 4302d3134b10SJeff Layton */ 43031da177e4SLinus Torvalds static void 4304d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 43051da177e4SLinus Torvalds { 4306217526e7SJeff Layton struct nfs4_ol_stateid *last; 4307d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 4308d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 4309d3134b10SJeff Layton nfsd_net_id); 431073758fedSStanislav Kinsbursky 4311fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 43121da177e4SLinus Torvalds 4313b401be22SJeff Layton /* 4314b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 4315b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 4316b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 4317b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 4318b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 4319b401be22SJeff Layton * there should be no danger of the refcount going back up again at 4320b401be22SJeff Layton * this point. 4321b401be22SJeff Layton */ 4322a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 4323b401be22SJeff Layton 4324d3134b10SJeff Layton release_all_access(s); 4325d3134b10SJeff Layton if (s->st_stid.sc_file) { 4326d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 4327d3134b10SJeff Layton s->st_stid.sc_file = NULL; 4328d3134b10SJeff Layton } 4329217526e7SJeff Layton 4330217526e7SJeff Layton spin_lock(&nn->client_lock); 4331217526e7SJeff Layton last = oo->oo_last_closed_stid; 4332d3134b10SJeff Layton oo->oo_last_closed_stid = s; 433373758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 433420b7d86fSArnd Bergmann oo->oo_time = ktime_get_boottime_seconds(); 4335217526e7SJeff Layton spin_unlock(&nn->client_lock); 4336217526e7SJeff Layton if (last) 4337217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 43381da177e4SLinus Torvalds } 43391da177e4SLinus Torvalds 43401da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 43411da177e4SLinus Torvalds static struct nfs4_file * 43425b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval) 43431da177e4SLinus Torvalds { 43441da177e4SLinus Torvalds struct nfs4_file *fp; 43451da177e4SLinus Torvalds 434636a80491SMadhuparna Bhowmik hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, 434736a80491SMadhuparna Bhowmik lockdep_is_held(&state_lock)) { 43484d94c2efSChristoph Hellwig if (fh_match(&fp->fi_fhandle, fh)) { 4349818a34ebSElena Reshetova if (refcount_inc_not_zero(&fp->fi_ref)) 43501da177e4SLinus Torvalds return fp; 43511da177e4SLinus Torvalds } 435213cd2184SNeilBrown } 43531da177e4SLinus Torvalds return NULL; 43541da177e4SLinus Torvalds } 43551da177e4SLinus Torvalds 4356e6ba76e1SChristoph Hellwig struct nfs4_file * 4357ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 4358950e0118STrond Myklebust { 4359950e0118STrond Myklebust struct nfs4_file *fp; 43605b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 4361950e0118STrond Myklebust 43625b095e99SJeff Layton rcu_read_lock(); 43635b095e99SJeff Layton fp = find_file_locked(fh, hashval); 43645b095e99SJeff Layton rcu_read_unlock(); 4365950e0118STrond Myklebust return fp; 4366950e0118STrond Myklebust } 4367950e0118STrond Myklebust 4368950e0118STrond Myklebust static struct nfs4_file * 4369f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 4370950e0118STrond Myklebust { 4371950e0118STrond Myklebust struct nfs4_file *fp; 43725b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 43735b095e99SJeff Layton 43745b095e99SJeff Layton rcu_read_lock(); 43755b095e99SJeff Layton fp = find_file_locked(fh, hashval); 43765b095e99SJeff Layton rcu_read_unlock(); 43775b095e99SJeff Layton if (fp) 43785b095e99SJeff Layton return fp; 4379950e0118STrond Myklebust 4380950e0118STrond Myklebust spin_lock(&state_lock); 43815b095e99SJeff Layton fp = find_file_locked(fh, hashval); 43825b095e99SJeff Layton if (likely(fp == NULL)) { 43835b095e99SJeff Layton nfsd4_init_file(fh, hashval, new); 4384950e0118STrond Myklebust fp = new; 4385950e0118STrond Myklebust } 4386950e0118STrond Myklebust spin_unlock(&state_lock); 4387950e0118STrond Myklebust 4388950e0118STrond Myklebust return fp; 4389950e0118STrond Myklebust } 4390950e0118STrond Myklebust 43914f83aa30SJ. Bruce Fields /* 43921da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 43931da177e4SLinus Torvalds * WRITE with all zero or all one stateid 43941da177e4SLinus Torvalds */ 4395b37ad28bSAl Viro static __be32 43961da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 43971da177e4SLinus Torvalds { 43981da177e4SLinus Torvalds struct nfs4_file *fp; 4399baeb4ff0SJeff Layton __be32 ret = nfs_ok; 44001da177e4SLinus Torvalds 4401ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 440213cd2184SNeilBrown if (!fp) 4403baeb4ff0SJeff Layton return ret; 4404baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 44051d31a253STrond Myklebust spin_lock(&fp->fi_lock); 4406baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 4407baeb4ff0SJeff Layton ret = nfserr_locked; 44081d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 440913cd2184SNeilBrown put_nfs4_file(fp); 441013cd2184SNeilBrown return ret; 44111da177e4SLinus Torvalds } 44121da177e4SLinus Torvalds 44130162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 44141da177e4SLinus Torvalds { 44150162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 441611b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 441711b9164aSTrond Myklebust nfsd_net_id); 4418e8c69d17SJ. Bruce Fields 441911b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 4420f54fe962SJeff Layton 442102e1215fSJeff Layton /* 442202e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 4423f54fe962SJeff Layton * already holding inode->i_lock. 4424f54fe962SJeff Layton * 4425dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 4426dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 4427dff1399fSJeff Layton */ 4428f54fe962SJeff Layton spin_lock(&state_lock); 4429dff1399fSJeff Layton if (dp->dl_time == 0) { 443020b7d86fSArnd Bergmann dp->dl_time = ktime_get_boottime_seconds(); 443102e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 443202e1215fSJeff Layton } 443302e1215fSJeff Layton spin_unlock(&state_lock); 4434dff1399fSJeff Layton } 44351da177e4SLinus Torvalds 44360162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 44370162ac2bSChristoph Hellwig struct rpc_task *task) 44380162ac2bSChristoph Hellwig { 44390162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 44400162ac2bSChristoph Hellwig 4441a457974fSAndrew Elble if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID) 4442a457974fSAndrew Elble return 1; 4443a457974fSAndrew Elble 44440162ac2bSChristoph Hellwig switch (task->tk_status) { 44450162ac2bSChristoph Hellwig case 0: 44460162ac2bSChristoph Hellwig return 1; 44471c73b9d2SScott Mayhew case -NFS4ERR_DELAY: 44481c73b9d2SScott Mayhew rpc_delay(task, 2 * HZ); 44491c73b9d2SScott Mayhew return 0; 44500162ac2bSChristoph Hellwig case -EBADHANDLE: 44510162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 44520162ac2bSChristoph Hellwig /* 44530162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 44540162ac2bSChristoph Hellwig * granting delegation. 44550162ac2bSChristoph Hellwig */ 44560162ac2bSChristoph Hellwig if (dp->dl_retries--) { 44570162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 44580162ac2bSChristoph Hellwig return 0; 44590162ac2bSChristoph Hellwig } 44600162ac2bSChristoph Hellwig /*FALLTHRU*/ 44610162ac2bSChristoph Hellwig default: 44621c73b9d2SScott Mayhew return 1; 44630162ac2bSChristoph Hellwig } 44640162ac2bSChristoph Hellwig } 44650162ac2bSChristoph Hellwig 44660162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 44670162ac2bSChristoph Hellwig { 44680162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 44690162ac2bSChristoph Hellwig 44700162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 44710162ac2bSChristoph Hellwig } 44720162ac2bSChristoph Hellwig 4473c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 44740162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 44750162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 44760162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 44770162ac2bSChristoph Hellwig }; 44780162ac2bSChristoph Hellwig 447902e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 448002e1215fSJeff Layton { 448102e1215fSJeff Layton /* 448202e1215fSJeff Layton * We're assuming the state code never drops its reference 448302e1215fSJeff Layton * without first removing the lease. Since we're in this lease 44844a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 44854a269efbSJ. Bruce Fields * i_lock) we know the server hasn't removed the lease yet, and 44864a269efbSJ. Bruce Fields * we know it's safe to take a reference. 448702e1215fSJeff Layton */ 4488a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 4489f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 44906b57d9c8SJ. Bruce Fields } 44916b57d9c8SJ. Bruce Fields 44921c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 44934d01b7f5SJeff Layton static bool 44944d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 44956b57d9c8SJ. Bruce Fields { 44964d01b7f5SJeff Layton bool ret = false; 4497653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 4498653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 44996b57d9c8SJ. Bruce Fields 45000272e1fdSJ. Bruce Fields /* 45010272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 4502acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 45036b57d9c8SJ. Bruce Fields * in time: 45040272e1fdSJ. Bruce Fields */ 45050272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 45061da177e4SLinus Torvalds 450702e1215fSJeff Layton spin_lock(&fp->fi_lock); 4508417c6629SJeff Layton fp->fi_had_conflict = true; 45095d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 451002e1215fSJeff Layton spin_unlock(&fp->fi_lock); 45114d01b7f5SJeff Layton return ret; 45121da177e4SLinus Torvalds } 45131da177e4SLinus Torvalds 4514c45198edSJeff Layton static int 45157448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 45167448cc37SJeff Layton struct list_head *dispose) 45171da177e4SLinus Torvalds { 45181da177e4SLinus Torvalds if (arg & F_UNLCK) 4519c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 45201da177e4SLinus Torvalds else 45211da177e4SLinus Torvalds return -EAGAIN; 45221da177e4SLinus Torvalds } 45231da177e4SLinus Torvalds 45247b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 45258fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 45268fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 45271da177e4SLinus Torvalds }; 45281da177e4SLinus Torvalds 45297a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 45307a8711c9SJ. Bruce Fields { 45317a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 45327a8711c9SJ. Bruce Fields return nfs_ok; 45337a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 45347a8711c9SJ. Bruce Fields return nfserr_replay_me; 45357a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 45367a8711c9SJ. Bruce Fields return nfs_ok; 45377a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 45387a8711c9SJ. Bruce Fields } 45391da177e4SLinus Torvalds 45404b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 45414b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 4542b7342204SOlga Kornievskaia struct nfsd_net *nn, 4543b7342204SOlga Kornievskaia bool sessions) 45444b24ca7dSJeff Layton { 45454b24ca7dSJeff Layton struct nfs4_client *found; 45464b24ca7dSJeff Layton 45474b24ca7dSJeff Layton if (cstate->clp) { 45484b24ca7dSJeff Layton found = cstate->clp; 45494b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 45504b24ca7dSJeff Layton return nfserr_stale_clientid; 45514b24ca7dSJeff Layton return nfs_ok; 45524b24ca7dSJeff Layton } 45534b24ca7dSJeff Layton 45544b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 45554b24ca7dSJeff Layton return nfserr_stale_clientid; 45564b24ca7dSJeff Layton 45574b24ca7dSJeff Layton /* 45584b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 45594b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 45604b24ca7dSJeff Layton * will be false. 45614b24ca7dSJeff Layton */ 45624b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 45633e339f96STrond Myklebust spin_lock(&nn->client_lock); 4564b7342204SOlga Kornievskaia found = find_confirmed_client(clid, sessions, nn); 45653e339f96STrond Myklebust if (!found) { 45663e339f96STrond Myklebust spin_unlock(&nn->client_lock); 45674b24ca7dSJeff Layton return nfserr_expired; 45683e339f96STrond Myklebust } 456914ed14ccSJ. Bruce Fields atomic_inc(&found->cl_rpc_users); 45703e339f96STrond Myklebust spin_unlock(&nn->client_lock); 45714b24ca7dSJeff Layton 45724b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 45734b24ca7dSJeff Layton cstate->clp = found; 45744b24ca7dSJeff Layton return nfs_ok; 45754b24ca7dSJeff Layton } 45764b24ca7dSJeff Layton 4577b37ad28bSAl Viro __be32 45786668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 45793320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 45801da177e4SLinus Torvalds { 45811da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 45821da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 45831da177e4SLinus Torvalds unsigned int strhashval; 4584fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 45854cdc951bSJ. Bruce Fields __be32 status; 45861da177e4SLinus Torvalds 45872c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 45881da177e4SLinus Torvalds return nfserr_stale_clientid; 458932513b40SJ. Bruce Fields /* 459032513b40SJ. Bruce Fields * In case we need it later, after we've already created the 459132513b40SJ. Bruce Fields * file and don't want to risk a further failure: 459232513b40SJ. Bruce Fields */ 459332513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 459432513b40SJ. Bruce Fields if (open->op_file == NULL) 459532513b40SJ. Bruce Fields return nfserr_jukebox; 45961da177e4SLinus Torvalds 4597b7342204SOlga Kornievskaia status = lookup_clientid(clientid, cstate, nn, false); 459813d6f66bSTrond Myklebust if (status) 459913d6f66bSTrond Myklebust return status; 460013d6f66bSTrond Myklebust clp = cstate->clp; 46012d91e895STrond Myklebust 4602d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 4603d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 46042d91e895STrond Myklebust open->op_openowner = oo; 46052d91e895STrond Myklebust if (!oo) { 4606bcf130f9SJ. Bruce Fields goto new_owner; 46070f442aa2SJ. Bruce Fields } 4608dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 46090f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 4610fe0750e5SJ. Bruce Fields release_openowner(oo); 4611fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 4612bcf130f9SJ. Bruce Fields goto new_owner; 46130f442aa2SJ. Bruce Fields } 46144cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 46154cdc951bSJ. Bruce Fields if (status) 46164cdc951bSJ. Bruce Fields return status; 46174cdc951bSJ. Bruce Fields goto alloc_stateid; 4618bcf130f9SJ. Bruce Fields new_owner: 461913d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 4620fe0750e5SJ. Bruce Fields if (oo == NULL) 46213e772463SJ. Bruce Fields return nfserr_jukebox; 4622fe0750e5SJ. Bruce Fields open->op_openowner = oo; 46234cdc951bSJ. Bruce Fields alloc_stateid: 4624b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 46254cdc951bSJ. Bruce Fields if (!open->op_stp) 46264cdc951bSJ. Bruce Fields return nfserr_jukebox; 46278287f009SSachin Bhamare 46288287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 46298287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 46308287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 46318287f009SSachin Bhamare if (!open->op_odstate) 46328287f009SSachin Bhamare return nfserr_jukebox; 46338287f009SSachin Bhamare } 46348287f009SSachin Bhamare 46350f442aa2SJ. Bruce Fields return nfs_ok; 46361da177e4SLinus Torvalds } 46371da177e4SLinus Torvalds 4638b37ad28bSAl Viro static inline __be32 46394a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 46404a6e43e6SNeilBrown { 46414a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 46424a6e43e6SNeilBrown return nfserr_openmode; 46434a6e43e6SNeilBrown else 46444a6e43e6SNeilBrown return nfs_ok; 46454a6e43e6SNeilBrown } 46464a6e43e6SNeilBrown 4647c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 464824a0111eSJ. Bruce Fields { 464924a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 465024a0111eSJ. Bruce Fields } 465124a0111eSJ. Bruce Fields 465238c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 4653f459e453SJ. Bruce Fields { 4654f459e453SJ. Bruce Fields struct nfs4_stid *ret; 4655f459e453SJ. Bruce Fields 465695da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 465795da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 4658f459e453SJ. Bruce Fields if (!ret) 4659f459e453SJ. Bruce Fields return NULL; 4660f459e453SJ. Bruce Fields return delegstateid(ret); 4661f459e453SJ. Bruce Fields } 4662f459e453SJ. Bruce Fields 46638b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 46648b289b2cSJ. Bruce Fields { 46658b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 46668b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 46678b289b2cSJ. Bruce Fields } 46688b289b2cSJ. Bruce Fields 4669b37ad28bSAl Viro static __be32 467041d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 4671567d9829SNeilBrown struct nfs4_delegation **dp) 4672567d9829SNeilBrown { 4673567d9829SNeilBrown int flags; 4674b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 4675dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 4676567d9829SNeilBrown 4677dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 4678dcd94cc2STrond Myklebust if (deleg == NULL) 4679c44c5eebSNeilBrown goto out; 468095da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 468195da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 468295da1b3aSAndrew Elble if (cl->cl_minorversion) 468395da1b3aSAndrew Elble status = nfserr_deleg_revoked; 468495da1b3aSAndrew Elble goto out; 468595da1b3aSAndrew Elble } 468624a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 4687dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 4688dcd94cc2STrond Myklebust if (status) { 4689dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 4690dcd94cc2STrond Myklebust goto out; 4691dcd94cc2STrond Myklebust } 4692dcd94cc2STrond Myklebust *dp = deleg; 4693c44c5eebSNeilBrown out: 46948b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 4695c44c5eebSNeilBrown return nfs_ok; 4696c44c5eebSNeilBrown if (status) 4697c44c5eebSNeilBrown return status; 4698dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 4699c44c5eebSNeilBrown return nfs_ok; 4700567d9829SNeilBrown } 4701567d9829SNeilBrown 470221fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 470321fb4016SJ. Bruce Fields { 470421fb4016SJ. Bruce Fields int flags = 0; 470521fb4016SJ. Bruce Fields 470621fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 470721fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 470821fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 470921fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 471021fb4016SJ. Bruce Fields return flags; 471121fb4016SJ. Bruce Fields } 471221fb4016SJ. Bruce Fields 4713b37ad28bSAl Viro static inline __be32 47141da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 47151da177e4SLinus Torvalds struct nfsd4_open *open) 47161da177e4SLinus Torvalds { 47171da177e4SLinus Torvalds struct iattr iattr = { 47181da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 47191da177e4SLinus Torvalds .ia_size = 0, 47201da177e4SLinus Torvalds }; 47211da177e4SLinus Torvalds if (!open->op_truncate) 47221da177e4SLinus Torvalds return 0; 47231da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 47249246585aSAl Viro return nfserr_inval; 47252a1aa489SArnd Bergmann return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0); 47261da177e4SLinus Torvalds } 47271da177e4SLinus Torvalds 47287e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 47296eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 47306eb3a1d0SJeff Layton struct nfsd4_open *open) 47317e6a72e5SChristoph Hellwig { 4732fd4f83fdSJeff Layton struct nfsd_file *nf = NULL; 47337e6a72e5SChristoph Hellwig __be32 status; 47347e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 47357e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 4736baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 47377e6a72e5SChristoph Hellwig 4738de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4739baeb4ff0SJeff Layton 4740baeb4ff0SJeff Layton /* 4741baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 4742baeb4ff0SJeff Layton * current access? 4743baeb4ff0SJeff Layton */ 4744baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4745baeb4ff0SJeff Layton if (status != nfs_ok) { 4746baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4747baeb4ff0SJeff Layton goto out; 4748baeb4ff0SJeff Layton } 4749baeb4ff0SJeff Layton 4750baeb4ff0SJeff Layton /* set access to the file */ 4751baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 4752baeb4ff0SJeff Layton if (status != nfs_ok) { 4753baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4754baeb4ff0SJeff Layton goto out; 4755baeb4ff0SJeff Layton } 4756baeb4ff0SJeff Layton 4757baeb4ff0SJeff Layton /* Set access bits in stateid */ 4758baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 4759baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 4760baeb4ff0SJeff Layton 4761baeb4ff0SJeff Layton /* Set new deny mask */ 4762baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 4763baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4764baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 4765baeb4ff0SJeff Layton 47667e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 4767de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4768fd4f83fdSJeff Layton status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); 47697e6a72e5SChristoph Hellwig if (status) 4770baeb4ff0SJeff Layton goto out_put_access; 4771de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4772de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 4773fd4f83fdSJeff Layton fp->fi_fds[oflag] = nf; 4774fd4f83fdSJeff Layton nf = NULL; 4775de18643dSTrond Myklebust } 47767e6a72e5SChristoph Hellwig } 4777de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4778fd4f83fdSJeff Layton if (nf) 4779fd4f83fdSJeff Layton nfsd_file_put(nf); 47807e6a72e5SChristoph Hellwig 47817e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 47827e6a72e5SChristoph Hellwig if (status) 47837e6a72e5SChristoph Hellwig goto out_put_access; 47847e6a72e5SChristoph Hellwig out: 47857e6a72e5SChristoph Hellwig return status; 4786baeb4ff0SJeff Layton out_put_access: 4787baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 4788baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 4789baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 4790baeb4ff0SJeff Layton goto out; 47917e6a72e5SChristoph Hellwig } 47927e6a72e5SChristoph Hellwig 4793b37ad28bSAl Viro static __be32 4794dcef0413SJ. 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) 47951da177e4SLinus Torvalds { 4796b37ad28bSAl Viro __be32 status; 47976ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 47981da177e4SLinus Torvalds 47996eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 4800baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 48017e6a72e5SChristoph Hellwig 4802baeb4ff0SJeff Layton /* test and set deny mode */ 4803baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 4804baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4805baeb4ff0SJeff Layton if (status == nfs_ok) { 4806baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4807baeb4ff0SJeff Layton fp->fi_share_deny |= 4808baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 48091da177e4SLinus Torvalds } 4810baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 48111da177e4SLinus Torvalds 4812baeb4ff0SJeff Layton if (status != nfs_ok) 4813baeb4ff0SJeff Layton return status; 4814baeb4ff0SJeff Layton 4815baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 4816baeb4ff0SJeff Layton if (status != nfs_ok) 4817baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 4818baeb4ff0SJeff Layton return status; 4819baeb4ff0SJeff Layton } 48201da177e4SLinus Torvalds 482114a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 482214a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 482314a24e99SJ. Bruce Fields { 482414a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 482514a24e99SJ. Bruce Fields return true; 482614a24e99SJ. Bruce Fields /* 482714a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 482814a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 482914a24e99SJ. Bruce Fields * until we hear otherwise: 483014a24e99SJ. Bruce Fields */ 483114a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 483214a24e99SJ. Bruce Fields } 483314a24e99SJ. Bruce Fields 4834653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 4835653e514eSJ. Bruce Fields int flag) 483622d38c4cSJ. Bruce Fields { 483722d38c4cSJ. Bruce Fields struct file_lock *fl; 483822d38c4cSJ. Bruce Fields 483922d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 484022d38c4cSJ. Bruce Fields if (!fl) 484122d38c4cSJ. Bruce Fields return NULL; 484222d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 4843617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 484422d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 484522d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 4846653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 484722d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 4848eb82dd39SJeff Layton fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; 484922d38c4cSJ. Bruce Fields return fl; 485022d38c4cSJ. Bruce Fields } 485122d38c4cSJ. Bruce Fields 48520b26693cSJeff Layton static struct nfs4_delegation * 48530b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 48548287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 4855acfdf5c3SJ. Bruce Fields { 485668b18f52SJ. Bruce Fields int status = 0; 48570b26693cSJeff Layton struct nfs4_delegation *dp; 4858eb82dd39SJeff Layton struct nfsd_file *nf; 4859353601e7SJ. Bruce Fields struct file_lock *fl; 4860417c6629SJeff Layton 4861353601e7SJ. Bruce Fields /* 4862353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 4863353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 4864353601e7SJ. Bruce Fields * the end: 4865353601e7SJ. Bruce Fields */ 4866bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 48670b26693cSJeff Layton return ERR_PTR(-EAGAIN); 48680b26693cSJeff Layton 4869eb82dd39SJeff Layton nf = find_readable_file(fp); 4870eb82dd39SJeff Layton if (!nf) { 4871353601e7SJ. Bruce Fields /* We should always have a readable file here */ 4872353601e7SJ. Bruce Fields WARN_ON_ONCE(1); 4873353601e7SJ. Bruce Fields return ERR_PTR(-EBADF); 4874353601e7SJ. Bruce Fields } 487534ed9872SAndrew Elble spin_lock(&state_lock); 487634ed9872SAndrew Elble spin_lock(&fp->fi_lock); 487768b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 487868b18f52SJ. Bruce Fields status = -EAGAIN; 4879353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 4880eb82dd39SJeff Layton fp->fi_deleg_file = nf; 4881353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 4882353601e7SJ. Bruce Fields * cleared */ 4883353601e7SJ. Bruce Fields fp->fi_delegees = 1; 4884eb82dd39SJeff Layton nf = NULL; 4885353601e7SJ. Bruce Fields } else 4886353601e7SJ. Bruce Fields fp->fi_delegees++; 4887353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 4888353601e7SJ. Bruce Fields spin_unlock(&state_lock); 4889eb82dd39SJeff Layton if (nf) 4890eb82dd39SJeff Layton nfsd_file_put(nf); 4891353601e7SJ. Bruce Fields if (status) 4892353601e7SJ. Bruce Fields return ERR_PTR(status); 4893353601e7SJ. Bruce Fields 4894353601e7SJ. Bruce Fields status = -ENOMEM; 4895353601e7SJ. Bruce Fields dp = alloc_init_deleg(clp, fp, fh, odstate); 4896353601e7SJ. Bruce Fields if (!dp) 4897353601e7SJ. Bruce Fields goto out_delegees; 4898353601e7SJ. Bruce Fields 4899353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 4900353601e7SJ. Bruce Fields if (!fl) 4901bd8d7250SAndrew Elble goto out_clnt_odstate; 4902353601e7SJ. Bruce Fields 4903eb82dd39SJeff Layton status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); 4904353601e7SJ. Bruce Fields if (fl) 4905353601e7SJ. Bruce Fields locks_free_lock(fl); 4906353601e7SJ. Bruce Fields if (status) 4907353601e7SJ. Bruce Fields goto out_clnt_odstate; 4908353601e7SJ. Bruce Fields 4909353601e7SJ. Bruce Fields spin_lock(&state_lock); 4910353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 4911353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 4912353601e7SJ. Bruce Fields status = -EAGAIN; 4913353601e7SJ. Bruce Fields else 4914353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 491534ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 491634ed9872SAndrew Elble spin_unlock(&state_lock); 491734ed9872SAndrew Elble 491834ed9872SAndrew Elble if (status) 4919692ad280SAndrew Elble goto out_unlock; 4920692ad280SAndrew Elble 49210b26693cSJeff Layton return dp; 4922692ad280SAndrew Elble out_unlock: 4923eb82dd39SJeff Layton vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); 4924353601e7SJ. Bruce Fields out_clnt_odstate: 4925353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 4926353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 4927353601e7SJ. Bruce Fields out_delegees: 4928353601e7SJ. Bruce Fields put_deleg_file(fp); 4929353601e7SJ. Bruce Fields return ERR_PTR(status); 4930edab9782SJ. Bruce Fields } 4931edab9782SJ. Bruce Fields 49324aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 49334aa8913cSBenny Halevy { 49344aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 49354aa8913cSBenny Halevy if (status == -EAGAIN) 49364aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 49374aa8913cSBenny Halevy else { 49384aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 49394aa8913cSBenny Halevy switch (open->op_deleg_want) { 49404aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 49414aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 49424aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 49434aa8913cSBenny Halevy break; 49444aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 49454aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 49464aa8913cSBenny Halevy break; 49474aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 4948063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 49494aa8913cSBenny Halevy } 49504aa8913cSBenny Halevy } 49514aa8913cSBenny Halevy } 49524aa8913cSBenny Halevy 49531da177e4SLinus Torvalds /* 49541da177e4SLinus Torvalds * Attempt to hand out a delegation. 495599c41515SJ. Bruce Fields * 495699c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 495799c41515SJ. Bruce Fields * proper support for them. 49581da177e4SLinus Torvalds */ 49591da177e4SLinus Torvalds static void 49604cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 49614cf59221SJeff Layton struct nfs4_ol_stateid *stp) 49621da177e4SLinus Torvalds { 49631da177e4SLinus Torvalds struct nfs4_delegation *dp; 49644cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 49654cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 496614a24e99SJ. Bruce Fields int cb_up; 496799c41515SJ. Bruce Fields int status = 0; 49681da177e4SLinus Torvalds 4969fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 49707b190fecSNeilBrown open->op_recall = 0; 49717b190fecSNeilBrown switch (open->op_claim_type) { 49727b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 49732bf23875SJ. Bruce Fields if (!cb_up) 49747b190fecSNeilBrown open->op_recall = 1; 497599c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 497699c41515SJ. Bruce Fields goto out_no_deleg; 49777b190fecSNeilBrown break; 49787b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 4979ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 498099c41515SJ. Bruce Fields /* 498199c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 4982c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 4983c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 498499c41515SJ. Bruce Fields */ 49854cf59221SJeff Layton if (locks_in_grace(clp->net)) 498699c41515SJ. Bruce Fields goto out_no_deleg; 4987dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 498899c41515SJ. Bruce Fields goto out_no_deleg; 49899a0590aeSSteve Dickson /* 49909a0590aeSSteve Dickson * Also, if the file was opened for write or 49919a0590aeSSteve Dickson * create, there's a good chance the client's 49929a0590aeSSteve Dickson * about to write to it, resulting in an 49939a0590aeSSteve Dickson * immediate recall (since we don't support 49949a0590aeSSteve Dickson * write delegations): 49959a0590aeSSteve Dickson */ 49961da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 499799c41515SJ. Bruce Fields goto out_no_deleg; 499899c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 499999c41515SJ. Bruce Fields goto out_no_deleg; 50007b190fecSNeilBrown break; 50017b190fecSNeilBrown default: 500299c41515SJ. Bruce Fields goto out_no_deleg; 50037b190fecSNeilBrown } 50048287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 50050b26693cSJeff Layton if (IS_ERR(dp)) 5006dd239cc0SJ. Bruce Fields goto out_no_deleg; 50071da177e4SLinus Torvalds 5008d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 50091da177e4SLinus Torvalds 50108c10cbdbSBenny Halevy dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", 5011d5477a8dSJ. Bruce Fields STATEID_VAL(&dp->dl_stid.sc_stateid)); 501299c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 501367cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5014dd239cc0SJ. Bruce Fields return; 5015dd239cc0SJ. Bruce Fields out_no_deleg: 501699c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 50177b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 5018d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 50191da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 5020d08d32e6SJ. Bruce Fields open->op_recall = 1; 5021d08d32e6SJ. Bruce Fields } 5022dd239cc0SJ. Bruce Fields 5023dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 5024dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 5025dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 5026dd239cc0SJ. Bruce Fields return; 50271da177e4SLinus Torvalds } 50281da177e4SLinus Torvalds 5029e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 5030e27f49c3SBenny Halevy struct nfs4_delegation *dp) 5031e27f49c3SBenny Halevy { 5032e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 5033e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5034e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5035e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 5036e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 5037e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5038e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5039e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 5040e27f49c3SBenny Halevy } 5041e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 5042e27f49c3SBenny Halevy * it already has, therefore we don't return 5043e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 5044e27f49c3SBenny Halevy */ 5045e27f49c3SBenny Halevy } 5046e27f49c3SBenny Halevy 5047b37ad28bSAl Viro __be32 50481da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 50491da177e4SLinus Torvalds { 50506668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 505138c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 50521da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 5053dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 5054567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 5055b37ad28bSAl Viro __be32 status; 5056d8a1a000STrond Myklebust bool new_stp = false; 50571da177e4SLinus Torvalds 50581da177e4SLinus Torvalds /* 50591da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 50601da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 50611da177e4SLinus Torvalds * If not found, create the nfs4_file struct 50621da177e4SLinus Torvalds */ 5063f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 5064950e0118STrond Myklebust if (fp != open->op_file) { 506541d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 5066c44c5eebSNeilBrown if (status) 5067c44c5eebSNeilBrown goto out; 506815ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 50691da177e4SLinus Torvalds } else { 5070950e0118STrond Myklebust open->op_file = NULL; 5071c44c5eebSNeilBrown status = nfserr_bad_stateid; 50728b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 5073c44c5eebSNeilBrown goto out; 50741da177e4SLinus Torvalds } 50751da177e4SLinus Torvalds 5076d8a1a000STrond Myklebust if (!stp) { 5077d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 5078d8a1a000STrond Myklebust if (!open->op_stp) 5079d8a1a000STrond Myklebust new_stp = true; 5080d8a1a000STrond Myklebust } 5081d8a1a000STrond Myklebust 50821da177e4SLinus Torvalds /* 50831da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 50841da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 5085d8a1a000STrond Myklebust * 5086d8a1a000STrond Myklebust * stp is already locked. 50871da177e4SLinus Torvalds */ 5088d8a1a000STrond Myklebust if (!new_stp) { 50891da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 5090f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 509135a92fe8SJeff Layton if (status) { 5092feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 50931da177e4SLinus Torvalds goto out; 509435a92fe8SJeff Layton } 50951da177e4SLinus Torvalds } else { 50966eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 50976eb3a1d0SJeff Layton if (status) { 5098d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 50996eb3a1d0SJeff Layton release_open_stateid(stp); 5100d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 51016eb3a1d0SJeff Layton goto out; 51026eb3a1d0SJeff Layton } 51038287f009SSachin Bhamare 51048287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 51058287f009SSachin Bhamare open->op_odstate); 51068287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 51078287f009SSachin Bhamare open->op_odstate = NULL; 51081da177e4SLinus Torvalds } 5109d8a1a000STrond Myklebust 51109767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 5111feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 51121da177e4SLinus Torvalds 5113d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 5114d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 5115d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5116d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 5117d24433cdSBenny Halevy goto nodeleg; 5118d24433cdSBenny Halevy } 5119d24433cdSBenny Halevy } 5120d24433cdSBenny Halevy 51211da177e4SLinus Torvalds /* 51221da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 51231da177e4SLinus Torvalds * OPEN succeeds even if we fail. 51241da177e4SLinus Torvalds */ 51254cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 5126d24433cdSBenny Halevy nodeleg: 51271da177e4SLinus Torvalds status = nfs_ok; 51281da177e4SLinus Torvalds 51298c10cbdbSBenny Halevy dprintk("%s: stateid=" STATEID_FMT "\n", __func__, 5130dcef0413SJ. Bruce Fields STATEID_VAL(&stp->st_stid.sc_stateid)); 51311da177e4SLinus Torvalds out: 5132d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 5133d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 5134e27f49c3SBenny Halevy open->op_deleg_want) 5135e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 5136d24433cdSBenny Halevy 513713cd2184SNeilBrown if (fp) 513813cd2184SNeilBrown put_nfs4_file(fp); 513937515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 514087186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 51411da177e4SLinus Torvalds /* 51421da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 51431da177e4SLinus Torvalds */ 51441da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 514519e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 514619e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 514719e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 51481da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 514919e4c347SJeff Layton 5150dcd94cc2STrond Myklebust if (dp) 5151dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5152d6f2bc5dSTrond Myklebust if (stp) 5153d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 51541da177e4SLinus Torvalds 51551da177e4SLinus Torvalds return status; 51561da177e4SLinus Torvalds } 51571da177e4SLinus Torvalds 515858fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 515942297899SJeff Layton struct nfsd4_open *open) 5160d29b20cdSJ. Bruce Fields { 5161d29b20cdSJ. Bruce Fields if (open->op_openowner) { 5162d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 5163d29b20cdSJ. Bruce Fields 5164d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 5165d3134b10SJeff Layton nfs4_put_stateowner(so); 5166d29b20cdSJ. Bruce Fields } 516732513b40SJ. Bruce Fields if (open->op_file) 51685b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 51694cdc951bSJ. Bruce Fields if (open->op_stp) 51706011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 51718287f009SSachin Bhamare if (open->op_odstate) 51728287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 5173d29b20cdSJ. Bruce Fields } 5174d29b20cdSJ. Bruce Fields 5175b37ad28bSAl Viro __be32 5176b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5177eb69853dSChristoph Hellwig union nfsd4_op_u *u) 51781da177e4SLinus Torvalds { 5179eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 51801da177e4SLinus Torvalds struct nfs4_client *clp; 5181b37ad28bSAl Viro __be32 status; 51827f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 51831da177e4SLinus Torvalds 51841da177e4SLinus Torvalds dprintk("process_renew(%08x/%08x): starting\n", 51851da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 5186b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 51879b2ef62bSJ. Bruce Fields if (status) 51881da177e4SLinus Torvalds goto out; 51894b24ca7dSJeff Layton clp = cstate->clp; 51901da177e4SLinus Torvalds status = nfserr_cb_path_down; 5191ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 519277a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 51931da177e4SLinus Torvalds goto out; 51941da177e4SLinus Torvalds status = nfs_ok; 51951da177e4SLinus Torvalds out: 51961da177e4SLinus Torvalds return status; 51971da177e4SLinus Torvalds } 51981da177e4SLinus Torvalds 51997f5ef2e9SJeff Layton void 520012760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 5201a76b4319SNeilBrown { 520233dcc481SJeff Layton /* do nothing if grace period already ended */ 5203a51c84edSStanislav Kinsbursky if (nn->grace_ended) 520433dcc481SJeff Layton return; 520533dcc481SJeff Layton 5206a51c84edSStanislav Kinsbursky nn->grace_ended = true; 520770b28235SJ. Bruce Fields /* 520870b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 520970b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 521070b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 521170b28235SJ. Bruce Fields * 521270b28235SJ. Bruce Fields */ 5213919b8049SJeff Layton nfsd4_record_grace_done(nn); 521470b28235SJ. Bruce Fields /* 521570b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 521670b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 521770b28235SJ. Bruce Fields * of luck on the next boot. 521870b28235SJ. Bruce Fields * 521970b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 522070b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 522170b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 522270b28235SJ. Bruce Fields */ 52235e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 522470b28235SJ. Bruce Fields /* 522570b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 522670b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 522770b28235SJ. Bruce Fields * regular locking can resume. 522870b28235SJ. Bruce Fields */ 5229a76b4319SNeilBrown } 5230a76b4319SNeilBrown 523103f318caSJ. Bruce Fields /* 523203f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 523303f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 523403f318caSJ. Bruce Fields */ 523503f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 523603f318caSJ. Bruce Fields { 523720b7d86fSArnd Bergmann time64_t double_grace_period_end = nn->boot_time + 523820b7d86fSArnd Bergmann 2 * nn->nfsd4_lease; 523903f318caSJ. Bruce Fields 5240362063a5SScott Mayhew if (nn->track_reclaim_completes && 5241362063a5SScott Mayhew atomic_read(&nn->nr_reclaim_complete) == 5242362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) 5243362063a5SScott Mayhew return false; 524403f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 524503f318caSJ. Bruce Fields return false; 524603f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 524703f318caSJ. Bruce Fields /* 524803f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 524903f318caSJ. Bruce Fields * still not done, give up: 525003f318caSJ. Bruce Fields */ 525120b7d86fSArnd Bergmann if (ktime_get_boottime_seconds() > double_grace_period_end) 525203f318caSJ. Bruce Fields return false; 525303f318caSJ. Bruce Fields return true; 525403f318caSJ. Bruce Fields } 525503f318caSJ. Bruce Fields 525620b7d86fSArnd Bergmann static time64_t 525709121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 52581da177e4SLinus Torvalds { 52591da177e4SLinus Torvalds struct nfs4_client *clp; 5260fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 52611da177e4SLinus Torvalds struct nfs4_delegation *dp; 5262217526e7SJeff Layton struct nfs4_ol_stateid *stp; 52637919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 52641da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 526520b7d86fSArnd Bergmann time64_t cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease; 526620b7d86fSArnd Bergmann time64_t t, new_timeo = nn->nfsd4_lease; 5267624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 5268624322f1SOlga Kornievskaia copy_stateid_t *cps_t; 5269624322f1SOlga Kornievskaia int i; 52701da177e4SLinus Torvalds 52711da177e4SLinus Torvalds dprintk("NFSD: laundromat service - starting\n"); 527203f318caSJ. Bruce Fields 527303f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 527403f318caSJ. Bruce Fields new_timeo = 0; 527503f318caSJ. Bruce Fields goto out; 527603f318caSJ. Bruce Fields } 5277362063a5SScott Mayhew dprintk("NFSD: end of grace period\n"); 527812760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 527936acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 5280624322f1SOlga Kornievskaia 5281624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5282624322f1SOlga Kornievskaia idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { 5283624322f1SOlga Kornievskaia cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); 5284624322f1SOlga Kornievskaia if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID && 528520b7d86fSArnd Bergmann cps->cpntf_time > cutoff) 5286624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 5287624322f1SOlga Kornievskaia } 5288624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5289624322f1SOlga Kornievskaia 5290c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 52915ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 52921da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 529320b7d86fSArnd Bergmann if (clp->cl_time > cutoff) { 52941da177e4SLinus Torvalds t = clp->cl_time - cutoff; 5295a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 52961da177e4SLinus Torvalds break; 52971da177e4SLinus Torvalds } 5298221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 5299d7682988SBenny Halevy dprintk("NFSD: client in use (clientid %08x)\n", 5300d7682988SBenny Halevy clp->cl_clientid.cl_id); 5301d7682988SBenny Halevy continue; 5302d7682988SBenny Halevy } 53034864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 530436acb66bSBenny Halevy } 5305c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 530636acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 530736acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 53081da177e4SLinus Torvalds dprintk("NFSD: purging unused client (clientid %08x)\n", 53091da177e4SLinus Torvalds clp->cl_clientid.cl_id); 53104864af97STrond Myklebust list_del_init(&clp->cl_lru); 53111da177e4SLinus Torvalds expire_client(clp); 53121da177e4SLinus Torvalds } 5313cdc97505SBenny Halevy spin_lock(&state_lock); 5314e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 53151da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 531620b7d86fSArnd Bergmann if (dp->dl_time > cutoff) { 5317a832e7aeSJeff Layton t = dp->dl_time - cutoff; 5318a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 53191da177e4SLinus Torvalds break; 53201da177e4SLinus Torvalds } 53213fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 532242690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 53231da177e4SLinus Torvalds } 5324cdc97505SBenny Halevy spin_unlock(&state_lock); 53252d4a532dSJeff Layton while (!list_empty(&reaplist)) { 53262d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 53272d4a532dSJeff Layton dl_recall_lru); 53282d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 53293bd64a5bSJ. Bruce Fields revoke_delegation(dp); 53301da177e4SLinus Torvalds } 5331217526e7SJeff Layton 5332217526e7SJeff Layton spin_lock(&nn->client_lock); 5333217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 5334217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 5335217526e7SJeff Layton oo_close_lru); 533620b7d86fSArnd Bergmann if (oo->oo_time > cutoff) { 5337a832e7aeSJeff Layton t = oo->oo_time - cutoff; 5338a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 53391da177e4SLinus Torvalds break; 53401da177e4SLinus Torvalds } 5341217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 5342217526e7SJeff Layton stp = oo->oo_last_closed_stid; 5343217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 5344217526e7SJeff Layton spin_unlock(&nn->client_lock); 5345217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 5346217526e7SJeff Layton spin_lock(&nn->client_lock); 53471da177e4SLinus Torvalds } 5348217526e7SJeff Layton spin_unlock(&nn->client_lock); 5349217526e7SJeff Layton 53507919d0a2SJeff Layton /* 53517919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 53527919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 53537919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 53547919d0a2SJeff Layton * under the assumption that the client is no longer interested. 53557919d0a2SJeff Layton * 53567919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 53577919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 53587919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 53597919d0a2SJeff Layton * indefinitely once the lock does become free. 53607919d0a2SJeff Layton */ 53617919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 53620cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 53637919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 53647919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 53657919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 536620b7d86fSArnd Bergmann if (nbl->nbl_time > cutoff) { 53677919d0a2SJeff Layton t = nbl->nbl_time - cutoff; 53687919d0a2SJeff Layton new_timeo = min(new_timeo, t); 53697919d0a2SJeff Layton break; 53707919d0a2SJeff Layton } 53717919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 53727919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 53737919d0a2SJeff Layton } 53740cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 53757919d0a2SJeff Layton 53767919d0a2SJeff Layton while (!list_empty(&reaplist)) { 537764ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 53787919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 53797919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 53807919d0a2SJeff Layton free_blocked_lock(nbl); 53817919d0a2SJeff Layton } 538203f318caSJ. Bruce Fields out: 538320b7d86fSArnd Bergmann new_timeo = max_t(time64_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 5384a832e7aeSJeff Layton return new_timeo; 53851da177e4SLinus Torvalds } 53861da177e4SLinus Torvalds 5387a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 5388a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 5389a254b246SHarvey Harrison 5390a254b246SHarvey Harrison static void 539109121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 53921da177e4SLinus Torvalds { 539320b7d86fSArnd Bergmann time64_t t; 53942e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 539509121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 539609121281SStanislav Kinsbursky laundromat_work); 53971da177e4SLinus Torvalds 539809121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 539920b7d86fSArnd Bergmann dprintk("NFSD: laundromat_main - sleeping for %lld seconds\n", t); 540009121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 54011da177e4SLinus Torvalds } 54021da177e4SLinus Torvalds 54038fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 5404f8816512SNeilBrown { 54058fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 5406f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 5407f7a4d872SJ. Bruce Fields return nfs_ok; 54081da177e4SLinus Torvalds } 54091da177e4SLinus Torvalds 54101da177e4SLinus Torvalds static inline int 541182c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 54121da177e4SLinus Torvalds { 541382c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 541482c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 541582c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 54161da177e4SLinus Torvalds } 54171da177e4SLinus Torvalds 54181da177e4SLinus Torvalds static inline int 541982c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 54201da177e4SLinus Torvalds { 542182c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 542282c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 54231da177e4SLinus Torvalds } 54241da177e4SLinus Torvalds 54251da177e4SLinus Torvalds static 5426dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 54271da177e4SLinus Torvalds { 5428b37ad28bSAl Viro __be32 status = nfserr_openmode; 54291da177e4SLinus Torvalds 543002921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 543102921914SJ. Bruce Fields if (stp->st_openstp) 543202921914SJ. Bruce Fields stp = stp->st_openstp; 543382c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 54341da177e4SLinus Torvalds goto out; 543582c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 54361da177e4SLinus Torvalds goto out; 54371da177e4SLinus Torvalds status = nfs_ok; 54381da177e4SLinus Torvalds out: 54391da177e4SLinus Torvalds return status; 54401da177e4SLinus Torvalds } 54411da177e4SLinus Torvalds 5442b37ad28bSAl Viro static inline __be32 54435ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 54441da177e4SLinus Torvalds { 5445203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 54461da177e4SLinus Torvalds return nfs_ok; 5447c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 544825985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 54491da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 54501da177e4SLinus Torvalds return nfserr_grace; 54511da177e4SLinus Torvalds } else if (flags & WR_STATE) 54521da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 54531da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 54541da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 54551da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 54561da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 54571da177e4SLinus Torvalds } 54581da177e4SLinus Torvalds 54591da177e4SLinus Torvalds /* 54601da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 54611da177e4SLinus Torvalds * that are not able to provide mandatory locking. 54621da177e4SLinus Torvalds */ 54631da177e4SLinus Torvalds static inline int 54645ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 54651da177e4SLinus Torvalds { 5466c87fb4a3SJ. Bruce Fields return opens_in_grace(net) && mandatory_lock(inode); 54671da177e4SLinus Torvalds } 54681da177e4SLinus Torvalds 546957b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 54700836f587SJ. Bruce Fields { 54716668958fSAndy Adamson /* 54726668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 54736668958fSAndy Adamson * when it is zero. 54746668958fSAndy Adamson */ 547528dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 547681b82965SJ. Bruce Fields return nfs_ok; 547781b82965SJ. Bruce Fields 547881b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 547981b82965SJ. Bruce Fields return nfs_ok; 54806668958fSAndy Adamson 54810836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 548214b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 54830836f587SJ. Bruce Fields return nfserr_bad_stateid; 54840836f587SJ. Bruce Fields /* 548581b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 548681b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 548781b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 548881b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 548981b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 549081b82965SJ. Bruce Fields * but better performance may result in retrying IO that 549181b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 549281b82965SJ. Bruce Fields * reordered in flight: 54930836f587SJ. Bruce Fields */ 54940836f587SJ. Bruce Fields return nfserr_old_stateid; 54950836f587SJ. Bruce Fields } 54960836f587SJ. Bruce Fields 549703da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 549803da3169STrond Myklebust { 549903da3169STrond Myklebust __be32 ret; 550003da3169STrond Myklebust 550103da3169STrond Myklebust spin_lock(&s->sc_lock); 550203da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 550303da3169STrond Myklebust if (ret == nfs_ok) 550403da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 550503da3169STrond Myklebust spin_unlock(&s->sc_lock); 550603da3169STrond Myklebust return ret; 550703da3169STrond Myklebust } 550803da3169STrond Myklebust 5509ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 5510ebe9cb3bSChristoph Hellwig { 5511ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 5512ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 5513ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 5514ebe9cb3bSChristoph Hellwig return nfs_ok; 5515ebe9cb3bSChristoph Hellwig } 5516ebe9cb3bSChristoph Hellwig 55177df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 551817456804SBryan Schumaker { 551997b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 55201af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 552117456804SBryan Schumaker 5522ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5523ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 55241af71cc8SJeff Layton return status; 55257df302f7SChuck Lever /* Client debugging aid. */ 55267df302f7SChuck Lever if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { 55277df302f7SChuck Lever char addr_str[INET6_ADDRSTRLEN]; 55287df302f7SChuck Lever rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, 55297df302f7SChuck Lever sizeof(addr_str)); 55307df302f7SChuck Lever pr_warn_ratelimited("NFSD: client %s testing state ID " 55317df302f7SChuck Lever "with incorrect client ID\n", addr_str); 55321af71cc8SJeff Layton return status; 55337df302f7SChuck Lever } 55341af71cc8SJeff Layton spin_lock(&cl->cl_lock); 55351af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 553697b7e3b6SJ. Bruce Fields if (!s) 55371af71cc8SJeff Layton goto out_unlock; 553803da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 553917456804SBryan Schumaker if (status) 55401af71cc8SJeff Layton goto out_unlock; 554123340032SJ. Bruce Fields switch (s->sc_type) { 554223340032SJ. Bruce Fields case NFS4_DELEG_STID: 55431af71cc8SJeff Layton status = nfs_ok; 55441af71cc8SJeff Layton break; 55453bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 55461af71cc8SJeff Layton status = nfserr_deleg_revoked; 55471af71cc8SJeff Layton break; 554823340032SJ. Bruce Fields case NFS4_OPEN_STID: 554923340032SJ. Bruce Fields case NFS4_LOCK_STID: 5550ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 55511af71cc8SJeff Layton break; 555223340032SJ. Bruce Fields default: 555323340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 5554b0fc29d6STrond Myklebust /* Fallthrough */ 555523340032SJ. Bruce Fields case NFS4_CLOSED_STID: 5556b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 55571af71cc8SJeff Layton status = nfserr_bad_stateid; 555823340032SJ. Bruce Fields } 55591af71cc8SJeff Layton out_unlock: 55601af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 55611af71cc8SJeff Layton return status; 556217456804SBryan Schumaker } 556317456804SBryan Schumaker 5564cd61c522SChristoph Hellwig __be32 55652dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 55662dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 55672dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 556838c2f4b1SJ. Bruce Fields { 55690eb6f20aSJ. Bruce Fields __be32 status; 557095da1b3aSAndrew Elble bool return_revoked = false; 557195da1b3aSAndrew Elble 557295da1b3aSAndrew Elble /* 557395da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 557495da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 557595da1b3aSAndrew Elble */ 557695da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 557795da1b3aSAndrew Elble return_revoked = true; 557895da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 557995da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 558038c2f4b1SJ. Bruce Fields 5581ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5582ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 558338c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 5584b7342204SOlga Kornievskaia status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn, 5585b7342204SOlga Kornievskaia false); 5586a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 55874b24ca7dSJeff Layton if (cstate->session) 5588a8a7c677STrond Myklebust return nfserr_bad_stateid; 558938c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 5590a8a7c677STrond Myklebust } 55910eb6f20aSJ. Bruce Fields if (status) 55920eb6f20aSJ. Bruce Fields return status; 55934b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 559438c2f4b1SJ. Bruce Fields if (!*s) 559538c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 559695da1b3aSAndrew Elble if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 559795da1b3aSAndrew Elble nfs4_put_stid(*s); 559895da1b3aSAndrew Elble if (cstate->minorversion) 559995da1b3aSAndrew Elble return nfserr_deleg_revoked; 560095da1b3aSAndrew Elble return nfserr_bad_stateid; 560195da1b3aSAndrew Elble } 560238c2f4b1SJ. Bruce Fields return nfs_ok; 560338c2f4b1SJ. Bruce Fields } 560438c2f4b1SJ. Bruce Fields 5605eb82dd39SJeff Layton static struct nfsd_file * 5606a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 5607a0649b2dSChristoph Hellwig { 5608af90f707SChristoph Hellwig if (!s) 5609af90f707SChristoph Hellwig return NULL; 5610af90f707SChristoph Hellwig 5611a0649b2dSChristoph Hellwig switch (s->sc_type) { 5612a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 5613a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 5614a0649b2dSChristoph Hellwig return NULL; 5615eb82dd39SJeff Layton return nfsd_file_get(s->sc_file->fi_deleg_file); 5616a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 5617a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 5618a0649b2dSChristoph Hellwig if (flags & RD_STATE) 5619a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 5620a0649b2dSChristoph Hellwig else 5621a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 5622a0649b2dSChristoph Hellwig break; 5623a0649b2dSChristoph Hellwig } 5624a0649b2dSChristoph Hellwig 5625a0649b2dSChristoph Hellwig return NULL; 5626a0649b2dSChristoph Hellwig } 5627a0649b2dSChristoph Hellwig 5628a0649b2dSChristoph Hellwig static __be32 5629d8836f77SJ. Bruce Fields nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) 5630a0649b2dSChristoph Hellwig { 5631a0649b2dSChristoph Hellwig __be32 status; 5632a0649b2dSChristoph Hellwig 5633a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 5634a0649b2dSChristoph Hellwig if (status) 5635a0649b2dSChristoph Hellwig return status; 5636a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 5637a0649b2dSChristoph Hellwig } 5638a0649b2dSChristoph Hellwig 5639af90f707SChristoph Hellwig static __be32 5640af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 56415c4583b2SJeff Layton struct nfsd_file **nfp, int flags) 5642af90f707SChristoph Hellwig { 5643af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 5644eb82dd39SJeff Layton struct nfsd_file *nf; 5645af90f707SChristoph Hellwig __be32 status; 5646af90f707SChristoph Hellwig 5647eb82dd39SJeff Layton nf = nfs4_find_file(s, flags); 5648eb82dd39SJeff Layton if (nf) { 5649af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 5650af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 56515c4583b2SJeff Layton if (status) { 56525c4583b2SJeff Layton nfsd_file_put(nf); 5653eb82dd39SJeff Layton goto out; 56545c4583b2SJeff Layton } 5655af90f707SChristoph Hellwig } else { 5656eb82dd39SJeff Layton status = nfsd_file_acquire(rqstp, fhp, acc, &nf); 5657af90f707SChristoph Hellwig if (status) 5658af90f707SChristoph Hellwig return status; 5659af90f707SChristoph Hellwig } 56605c4583b2SJeff Layton *nfp = nf; 5661eb82dd39SJeff Layton out: 5662eb82dd39SJeff Layton return status; 5663af90f707SChristoph Hellwig } 5664624322f1SOlga Kornievskaia static void 5665624322f1SOlga Kornievskaia _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 5666624322f1SOlga Kornievskaia { 5667624322f1SOlga Kornievskaia WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID); 5668624322f1SOlga Kornievskaia if (!refcount_dec_and_test(&cps->cp_stateid.sc_count)) 5669624322f1SOlga Kornievskaia return; 5670624322f1SOlga Kornievskaia list_del(&cps->cp_list); 5671624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 5672624322f1SOlga Kornievskaia cps->cp_stateid.stid.si_opaque.so_id); 5673624322f1SOlga Kornievskaia kfree(cps); 5674624322f1SOlga Kornievskaia } 5675b7342204SOlga Kornievskaia /* 5676b7342204SOlga Kornievskaia * A READ from an inter server to server COPY will have a 5677b7342204SOlga Kornievskaia * copy stateid. Look up the copy notify stateid from the 5678b7342204SOlga Kornievskaia * idr structure and take a reference on it. 5679b7342204SOlga Kornievskaia */ 5680ce0887acSOlga Kornievskaia __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st, 5681ce0887acSOlga Kornievskaia struct nfs4_client *clp, 5682b7342204SOlga Kornievskaia struct nfs4_cpntf_state **cps) 5683b7342204SOlga Kornievskaia { 5684b7342204SOlga Kornievskaia copy_stateid_t *cps_t; 5685b7342204SOlga Kornievskaia struct nfs4_cpntf_state *state = NULL; 5686b7342204SOlga Kornievskaia 5687b7342204SOlga Kornievskaia if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id) 5688b7342204SOlga Kornievskaia return nfserr_bad_stateid; 5689b7342204SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5690b7342204SOlga Kornievskaia cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id); 5691b7342204SOlga Kornievskaia if (cps_t) { 5692b7342204SOlga Kornievskaia state = container_of(cps_t, struct nfs4_cpntf_state, 5693b7342204SOlga Kornievskaia cp_stateid); 56945277a79eSDan Carpenter if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID) { 56955277a79eSDan Carpenter state = NULL; 56965277a79eSDan Carpenter goto unlock; 56975277a79eSDan Carpenter } 5698ce0887acSOlga Kornievskaia if (!clp) 5699b7342204SOlga Kornievskaia refcount_inc(&state->cp_stateid.sc_count); 5700ce0887acSOlga Kornievskaia else 5701ce0887acSOlga Kornievskaia _free_cpntf_state_locked(nn, state); 5702b7342204SOlga Kornievskaia } 57035277a79eSDan Carpenter unlock: 5704b7342204SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5705b7342204SOlga Kornievskaia if (!state) 5706b7342204SOlga Kornievskaia return nfserr_bad_stateid; 5707ce0887acSOlga Kornievskaia if (!clp && state) 5708b7342204SOlga Kornievskaia *cps = state; 5709b7342204SOlga Kornievskaia return 0; 5710b7342204SOlga Kornievskaia } 5711b7342204SOlga Kornievskaia 5712b7342204SOlga Kornievskaia static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, 5713b7342204SOlga Kornievskaia struct nfs4_stid **stid) 5714b7342204SOlga Kornievskaia { 5715b7342204SOlga Kornievskaia __be32 status; 5716b7342204SOlga Kornievskaia struct nfs4_cpntf_state *cps = NULL; 5717b7342204SOlga Kornievskaia struct nfsd4_compound_state cstate; 5718b7342204SOlga Kornievskaia 5719ce0887acSOlga Kornievskaia status = manage_cpntf_state(nn, st, NULL, &cps); 5720b7342204SOlga Kornievskaia if (status) 5721b7342204SOlga Kornievskaia return status; 5722b7342204SOlga Kornievskaia 572320b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 5724b7342204SOlga Kornievskaia memset(&cstate, 0, sizeof(cstate)); 5725b7342204SOlga Kornievskaia status = lookup_clientid(&cps->cp_p_clid, &cstate, nn, true); 5726b7342204SOlga Kornievskaia if (status) 5727b7342204SOlga Kornievskaia goto out; 5728b7342204SOlga Kornievskaia status = nfsd4_lookup_stateid(&cstate, &cps->cp_p_stateid, 5729b7342204SOlga Kornievskaia NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 5730b7342204SOlga Kornievskaia stid, nn); 5731b7342204SOlga Kornievskaia put_client_renew(cstate.clp); 5732b7342204SOlga Kornievskaia out: 5733b7342204SOlga Kornievskaia nfs4_put_cpntf_state(nn, cps); 5734b7342204SOlga Kornievskaia return status; 5735b7342204SOlga Kornievskaia } 5736624322f1SOlga Kornievskaia 5737624322f1SOlga Kornievskaia void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 5738624322f1SOlga Kornievskaia { 5739624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5740624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 5741624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5742624322f1SOlga Kornievskaia } 5743af90f707SChristoph Hellwig 57441da177e4SLinus Torvalds /* 57451da177e4SLinus Torvalds * Checks for stateid operations 57461da177e4SLinus Torvalds */ 5747b37ad28bSAl Viro __be32 5748af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 5749aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 5750624322f1SOlga Kornievskaia stateid_t *stateid, int flags, struct nfsd_file **nfp, 5751624322f1SOlga Kornievskaia struct nfs4_stid **cstid) 57521da177e4SLinus Torvalds { 5753a0649b2dSChristoph Hellwig struct inode *ino = d_inode(fhp->fh_dentry); 5754af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 57553320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5756af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 5757b37ad28bSAl Viro __be32 status; 57581da177e4SLinus Torvalds 57595c4583b2SJeff Layton if (nfp) 57605c4583b2SJeff Layton *nfp = NULL; 57611da177e4SLinus Torvalds 57625ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 57631da177e4SLinus Torvalds return nfserr_grace; 57641da177e4SLinus Torvalds 5765af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 5766af90f707SChristoph Hellwig status = check_special_stateids(net, fhp, stateid, flags); 5767af90f707SChristoph Hellwig goto done; 5768af90f707SChristoph Hellwig } 57691da177e4SLinus Torvalds 57702dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 5771db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 57722dd6e458STrond Myklebust &s, nn); 5773b7342204SOlga Kornievskaia if (status == nfserr_bad_stateid) 5774b7342204SOlga Kornievskaia status = find_cpntf_state(nn, stateid, &s); 577538c2f4b1SJ. Bruce Fields if (status) 5776c2d1d6a8STrond Myklebust return status; 577703da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 5778a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 57790c2a498fSJ. Bruce Fields if (status) 57800c2a498fSJ. Bruce Fields goto out; 5781a0649b2dSChristoph Hellwig 5782f7a4d872SJ. Bruce Fields switch (s->sc_type) { 5783f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 5784a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 5785f7a4d872SJ. Bruce Fields break; 5786f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 5787f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 5788d8836f77SJ. Bruce Fields status = nfs4_check_olstateid(openlockstateid(s), flags); 5789f7a4d872SJ. Bruce Fields break; 5790f7a4d872SJ. Bruce Fields default: 579114bcab1aSTrond Myklebust status = nfserr_bad_stateid; 5792a0649b2dSChristoph Hellwig break; 57931da177e4SLinus Torvalds } 57948fcd461dSJeff Layton if (status) 57958fcd461dSJeff Layton goto out; 57968fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 5797a0649b2dSChristoph Hellwig 5798af90f707SChristoph Hellwig done: 57995c4583b2SJeff Layton if (status == nfs_ok && nfp) 58005c4583b2SJeff Layton status = nfs4_check_file(rqstp, fhp, s, nfp, flags); 58011da177e4SLinus Torvalds out: 5802624322f1SOlga Kornievskaia if (s) { 5803624322f1SOlga Kornievskaia if (!status && cstid) 5804624322f1SOlga Kornievskaia *cstid = s; 5805624322f1SOlga Kornievskaia else 5806fd911011STrond Myklebust nfs4_put_stid(s); 5807624322f1SOlga Kornievskaia } 58081da177e4SLinus Torvalds return status; 58091da177e4SLinus Torvalds } 58101da177e4SLinus Torvalds 5811e1ca12dfSBryan Schumaker /* 581217456804SBryan Schumaker * Test if the stateid is valid 581317456804SBryan Schumaker */ 581417456804SBryan Schumaker __be32 581517456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5816eb69853dSChristoph Hellwig union nfsd4_op_u *u) 581717456804SBryan Schumaker { 5818eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 581903cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 582003cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 582103cfb420SBryan Schumaker 582203cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 58237df302f7SChuck Lever stateid->ts_id_status = 58247df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 582503cfb420SBryan Schumaker 582617456804SBryan Schumaker return nfs_ok; 582717456804SBryan Schumaker } 582817456804SBryan Schumaker 582942691398SChuck Lever static __be32 583042691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 583142691398SChuck Lever { 583242691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 583342691398SChuck Lever __be32 ret; 583442691398SChuck Lever 5835659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 5836659aefb6STrond Myklebust if (ret) 5837659aefb6STrond Myklebust goto out_put_stid; 583842691398SChuck Lever 583942691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 584042691398SChuck Lever if (ret) 584142691398SChuck Lever goto out; 584242691398SChuck Lever 584342691398SChuck Lever ret = nfserr_locks_held; 584442691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 584542691398SChuck Lever lockowner(stp->st_stateowner))) 584642691398SChuck Lever goto out; 584742691398SChuck Lever 584842691398SChuck Lever release_lock_stateid(stp); 584942691398SChuck Lever ret = nfs_ok; 585042691398SChuck Lever 585142691398SChuck Lever out: 585242691398SChuck Lever mutex_unlock(&stp->st_mutex); 5853659aefb6STrond Myklebust out_put_stid: 585442691398SChuck Lever nfs4_put_stid(s); 585542691398SChuck Lever return ret; 585642691398SChuck Lever } 585742691398SChuck Lever 5858e1ca12dfSBryan Schumaker __be32 5859e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5860eb69853dSChristoph Hellwig union nfsd4_op_u *u) 5861e1ca12dfSBryan Schumaker { 5862eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 5863e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 58642da1cec7SJ. Bruce Fields struct nfs4_stid *s; 58653bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 586638c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 58672da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 5868e1ca12dfSBryan Schumaker 58691af71cc8SJeff Layton spin_lock(&cl->cl_lock); 58701af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 58712da1cec7SJ. Bruce Fields if (!s) 58721af71cc8SJeff Layton goto out_unlock; 587303da3169STrond Myklebust spin_lock(&s->sc_lock); 58742da1cec7SJ. Bruce Fields switch (s->sc_type) { 58752da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 5876e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 58771af71cc8SJeff Layton break; 58782da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 58791af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 58801af71cc8SJeff Layton if (ret) 58811af71cc8SJeff Layton break; 58821af71cc8SJeff Layton ret = nfserr_locks_held; 58831af71cc8SJeff Layton break; 58842da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 588503da3169STrond Myklebust spin_unlock(&s->sc_lock); 5886a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 58871af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 588842691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 58891af71cc8SJeff Layton goto out; 58903bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 589103da3169STrond Myklebust spin_unlock(&s->sc_lock); 58923bd64a5bSJ. Bruce Fields dp = delegstateid(s); 58932d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 58942d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 58956011695dSTrond Myklebust nfs4_put_stid(s); 58963bd64a5bSJ. Bruce Fields ret = nfs_ok; 58971af71cc8SJeff Layton goto out; 58981af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 5899e1ca12dfSBryan Schumaker } 590003da3169STrond Myklebust spin_unlock(&s->sc_lock); 59011af71cc8SJeff Layton out_unlock: 59021af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 5903e1ca12dfSBryan Schumaker out: 5904e1ca12dfSBryan Schumaker return ret; 5905e1ca12dfSBryan Schumaker } 5906e1ca12dfSBryan Schumaker 59074c4cd222SNeilBrown static inline int 59084c4cd222SNeilBrown setlkflg (int type) 59094c4cd222SNeilBrown { 59104c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 59114c4cd222SNeilBrown RD_STATE : WR_STATE; 59124c4cd222SNeilBrown } 59131da177e4SLinus Torvalds 5914dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 5915c0a5d93eSJ. Bruce Fields { 5916c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 5917c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 5918c0a5d93eSJ. Bruce Fields __be32 status; 5919c0a5d93eSJ. Bruce Fields 5920c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 5921c0a5d93eSJ. Bruce Fields if (status) 5922c0a5d93eSJ. Bruce Fields return status; 59239271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 59249271d7e5STrond Myklebust if (status != nfs_ok) 59259271d7e5STrond Myklebust return status; 5926f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 592735a92fe8SJeff Layton if (status == nfs_ok) 592835a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 592935a92fe8SJeff Layton if (status != nfs_ok) 5930feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 5931f7a4d872SJ. Bruce Fields return status; 5932c0a5d93eSJ. Bruce Fields } 5933c0a5d93eSJ. Bruce Fields 59341da177e4SLinus Torvalds /* 59351da177e4SLinus Torvalds * Checks for sequence id mutating operations. 59361da177e4SLinus Torvalds */ 5937b37ad28bSAl Viro static __be32 5938dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 59392288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 59403320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 59413320fef1SStanislav Kinsbursky struct nfsd_net *nn) 59421da177e4SLinus Torvalds { 59430836f587SJ. Bruce Fields __be32 status; 594438c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 5945e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 59461da177e4SLinus Torvalds 59478c10cbdbSBenny Halevy dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 59488c10cbdbSBenny Halevy seqid, STATEID_VAL(stateid)); 59491da177e4SLinus Torvalds 59501da177e4SLinus Torvalds *stpp = NULL; 59512dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 5952c0a5d93eSJ. Bruce Fields if (status) 5953c0a5d93eSJ. Bruce Fields return status; 5954e17f99b7STrond Myklebust stp = openlockstateid(s); 595558fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 59561da177e4SLinus Torvalds 5957e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 5958fd911011STrond Myklebust if (!status) 5959e17f99b7STrond Myklebust *stpp = stp; 5960fd911011STrond Myklebust else 5961fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 5962e17f99b7STrond Myklebust return status; 59631da177e4SLinus Torvalds } 59641da177e4SLinus Torvalds 59653320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 59663320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 5967c0a5d93eSJ. Bruce Fields { 5968c0a5d93eSJ. Bruce Fields __be32 status; 5969c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 59704cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 59711da177e4SLinus Torvalds 5972c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 59734cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 59740836f587SJ. Bruce Fields if (status) 59750836f587SJ. Bruce Fields return status; 59764cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 59774cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 5978feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 59794cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 5980c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 59814cbfc9f7STrond Myklebust } 59824cbfc9f7STrond Myklebust *stpp = stp; 59833a4f98bbSNeilBrown return nfs_ok; 59841da177e4SLinus Torvalds } 59851da177e4SLinus Torvalds 5986b37ad28bSAl Viro __be32 5987ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5988eb69853dSChristoph Hellwig union nfsd4_op_u *u) 59891da177e4SLinus Torvalds { 5990eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 5991b37ad28bSAl Viro __be32 status; 5992fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 5993dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 59943320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 59951da177e4SLinus Torvalds 5996a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 5997a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 59981da177e4SLinus Torvalds 5999ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 6000a8cddc5dSJ. Bruce Fields if (status) 6001a8cddc5dSJ. Bruce Fields return status; 60021da177e4SLinus Torvalds 60039072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 6004ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 60053320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 60069072d5c6SJ. Bruce Fields if (status) 60071da177e4SLinus Torvalds goto out; 6008fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 600968b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 601035a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 6011feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 60122585fc79STrond Myklebust goto put_stateid; 601335a92fe8SJeff Layton } 6014dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 60159767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 6016feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 60178c10cbdbSBenny Halevy dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 6018dcef0413SJ. Bruce Fields __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 6019c7b9a459SNeilBrown 60202a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 602168b66e82SJ. Bruce Fields status = nfs_ok; 60222585fc79STrond Myklebust put_stateid: 60232585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 60241da177e4SLinus Torvalds out: 60259411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 60261da177e4SLinus Torvalds return status; 60271da177e4SLinus Torvalds } 60281da177e4SLinus Torvalds 60296409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 60301da177e4SLinus Torvalds { 603182c5ff1bSJeff Layton if (!test_access(access, stp)) 60326409a5a6SJ. Bruce Fields return; 603311b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 603482c5ff1bSJeff Layton clear_access(access, stp); 6035f197c271SJ. Bruce Fields } 60366409a5a6SJ. Bruce Fields 60376409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 60386409a5a6SJ. Bruce Fields { 60396409a5a6SJ. Bruce Fields switch (to_access) { 60406409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 60416409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 60426409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 60436409a5a6SJ. Bruce Fields break; 60446409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 60456409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 60466409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 60476409a5a6SJ. Bruce Fields break; 60486409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 60496409a5a6SJ. Bruce Fields break; 60506409a5a6SJ. Bruce Fields default: 6051063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 60521da177e4SLinus Torvalds } 60531da177e4SLinus Torvalds } 60541da177e4SLinus Torvalds 6055b37ad28bSAl Viro __be32 6056ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 6057eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 60581da177e4SLinus Torvalds { 6059eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 6060b37ad28bSAl Viro __be32 status; 6061dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 60623320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 60631da177e4SLinus Torvalds 6064a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 6065a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 60661da177e4SLinus Torvalds 6067c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 60682c8bd7e0SBenny Halevy if (od->od_deleg_want) 60692c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 60702c8bd7e0SBenny Halevy od->od_deleg_want); 60711da177e4SLinus Torvalds 6072c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 60733320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 60749072d5c6SJ. Bruce Fields if (status) 60751da177e4SLinus Torvalds goto out; 60761da177e4SLinus Torvalds status = nfserr_inval; 607782c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 6078c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 60791da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 60800667b1e9STrond Myklebust goto put_stateid; 60811da177e4SLinus Torvalds } 6082ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 6083c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 60841da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 60850667b1e9STrond Myklebust goto put_stateid; 60861da177e4SLinus Torvalds } 60876409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 6088ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 60899767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 60901da177e4SLinus Torvalds status = nfs_ok; 60910667b1e9STrond Myklebust put_stateid: 6092feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 60930667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 60941da177e4SLinus Torvalds out: 60959411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 60961da177e4SLinus Torvalds return status; 60971da177e4SLinus Torvalds } 60981da177e4SLinus Torvalds 6099f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 6100f7a4d872SJ. Bruce Fields { 6101acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 6102e8568739SJeff Layton bool unhashed; 6103d83017f9SJeff Layton LIST_HEAD(reaplist); 6104acf9295bSTrond Myklebust 61052c41beb0SJeff Layton spin_lock(&clp->cl_lock); 6106e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 6107acf9295bSTrond Myklebust 6108d83017f9SJeff Layton if (clp->cl_minorversion) { 6109e8568739SJeff Layton if (unhashed) 6110d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 6111d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6112d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6113d83017f9SJeff Layton } else { 6114d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6115d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6116e8568739SJeff Layton if (unhashed) 6117d3134b10SJeff Layton move_to_close_lru(s, clp->net); 611838c387b5SJ. Bruce Fields } 6119d83017f9SJeff Layton } 612038c387b5SJ. Bruce Fields 61211da177e4SLinus Torvalds /* 61221da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 61231da177e4SLinus Torvalds */ 6124b37ad28bSAl Viro __be32 6125ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6126eb69853dSChristoph Hellwig union nfsd4_op_u *u) 61271da177e4SLinus Torvalds { 6128eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 6129b37ad28bSAl Viro __be32 status; 6130dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 61313320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 61323320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 61331da177e4SLinus Torvalds 6134a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 6135a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 61361da177e4SLinus Torvalds 6137f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 6138f7a4d872SJ. Bruce Fields &close->cl_stateid, 6139f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 61403320fef1SStanislav Kinsbursky &stp, nn); 61419411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 61429072d5c6SJ. Bruce Fields if (status) 61431da177e4SLinus Torvalds goto out; 614415ca08d3STrond Myklebust 614515ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 6146bd2decacSJeff Layton 6147bd2decacSJeff Layton /* 6148bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 6149bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 6150bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 6151bd2decacSJeff Layton * that racing ops see that there was a state change. 6152bd2decacSJeff Layton */ 61539767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 61541da177e4SLinus Torvalds 6155f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 615615ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 61578a0b589dSTrond Myklebust 6158bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 6159bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 6160bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 6161bd2decacSJeff Layton * universally. 6162bd2decacSJeff Layton * 6163bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 6164bd2decacSJeff Layton */ 6165bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 6166fb500a7cSTrond Myklebust 61678a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 61688a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 61691da177e4SLinus Torvalds out: 61701da177e4SLinus Torvalds return status; 61711da177e4SLinus Torvalds } 61721da177e4SLinus Torvalds 6173b37ad28bSAl Viro __be32 6174ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6175eb69853dSChristoph Hellwig union nfsd4_op_u *u) 61761da177e4SLinus Torvalds { 6177eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 6178203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 6179203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 618038c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6181b37ad28bSAl Viro __be32 status; 61823320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 61831da177e4SLinus Torvalds 6184ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 6185203a8c8eSJ. Bruce Fields return status; 61861da177e4SLinus Torvalds 61872dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 618838c2f4b1SJ. Bruce Fields if (status) 6189203a8c8eSJ. Bruce Fields goto out; 619038c2f4b1SJ. Bruce Fields dp = delegstateid(s); 619103da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 6192203a8c8eSJ. Bruce Fields if (status) 6193fd911011STrond Myklebust goto put_stateid; 6194203a8c8eSJ. Bruce Fields 61953bd64a5bSJ. Bruce Fields destroy_delegation(dp); 6196fd911011STrond Myklebust put_stateid: 6197fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 61981da177e4SLinus Torvalds out: 61991da177e4SLinus Torvalds return status; 62001da177e4SLinus Torvalds } 62011da177e4SLinus Torvalds 620287df4de8SBenny Halevy static inline u64 620387df4de8SBenny Halevy end_offset(u64 start, u64 len) 620487df4de8SBenny Halevy { 620587df4de8SBenny Halevy u64 end; 620687df4de8SBenny Halevy 620787df4de8SBenny Halevy end = start + len; 620887df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 620987df4de8SBenny Halevy } 621087df4de8SBenny Halevy 621187df4de8SBenny Halevy /* last octet in a range */ 621287df4de8SBenny Halevy static inline u64 621387df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 621487df4de8SBenny Halevy { 621587df4de8SBenny Halevy u64 end; 621687df4de8SBenny Halevy 6217063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 621887df4de8SBenny Halevy end = start + len; 621987df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 622087df4de8SBenny Halevy } 622187df4de8SBenny Halevy 62221da177e4SLinus Torvalds /* 62231da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 62241da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 62251da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 62261da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 62271da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 62281da177e4SLinus Torvalds * the VFS, but this is a very deep change! 62291da177e4SLinus Torvalds */ 62301da177e4SLinus Torvalds static inline void 62311da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 62321da177e4SLinus Torvalds { 62331da177e4SLinus Torvalds if (lock->fl_start < 0) 62341da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 62351da177e4SLinus Torvalds if (lock->fl_end < 0) 62361da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 62371da177e4SLinus Torvalds } 62381da177e4SLinus Torvalds 6239cae80b30SJeff Layton static fl_owner_t 6240cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner) 6241aef9583bSKinglong Mee { 6242cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6243cae80b30SJeff Layton 6244cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 6245cae80b30SJeff Layton return owner; 6246aef9583bSKinglong Mee } 6247aef9583bSKinglong Mee 6248cae80b30SJeff Layton static void 6249cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner) 6250aef9583bSKinglong Mee { 6251cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6252aef9583bSKinglong Mee 6253cae80b30SJeff Layton if (lo) 6254aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 6255aef9583bSKinglong Mee } 6256aef9583bSKinglong Mee 625776d348faSJeff Layton static void 625876d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 625976d348faSJeff Layton { 626076d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 626176d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 626276d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 626376d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 626476d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 626576d348faSJeff Layton bool queue = false; 626676d348faSJeff Layton 62677919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 62680cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 626976d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 627076d348faSJeff Layton list_del_init(&nbl->nbl_list); 62717919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 627276d348faSJeff Layton queue = true; 627376d348faSJeff Layton } 62740cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 627576d348faSJeff Layton 627676d348faSJeff Layton if (queue) 627776d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 627876d348faSJeff Layton } 627976d348faSJeff Layton 62807b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 628176d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 6282aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 6283aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 6284d5b9026aSNeilBrown }; 62851da177e4SLinus Torvalds 62861da177e4SLinus Torvalds static inline void 62871da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 62881da177e4SLinus Torvalds { 6289fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 62901da177e4SLinus Torvalds 6291d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 6292fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 62936f4859b8SJ. Bruce Fields xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner, 62946f4859b8SJ. Bruce Fields GFP_KERNEL); 62957c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 62967c13f344SJ. Bruce Fields /* We just don't care that much */ 62977c13f344SJ. Bruce Fields goto nevermind; 6298fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 6299d5b9026aSNeilBrown } else { 63007c13f344SJ. Bruce Fields nevermind: 63017c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 63027c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 6303d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 6304d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 63051da177e4SLinus Torvalds } 63061da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 630787df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 630887df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 63091da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 63101da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 63111da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 63121da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 63131da177e4SLinus Torvalds } 63141da177e4SLinus Torvalds 6315fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6316c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 63171da177e4SLinus Torvalds { 6318d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 6319b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 63201da177e4SLinus Torvalds 63210a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 63220a880a28STrond Myklebust 6323d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 6324d4f0489fSTrond Myklebust so_strhash) { 6325b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 6326b3c32bcdSTrond Myklebust continue; 6327b5971afaSKinglong Mee if (same_owner_str(so, owner)) 6328b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 63291da177e4SLinus Torvalds } 63301da177e4SLinus Torvalds return NULL; 63311da177e4SLinus Torvalds } 63321da177e4SLinus Torvalds 6333c58c6610STrond Myklebust static struct nfs4_lockowner * 6334c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 6335c58c6610STrond Myklebust { 6336c58c6610STrond Myklebust struct nfs4_lockowner *lo; 6337c58c6610STrond Myklebust 6338d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6339c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 6340d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6341c58c6610STrond Myklebust return lo; 6342c58c6610STrond Myklebust } 6343c58c6610STrond Myklebust 63448f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 63458f4b54c5SJeff Layton { 6346c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 63478f4b54c5SJeff Layton } 63488f4b54c5SJeff Layton 63496b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 63506b180f0bSJeff Layton { 63516b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 63526b180f0bSJeff Layton 63536b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 63546b180f0bSJeff Layton } 63556b180f0bSJeff Layton 63566b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 63578f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 63586b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 63596b180f0bSJeff Layton }; 63606b180f0bSJeff Layton 63611da177e4SLinus Torvalds /* 63621da177e4SLinus Torvalds * Alloc a lock owner structure. 63631da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 636425985edcSLucas De Marchi * occurred. 63651da177e4SLinus Torvalds * 636616bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 63671da177e4SLinus Torvalds */ 6368fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6369c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 6370c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 6371c58c6610STrond Myklebust struct nfsd4_lock *lock) 6372c58c6610STrond Myklebust { 6373c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 63741da177e4SLinus Torvalds 6375fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 6376fe0750e5SJ. Bruce Fields if (!lo) 63771da177e4SLinus Torvalds return NULL; 637876d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 6379fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 6380fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 63815db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 63826b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 6383d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6384c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 6385c58c6610STrond Myklebust if (ret == NULL) { 6386c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 6387d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 6388c58c6610STrond Myklebust ret = lo; 6389c58c6610STrond Myklebust } else 6390d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 6391d50ffdedSKinglong Mee 6392d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6393340f0ba1SJ. Bruce Fields return ret; 63941da177e4SLinus Torvalds } 63951da177e4SLinus Torvalds 6396fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 6397fd1fd685STrond Myklebust find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) 6398fd1fd685STrond Myklebust { 6399fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 6400fd1fd685STrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 6401fd1fd685STrond Myklebust 6402fd1fd685STrond Myklebust lockdep_assert_held(&clp->cl_lock); 6403fd1fd685STrond Myklebust 6404fd1fd685STrond Myklebust list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { 6405fd1fd685STrond Myklebust if (lst->st_stid.sc_type != NFS4_LOCK_STID) 6406fd1fd685STrond Myklebust continue; 6407fd1fd685STrond Myklebust if (lst->st_stid.sc_file == fp) { 6408fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 6409fd1fd685STrond Myklebust return lst; 6410fd1fd685STrond Myklebust } 6411fd1fd685STrond Myklebust } 6412fd1fd685STrond Myklebust return NULL; 6413fd1fd685STrond Myklebust } 6414fd1fd685STrond Myklebust 6415beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 6416356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 6417356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 6418f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 64191da177e4SLinus Torvalds { 6420d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 6421beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 64221da177e4SLinus Torvalds 6423beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 64244f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 6425beeca19cSTrond Myklebust retry: 6426beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 6427beeca19cSTrond Myklebust spin_lock(&fp->fi_lock); 6428beeca19cSTrond Myklebust retstp = find_lock_stateid(lo, fp); 6429beeca19cSTrond Myklebust if (retstp) 6430beeca19cSTrond Myklebust goto out_unlock; 6431356a95ecSJeff Layton 6432a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 64333abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 6434b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 643513cd2184SNeilBrown get_nfs4_file(fp); 643611b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 64370997b173SJ. Bruce Fields stp->st_access_bmap = 0; 64381da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 64394c4cd222SNeilBrown stp->st_openstp = open_stp; 64403c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 64411c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 64421d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 6443beeca19cSTrond Myklebust out_unlock: 64441d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 6445beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 6446beeca19cSTrond Myklebust if (retstp) { 6447beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 6448beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 6449beeca19cSTrond Myklebust goto retry; 6450beeca19cSTrond Myklebust } 6451beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 6452beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 6453beeca19cSTrond Myklebust stp = retstp; 6454beeca19cSTrond Myklebust } 6455beeca19cSTrond Myklebust return stp; 64561da177e4SLinus Torvalds } 64571da177e4SLinus Torvalds 6458c53530daSJeff Layton static struct nfs4_ol_stateid * 6459356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 6460356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 6461356a95ecSJeff Layton bool *new) 6462356a95ecSJeff Layton { 6463356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 6464356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 6465356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 6466356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 6467356a95ecSJeff Layton 6468beeca19cSTrond Myklebust *new = false; 6469356a95ecSJeff Layton spin_lock(&clp->cl_lock); 6470356a95ecSJeff Layton lst = find_lock_stateid(lo, fi); 6471356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 6472beeca19cSTrond Myklebust if (lst != NULL) { 6473beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 6474beeca19cSTrond Myklebust goto out; 6475beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 6476beeca19cSTrond Myklebust } 6477d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 6478356a95ecSJeff Layton if (ns == NULL) 6479356a95ecSJeff Layton return NULL; 6480356a95ecSJeff Layton 6481beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 6482beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 6483356a95ecSJeff Layton *new = true; 6484beeca19cSTrond Myklebust else 6485356a95ecSJeff Layton nfs4_put_stid(ns); 6486beeca19cSTrond Myklebust out: 6487356a95ecSJeff Layton return lst; 6488356a95ecSJeff Layton } 6489c53530daSJeff Layton 6490fd39ca9aSNeilBrown static int 64911da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 64921da177e4SLinus Torvalds { 649387df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 6494e7969315SKinglong Mee (length > ~offset))); 64951da177e4SLinus Torvalds } 64961da177e4SLinus Torvalds 6497dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 64980997b173SJ. Bruce Fields { 649911b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 65000997b173SJ. Bruce Fields 65017214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 65027214e860SJeff Layton 650382c5ff1bSJeff Layton if (test_access(access, lock_stp)) 65040997b173SJ. Bruce Fields return; 650512659651SJeff Layton __nfs4_file_get_access(fp, access); 650682c5ff1bSJeff Layton set_access(access, lock_stp); 65070997b173SJ. Bruce Fields } 65080997b173SJ. Bruce Fields 6509356a95ecSJeff Layton static __be32 6510356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 6511356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 6512356a95ecSJeff Layton struct nfsd4_lock *lock, 6513dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 651464a284d0SJ. Bruce Fields { 65155db1c03fSJeff Layton __be32 status; 651611b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 651764a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 651864a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 65192b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 652064a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 6521dd257933SJeff Layton struct nfs4_ol_stateid *lst; 652264a284d0SJ. Bruce Fields unsigned int strhashval; 652364a284d0SJ. Bruce Fields 6524c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 6525c53530daSJeff Layton if (!lo) { 652676f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 652764a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 652864a284d0SJ. Bruce Fields if (lo == NULL) 652964a284d0SJ. Bruce Fields return nfserr_jukebox; 6530c53530daSJeff Layton } else { 6531c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 65325db1c03fSJeff Layton status = nfserr_bad_seqid; 6533c53530daSJeff Layton if (!cstate->minorversion && 6534c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 65355db1c03fSJeff Layton goto out; 6536c53530daSJeff Layton } 6537c53530daSJeff Layton 6538dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 6539dd257933SJeff Layton if (lst == NULL) { 65405db1c03fSJeff Layton status = nfserr_jukebox; 65415db1c03fSJeff Layton goto out; 654264a284d0SJ. Bruce Fields } 6543dd257933SJeff Layton 65445db1c03fSJeff Layton status = nfs_ok; 6545dd257933SJeff Layton *plst = lst; 65465db1c03fSJeff Layton out: 65475db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 65485db1c03fSJeff Layton return status; 654964a284d0SJ. Bruce Fields } 655064a284d0SJ. Bruce Fields 65511da177e4SLinus Torvalds /* 65521da177e4SLinus Torvalds * LOCK operation 65531da177e4SLinus Torvalds */ 6554b37ad28bSAl Viro __be32 6555ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6556eb69853dSChristoph Hellwig union nfsd4_op_u *u) 65571da177e4SLinus Torvalds { 6558eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 6559fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 6560fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 65613d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 65620667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 65637214e860SJeff Layton struct nfs4_file *fp; 6564eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 656576d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 656621179d81SJeff Layton struct file_lock *file_lock = NULL; 656721179d81SJeff Layton struct file_lock *conflock = NULL; 6568b37ad28bSAl Viro __be32 status = 0; 6569b34f27aaSJ. Bruce Fields int lkflg; 6570b8dd7b9aSAl Viro int err; 65715db1c03fSJeff Layton bool new = false; 657276d348faSJeff Layton unsigned char fl_type; 657376d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 65743320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 65753320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 65761da177e4SLinus Torvalds 65771da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 65781da177e4SLinus Torvalds (long long) lock->lk_offset, 65791da177e4SLinus Torvalds (long long) lock->lk_length); 65801da177e4SLinus Torvalds 65811da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 65821da177e4SLinus Torvalds return nfserr_inval; 65831da177e4SLinus Torvalds 6584ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 65858837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 6586a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 6587a6f6ef2fSAndy Adamson return status; 6588a6f6ef2fSAndy Adamson } 6589a6f6ef2fSAndy Adamson 65901da177e4SLinus Torvalds if (lock->lk_is_new) { 6591684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 6592684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 659376f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 6594684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 6595684e5638SJ. Bruce Fields sizeof(clientid_t)); 6596684e5638SJ. Bruce Fields 65971da177e4SLinus Torvalds status = nfserr_stale_clientid; 65982c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 65991da177e4SLinus Torvalds goto out; 66001da177e4SLinus Torvalds 66011da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 6602c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 66031da177e4SLinus Torvalds lock->lk_new_open_seqid, 66041da177e4SLinus Torvalds &lock->lk_new_open_stateid, 66053320fef1SStanislav Kinsbursky &open_stp, nn); 660637515177SNeilBrown if (status) 66071da177e4SLinus Torvalds goto out; 6608feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 6609fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 6610b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 6611684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 661276f6c9e1SKinglong Mee &lock->lk_new_clientid)) 6613b34f27aaSJ. Bruce Fields goto out; 661464a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 66155db1c03fSJeff Layton &lock_stp, &new); 66163d0fabd5STrond Myklebust } else { 6617dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 66181da177e4SLinus Torvalds lock->lk_old_lock_seqid, 66191da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 66203320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 66213d0fabd5STrond Myklebust } 66221da177e4SLinus Torvalds if (status) 66231da177e4SLinus Torvalds goto out; 6624fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 66251da177e4SLinus Torvalds 6626b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 6627b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 6628b34f27aaSJ. Bruce Fields if (status) 6629b34f27aaSJ. Bruce Fields goto out; 6630b34f27aaSJ. Bruce Fields 66310dd395dcSNeilBrown status = nfserr_grace; 66323320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 66330dd395dcSNeilBrown goto out; 66340dd395dcSNeilBrown status = nfserr_no_grace; 66353320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 66360dd395dcSNeilBrown goto out; 66370dd395dcSNeilBrown 663811b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 66391da177e4SLinus Torvalds switch (lock->lk_type) { 66401da177e4SLinus Torvalds case NFS4_READW_LT: 664176d348faSJeff Layton if (nfsd4_has_session(cstate)) 664276d348faSJeff Layton fl_flags |= FL_SLEEP; 664376d348faSJeff Layton /* Fallthrough */ 664476d348faSJeff Layton case NFS4_READ_LT: 66457214e860SJeff Layton spin_lock(&fp->fi_lock); 6646eb82dd39SJeff Layton nf = find_readable_file_locked(fp); 6647eb82dd39SJeff Layton if (nf) 66480997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 66497214e860SJeff Layton spin_unlock(&fp->fi_lock); 665076d348faSJeff Layton fl_type = F_RDLCK; 66511da177e4SLinus Torvalds break; 66521da177e4SLinus Torvalds case NFS4_WRITEW_LT: 665376d348faSJeff Layton if (nfsd4_has_session(cstate)) 665476d348faSJeff Layton fl_flags |= FL_SLEEP; 665576d348faSJeff Layton /* Fallthrough */ 665676d348faSJeff Layton case NFS4_WRITE_LT: 66577214e860SJeff Layton spin_lock(&fp->fi_lock); 6658eb82dd39SJeff Layton nf = find_writeable_file_locked(fp); 6659eb82dd39SJeff Layton if (nf) 66600997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 66617214e860SJeff Layton spin_unlock(&fp->fi_lock); 666276d348faSJeff Layton fl_type = F_WRLCK; 66631da177e4SLinus Torvalds break; 66641da177e4SLinus Torvalds default: 66651da177e4SLinus Torvalds status = nfserr_inval; 66661da177e4SLinus Torvalds goto out; 66671da177e4SLinus Torvalds } 666876d348faSJeff Layton 6669eb82dd39SJeff Layton if (!nf) { 6670f9d7562fSJ. Bruce Fields status = nfserr_openmode; 6671f9d7562fSJ. Bruce Fields goto out; 6672f9d7562fSJ. Bruce Fields } 6673aef9583bSKinglong Mee 667476d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 667576d348faSJeff Layton if (!nbl) { 667676d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 667776d348faSJeff Layton status = nfserr_jukebox; 667876d348faSJeff Layton goto out; 667976d348faSJeff Layton } 668076d348faSJeff Layton 668176d348faSJeff Layton file_lock = &nbl->nbl_lock; 668276d348faSJeff Layton file_lock->fl_type = fl_type; 6683aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 668421179d81SJeff Layton file_lock->fl_pid = current->tgid; 6685eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 668676d348faSJeff Layton file_lock->fl_flags = fl_flags; 668721179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 668821179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 668921179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 669021179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 66911da177e4SLinus Torvalds 669221179d81SJeff Layton conflock = locks_alloc_lock(); 669321179d81SJeff Layton if (!conflock) { 669421179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 669521179d81SJeff Layton status = nfserr_jukebox; 669621179d81SJeff Layton goto out; 669721179d81SJeff Layton } 66981da177e4SLinus Torvalds 669976d348faSJeff Layton if (fl_flags & FL_SLEEP) { 670020b7d86fSArnd Bergmann nbl->nbl_time = ktime_get_boottime_seconds(); 67010cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 670276d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 67037919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 67040cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 670576d348faSJeff Layton } 670676d348faSJeff Layton 6707eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, conflock); 670876d348faSJeff Layton switch (err) { 67091da177e4SLinus Torvalds case 0: /* success! */ 67109767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 6711b8dd7b9aSAl Viro status = 0; 671203f318caSJ. Bruce Fields if (lock->lk_reclaim) 671303f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 6714eb76b3fdSAndy Adamson break; 671576d348faSJeff Layton case FILE_LOCK_DEFERRED: 671676d348faSJeff Layton nbl = NULL; 671776d348faSJeff Layton /* Fallthrough */ 671876d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 6719eb76b3fdSAndy Adamson status = nfserr_denied; 6720eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 672121179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 6722eb76b3fdSAndy Adamson break; 672376d348faSJeff Layton case -EDEADLK: 67241da177e4SLinus Torvalds status = nfserr_deadlock; 6725eb76b3fdSAndy Adamson break; 67261da177e4SLinus Torvalds default: 6727fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 67283e772463SJ. Bruce Fields status = nfserrno(err); 6729eb76b3fdSAndy Adamson break; 67301da177e4SLinus Torvalds } 67311da177e4SLinus Torvalds out: 673276d348faSJeff Layton if (nbl) { 673376d348faSJeff Layton /* dequeue it if we queued it before */ 673476d348faSJeff Layton if (fl_flags & FL_SLEEP) { 67350cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 673676d348faSJeff Layton list_del_init(&nbl->nbl_list); 67377919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 67380cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 673976d348faSJeff Layton } 674076d348faSJeff Layton free_blocked_lock(nbl); 674176d348faSJeff Layton } 6742eb82dd39SJeff Layton if (nf) 6743eb82dd39SJeff Layton nfsd_file_put(nf); 67445db1c03fSJeff Layton if (lock_stp) { 67455db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 67465db1c03fSJeff Layton if (cstate->replay_owner && 67475db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 67485db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 67495db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 67505db1c03fSJeff Layton 67515db1c03fSJeff Layton /* 67525db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 67535db1c03fSJeff Layton * returning an error, then just go ahead and release it. 67545db1c03fSJeff Layton */ 675525020720SJ. Bruce Fields if (status && new) 67565db1c03fSJeff Layton release_lock_stateid(lock_stp); 6757beeca19cSTrond Myklebust 6758beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 67595db1c03fSJeff Layton 67603d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 67615db1c03fSJeff Layton } 67620667b1e9STrond Myklebust if (open_stp) 67630667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 67649411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 676521179d81SJeff Layton if (conflock) 676621179d81SJeff Layton locks_free_lock(conflock); 67671da177e4SLinus Torvalds return status; 67681da177e4SLinus Torvalds } 67691da177e4SLinus Torvalds 67701da177e4SLinus Torvalds /* 677155ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 677255ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 677355ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 677455ef1274SJ. Bruce Fields * inode operation.) 677555ef1274SJ. Bruce Fields */ 677604da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 677755ef1274SJ. Bruce Fields { 67786b556ca2SJeff Layton struct nfsd_file *nf; 67796b556ca2SJeff Layton __be32 err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); 678004da6e9dSAl Viro if (!err) { 67816b556ca2SJeff Layton err = nfserrno(vfs_test_lock(nf->nf_file, lock)); 67826b556ca2SJeff Layton nfsd_file_put(nf); 678304da6e9dSAl Viro } 678455ef1274SJ. Bruce Fields return err; 678555ef1274SJ. Bruce Fields } 678655ef1274SJ. Bruce Fields 678755ef1274SJ. Bruce Fields /* 67881da177e4SLinus Torvalds * LOCKT operation 67891da177e4SLinus Torvalds */ 6790b37ad28bSAl Viro __be32 6791ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6792eb69853dSChristoph Hellwig union nfsd4_op_u *u) 67931da177e4SLinus Torvalds { 6794eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 679521179d81SJeff Layton struct file_lock *file_lock = NULL; 67965db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 6797b37ad28bSAl Viro __be32 status; 67987f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 67991da177e4SLinus Torvalds 68005ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 68011da177e4SLinus Torvalds return nfserr_grace; 68021da177e4SLinus Torvalds 68031da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 68041da177e4SLinus Torvalds return nfserr_inval; 68051da177e4SLinus Torvalds 68069b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 6807b7342204SOlga Kornievskaia status = lookup_clientid(&lockt->lt_clientid, cstate, nn, 6808b7342204SOlga Kornievskaia false); 68099b2ef62bSJ. Bruce Fields if (status) 68101da177e4SLinus Torvalds goto out; 68119b2ef62bSJ. Bruce Fields } 68121da177e4SLinus Torvalds 681375c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 68141da177e4SLinus Torvalds goto out; 68151da177e4SLinus Torvalds 681621179d81SJeff Layton file_lock = locks_alloc_lock(); 681721179d81SJeff Layton if (!file_lock) { 681821179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 681921179d81SJeff Layton status = nfserr_jukebox; 682021179d81SJeff Layton goto out; 682121179d81SJeff Layton } 68226cd90662SKinglong Mee 68231da177e4SLinus Torvalds switch (lockt->lt_type) { 68241da177e4SLinus Torvalds case NFS4_READ_LT: 68251da177e4SLinus Torvalds case NFS4_READW_LT: 682621179d81SJeff Layton file_lock->fl_type = F_RDLCK; 68271da177e4SLinus Torvalds break; 68281da177e4SLinus Torvalds case NFS4_WRITE_LT: 68291da177e4SLinus Torvalds case NFS4_WRITEW_LT: 683021179d81SJeff Layton file_lock->fl_type = F_WRLCK; 68311da177e4SLinus Torvalds break; 68321da177e4SLinus Torvalds default: 68332fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 68341da177e4SLinus Torvalds status = nfserr_inval; 68351da177e4SLinus Torvalds goto out; 68361da177e4SLinus Torvalds } 68371da177e4SLinus Torvalds 6838c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 6839fe0750e5SJ. Bruce Fields if (lo) 684021179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 684121179d81SJeff Layton file_lock->fl_pid = current->tgid; 684221179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 68431da177e4SLinus Torvalds 684421179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 684521179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 68461da177e4SLinus Torvalds 684721179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 68481da177e4SLinus Torvalds 684921179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 685004da6e9dSAl Viro if (status) 6851fd85b817SMarc Eshel goto out; 685204da6e9dSAl Viro 685321179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 68541da177e4SLinus Torvalds status = nfserr_denied; 685521179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 68561da177e4SLinus Torvalds } 68571da177e4SLinus Torvalds out: 68585db1c03fSJeff Layton if (lo) 68595db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 686021179d81SJeff Layton if (file_lock) 686121179d81SJeff Layton locks_free_lock(file_lock); 68621da177e4SLinus Torvalds return status; 68631da177e4SLinus Torvalds } 68641da177e4SLinus Torvalds 6865b37ad28bSAl Viro __be32 6866ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6867eb69853dSChristoph Hellwig union nfsd4_op_u *u) 68681da177e4SLinus Torvalds { 6869eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 6870dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 6871eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 687221179d81SJeff Layton struct file_lock *file_lock = NULL; 6873b37ad28bSAl Viro __be32 status; 6874b8dd7b9aSAl Viro int err; 68753320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 68761da177e4SLinus Torvalds 68771da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 68781da177e4SLinus Torvalds (long long) locku->lu_offset, 68791da177e4SLinus Torvalds (long long) locku->lu_length); 68801da177e4SLinus Torvalds 68811da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 68821da177e4SLinus Torvalds return nfserr_inval; 68831da177e4SLinus Torvalds 68849072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 68853320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 68863320fef1SStanislav Kinsbursky &stp, nn); 68879072d5c6SJ. Bruce Fields if (status) 68881da177e4SLinus Torvalds goto out; 6889eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 6890eb82dd39SJeff Layton if (!nf) { 6891f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 6892858cc573STrond Myklebust goto put_stateid; 6893f9d7562fSJ. Bruce Fields } 689421179d81SJeff Layton file_lock = locks_alloc_lock(); 689521179d81SJeff Layton if (!file_lock) { 689621179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 689721179d81SJeff Layton status = nfserr_jukebox; 6898eb82dd39SJeff Layton goto put_file; 689921179d81SJeff Layton } 69006cd90662SKinglong Mee 690121179d81SJeff Layton file_lock->fl_type = F_UNLCK; 6902aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 690321179d81SJeff Layton file_lock->fl_pid = current->tgid; 6904eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 690521179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 690621179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 690721179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 69081da177e4SLinus Torvalds 690921179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 691021179d81SJeff Layton locku->lu_length); 691121179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 69121da177e4SLinus Torvalds 6913eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, NULL); 6914b8dd7b9aSAl Viro if (err) { 6915fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 69161da177e4SLinus Torvalds goto out_nfserr; 69171da177e4SLinus Torvalds } 69189767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 6919eb82dd39SJeff Layton put_file: 6920eb82dd39SJeff Layton nfsd_file_put(nf); 6921858cc573STrond Myklebust put_stateid: 6922feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6923858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 69241da177e4SLinus Torvalds out: 69259411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 692621179d81SJeff Layton if (file_lock) 692721179d81SJeff Layton locks_free_lock(file_lock); 69281da177e4SLinus Torvalds return status; 69291da177e4SLinus Torvalds 69301da177e4SLinus Torvalds out_nfserr: 6931b8dd7b9aSAl Viro status = nfserrno(err); 6932eb82dd39SJeff Layton goto put_file; 69331da177e4SLinus Torvalds } 69341da177e4SLinus Torvalds 69351da177e4SLinus Torvalds /* 69361da177e4SLinus Torvalds * returns 6937f9c00c3aSJeff Layton * true: locks held by lockowner 6938f9c00c3aSJeff Layton * false: no locks held by lockowner 69391da177e4SLinus Torvalds */ 6940f9c00c3aSJeff Layton static bool 6941f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 69421da177e4SLinus Torvalds { 6943bd61e0a9SJeff Layton struct file_lock *fl; 6944f9c00c3aSJeff Layton int status = false; 6945eb82dd39SJeff Layton struct nfsd_file *nf = find_any_file(fp); 6946f9c00c3aSJeff Layton struct inode *inode; 6947bd61e0a9SJeff Layton struct file_lock_context *flctx; 6948f9c00c3aSJeff Layton 6949eb82dd39SJeff Layton if (!nf) { 6950f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 6951f9c00c3aSJeff Layton WARN_ON_ONCE(1); 6952f9c00c3aSJeff Layton return status; 6953f9c00c3aSJeff Layton } 6954f9c00c3aSJeff Layton 6955eb82dd39SJeff Layton inode = locks_inode(nf->nf_file); 6956bd61e0a9SJeff Layton flctx = inode->i_flctx; 69571da177e4SLinus Torvalds 6958bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 69596109c850SJeff Layton spin_lock(&flctx->flc_lock); 6960bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 6961bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 6962f9c00c3aSJeff Layton status = true; 6963f9c00c3aSJeff Layton break; 69641da177e4SLinus Torvalds } 6965796dadfdSJ. Bruce Fields } 69666109c850SJeff Layton spin_unlock(&flctx->flc_lock); 6967bd61e0a9SJeff Layton } 6968eb82dd39SJeff Layton nfsd_file_put(nf); 69691da177e4SLinus Torvalds return status; 69701da177e4SLinus Torvalds } 69711da177e4SLinus Torvalds 6972b37ad28bSAl Viro __be32 6973b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 6974b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 6975eb69853dSChristoph Hellwig union nfsd4_op_u *u) 69761da177e4SLinus Torvalds { 6977eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 69781da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 6979882e9d25SJeff Layton struct nfs4_stateowner *sop; 6980882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 6981dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 69821da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 6983d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 6984b37ad28bSAl Viro __be32 status; 69857f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 6986c58c6610STrond Myklebust struct nfs4_client *clp; 698788584818SChuck Lever LIST_HEAD (reaplist); 69881da177e4SLinus Torvalds 69891da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 69901da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 69911da177e4SLinus Torvalds 6992b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 69939b2ef62bSJ. Bruce Fields if (status) 699451f5e783STrond Myklebust return status; 69959b2ef62bSJ. Bruce Fields 6996d4f0489fSTrond Myklebust clp = cstate->clp; 6997fd44907cSJeff Layton /* Find the matching lock stateowner */ 6998d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6999882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 7000d4f0489fSTrond Myklebust so_strhash) { 7001882e9d25SJeff Layton 7002882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 700316bfdaafSJ. Bruce Fields continue; 7004882e9d25SJeff Layton 7005882e9d25SJeff Layton /* see if there are still any locks associated with it */ 7006882e9d25SJeff Layton lo = lockowner(sop); 7007882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 7008882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 7009882e9d25SJeff Layton status = nfserr_locks_held; 7010882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 701151f5e783STrond Myklebust return status; 7012882e9d25SJeff Layton } 7013882e9d25SJeff Layton } 7014882e9d25SJeff Layton 7015b5971afaSKinglong Mee nfs4_get_stateowner(sop); 7016fd44907cSJeff Layton break; 7017fd44907cSJeff Layton } 701888584818SChuck Lever if (!lo) { 7019d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 702088584818SChuck Lever return status; 702188584818SChuck Lever } 702288584818SChuck Lever 702388584818SChuck Lever unhash_lockowner_locked(lo); 702488584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 702588584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 702688584818SChuck Lever struct nfs4_ol_stateid, 702788584818SChuck Lever st_perstateowner); 702888584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 702988584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 703088584818SChuck Lever } 703188584818SChuck Lever spin_unlock(&clp->cl_lock); 703288584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 703368ef3bc3SJeff Layton remove_blocked_locks(lo); 703488584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 703588584818SChuck Lever 70361da177e4SLinus Torvalds return status; 70371da177e4SLinus Torvalds } 70381da177e4SLinus Torvalds 70391da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 7040a55370a3SNeilBrown alloc_reclaim(void) 70411da177e4SLinus Torvalds { 7042a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 70431da177e4SLinus Torvalds } 70441da177e4SLinus Torvalds 70450ce0c2b5SJeff Layton bool 70466b189105SScott Mayhew nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) 7047c7b9a459SNeilBrown { 70480ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 7049c7b9a459SNeilBrown 705052e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 70510ce0c2b5SJeff Layton return (crp && crp->cr_clp); 7052c7b9a459SNeilBrown } 7053c7b9a459SNeilBrown 70541da177e4SLinus Torvalds /* 70551da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 70566b189105SScott Mayhew * 70576b189105SScott Mayhew * The caller is responsible for freeing name.data if NULL is returned (it 70586b189105SScott Mayhew * will be freed in nfs4_remove_reclaim_record in the normal case). 70591da177e4SLinus Torvalds */ 7060772a9bbbSJeff Layton struct nfs4_client_reclaim * 70616ee95d1cSScott Mayhew nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, 70626ee95d1cSScott Mayhew struct nfsd_net *nn) 70631da177e4SLinus Torvalds { 70641da177e4SLinus Torvalds unsigned int strhashval; 7065772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 70661da177e4SLinus Torvalds 70676b189105SScott Mayhew dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", name.len, name.data); 7068a55370a3SNeilBrown crp = alloc_reclaim(); 7069772a9bbbSJeff Layton if (crp) { 7070a55370a3SNeilBrown strhashval = clientstr_hashval(name); 70711da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 707252e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 70736b189105SScott Mayhew crp->cr_name.data = name.data; 70746b189105SScott Mayhew crp->cr_name.len = name.len; 70756ee95d1cSScott Mayhew crp->cr_princhash.data = princhash.data; 70766ee95d1cSScott Mayhew crp->cr_princhash.len = princhash.len; 70770ce0c2b5SJeff Layton crp->cr_clp = NULL; 707852e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 7079772a9bbbSJeff Layton } 7080772a9bbbSJeff Layton return crp; 70811da177e4SLinus Torvalds } 70821da177e4SLinus Torvalds 70832a4317c5SJeff Layton void 708452e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 7085ce30e539SJeff Layton { 7086ce30e539SJeff Layton list_del(&crp->cr_strhash); 70876b189105SScott Mayhew kfree(crp->cr_name.data); 70886ee95d1cSScott Mayhew kfree(crp->cr_princhash.data); 7089ce30e539SJeff Layton kfree(crp); 709052e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 7091ce30e539SJeff Layton } 7092ce30e539SJeff Layton 7093ce30e539SJeff Layton void 709452e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 70951da177e4SLinus Torvalds { 70961da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 70971da177e4SLinus Torvalds int i; 70981da177e4SLinus Torvalds 70991da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 710052e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 710152e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 71021da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 710352e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 71041da177e4SLinus Torvalds } 71051da177e4SLinus Torvalds } 7106063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 71071da177e4SLinus Torvalds } 71081da177e4SLinus Torvalds 71091da177e4SLinus Torvalds /* 71101da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 71112a4317c5SJeff Layton struct nfs4_client_reclaim * 71126b189105SScott Mayhew nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) 71131da177e4SLinus Torvalds { 71141da177e4SLinus Torvalds unsigned int strhashval; 71151da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 71161da177e4SLinus Torvalds 71176b189105SScott Mayhew dprintk("NFSD: nfs4_find_reclaim_client for name %.*s\n", name.len, name.data); 71181da177e4SLinus Torvalds 71196b189105SScott Mayhew strhashval = clientstr_hashval(name); 712052e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 71216b189105SScott Mayhew if (compare_blob(&crp->cr_name, &name) == 0) { 71221da177e4SLinus Torvalds return crp; 71231da177e4SLinus Torvalds } 71241da177e4SLinus Torvalds } 71251da177e4SLinus Torvalds return NULL; 71261da177e4SLinus Torvalds } 71271da177e4SLinus Torvalds 71281da177e4SLinus Torvalds /* 71291da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 71301da177e4SLinus Torvalds */ 7131b37ad28bSAl Viro __be32 71320fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 71330fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 71340fe492dbSTrond Myklebust struct nfsd_net *nn) 71351da177e4SLinus Torvalds { 71360fe492dbSTrond Myklebust __be32 status; 7137a52d726bSJeff Layton 7138a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 7139b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 71400fe492dbSTrond Myklebust if (status) 7141a52d726bSJeff Layton return nfserr_reclaim_bad; 7142a52d726bSJeff Layton 71433b3e7b72SJeff Layton if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) 71443b3e7b72SJeff Layton return nfserr_no_grace; 71453b3e7b72SJeff Layton 71460fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 71470fe492dbSTrond Myklebust return nfserr_reclaim_bad; 71480fe492dbSTrond Myklebust 71490fe492dbSTrond Myklebust return nfs_ok; 71501da177e4SLinus Torvalds } 71511da177e4SLinus Torvalds 715265178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 7153016200c3SJeff Layton static inline void 7154016200c3SJeff Layton put_client(struct nfs4_client *clp) 7155016200c3SJeff Layton { 715614ed14ccSJ. Bruce Fields atomic_dec(&clp->cl_rpc_users); 7157016200c3SJeff Layton } 7158016200c3SJeff Layton 7159285abdeeSJeff Layton static struct nfs4_client * 7160285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 7161285abdeeSJeff Layton { 7162285abdeeSJeff Layton struct nfs4_client *clp; 7163285abdeeSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7164285abdeeSJeff Layton nfsd_net_id); 7165285abdeeSJeff Layton 7166285abdeeSJeff Layton if (!nfsd_netns_ready(nn)) 7167285abdeeSJeff Layton return NULL; 7168285abdeeSJeff Layton 7169285abdeeSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 7170285abdeeSJeff Layton if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 7171285abdeeSJeff Layton return clp; 7172285abdeeSJeff Layton } 7173285abdeeSJeff Layton return NULL; 7174285abdeeSJeff Layton } 7175285abdeeSJeff Layton 71767ec0e36fSJeff Layton u64 7177285abdeeSJeff Layton nfsd_inject_print_clients(void) 71787ec0e36fSJeff Layton { 71797ec0e36fSJeff Layton struct nfs4_client *clp; 71807ec0e36fSJeff Layton u64 count = 0; 71817ec0e36fSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 71827ec0e36fSJeff Layton nfsd_net_id); 71837ec0e36fSJeff Layton char buf[INET6_ADDRSTRLEN]; 71847ec0e36fSJeff Layton 71857ec0e36fSJeff Layton if (!nfsd_netns_ready(nn)) 71867ec0e36fSJeff Layton return 0; 71877ec0e36fSJeff Layton 71887ec0e36fSJeff Layton spin_lock(&nn->client_lock); 71897ec0e36fSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 71907ec0e36fSJeff Layton rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 71917ec0e36fSJeff Layton pr_info("NFS Client: %s\n", buf); 71927ec0e36fSJeff Layton ++count; 71937ec0e36fSJeff Layton } 71947ec0e36fSJeff Layton spin_unlock(&nn->client_lock); 71957ec0e36fSJeff Layton 71967ec0e36fSJeff Layton return count; 71977ec0e36fSJeff Layton } 719865178db4SBryan Schumaker 7199a0926d15SJeff Layton u64 7200285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) 7201a0926d15SJeff Layton { 7202a0926d15SJeff Layton u64 count = 0; 7203a0926d15SJeff Layton struct nfs4_client *clp; 7204a0926d15SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7205a0926d15SJeff Layton nfsd_net_id); 7206a0926d15SJeff Layton 7207a0926d15SJeff Layton if (!nfsd_netns_ready(nn)) 7208a0926d15SJeff Layton return count; 7209a0926d15SJeff Layton 7210a0926d15SJeff Layton spin_lock(&nn->client_lock); 7211a0926d15SJeff Layton clp = nfsd_find_client(addr, addr_size); 7212a0926d15SJeff Layton if (clp) { 7213a0926d15SJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) 7214a0926d15SJeff Layton ++count; 7215a0926d15SJeff Layton else 7216a0926d15SJeff Layton clp = NULL; 7217a0926d15SJeff Layton } 7218a0926d15SJeff Layton spin_unlock(&nn->client_lock); 7219a0926d15SJeff Layton 7220a0926d15SJeff Layton if (clp) 7221a0926d15SJeff Layton expire_client(clp); 7222a0926d15SJeff Layton 7223a0926d15SJeff Layton return count; 7224a0926d15SJeff Layton } 7225a0926d15SJeff Layton 722669fc9edfSJeff Layton u64 7227285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max) 722869fc9edfSJeff Layton { 722969fc9edfSJeff Layton u64 count = 0; 723069fc9edfSJeff Layton struct nfs4_client *clp, *next; 723169fc9edfSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 723269fc9edfSJeff Layton nfsd_net_id); 723369fc9edfSJeff Layton LIST_HEAD(reaplist); 723469fc9edfSJeff Layton 723569fc9edfSJeff Layton if (!nfsd_netns_ready(nn)) 723669fc9edfSJeff Layton return count; 723769fc9edfSJeff Layton 723869fc9edfSJeff Layton spin_lock(&nn->client_lock); 723969fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 724069fc9edfSJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) { 724169fc9edfSJeff Layton list_add(&clp->cl_lru, &reaplist); 724269fc9edfSJeff Layton if (max != 0 && ++count >= max) 724369fc9edfSJeff Layton break; 724469fc9edfSJeff Layton } 724569fc9edfSJeff Layton } 724669fc9edfSJeff Layton spin_unlock(&nn->client_lock); 724769fc9edfSJeff Layton 724869fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &reaplist, cl_lru) 724969fc9edfSJeff Layton expire_client(clp); 725069fc9edfSJeff Layton 725169fc9edfSJeff Layton return count; 725269fc9edfSJeff Layton } 725369fc9edfSJeff Layton 7254184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 7255184c1847SBryan Schumaker const char *type) 7256184c1847SBryan Schumaker { 7257184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 72580a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 7259184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 7260184c1847SBryan Schumaker } 7261184c1847SBryan Schumaker 7262016200c3SJeff Layton static void 7263016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, 7264016200c3SJeff Layton struct list_head *collect) 7265016200c3SJeff Layton { 7266016200c3SJeff Layton struct nfs4_client *clp = lst->st_stid.sc_client; 7267016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7268016200c3SJeff Layton nfsd_net_id); 7269016200c3SJeff Layton 7270016200c3SJeff Layton if (!collect) 7271016200c3SJeff Layton return; 7272016200c3SJeff Layton 7273016200c3SJeff Layton lockdep_assert_held(&nn->client_lock); 727414ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 7275016200c3SJeff Layton list_add(&lst->st_locks, collect); 7276016200c3SJeff Layton } 7277016200c3SJeff Layton 72783c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 72793738d50eSJeff Layton struct list_head *collect, 7280e8568739SJeff Layton bool (*func)(struct nfs4_ol_stateid *)) 7281fc29171fSBryan Schumaker { 7282fc29171fSBryan Schumaker struct nfs4_openowner *oop; 7283fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 72843c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 7285fc29171fSBryan Schumaker u64 count = 0; 7286fc29171fSBryan Schumaker 7287016200c3SJeff Layton spin_lock(&clp->cl_lock); 7288fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 72893c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 72903c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 72913c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 72923c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 72933738d50eSJeff Layton if (func) { 7294e8568739SJeff Layton if (func(lst)) 7295016200c3SJeff Layton nfsd_inject_add_lock_to_list(lst, 72963738d50eSJeff Layton collect); 72973738d50eSJeff Layton } 7298016200c3SJeff Layton ++count; 7299016200c3SJeff Layton /* 7300016200c3SJeff Layton * Despite the fact that these functions deal 7301016200c3SJeff Layton * with 64-bit integers for "count", we must 7302016200c3SJeff Layton * ensure that it doesn't blow up the 730314ed14ccSJ. Bruce Fields * clp->cl_rpc_users. Throw a warning if we 7304016200c3SJeff Layton * start to approach INT_MAX here. 7305016200c3SJeff Layton */ 7306016200c3SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 7307016200c3SJeff Layton if (count == max) 7308016200c3SJeff Layton goto out; 7309fc29171fSBryan Schumaker } 7310fc29171fSBryan Schumaker } 7311fc29171fSBryan Schumaker } 7312016200c3SJeff Layton out: 7313016200c3SJeff Layton spin_unlock(&clp->cl_lock); 7314fc29171fSBryan Schumaker 7315fc29171fSBryan Schumaker return count; 7316fc29171fSBryan Schumaker } 7317fc29171fSBryan Schumaker 7318016200c3SJeff Layton static u64 7319016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, 7320016200c3SJeff Layton u64 max) 7321fc29171fSBryan Schumaker { 7322016200c3SJeff Layton return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); 7323fc29171fSBryan Schumaker } 7324fc29171fSBryan Schumaker 7325016200c3SJeff Layton static u64 7326016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp) 7327184c1847SBryan Schumaker { 7328016200c3SJeff Layton u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); 7329184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 7330184c1847SBryan Schumaker return count; 7331184c1847SBryan Schumaker } 7332184c1847SBryan Schumaker 7333016200c3SJeff Layton u64 7334285abdeeSJeff Layton nfsd_inject_print_locks(void) 7335016200c3SJeff Layton { 7336016200c3SJeff Layton struct nfs4_client *clp; 7337016200c3SJeff Layton u64 count = 0; 7338016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7339016200c3SJeff Layton nfsd_net_id); 7340016200c3SJeff Layton 7341016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 7342016200c3SJeff Layton return 0; 7343016200c3SJeff Layton 7344016200c3SJeff Layton spin_lock(&nn->client_lock); 7345016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 7346016200c3SJeff Layton count += nfsd_print_client_locks(clp); 7347016200c3SJeff Layton spin_unlock(&nn->client_lock); 7348016200c3SJeff Layton 7349016200c3SJeff Layton return count; 7350016200c3SJeff Layton } 7351016200c3SJeff Layton 7352016200c3SJeff Layton static void 7353016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist) 7354016200c3SJeff Layton { 7355016200c3SJeff Layton struct nfs4_client *clp; 7356016200c3SJeff Layton struct nfs4_ol_stateid *stp, *next; 7357016200c3SJeff Layton 7358016200c3SJeff Layton list_for_each_entry_safe(stp, next, reaplist, st_locks) { 7359016200c3SJeff Layton list_del_init(&stp->st_locks); 7360016200c3SJeff Layton clp = stp->st_stid.sc_client; 7361016200c3SJeff Layton nfs4_put_stid(&stp->st_stid); 7362016200c3SJeff Layton put_client(clp); 7363016200c3SJeff Layton } 7364016200c3SJeff Layton } 7365016200c3SJeff Layton 7366016200c3SJeff Layton u64 7367285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) 7368016200c3SJeff Layton { 7369016200c3SJeff Layton unsigned int count = 0; 7370016200c3SJeff Layton struct nfs4_client *clp; 7371016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7372016200c3SJeff Layton nfsd_net_id); 7373016200c3SJeff Layton LIST_HEAD(reaplist); 7374016200c3SJeff Layton 7375016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 7376016200c3SJeff Layton return count; 7377016200c3SJeff Layton 7378016200c3SJeff Layton spin_lock(&nn->client_lock); 7379016200c3SJeff Layton clp = nfsd_find_client(addr, addr_size); 7380016200c3SJeff Layton if (clp) 7381016200c3SJeff Layton count = nfsd_collect_client_locks(clp, &reaplist, 0); 7382016200c3SJeff Layton spin_unlock(&nn->client_lock); 7383016200c3SJeff Layton nfsd_reap_locks(&reaplist); 7384016200c3SJeff Layton return count; 7385016200c3SJeff Layton } 7386016200c3SJeff Layton 7387016200c3SJeff Layton u64 7388285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max) 7389016200c3SJeff Layton { 7390016200c3SJeff Layton u64 count = 0; 7391016200c3SJeff Layton struct nfs4_client *clp; 7392016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7393016200c3SJeff Layton nfsd_net_id); 7394016200c3SJeff Layton LIST_HEAD(reaplist); 7395016200c3SJeff Layton 7396016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 7397016200c3SJeff Layton return count; 7398016200c3SJeff Layton 7399016200c3SJeff Layton spin_lock(&nn->client_lock); 7400016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 7401016200c3SJeff Layton count += nfsd_collect_client_locks(clp, &reaplist, max - count); 7402016200c3SJeff Layton if (max != 0 && count >= max) 7403016200c3SJeff Layton break; 7404016200c3SJeff Layton } 7405016200c3SJeff Layton spin_unlock(&nn->client_lock); 7406016200c3SJeff Layton nfsd_reap_locks(&reaplist); 7407016200c3SJeff Layton return count; 7408016200c3SJeff Layton } 7409016200c3SJeff Layton 741082e05efaSJeff Layton static u64 741182e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, 741282e05efaSJeff Layton struct list_head *collect, 741382e05efaSJeff Layton void (*func)(struct nfs4_openowner *)) 74144dbdbda8SBryan Schumaker { 74154dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 741682e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 741782e05efaSJeff Layton nfsd_net_id); 74184dbdbda8SBryan Schumaker u64 count = 0; 74194dbdbda8SBryan Schumaker 742082e05efaSJeff Layton lockdep_assert_held(&nn->client_lock); 742182e05efaSJeff Layton 742282e05efaSJeff Layton spin_lock(&clp->cl_lock); 74234dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 742482e05efaSJeff Layton if (func) { 74254dbdbda8SBryan Schumaker func(oop); 742682e05efaSJeff Layton if (collect) { 742714ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 742882e05efaSJeff Layton list_add(&oop->oo_perclient, collect); 742982e05efaSJeff Layton } 743082e05efaSJeff Layton } 743182e05efaSJeff Layton ++count; 743282e05efaSJeff Layton /* 743382e05efaSJeff Layton * Despite the fact that these functions deal with 743482e05efaSJeff Layton * 64-bit integers for "count", we must ensure that 743514ed14ccSJ. Bruce Fields * it doesn't blow up the clp->cl_rpc_users. Throw a 743682e05efaSJeff Layton * warning if we start to approach INT_MAX here. 743782e05efaSJeff Layton */ 743882e05efaSJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 743982e05efaSJeff Layton if (count == max) 74404dbdbda8SBryan Schumaker break; 74414dbdbda8SBryan Schumaker } 744282e05efaSJeff Layton spin_unlock(&clp->cl_lock); 74434dbdbda8SBryan Schumaker 74444dbdbda8SBryan Schumaker return count; 74454dbdbda8SBryan Schumaker } 74464dbdbda8SBryan Schumaker 744782e05efaSJeff Layton static u64 744882e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp) 74494dbdbda8SBryan Schumaker { 745082e05efaSJeff Layton u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); 745182e05efaSJeff Layton 745282e05efaSJeff Layton nfsd_print_count(clp, count, "openowners"); 745382e05efaSJeff Layton return count; 74544dbdbda8SBryan Schumaker } 74554dbdbda8SBryan Schumaker 745682e05efaSJeff Layton static u64 745782e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp, 745882e05efaSJeff Layton struct list_head *collect, u64 max) 7459184c1847SBryan Schumaker { 746082e05efaSJeff Layton return nfsd_foreach_client_openowner(clp, max, collect, 746182e05efaSJeff Layton unhash_openowner_locked); 746282e05efaSJeff Layton } 746382e05efaSJeff Layton 746482e05efaSJeff Layton u64 7465285abdeeSJeff Layton nfsd_inject_print_openowners(void) 746682e05efaSJeff Layton { 746782e05efaSJeff Layton struct nfs4_client *clp; 746882e05efaSJeff Layton u64 count = 0; 746982e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 747082e05efaSJeff Layton nfsd_net_id); 747182e05efaSJeff Layton 747282e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 747382e05efaSJeff Layton return 0; 747482e05efaSJeff Layton 747582e05efaSJeff Layton spin_lock(&nn->client_lock); 747682e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 747782e05efaSJeff Layton count += nfsd_print_client_openowners(clp); 747882e05efaSJeff Layton spin_unlock(&nn->client_lock); 747982e05efaSJeff Layton 748082e05efaSJeff Layton return count; 748182e05efaSJeff Layton } 748282e05efaSJeff Layton 748382e05efaSJeff Layton static void 748482e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist) 748582e05efaSJeff Layton { 748682e05efaSJeff Layton struct nfs4_client *clp; 748782e05efaSJeff Layton struct nfs4_openowner *oop, *next; 748882e05efaSJeff Layton 748982e05efaSJeff Layton list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { 749082e05efaSJeff Layton list_del_init(&oop->oo_perclient); 749182e05efaSJeff Layton clp = oop->oo_owner.so_client; 749282e05efaSJeff Layton release_openowner(oop); 749382e05efaSJeff Layton put_client(clp); 749482e05efaSJeff Layton } 749582e05efaSJeff Layton } 749682e05efaSJeff Layton 749782e05efaSJeff Layton u64 7498285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, 7499285abdeeSJeff Layton size_t addr_size) 750082e05efaSJeff Layton { 750182e05efaSJeff Layton unsigned int count = 0; 750282e05efaSJeff Layton struct nfs4_client *clp; 750382e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 750482e05efaSJeff Layton nfsd_net_id); 750582e05efaSJeff Layton LIST_HEAD(reaplist); 750682e05efaSJeff Layton 750782e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 750882e05efaSJeff Layton return count; 750982e05efaSJeff Layton 751082e05efaSJeff Layton spin_lock(&nn->client_lock); 751182e05efaSJeff Layton clp = nfsd_find_client(addr, addr_size); 751282e05efaSJeff Layton if (clp) 751382e05efaSJeff Layton count = nfsd_collect_client_openowners(clp, &reaplist, 0); 751482e05efaSJeff Layton spin_unlock(&nn->client_lock); 751582e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 751682e05efaSJeff Layton return count; 751782e05efaSJeff Layton } 751882e05efaSJeff Layton 751982e05efaSJeff Layton u64 7520285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max) 752182e05efaSJeff Layton { 752282e05efaSJeff Layton u64 count = 0; 752382e05efaSJeff Layton struct nfs4_client *clp; 752482e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 752582e05efaSJeff Layton nfsd_net_id); 752682e05efaSJeff Layton LIST_HEAD(reaplist); 752782e05efaSJeff Layton 752882e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 752982e05efaSJeff Layton return count; 753082e05efaSJeff Layton 753182e05efaSJeff Layton spin_lock(&nn->client_lock); 753282e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 753382e05efaSJeff Layton count += nfsd_collect_client_openowners(clp, &reaplist, 753482e05efaSJeff Layton max - count); 753582e05efaSJeff Layton if (max != 0 && count >= max) 753682e05efaSJeff Layton break; 753782e05efaSJeff Layton } 753882e05efaSJeff Layton spin_unlock(&nn->client_lock); 753982e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 7540184c1847SBryan Schumaker return count; 7541184c1847SBryan Schumaker } 7542184c1847SBryan Schumaker 7543269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 7544269de30fSBryan Schumaker struct list_head *victims) 7545269de30fSBryan Schumaker { 7546269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 754798d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 754898d5c7c5SJeff Layton nfsd_net_id); 7549269de30fSBryan Schumaker u64 count = 0; 7550269de30fSBryan Schumaker 755198d5c7c5SJeff Layton lockdep_assert_held(&nn->client_lock); 755298d5c7c5SJeff Layton 755398d5c7c5SJeff Layton spin_lock(&state_lock); 7554269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 7555dff1399fSJeff Layton if (victims) { 7556dff1399fSJeff Layton /* 7557dff1399fSJeff Layton * It's not safe to mess with delegations that have a 7558dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 7559dff1399fSJeff Layton * and could be processed by the laundromat outside of 7560dff1399fSJeff Layton * the state_lock. Just leave them be. 7561dff1399fSJeff Layton */ 7562dff1399fSJeff Layton if (dp->dl_time != 0) 7563dff1399fSJeff Layton continue; 7564dff1399fSJeff Layton 756514ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 75663fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 756742690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 7568dff1399fSJeff Layton } 756998d5c7c5SJeff Layton ++count; 757098d5c7c5SJeff Layton /* 757198d5c7c5SJeff Layton * Despite the fact that these functions deal with 757298d5c7c5SJeff Layton * 64-bit integers for "count", we must ensure that 757314ed14ccSJ. Bruce Fields * it doesn't blow up the clp->cl_rpc_users. Throw a 757498d5c7c5SJeff Layton * warning if we start to approach INT_MAX here. 757598d5c7c5SJeff Layton */ 757698d5c7c5SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 757798d5c7c5SJeff Layton if (count == max) 7578269de30fSBryan Schumaker break; 7579269de30fSBryan Schumaker } 758098d5c7c5SJeff Layton spin_unlock(&state_lock); 7581269de30fSBryan Schumaker return count; 7582269de30fSBryan Schumaker } 7583269de30fSBryan Schumaker 758498d5c7c5SJeff Layton static u64 758598d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp) 7586269de30fSBryan Schumaker { 758798d5c7c5SJeff Layton u64 count = nfsd_find_all_delegations(clp, 0, NULL); 7588184c1847SBryan Schumaker 7589184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 7590184c1847SBryan Schumaker return count; 7591184c1847SBryan Schumaker } 7592184c1847SBryan Schumaker 759398d5c7c5SJeff Layton u64 7594285abdeeSJeff Layton nfsd_inject_print_delegations(void) 759598d5c7c5SJeff Layton { 759698d5c7c5SJeff Layton struct nfs4_client *clp; 759798d5c7c5SJeff Layton u64 count = 0; 759898d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 759998d5c7c5SJeff Layton nfsd_net_id); 760098d5c7c5SJeff Layton 760198d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 760298d5c7c5SJeff Layton return 0; 760398d5c7c5SJeff Layton 760498d5c7c5SJeff Layton spin_lock(&nn->client_lock); 760598d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 760698d5c7c5SJeff Layton count += nfsd_print_client_delegations(clp); 760798d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 760898d5c7c5SJeff Layton 760998d5c7c5SJeff Layton return count; 761098d5c7c5SJeff Layton } 761198d5c7c5SJeff Layton 761298d5c7c5SJeff Layton static void 761398d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist) 761498d5c7c5SJeff Layton { 761598d5c7c5SJeff Layton struct nfs4_client *clp; 761698d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 761798d5c7c5SJeff Layton 761898d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 761998d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 762098d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 762198d5c7c5SJeff Layton revoke_delegation(dp); 762298d5c7c5SJeff Layton put_client(clp); 762398d5c7c5SJeff Layton } 762498d5c7c5SJeff Layton } 762598d5c7c5SJeff Layton 762698d5c7c5SJeff Layton u64 7627285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, 7628285abdeeSJeff Layton size_t addr_size) 762998d5c7c5SJeff Layton { 763098d5c7c5SJeff Layton u64 count = 0; 763198d5c7c5SJeff Layton struct nfs4_client *clp; 763298d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 763398d5c7c5SJeff Layton nfsd_net_id); 763498d5c7c5SJeff Layton LIST_HEAD(reaplist); 763598d5c7c5SJeff Layton 763698d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 763798d5c7c5SJeff Layton return count; 763898d5c7c5SJeff Layton 763998d5c7c5SJeff Layton spin_lock(&nn->client_lock); 764098d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 764198d5c7c5SJeff Layton if (clp) 764298d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 764398d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 764498d5c7c5SJeff Layton 764598d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 764698d5c7c5SJeff Layton return count; 764798d5c7c5SJeff Layton } 764898d5c7c5SJeff Layton 764998d5c7c5SJeff Layton u64 7650285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max) 765198d5c7c5SJeff Layton { 765298d5c7c5SJeff Layton u64 count = 0; 765398d5c7c5SJeff Layton struct nfs4_client *clp; 765498d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 765598d5c7c5SJeff Layton nfsd_net_id); 765698d5c7c5SJeff Layton LIST_HEAD(reaplist); 765798d5c7c5SJeff Layton 765898d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 765998d5c7c5SJeff Layton return count; 766098d5c7c5SJeff Layton 766198d5c7c5SJeff Layton spin_lock(&nn->client_lock); 766298d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 766398d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 766498d5c7c5SJeff Layton if (max != 0 && count >= max) 766598d5c7c5SJeff Layton break; 766698d5c7c5SJeff Layton } 766798d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 766898d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 766998d5c7c5SJeff Layton return count; 767098d5c7c5SJeff Layton } 767198d5c7c5SJeff Layton 767298d5c7c5SJeff Layton static void 767398d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist) 767498d5c7c5SJeff Layton { 767598d5c7c5SJeff Layton struct nfs4_client *clp; 767698d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 767798d5c7c5SJeff Layton 767898d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 767998d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 768098d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 768198d5c7c5SJeff Layton /* 768298d5c7c5SJeff Layton * We skipped all entries that had a zero dl_time before, 768398d5c7c5SJeff Layton * so we can now reset the dl_time back to 0. If a delegation 768498d5c7c5SJeff Layton * break comes in now, then it won't make any difference since 768598d5c7c5SJeff Layton * we're recalling it either way. 768698d5c7c5SJeff Layton */ 768798d5c7c5SJeff Layton spin_lock(&state_lock); 768898d5c7c5SJeff Layton dp->dl_time = 0; 768998d5c7c5SJeff Layton spin_unlock(&state_lock); 769098d5c7c5SJeff Layton nfsd_break_one_deleg(dp); 769198d5c7c5SJeff Layton put_client(clp); 769298d5c7c5SJeff Layton } 769398d5c7c5SJeff Layton } 769498d5c7c5SJeff Layton 769598d5c7c5SJeff Layton u64 7696285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, 769798d5c7c5SJeff Layton size_t addr_size) 769898d5c7c5SJeff Layton { 769998d5c7c5SJeff Layton u64 count = 0; 770098d5c7c5SJeff Layton struct nfs4_client *clp; 770198d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 770298d5c7c5SJeff Layton nfsd_net_id); 770398d5c7c5SJeff Layton LIST_HEAD(reaplist); 770498d5c7c5SJeff Layton 770598d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 770698d5c7c5SJeff Layton return count; 770798d5c7c5SJeff Layton 770898d5c7c5SJeff Layton spin_lock(&nn->client_lock); 770998d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 771098d5c7c5SJeff Layton if (clp) 771198d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 771298d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 771398d5c7c5SJeff Layton 771498d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 771598d5c7c5SJeff Layton return count; 771698d5c7c5SJeff Layton } 771798d5c7c5SJeff Layton 771898d5c7c5SJeff Layton u64 7719285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max) 772098d5c7c5SJeff Layton { 772198d5c7c5SJeff Layton u64 count = 0; 772298d5c7c5SJeff Layton struct nfs4_client *clp, *next; 772398d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 772498d5c7c5SJeff Layton nfsd_net_id); 772598d5c7c5SJeff Layton LIST_HEAD(reaplist); 772698d5c7c5SJeff Layton 772798d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 772898d5c7c5SJeff Layton return count; 772998d5c7c5SJeff Layton 773098d5c7c5SJeff Layton spin_lock(&nn->client_lock); 773198d5c7c5SJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 773298d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 773398d5c7c5SJeff Layton if (max != 0 && ++count >= max) 773498d5c7c5SJeff Layton break; 773598d5c7c5SJeff Layton } 773698d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 773798d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 773898d5c7c5SJeff Layton return count; 773998d5c7c5SJeff Layton } 774065178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 774165178db4SBryan Schumaker 7742c2f1a551SMeelap Shah /* 7743c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 7744c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 7745c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 7746c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 7747c2f1a551SMeelap Shah * 7748c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 7749c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 7750c2f1a551SMeelap Shah */ 7751c2f1a551SMeelap Shah static void 7752c2f1a551SMeelap Shah set_max_delegations(void) 7753c2f1a551SMeelap Shah { 7754c2f1a551SMeelap Shah /* 7755c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 7756c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 7757c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 7758c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 7759c2f1a551SMeelap Shah */ 7760c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 7761c2f1a551SMeelap Shah } 7762c2f1a551SMeelap Shah 7763d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 77648daae4dcSStanislav Kinsbursky { 77658daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 77668daae4dcSStanislav Kinsbursky int i; 77678daae4dcSStanislav Kinsbursky 77686da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 77696da2ec56SKees Cook sizeof(struct list_head), 77706da2ec56SKees Cook GFP_KERNEL); 77718daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 7772382a62e7SStanislav Kinsbursky goto err; 77736da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 77746da2ec56SKees Cook sizeof(struct list_head), 77756da2ec56SKees Cook GFP_KERNEL); 77760a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 77770a7ec377SStanislav Kinsbursky goto err_unconf_id; 77786da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 77796da2ec56SKees Cook sizeof(struct list_head), 77806da2ec56SKees Cook GFP_KERNEL); 77811872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 77821872de0eSStanislav Kinsbursky goto err_sessionid; 77838daae4dcSStanislav Kinsbursky 7784382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 77858daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 77860a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 7787382a62e7SStanislav Kinsbursky } 77881872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 77891872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 7790382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 7791a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 77929cc76801SArnd Bergmann nn->boot_time = ktime_get_real_seconds(); 779381833de1SVasily Averin nn->grace_ended = false; 779481833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 779581833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 77965ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 779773758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 7798e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 7799c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 7800e0639dc5SOlga Kornievskaia spin_lock_init(&nn->s2s_cp_lock); 7801e0639dc5SOlga Kornievskaia idr_init(&nn->s2s_cp_stateids); 78028daae4dcSStanislav Kinsbursky 78030cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 78040cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 78050cc11a61SJeff Layton 780609121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 7807d85ed443SStanislav Kinsbursky get_net(net); 780809121281SStanislav Kinsbursky 78098daae4dcSStanislav Kinsbursky return 0; 7810382a62e7SStanislav Kinsbursky 78111872de0eSStanislav Kinsbursky err_sessionid: 78129b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 78130a7ec377SStanislav Kinsbursky err_unconf_id: 78140a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 7815382a62e7SStanislav Kinsbursky err: 7816382a62e7SStanislav Kinsbursky return -ENOMEM; 78178daae4dcSStanislav Kinsbursky } 78188daae4dcSStanislav Kinsbursky 78198daae4dcSStanislav Kinsbursky static void 78204dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 78218daae4dcSStanislav Kinsbursky { 78228daae4dcSStanislav Kinsbursky int i; 78238daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 78248daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 78258daae4dcSStanislav Kinsbursky 78268daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 78278daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 78288daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 78298daae4dcSStanislav Kinsbursky destroy_client(clp); 78308daae4dcSStanislav Kinsbursky } 78318daae4dcSStanislav Kinsbursky } 7832a99454aaSStanislav Kinsbursky 783368ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 783468ef3bc3SJeff Layton 78352b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 78362b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 78372b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 7838a99454aaSStanislav Kinsbursky destroy_client(clp); 7839a99454aaSStanislav Kinsbursky } 78402b905635SKinglong Mee } 7841a99454aaSStanislav Kinsbursky 78421872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 78430a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 78448daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 78454dce0ac9SStanislav Kinsbursky put_net(net); 78468daae4dcSStanislav Kinsbursky } 78478daae4dcSStanislav Kinsbursky 7848f252bc68SStanislav Kinsbursky int 7849d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 7850ac4d8ff2SNeilBrown { 78515e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 7852b5a1a81eSJ. Bruce Fields int ret; 7853b5a1a81eSJ. Bruce Fields 7854d85ed443SStanislav Kinsbursky ret = nfs4_state_create_net(net); 78558daae4dcSStanislav Kinsbursky if (ret) 78568daae4dcSStanislav Kinsbursky return ret; 7857d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 7858d4318acdSJeff Layton nfsd4_client_tracking_init(net); 7859362063a5SScott Mayhew if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) 7860362063a5SScott Mayhew goto skip_grace; 786120b7d86fSArnd Bergmann printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", 78627e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 78635284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 7864d85ed443SStanislav Kinsbursky return 0; 7865362063a5SScott Mayhew 7866362063a5SScott Mayhew skip_grace: 7867362063a5SScott Mayhew printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n", 7868362063a5SScott Mayhew net->ns.inum); 7869362063a5SScott Mayhew queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ); 7870362063a5SScott Mayhew nfsd4_end_grace(nn); 7871362063a5SScott Mayhew return 0; 7872a6d6b781SJeff Layton } 7873d85ed443SStanislav Kinsbursky 7874d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 7875d85ed443SStanislav Kinsbursky 7876d85ed443SStanislav Kinsbursky int 7877d85ed443SStanislav Kinsbursky nfs4_state_start(void) 7878d85ed443SStanislav Kinsbursky { 7879d85ed443SStanislav Kinsbursky int ret; 7880d85ed443SStanislav Kinsbursky 788151a54568SJeff Layton laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 7882a6d6b781SJeff Layton if (laundry_wq == NULL) { 7883a6d6b781SJeff Layton ret = -ENOMEM; 7884a26dd64fSChuck Lever goto out; 7885a6d6b781SJeff Layton } 7886b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 7887b5a1a81eSJ. Bruce Fields if (ret) 7888b5a1a81eSJ. Bruce Fields goto out_free_laundry; 788909121281SStanislav Kinsbursky 7890c2f1a551SMeelap Shah set_max_delegations(); 7891b5a1a81eSJ. Bruce Fields return 0; 7892d85ed443SStanislav Kinsbursky 7893b5a1a81eSJ. Bruce Fields out_free_laundry: 7894b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 7895a26dd64fSChuck Lever out: 7896b5a1a81eSJ. Bruce Fields return ret; 78971da177e4SLinus Torvalds } 78981da177e4SLinus Torvalds 7899f252bc68SStanislav Kinsbursky void 79004dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 79011da177e4SLinus Torvalds { 79021da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 79031da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 79044dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 79051da177e4SLinus Torvalds 79064dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 79074dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 7908ac55fdc4SJeff Layton 79091da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 7910cdc97505SBenny Halevy spin_lock(&state_lock); 7911e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 79121da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 79133fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 791442690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 79151da177e4SLinus Torvalds } 7916cdc97505SBenny Halevy spin_unlock(&state_lock); 79171da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 79181da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 791942690676SJeff Layton list_del_init(&dp->dl_recall_lru); 79200af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 79211da177e4SLinus Torvalds } 79221da177e4SLinus Torvalds 79233320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 79244dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 79251da177e4SLinus Torvalds } 79261da177e4SLinus Torvalds 79271da177e4SLinus Torvalds void 79281da177e4SLinus Torvalds nfs4_state_shutdown(void) 79291da177e4SLinus Torvalds { 79305e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 7931c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 79321da177e4SLinus Torvalds } 79338b70484cSTigran Mkrtchyan 79348b70484cSTigran Mkrtchyan static void 79358b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 79368b70484cSTigran Mkrtchyan { 793751100d2bSOlga Kornievskaia if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) && 793851100d2bSOlga Kornievskaia CURRENT_STATEID(stateid)) 793937c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 79408b70484cSTigran Mkrtchyan } 79418b70484cSTigran Mkrtchyan 79428b70484cSTigran Mkrtchyan static void 79438b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 79448b70484cSTigran Mkrtchyan { 794537c593c5STigran Mkrtchyan if (cstate->minorversion) { 794637c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 794751100d2bSOlga Kornievskaia SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 794837c593c5STigran Mkrtchyan } 794937c593c5STigran Mkrtchyan } 795037c593c5STigran Mkrtchyan 795137c593c5STigran Mkrtchyan void 795237c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 795337c593c5STigran Mkrtchyan { 795451100d2bSOlga Kornievskaia CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 79558b70484cSTigran Mkrtchyan } 79568b70484cSTigran Mkrtchyan 795762cd4a59STigran Mkrtchyan /* 795862cd4a59STigran Mkrtchyan * functions to set current state id 795962cd4a59STigran Mkrtchyan */ 79608b70484cSTigran Mkrtchyan void 7961b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 7962b60e9859SChristoph Hellwig union nfsd4_op_u *u) 79639428fe1aSTigran Mkrtchyan { 7964b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 79659428fe1aSTigran Mkrtchyan } 79669428fe1aSTigran Mkrtchyan 79679428fe1aSTigran Mkrtchyan void 7968b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 7969b60e9859SChristoph Hellwig union nfsd4_op_u *u) 79708b70484cSTigran Mkrtchyan { 7971b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 79728b70484cSTigran Mkrtchyan } 79738b70484cSTigran Mkrtchyan 79748b70484cSTigran Mkrtchyan void 7975b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 7976b60e9859SChristoph Hellwig union nfsd4_op_u *u) 797762cd4a59STigran Mkrtchyan { 7978b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 797962cd4a59STigran Mkrtchyan } 798062cd4a59STigran Mkrtchyan 798162cd4a59STigran Mkrtchyan void 7982b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 7983b60e9859SChristoph Hellwig union nfsd4_op_u *u) 798462cd4a59STigran Mkrtchyan { 7985b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 798662cd4a59STigran Mkrtchyan } 798762cd4a59STigran Mkrtchyan 798862cd4a59STigran Mkrtchyan /* 798962cd4a59STigran Mkrtchyan * functions to consume current state id 799062cd4a59STigran Mkrtchyan */ 79911e97b519STigran Mkrtchyan 79921e97b519STigran Mkrtchyan void 799357832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 799457832e7bSChristoph Hellwig union nfsd4_op_u *u) 79959428fe1aSTigran Mkrtchyan { 799657832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 79979428fe1aSTigran Mkrtchyan } 79989428fe1aSTigran Mkrtchyan 79999428fe1aSTigran Mkrtchyan void 800057832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 800157832e7bSChristoph Hellwig union nfsd4_op_u *u) 80029428fe1aSTigran Mkrtchyan { 800357832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 80049428fe1aSTigran Mkrtchyan } 80059428fe1aSTigran Mkrtchyan 80069428fe1aSTigran Mkrtchyan void 800757832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 800857832e7bSChristoph Hellwig union nfsd4_op_u *u) 80091e97b519STigran Mkrtchyan { 801057832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 80111e97b519STigran Mkrtchyan } 80121e97b519STigran Mkrtchyan 80131e97b519STigran Mkrtchyan void 801457832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 801557832e7bSChristoph Hellwig union nfsd4_op_u *u) 80161e97b519STigran Mkrtchyan { 801757832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 80181e97b519STigran Mkrtchyan } 80191e97b519STigran Mkrtchyan 802062cd4a59STigran Mkrtchyan void 802157832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 802257832e7bSChristoph Hellwig union nfsd4_op_u *u) 80238b70484cSTigran Mkrtchyan { 802457832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 80258b70484cSTigran Mkrtchyan } 80268b70484cSTigran Mkrtchyan 80278b70484cSTigran Mkrtchyan void 802857832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 802957832e7bSChristoph Hellwig union nfsd4_op_u *u) 80308b70484cSTigran Mkrtchyan { 803157832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 80328b70484cSTigran Mkrtchyan } 803330813e27STigran Mkrtchyan 803430813e27STigran Mkrtchyan void 803557832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 803657832e7bSChristoph Hellwig union nfsd4_op_u *u) 803730813e27STigran Mkrtchyan { 803857832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 803930813e27STigran Mkrtchyan } 804030813e27STigran Mkrtchyan 804130813e27STigran Mkrtchyan void 804257832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 804357832e7bSChristoph Hellwig union nfsd4_op_u *u) 804430813e27STigran Mkrtchyan { 804557832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 804630813e27STigran Mkrtchyan } 8047